summaryrefslogtreecommitdiff
path: root/guix/scripts
diff options
context:
space:
mode:
authorEfraim Flashner <efraim@flashner.co.il>2023-01-30 11:33:18 +0200
committerEfraim Flashner <efraim@flashner.co.il>2023-01-30 12:39:40 +0200
commit4cf1acc7f3033b50b0bf19e02c9f522d522d338c (patch)
tree9fd64956ee60304c15387eb394cd649e49f01467 /guix/scripts
parentedb8c09addd186d9538d43b12af74d6c7aeea082 (diff)
parent595b53b74e3ef57a1c0c96108ba86d38a170a241 (diff)
Merge remote-tracking branch 'origin/master' into core-updates
Conflicts: doc/guix.texi gnu/local.mk gnu/packages/admin.scm gnu/packages/base.scm gnu/packages/chromium.scm gnu/packages/compression.scm gnu/packages/databases.scm gnu/packages/diffoscope.scm gnu/packages/freedesktop.scm gnu/packages/gnome.scm gnu/packages/gnupg.scm gnu/packages/guile.scm gnu/packages/inkscape.scm gnu/packages/llvm.scm gnu/packages/openldap.scm gnu/packages/pciutils.scm gnu/packages/ruby.scm gnu/packages/samba.scm gnu/packages/sqlite.scm gnu/packages/statistics.scm gnu/packages/syndication.scm gnu/packages/tex.scm gnu/packages/tls.scm gnu/packages/version-control.scm gnu/packages/xml.scm guix/build-system/copy.scm guix/scripts/home.scm
Diffstat (limited to 'guix/scripts')
-rw-r--r--guix/scripts/archive.scm1
-rw-r--r--guix/scripts/build.scm13
-rw-r--r--guix/scripts/challenge.scm1
-rw-r--r--guix/scripts/deploy.scm3
-rw-r--r--guix/scripts/describe.scm3
-rw-r--r--guix/scripts/environment.scm462
-rw-r--r--guix/scripts/gc.scm11
-rw-r--r--guix/scripts/graph.scm14
-rw-r--r--guix/scripts/home.scm9
-rw-r--r--guix/scripts/import.scm4
-rw-r--r--guix/scripts/import/cran.scm21
-rw-r--r--guix/scripts/offload.scm40
-rw-r--r--guix/scripts/pack.scm205
-rw-r--r--guix/scripts/package.scm1
-rw-r--r--guix/scripts/publish.scm25
-rw-r--r--guix/scripts/pull.scm1
-rw-r--r--guix/scripts/refresh.scm140
-rw-r--r--guix/scripts/repl.scm14
-rw-r--r--guix/scripts/shell.scm105
-rw-r--r--guix/scripts/size.scm1
-rw-r--r--guix/scripts/style.scm16
-rwxr-xr-xguix/scripts/substitute.scm169
-rw-r--r--guix/scripts/system.scm14
-rw-r--r--guix/scripts/system/reconfigure.scm20
-rw-r--r--guix/scripts/system/search.scm4
-rw-r--r--guix/scripts/weather.scm1
26 files changed, 847 insertions, 451 deletions
diff --git a/guix/scripts/archive.scm b/guix/scripts/archive.scm
index 1e961c84e6..3b2bdee835 100644
--- a/guix/scripts/archive.scm
+++ b/guix/scripts/archive.scm
@@ -26,7 +26,6 @@
#:select (fold-archive restore-file))
#:use-module (guix store)
#:use-module ((guix status) #:select (with-status-verbosity))
- #:use-module (guix grafts)
#:use-module (guix packages)
#:use-module (guix derivations)
#:use-module (guix monads)
diff --git a/guix/scripts/build.scm b/guix/scripts/build.scm
index 06d9ad1f0c..b4437172d7 100644
--- a/guix/scripts/build.scm
+++ b/guix/scripts/build.scm
@@ -28,10 +28,7 @@
#:use-module (guix derivations)
#:use-module (guix packages)
#:use-module (guix memoization)
- #:use-module (guix grafts)
-
#:use-module (guix utils)
-
#:use-module (guix monads)
#:use-module (guix gexp)
#:use-module (guix profiles)
@@ -383,8 +380,9 @@ use '--no-offload' instead~%")))
(format #f (G_ "Did you mean @code{~a}?
Try @option{--list-targets} to view available targets.~%")
closest))
- (display-hint (G_ "\
-Try @option{--list-targets} to view available targets.~%")))
+ (display-hint
+ (format #f (G_ "\
+Try @option{--list-targets} to view available targets.~%"))))
(exit 1))))))))
(define %standard-native-build-options
@@ -409,8 +407,9 @@ Try @option{--list-targets} to view available targets.~%")))
(format #f (G_ "Did you mean @code{~a}?
Try @option{--list-systems} to view available system types.~%")
closest))
- (display-hint (G_ "\
-Try @option{--list-systems} to view available system types.~%")))
+ (display-hint
+ (format #f (G_ "\
+Try @option{--list-systems} to view available system types.~%"))))
(exit 1))))))))
diff --git a/guix/scripts/challenge.scm b/guix/scripts/challenge.scm
index f1e5f67dab..620a1762a1 100644
--- a/guix/scripts/challenge.scm
+++ b/guix/scripts/challenge.scm
@@ -22,7 +22,6 @@
#:use-module (guix scripts)
#:use-module (guix store)
#:use-module (guix utils)
- #:use-module (guix grafts)
#:use-module (guix monads)
#:use-module (guix base32)
#:use-module (guix packages)
diff --git a/guix/scripts/deploy.scm b/guix/scripts/deploy.scm
index 2c76645173..ef6f9acc86 100644
--- a/guix/scripts/deploy.scm
+++ b/guix/scripts/deploy.scm
@@ -27,7 +27,6 @@
#:use-module (guix gexp)
#:use-module (guix ui)
#:use-module (guix utils)
- #:use-module (guix grafts)
#:use-module ((guix status) #:select (with-status-verbosity))
#:use-module (guix diagnostics)
#:use-module (guix i18n)
@@ -256,7 +255,7 @@ otherwise."
(leave (G_ "missing deployment file argument~%")))
(when (and (pair? command) (not execute-command?))
- (leave (G_ "'--' was used by '-x' was not specified~%")))
+ (leave (G_ "'--' was used, but '-x' was not specified~%")))
(with-status-verbosity (assoc-ref opts 'verbosity)
(with-store store
diff --git a/guix/scripts/describe.scm b/guix/scripts/describe.scm
index 0c310e3da8..80cd0ce00a 100644
--- a/guix/scripts/describe.scm
+++ b/guix/scripts/describe.scm
@@ -3,6 +3,7 @@
;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
;;; Copyright © 2020 Ekaitz Zarraga <ekaitz@elenq.tech>
;;; Copyright © 2021 Simon Tournier <zimon.toutoune@gmail.com>
+;;; Copyright © 2022 jgart <jgart@dismail.de>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -119,6 +120,7 @@ Display information about the channels currently in use.\n"))
(let ((intro (channel-introduction channel)))
`((name . ,(channel-name channel))
(url . ,(channel-url channel))
+ (branch . ,(channel-branch channel))
(commit . ,(channel-commit channel))
,@(if intro
`((introduction
@@ -135,6 +137,7 @@ Display information about the channels currently in use.\n"))
(format port "name: ~a~%" (channel-name channel))
(format port "url: ~a~%" (channel-url channel))
+ (format port "branch: ~a~%" (channel-branch channel))
(format port "commit: ~a~%" (channel-commit channel))
(when intro
(format port "introductioncommit: ~a~%"
diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm
index 2493134470..46435ae48e 100644
--- a/guix/scripts/environment.scm
+++ b/guix/scripts/environment.scm
@@ -1,7 +1,8 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2014, 2015, 2018 David Thompson <davet@gnu.org>
-;;; Copyright © 2015-2022 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2015-2023 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2018 Mike Gerwitz <mtg@gnu.org>
+;;; Copyright © 2022, 2023 John Kehayias <john.kehayias@protonmail.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -23,7 +24,6 @@
#:use-module (guix store)
#:use-module (guix utils)
#:use-module ((guix status) #:select (with-status-verbosity))
- #:use-module (guix grafts)
#:use-module (guix derivations)
#:use-module (guix packages)
#:use-module (guix profiles)
@@ -33,8 +33,10 @@
#:use-module ((guix gexp) #:select (lower-object))
#:use-module (guix scripts)
#:use-module (guix scripts build)
+ #:autoload (guix scripts pack) (symlink-spec-option-parser)
#:use-module (guix transformations)
#:autoload (ice-9 ftw) (scandir)
+ #:use-module (gnu build install)
#:autoload (gnu build linux-container) (call-with-container %namespaces
user-namespace-supported?
unprivileged-user-namespace-supported?
@@ -120,6 +122,9 @@ shell'."
--expose=SPEC for containers, expose read-only host file system
according to SPEC"))
(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"))
(display (G_ "
--bootstrap use bootstrap binaries to build the environment")))
@@ -157,6 +162,7 @@ COMMAND or an interactive shell in that environment.\n"))
(define %default-options
`((system . ,(%current-system))
(substitutes? . #t)
+ (symlinks . ())
(offload? . #t)
(graft? . #t)
(print-build-trace? . #t)
@@ -256,6 +262,7 @@ use '--preserve' instead~%"))
(alist-cons 'file-system-mapping
(specification->file-system-mapping arg #f)
result)))
+ (option '(#\S "symlink") #t #f symlink-spec-option-parser)
(option '(#\r "root") #t #f
(lambda (opt name arg result)
(alist-cons 'gc-root arg result)))
@@ -375,6 +382,65 @@ requisite store items i.e. the union closure of all the inputs."
input->requisites inputs)))
(return (delete-duplicates (concatenate reqs)))))
+(define (setup-fhs profile)
+ "Setup the FHS container by creating and linking expected directories from
+PROFILE (other bind mounts are done in LAUNCH-ENVIRONMENT/CONTAINER),
+providing a symlink for CC if GCC is in the container PROFILE, and writing
+/etc/ld.so.conf."
+ ;; Additional symlinks for an FHS container.
+ (define fhs-symlinks
+ `(("/lib" . "/usr/lib")
+ ,(if (target-64bit?)
+ '("/lib" . "/lib64")
+ '("/lib" . "/lib32"))
+ ("/bin" . "/usr/bin")
+ ("/sbin" . "/usr/sbin")))
+
+ ;; A procedure to symlink the contents (at the top level) of a directory,
+ ;; excluding the directory itself and parent, along with any others provided
+ ;; in EXCLUDE.
+ (define* (link-contents dir #:key (exclude '()))
+ (for-each (lambda (file)
+ (symlink (string-append profile dir "/" file)
+ (string-append dir "/" file)))
+ (scandir (string-append profile dir)
+ (negate (cut member <>
+ (append exclude '("." ".." )))))))
+
+ ;; The FHS container sets up the expected filesystem through MAPPINGS with
+ ;; FHS-MAPPINGS (in LAUNCH-ENVIRONMENT/CONTAINER), the symlinks through
+ ;; FHS-SYMLINKS, and linking the contents of PROFILE/bin and PROFILE/etc
+ ;; using LINK-CONTENTS, as these both have or will have contents for a
+ ;; non-FHS container so must be handled separately.
+ (mkdir-p "/usr")
+ (for-each (lambda (link)
+ (if (file-exists? (car link))
+ (symlink (car link) (cdr link))))
+ fhs-symlinks)
+ (link-contents "/bin" #:exclude '("sh"))
+ (mkdir-p "/etc")
+ (link-contents "/etc")
+
+ ;; Provide a frequently expected 'cc' symlink to gcc (in case it is in
+ ;; PROFILE), though this could also be done by the user in the container,
+ ;; e.g. in $HOME/.local/bin and adding that to $PATH. Note: we do this in
+ ;; /bin since that already has the sh symlink and the other (optional) FHS
+ ;; bin directories will link to /bin.
+ (let ((gcc-path (string-append profile "/bin/gcc")))
+ (if (file-exists? gcc-path)
+ (symlink gcc-path "/bin/cc")))
+
+ ;; Guix's ldconfig doesn't search in FHS default locations, so provide a
+ ;; minimal ld.so.conf.
+ (call-with-output-file "/etc/ld.so.conf"
+ (lambda (port)
+ (for-each (lambda (directory)
+ (display directory port)
+ (newline port))
+ ;; /lib/nss is needed as Guix's nss puts libraries
+ ;; there rather than in the lib directory.
+ '("/lib" "/lib/nss")))))
+
(define (status->exit-code status)
"Compute the exit code made from STATUS, a value as returned by 'waitpid',
and suitable for 'exit'."
@@ -386,11 +452,13 @@ and suitable for 'exit'."
(define primitive-exit/status (compose primitive-exit status->exit-code))
(define* (launch-environment command profile manifest
- #:key pure? (white-list '()))
- "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, except those matching the
-regexps in WHITE-LIST."
+ #:key pure? (white-list '())
+ emulate-fhs?)
+ "Load the environment of PROFILE, which corresponds to MANIFEST, and execute
+COMMAND. When PURE?, pre-existing environment variables are cleared before
+setting the new ones, except those matching the regexps in WHITE-LIST. When
+EMULATE-FHS?, first set up an FHS environment with $PATH and generate the LD
+cache."
;; Properly handle SIGINT, so pressing C-c in an interactive terminal
;; application works.
(sigaction SIGINT SIG_DFL)
@@ -406,6 +474,15 @@ regexps in WHITE-LIST."
((program . args)
(catch 'system-error
(lambda ()
+ (when emulate-fhs?
+ ;; When running in a container with EMULATE-FHS?, augment $PATH
+ ;; (optional, but to better match FHS expectations), and generate
+ ;; /etc/ld.so.cache.
+ (setenv "PATH" (string-append "/bin:/usr/bin:/sbin:/usr/sbin"
+ (if (getenv "PATH")
+ (string-append ":" (getenv "PATH"))
+ "")))
+ (invoke "ldconfig" "-X"))
(apply execlp program program args))
(lambda _
;; Report the error from here because the parent process cannot
@@ -527,7 +604,12 @@ environment~%")))
(match (vhash-assoc "PS1" actual)
(#f #f)
((_ . str)
- (when (and (getenv "PS1") (string=? str (getenv "PS1")))
+ (when (and (getenv "PS1") (string=? str (getenv "PS1"))
+
+ ;; 'PS1' might be conditional on 'GUIX_ENVIRONMENT', as
+ ;; shown in the hint below.
+ (not (or (string-contains str "$GUIX_ENVIRONMENT")
+ (string-contains str "${GUIX_ENVIRONMENT"))))
(warning (G_ "'PS1' is the same in sub-shell~%"))
(display-hint (G_ "Consider setting a different prompt for
environment shells to make them distinguishable.
@@ -536,10 +618,7 @@ If you are using Bash, you can do that by adding these lines to
@file{~/.bashrc}:
@example
-if [ -n \"$GUIX_ENVIRONMENT\" ]
-then
- export PS1=\"\\u@@\\h \\w [env]\\$ \"
-fi
+PS1='\\u@@\\h \\w${GUIX_ENVIRONMENT:+ [env]}\\$ '
@end example
"))))))
@@ -604,16 +683,27 @@ regexps in WHITE-LIST."
(define* (launch-environment/container #:key command bash user user-mappings
profile manifest link-profile? network?
- map-cwd? (white-list '()))
+ map-cwd? emulate-fhs? (setup-hook #f)
+ (symlinks '()) (white-list '()))
"Run COMMAND within a container that features the software in PROFILE.
-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 NETWORK?, access to the host system network is permitted.
-USER-MAPPINGS, a list of file system mappings, contains the user-specified
-host file systems to mount inside the container. If USER is not #f, each
-target of USER-MAPPINGS will be re-written relative to '/home/USER', and USER
-will be used for the passwd entry. LINK-PROFILE? creates a symbolic link from
-~/.guix-profile to the environment profile.
+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
+NETWORK?, access to the host system network is permitted. USER-MAPPINGS, a
+list of file system mappings, contains the user-specified host file systems to
+mount inside the container. If USER is not #f, each target of USER-MAPPINGS
+will be re-written relative to '/home/USER', and USER will be used for the
+passwd entry.
+
+When EMULATE-FHS?, set up the container to follow the Filesystem Hierarchy
+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
+with the EMULATE-FHS? option.
+
+LINK-PROFILE? creates a symbolic link from ~/.guix-profile to the
+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
WHILE-LIST."
@@ -621,6 +711,21 @@ WHILE-LIST."
(and (file-exists? (file-system-mapping-source mapping))
(file-system-mapping->bind-mount mapping)))
+ ;; File system mappings for an FHS container, where the entire directory can
+ ;; be mapped. Others (bin and etc) will already have contents and need to
+ ;; use LINK-CONTENTS (defined in SETUP-FHS) to symlink the directory
+ ;; contents.
+ (define fhs-mappings
+ (map (lambda (mapping)
+ (file-system-mapping
+ (source (string-append profile (car mapping)))
+ (target (cdr mapping))))
+ '(("/lib" . "/lib")
+ ("/include" . "/usr/include")
+ ("/sbin" . "/sbin")
+ ("/libexec" . "/usr/libexec")
+ ("/share" . "/usr/share"))))
+
(mlet %store-monad ((reqs (inputs->requisites
(list (direct-store-path bash) profile))))
(return
@@ -628,14 +733,21 @@ WHILE-LIST."
(home (getenv "HOME"))
(uid (if user 1000 (getuid)))
(gid (if user 1000 (getgid)))
- (passwd (let ((pwd (getpwuid (getuid))))
+
+ ;; On a foreign distro, the name service switch might be
+ ;; dysfunctional and 'getpwuid' throws. Don't let that hamper
+ ;; operations.
+ (passwd (let ((pwd (false-if-exception (getpwuid (getuid)))))
(password-entry
- (name (or user (passwd:name pwd)))
- (real-name (if user
+ (name (or user
+ (and=> pwd passwd:name)
+ (getenv "USER")
+ "charlie"))
+ (real-name (if (or user (not pwd))
""
(passwd:gecos pwd)))
(uid uid) (gid gid) (shell bash)
- (directory (if user
+ (directory (if (or user (not pwd))
(string-append "/home/" user)
(passwd:dir pwd))))))
(groups (list (group-entry (name "users") (gid gid))
@@ -675,6 +787,11 @@ WHILE-LIST."
(filter-map optional-mapping->fs
%network-file-mappings)
'())
+ ;; Mappings for an FHS container.
+ (if emulate-fhs?
+ (filter-map optional-mapping->fs
+ fhs-mappings)
+ '())
(map file-system-mapping->bind-mount
mappings))))
(exit/status
@@ -702,6 +819,19 @@ WHILE-LIST."
(mkdir-p 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.
+ (when setup-hook
+ (setup-hook profile))
+
;; If requested, link $GUIX_ENVIRONMENT to $HOME/.guix-profile;
;; this allows programs expecting that path to continue working as
;; expected within a container.
@@ -743,7 +873,8 @@ WHILE-LIST."
(if link-profile?
(string-append home-dir "/.guix-profile")
profile)
- manifest #:pure? #f)))
+ manifest #:pure? #f
+ #:emulate-fhs? emulate-fhs?)))
#:guest-uid uid
#:guest-gid gid
#:namespaces (if network?
@@ -861,147 +992,158 @@ message if any test fails."
(category development)
(synopsis "spawn one-off software environments (deprecated)")
- (guix-environment* (parse-args args)))
+ (with-error-handling
+ (guix-environment* (parse-args args))))
(define (guix-environment* opts)
"Run the 'guix environment' command on OPTS, an alist resulting for
command-line option processing with 'parse-command-line'."
- (with-error-handling
- (let* ((pure? (assoc-ref opts 'pure))
- (container? (assoc-ref opts 'container?))
- (link-prof? (assoc-ref opts 'link-profile?))
- (network? (assoc-ref opts 'network?))
- (no-cwd? (assoc-ref opts 'no-cwd?))
- (user (assoc-ref opts 'user))
- (bootstrap? (assoc-ref opts 'bootstrap?))
- (system (assoc-ref opts 'system))
- (profile (assoc-ref opts 'profile))
- (command (or (assoc-ref opts 'exec)
- ;; Spawn a shell if the user didn't specify
- ;; anything in particular.
- (if container?
- ;; The user's shell is likely not available
- ;; within the container.
- '("/bin/sh")
- (list %default-shell))))
- (mappings (pick-all opts 'file-system-mapping))
- (white-list (pick-all opts 'inherit-regexp)))
-
- (define store-needed?
- ;; Whether connecting to the daemon is needed.
- (or container? (not profile)))
-
- (define-syntax-rule (with-store/maybe store exp ...)
- ;; Evaluate EXP... with STORE bound to a connection, unless
- ;; STORE-NEEDED? is false, in which case STORE is bound to #f.
- (let ((proc (lambda (store) exp ...)))
- (if store-needed?
- (with-store s
- (set-build-options-from-command-line s opts)
- (with-build-handler (build-notifier #:use-substitutes?
- (assoc-ref opts 'substitutes?)
- #:verbosity
- (assoc-ref opts 'verbosity)
- #:dry-run?
- (assoc-ref opts 'dry-run?))
- (proc s)))
- (proc #f))))
-
- (when container? (assert-container-features))
-
- (when (and (not container?) link-prof?)
+ (let* ((pure? (assoc-ref opts 'pure))
+ (container? (assoc-ref opts 'container?))
+ (link-prof? (assoc-ref opts 'link-profile?))
+ (symlinks (assoc-ref opts 'symlinks))
+ (network? (assoc-ref opts 'network?))
+ (no-cwd? (assoc-ref opts 'no-cwd?))
+ (emulate-fhs? (assoc-ref opts 'emulate-fhs?))
+ (user (assoc-ref opts 'user))
+ (bootstrap? (assoc-ref opts 'bootstrap?))
+ (system (assoc-ref opts 'system))
+ (profile (assoc-ref opts 'profile))
+ (command (or (assoc-ref opts 'exec)
+ ;; Spawn a shell if the user didn't specify
+ ;; anything in particular.
+ (if container?
+ ;; The user's shell is likely not available
+ ;; within the container.
+ '("/bin/sh")
+ (list %default-shell))))
+ (mappings (pick-all opts 'file-system-mapping))
+ (white-list (pick-all opts 'inherit-regexp)))
+
+ (define store-needed?
+ ;; Whether connecting to the daemon is needed.
+ (or container? (not profile)))
+
+ (define-syntax-rule (with-store/maybe store exp ...)
+ ;; Evaluate EXP... with STORE bound to a connection, unless
+ ;; STORE-NEEDED? is false, in which case STORE is bound to #f.
+ (let ((proc (lambda (store) exp ...)))
+ (if store-needed?
+ (with-store s
+ (set-build-options-from-command-line s opts)
+ (with-build-handler (build-notifier #:use-substitutes?
+ (assoc-ref opts 'substitutes?)
+ #:verbosity
+ (assoc-ref opts 'verbosity)
+ #:dry-run?
+ (assoc-ref opts 'dry-run?))
+ (proc s)))
+ (proc #f))))
+
+ (when container? (assert-container-features))
+
+ (when (not container?)
+ (when link-prof?
(leave (G_ "'--link-profile' cannot be used without '--container'~%")))
- (when (and (not container?) user)
+ (when user
(leave (G_ "'--user' cannot be used without '--container'~%")))
- (when (and (not container?) no-cwd?)
- (leave (G_ "--no-cwd cannot be used without --container~%")))
-
-
- (with-store/maybe store
- (with-status-verbosity (assoc-ref opts 'verbosity)
- (define manifest-from-opts
- (options/resolve-packages store opts))
-
- (define manifest
- (if profile
- (profile-manifest profile)
- manifest-from-opts))
-
- (when (and profile
- (> (length (manifest-entries manifest-from-opts)) 0))
- (leave (G_ "'--profile' cannot be used with package options~%")))
-
- (when (null? (manifest-entries manifest))
- (warning (G_ "no packages specified; creating an empty environment~%")))
-
- ;; Use the bootstrap Guile when requested.
- (parameterize ((%graft? (assoc-ref opts 'graft?))
- (%guile-for-build
- (and store-needed?
- (package-derivation
- store
- (if bootstrap?
- %bootstrap-guile
- (default-guile))))))
- (run-with-store store
- ;; Containers need a Bourne shell at /bin/sh.
- (mlet* %store-monad ((bash (environment-bash container?
- bootstrap?
- system))
- (prof-drv (if profile
- (return #f)
- (manifest->derivation
- manifest system bootstrap?)))
- (profile -> (if profile
- (readlink* profile)
- (derivation->output-path prof-drv)))
- (gc-root -> (assoc-ref opts 'gc-root)))
-
- ;; First build the inputs. This is necessary even for
- ;; --search-paths. Additionally, we might need to build bash for
- ;; a container.
- (mbegin %store-monad
- (mwhen store-needed?
- (built-derivations (append
- (if prof-drv (list prof-drv) '())
- (if (derivation? bash) (list bash) '()))))
- (mwhen gc-root
- (register-gc-root profile gc-root))
-
- (mwhen (assoc-ref opts 'check?)
- (return
- (if container?
- (warning (G_ "'--check' is unnecessary \
+ (when no-cwd?
+ (leave (G_ "--no-cwd 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-status-verbosity (assoc-ref opts 'verbosity)
+ (define manifest-from-opts
+ (options/resolve-packages store opts))
+
+ (define manifest
+ (if profile
+ (profile-manifest profile)
+ manifest-from-opts))
+
+ (when (and profile
+ (> (length (manifest-entries manifest-from-opts)) 0))
+ (leave (G_ "'--profile' cannot be used with package options~%")))
+
+ (when (null? (manifest-entries manifest))
+ (warning (G_ "no packages specified; creating an empty environment~%")))
+
+ ;; Use the bootstrap Guile when requested.
+ (parameterize ((%graft? (assoc-ref opts 'graft?))
+ (%guile-for-build
+ (and store-needed?
+ (package-derivation
+ store
+ (if bootstrap?
+ %bootstrap-guile
+ (default-guile))))))
+ (run-with-store store
+ ;; Containers need a Bourne shell at /bin/sh.
+ (mlet* %store-monad ((bash (environment-bash container?
+ bootstrap?
+ system))
+ (prof-drv (if profile
+ (return #f)
+ (manifest->derivation
+ manifest system bootstrap?)))
+ (profile -> (if profile
+ (readlink* profile)
+ (derivation->output-path prof-drv)))
+ (gc-root -> (assoc-ref opts 'gc-root)))
+
+ ;; First build the inputs. This is necessary even for
+ ;; --search-paths. Additionally, we might need to build bash for
+ ;; a container.
+ (mbegin %store-monad
+ (mwhen store-needed?
+ (built-derivations (append
+ (if prof-drv (list prof-drv) '())
+ (if (derivation? bash) (list bash) '()))))
+ (mwhen gc-root
+ (register-gc-root profile gc-root))
+
+ (mwhen (assoc-ref opts 'check?)
+ (return
+ (if container?
+ (warning (G_ "'--check' is unnecessary \
when using '--container'; doing nothing~%"))
- (validate-child-shell-environment profile manifest))))
-
- (cond
- ((assoc-ref opts 'search-paths)
- (show-search-paths profile manifest #:pure? pure?)
- (return #t))
- (container?
- (let ((bash-binary
- (if bootstrap?
- (derivation->output-path bash)
- (string-append (derivation->output-path bash)
- "/bin/sh"))))
- (launch-environment/container #:command command
- #:bash bash-binary
- #:user user
- #:user-mappings mappings
- #:profile profile
- #:manifest manifest
- #:white-list white-list
- #:link-profile? link-prof?
- #:network? network?
- #:map-cwd? (not no-cwd?))))
-
- (else
- (return
- (exit/status
- (launch-environment/fork command profile manifest
- #:white-list white-list
- #:pure? pure?))))))))))))))
+ (validate-child-shell-environment profile manifest))))
+
+ (cond
+ ((assoc-ref opts 'search-paths)
+ (show-search-paths profile manifest #:pure? pure?)
+ (return #t))
+ (container?
+ (let ((bash-binary
+ (if bootstrap?
+ (derivation->output-path bash)
+ (string-append (derivation->output-path bash)
+ "/bin/sh"))))
+ (launch-environment/container #:command command
+ #:bash bash-binary
+ #:user user
+ #:user-mappings mappings
+ #:profile profile
+ #:manifest manifest
+ #:white-list white-list
+ #:link-profile? link-prof?
+ #:network? network?
+ #:map-cwd? (not no-cwd?)
+ #:emulate-fhs? emulate-fhs?
+ #:symlinks symlinks
+ #:setup-hook
+ (and emulate-fhs?
+ setup-fhs))))
+
+ (else
+ (return
+ (exit/status
+ (launch-environment/fork command profile manifest
+ #:white-list white-list
+ #:pure? pure?)))))))))))))
;;; Local Variables:
;;; eval: (put 'with-store/maybe 'scheme-indent-function 1)
diff --git a/guix/scripts/gc.scm b/guix/scripts/gc.scm
index 65cd4bdf8b..5e775c5cdb 100644
--- a/guix/scripts/gc.scm
+++ b/guix/scripts/gc.scm
@@ -1,5 +1,6 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2012-2013, 2015-2020, 2022 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2022 Efraim Flashner <efraim@flashner.co.il>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -27,6 +28,7 @@
generation-number)
#:autoload (guix scripts package) (delete-generations)
#:autoload (gnu home) (home-generation-base)
+ #:autoload (guix store database) (vacuum-database)
#:use-module (ice-9 match)
#:use-module (ice-9 regex)
#:use-module (srfi srfi-1)
@@ -87,6 +89,10 @@ Invoke the garbage collector.\n"))
--clear-failures remove PATHS from the set of cached failures"))
(newline)
(display (G_ "
+ --vacuum-database repack the sqlite database tracking the store
+ using less space"))
+ (newline)
+ (display (G_ "
-h, --help display this help and exit"))
(display (G_ "
-V, --version display version information and exit"))
@@ -131,6 +137,11 @@ current one."
(lambda args
(show-version-and-exit "guix gc")))
+ (option '("vacuum-database") #f #f
+ (lambda args
+ (vacuum-database)
+ (exit 0)))
+
(option '(#\C "collect-garbage") #f #t
(lambda (opt name arg result)
(let ((result (alist-cons 'action 'collect-garbage
diff --git a/guix/scripts/graph.scm b/guix/scripts/graph.scm
index 2f102180c9..6847dd1962 100644
--- a/guix/scripts/graph.scm
+++ b/guix/scripts/graph.scm
@@ -569,6 +569,12 @@ Emit a representation of the dependency graph of PACKAGE...\n"))
(category packaging)
(synopsis "view and query package dependency graphs")
+ (define (shorter? str1 str2)
+ (< (string-length str1) (string-length str2)))
+
+ (define length-sorted
+ (cut sort <> shorter?))
+
(with-error-handling
(define opts
(parse-command-line args %options
@@ -598,13 +604,17 @@ Emit a representation of the dependency graph of PACKAGE...\n"))
(run-with-store store
;; XXX: Since grafting can trigger unsolicited builds, disable it.
- (mlet %store-monad ((_ (set-grafting #f))
+ (mlet %store-monad ((_g (set-grafting #f))
(nodes (mapm %store-monad
(node-type-convert type)
(reverse items))))
(if (assoc-ref opts 'path?)
+ ;; Sort by string length such that, in case of multiple
+ ;; outputs, the shortest one (which corresponds to "out") is
+ ;; picked (yup, a hack).
(match nodes
- (((node1 _ ...) (node2 _ ...))
+ (((= length-sorted (node1 _ ...))
+ (= length-sorted (node2 _ ...)))
(display-path node1 node2 type))
(_
(leave (G_ "'--path' option requires exactly two \
diff --git a/guix/scripts/home.scm b/guix/scripts/home.scm
index ae830d0b48..a37f059711 100644
--- a/guix/scripts/home.scm
+++ b/guix/scripts/home.scm
@@ -3,7 +3,7 @@
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
;;; Copyright © 2021 Pierre Langlois <pierre.langlois@gmx.com>
;;; Copyright © 2021 Oleg Pykhalov <go.wigust@gmail.com>
-;;; Copyright © 2022 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2022-2023 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2022 Arun Isaac <arunisaac@systemreboot.net>
;;; Copyright © 2022 Antero Mejr <antero@mailbox.org>
;;;
@@ -48,7 +48,6 @@
#:use-module (guix derivations)
#:use-module (guix ui)
#:autoload (guix colors) (supports-hyperlinks? file-hyperlink)
- #:use-module (guix grafts)
#:use-module (guix packages)
#:use-module (guix profiles)
#:use-module (guix store)
@@ -173,7 +172,7 @@ Some ACTIONS support additional ARGS.\n"))
(alist-cons 'dry-run? #t result)))
(option '(#\V "version") #f #f
(lambda args
- (show-version-and-exit "guix show")))
+ (show-version-and-exit "guix home")))
(option '(#\v "verbosity") #t #f
(lambda (opt name arg result)
(let ((level (string->number* arg)))
@@ -477,7 +476,7 @@ resulting from command-line parsing."
(define (ensure-home-environment file-or-exp obj)
(ensure-profile-directory)
(unless (home-environment? obj)
- (leave (G_ "'~a' does not return a home environment ~%")
+ (leave (G_ "'~a' does not return a home environment~%")
file-or-exp))
obj)
@@ -707,7 +706,7 @@ deploy the home environment described by these files.\n")
(define (service-type-description-string type)
"Return the rendered and localised description of TYPE, a service type."
(and=> (service-type-description type)
- (compose texi->plain-text P_)))
+ (compose texi->plain-text G_)))
(define %service-type-metrics
;; Metrics used to estimate the relevance of a search result.
diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm
index bd3cfd2dc3..2bca927d63 100644
--- a/guix/scripts/import.scm
+++ b/guix/scripts/import.scm
@@ -97,7 +97,9 @@ Run IMPORTER with ARGS.\n"))
((? list? expressions)
(for-each (lambda (expr)
(print expr)
- (newline))
+ ;; Two newlines: one after the closing paren, and
+ ;; one to leave a blank line.
+ (newline) (newline))
expressions))
(x
(leave (G_ "'~a' import failed~%") importer))))
diff --git a/guix/scripts/import/cran.scm b/guix/scripts/import/cran.scm
index 2934d4300a..5298f059f2 100644
--- a/guix/scripts/import/cran.scm
+++ b/guix/scripts/import/cran.scm
@@ -53,6 +53,9 @@ Import and convert the CRAN package for PACKAGE-NAME.\n"))
(display (G_ "
-s, --style=STYLE choose output style, either specification or variable"))
(display (G_ "
+ -p, --license-prefix=PREFIX
+ add custom prefix to licenses"))
+ (display (G_ "
-V, --version display version information and exit"))
(newline)
(show-bug-report-information))
@@ -74,6 +77,10 @@ Import and convert the CRAN package for PACKAGE-NAME.\n"))
(lambda (opt name arg result)
(alist-cons 'style (string->symbol arg)
(alist-delete 'style result))))
+ (option '(#\p "license-prefix") #t #f
+ (lambda (opt name arg result)
+ (alist-cons 'license-prefix arg
+ (alist-delete 'license-prefix result))))
(option '(#\r "recursive") #f #f
(lambda (opt name arg result)
(alist-cons 'recursive #t result)))
@@ -95,7 +102,13 @@ Import and convert the CRAN package for PACKAGE-NAME.\n"))
(('argument . value)
value)
(_ #f))
- (reverse opts))))
+ (reverse opts)))
+ (prefix (assoc-ref opts 'license-prefix))
+ (prefix-proc (if (string? prefix)
+ (lambda (symbol)
+ (string->symbol
+ (string-append prefix (symbol->string symbol))))
+ identity)))
(parameterize ((%input-style (assoc-ref opts 'style)))
(match args
((spec)
@@ -107,11 +120,13 @@ Import and convert the CRAN package for PACKAGE-NAME.\n"))
(filter identity
(cran-recursive-import name
#:version version
- #:repo (or (assoc-ref opts 'repo) 'cran)))))
+ #:repo (or (assoc-ref opts 'repo) 'cran)
+ #:license-prefix prefix-proc))))
;; Single import
(let ((sexp (cran->guix-package name
#:version version
- #:repo (or (assoc-ref opts 'repo) 'cran))))
+ #:repo (or (assoc-ref opts 'repo) 'cran)
+ #:license-prefix prefix-proc)))
(unless sexp
(leave (G_ "failed to download description for package '~a'~%")
name))
diff --git a/guix/scripts/offload.scm b/guix/scripts/offload.scm
index 925325ef5f..578b3b9888 100644
--- a/guix/scripts/offload.scm
+++ b/guix/scripts/offload.scm
@@ -25,7 +25,7 @@
#:autoload (ssh auth) (userauth-public-key!)
#:autoload (ssh session) (make-session
connect! get-error
- disconnect! session-set!)
+ disconnect! session-set! session-get)
#:autoload (ssh version) (zlib-support?)
#:use-module (guix config)
#:use-module (guix records)
@@ -34,7 +34,8 @@
send-files retrieve-files retrieve-files*
remote-inferior report-guile-error)
#:use-module (guix store)
- #:autoload (guix inferior) (inferior-eval close-inferior inferior?)
+ #:autoload (guix inferior) (inferior-eval close-inferior
+ inferior? inferior-protocol-error?)
#:autoload (guix derivations) (read-derivation-from-file
derivation-file-name
build-derivations)
@@ -111,7 +112,7 @@
;; A #f value tells the offload scheduler to disregard the load of the build
;; machine when selecting the best offload machine.
(overload-threshold build-machine-overload-threshold ; inexact real between
- (default 0.6)) ; 0.0 and 1.0 | #f
+ (default 0.8)) ; 0.0 and 1.0 | #f
(parallel-builds build-machine-parallel-builds ; number
(default 1))
(speed build-machine-speed ; inexact real
@@ -473,6 +474,15 @@ logical cores available, to give a rough estimation of CPU usage. Return
(vector-set! vec j (vector-ref vec (- i 1)))
(loop (cons val result) (- i 1))))))))
+(define (remote-inferior* session)
+ "Like 'remote-inferior', but upon error return #f."
+ (or (guard (c ((inferior-protocol-error? c) #f))
+ (remote-inferior session))
+ (begin
+ (warning (G_ "failed to run 'guix repl' on machine '~a'~%")
+ (session-get session 'host))
+ #f)))
+
(define (choose-build-machine machines)
"Return two values: the best machine among MACHINES and its build
slot (which must later be released with 'release-build-slot'), or #f and #f."
@@ -511,7 +521,7 @@ slot (which must later be released with 'release-build-slot'), or #f and #f."
;; too costly to call it once for every machine.
(let* ((session (false-if-exception (open-ssh-session best
%short-timeout)))
- (node (and session (remote-inferior session)))
+ (node (and session (remote-inferior* session)))
(load (and node (node-load node)))
(threshold (build-machine-overload-threshold best))
(space (and node (node-free-disk-space node))))
@@ -708,6 +718,11 @@ machine."
(and (string=? (build-machine-name m1) (build-machine-name m2))
(= (build-machine-port m1) (build-machine-port m2))))
+ (define (if-true proc)
+ (lambda args
+ (when (every ->bool args)
+ (apply proc args))))
+
;; A given build machine may appear several times (e.g., once for
;; "x86_64-linux" and a second time for "i686-linux"); test them only once.
(let ((machines (filter pred
@@ -718,12 +733,12 @@ machine."
(let* ((names (map build-machine-name machines))
(sockets (map build-machine-daemon-socket machines))
(sessions (map (cut open-ssh-session <> %short-timeout) machines))
- (nodes (map remote-inferior sessions)))
- (for-each assert-node-has-guix nodes names)
- (for-each assert-node-repl nodes names)
- (for-each assert-node-can-import sessions nodes names sockets)
- (for-each assert-node-can-export sessions nodes names sockets)
- (for-each close-inferior nodes)
+ (nodes (map remote-inferior* sessions)))
+ (for-each (if-true assert-node-has-guix) nodes names)
+ (for-each (if-true assert-node-repl) nodes names)
+ (for-each (if-true assert-node-can-import) sessions nodes names sockets)
+ (for-each (if-true assert-node-can-export) sessions nodes names sockets)
+ (for-each (if-true close-inferior) nodes)
(for-each disconnect! sessions))))
(define (check-machine-status machine-file pred)
@@ -743,10 +758,9 @@ machine."
(define session
(open-ssh-session machine %short-timeout))
- (match (remote-inferior session)
+ (match (remote-inferior* session)
(#f
- (warning (G_ "failed to run 'guix repl' on machine '~a'~%")
- (build-machine-name machine)))
+ #f)
((? inferior? inferior)
(let ((now (car (gettimeofday))))
(match (inferior-eval '(list (uname)
diff --git a/guix/scripts/pack.scm b/guix/scripts/pack.scm
index 78b6978c92..f65642fb85 100644
--- a/guix/scripts/pack.scm
+++ b/guix/scripts/pack.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2015, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2015, 2017-2022 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2017, 2018 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2018 Konrad Hinsen <konrad.hinsen@fastmail.net>
;;; Copyright © 2018 Chris Marusich <cmmarusich@gmail.com>
@@ -33,7 +33,6 @@
#:use-module (guix store)
#:use-module ((guix status) #:select (with-status-verbosity))
#:use-module ((guix self) #:select (make-config.scm))
- #:use-module (guix grafts)
#:autoload (guix inferior) (inferior-package?
inferior-package-name
inferior-package-version)
@@ -43,6 +42,7 @@
#:use-module (guix profiles)
#:use-module (guix describe)
#:use-module (guix derivations)
+ #:use-module (guix diagnostics)
#:use-module (guix search-paths)
#:use-module (guix build-system gnu)
#:use-module (guix scripts build)
@@ -60,9 +60,12 @@
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-9)
#:use-module (srfi srfi-26)
+ #:use-module (srfi srfi-35)
#:use-module (srfi srfi-37)
#:use-module (ice-9 match)
- #:export (self-contained-tarball
+ #:export (symlink-spec-option-parser
+
+ self-contained-tarball
debian-archive
docker-image
squashfs-image
@@ -161,6 +164,36 @@ its source property."
((_) str)
((names ... _) (loop names))))))
+(define (symlink-spec-option-parser opt name arg result)
+ "A SRFI-37 option parser for the --symlink option. The symlink spec accepts
+the link file name as its left-hand side value and its target as its
+right-hand side value. The target must be a relative link."
+ ;; 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 #\=)
+ ((source target)
+ (when (string-prefix? "/" target)
+ (raise-exception
+ (make-compound-condition
+ (formatted-message (G_ "symlink target is absolute: '~a'~%") target)
+ (condition
+ (&fix-hint (hint (format #f (G_ "The target of the symlink must be
+relative rather than absolute, as it is relative to the profile created.
+Perhaps the source and target components of the symlink spec were inverted?
+Below is a valid example, where the @file{/usr/bin/env} symbolic link is to
+target the profile's @file{bin/env} file:
+@example
+--symlink=/usr/bin/env=bin/env
+@end example"))))))))
+ (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.
@@ -227,8 +260,9 @@ its source property."
`(,@(if (string=? parent "/")
'()
`((directory ,parent)))
- (,source
- -> ,(relative-file-name parent target)))))))
+ ;; Use a relative file name for compatibility with
+ ;; relocatable packs.
+ (,source -> ,(relative-file-name parent target)))))))
(define directives
;; Fully-qualified symlinks.
@@ -668,7 +702,6 @@ Valid compressors are: ~a~%") compressor-name %valid-compressors)))
(guix build utils)
(guix profiles)
(ice-9 match)
- ((oop goops) #:select (get-keyword))
(srfi srfi-1))
(define machine-type
@@ -729,15 +762,20 @@ Valid compressors are: ~a~%") compressor-name %valid-compressors)))
(copy-file #+data-tarball data-tarball-file-name)
+ (define (keyword-ref lst keyword)
+ (match (memq keyword lst)
+ ((_ value . _) value)
+ (#f #f)))
+
;; Generate the control archive.
(define control-file
- (get-keyword #:control-file '#$extra-options))
+ (keyword-ref '#$extra-options #:control-file))
(define postinst-file
- (get-keyword #:postinst-file '#$extra-options))
+ (keyword-ref '#$extra-options #:postinst-file))
(define triggers-file
- (get-keyword #:triggers-file '#$extra-options))
+ (keyword-ref '#$extra-options #:triggers-file))
(define control-tarball-file-name
(string-append "control.tar"
@@ -1209,20 +1247,7 @@ last resort for relocation."
(lambda (opt name arg result)
(alist-cons 'compressor (lookup-compressor arg)
result)))
- (option '(#\S "symlink") #t #f
- (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 '(#\S "symlink") #t #f symlink-spec-option-parser)
(option '("save-provenance") #f #f
(lambda (opt name arg result)
(alist-cons 'save-provenance? #t result)))
@@ -1322,74 +1347,74 @@ Create a bundle of PACKAGE.\n"))
(category development)
(synopsis "create application bundles")
- (define opts
- (parse-command-line args %options (list %default-options)))
-
- (define maybe-package-argument
- ;; Given an option pair, return a package, a package/output tuple, or #f.
- (match-lambda
- (('argument . spec)
- (call-with-values
- (lambda ()
- (specification->package+output spec))
- list))
- (('expression . exp)
- (read/eval-package-expression exp))
- (x #f)))
-
- (define (manifest-from-args store opts)
- (let* ((transform (options->transformation opts))
- (packages (map (match-lambda
- (((? package? package) output)
- (list (transform package) output))
- ((? package? package)
- (list (transform package) "out")))
- (reverse
- (filter-map maybe-package-argument opts))))
- (manifests (filter-map (match-lambda
- (('manifest . file) file)
- (_ #f))
- opts)))
- (define with-provenance
- (if (assoc-ref opts 'save-provenance?)
- (lambda (manifest)
- (map-manifest-entries
- (lambda (entry)
- (let ((entry (manifest-entry-with-provenance entry)))
- (unless (assq 'provenance (manifest-entry-properties entry))
- (warning (G_ "could not determine provenance of package ~a~%")
- (manifest-entry-name entry)))
- entry))
- manifest))
- identity))
-
- (with-provenance
- (cond
- ((and (not (null? manifests)) (not (null? packages)))
- (leave (G_ "both a manifest and a package list were given~%")))
- ((not (null? manifests))
- (concatenate-manifests
- (map (lambda (file)
- (let ((user-module (make-user-module
- '((guix profiles) (gnu)))))
- (load* file user-module)))
- manifests)))
- (else
- (packages->manifest packages))))))
-
- (define (process-file-arg opts name)
- ;; Validate that the file exists and return it as a <local-file> object,
- ;; else #f.
- (let ((value (assoc-ref opts name)))
- (match value
- ((and (? string?) (not (? file-exists?)))
- (leave (G_ "file provided with option ~a does not exist: ~a~%")
- (string-append "--" (symbol->string name)) value))
- ((? string?)
- (local-file value))
- (#f #f))))
-
(with-error-handling
+ (define opts
+ (parse-command-line args %options (list %default-options)))
+
+ (define maybe-package-argument
+ ;; Given an option pair, return a package, a package/output tuple, or #f.
+ (match-lambda
+ (('argument . spec)
+ (call-with-values
+ (lambda ()
+ (specification->package+output spec))
+ list))
+ (('expression . exp)
+ (read/eval-package-expression exp))
+ (x #f)))
+
+ (define (manifest-from-args store opts)
+ (let* ((transform (options->transformation opts))
+ (packages (map (match-lambda
+ (((? package? package) output)
+ (list (transform package) output))
+ ((? package? package)
+ (list (transform package) "out")))
+ (reverse
+ (filter-map maybe-package-argument opts))))
+ (manifests (filter-map (match-lambda
+ (('manifest . file) file)
+ (_ #f))
+ opts)))
+ (define with-provenance
+ (if (assoc-ref opts 'save-provenance?)
+ (lambda (manifest)
+ (map-manifest-entries
+ (lambda (entry)
+ (let ((entry (manifest-entry-with-provenance entry)))
+ (unless (assq 'provenance (manifest-entry-properties entry))
+ (warning (G_ "could not determine provenance of package ~a~%")
+ (manifest-entry-name entry)))
+ entry))
+ manifest))
+ identity))
+
+ (with-provenance
+ (cond
+ ((and (not (null? manifests)) (not (null? packages)))
+ (leave (G_ "both a manifest and a package list were given~%")))
+ ((not (null? manifests))
+ (concatenate-manifests
+ (map (lambda (file)
+ (let ((user-module (make-user-module
+ '((guix profiles) (gnu)))))
+ (load* file user-module)))
+ manifests)))
+ (else
+ (packages->manifest packages))))))
+
+ (define (process-file-arg opts name)
+ ;; Validate that the file exists and return it as a <local-file> object,
+ ;; else #f.
+ (let ((value (assoc-ref opts name)))
+ (match value
+ ((and (? string?) (not (? file-exists?)))
+ (leave (G_ "file provided with option ~a does not exist: ~a~%")
+ (string-append "--" (symbol->string name)) value))
+ ((? string?)
+ (local-file value))
+ (#f #f))))
+
(with-store store
(with-status-verbosity (assoc-ref opts 'verbosity)
;; Set the build options before we do anything else.
diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm
index 134337b13e..2f774621bb 100644
--- a/guix/scripts/package.scm
+++ b/guix/scripts/package.scm
@@ -34,7 +34,6 @@
#:use-module ((guix status) #:select (with-status-verbosity))
#:use-module ((guix build syscalls) #:select (terminal-rows))
#:use-module (guix store)
- #:use-module (guix grafts)
#:use-module (guix derivations)
#:use-module (guix packages)
#:use-module (guix profiles)
diff --git a/guix/scripts/publish.scm b/guix/scripts/publish.scm
index 3bf3bd9c7c..6307ae54bb 100644
--- a/guix/scripts/publish.scm
+++ b/guix/scripts/publish.scm
@@ -4,7 +4,7 @@
;;; Copyright © 2015-2022 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2020 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;; Copyright © 2021 Simon Tournier <zimon.toutoune@gmail.com>
-;;; Copyright © 2021 Mathieu Othacehe <othacehe@gnu.org>
+;;; Copyright © 2021, 2022 Mathieu Othacehe <othacehe@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -375,14 +375,28 @@ References: ~a~%"
compression)))
compressions))))
+;; Custom header to indicate that baking is in progress.
+(declare-opaque-header! "X-Baking")
+
(define* (not-found request
- #:key (phrase "Resource not found")
+ #:key
+ baking?
+ (phrase "Resource not found")
ttl)
"Render 404 response for REQUEST."
+ (format #t "-> ~a ~a: 404~a~%"
+ (request-method request)
+ (uri-path (request-uri request))
+ (if baking? " (baking)" ""))
(values (build-response #:code 404
- #:headers (if ttl
- `((cache-control (max-age . ,ttl)))
- '()))
+ #:headers
+ (append
+ (if ttl
+ `((cache-control (max-age . ,ttl)))
+ '())
+ (if baking?
+ '((x-baking . "1"))
+ '())))
(string-append phrase ": "
(uri-path (request-uri request)))))
@@ -587,6 +601,7 @@ requested using POOL."
#:nar-path nar-path
#:compressions compressions)
(not-found request
+ #:baking? #t
#:phrase "We're baking it"
#:ttl 300))) ;should be available within 5m
(else
diff --git a/guix/scripts/pull.scm b/guix/scripts/pull.scm
index 19224cf70b..7b6c58dbc3 100644
--- a/guix/scripts/pull.scm
+++ b/guix/scripts/pull.scm
@@ -31,7 +31,6 @@
#:use-module (guix derivations)
#:use-module (guix profiles)
#:use-module (guix gexp)
- #:use-module (guix grafts)
#:use-module (guix memoization)
#:use-module (guix monads)
#:use-module (guix channels)
diff --git a/guix/scripts/refresh.scm b/guix/scripts/refresh.scm
index 14329751f8..6498d73c2b 100644
--- a/guix/scripts/refresh.scm
+++ b/guix/scripts/refresh.scm
@@ -9,6 +9,7 @@
;;; Copyright © 2019 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2020 Simon Tournier <zimon.toutoune@gmail.com>
;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
+;;; Copyright © 2022 Hartmut Goebel <h.goebel@crazy-compilers.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -46,6 +47,7 @@
#:use-module (ice-9 vlist)
#:use-module (ice-9 format)
#:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-9)
#:use-module (srfi srfi-26)
#:use-module (srfi srfi-37)
#:use-module (srfi srfi-71)
@@ -181,9 +183,31 @@ specified with `--select'.\n"))
(newline)
(show-bug-report-information))
-(define (options->packages opts)
- "Return the list of packages requested by OPTS, honoring options like
-'--recursive'."
+
+;;;
+;;; Utilities.
+;;;
+
+(define-record-type <update-spec>
+ (%update-spec package version)
+ update?
+ (package update-spec-package)
+ (version update-spec-version))
+
+(define* (update-spec package #:optional version)
+ (%update-spec package version))
+
+(define (update-specification->update-spec spec)
+ "Given SPEC, a package name like \"guile@2.0=2.0.8\", return a <update>
+record with two fields: the package to upgrade, and the target version."
+ (match (string-rindex spec #\=)
+ (#f (update-spec (specification->package spec) #f))
+ (idx (update-spec (specification->package (substring spec 0 idx))
+ (substring spec (1+ idx))))))
+
+(define (options->update-specs opts)
+ "Return the list of <update-spec> records requested by OPTS, honoring
+options like '--recursive'."
(define core-package?
(let* ((input->package (match-lambda
((name (? package? package) _ ...) package)
@@ -218,41 +242,43 @@ update would trigger a complete rebuild."
(_
(cons package lst)))))
- (define args-packages
- ;; Packages explicitly passed as command-line arguments.
- (match (filter-map (match-lambda
+ (define update-specs
+ ;; Update specs explicitly passed as command-line arguments.
+ (match (append-map (match-lambda
(('argument . spec)
;; Take either the specified version or the
;; latest one.
- (specification->package spec))
+ (list (update-specification->update-spec spec)))
(('expression . exp)
- (read/eval-package-expression exp))
- (_ #f))
+ (list (update-spec (read/eval-package-expression exp))))
+ (('manifest . manifest)
+ (map update-spec (packages-from-manifest manifest)))
+ (_
+ '()))
opts)
(() ;default to all packages
(let ((select? (match (assoc-ref opts 'select)
('core core-package?)
('non-core (negate core-package?))
(_ (const #t)))))
- (fold-packages (lambda (package result)
- (if (select? package)
- (keep-newest package result)
- result))
- '())))
+ (map update-spec
+ (fold-packages (lambda (package result)
+ (if (select? package)
+ (keep-newest package result)
+ result))
+ '()))))
(some ;user-specified packages
some)))
- (define packages
- (match (assoc-ref opts 'manifest)
- (#f args-packages)
- ((? string? file) (packages-from-manifest file))))
-
(if (assoc-ref opts 'recursive?)
- (mlet %store-monad ((edges (node-edges %bag-node-type
- (all-packages))))
- (return (node-transitive-edges packages edges)))
+ (mlet* %store-monad ((edges (node-edges %bag-node-type (all-packages)))
+ (packages -> (node-transitive-edges
+ (map update-spec-package update-specs)
+ edges)))
+ ;; FIXME: The 'version' field of each update spec is lost.
+ (return (map update-spec packages)))
(with-monad %store-monad
- (return packages))))
+ (return update-specs))))
;;;
@@ -298,7 +324,7 @@ update would trigger a complete rebuild."
(G_ "no updater for ~a~%")
(package-name package)))
-(define* (update-package store package updaters
+(define* (update-package store package version updaters
#:key (key-download 'interactive) warn?)
"Update the source file that defines PACKAGE with the new version.
KEY-DOWNLOAD specifies a download policy for missing OpenPGP keys; allowed
@@ -307,7 +333,7 @@ warn about packages that have no matching updater."
(if (lookup-updater package updaters)
(let ((version output source
(package-update store package updaters
- #:key-download key-download))
+ #:key-download key-download #:version version))
(loc (or (package-field-location package 'version)
(package-location package))))
(when version
@@ -361,10 +387,15 @@ downloaded and authenticated; not updating~%")
(when warn?
(warn-no-updater package))))
-(define* (check-for-package-update package updaters #:key warn?)
- "Check whether an update is available for PACKAGE and print a message. When
-WARN? is true and no updater exists for PACKAGE, print a warning."
- (match (package-latest-release package updaters)
+(define* (check-for-package-update update-spec updaters #:key warn?)
+ "Check whether UPDATE-SPEC is feasible, and print a message.
+When WARN? is true and no updater exists for PACKAGE, print a warning."
+ (define package
+ (update-spec-package update-spec))
+
+ (match (package-latest-release package updaters
+ #:version
+ (update-spec-version update-spec))
((? upstream-source? source)
(let ((loc (or (package-field-location package 'version)
(package-location package))))
@@ -382,23 +413,34 @@ WARN? is true and no updater exists for PACKAGE, print a warning."
(package-version package)
(package-name package))))
(else
- (when warn?
- (warning loc
- (G_ "~a is greater than \
+ (if (update-spec-version update-spec)
+ (info loc
+ (G_ "~a would be downgraded from ~a to ~a~%")
+ (package-name package)
+ (package-version package)
+ (upstream-source-version source))
+ (when warn?
+ (warning loc
+ (G_ "~a is greater than \
the latest known version of ~a (~a)~%")
- (package-version package)
- (package-name package)
- (upstream-source-version source)))))))
+ (package-version package)
+ (package-name package)
+ (upstream-source-version source))))))))
(#f
(when warn?
;; Distinguish between "no updater" and "failing updater."
(match (lookup-updater package updaters)
((? upstream-updater? updater)
- (warning (package-location package)
- (G_ "'~a' updater failed to determine available \
+ (if (update-spec-version update-spec)
+ (warning (G_ "'~a' updater failed to find version ~a of '~a'~%")
+ (upstream-updater-name updater)
+ (update-spec-version update-spec)
+ (package-name package))
+ (warning (package-location package)
+ (G_ "'~a' updater failed to determine available \
releases for ~a~%")
- (upstream-updater-name updater)
- (package-name package)))
+ (upstream-updater-name updater)
+ (package-name package))))
(#f
(warn-no-updater package)))))))
@@ -540,12 +582,12 @@ all are dependent packages: ~{~a~^ ~}~%")
(with-error-handling
(with-store store
(run-with-store store
- (mlet %store-monad ((packages (options->packages opts)))
+ (mlet %store-monad ((update-specs (options->update-specs opts)))
(cond
(list-dependent?
- (list-dependents packages))
+ (list-dependents (map update-spec-package update-specs)))
(list-transitive?
- (list-transitive packages))
+ (list-transitive (map update-spec-package update-specs)))
(update?
(parameterize ((%openpgp-key-server
(or (assoc-ref opts 'key-server)
@@ -558,13 +600,17 @@ all are dependent packages: ~{~a~^ ~}~%")
(string-append (config-directory)
"/upstream/trustedkeys.kbx"))))
(for-each
- (cut update-package store <> updaters
- #:key-download key-download
- #:warn? warn?)
- packages)
+ (lambda (update)
+ (update-package store
+ (update-spec-package update)
+ (update-spec-version update)
+ updaters
+ #:key-download key-download
+ #:warn? warn?))
+ update-specs)
(return #t)))
(else
(for-each (cut check-for-package-update <> updaters
#:warn? warn?)
- packages)
+ update-specs)
(return #t)))))))))
diff --git a/guix/scripts/repl.scm b/guix/scripts/repl.scm
index 50d18c7760..787c63d48e 100644
--- a/guix/scripts/repl.scm
+++ b/guix/scripts/repl.scm
@@ -52,12 +52,19 @@
(option '(#\t "type") #t #f
(lambda (opt name arg result)
(alist-cons 'type (string->symbol arg) result)))
+ (option '("list-types") #f #f
+ (lambda (opt name arg result)
+ (display (string-join '("guile" "machine") "\n" 'suffix))
+ (exit 0)))
(option '("listen") #t #f
(lambda (opt name arg result)
(alist-cons 'listen arg result)))
(option '(#\q) #f #f
(lambda (opt name arg result)
(alist-cons 'ignore-dot-guile? #t result)))
+ (option '(#\i "interactive") #f #f
+ (lambda (opt name arg result)
+ (alist-cons 'interactive? #t result)))
(option '(#\L "load-path") #t #f
(lambda (opt name arg result)
;; XXX: Imperatively modify the search paths.
@@ -71,6 +78,8 @@
In the Guix execution environment, run FILE as a Guile script with
command-line arguments ARGS. If no FILE is given, start a Guile REPL.\n"))
(display (G_ "
+ --list-types display REPL types and exit"))
+ (display (G_ "
-t, --type=TYPE start a REPL of the given TYPE"))
(display (G_ "
--listen=ENDPOINT listen to ENDPOINT instead of standard input"))
@@ -78,6 +87,9 @@ command-line arguments ARGS. If no FILE is given, start a Guile REPL.\n"))
-q inhibit loading of ~/.guile"))
(newline)
(display (G_ "
+ -i, --interactive launch REPL after evaluating FILE"))
+ (newline)
+ (display (G_ "
-L, --load-path=DIR prepend DIR to the package module search path"))
(newline)
(display (G_ "
@@ -190,7 +202,7 @@ call THUNK."
;; file in %LOAD-PATH. Thus, pass (getcwd) instead of ".".
(load-in-vicinity (getcwd) (car script)))))
- (when (null? script)
+ (when (or (null? script) (assoc-ref opts 'interactive?))
;; Start REPL
(let ((type (assoc-ref opts 'type)))
(call-with-connection (assoc-ref opts 'listen)
diff --git a/guix/scripts/shell.scm b/guix/scripts/shell.scm
index c115a00320..64b5c2e8e9 100644
--- a/guix/scripts/shell.scm
+++ b/guix/scripts/shell.scm
@@ -20,7 +20,8 @@
#:use-module (guix ui)
#:use-module ((guix diagnostics) #:select (location))
#:use-module (guix scripts environment)
- #:autoload (guix scripts build) (show-build-options-help)
+ #:autoload (guix scripts build) (show-build-options-help
+ show-native-build-options-help)
#:autoload (guix transformations) (options->transformation
transformation-option-key?
show-transformation-options-help)
@@ -68,11 +69,16 @@ interactive shell in that environment.\n"))
--rebuild-cache rebuild cached environment, if any"))
(display (G_ "
--export-manifest print a manifest for the given options"))
+ (display (G_ "
+ -F, --emulate-fhs for containers, emulate the Filesystem Hierarchy
+ Standard (FHS)"))
(show-environment-options-help)
(newline)
(show-build-options-help)
(newline)
+ (show-native-build-options-help)
+ (newline)
(show-transformation-options-help)
(newline)
(display (G_ "
@@ -136,7 +142,11 @@ interactive shell in that environment.\n"))
(alist-cons 'explicit-loading? #t result)))
(option '("rebuild-cache") #f #f
(lambda (opt name arg result)
- (alist-cons 'rebuild-cache? #t result))))
+ (alist-cons 'rebuild-cache? #t result)))
+
+ (option '(#\F "emulate-fhs") #f #f
+ (lambda (opt name arg result)
+ (alist-cons 'emulate-fhs? #t result))))
(filter-map (lambda (opt)
(and (not (any (lambda (name)
(member name to-remove))
@@ -157,8 +167,18 @@ interactive shell in that environment.\n"))
;; The '--' token is used to separate the command to run from the rest of
;; the operands.
(let ((args command (break (cut string=? "--" <>) args)))
- (let ((opts (parse-command-line args %options (list %default-options)
- #:argument-handler handle-argument)))
+ (let* ((args-parsed (parse-command-line args %options (list %default-options)
+ #:argument-handler handle-argument))
+ ;; For an FHS-container, add the (hidden) package glibc-for-fhs
+ ;; which uses the global cache at /etc/ld.so.cache. We handle
+ ;; adding this package here to ensure it will always appear in the
+ ;; container as it is the first package in OPTS.
+ (opts (if (assoc-ref args-parsed 'emulate-fhs?)
+ (alist-cons 'expression
+ '(ad-hoc-package
+ "(@@ (gnu packages base) glibc-for-fhs)")
+ args-parsed)
+ args-parsed)))
(options-with-caching
(auto-detect-manifest
(match command
@@ -517,43 +537,44 @@ concatenates MANIFESTS, a list of expressions."
(category development)
(synopsis "spawn one-off software environments")
- (define (cache-entries directory)
- (filter-map (match-lambda
- ((or "." "..") #f)
- (file (string-append directory "/" file)))
- (or (scandir directory) '())))
-
- (define* (entry-expiration file)
- ;; Return the time at which FILE, a cached profile, is considered expired.
- (match (false-if-exception (lstat file))
- (#f 0) ;FILE may have been deleted in the meantime
- (st (+ (stat:atime st) (* 60 60 24 7)))))
-
- (define opts
- (parse-args args))
-
- (define interactive?
- (not (assoc-ref opts 'exec)))
-
- (if (assoc-ref opts 'check?)
- (record-hint 'shell-check)
- (when (and interactive?
- (not (hint-given? 'shell-check))
- (not (assoc-ref opts 'container?))
- (not (assoc-ref opts 'search-paths)))
- (display-hint (G_ "Consider passing the @option{--check} option once
+ (with-error-handling
+ (define (cache-entries directory)
+ (filter-map (match-lambda
+ ((or "." "..") #f)
+ (file (string-append directory "/" file)))
+ (or (scandir directory) '())))
+
+ (define* (entry-expiration file)
+ ;; Return the time at which FILE, a cached profile, is considered expired.
+ (match (false-if-exception (lstat file))
+ (#f 0) ;FILE may have been deleted in the meantime
+ (st (+ (stat:atime st) (* 60 60 24 7)))))
+
+ (define opts
+ (parse-args args))
+
+ (define interactive?
+ (not (assoc-ref opts 'exec)))
+
+ (if (assoc-ref opts 'check?)
+ (record-hint 'shell-check)
+ (when (and interactive?
+ (not (hint-given? 'shell-check))
+ (not (assoc-ref opts 'container?))
+ (not (assoc-ref opts 'search-paths)))
+ (display-hint (G_ "Consider passing the @option{--check} option once
to make sure your shell does not clobber environment variables."))) )
- ;; Clean the cache in EXIT-HOOK so that (1) it happens after potential use
- ;; of cached profiles, and (2) cleanup actually happens, even when
- ;; 'guix-environment*' calls 'exit'.
- (add-hook! exit-hook
- (lambda _
- (maybe-remove-expired-cache-entries
- (%profile-cache-directory)
- cache-entries
- #:entry-expiration entry-expiration)))
-
- (if (assoc-ref opts 'export-manifest?)
- (export-manifest opts (current-output-port))
- (guix-environment* opts)))
+ ;; Clean the cache in EXIT-HOOK so that (1) it happens after potential use
+ ;; of cached profiles, and (2) cleanup actually happens, even when
+ ;; 'guix-environment*' calls 'exit'.
+ (add-hook! exit-hook
+ (lambda _
+ (maybe-remove-expired-cache-entries
+ (%profile-cache-directory)
+ cache-entries
+ #:entry-expiration entry-expiration)))
+
+ (if (assoc-ref opts 'export-manifest?)
+ (export-manifest opts (current-output-port))
+ (guix-environment* opts))))
diff --git a/guix/scripts/size.scm b/guix/scripts/size.scm
index 5bb970443c..48b8ecc881 100644
--- a/guix/scripts/size.scm
+++ b/guix/scripts/size.scm
@@ -24,7 +24,6 @@
#:use-module (guix store)
#:use-module (guix monads)
#:use-module (guix combinators)
- #:use-module (guix grafts)
#:use-module (guix packages)
#:use-module (guix derivations)
#:use-module (gnu packages)
diff --git a/guix/scripts/style.scm b/guix/scripts/style.scm
index c0b9ea1a28..fa7175fb16 100644
--- a/guix/scripts/style.scm
+++ b/guix/scripts/style.scm
@@ -335,13 +335,15 @@ PACKAGE."
(define* (format-whole-file file #:rest rest)
"Reformat all of FILE."
- (let ((lst (call-with-input-file file read-with-comments/sequence)))
- (with-atomic-file-output file
- (lambda (port)
- (apply pretty-print-with-comments/splice port lst
- #:format-comment canonicalize-comment
- #:format-vertical-space canonicalize-vertical-space
- rest)))))
+ (with-fluids ((%default-port-encoding "UTF-8"))
+ (let ((lst (call-with-input-file file read-with-comments/sequence
+ #:guess-encoding #t)))
+ (with-atomic-file-output file
+ (lambda (port)
+ (apply pretty-print-with-comments/splice port lst
+ #:format-comment canonicalize-comment
+ #:format-vertical-space canonicalize-vertical-space
+ rest))))))
;;;
diff --git a/guix/scripts/substitute.scm b/guix/scripts/substitute.scm
index cdf591ac4d..fedb33019d 100755
--- a/guix/scripts/substitute.scm
+++ b/guix/scripts/substitute.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013-2022 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013-2023 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2014 Nikita Karetnikov <nikita@karetnikov.org>
;;; Copyright © 2018 Kyle Meyer <kyle@kyleam.com>
;;; Copyright © 2020 Christopher Baines <mail@cbaines.net>
@@ -366,7 +366,7 @@ authorized substitutes."
When FRESH? is true, delete any cached connections for URI and open a new one.
Return #f if URI's scheme is 'file' or #f.
-When true, TIMEOUT is the maximum number of milliseconds to wait for
+When true, TIMEOUT is the maximum number of seconds to wait for
connection establishment. When VERIFY-CERTIFICATE? is true, verify HTTPS
server certificates."
(define host (uri-host uri))
@@ -437,20 +437,13 @@ server certificates."
"Bind PORT with EXP... to a socket connected to URI."
(call-with-cached-connection uri (lambda (port) exp ...)))
-(define* (process-substitution port store-item destination
- #:key cache-urls acl
- deduplicate? print-build-trace?)
- "Substitute STORE-ITEM (a store file name) from CACHE-URLS, and write it to
-DESTINATION as a nar file. Verify the substitute against ACL, and verify its
-hash against what appears in the narinfo. When DEDUPLICATE? is true, and if
-DESTINATION is in the store, deduplicate its files. Print a status line to
-PORT."
- (define narinfo
- (lookup-narinfo cache-urls store-item
- (if (%allow-unauthenticated-substitutes?)
- (const #t)
- (cut valid-narinfo? <> acl))))
-
+(define* (download-nar narinfo destination
+ #:key status-port
+ deduplicate? print-build-trace?)
+ "Download the nar prescribed in NARINFO, which is assumed to be authentic
+and authorized, and write it to DESTINATION. When DEDUPLICATE? is true, and
+if DESTINATION is in the store, deduplicate its files. Print a status line to
+STATUS-PORT."
(define destination-in-store?
(string-prefix? (string-append (%store-prefix) "/")
destination))
@@ -467,33 +460,24 @@ PORT."
(let ((port (open-file (uri-path uri) "r0b")))
(values port (stat:size (stat port)))))
((http https)
- (guard (c ((http-get-error? c)
- (leave (G_ "download from '~a' failed: ~a, ~s~%")
- (uri->string (http-get-error-uri c))
- (http-get-error-code c)
- (http-get-error-reason c))))
- ;; Test this with:
- ;; sudo tc qdisc add dev eth0 root netem delay 1500ms
- ;; and then cancel with:
- ;; sudo tc qdisc del dev eth0 root
- (with-timeout %fetch-timeout
- (begin
- (warning (G_ "while fetching ~a: server is somewhat slow~%")
- (uri->string uri))
- (warning (G_ "try `--no-substitutes' if the problem persists~%")))
- (with-cached-connection uri port
- (http-fetch uri #:text? #f
- #:port port
- #:keep-alive? #t
- #:buffered? #f)))))
+ ;; Test this with:
+ ;; sudo tc qdisc add dev eth0 root netem delay 1500ms
+ ;; and then cancel with:
+ ;; sudo tc qdisc del dev eth0 root
+ (with-timeout %fetch-timeout
+ (begin
+ (warning (G_ "while fetching ~a: server is somewhat slow~%")
+ (uri->string uri))
+ (warning (G_ "try `--no-substitutes' if the problem persists~%")))
+ (with-cached-connection uri port
+ (http-fetch uri #:text? #f
+ #:port port
+ #:keep-alive? #t
+ #:buffered? #f))))
(else
(leave (G_ "unsupported substitute URI scheme: ~a~%")
(uri->string uri)))))
- (unless narinfo
- (leave (G_ "no valid substitute for '~a'~%")
- store-item))
-
(let ((uri compression file-size
(narinfo-best-uri narinfo
#:fast-decompression?
@@ -575,14 +559,109 @@ PORT."
(let ((actual (get-hash)))
(if (bytevector=? actual expected)
;; Tell the daemon that we're done.
- (format port "success ~a ~a~%"
+ (format status-port "success ~a ~a~%"
(narinfo-hash narinfo) (narinfo-size narinfo))
;; The actual data has a different hash than that in NARINFO.
- (format port "hash-mismatch ~a ~a ~a~%"
+ (format status-port "hash-mismatch ~a ~a ~a~%"
(hash-algorithm-name algorithm)
(bytevector->nix-base32-string expected)
(bytevector->nix-base32-string actual)))))))
+(define system-error?
+ (let ((kind-and-args? (exception-predicate &exception-with-kind-and-args)))
+ (lambda (exception)
+ "Return true if EXCEPTION is a Guile 'system-error exception."
+ (and (kind-and-args? exception)
+ (eq? 'system-error (exception-kind exception))))))
+
+(define network-error?
+ (let ((kind-and-args? (exception-predicate &exception-with-kind-and-args)))
+ (lambda (exception)
+ "Return true if EXCEPTION denotes a networking error."
+ (or (and (system-error? exception)
+ (let ((errno (system-error-errno
+ (cons 'system-error (exception-args exception)))))
+ (memv errno (list ECONNRESET ECONNABORTED
+ ECONNREFUSED EHOSTUNREACH
+ ENOENT)))) ;for "file://"
+ (and (kind-and-args? exception)
+ (memq (exception-kind exception)
+ '(gnutls-error getaddrinfo-error)))
+ (and (http-get-error? exception)
+ (begin
+ (warning (G_ "download from '~a' failed: ~a, ~s~%")
+ (uri->string (http-get-error-uri exception))
+ (http-get-error-code exception)
+ (http-get-error-reason exception))
+ #t))))))
+
+(define* (process-substitution/fallback port narinfo destination
+ #:key cache-urls acl
+ deduplicate? print-build-trace?)
+ "Attempt to substitute NARINFO, which is assumed to be authorized or
+equivalent, by trying to download its nar from each entry in CACHE-URLS.
+
+This can be less efficient than 'lookup-narinfo', which stops at the first
+entry that provides a valid narinfo, but it makes sure we eventually find a
+way to download the nar."
+ ;; Note: Keep NARINFO's uri-base in CACHE-URLS: that lets us retry in case
+ ;; this was a transient issue.
+ (let loop ((cache-urls cache-urls))
+ (match cache-urls
+ (()
+ (leave (G_ "failed to find alternative substitute for '~a'~%")
+ (narinfo-path narinfo)))
+ ((cache-url rest ...)
+ (match (lookup-narinfos cache-url
+ (list (narinfo-path narinfo))
+ #:open-connection
+ open-connection-for-uri/cached)
+ ((alternate)
+ (if (or (equivalent-narinfo? narinfo alternate)
+ (valid-narinfo? alternate acl)
+ (%allow-unauthenticated-substitutes?))
+ (guard (c ((network-error? c) (loop rest)))
+ (download-nar alternate destination
+ #:status-port port
+ #:deduplicate? deduplicate?
+ #:print-build-trace? print-build-trace?))
+ (loop rest)))
+ (()
+ (loop rest)))))))
+
+(define* (process-substitution port store-item destination
+ #:key cache-urls acl
+ deduplicate? print-build-trace?)
+ "Substitute STORE-ITEM (a store file name) from CACHE-URLS, and write it to
+DESTINATION as a nar file. Verify the substitute against ACL, and verify its
+hash against what appears in the narinfo. When DEDUPLICATE? is true, and if
+DESTINATION is in the store, deduplicate its files. Print a status line to
+PORT."
+ (define narinfo
+ (lookup-narinfo cache-urls store-item
+ (if (%allow-unauthenticated-substitutes?)
+ (const #t)
+ (cut valid-narinfo? <> acl))))
+
+ (unless narinfo
+ (leave (G_ "no valid substitute for '~a'~%")
+ store-item))
+
+ (guard (c ((network-error? c)
+ (format (current-error-port)
+ (G_ "retrying download of '~a' with other substitute URLs...~%")
+ store-item)
+ (process-substitution/fallback port narinfo destination
+ #:cache-urls cache-urls
+ #:acl acl
+ #:deduplicate? deduplicate?
+ #:print-build-trace?
+ print-build-trace?)))
+ (download-nar narinfo destination
+ #:status-port port
+ #:deduplicate? deduplicate?
+ #:print-build-trace? print-build-trace?)))
+
;;;
;;; Entry point.
@@ -627,10 +706,12 @@ substitutes may be unavailable\n")))))
(string-drop option=value (+ 1 equal-sign))))))
(string-tokenize newline-separated %not-newline)))))
-(define (find-daemon-option option)
- "Return the value of build daemon option OPTION, or #f if it could not be
+(define find-daemon-option
+ (let ((options (delay (daemon-options))))
+ (lambda (option)
+ "Return the value of build daemon option OPTION, or #f if it could not be
found."
- (assoc-ref (daemon-options) option))
+ (assoc-ref (force options) option))))
(define %default-substitute-urls
(match (and=> (or (find-daemon-option "untrusted-substitute-urls") ;client
diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm
index 4bcf789703..6fd915cb5e 100644
--- a/guix/scripts/system.scm
+++ b/guix/scripts/system.scm
@@ -38,7 +38,6 @@
(sqlite-register store-database-file call-with-database)
#:autoload (guix build store-copy) (copy-store-item)
#:use-module (guix describe)
- #:use-module (guix grafts)
#:use-module (guix gexp)
#:use-module (guix derivations)
#:use-module (guix diagnostics)
@@ -92,6 +91,7 @@
#:use-module (ice-9 match)
#:use-module (rnrs bytevectors)
#:export (guix-system
+ read-operating-system
service-node-type
shepherd-service-node-type))
@@ -107,6 +107,11 @@
(gnu services)
(gnu system shadow))))
+;; Note: The procedure below is used in external projects such as Emacs-Guix.
+(define (read-operating-system file)
+ "Read the operating-system declaration from FILE and return it."
+ (load* file %user-module))
+
;;;
;;; Installation.
@@ -837,7 +842,10 @@ static checks."
(check-mapped-devices os)
(when (zero? (getuid))
(check-file-system-availability (operating-system-file-systems os))
- (check-initrd-modules os)))
+ (unless (%current-target-system)
+ ;; Skip the check if the user is making use of --target, as it cannot
+ ;; be checked against the running kernel.
+ (check-initrd-modules os))))
(mlet* %store-monad
((sys (system-derivation-for-action image action
@@ -1040,7 +1048,7 @@ Some ACTIONS support additional ARGS.\n"))
(newline)
(display (G_ "
--graph-backend=BACKEND
- use BACKEND for 'extension-graphs' and 'shepherd-graph'"))
+ use BACKEND for 'extension-graph' and 'shepherd-graph'"))
(newline)
(display (G_ "
-I, --list-installed[=REGEXP]
diff --git a/guix/scripts/system/reconfigure.scm b/guix/scripts/system/reconfigure.scm
index f12bc2db88..9948df0ca6 100644
--- a/guix/scripts/system/reconfigure.scm
+++ b/guix/scripts/system/reconfigure.scm
@@ -41,9 +41,9 @@
#:use-module (guix diagnostics)
#:use-module (ice-9 match)
#:use-module (srfi srfi-1)
- #:use-module (srfi srfi-11)
#:use-module (srfi srfi-34)
#:use-module (srfi srfi-35)
+ #:use-module (srfi srfi-71)
#:use-module ((guix config) #:select (%guix-package-name))
#:export (switch-system-program
switch-to-system
@@ -186,8 +186,8 @@ services as defined by OS."
#:target-type shepherd-root-service-type))))
(mlet* %store-monad ((live-services (running-services eval)))
- (let*-values (((to-unload to-restart)
- (shepherd-service-upgrade live-services target-services)))
+ (let ((to-unload to-restart
+ (shepherd-service-upgrade live-services target-services)))
(let* ((to-unload (map live-service-canonical-name to-unload))
(to-restart (map shepherd-service-canonical-name to-restart))
(running (map live-service-canonical-name
@@ -349,14 +349,12 @@ to commits of channels in NEW."
(channel-name old)))
new)))
(and new
- (let-values (((checkout commit relation)
- (update-cached-checkout
- (channel-url new)
- #:ref
- `(commit . ,(channel-commit new))
- #:starting-commit
- (channel-commit old)
- #:check-out? #f)))
+ (let ((checkout commit relation
+ (update-cached-checkout
+ (channel-url new)
+ #:ref `(commit . ,(channel-commit new))
+ #:starting-commit (channel-commit old)
+ #:check-out? #f)))
(list new
(channel-commit old) (channel-commit new)
relation)))))
diff --git a/guix/scripts/system/search.scm b/guix/scripts/system/search.scm
index 44f00194cd..d978884518 100644
--- a/guix/scripts/system/search.scm
+++ b/guix/scripts/system/search.scm
@@ -127,7 +127,7 @@ procedure that may return a colorized version of its argument."
(parameterize ((%text-width width*))
(texi->plain-text
(string-append "description: "
- (or (and=> (service-type-description type) P_)
+ (or (and=> (service-type-description type) G_)
""))))
#\newline)))))
@@ -144,7 +144,7 @@ procedure that may return a colorized version of its argument."
(define (service-type-description-string type)
"Return the rendered and localised description of TYPE, a service type."
(and=> (service-type-description type)
- (compose texi->plain-text P_)))
+ (compose texi->plain-text G_)))
(define %service-type-metrics
;; Metrics used to estimate the relevance of a search result.
diff --git a/guix/scripts/weather.scm b/guix/scripts/weather.scm
index f46c11b1a5..dc27f81984 100644
--- a/guix/scripts/weather.scm
+++ b/guix/scripts/weather.scm
@@ -29,7 +29,6 @@
#:use-module (guix progress)
#:use-module (guix monads)
#:use-module (guix store)
- #:use-module (guix grafts)
#:use-module (guix gexp)
#:use-module (guix colors)
#:use-module ((guix build syscalls) #:select (terminal-columns))