commit df07954f74c10d05ac68f9b64cf32d6ddb1e3515 Author: Some One Date: Wed Aug 13 20:52:04 2025 +0200 diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..a38e18c --- /dev/null +++ b/flake.lock @@ -0,0 +1,44 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1754725699, + "narHash": "sha256-iAcj9T/Y+3DBy2J0N+yF9XQQQ8IEb5swLFzs23CdP88=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "85dbfc7aaf52ecb755f87e577ddbe6dbbdbc1054", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-old": { + "locked": { + "lastModified": 1754725699, + "narHash": "sha256-iAcj9T/Y+3DBy2J0N+yF9XQQQ8IEb5swLFzs23CdP88=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "85dbfc7aaf52ecb755f87e577ddbe6dbbdbc1054", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "nixpkgs-old": "nixpkgs-old" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..9bcdf9a --- /dev/null +++ b/flake.nix @@ -0,0 +1,30 @@ +{ + description = "A very basic flake"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + nixpkgs-old.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + }; + + outputs = + { + self, + nixpkgs, + nixpkgs-old, + }: + let + forAllSystems = + f: nixpkgs.lib.genAttrs [ "x86_64-linux" "aarch64-linux" ] (sys: let pkgs = import nixpkgs {system = sys; overlays = [self.overlays.default];}; in f pkgs); + myOverlay = + pkgs: + import ./overlay.nix { + inherit pkgs; + oldPkgs = nixpkgs-old.legacyPackages.${pkgs.hostPlatform.system}; + }; + in + { + overlays.default = final: _: myOverlay final; + + legacyPackages = forAllSystems (pkgs: myOverlay pkgs); + }; +} diff --git a/importlib.nix b/importlib.nix new file mode 100644 index 0000000..81a8104 --- /dev/null +++ b/importlib.nix @@ -0,0 +1,11 @@ +{stdenv, fetchPypi, python26Packages }: python26Packages.buildPythonPackage rec { + pname = "importlib"; + version = "1.0.2"; + pyproject = true; + + src = fetchPypi { + inherit pname version; + extension = "tar.gz"; + hash = "sha256-JNCWaqdoWbKISFgD8xAHZRL4c3fmya/pwoxSqMzdMow="; + }; +} diff --git a/jinja2.nix b/jinja2.nix new file mode 100644 index 0000000..24b7e91 --- /dev/null +++ b/jinja2.nix @@ -0,0 +1,16 @@ +{stdenv, fetchPypi, buildPythonPackage, setuptools }: buildPythonPackage rec { + pname = "Jinja2"; + version = "2.5.2"; + format = "setuptools"; + #pyproject = true; + + src = fetchPypi { + inherit pname version; + extension = "tar.gz"; + hash = "sha256-GQQPAbOp2MY+TVeTb3hxCQgZm2k3CrRKD3QH3YkfAZs="; + }; + + propagatedBuildInputs = [setuptools]; + + #dependencies = [importlib]; +} diff --git a/overlay.nix b/overlay.nix new file mode 100644 index 0000000..9e95788 --- /dev/null +++ b/overlay.nix @@ -0,0 +1,28 @@ +{ pkgs, oldPkgs }: +let +bommels = pkgs.lib.makeScope pkgs.newScope (self: rec { +# python26 = pkgs.callPackage ./python26/default.nix { +# self = python26; +# xlibsWrapper = pkgs.xlibsWrapper; +# }; + + setuptools = self.callPackage ./setuptools.nix { inherit pythonPackages; }; + #wrapPython = pkgs.callPackage ./python26/wrap-python.nix { python = python26; }; + #mkPythonDerivation = pkgs.callPackage ./python26/mk-python-derivation.nix { inherit setuptools wrapPython; python = python26; }; + #bootstrapped-pip = pkgs.callPackage ./python26/bootstrapped-pip.nix { python = python26; }; + #buildPythonPackage = pkgs.callPackage ./python26/build-python-package.nix { inherit bootstrapped-pip mkPythonDerivation; python = python26; }; + + #pip = pkgs.callPackage ./pip.nix { inherit python26 buildPythonPackage; }; + pythonInterpreters = self.callPackage ./python-interpreters.nix {}; + inherit (pythonInterpreters) python26; + python26Packages = python26.pkgs; + pythonPackages = python26Packages; + + #importlib = self.callPackage ./importlib.nix {}; + some-package = pkgs.callPackage ./some-package.nix { inherit pythonPackages; }; +}); +in +{ + inherit bommels; + inherit (bommels) python26; +} diff --git a/pip-install-hook.nix b/pip-install-hook.nix new file mode 100644 index 0000000..f6546fd --- /dev/null +++ b/pip-install-hook.nix @@ -0,0 +1,37 @@ +# Setup hook for pip. +# shellcheck shell=bash + +echo "Sourcing pip-install-hook" + +pipInstallPhase() { + echo "Executing pipInstallPhase" + runHook preInstall + + # shellcheck disable=SC2154 + mkdir -p "$out/@pythonSitePackages@" + export PYTHONPATH="$out/@pythonSitePackages@:$PYTHONPATH" + + local -a flagsArray=( + --no-index + --no-warn-script-location + --prefix="$out" + --no-cache + ) + concatTo flagsArray pipInstallFlags + + echo "Lolol" + + pushd dist || return 1 + echoCmd 'pip install flags' "${flagsArray[@]}" + # @pythonInterpreter@ -m pip install ./*.whl "${flagsArray[@]}" + @pip@ install ./*.whl "${flagsArray[@]}" + popd || return 1 + + runHook postInstall + echo "Finished executing pipInstallPhase" +} + +if [ -z "${dontUsePipInstall-}" ] && [ -z "${installPhase-}" ]; then + echo "Using pipInstallPhase" + installPhase=pipInstallPhase +fi diff --git a/pip.nix b/pip.nix new file mode 100644 index 0000000..4a5808a --- /dev/null +++ b/pip.nix @@ -0,0 +1,10 @@ +{stdenv, buildPythonPackage, fetchPypi, python26 }: buildPythonPackage rec { + pname = "pip"; + version = "9.0.3"; + pyproject = true; + + src = fetchPypi { + inherit pname version; + hash = ""; + }; +} diff --git a/python-imports-check-hook.sh b/python-imports-check-hook.sh new file mode 100644 index 0000000..c3c758d --- /dev/null +++ b/python-imports-check-hook.sh @@ -0,0 +1,28 @@ +# shellcheck shell=bash + +# Setup hook for checking whether Python imports succeed +echo "Sourcing python-imports-check-hook.sh" + +pythonImportsCheckPhase() { + echo "Executing pythonImportsCheckPhase" + + if [[ -n "${pythonImportsCheck[*]-}" ]]; then + echo "Check whether the following modules can be imported: ${pythonImportsCheck[*]}" + # shellcheck disable=SC2154 + pythonImportsCheckOutput="$out" + if [[ -n "${python-}" ]]; then + echo "Using python specific output \$python for imports check" + pythonImportsCheckOutput=$python + fi + export PYTHONPATH="$pythonImportsCheckOutput/@pythonSitePackages@:$PYTHONPATH" + # Python modules and namespaces names are Python identifiers, which must not contain spaces. + # See https://docs.python.org/3/reference/lexical_analysis.html + # shellcheck disable=SC2048,SC2086 + (cd "$pythonImportsCheckOutput" && @pythonCheckInterpreter@ -c 'import sys; import importlib; list(map(lambda mod: importlib.import_module(mod), sys.argv[1:]))' ${pythonImportsCheck[*]}) + fi +} + +if [[ -z "${dontUsePythonImportsCheck-}" ]]; then + echo "Using pythonImportsCheckPhase" + appendToVar preDistPhases pythonImportsCheckPhase +fi diff --git a/python-interpreters.nix b/python-interpreters.nix new file mode 100644 index 0000000..7c7acd5 --- /dev/null +++ b/python-interpreters.nix @@ -0,0 +1,80 @@ +{ + __splicedPackages, + callPackage, + fetchzip, + config, + db, + lib, + makeScopeWithSplicing', + pythonPackagesExtensions, + stdenv, + path +}@args: + +( + let + pythonBase = path + "/pkgs/development/interpreters/python"; + + # Common passthru for all Python interpreters. + passthruFun = import ( pythonBase + "/passthrufun.nix") args; + fixupString = s: lib.replaceString "2.7" "2.6" (lib.replaceString "2.7.1" "2.6.9" s); + + pythonRaw = ((callPackage "${pythonBase}/cpython/2.7" { + # TODO: splicedPackages again + self = __splicedPackages.python26; + sourceVersion = { + major = "2"; + minor = "6"; + patch = "9"; + suffix = ""; # ActiveState's Python 2 extended support + }; + hash = "sha256-uxXpGJ5rGPb5x0bIg5yqyQmyLKrjIl0LZjgApzsfd3Q="; + inherit passthruFun; + }).override { + rebuildBytecode = false; + pythonAttr = "python26"; + packageOverrides = import ./python-overrides.nix; + #packageOverridesss = _: super: { + # setupTools = "lol"; + #}; + }); + + in { + + python26 = pythonRaw.overrideAttrs (prev: { + patches = [ + # Look in C_INCLUDE_PATH and LIBRARY_PATH for stuff. + ./python26/search-path.patch + + # Python recompiles a Python if the mtime stored *in* the + # pyc/pyo file differs from the mtime of the source file. This + # doesn't work in Nix because Nix changes the mtime of files in + # the Nix store to 1. So treat that as a special case. + ./python26/nix-store-mtime.patch + + # http://bugs.python.org/issue10013 + ./python26/python2.6-fix-parallel-make.patch + ]; + postInstall = fixupString prev.postInstall; + preConfigure = lib.replaceString "${stdenv.cc.libc}/include/" "${stdenv.cc.libc.dev or stdenv.libc}/include/" prev.preConfigure; + }); + + pypy27 = callPackage ./pypy { + self = __splicedPackages.pypy27; + sourceVersion = { + major = "7"; + minor = "3"; + patch = "19"; + }; + + hash = "sha256-hwPNywH5+Clm3UO2pgGPFAOZ21HrtDwSXB+aIV57sAM="; + pythonVersion = "2.7"; + db = db.override { dbmSupport = !stdenv.hostPlatform.isDarwin; }; + python = __splicedPackages.pythonInterpreters.pypy27_prebuilt; + inherit passthruFun; + }; + } + // lib.optionalAttrs config.allowAliases { + pypy39_prebuilt = throw "pypy 3.9 has been removed, use pypy 3.10 instead"; # Added 2025-01-03 + } +) diff --git a/python-overrides.nix b/python-overrides.nix new file mode 100644 index 0000000..e6d854e --- /dev/null +++ b/python-overrides.nix @@ -0,0 +1,40 @@ +self: super: + +let + pipFunction = {fetchFromGitHub}: rec {version = "9.0.3";src = fetchFromGitHub {owner = "pypa"; repo = "pip"; rev = version; hash = "sha256-ei5ru7kr6m+VJYcYMH8Fjya1eqBqkOaC4+JwDqTd46Q=";};}; +in +with self; +with super; +rec { + bootstrapped-pip = toPythonModule (callPackage ./python26/bootstrapped-pip.nix {}); + + pipInstallHookMine = callPackage ( + { makePythonHook, pip }: + makePythonHook { + name = "pip-install-hook"; + propagatedBuildInputs = [ pip ]; + substitutions = { + inherit pythonInterpreter pythonSitePackages pip; + }; + } ./pip-install-hook.sh + ) { }; + pipInstallHook = pipInstallHookMine; + pythonImportsCheckHookMine = callPackage ( + { makePythonHook }: + makePythonHook { + name = "python-imports-check-hook"; + substitutions = { + inherit pythonInterpreter pythonSitePackages; + }; + } ./python-imports-check-hook.sh + ) { }; + pythonImportsCheckHook = pythonImportsCheckHookMine; + + setuptools = toPythonModule (callPackage ./setuptools.nix { }); + wheel = callPackage ./python26/wheel.nix { }; + #pip = pip.overridePythonAttrs (callPackage pipFunction {}); + + bommels = { + jinja2 = callPackage ./jinja2.nix { }; + }; +} diff --git a/python26/bootstrapped-pip.nix b/python26/bootstrapped-pip.nix new file mode 100644 index 0000000..4b1c836 --- /dev/null +++ b/python26/bootstrapped-pip.nix @@ -0,0 +1,56 @@ +{ lib, stdenv, python, fetchurl, makeWrapper, unzip }: + +let + wheel_source = fetchurl { + url = "https://pypi.python.org/packages/py2.py3/w/wheel/wheel-0.29.0-py2.py3-none-any.whl"; + sha256 = "ea8033fc9905804e652f75474d33410a07404c1a78dd3c949a66863bd1050ebd"; + }; + setuptools_source = fetchurl { + url = "https://files.pythonhosted.org/packages/b8/cb/b919f52dd81b4b2210d0c5529b6b629a4002e08d49a90183605d1181b10c/setuptools-30.2.0-py2.py3-none-any.whl"; + sha256 = "b7e7b28d6a728ea38953d66e12ef400c3c153c523539f1b3997c5a42f3770ff1"; + }; + argparse_source = fetchurl { + url = "https://pypi.python.org/packages/2.7/a/argparse/argparse-1.4.0-py2.py3-none-any.whl"; + sha256 = "0533cr5w14da8wdb2q4py6aizvbvsdbk3sj7m1jx9lwznvnlf5n3"; + }; +in stdenv.mkDerivation rec { + name = "${python.libPrefix}-bootstrapped-pip-${version}"; + version = "9.0.1"; + + src = fetchurl { + url = "https://files.pythonhosted.org/packages/b6/ac/7015eb97dc749283ffdec1c3a88ddb8ae03b8fad0f0e611408f196358da3/pip-9.0.1-py2.py3-none-any.whl"; + sha256 = "690b762c0a8460c303c089d5d0be034fb15a5ea2b75bdf565f40421f542fefb0"; + }; + + unpackPhase = '' + mkdir -p $out/${python.sitePackages} + unzip -d $out/${python.sitePackages} $src + unzip -d $out/${python.sitePackages} ${setuptools_source} + unzip -d $out/${python.sitePackages} ${wheel_source} + '' + lib.optionalString (python.isPy26 or true) '' + unzip -d $out/${python.sitePackages} ${argparse_source} + ''; + + + patchPhase = '' + mkdir -p $out/bin + ''; + + buildInputs = [ python makeWrapper unzip ]; + + installPhase = '' + runHook preInstall + + # install pip binary + echo '#!${python.interpreter}' > $out/bin/pip + echo 'import sys;from pip import main' >> $out/bin/pip + echo 'sys.exit(main())' >> $out/bin/pip + chmod +x $out/bin/pip + + # wrap binaries with PYTHONPATH + for f in $out/bin/*; do + wrapProgram $f --prefix PYTHONPATH ":" $out/${python.sitePackages}/ + done + runHook postInstall + ''; +} diff --git a/python26/build-python-package-common.nix b/python26/build-python-package-common.nix new file mode 100644 index 0000000..2b383fe --- /dev/null +++ b/python26/build-python-package-common.nix @@ -0,0 +1,32 @@ +# This function provides generic bits to install a Python wheel. + +{ python +, bootstrapped-pip +}: + +{ buildInputs ? [] +# Additional flags to pass to "pip install". +, installFlags ? [] +, ... } @ attrs: + +attrs // { + buildInputs = buildInputs ++ [ bootstrapped-pip ]; + + configurePhase = attrs.configurePhase or '' + runHook preConfigure + runHook postConfigure + ''; + + installPhase = attrs.installPhase or '' + runHook preInstall + + mkdir -p "$out/${python.sitePackages}" + export PYTHONPATH="$out/${python.sitePackages}:$PYTHONPATH" + + pushd dist + ${bootstrapped-pip}/bin/pip install *.whl --no-index --prefix=$out --no-cache ${toString installFlags} --build tmpbuild + popd + + runHook postInstall + ''; +} diff --git a/python26/build-python-package-setuptools.nix b/python26/build-python-package-setuptools.nix new file mode 100644 index 0000000..a09febb --- /dev/null +++ b/python26/build-python-package-setuptools.nix @@ -0,0 +1,56 @@ +# This function provides specific bits for building a setuptools-based Python package. + +{ lib +, python +, bootstrapped-pip +}: + +{ +# passed to "python setup.py build_ext" +# https://github.com/pypa/pip/issues/881 + setupPyBuildFlags ? [] +# Execute before shell hook +, preShellHook ? "" +# Execute after shell hook +, postShellHook ? "" +, ... } @ attrs: + +let + # use setuptools shim (so that setuptools is imported before distutils) + # pip does the same thing: https://github.com/pypa/pip/pull/3265 + setuppy = ./run_setup.py; + +in attrs // { + # we copy nix_run_setup.py over so it's executed relative to the root of the source + # many project make that assumption + buildPhase = attrs.buildPhase or '' + runHook preBuild + cp ${setuppy} nix_run_setup.py + ${python.interpreter} nix_run_setup.py ${lib.optionalString (setupPyBuildFlags != []) ("build_ext " + (lib.concatStringsSep " " setupPyBuildFlags))} bdist_wheel + runHook postBuild + ''; + + installCheckPhase = attrs.checkPhase or '' + runHook preCheck + ${python.interpreter} nix_run_setup.py test + runHook postCheck + ''; + + # Python packages that are installed with setuptools + # are typically distributed with tests. + # With Python it's a common idiom to run the tests + # after the software has been installed. + doCheck = attrs.doCheck or true; + + shellHook = attrs.shellHook or '' + ${preShellHook} + if test -e setup.py; then + tmp_path=$(mktemp -d) + export PATH="$tmp_path/bin:$PATH" + export PYTHONPATH="$tmp_path/${python.sitePackages}:$PYTHONPATH" + mkdir -p $tmp_path/${python.sitePackages} + ${bootstrapped-pip}/bin/pip install -e . --prefix $tmp_path >&2 + fi + ${postShellHook} + ''; +} diff --git a/python26/build-python-package-wheel.nix b/python26/build-python-package-wheel.nix new file mode 100644 index 0000000..7be0a4c --- /dev/null +++ b/python26/build-python-package-wheel.nix @@ -0,0 +1,20 @@ +# This function provides specific bits for building a wheel-based Python package. + +{ +}: + +{ ... } @ attrs: + +attrs // { + unpackPhase = '' + mkdir dist + cp $src dist/"''${src#*-}" + ''; + + # Wheels are pre-compiled + buildPhase = attrs.buildPhase or ":"; + installCheckPhase = attrs.checkPhase or ":"; + + # Wheels don't have any checks to run + doCheck = attrs.doCheck or false; +} \ No newline at end of file diff --git a/python26/build-python-package.nix b/python26/build-python-package.nix new file mode 100644 index 0000000..91c9479 --- /dev/null +++ b/python26/build-python-package.nix @@ -0,0 +1,34 @@ +/* This function provides a generic Python package builder. It is + intended to work with packages that use `distutils/setuptools' + (http://pypi.python.org/pypi/setuptools/), which represents a large + number of Python packages nowadays. */ + +{ lib +, python +, mkPythonDerivation +, bootstrapped-pip +}: + +let + setuptools-specific = import ./build-python-package-setuptools.nix { inherit lib python bootstrapped-pip; }; + wheel-specific = import ./build-python-package-wheel.nix { }; + common = import ./build-python-package-common.nix { inherit python bootstrapped-pip; }; +in + +{ +# Several package formats are supported. +# "setuptools" : Install a common setuptools/distutils based package. This builds a wheel. +# "wheel" : Install from a pre-compiled wheel. +# "flit" : Install a flit package. This builds a wheel. +# "other" : Provide your own buildPhase and installPhase. +format ? "setuptools" +, ... } @ attrs: + +let + formatspecific = + if format == "setuptools" then common (setuptools-specific attrs) + else if format == "wheel" then common (wheel-specific attrs) + else if format == "other" then {} + else throw "Unsupported format ${format}"; + +in mkPythonDerivation ( attrs // formatspecific ) diff --git a/python26/default.nix b/python26/default.nix new file mode 100644 index 0000000..4154307 --- /dev/null +++ b/python26/default.nix @@ -0,0 +1,216 @@ +{ lib, stdenv, fetchurl, zlib ? null, zlibSupport ? true, bzip2, includeModules ? false +, sqlite, tcl, tk, xlibsWrapper, openssl, readline, db, ncurses, gdbm, self, callPackage +/*, python26Packages*/ }: + +assert zlibSupport -> zlib != null; + +let + majorVersion = "2.6"; + version = "${majorVersion}.9"; + + src = fetchurl { + url = "http://www.python.org/ftp/python/${version}/Python-${version}.tar.xz"; + sha256 = "0hbfs2691b60c7arbysbzr0w9528d5pl8a4x7mq5psh6a2cvprya"; + }; + + patches = + [ # Look in C_INCLUDE_PATH and LIBRARY_PATH for stuff. + ./search-path.patch + + # Python recompiles a Python if the mtime stored *in* the + # pyc/pyo file differs from the mtime of the source file. This + # doesn't work in Nix because Nix changes the mtime of files in + # the Nix store to 1. So treat that as a special case. + ./nix-store-mtime.patch + + # http://bugs.python.org/issue10013 + ./python2.6-fix-parallel-make.patch + ]; + + preConfigure = '' + # Purity. + for i in /usr /sw /opt /pkg; do + substituteInPlace ./setup.py --replace $i /no-such-path + done + '' + lib.optionalString (stdenv ? cc && stdenv.cc.libc != null) '' + for i in Lib/plat-*/regen; do + substituteInPlace $i --replace /usr/include/ ${stdenv.cc.libc.dev or stdenv.cc.libc}/include/ + done + '' + lib.optionalString stdenv.isCygwin '' + # On Cygwin, `make install' tries to read this Makefile. + mkdir -p $out/lib/python${majorVersion}/config + touch $out/lib/python${majorVersion}/config/Makefile + mkdir -p $out/include/python${majorVersion} + touch $out/include/python${majorVersion}/pyconfig.h + ''; + + configureFlags = ["--enable-shared" "--with-threads" "--enable-unicode=ucs4"]; + + buildInputs = + lib.optional (stdenv ? cc && stdenv.cc.libc != null) stdenv.cc.libc ++ + [ bzip2 openssl ]++ lib.optionals includeModules [ db openssl ncurses gdbm readline xlibsWrapper tcl tk sqlite ] + ++ lib.optional zlibSupport zlib; + + mkPaths = paths: { + C_INCLUDE_PATH = lib.makeSearchPathOutput "dev" "include" paths; + LIBRARY_PATH = lib.makeLibraryPath paths; + }; + + # Build the basic Python interpreter without modules that have + # external dependencies. + python = stdenv.mkDerivation { + name = "python${if includeModules then "" else "-minimal"}-${version}"; + pythonVersion = majorVersion; + + inherit majorVersion version src patches buildInputs preConfigure + configureFlags; + + inherit (mkPaths buildInputs) C_INCLUDE_PATH LIBRARY_PATH; + + NIX_CFLAGS_COMPILE = lib.optionalString stdenv.isDarwin "-msse2"; + + setupHook = ./setup-hook.sh; + + postInstall = + '' + # needed for some packages, especially packages that backport + # functionality to 2.x from 3.x + for item in $out/lib/python${majorVersion}/test/*; do + if [[ "$item" != */test_support.py* ]]; then + rm -rf "$item" + fi + done + touch $out/lib/python${majorVersion}/test/__init__.py + ln -s $out/lib/python${majorVersion}/pdb.py $out/bin/pdb + ln -s $out/lib/python${majorVersion}/pdb.py $out/bin/pdb${majorVersion} + mv $out/share/man/man1/{python.1,python2.6.1} + ln -s $out/share/man/man1/{python2.6.1,python.1} + + #paxmark E $out/bin/python${majorVersion} + + ${ lib.optionalString includeModules "$out/bin/python ./setup.py build_ext"} + + rm "$out"/lib/python*/plat-*/regen # refers to glibc.dev + ''; + + passthru = rec { + inherit zlibSupport; + isPy2 = true; + isPy26 = true; + buildEnv = callPackage ./wrapper.nix { python = self; }; + #withPackages = import ../../with-packages.nix { inherit buildEnv; pythonPackages = python26Packages; }; + libPrefix = "python${majorVersion}"; + executable = libPrefix; + sitePackages = "lib/${libPrefix}/site-packages"; + interpreter = "${self}/bin/${executable}"; + }; + + enableParallelBuilding = true; + + meta = { + homepage = "http://python.org"; + description = "A high-level dynamically-typed programming language"; + longDescription = '' + Python is a remarkably powerful dynamic programming language that + is used in a wide variety of application domains. Some of its key + distinguishing features include: clear, readable syntax; strong + introspection capabilities; intuitive object orientation; natural + expression of procedural code; full modularity, supporting + hierarchical packages; exception-based error handling; and very + high level dynamic data types. + ''; + license = lib.licenses.psfl; + platforms = lib.platforms.all; + maintainers = with lib.maintainers; [ chaoflow domenkozar ]; + # If you want to use Python 2.6, remove "broken = true;" at your own + # risk. Python 2.6 has known security vulnerabilities is not receiving + # security updates as of October 2013. + #broken = true; + }; + }; + + + # This function builds a Python module included in the main Python + # distribution in a separate derivation. + buildInternalPythonModule = + { moduleName + , internalName ? "_" + moduleName + , deps + }: + if includeModules then null else stdenv.mkDerivation rec { + name = "python-${moduleName}-${python.version}"; + + inherit src patches preConfigure configureFlags; + + buildInputs = [ python ] ++ deps; + + inherit (mkPaths buildInputs) C_INCLUDE_PATH LIBRARY_PATH; + + buildPhase = + '' + substituteInPlace setup.py --replace 'self.extensions = extensions' \ + 'self.extensions = [ext for ext in self.extensions if ext.name in ["${internalName}"]]' + + python ./setup.py build_ext + [ -z "$(find build -name '*_failed.so' -print)" ] + ''; + + installPhase = + '' + dest=$out/lib/${python.libPrefix}/site-packages + mkdir -p $dest + cp -p $(find . -name "*.${if stdenv.isCygwin then "dll" else "so"}") $dest/ + ''; + }; + + + # The Python modules included in the main Python distribution, built + # as separate derivations. + modules = { + + bsddb = buildInternalPythonModule { + moduleName = "bsddb"; + deps = [ db ]; + }; + + crypt = buildInternalPythonModule { + moduleName = "crypt"; + internalName = "crypt"; + deps = lib.optional (stdenv ? glibc) stdenv.glibc; + }; + + curses = buildInternalPythonModule { + moduleName = "curses"; + deps = [ ncurses ]; + }; + + curses_panel = buildInternalPythonModule { + moduleName = "curses_panel"; + deps = [ ncurses modules.curses ]; + }; + + gdbm = buildInternalPythonModule { + moduleName = "gdbm"; + internalName = "gdbm"; + deps = [ gdbm ]; + }; + + sqlite3 = buildInternalPythonModule { + moduleName = "sqlite3"; + deps = [ sqlite ]; + }; + + tkinter = buildInternalPythonModule { + moduleName = "tkinter"; + deps = [ tcl tk xlibsWrapper ]; + }; + + readline = buildInternalPythonModule { + moduleName = "readline"; + internalName = "readline"; + deps = [ readline ]; + }; + + }; + +in python // { inherit modules; } diff --git a/python26/mk-python-derivation.nix b/python26/mk-python-derivation.nix new file mode 100644 index 0000000..69eea05 --- /dev/null +++ b/python26/mk-python-derivation.nix @@ -0,0 +1,102 @@ +/* Generic builder for Python packages that come without a setup.py. */ + +{ lib +, python +, wrapPython +, setuptools +, unzip +, ensureNewerSourcesHook +}: + +{ name + +# by default prefix `name` e.g. "python3.3-${name}" +, namePrefix ? python.libPrefix + "-" + +# Dependencies for building the package +, buildInputs ? [] + +# Dependencies needed for running the checkPhase. +# These are added to buildInputs when doCheck = true. +, checkInputs ? [] + +# propagate build dependencies so in case we have A -> B -> C, +# C can import package A propagated by B +, propagatedBuildInputs ? [] + +# DEPRECATED: use propagatedBuildInputs +, pythonPath ? [] + +# used to disable derivation, useful for specific python versions +, disabled ? false + +# Raise an error if two packages are installed with the same name +, catchConflicts ? true + +# Additional arguments to pass to the makeWrapper function, which wraps +# generated binaries. +, makeWrapperArgs ? [] + +, meta ? {} + +, passthru ? {} + +, doCheck ? false + +, ... } @ attrs: + + +# Keep extra attributes from `attrs`, e.g., `patchPhase', etc. +if disabled +then throw "${name} not supported for interpreter ${python.executable}" +else + +python.stdenv.mkDerivation (builtins.removeAttrs attrs ["disabled"] // { + + name = namePrefix + name; + + inherit pythonPath; + + + # Determinism: The interpreter is patched to write null timestamps when compiling python files. + # This way python doesn't try to update them when we freeze timestamps in nix store. + DETERMINISTIC_BUILD=1; + # Determinism: We fix the hashes of str, bytes and datetime objects. + PYTHONHASHSEED = 0; + + buildInputs = [ wrapPython ] ++ buildInputs ++ pythonPath + ++ [ (ensureNewerSourcesHook { year = "1980"; }) ] + ++ (lib.optional (lib.hasSuffix "zip" attrs.src.name or "") unzip) + ++ lib.optionals doCheck checkInputs; + + # propagate python/setuptools to active setup-hook in nix-shell + propagatedBuildInputs = propagatedBuildInputs ++ [ python setuptools ]; + + # Python packages don't have a checkPhase, only an installCheckPhase + doCheck = false; + doInstallCheck = doCheck; + + postFixup = '' + wrapPythonPrograms + '' + lib.optionalString catchConflicts '' + # check if we have two packages with the same name in closure and fail + # this shouldn't happen, something went wrong with dependencies specs + ${python.interpreter} ${./catch_conflicts.py} + '' + attrs.postFixup or ''''; + + passthru = { + inherit python; # The python interpreter + } // passthru; + + meta = with lib.maintainers; { + # default to python's platforms + platforms = python.meta.platforms; + } // meta // { + # add extra maintainer(s) to every package + maintainers = (meta.maintainers or []) ++ [ chaoflow domenkozar ]; + # a marker for release utilities to discover python packages + isBuildPythonPackage = python.meta.platforms; + }; +}) + + diff --git a/python26/nix-store-mtime.patch b/python26/nix-store-mtime.patch new file mode 100644 index 0000000..83f3fea --- /dev/null +++ b/python26/nix-store-mtime.patch @@ -0,0 +1,12 @@ +diff -ru -x '*~' Python-2.7.1-orig/Python/import.c Python-2.7.1/Python/import.c +--- Python-2.7.1-orig/Python/import.c 2010-05-20 20:37:55.000000000 +0200 ++++ Python-2.7.1/Python/import.c 2011-01-04 15:55:11.000000000 +0100 +@@ -751,7 +751,7 @@ + return NULL; + } + pyc_mtime = PyMarshal_ReadLongFromFile(fp); +- if (pyc_mtime != mtime) { ++ if (pyc_mtime != mtime && mtime != 1) { + if (Py_VerboseFlag) + PySys_WriteStderr("# %s has bad mtime\n", cpathname); + fclose(fp); diff --git a/python26/python2.6-fix-parallel-make.patch b/python26/python2.6-fix-parallel-make.patch new file mode 100644 index 0000000..c43e141 --- /dev/null +++ b/python26/python2.6-fix-parallel-make.patch @@ -0,0 +1,37 @@ +diff -up Python-2.7/Makefile.pre.in.fix-parallel-make Python-2.7/Makefile.pre.in +--- Python-2.7/Makefile.pre.in.fix-parallel-make 2010-07-22 15:01:39.567996932 -0400 ++++ Python-2.7/Makefile.pre.in 2010-07-22 15:47:02.437998509 -0400 +@@ -207,6 +207,7 @@ SIGNAL_OBJS= @SIGNAL_OBJS@ + + ########################################################################## + # Grammar ++GRAMMAR_STAMP= $(srcdir)/grammar-stamp + GRAMMAR_H= $(srcdir)/Include/graminit.h + GRAMMAR_C= $(srcdir)/Python/graminit.c + GRAMMAR_INPUT= $(srcdir)/Grammar/Grammar +@@ -530,10 +531,24 @@ Modules/getpath.o: $(srcdir)/Modules/get + Modules/python.o: $(srcdir)/Modules/python.c + $(MAINCC) -c $(PY_CFLAGS) -o $@ $(srcdir)/Modules/python.c + ++# GNU "make" interprets rules with two dependents as two copies of the rule. ++# ++# In a parallel build this can lead to pgen being run twice, once for each of ++# GRAMMAR_H and GRAMMAR_C, leading to race conditions in which the compiler ++# reads a partially-overwritten copy of one of these files, leading to syntax ++# errors (or linker errors if the fragment happens to be syntactically valid C) ++# ++# See http://www.gnu.org/software/hello/manual/automake/Multiple-Outputs.html ++# for more information ++# ++# Introduce ".grammar-stamp" as a contrived single output from PGEN to avoid ++# this: ++$(GRAMMAR_H) $(GRAMMAR_C): $(GRAMMAR_STAMP) + +-$(GRAMMAR_H) $(GRAMMAR_C): $(PGEN) $(GRAMMAR_INPUT) ++$(GRAMMAR_STAMP): $(PGEN) $(GRAMMAR_INPUT) + -@$(INSTALL) -d Include + -$(PGEN) $(GRAMMAR_INPUT) $(GRAMMAR_H) $(GRAMMAR_C) ++ touch $(GRAMMAR_STAMP) + + $(PGEN): $(PGENOBJS) + $(CC) $(OPT) $(LDFLAGS) $(PGENOBJS) $(LIBS) -o $(PGEN) diff --git a/python26/search-path.patch b/python26/search-path.patch new file mode 100644 index 0000000..2e7b752 --- /dev/null +++ b/python26/search-path.patch @@ -0,0 +1,27 @@ +diff -rc Python-2.4.4-orig/setup.py Python-2.4.4/setup.py +*** Python-2.4.4-orig/setup.py 2006-10-08 19:41:25.000000000 +0200 +--- Python-2.4.4/setup.py 2007-05-27 16:04:54.000000000 +0200 +*************** +*** 279,288 **** + # Check for AtheOS which has libraries in non-standard locations + if platform == 'atheos': + lib_dirs += ['/system/libs', '/atheos/autolnk/lib'] +- lib_dirs += os.getenv('LIBRARY_PATH', '').split(os.pathsep) + inc_dirs += ['/system/include', '/atheos/autolnk/include'] +- inc_dirs += os.getenv('C_INCLUDE_PATH', '').split(os.pathsep) + + # OSF/1 and Unixware have some stuff in /usr/ccs/lib (like -ldb) + if platform in ['osf1', 'unixware7', 'openunix8']: + lib_dirs += ['/usr/ccs/lib'] +--- 279,289 ---- + # Check for AtheOS which has libraries in non-standard locations + if platform == 'atheos': + lib_dirs += ['/system/libs', '/atheos/autolnk/lib'] + inc_dirs += ['/system/include', '/atheos/autolnk/include'] + ++ lib_dirs += os.getenv('LIBRARY_PATH', '').split(os.pathsep) ++ inc_dirs += os.getenv('C_INCLUDE_PATH', '').split(os.pathsep) ++ + # OSF/1 and Unixware have some stuff in /usr/ccs/lib (like -ldb) + if platform in ['osf1', 'unixware7', 'openunix8']: + lib_dirs += ['/usr/ccs/lib'] diff --git a/python26/setup-hook.sh b/python26/setup-hook.sh new file mode 100644 index 0000000..4caff9c --- /dev/null +++ b/python26/setup-hook.sh @@ -0,0 +1,15 @@ +addPythonPath() { + addToSearchPathWithCustomDelimiter : PYTHONPATH $1/lib/python2.6/site-packages +} + +toPythonPath() { + local paths="$1" + local result= + for i in $paths; do + p="$i/lib/python2.6/site-packages" + result="${result}${result:+:}$p" + done + echo $result +} + +envHooks+=(addPythonPath) diff --git a/python26/wheel.nix b/python26/wheel.nix new file mode 100644 index 0000000..2418503 --- /dev/null +++ b/python26/wheel.nix @@ -0,0 +1,44 @@ +{ lib +, buildPythonPackage +, fetchPypi +, jsonschema +, bootstrapped-pip +, setuptools +, fetchFromGitHub +}: + +buildPythonPackage rec { + pname = "wheel"; + version = "0.29.0"; + format = "setuptools"; + + #src = fetchPypi { + # inherit pname version; + # sha256 = "1ebb8ad7e26b448e9caa4773d2357849bf80ff9e313964bcaf79cbf0201a1648"; + #}; + src = fetchFromGitHub { + owner = "pypa"; + repo = pname; + rev = version; + name = "${pname}-${version}-source"; + hash = "sha256-HedK21Lykt1dbq1wIKGlInuEWV4WezjV2Q2YX+0vyO8="; + }; + + #buildInputs = [ pytest pytestcov coverage ]; + #nativeBuildInputs = [ bootstrapped-pip setuptools ]; + + #catchConflicts = false; + + #doCheck = false; + + #pythonImportsCheck = [ "wheel" ]; + + # We add this flag to ignore the copy installed by bootstrapped-pip + installFlags = [ "--ignore-installed" ]; + + meta = { + description = "A built-package format for Python"; + license = with lib.licenses; [ mit ]; + homepage = "https://bitbucket.org/pypa/wheel/"; + }; +} diff --git a/python26/wrap-python.nix b/python26/wrap-python.nix new file mode 100644 index 0000000..1efd777 --- /dev/null +++ b/python26/wrap-python.nix @@ -0,0 +1,51 @@ +{ lib +, python +, makeSetupHook +, makeWrapper }: + +with lib; + +makeSetupHook { + deps = makeWrapper; + substitutions.libPrefix = python.libPrefix; + substitutions.executable = python.interpreter; + substitutions.python = python; + substitutions.magicalSedExpression = let + # Looks weird? Of course, it's between single quoted shell strings. + # NOTE: Order DOES matter here, so single character quotes need to be + # at the last position. + quoteVariants = [ "'\"'''\"'" "\"\"\"" "\"" "'\"'\"'" ]; # hey Vim: '' + + mkStringSkipper = labelNum: quote: let + label = "q${toString labelNum}"; + isSingle = elem quote [ "\"" "'\"'\"'" ]; + endQuote = if isSingle then "[^\\\\]${quote}" else quote; + in '' + /^[a-z]?${quote}/ { + /${quote}${quote}|${quote}.*${endQuote}/{n;br} + :${label}; n; /^${quote}/{n;br}; /${endQuote}/{n;br}; b${label} + } + ''; + + # This preamble does two things: + # * Sets argv[0] to the original application's name; otherwise it would be .foo-wrapped. + # Python doesn't support `exec -a`. + # * Adds all required libraries to sys.path via `site.addsitedir`. It also handles *.pth files. + preamble = '' + import sys + import site + import functools + sys.argv[0] = '"'$(readlink -f "$f")'"' + functools.reduce(lambda k, p: site.addsitedir(p, k), ['"$([ -n "$program_PYTHONPATH" ] && (echo "'$program_PYTHONPATH'" | sed "s|:|','|g") || true)"'], site._init_pathinfo()) + ''; + + in '' + 1 { + :r + /\\$|,$/{N;br} + /__future__|^ |^ *(#.*)?$/{n;br} + ${concatImapStrings mkStringSkipper quoteVariants} + /^[^# ]/i ${replaceStrings ["\n"] [";"] preamble} + } + ''; +} ./wrap.sh diff --git a/python26/wrapper.nix b/python26/wrapper.nix new file mode 100644 index 0000000..ba39965 --- /dev/null +++ b/python26/wrapper.nix @@ -0,0 +1,54 @@ +{ stdenv, python, buildEnv, makeWrapper +, extraLibs ? [] +, postBuild ? "" +, ignoreCollisions ? false }: + +# Create a python executable that knows about additional packages. +let + recursivePthLoader = import ../../python-modules/recursive-pth-loader/default.nix { stdenv = stdenv; python = python; }; + env = ( + let + paths = stdenv.lib.filter (x : x ? pythonPath) (stdenv.lib.closePropagation extraLibs) ++ [ python recursivePthLoader ]; + in buildEnv { + name = "${python.name}-env"; + + inherit paths; + inherit ignoreCollisions; + + postBuild = '' + . "${makeWrapper}/nix-support/setup-hook" + + if [ -L "$out/bin" ]; then + unlink "$out/bin" + fi + mkdir -p "$out/bin" + + for path in ${stdenv.lib.concatStringsSep " " paths}; do + if [ -d "$path/bin" ]; then + cd "$path/bin" + for prg in *; do + if [ -f "$prg" ]; then + rm -f "$out/bin/$prg" + makeWrapper "$path/bin/$prg" "$out/bin/$prg" --set PYTHONHOME "$out" + fi + done + fi + done + '' + postBuild; + + passthru.env = stdenv.mkDerivation { + name = "interactive-${python.name}-environment"; + nativeBuildInputs = [ env ]; + + buildCommand = '' + echo >&2 "" + echo >&2 "*** Python 'env' attributes are intended for interactive nix-shell sessions, not for building! ***" + echo >&2 "" + exit 1 + ''; + }; + }) // { + inherit python; + inherit (python) meta; + }; +in env diff --git a/result b/result new file mode 120000 index 0000000..41ef4f2 --- /dev/null +++ b/result @@ -0,0 +1 @@ +/nix/store/b5d52gx1g9lwihsqgkdgm606nb1hni57-python2.6-wheel-0.29.0 \ No newline at end of file diff --git a/setuptools.nix b/setuptools.nix new file mode 100644 index 0000000..55d6df3 --- /dev/null +++ b/setuptools.nix @@ -0,0 +1,40 @@ +{ lib, + stdenv +, fetchPypi +, python +, wrapPython +, unzip +}: + +# Should use buildPythonPackage here somehow +stdenv.mkDerivation rec { + pname = "setuptools"; + version = "36.8.0"; + name = "${python.libPrefix}-${pname}-${version}"; + + src = fetchPypi { + inherit pname version; + extension = "zip"; + hash = "sha256-sqpaAOnk/SDzw91BLUkJIXRu/hS9o01TlzxKWasFs10="; + }; + + buildInputs = [ python wrapPython unzip ]; + doCheck = false; # requires pytest + installPhase = '' + dst=$out/${python.sitePackages} + mkdir -p $dst + export PYTHONPATH="$dst:$PYTHONPATH" + ${python.interpreter} setup.py install --prefix=$out + wrapPythonPrograms + ''; + + pythonPath = []; + + meta = with lib; { + description = "Utilities to facilitate the installation of Python packages"; + homepage = http://pypi.python.org/pypi/setuptools; + license = with licenses; [ psfl zpl20 ]; + platforms = platforms.all; + priority = 10; + }; +} diff --git a/some-package.nix b/some-package.nix new file mode 100644 index 0000000..b99c256 --- /dev/null +++ b/some-package.nix @@ -0,0 +1,8 @@ +{stdenv, path }: stdenv.mkDerivation { + pname = "abc"; + version = "0.1.0"; + #src = ./some-package.nix; + builder = '' + ''; + PATH_TEST=path; +}