environment: Add '--nesting'.
* guix/scripts/environment.scm (show-environment-options-help) (%options): Add '--nesting'. (options/resolve-packages): Handle it. (launch-environment/container): Add #:nesting? and honor it. [nesting-mappings]: New procedure. (guix-environment*): Add support for '--nesting'. * guix/scripts/shell.scm (profile-cached-gc-root): Special-case 'nesting?'. * tests/guix-environment-container.sh: Test it. * doc/guix.texi (Invoking guix shell): Document it.
This commit is contained in:
parent
58769f9273
commit
57db09aae7
4 changed files with 124 additions and 4 deletions
|
@ -6357,6 +6357,57 @@ cache (contrary to glibc in regular Guix usage) and set up the
|
||||||
expected FHS directories: @file{/bin}, @file{/etc}, @file{/lib}, and
|
expected FHS directories: @file{/bin}, @file{/etc}, @file{/lib}, and
|
||||||
@file{/usr} from the container's profile.
|
@file{/usr} from the container's profile.
|
||||||
|
|
||||||
|
@cindex nested containers, for @command{guix shell}
|
||||||
|
@cindex container nesting, for @command{guix shell}
|
||||||
|
@item --nesting
|
||||||
|
@itemx -W
|
||||||
|
When used with @option{--container}, provide Guix @emph{inside} the
|
||||||
|
container and arrange so that it can interact with the build daemon that
|
||||||
|
runs outside the container. This is useful if you want, within your
|
||||||
|
isolated container, to create other containers, as in this sample
|
||||||
|
session:
|
||||||
|
|
||||||
|
@example
|
||||||
|
$ guix shell -CW coreutils
|
||||||
|
[env]$ guix shell -C guile -- guile -c '(display "hello!\n")'
|
||||||
|
hello!
|
||||||
|
[env]$ exit
|
||||||
|
@end example
|
||||||
|
|
||||||
|
The session above starts a container with @code{coreutils} programs
|
||||||
|
available in @env{PATH}. From there, we spawn @command{guix shell} to
|
||||||
|
create a @emph{nested} container that provides nothing but Guile.
|
||||||
|
|
||||||
|
Another example is evaluating a @file{guix.scm} file that is untrusted,
|
||||||
|
as shown here:
|
||||||
|
|
||||||
|
@example
|
||||||
|
guix shell -CW -- guix build -f guix.scm
|
||||||
|
@end example
|
||||||
|
|
||||||
|
The @command{guix build} command as executed above can only access the
|
||||||
|
current directory.
|
||||||
|
|
||||||
|
Under the hood, the @option{-W} option does several things:
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
@item
|
||||||
|
map the daemon's socket (by default
|
||||||
|
@file{/var/guix/daemon-socket/socket}) inside the container;
|
||||||
|
@item
|
||||||
|
map the whole store (by default @file{/gnu/store}) inside the container
|
||||||
|
such that store items made available by nested @command{guix}
|
||||||
|
invocations are visible;
|
||||||
|
@item
|
||||||
|
add the currently-used @command{guix} command to the profile in the
|
||||||
|
container, such that @command{guix describe} returns the same state
|
||||||
|
inside and outside the container;
|
||||||
|
@item
|
||||||
|
share the cache (by default @file{~/.cache/guix}) with the host, to
|
||||||
|
speed up operations such as @command{guix time-machine} and
|
||||||
|
@command{guix shell}.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
@item --rebuild-cache
|
@item --rebuild-cache
|
||||||
@cindex caching, of profiles
|
@cindex caching, of profiles
|
||||||
@cindex caching, in @command{guix shell}
|
@cindex caching, in @command{guix shell}
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
#:use-module (guix build utils)
|
#:use-module (guix build utils)
|
||||||
#:use-module (guix monads)
|
#:use-module (guix monads)
|
||||||
#:use-module ((guix gexp) #:select (lower-object))
|
#:use-module ((guix gexp) #:select (lower-object))
|
||||||
|
#:autoload (guix describe) (current-profile current-channels)
|
||||||
|
#:autoload (guix channels) (guix-channel? channel-commit)
|
||||||
#:use-module (guix scripts)
|
#:use-module (guix scripts)
|
||||||
#:use-module (guix scripts build)
|
#:use-module (guix scripts build)
|
||||||
#:autoload (guix scripts pack) (symlink-spec-option-parser)
|
#:autoload (guix scripts pack) (symlink-spec-option-parser)
|
||||||
|
@ -49,9 +51,11 @@
|
||||||
#:autoload (gnu packages) (specification->package+output)
|
#:autoload (gnu packages) (specification->package+output)
|
||||||
#:autoload (gnu packages bash) (bash)
|
#:autoload (gnu packages bash) (bash)
|
||||||
#:autoload (gnu packages bootstrap) (bootstrap-executable %bootstrap-guile)
|
#:autoload (gnu packages bootstrap) (bootstrap-executable %bootstrap-guile)
|
||||||
|
#:autoload (gnu packages package-management) (guix)
|
||||||
#:use-module (ice-9 match)
|
#:use-module (ice-9 match)
|
||||||
#:autoload (ice-9 rdelim) (read-line)
|
#:autoload (ice-9 rdelim) (read-line)
|
||||||
#:use-module (ice-9 vlist)
|
#:use-module (ice-9 vlist)
|
||||||
|
#:autoload (web uri) (string->uri uri-scheme)
|
||||||
#:use-module (srfi srfi-1)
|
#:use-module (srfi srfi-1)
|
||||||
#:use-module (srfi srfi-11)
|
#:use-module (srfi srfi-11)
|
||||||
#:use-module (srfi srfi-26)
|
#:use-module (srfi srfi-26)
|
||||||
|
@ -108,6 +112,8 @@ shell'."
|
||||||
-P, --link-profile link environment profile to ~/.guix-profile within
|
-P, --link-profile link environment profile to ~/.guix-profile within
|
||||||
an isolated container"))
|
an isolated container"))
|
||||||
(display (G_ "
|
(display (G_ "
|
||||||
|
-W, --nesting make Guix available within the container"))
|
||||||
|
(display (G_ "
|
||||||
-u, --user=USER instead of copying the name and home of the current
|
-u, --user=USER instead of copying the name and home of the current
|
||||||
user into an isolated container, use the name USER
|
user into an isolated container, use the name USER
|
||||||
with home directory /home/USER"))
|
with home directory /home/USER"))
|
||||||
|
@ -238,6 +244,9 @@ use '--preserve' instead~%"))
|
||||||
(option '(#\N "network") #f #f
|
(option '(#\N "network") #f #f
|
||||||
(lambda (opt name arg result)
|
(lambda (opt name arg result)
|
||||||
(alist-cons 'network? #t result)))
|
(alist-cons 'network? #t result)))
|
||||||
|
(option '(#\W "nesting") #f #f
|
||||||
|
(lambda (opt name arg result)
|
||||||
|
(alist-cons 'nesting? #t result)))
|
||||||
(option '(#\P "link-profile") #f #f
|
(option '(#\P "link-profile") #f #f
|
||||||
(lambda (opt name arg result)
|
(lambda (opt name arg result)
|
||||||
(alist-cons 'link-profile? #t result)))
|
(alist-cons 'link-profile? #t result)))
|
||||||
|
@ -342,6 +351,26 @@ for the corresponding packages."
|
||||||
(packages->outputs (load* file module) mode)))
|
(packages->outputs (load* file module) mode)))
|
||||||
(('manifest . file)
|
(('manifest . file)
|
||||||
(manifest-entries (load-manifest file)))
|
(manifest-entries (load-manifest file)))
|
||||||
|
(('nesting? . #t)
|
||||||
|
(if (assoc-ref opts 'profile)
|
||||||
|
'()
|
||||||
|
(let ((profile (and=> (current-profile) readlink*)))
|
||||||
|
(if (or (not profile) (not (store-path? profile)))
|
||||||
|
(begin
|
||||||
|
(warning (G_ "\
|
||||||
|
could not add current Guix to the profile~%"))
|
||||||
|
'())
|
||||||
|
(list (manifest-entry
|
||||||
|
(name "guix")
|
||||||
|
(version
|
||||||
|
(or (any (lambda (channel)
|
||||||
|
(and (guix-channel? channel)
|
||||||
|
(channel-commit channel)))
|
||||||
|
(current-channels))
|
||||||
|
"0"))
|
||||||
|
(item profile)
|
||||||
|
(search-paths
|
||||||
|
(package-native-search-paths guix))))))))
|
||||||
(_ '()))
|
(_ '()))
|
||||||
opts)
|
opts)
|
||||||
manifest-entry=?)))
|
manifest-entry=?)))
|
||||||
|
@ -688,7 +717,8 @@ regexps in WHITE-LIST."
|
||||||
|
|
||||||
(define* (launch-environment/container #:key command bash user user-mappings
|
(define* (launch-environment/container #:key command bash user user-mappings
|
||||||
profile manifest link-profile? network?
|
profile manifest link-profile? network?
|
||||||
map-cwd? emulate-fhs? (setup-hook #f)
|
map-cwd? emulate-fhs? nesting?
|
||||||
|
(setup-hook #f)
|
||||||
(symlinks '()) (white-list '()))
|
(symlinks '()) (white-list '()))
|
||||||
"Run COMMAND within a container that features the software in PROFILE.
|
"Run COMMAND within a container that features the software in PROFILE.
|
||||||
Environment variables are set according to the search paths of MANIFEST. The
|
Environment variables are set according to the search paths of MANIFEST. The
|
||||||
|
@ -704,6 +734,9 @@ Standard and provide a glibc that reads the cache from /etc/ld.so.cache.
|
||||||
SETUP-HOOK is an additional setup procedure to be called, currently only used
|
SETUP-HOOK is an additional setup procedure to be called, currently only used
|
||||||
with the EMULATE-FHS? option.
|
with the EMULATE-FHS? option.
|
||||||
|
|
||||||
|
When NESTING? is true, share all the store with the container and add Guix to
|
||||||
|
its profile, allowing its use from within the container.
|
||||||
|
|
||||||
LINK-PROFILE? creates a symbolic link from ~/.guix-profile to the
|
LINK-PROFILE? creates a symbolic link from ~/.guix-profile to the
|
||||||
environment profile.
|
environment profile.
|
||||||
|
|
||||||
|
@ -731,8 +764,26 @@ WHILE-LIST."
|
||||||
("/libexec" . "/usr/libexec")
|
("/libexec" . "/usr/libexec")
|
||||||
("/share" . "/usr/share"))))
|
("/share" . "/usr/share"))))
|
||||||
|
|
||||||
(mlet %store-monad ((reqs (inputs->requisites
|
(define (nesting-mappings)
|
||||||
(list (direct-store-path bash) profile))))
|
;; Files shared with the host when enabling nesting.
|
||||||
|
(cons* (file-system-mapping
|
||||||
|
(source (%store-prefix))
|
||||||
|
(target source))
|
||||||
|
(file-system-mapping
|
||||||
|
(source (cache-directory))
|
||||||
|
(target source)
|
||||||
|
(writable? #t))
|
||||||
|
(let ((uri (string->uri (%daemon-socket-uri))))
|
||||||
|
(if (or (not uri) (eq? 'file (uri-scheme uri)))
|
||||||
|
(list (file-system-mapping
|
||||||
|
(source (%daemon-socket-uri))
|
||||||
|
(target source)))
|
||||||
|
'()))))
|
||||||
|
|
||||||
|
(mlet %store-monad ((reqs (if nesting?
|
||||||
|
(return '())
|
||||||
|
(inputs->requisites
|
||||||
|
(list (direct-store-path bash) profile)))))
|
||||||
(return
|
(return
|
||||||
(let* ((cwd (getcwd))
|
(let* ((cwd (getcwd))
|
||||||
(home (getenv "HOME"))
|
(home (getenv "HOME"))
|
||||||
|
@ -795,11 +846,14 @@ WHILE-LIST."
|
||||||
(filter-map optional-mapping->fs
|
(filter-map optional-mapping->fs
|
||||||
%network-file-mappings)
|
%network-file-mappings)
|
||||||
'())
|
'())
|
||||||
;; Mappings for an FHS container.
|
|
||||||
(if emulate-fhs?
|
(if emulate-fhs?
|
||||||
(filter-map optional-mapping->fs
|
(filter-map optional-mapping->fs
|
||||||
fhs-mappings)
|
fhs-mappings)
|
||||||
'())
|
'())
|
||||||
|
(if nesting?
|
||||||
|
(filter-map optional-mapping->fs
|
||||||
|
(nesting-mappings))
|
||||||
|
'())
|
||||||
(map file-system-mapping->bind-mount
|
(map file-system-mapping->bind-mount
|
||||||
mappings))))
|
mappings))))
|
||||||
(exit/status
|
(exit/status
|
||||||
|
@ -1013,6 +1067,7 @@ command-line option processing with 'parse-command-line'."
|
||||||
(network? (assoc-ref opts 'network?))
|
(network? (assoc-ref opts 'network?))
|
||||||
(no-cwd? (assoc-ref opts 'no-cwd?))
|
(no-cwd? (assoc-ref opts 'no-cwd?))
|
||||||
(emulate-fhs? (assoc-ref opts 'emulate-fhs?))
|
(emulate-fhs? (assoc-ref opts 'emulate-fhs?))
|
||||||
|
(nesting? (assoc-ref opts 'nesting?))
|
||||||
(user (assoc-ref opts 'user))
|
(user (assoc-ref opts 'user))
|
||||||
(bootstrap? (assoc-ref opts 'bootstrap?))
|
(bootstrap? (assoc-ref opts 'bootstrap?))
|
||||||
(system (assoc-ref opts 'system))
|
(system (assoc-ref opts 'system))
|
||||||
|
@ -1059,6 +1114,8 @@ command-line option processing with 'parse-command-line'."
|
||||||
(leave (G_ "--no-cwd cannot be used without '--container'~%")))
|
(leave (G_ "--no-cwd cannot be used without '--container'~%")))
|
||||||
(when emulate-fhs?
|
(when emulate-fhs?
|
||||||
(leave (G_ "'--emulate-fhs' cannot be used without '--container~%'")))
|
(leave (G_ "'--emulate-fhs' cannot be used without '--container~%'")))
|
||||||
|
(when nesting?
|
||||||
|
(leave (G_ "'--nesting' cannot be used without '--container~%'")))
|
||||||
(when (pair? symlinks)
|
(when (pair? symlinks)
|
||||||
(leave (G_ "'--symlink' cannot be used without '--container~%'"))))
|
(leave (G_ "'--symlink' cannot be used without '--container~%'"))))
|
||||||
|
|
||||||
|
@ -1141,6 +1198,7 @@ when using '--container'; doing nothing~%"))
|
||||||
#:network? network?
|
#:network? network?
|
||||||
#:map-cwd? (not no-cwd?)
|
#:map-cwd? (not no-cwd?)
|
||||||
#:emulate-fhs? emulate-fhs?
|
#:emulate-fhs? emulate-fhs?
|
||||||
|
#:nesting? nesting?
|
||||||
#:symlinks symlinks
|
#:symlinks symlinks
|
||||||
#:setup-hook
|
#:setup-hook
|
||||||
(and emulate-fhs?
|
(and emulate-fhs?
|
||||||
|
|
|
@ -389,6 +389,8 @@ return #f and #f."
|
||||||
(if (not file)
|
(if (not file)
|
||||||
(loop rest system file (cons spec specs))
|
(loop rest system file (cons spec specs))
|
||||||
(values #f #f)))
|
(values #f #f)))
|
||||||
|
((('nesting? . #t) . rest)
|
||||||
|
(loop rest system file (append specs '("nested guix"))))
|
||||||
((('load . ('package candidate)) . rest)
|
((('load . ('package candidate)) . rest)
|
||||||
(if (and (not file) (null? specs))
|
(if (and (not file) (null? specs))
|
||||||
(loop rest system candidate specs)
|
(loop rest system candidate specs)
|
||||||
|
|
|
@ -264,3 +264,12 @@ guix shell --bootstrap guile-bootstrap --container \
|
||||||
|
|
||||||
# An invalid symlink spec causes the command to fail.
|
# An invalid symlink spec causes the command to fail.
|
||||||
! guix shell --bootstrap -CS bin/guile=/usr/bin/guile guile-bootstrap -- exit
|
! guix shell --bootstrap -CS bin/guile=/usr/bin/guile guile-bootstrap -- exit
|
||||||
|
|
||||||
|
# Check whether '--nesting' works.
|
||||||
|
guix build hello -d
|
||||||
|
env="$(type -P pre-inst-env)"
|
||||||
|
if guix shell -C -D guix -- "$env" guix build hello -d # cannot work
|
||||||
|
then false; else true; fi
|
||||||
|
hello_drv="$(guix build hello -d)"
|
||||||
|
hello_drv_nested="$(cd "$(dirname env)" && guix shell --bootstrap -CW -D guix -- "$env" guix build hello -d)"
|
||||||
|
test "$hello_drv" = "$hello_drv_nested"
|
||||||
|
|
Reference in a new issue