JupyShare/flake.nix

314 lines
9.0 KiB
Nix
Raw Normal View History

2025-06-17 13:06:48 +02:00
{
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
2025-06-23 16:52:42 +02:00
#supervisor
2025-06-17 13:06:48 +02:00
];
# 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;
});
}