{ 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; }); }