314 lines
9.0 KiB
Nix
314 lines
9.0 KiB
Nix
{
|
|
description = "JupyterHub Notebook Viewer Development Environment";
|
|
|
|
inputs = {
|
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
|
flake-utils.url = "github:numtide/flake-utils";
|
|
};
|
|
|
|
outputs = { self, nixpkgs, flake-utils }:
|
|
flake-utils.lib.eachDefaultSystem (system:
|
|
let
|
|
pkgs = nixpkgs.legacyPackages.${system};
|
|
|
|
# Python with required packages
|
|
python = pkgs.python311.withPackages (ps: with ps; [
|
|
flask
|
|
python-dotenv
|
|
nbformat
|
|
nbconvert
|
|
werkzeug
|
|
jinja2
|
|
markupsafe
|
|
itsdangerous
|
|
click
|
|
blinker
|
|
jupyter-core
|
|
traitlets
|
|
jupyter-client
|
|
ipython
|
|
bleach
|
|
defusedxml
|
|
mistune
|
|
pandocfilters
|
|
beautifulsoup4
|
|
webencodings
|
|
fastjsonschema
|
|
jsonschema
|
|
pyrsistent
|
|
pyzmq
|
|
tornado
|
|
nest-asyncio
|
|
psutil
|
|
packaging
|
|
platformdirs
|
|
debugpy
|
|
matplotlib-inline
|
|
pygments
|
|
cffi
|
|
argon2-cffi
|
|
jupyterlab-pygments
|
|
nbclient
|
|
tinycss2
|
|
]);
|
|
|
|
# Development tools
|
|
devTools = with pkgs; [
|
|
# Core development
|
|
python
|
|
nodejs_20
|
|
|
|
# System tools
|
|
curl
|
|
jq
|
|
tree
|
|
htop
|
|
|
|
# Container tools
|
|
docker
|
|
docker-compose
|
|
|
|
# Documentation tools
|
|
pandoc
|
|
|
|
# LaTeX for nbconvert
|
|
texlive.combined.scheme-medium
|
|
|
|
# Version control
|
|
git
|
|
|
|
# Text editors
|
|
vim
|
|
nano
|
|
|
|
# Network tools
|
|
netcat
|
|
|
|
# Process management
|
|
#supervisor
|
|
];
|
|
|
|
# Shell script for easy setup
|
|
setupScript = pkgs.writeShellScriptBin "setup-dev" ''
|
|
echo "Setting up JupyterHub Notebook Viewer development environment..."
|
|
|
|
# Create directories
|
|
mkdir -p shared notebooks templates
|
|
|
|
# Copy example .env if it doesn't exist
|
|
if [ ! -f .env ]; then
|
|
cp .env.example .env 2>/dev/null || echo "No .env.example found, using defaults"
|
|
fi
|
|
|
|
# Set up git hooks if in git repo
|
|
if [ -d .git ]; then
|
|
echo "Setting up git hooks..."
|
|
cp .githooks/* .git/hooks/ 2>/dev/null || true
|
|
fi
|
|
|
|
# Create sample notebook if shared directory is empty
|
|
if [ ! "$(ls -A shared)" ]; then
|
|
echo "Creating sample notebook..."
|
|
cat > shared/sample.ipynb << 'EOF'
|
|
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Sample Notebook\n",
|
|
"\n",
|
|
"This is a sample Jupyter notebook for testing the viewer."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"print('Hello from JupyterHub Notebook Viewer!')\n",
|
|
"import numpy as np\n",
|
|
"import matplotlib.pyplot as plt\n",
|
|
"\n",
|
|
"x = np.linspace(0, 10, 100)\n",
|
|
"y = np.sin(x)\n",
|
|
"\n",
|
|
"plt.figure(figsize=(10, 6))\n",
|
|
"plt.plot(x, y)\n",
|
|
"plt.title('Sample Plot')\n",
|
|
"plt.xlabel('X')\n",
|
|
"plt.ylabel('sin(x)')\n",
|
|
"plt.grid(True)\n",
|
|
"plt.show()"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"name": "python",
|
|
"version": "3.11.0"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 4
|
|
}
|
|
EOF
|
|
fi
|
|
|
|
echo "Development environment setup complete!"
|
|
echo "Run 'python app.py' to start the development server"
|
|
'';
|
|
|
|
# Script for running tests
|
|
testScript = pkgs.writeShellScriptBin "run-tests" ''
|
|
echo "Running tests for JupyterHub Notebook Viewer..."
|
|
|
|
# Basic import test
|
|
python -c "
|
|
import app
|
|
print('✓ App imports successfully')
|
|
|
|
# Test configuration loading
|
|
from dotenv import load_dotenv
|
|
load_dotenv()
|
|
print('✓ Environment variables loaded')
|
|
|
|
# Test nbconvert
|
|
import nbformat
|
|
import nbconvert
|
|
print('✓ Jupyter dependencies working')
|
|
"
|
|
|
|
# Test Flask app creation
|
|
python -c "
|
|
import app
|
|
test_app = app.app.test_client()
|
|
response = test_app.get('/')
|
|
if response.status_code in [200, 404]: # 404 is OK if no shared dir
|
|
print('✓ Flask app responds correctly')
|
|
else:
|
|
print('✗ Flask app error:', response.status_code)
|
|
exit(1)
|
|
"
|
|
|
|
echo "All tests passed!"
|
|
'';
|
|
|
|
# Development server with auto-reload
|
|
devServerScript = pkgs.writeShellScriptBin "dev-server" ''
|
|
echo "Starting development server with auto-reload..."
|
|
export FLASK_DEBUG=True
|
|
export FLASK_ENV=development
|
|
|
|
# Load .env file
|
|
if [ -f .env ]; then
|
|
export $(cat .env | grep -v '^#' | xargs)
|
|
fi
|
|
|
|
# Start the server
|
|
python app.py
|
|
'';
|
|
|
|
in
|
|
{
|
|
# Development shell
|
|
devShells.default = pkgs.mkShell {
|
|
buildInputs = devTools ++ [
|
|
setupScript
|
|
testScript
|
|
devServerScript
|
|
];
|
|
|
|
shellHook = ''
|
|
echo "🚀 JupyterHub Notebook Viewer Development Environment"
|
|
echo "=================================================="
|
|
echo ""
|
|
echo "Available commands:"
|
|
echo " setup-dev - Set up development environment"
|
|
echo " dev-server - Start development server with auto-reload"
|
|
echo " run-tests - Run basic tests"
|
|
echo " python app.py - Start the application"
|
|
echo ""
|
|
echo "Docker commands:"
|
|
echo " docker-compose up - Start with Docker"
|
|
echo " docker-compose up --build - Rebuild and start"
|
|
echo " docker-compose up -d - Start in background"
|
|
echo " docker-compose --profile with-proxy up - Start with nginx proxy"
|
|
echo ""
|
|
echo "Configuration:"
|
|
echo " Edit .env file to configure the application"
|
|
echo " JUPYTERHUB_SHARED_DIR: $(echo ''${JUPYTERHUB_SHARED_DIR:-/shared})"
|
|
echo ""
|
|
|
|
# Auto-setup on first run
|
|
if [ ! -f .env ] && [ ! -d shared ]; then
|
|
echo "First run detected, running setup..."
|
|
setup-dev
|
|
fi
|
|
'';
|
|
|
|
# Environment variables for development
|
|
FLASK_DEBUG = "True";
|
|
FLASK_ENV = "development";
|
|
PYTHONPATH = ".";
|
|
};
|
|
|
|
# Package for the application
|
|
packages.default = pkgs.stdenv.mkDerivation {
|
|
pname = "jupyterhub-notebook-viewer";
|
|
version = "1.0.0";
|
|
|
|
src = ./.;
|
|
|
|
buildInputs = [ python ];
|
|
|
|
installPhase = ''
|
|
mkdir -p $out/bin $out/share/jupyterhub-notebook-viewer
|
|
|
|
# Copy application files
|
|
cp app.py $out/share/jupyterhub-notebook-viewer/
|
|
cp -r templates $out/share/jupyterhub-notebook-viewer/
|
|
|
|
# Create wrapper script
|
|
cat > $out/bin/jupyterhub-notebook-viewer << EOF
|
|
#!${pkgs.bash}/bin/bash
|
|
cd $out/share/jupyterhub-notebook-viewer
|
|
exec ${python}/bin/python app.py "\$@"
|
|
EOF
|
|
chmod +x $out/bin/jupyterhub-notebook-viewer
|
|
'';
|
|
|
|
meta = with pkgs.lib; {
|
|
description = "Web viewer for JupyterHub shared notebooks";
|
|
license = licenses.mit;
|
|
platforms = platforms.unix;
|
|
};
|
|
};
|
|
|
|
# Docker image build
|
|
packages.docker = pkgs.dockerTools.buildImage {
|
|
name = "jupyterhub-notebook-viewer";
|
|
tag = "latest";
|
|
|
|
contents = [ python pkgs.pandoc ];
|
|
|
|
config = {
|
|
Cmd = [ "${python}/bin/python" "/app/app.py" ];
|
|
WorkingDir = "/app";
|
|
ExposedPorts = {
|
|
"5000/tcp" = {};
|
|
};
|
|
};
|
|
};
|
|
|
|
# Formatter for nix files
|
|
formatter = pkgs.nixpkgs-fmt;
|
|
});
|
|
}
|