From fc4cc45da80ca148bd88f61590915ff4bdef28b9 Mon Sep 17 00:00:00 2001 From: Hugo Lecomte Date: Thu, 10 Jun 2021 18:03:43 +0200 Subject: [PATCH] Add Guix buildpack --- docs/source/config_files.rst | 21 ++++++ repo2docker/app.py | 2 + repo2docker/buildpacks/__init__.py | 1 + repo2docker/buildpacks/base.py | 1 + repo2docker/buildpacks/guix/__init__.py | 75 +++++++++++++++++++ repo2docker/buildpacks/guix/guix-install.bash | 8 ++ tests/guix/binder-dir/README.rst | 4 + tests/guix/binder-dir/binder/manifest.scm | 3 + tests/guix/binder-dir/verify | 3 + tests/guix/ignore-outside/README.rst | 4 + tests/guix/ignore-outside/binder/manifest.scm | 4 + tests/guix/ignore-outside/manifest.scm | 2 + tests/guix/ignore-outside/verify | 3 + tests/guix/simple-channels/README.rst | 4 + tests/guix/simple-channels/channels.scm | 20 +++++ tests/guix/simple-channels/manifest.scm | 3 + tests/guix/simple-channels/verify | 3 + tests/guix/simple/README.rst | 5 ++ tests/guix/simple/manifest.scm | 3 + tests/guix/simple/verify | 3 + 20 files changed, 172 insertions(+) create mode 100644 repo2docker/buildpacks/guix/__init__.py create mode 100755 repo2docker/buildpacks/guix/guix-install.bash create mode 100644 tests/guix/binder-dir/README.rst create mode 100644 tests/guix/binder-dir/binder/manifest.scm create mode 100755 tests/guix/binder-dir/verify create mode 100644 tests/guix/ignore-outside/README.rst create mode 100644 tests/guix/ignore-outside/binder/manifest.scm create mode 100644 tests/guix/ignore-outside/manifest.scm create mode 100755 tests/guix/ignore-outside/verify create mode 100644 tests/guix/simple-channels/README.rst create mode 100644 tests/guix/simple-channels/channels.scm create mode 100644 tests/guix/simple-channels/manifest.scm create mode 100755 tests/guix/simple-channels/verify create mode 100644 tests/guix/simple/README.rst create mode 100644 tests/guix/simple/manifest.scm create mode 100755 tests/guix/simple/verify diff --git a/docs/source/config_files.rst b/docs/source/config_files.rst index 4b71980cf..a9efcc0d6 100644 --- a/docs/source/config_files.rst +++ b/docs/source/config_files.rst @@ -231,6 +231,27 @@ to produce a reproducible environment. To see an example repository visit `nix binder example `_. +.. _manifest.scm: + +``manifest.scm`` - the Guix package manager +=========================================== + +Specify packages to be installed by the `Guix package manager `_. +All packages specified in |manifest|_ will be installed in a container using |guix_package|_. In addition, you can use different `channels `_ rather +than the ones available by default (official channels of GNU Guix 1.3.0). +You must describe such channels in a ``channels.scm`` file which will be used +alongside ``manifest.scm`` with the |guix_time-machine|_ command. Furthermore, using a ``channels.scm`` file lets you `pin a specific revision `_ of Guix, allowing you to unambiguously specific the software environment to reproduce. + +For more information about Guix please read the `manual `_. + +.. |manifest| replace:: ``manifest.scm`` +.. _manifest: https://guix.gnu.org/manual/en/html_node/Invoking-guix-package.html#index-profile-manifesthy + +.. |guix_package| replace:: ``guix package`` +.. _guix_package: https://guix.gnu.org/manual/en/html_node/Invoking-guix-package.html#Invoking-guix-package + +.. |guix_time-machine| replace:: ``guix time-machine`` +.. _guix_time-machine: https://guix.gnu.org/manual/en/html_node/Invoking-guix-time_002dmachine.html ``Dockerfile`` - Advanced environments ====================================== diff --git a/repo2docker/app.py b/repo2docker/app.py index 8a804905c..6cb173712 100755 --- a/repo2docker/app.py +++ b/repo2docker/app.py @@ -37,6 +37,7 @@ PipfileBuildPack, PythonBuildPack, RBuildPack, + GuixBuildPack, ) from . import contentproviders from .utils import ByteSpecification, chdir @@ -99,6 +100,7 @@ def _default_log_level(self): CondaBuildPack, PipfileBuildPack, PythonBuildPack, + GuixBuildPack, ], config=True, help=""" diff --git a/repo2docker/buildpacks/__init__.py b/repo2docker/buildpacks/__init__.py index 10fe89a4e..cde1fb21c 100644 --- a/repo2docker/buildpacks/__init__.py +++ b/repo2docker/buildpacks/__init__.py @@ -8,3 +8,4 @@ from .legacy import LegacyBinderDockerBuildPack from .r import RBuildPack from .nix import NixBuildPack +from .guix import GuixBuildPack diff --git a/repo2docker/buildpacks/base.py b/repo2docker/buildpacks/base.py index 145d29648..1889bc7ef 100644 --- a/repo2docker/buildpacks/base.py +++ b/repo2docker/buildpacks/base.py @@ -718,3 +718,4 @@ def get_start_script(self): # the only path evaluated at container start time rather than build time return os.path.join("${REPO_DIR}", start) return None + diff --git a/repo2docker/buildpacks/guix/__init__.py b/repo2docker/buildpacks/guix/__init__.py new file mode 100644 index 000000000..51cc27c13 --- /dev/null +++ b/repo2docker/buildpacks/guix/__init__.py @@ -0,0 +1,75 @@ +"""BuildPack for guix environments""" +import os + +from ..base import BuildPack, BaseImage + + +class GuixBuildPack(BaseImage): + """A guix Package Manager BuildPack""" + + def get_path(self): + """Return paths to be added to PATH environment variable""" + return super().get_path() + [ + "/var/guix/profiles/per-user/$NB_USER/.guix-profile/bin" + ] + + + def get_build_scripts(self): + """ + Install guix package manager version 1.3.0.x86_64-linux, using + an unmodified installation script found at + https://git.savannah.gnu.org/cgit/guix.git/plain/etc/guix-install.sh?id=a0178d34f582b50e9bdbb0403943129ae5b560ff + """ + return super().get_build_scripts() + [ + ( + "root", + """ + bash /tmp/.local/bin/guix-install.bash + """, + ), + + ] + + def get_build_script_files(self): + + """Copying guix installation script on the image""" + return { + "guix/guix-install.bash": + "/tmp/.local/bin/guix-install.bash", + } + + def get_assemble_scripts(self): + """ + Wake up the guix daemon with root permission, set guix environnement + variables, make sure we never use debian's python by error by + renaming it, then, as an user install packages listed in + manifest.scm, use guix time-machine if channels.scm file exists + """ + assemble_script =""" + /var/guix/profiles/per-user/root/current-guix/bin/guix-daemon \ + --build-users-group=guixbuild --disable-chroot & \ + mv /usr/bin/python /usr/bin/python.debian && \ + su - $NB_USER -c '{}' && \ + echo 'GUIX_PROFILE="/var/guix/profiles/per-user/$NB_USER/.guix-profile" ; \ + source "$GUIX_PROFILE/etc/profile"'>> ~/.bash_profile + """ + + if os.path.exists(self.binder_path("channels.scm")): + assemble_script = assemble_script.format( + "guix time-machine -C " + self.binder_path("channels.scm") + + " -- package -m " + self.binder_path("manifest.scm") + ) + else: + assemble_script = assemble_script.format( + "guix package -m " + self.binder_path("manifest.scm") + ) + return super().get_assemble_scripts() + [ + ( "root", + assemble_script, + ) + ] + + def detect(self): + """Check if current repo should be built with the guix BuildPack""" + return os.path.exists(self.binder_path("manifest.scm")) + diff --git a/repo2docker/buildpacks/guix/guix-install.bash b/repo2docker/buildpacks/guix/guix-install.bash new file mode 100755 index 000000000..65f1c551f --- /dev/null +++ b/repo2docker/buildpacks/guix/guix-install.bash @@ -0,0 +1,8 @@ +#!/bin/bash +# This downloads and installs a pinned version of Guix +set -ex + +wget https://git.savannah.gnu.org/cgit/guix.git/plain/etc/guix-install.sh?id=a0178d34f582b50e9bdbb0403943129ae5b560ff + +yes | BIN_VER=1.3.0x86_64-linux \ + bash guix-install.sh?id=a0178d34f582b50e9bdbb0403943129ae5b560ff diff --git a/tests/guix/binder-dir/README.rst b/tests/guix/binder-dir/README.rst new file mode 100644 index 000000000..ac0bbd5e5 --- /dev/null +++ b/tests/guix/binder-dir/README.rst @@ -0,0 +1,4 @@ +`manifest.scm` in a binder/ directory +------------------------------------- + +Check if we can find and use `manifest.scm` when it is ina `binder/` sub-directory. diff --git a/tests/guix/binder-dir/binder/manifest.scm b/tests/guix/binder-dir/binder/manifest.scm new file mode 100644 index 000000000..c9fdbeb25 --- /dev/null +++ b/tests/guix/binder-dir/binder/manifest.scm @@ -0,0 +1,3 @@ +(specifications->manifest + '("jupyter" + "hello")) diff --git a/tests/guix/binder-dir/verify b/tests/guix/binder-dir/verify new file mode 100755 index 000000000..ecc7f040f --- /dev/null +++ b/tests/guix/binder-dir/verify @@ -0,0 +1,3 @@ +#!/bin/sh + +hello \ No newline at end of file diff --git a/tests/guix/ignore-outside/README.rst b/tests/guix/ignore-outside/README.rst new file mode 100644 index 000000000..b0bb62edc --- /dev/null +++ b/tests/guix/ignore-outside/README.rst @@ -0,0 +1,4 @@ +`manifest.scm` in main directory and in `binder/` +------------------------------------------------- + +Check if `manifest.scm` located in the `binder/` sub-directory is prefered to the one in the main directory. diff --git a/tests/guix/ignore-outside/binder/manifest.scm b/tests/guix/ignore-outside/binder/manifest.scm new file mode 100644 index 000000000..a262c0505 --- /dev/null +++ b/tests/guix/ignore-outside/binder/manifest.scm @@ -0,0 +1,4 @@ +(specifications->manifest + '("jupyter" + "python" + "python-numpy")) diff --git a/tests/guix/ignore-outside/manifest.scm b/tests/guix/ignore-outside/manifest.scm new file mode 100644 index 000000000..452b8ff0d --- /dev/null +++ b/tests/guix/ignore-outside/manifest.scm @@ -0,0 +1,2 @@ +(specifications->manifest + '("jupyter")) diff --git a/tests/guix/ignore-outside/verify b/tests/guix/ignore-outside/verify new file mode 100755 index 000000000..7fa832bdc --- /dev/null +++ b/tests/guix/ignore-outside/verify @@ -0,0 +1,3 @@ +#!/usr/bin/env python3 + +import numpy diff --git a/tests/guix/simple-channels/README.rst b/tests/guix/simple-channels/README.rst new file mode 100644 index 000000000..5a8949352 --- /dev/null +++ b/tests/guix/simple-channels/README.rst @@ -0,0 +1,4 @@ +`manifest.scm` and `channels.scm` in main directory +--------------------------------------------------- + +CHeck if we can use `manifest.scm` alongside a `channels.scm` file using `guix time-machine ...` diff --git a/tests/guix/simple-channels/channels.scm b/tests/guix/simple-channels/channels.scm new file mode 100644 index 000000000..3ae7063ad --- /dev/null +++ b/tests/guix/simple-channels/channels.scm @@ -0,0 +1,20 @@ +(list (channel + (name 'guix) + (url "https://git.savannah.gnu.org/git/guix.git") + (commit + "f1bfd9f1948a5ff336d737c0614b9a30c2bb3097") + (introduction + (make-channel-introduction + "9edb3f66fd807b096b48283debdcddccfea34bad" + (openpgp-fingerprint + "BBB0 2DDF 2CEA F6A8 0D1D E643 A2A0 6DF2 A33A 54FA")))) + (channel + (name 'nonguix) + (url "https://gitlab.com/nonguix/nonguix") + (commit + "46c1d8bcca674d3a71cd077c52dde9552a89873d") + (introduction + (make-channel-introduction + "897c1a470da759236cc11798f4e0a5f7d4d59fbc" + (openpgp-fingerprint + "2A39 3FFF 68F4 EF7A 3D29 12AF 6F51 20A0 22FB B2D5"))))) diff --git a/tests/guix/simple-channels/manifest.scm b/tests/guix/simple-channels/manifest.scm new file mode 100644 index 000000000..c9fdbeb25 --- /dev/null +++ b/tests/guix/simple-channels/manifest.scm @@ -0,0 +1,3 @@ +(specifications->manifest + '("jupyter" + "hello")) diff --git a/tests/guix/simple-channels/verify b/tests/guix/simple-channels/verify new file mode 100755 index 000000000..1d4239a7a --- /dev/null +++ b/tests/guix/simple-channels/verify @@ -0,0 +1,3 @@ +#!/bin/sh + +hello diff --git a/tests/guix/simple/README.rst b/tests/guix/simple/README.rst new file mode 100644 index 000000000..b0c266935 --- /dev/null +++ b/tests/guix/simple/README.rst @@ -0,0 +1,5 @@ + +`manifest.scm` in the main directory +---------------------------------- + +Check if we can find and use `manifest.scm` when it is in the main directory. diff --git a/tests/guix/simple/manifest.scm b/tests/guix/simple/manifest.scm new file mode 100644 index 000000000..c9fdbeb25 --- /dev/null +++ b/tests/guix/simple/manifest.scm @@ -0,0 +1,3 @@ +(specifications->manifest + '("jupyter" + "hello")) diff --git a/tests/guix/simple/verify b/tests/guix/simple/verify new file mode 100755 index 000000000..1d4239a7a --- /dev/null +++ b/tests/guix/simple/verify @@ -0,0 +1,3 @@ +#!/bin/sh + +hello