From 30794845eee95561ef53c48491c54c8db37e52cc Mon Sep 17 00:00:00 2001
From: Marc Weber <marco-oweber@gmx.de>
Date: Tue, 2 Dec 2008 12:27:05 +0000
Subject: [PATCH] python 25 proposal

svn path=/nixpkgs/trunk/; revision=13547
---
 .../interpreters/python-new/2.5/default.nix   | 306 ++++++++++++++++++
 .../python-new/2.5/nix-find-sites-2.5.patch   |  33 ++
 .../interpreters/python-new/2.5/python.nix    |  69 ++++
 .../python-new/2.5/search-path.patch          |  28 ++
 pkgs/top-level/all-packages.nix               |  10 +
 5 files changed, 446 insertions(+)
 create mode 100644 pkgs/development/interpreters/python-new/2.5/default.nix
 create mode 100644 pkgs/development/interpreters/python-new/2.5/nix-find-sites-2.5.patch
 create mode 100644 pkgs/development/interpreters/python-new/2.5/python.nix
 create mode 100644 pkgs/development/interpreters/python-new/2.5/search-path.patch

diff --git a/pkgs/development/interpreters/python-new/2.5/default.nix b/pkgs/development/interpreters/python-new/2.5/default.nix
new file mode 100644
index 000000000000..e75d5c3a47fb
--- /dev/null
+++ b/pkgs/development/interpreters/python-new/2.5/default.nix
@@ -0,0 +1,306 @@
+# the nix-python way..
+
+# By default python looks in the $prefix/lib/python-$version/site-packages directory
+# and reads the .pth files to add the library paths to sys.path. 
+# Using PYHTONPATH is not enough because it doesn't make python read the .pth files
+# telling python where to find additional modules. PYTHONUSERBASE would suffice, but
+# it only supports *one* user location. That's why I've added the new env var NIX_PYTHON_SITES
+# containing a colon separated list of modules telling python where to look
+# for imports and also read the .pth files
+
+p: # p = pkgs
+let 
+  inherit (p) lib fetchurl stdenv getConfig;
+in
+  lib.fix ( t : { # t = this attrs
+
+    version = "2.5";
+    versionAttr = "python25";
+
+    # see pythonFull.
+    pythonMinimal = ( (import ./python.nix) {
+      name = "python-${t.version}";
+      inherit (p) fetchurl stdenv lib bzip2 ncurses composableDerivation;
+      inherit  (p) zlib sqlite db4 readline openssl gdbm;
+    });
+
+    # python wiht all features enabled.
+    # if you really need a stripped version we should add __overides
+    # so that you can replace it the way it's done in all-packages.nix
+    pythonFull = t.pythonMinimal.passthru.fun {
+     name = "python-${t.version}-full";
+      cfg = {
+        zlibSupport = true;
+        sqliteSupport = true;
+        db4Support = true;
+        readlineSupport = true;
+        opensslSupport = true;
+        gdbmSupport = true;
+      };
+    };
+
+    # python wrapper. You should install this
+    # It automatically wrapps python adding NIX_PYTHON_SITES so that you can use all the libraries
+    # when running the wrapper from the console.
+    # configuration:
+    # python25 = { wrapperLibs = let p = pkgs.python25New; in [ p.wxPython25 p.name p.name2 ]; }; 
+    # python25 = { wrapperLibs = [ "all" ]; }; # install all libraries provided by this file
+    # TODO: does pydoc find stuff from libraries?
+    pythonWrapper = stdenv.mkDerivation {
+      name = "${t.pythonFull.name}-wrapper";
+      # [1] using full because I feel installing various versions isn't any better
+      phases = "buildPhase";
+      buildInputs = [ p.makeWrapper ] 
+        ++ lib.concatMap (x: if x == "all" then t.all else [x]) (getConfig [t.versionAttr "wrapperLibs"] []);
+
+      buildPhase = ''
+        ensureDir $out/bin
+        cat >> $out/bin/python << EOF
+        export NIX_PYTHON_SITES=\$NIX_PYTHON_SITES:$NIX_PYTHON_SITES
+        exec ${t.pythonFull}/bin/python "\$@"
+        EOF
+        chmod +x $out/bin/python
+      '';
+    };
+
+    ### basic support for installing python libraries
+    # set pyCheck to a small python snippet importing all modules of this python
+    # lib to verify it works
+    # You can define { python25 { debugCmd = "DISPLAY=:0.0 pathtoxterm"; }
+    # in your config for easier debugging..
+    pythonLibStub = p.composableDerivation {
+      initial = {
+          propagatedBuildInputs = [ t.pythonFull ]; # see [1]
+          postPhases = ["postAll"]; # using new name so that you dno't override this phase by accident
+          prePhases = ["defineValidatingEval"];
+          # ensure phases are run or a non zero exit status is caused (if there are any syntax errors such as eval "while")
+          defineValidatingEval = ''
+            eval(){
+              e="$(type eval | { read; while read line; do echo $line; done })"
+              unset eval;
+              local evalSucc="failure"
+              eval "evalSucc=ok;""$1"
+              eval "$e"
+              [ $evalSucc = "failure" ] && { echo "eval failed, snippet:"; echo "$1"; return 1; }
+            }
+          '';
+          postAll = ''
+            ensureDir $out/nix-support
+            echo "export NIX_PYTHON_SITES=\"$out:\$NIX_PYTHON_SITES\"" >> $out/nix-support/setup-hook 
+            # run check
+            [ -n "$pyCheck" ] \
+              && ( . $out/nix-support/setup-hook
+                   mkdir $TMP/new-test; cd $TMP/new-test
+                   echo PYTHONPATH=$PYTHONPATH
+                   echo NIX_PYTHON_SITES=$NIX_PYTHON_SITES
+                   script="$(echo -e "import sys\nprint sys.path\npyCheck\nprint \"check ok\"")"
+                   script="''${script/pyCheck/$pyCheck}"
+                   echo "check script is"; echo "$script"
+                   echo "$script" | /var/run/current-system/sw/bin/strace -o $TMP/strace -f python || { ${ getConfig [t.versionAttr "debugCmd"] ":"} ; exit 1; }
+                   )'';
+          passthru = {
+            libPython = t.version; # used to find all python libraries fitting this version (-> see name all below)
+          };
+          mergeAttrBy = {
+            postCheck = x : y : "${x}\n${y}";
+          };
+      };
+    };
+
+    # same as pythonLibStub, but runs default python setup.py actions
+    pythonLibSetup = t.pythonLibStub.passthru.fun {
+      buildPhase = ''python setup.py $setupFlags build'';
+      installPhase = ''python setup.py $setupFlags install --prefix=$out'';
+      mergeAttrBy = {
+        setupFlags = lib.concatList;
+      };
+    };
+
+    ### python libraries:
+
+    wxPythonBaseFun = (t.pythonLibSetup.passthru.funMerge (a :
+      let inherit (a.fixed) wxGTK version; in
+        {
+          buildInputs = [p.pkgconfig wxGTK (wxGTK.gtk)];
+          setupFlags=["WXPORT=gtk2 NO_HEADERS=1 BUILD_GLCANVAS=0 BUILD_OGL=0 UNICODE=1"];
+          configurePhase = ''cd wxPython'';
+          pyCheck = "import wx";
+          name = "wxPython-${version}";
+          meta = { # 2.6.x and 2.8.x
+            description="A blending of the wxWindows C++ class library with Python";
+            homepage="http://www.wxpython.org/";
+            license="wxWinLL-3";
+          };
+        }
+    )).passthru.fun;
+
+    wxPython26 = t.wxPythonBaseFun {
+      version = "2.6.3.3";
+      passthru = { wxGTK = p.wxGTK26; };
+      src = fetchurl {
+        url = mirror://sourceforge/wxpython/wxPython-src-2.6.3.3.tar.bz2;
+        md5 = "66b9c5f8e20a9505c39dab1a1234daa9";
+      };
+    };
+
+    # compilation errors
+    #wxPython28 = t.wxPythonBaseFun {
+    #  version = "2.8.9.1";
+    #  passthru = { wxGTK = wxGTK28; };
+    #  src = fetchurl {
+    #    url = mirror://sourceforge.net/sourceforge/wxpython/wxPython-src-2.8.9.1.tar.bz2;
+    #    sha256 = "1yp7l2c2lfpwc2x5lk5pawmzq2bqajzhbzqs1p10jd211slwhjsq";
+    #  };
+    #};
+
+    # couldn't download source
+    #foursuite = pythonLibSetup.passthru.fun {
+    #  version = "1.0.2";
+    #  name = "4suite-${version}";
+    #  src = fetchurl {
+    #    url = "mirror://sourceforge/foursuite/4Suite-XML-${version}.tar.bz2";
+    #    sha256 = "0g5cyqxhhiqnvqk457k8sb97r18pwgx6gff18q5296xd3zf4cias";
+    #  };
+    #};
+
+    #bsddb3 = t.pythonLibSetup.passthru.fun {
+    #  version = "1.0.2";
+    #  name = "bsddb3-4.5.0";
+    #  setupFlags = ["--berkeley-db=${p.db4}"];
+    #  src = fetchurl {
+    #    url = mirror://sourceforge/pybsddb/bsddb3-4.5.0.tar.gz;
+    #    sha256 = "1h09kij32iikr9racp5p7qrb4li2gf2hs0lyq6d312qarja4d45v";
+    #  };
+    #};
+
+  pygobject = t.pythonLibStub.passthru.fun {
+    name = "pygobject-2.15.4";
+    flags = { libffi = { buildInputs = [p.libffi];}; };
+    cfg = { libffi = true; };
+    buildInputs = [ p.pkgconfig p.gtkLibs.glib];
+    src = fetchurl {
+      url = "http://ftp.gnome.org/pub/GNOME/sources/pygobject/2.15/pygobject-2.15.4.tar.bz2";
+      sha256 = "19vxczy01xyss2f5aqf93al3jzrxn50srgzkl4w7ivdz50rnjin7";
+    };
+    pyCheck = "import gobject";
+  };
+
+  pygtkBaseFun = (t.pythonLibStub.passthru.funMerge (a :
+    let inherit (a.fixed) glib gtk version; in {
+      name = "pygtk-${version}";
+      buildInputs = [p.pkgconfig glib gtk];
+      propagatedBuildInputs = [t.pygobject t.pycairo ];
+      flags = {
+        cairo = { buildInputs = [ p.cairo ]; }; # TODO add pyCheck
+        glade = { buildInputs = [ p.glade ]; }; # TODO add pyCheck
+      };
+      cfg = {
+        glade = true;
+        cairo = true;
+      };
+    }
+  )).passthru.fun;
+
+  #pygtk213 = t.pygtkBaseFun {
+  #  version = "2.13.0";
+  #  src = fetchurl {
+  #    url = http://ftp.gnome.org/pub/GNOME/sources/pygtk/2.13/pygtk-2.13.0.tar.bz2;
+  #    sha256 = "0644ll48hi8kwfng37b0k5qgb0fbiy298r7sxd4j7ag7lj4bgic0";
+  #  };
+  #  passthru = { inherit (p.gtkLibs) glib gitk; };
+  #  pyCheck = ''
+  #    import pygtk; pygtk.require('2.0')
+  #    import gtk
+  #  '';
+  #};
+
+  pygtk212 = t.pygtkBaseFun {
+    version = "2.12.1";
+    src = fetchurl {
+      url = http://ftp.acc.umu.se/pub/GNOME/sources/pygtk/2.12/pygtk-2.12.1.tar.bz2;
+      sha256 = "0gg13xgr7y9sppw8bdys042928nc66czn74g60333c4my95ys021";
+    };
+    passthru = { inherit (p.gtkLibs) glib gtk; };
+    pyCheck = ''
+      import pygtk; pygtk.require('2.0')
+      import gtk
+    '';
+    patches = [ ./pygtk-2.12.1-fix-amd64-from-gentoo.patch ];
+  };
+
+  pycairo = t.pythonLibStub.passthru.fun {
+    name = "pycairo-1.8.0";
+    buildInputs = [ p.pkgconfig p.cairo p.x11 ];
+    src = fetchurl {
+      url = http://www.cairographics.org/releases/pycairo-1.6.4.tar.gz;
+      md5 = "2c3aa21e6e610321498f9f81f7b625df";
+    };
+    pyCheck = "import cairo";
+  };
+
+  gstPython = t.pythonLibStub.passthru.fun {
+    name = "gst-python-0.10.13";
+    src = fetchurl {
+      url = http://gstreamer.freedesktop.org/src/gst-python/gst-python-0.10.13.tar.gz;
+      sha256 = "0yin36acr5ryfpmhlb4rlagabgxrjcmbpizwrc8csadmxzmigb86";
+    };
+    buildInputs =[ p.flex2535 p.pkgconfig];
+    propagatedBuildInputs = [
+          t.pygtk212
+          p.gst_all.gstreamer
+          p.gst_all.gstPluginsBase
+          p.gst_all.gstPluginsGood
+        ];
+    pyCheck = ''
+      import pygst
+      pygst.require('0.10')
+      import gst
+    '';
+    meta = {
+      description = "python gstreamer bindings";
+      homepage = http://gstreamer.freedesktop.org/modules/gst-python.html;
+      license = "GPLv2.1";
+    };
+  };
+
+  ### python applications
+
+  pythonExStub = p.composableDerivation {
+    initial = {
+      buildInputs = [p.makeWrapper];
+      postPhases = ["wrapExecutables"];
+      propagatedBuildInputs = [ t.pythonFull ]; # see [1]
+      wrapExecutables = ''
+        for prog in $out/bin/*; do
+        wrapProgram "$prog"     \
+                     --set NIX_PYTHON_SITES "$NIX_PYTHON_SITES"
+        done
+      '';
+    };
+  };
+
+  pitivi = t.pythonExStub.passthru.fun {
+    name = "pitivi-0.11.2";
+    src = fetchurl {
+      url = http://ftp.gnome.org/pub/GNOME/sources/pitivi/0.11/pitivi-0.11.2.tar.bz2;
+      sha256 = "0d3bqgfp60qm5bf904k477bd8jhxizj1klv84wbxsz9vhjwx9zcl";
+    };
+    buildInputs =[ t.pygtk212 t.gstPython p.intltool p.gettext p.makeWrapper p.gettext ];
+    # why do have to add gtk-2.0 explicitely?
+    meta = {
+        description = "A non-linear video editor using the GStreamer multimedia framework";
+        homepage = http://www.pitivi.org/wiki/Downloads;
+        license = "LGPL-2.1";
+    };
+    postInstall = ''
+      # set the python which has been used to compile this package
+      sed -i -e 's@#!.*@#!'"$(which python)@" $out/bin/pitivi
+    '';
+  };
+
+  all = lib.filter (x: 
+                   (__isAttrs x)
+                && ((lib.maybeAttr "libPython" false x) == t.version)
+                && (lib.maybeAttr "name" false x != false) # don't collect pythonLibStub etc
+        ) (lib.flattenAttrs (removeAttrs t ["all"])); # nix is not yet lazy enough, so I've to remove all first
+})
diff --git a/pkgs/development/interpreters/python-new/2.5/nix-find-sites-2.5.patch b/pkgs/development/interpreters/python-new/2.5/nix-find-sites-2.5.patch
new file mode 100644
index 000000000000..2fa610fdb044
--- /dev/null
+++ b/pkgs/development/interpreters/python-new/2.5/nix-find-sites-2.5.patch
@@ -0,0 +1,33 @@
+--- a/site.py    2008-11-19 14:48:49.000000000 +0100
+--- Python-2.5-orig/Lib/site.py	2008-05-10 19:36:24.000000000 +0200
++++ Python-2.5/Lib/site.py	2008-11-17 05:37:02.000000000 +0100
+@@ -390,6 +390,20 @@
+     except ImportError:
+         pass
+ 
++def addnixsitepackages(known_paths):
++    """
++    used to add multiple site packages for /nix/store to sys.path also
++    evaluating the .pth files (http://docs.python.org/library/site.html#module-site)
++    """
++    env_nix_sites = os.environ.get("NIX_PYTHON_SITES", None)
++    if env_nix_sites:
++      for path in env_nix_sites.split(":"):
++        if os.path.isdir(path):
++          NIX_SITE = os.path.join(path, "lib",
++                                 "python" + sys.version[:3],
++                                 "site-packages")
++          addsitedir(NIX_SITE, known_paths)
++    return known_paths
+ 
+ def main():
+     abs__file__()
+@@ -400,6 +414,7 @@
+     paths_in_sys = addsitepackages(paths_in_sys)
+     if sys.platform == 'os2emx':
+         setBEGINLIBPATH()
++    paths_in_sys = addnixsitepackages(paths_in_sys)
+     setquit()
+     setcopyright()
+     sethelper()
+
diff --git a/pkgs/development/interpreters/python-new/2.5/python.nix b/pkgs/development/interpreters/python-new/2.5/python.nix
new file mode 100644
index 000000000000..6ae5ffb68228
--- /dev/null
+++ b/pkgs/development/interpreters/python-new/2.5/python.nix
@@ -0,0 +1,69 @@
+args: with args;
+let inherit (lib) optional prepareDerivationArgs concatStringsSep fix;  in
+
+composableDerivation {
+  f = args: let attr = lib.prepareDerivationArgs args; in stdenv.mkDerivation ( attr // {
+      C_INCLUDE_PATH = concatStringsSep ":" (map (p: "${p}/include") attr.buildInputs);
+      LIBRARY_PATH = concatStringsSep ":" (map (p: "${p}/lib") attr.buildInputs);
+    });
+  initial = {
+
+    postPhases = ["runCheck"];
+
+    mergeAttrBy = { pyCheck = x : y : "${x}\n${y}"; };
+
+    # should be last because it sources setup-hook of this package itself
+    runCheck = ''
+      PATH=$out/bin:$PATH; . $out/nix-support/setup-hook;
+      echo -e "import sys\n$pyCheck\nprint \"import pyCheck ok\"" | python
+    '';
+
+    inherit (args) name;
+
+    # everything can be overriden by composedArgsAndFun additional args 
+    # assuming that if a module can be loaded that it does also work..
+    flags = {
+      zlib = { buildInputs = [ zlib ]; pyCheck = "import zlib"; };
+      gdbm = { buildInputs = [ gdbm ]; pyCheck = "import gdbm"; };
+      sqlite = { buildInputs = [ sqlite ]; pyCheck = "import sqlite3"; };
+      db4 = { buildInputs = [ db4 ]; }; # TODO add pyCheck
+      readline = { buildInputs = [ readline ]; }; # doesn't work yet (?)
+      openssl = { buildInputs = [ openssl ]; pyCheck ="import socket\nsocket.ssl"; };
+    };
+
+    src = fetchurl {
+      url = http://www.python.org/ftp/python/2.5.2/Python-2.5.2.tar.bz2;
+      sha256 = "0gh8bvs56vdv8qmlfmiwyczjpldj0y3zbzd0zyhyjfd0c8m0xy7j";
+    };
+
+    configureFlags = ["--enable-shared" "--with-wctype-functions"];
+
+    buildInputs =
+      optional (stdenv ? gcc && stdenv.gcc.libc != null) stdenv.gcc.libc ++
+      [bzip2 ncurses];
+
+    patches = [
+      # Look in C_INCLUDE_PATH and LIBRARY_PATH for stuff.
+      ./search-path.patch
+
+
+      # make python know about libraries reading .pth files
+      # http://docs.python.org/library/site.html#module-site
+      # TODO: think about security (see the other code contained in site.py)
+      ./nix-find-sites-2.5.patch
+    ];
+
+    preConfigure = ''
+      # Purity.
+      for i in /usr /sw /opt /pkg; do 
+        substituteInPlace ./setup.py --replace $i /no-such-path
+      done
+      export NIX_LDFLAGS="$NIX_LDFLAGS -lncurses"
+    '';
+    
+    postInstall = "
+      rm -rf $out/lib/python2.5/test
+    ";
+
+  };
+}
diff --git a/pkgs/development/interpreters/python-new/2.5/search-path.patch b/pkgs/development/interpreters/python-new/2.5/search-path.patch
new file mode 100644
index 000000000000..8fcddcb3f8d5
--- /dev/null
+++ b/pkgs/development/interpreters/python-new/2.5/search-path.patch
@@ -0,0 +1,28 @@
+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/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index e7bf2abd2c18..f0fc62aa5fe1 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -2095,6 +2095,16 @@ let
     xproto = if getConfig ["python" "tkSupport"] true then xlibs.xproto else null;
   };
 
+  # new python and lib proposal
+  # - adding a python lib to buildinputs should be enough 
+  #   (handles .pth files by patching site.py   
+  #    while introducing NIX_PYTHON_SITES describing list of modules)
+  # - adding pyCheck = "import foo" test scripts to ensure libraries can be imported
+  # - providing pythonWrapper so that you can run python and import the selected libraries
+  # feel free to comment on this (experimental)
+  python25New = recurseIntoAttrs ((import ../development/interpreters/python-new/2.5) pkgs);
+  pythonNew = python25New; # the default python
+
   pyrex = pyrex095;
 
   pyrex095 = import ../development/interpreters/pyrex/0.9.5.nix {