me
/
guix
Archived
1
0
Fork 0

guix: shell: Add '--symlink' option.

* guix/scripts/pack.scm (%options): Extract symlink parsing logic to...
(symlink-spec-option-parser): ... here.
(self-contained-tarball/builder): Add a comment mentioning why a relative file
name is used for the link target.
* guix/scripts/environment.scm (show-environment-options-help): Document new
--symlink option.
(%default-options): Add default value for symlinks.
(%options): Register new symlink option.
(launch-environment/container): Add #:symlinks argument and extend doc, and
create symlinks using evaluate-populate-directive.
(guix-environment*): Pass symlinks arguments to launch-environment/container.
* doc/guix.texi (Invoking guix shell): Document it.
* tests/guix-shell.sh: Add a --symlink (negative) test.
* tests/guix-environment-container.sh: Add tests.
Maxim Cournoyer 2022-10-25 16:32:01 -04:00
parent 0bb872b379
commit b31ea797ed
No known key found for this signature in database
GPG Key ID: 1260E46482E63562
5 changed files with 75 additions and 28 deletions

View File

@ -49,7 +49,7 @@ Copyright @copyright{} 2017 humanitiesNerd@*
Copyright @copyright{} 2017, 2021 Christine Lemmer-Webber@* Copyright @copyright{} 2017, 2021 Christine Lemmer-Webber@*
Copyright @copyright{} 2017, 2018, 2019, 2020, 2021, 2022 Marius Bakke@* Copyright @copyright{} 2017, 2018, 2019, 2020, 2021, 2022 Marius Bakke@*
Copyright @copyright{} 2017, 2019, 2020, 2022 Hartmut Goebel@* Copyright @copyright{} 2017, 2019, 2020, 2022 Hartmut Goebel@*
Copyright @copyright{} 2017, 2019, 2020, 2021 Maxim Cournoyer@* Copyright @copyright{} 2017, 2019, 2020, 2021, 2022 Maxim Cournoyer@*
Copyright @copyright{} 20172022 Tobias Geerinckx-Rice@* Copyright @copyright{} 20172022 Tobias Geerinckx-Rice@*
Copyright @copyright{} 2017 George Clemmer@* Copyright @copyright{} 2017 George Clemmer@*
Copyright @copyright{} 2017 Andy Wingo@* Copyright @copyright{} 2017 Andy Wingo@*
@ -6246,6 +6246,12 @@ directory:
guix shell --container --expose=$HOME=/exchange guile -- guile guix shell --container --expose=$HOME=/exchange guile -- guile
@end example @end example
@cindex symbolic links, guix shell
@item --symlink=@var{spec}
@itemx -S @var{spec}
For containers, create the symbolic links specified by @var{spec}, as
documented in @ref{pack-symlink-option}.
@cindex file system hierarchy standard (FHS) @cindex file system hierarchy standard (FHS)
@cindex FHS (file system hierarchy standard) @cindex FHS (file system hierarchy standard)
@item --emulate-fhs @item --emulate-fhs
@ -7038,6 +7044,7 @@ Compress the resulting tarball using @var{tool}---one of @code{gzip},
@code{zstd}, @code{bzip2}, @code{xz}, @code{lzip}, or @code{none} for no @code{zstd}, @code{bzip2}, @code{xz}, @code{lzip}, or @code{none} for no
compression. compression.
@anchor{pack-symlink-option}
@item --symlink=@var{spec} @item --symlink=@var{spec}
@itemx -S @var{spec} @itemx -S @var{spec}
Add the symlinks specified by @var{spec} to the pack. This option can Add the symlinks specified by @var{spec} to the pack. This option can

View File

@ -33,8 +33,10 @@
#:use-module ((guix gexp) #:select (lower-object)) #:use-module ((guix gexp) #:select (lower-object))
#: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)
#:use-module (guix transformations) #:use-module (guix transformations)
#:autoload (ice-9 ftw) (scandir) #:autoload (ice-9 ftw) (scandir)
#:use-module (gnu build install)
#:autoload (gnu build linux-container) (call-with-container %namespaces #:autoload (gnu build linux-container) (call-with-container %namespaces
user-namespace-supported? user-namespace-supported?
unprivileged-user-namespace-supported? unprivileged-user-namespace-supported?
@ -120,6 +122,9 @@ shell'."
--expose=SPEC for containers, expose read-only host file system --expose=SPEC for containers, expose read-only host file system
according to SPEC")) according to SPEC"))
(display (G_ " (display (G_ "
-S, --symlink=SPEC for containers, add symlinks to the profile according
to SPEC, e.g. \"/usr/bin/env=bin/env\"."))
(display (G_ "
-v, --verbosity=LEVEL use the given verbosity LEVEL")) -v, --verbosity=LEVEL use the given verbosity LEVEL"))
(display (G_ " (display (G_ "
--bootstrap use bootstrap binaries to build the environment"))) --bootstrap use bootstrap binaries to build the environment")))
@ -157,6 +162,7 @@ COMMAND or an interactive shell in that environment.\n"))
(define %default-options (define %default-options
`((system . ,(%current-system)) `((system . ,(%current-system))
(substitutes? . #t) (substitutes? . #t)
(symlinks . ())
(offload? . #t) (offload? . #t)
(graft? . #t) (graft? . #t)
(print-build-trace? . #t) (print-build-trace? . #t)
@ -256,6 +262,7 @@ use '--preserve' instead~%"))
(alist-cons 'file-system-mapping (alist-cons 'file-system-mapping
(specification->file-system-mapping arg #f) (specification->file-system-mapping arg #f)
result))) result)))
(option '(#\S "symlink") #t #f symlink-spec-option-parser)
(option '(#\r "root") #t #f (option '(#\r "root") #t #f
(lambda (opt name arg result) (lambda (opt name arg result)
(alist-cons 'gc-root arg result))) (alist-cons 'gc-root arg result)))
@ -672,7 +679,7 @@ 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? (setup-hook #f)
(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
global shell is BASH, a file name for a GNU Bash binary in the store. When global shell is BASH, a file name for a GNU Bash binary in the store. When
@ -690,6 +697,9 @@ with the EMULATE-FHS? option.
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.
SYMLINKS must be a list of (SOURCE -> TARGET) tuples denoting symlinks to be
added to the container.
Preserve environment variables whose name matches the one of the regexps in Preserve environment variables whose name matches the one of the regexps in
WHILE-LIST." WHILE-LIST."
(define (optional-mapping->fs mapping) (define (optional-mapping->fs mapping)
@ -797,6 +807,15 @@ WHILE-LIST."
(mkdir-p home-dir) (mkdir-p home-dir)
(setenv "HOME" home-dir) (setenv "HOME" home-dir)
;; Create symlinks.
(let ((symlink->directives
(match-lambda
((source '-> target)
`((directory ,(dirname source))
(,source -> ,(string-append profile "/" target)))))))
(for-each (cut evaluate-populate-directive <> ".")
(append-map symlink->directives symlinks)))
;; Call an additional setup procedure, if provided. ;; Call an additional setup procedure, if provided.
(when setup-hook (when setup-hook
(setup-hook profile)) (setup-hook profile))
@ -970,6 +989,7 @@ command-line option processing with 'parse-command-line'."
(let* ((pure? (assoc-ref opts 'pure)) (let* ((pure? (assoc-ref opts 'pure))
(container? (assoc-ref opts 'container?)) (container? (assoc-ref opts 'container?))
(link-prof? (assoc-ref opts 'link-profile?)) (link-prof? (assoc-ref opts 'link-profile?))
(symlinks (assoc-ref opts 'symlinks))
(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?))
@ -1010,15 +1030,17 @@ command-line option processing with 'parse-command-line'."
(when container? (assert-container-features)) (when container? (assert-container-features))
(when (and (not container?) link-prof?) (when (not container?)
(leave (G_ "'--link-profile' cannot be used without '--container'~%"))) (when link-prof?
(when (and (not container?) user) (leave (G_ "'--link-profile' cannot be used without '--container'~%")))
(leave (G_ "'--user' cannot be used without '--container'~%"))) (when user
(when (and (not container?) no-cwd?) (leave (G_ "'--user' cannot be used without '--container'~%")))
(leave (G_ "--no-cwd cannot be used without '--container'~%"))) (when no-cwd?
(when (and (not container?) emulate-fhs?) (leave (G_ "--no-cwd cannot be used without '--container'~%")))
(leave (G_ "'--emulate-fhs' cannot be used without '--container~%'"))) (when emulate-fhs?
(leave (G_ "'--emulate-fhs' cannot be used without '--container~%'")))
(when (pair? symlinks)
(leave (G_ "'--symlink' cannot be used without '--container~%'"))))
(with-store/maybe store (with-store/maybe store
(with-status-verbosity (assoc-ref opts 'verbosity) (with-status-verbosity (assoc-ref opts 'verbosity)
@ -1099,6 +1121,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?
#:symlinks symlinks
#:setup-hook #:setup-hook
(and emulate-fhs? (and emulate-fhs?
setup-fhs)))) setup-fhs))))

View File

@ -61,7 +61,9 @@
#:use-module (srfi srfi-26) #:use-module (srfi srfi-26)
#:use-module (srfi srfi-37) #:use-module (srfi srfi-37)
#:use-module (ice-9 match) #:use-module (ice-9 match)
#:export (self-contained-tarball #:export (symlink-spec-option-parser
self-contained-tarball
debian-archive debian-archive
docker-image docker-image
squashfs-image squashfs-image
@ -160,6 +162,21 @@ its source property."
((_) str) ((_) str)
((names ... _) (loop names)))))) ((names ... _) (loop names))))))
(define (symlink-spec-option-parser opt name arg result)
"A SRFI-37 option parser for the --symlink option."
;; Note: Using 'string-split' allows us to handle empty
;; TARGET (as in "/opt/guile=", meaning that /opt/guile is
;; a symlink to the profile) correctly.
(match (string-split arg (char-set #\=))
((source target)
(let ((symlinks (assoc-ref result 'symlinks)))
(alist-cons 'symlinks
`((,source -> ,target) ,@symlinks)
(alist-delete 'symlinks result eq?))))
(x
(leave (G_ "~a: invalid symlink specification~%")
arg))))
;;; ;;;
;;; Tarball format. ;;; Tarball format.
@ -226,8 +243,9 @@ its source property."
`(,@(if (string=? parent "/") `(,@(if (string=? parent "/")
'() '()
`((directory ,parent))) `((directory ,parent)))
(,source ;; Use a relative file name for compatibility with
-> ,(relative-file-name parent target))))))) ;; relocatable packs.
(,source -> ,(relative-file-name parent target)))))))
(define directives (define directives
;; Fully-qualified symlinks. ;; Fully-qualified symlinks.
@ -1208,20 +1226,7 @@ last resort for relocation."
(lambda (opt name arg result) (lambda (opt name arg result)
(alist-cons 'compressor (lookup-compressor arg) (alist-cons 'compressor (lookup-compressor arg)
result))) result)))
(option '(#\S "symlink") #t #f (option '(#\S "symlink") #t #f symlink-spec-option-parser)
(lambda (opt name arg result)
;; Note: Using 'string-split' allows us to handle empty
;; TARGET (as in "/opt/guile=", meaning that /opt/guile is
;; a symlink to the profile) correctly.
(match (string-split arg (char-set #\=))
((source target)
(let ((symlinks (assoc-ref result 'symlinks)))
(alist-cons 'symlinks
`((,source -> ,target) ,@symlinks)
(alist-delete 'symlinks result eq?))))
(x
(leave (G_ "~a: invalid symlink specification~%")
arg)))))
(option '("save-provenance") #f #f (option '("save-provenance") #f #f
(lambda (opt name arg result) (lambda (opt name arg result)
(alist-cons 'save-provenance? #t result))) (alist-cons 'save-provenance? #t result)))

View File

@ -241,3 +241,12 @@ guix shell -CF --bootstrap guile-bootstrap glibc \
"glibc-for-fhs") "glibc-for-fhs")
0 0
1))' 1))'
# '--symlink' works.
echo "TESTING SYMLINK IN CONTAINER"
guix shell --bootstrap guile-bootstrap --container \
--symlink=/usr/bin/guile=bin/guile -- \
/usr/bin/guile --version
# A dangling symlink causes the command to fail.
! guix shell --bootstrap -CS /usr/bin/python=bin/python guile-bootstrap -- exit

View File

@ -32,6 +32,9 @@ export XDG_CONFIG_HOME
guix shell --bootstrap --pure guile-bootstrap -- guile --version guix shell --bootstrap --pure guile-bootstrap -- guile --version
# '--symlink' can only be used with --container.
! guix shell --bootstrap guile-bootstrap -S /dummy=bin/guile
# '--ad-hoc' is a thing of the past. # '--ad-hoc' is a thing of the past.
! guix shell --ad-hoc guile-bootstrap ! guix shell --ad-hoc guile-bootstrap