From: David Thompson <da...@gnu.org> * guix/scripts/enviroment.scm (show-help): Show help for new option. (%options): Add --container option. (launch-environment, launch-environment/container): New procedures. (guix-environment): Spawn new process in a container when requested. * doc/guix.texi (Invoking guix environment): Document it. --- doc/guix.texi | 16 +++++++++++++++ guix/scripts/environment.scm | 48 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 2 deletions(-)
diff --git a/doc/guix.texi b/doc/guix.texi index d24f97e..57fc446 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -4191,6 +4191,15 @@ NumPy: guix environment --ad-hoc python2-numpy python-2.7 -E python @end example +Sometimes it is desirable to isolate the environment as much as +possible, for maximal purity and reproducibility. For example, the +following command spawns a Guile REPL in a ``container'' where only the +store and the current working directory are mounted: + +@example +guix environment --ad-hoc --container guile --exec=guile +@end example + The available options are summarized below. @table @code @@ -4256,6 +4265,13 @@ environment. @item --system=@var{system} @itemx -s @var{system} Attempt to build for @var{system}---e.g., @code{i686-linux}. + +@item --container +@itemx -C +Run command within an isolated container. The current working directory +outside the container is mapped to @file{/env} inside the container. +Additionally, the spawned process runs as the current user outside the +container, but has root privileges in the context of the container. @end table It also supports all of the common build options that @command{guix diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm index ecdbc7a..41d1554 100644 --- a/guix/scripts/environment.scm +++ b/guix/scripts/environment.scm @@ -28,6 +28,9 @@ #:use-module (guix monads) #:use-module ((guix gexp) #:select (lower-inputs)) #:use-module (guix scripts build) + #:use-module (gnu build linux-container) + #:use-module (gnu system linux-container) + #:use-module (gnu system file-systems) #:use-module (gnu packages) #:use-module (ice-9 format) #:use-module (ice-9 match) @@ -122,6 +125,8 @@ shell command in that environment.\n")) --search-paths display needed environment variable definitions")) (display (_ " -s, --system=SYSTEM attempt to build for SYSTEM--e.g., \"i686-linux\"")) + (display (_ " + -C, --container run command within an isolated container")) (newline) (show-build-options-help) (newline) @@ -174,6 +179,9 @@ shell command in that environment.\n")) (lambda (opt name arg result) (alist-cons 'system arg (alist-delete 'system result eq?)))) + (option '(#\C "container") #f #f + (lambda (opt name arg result) + (alist-cons 'container? #t result))) %standard-build-options)) (define (pick-all alist key) @@ -229,6 +237,38 @@ OUTPUT) tuples, using the build options in OPTS." (built-derivations derivations) (return derivations)))))))) +(define (launch-environment command inputs paths pure?) + "Run COMMAND in a new environment containing INPUTS, using the native search +paths defined by the list PATHS. When PURE?, pre-existing environment +variables are cleared before setting the new ones." + (create-environment inputs paths pure?) + (system command)) + +(define (launch-environment/container command inputs paths) + "Run COMMAND within a Linux container that includes INPUTS and the +environment variables defined by PATHS, a list of native search paths." + ;; Bind-mount the store and the current working directory within the + ;; container. + (let* ((mappings + (list (file-system-mapping + (source (%store-prefix)) + (target (%store-prefix)) + (writable? #f)) + (file-system-mapping + (source (getcwd)) + (target "/env") + (writable? #t)))) + (file-systems + (append %container-file-systems + (map mapping->file-system mappings))) + (status + (call-with-container (map file-system->spec file-systems) + (lambda () + (chdir "/env") + ;; A container's environment is already purified. + (launch-environment command inputs paths #f))))) + (status:exit-val status))) + ;; Entry point. (define (guix-environment . args) (define (handle-argument arg result) @@ -238,6 +278,7 @@ OUTPUT) tuples, using the build options in OPTS." (let* ((opts (parse-command-line args %options (list %default-options) #:argument-handler handle-argument)) (pure? (assoc-ref opts 'pure)) + (container? (assoc-ref opts 'container?)) (ad-hoc? (assoc-ref opts 'ad-hoc?)) (command (assoc-ref opts 'exec)) (packages (pick-all (options/resolve-packages opts) 'package)) @@ -279,6 +320,9 @@ OUTPUT) tuples, using the build options in OPTS." ((assoc-ref opts 'search-paths) (show-search-paths inputs paths pure?) (return #t)) + (container? + (return + (launch-environment/container command inputs paths))) (else - (create-environment inputs paths pure?) - (return (exit (status:exit-val (system command))))))))))))) + (return + (launch-environment command inputs paths pure?))))))))))) -- 2.4.3