diff options
Diffstat (limited to 'guix/scripts')
35 files changed, 1298 insertions, 1065 deletions
diff --git a/guix/scripts/archive.scm b/guix/scripts/archive.scm index 8137455a9d..5ea19784dc 100644 --- a/guix/scripts/archive.scm +++ b/guix/scripts/archive.scm @@ -58,41 +58,41 @@ (verbosity . 0))) (define (show-help) - (display (_ "Usage: guix archive [OPTION]... PACKAGE... + (display (G_ "Usage: guix archive [OPTION]... PACKAGE... Export/import one or more packages from/to the store.\n")) - (display (_ " + (display (G_ " --export export the specified files/packages to stdout")) - (display (_ " + (display (G_ " -r, --recursive combined with '--export', include dependencies")) - (display (_ " + (display (G_ " --import import from the archive passed on stdin")) - (display (_ " + (display (G_ " --missing print the files from stdin that are missing")) - (display (_ " + (display (G_ " -x, --extract=DIR extract the archive on stdin to DIR")) (newline) - (display (_ " + (display (G_ " --generate-key[=PARAMETERS] generate a key pair with the given parameters")) - (display (_ " + (display (G_ " --authorize authorize imports signed by the public key on stdin")) (newline) - (display (_ " + (display (G_ " -e, --expression=EXPR build the package or derivation EXPR evaluates to")) - (display (_ " + (display (G_ " -S, --source build the packages' source derivations")) - (display (_ " + (display (G_ " -s, --system=SYSTEM attempt to build for SYSTEM--e.g., \"i686-linux\"")) - (display (_ " + (display (G_ " --target=TRIPLET cross-build for TRIPLET--e.g., \"armel-linux-gnu\"")) (newline) (show-build-options-help) (newline) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -140,7 +140,7 @@ Export/import one or more packages from/to the store.\n")) (or arg %key-generation-parameters)))) (alist-cons 'generate-key params result))) (lambda (key proc err) - (leave (_ "invalid key generation parameters: ~a: ~a~%") + (leave (G_ "invalid key generation parameters: ~a: ~a~%") (error-source err) (error-string err)))))) (option '("authorize") #f #f @@ -179,7 +179,7 @@ derivation of a package." (let ((source (package-source p))) (if source (package-source-derivation store source) - (leave (_ "package `~a' has no source~%") + (leave (G_ "package `~a' has no source~%") (package-name p)))) (package-derivation store p system))) ((? procedure? proc) @@ -248,25 +248,25 @@ resulting archive to the standard output port." (build-derivations store drv)) (export-paths store files (current-output-port) #:recursive? (assoc-ref opts 'export-recursive?)) - (leave (_ "unable to export the given packages~%"))))) + (leave (G_ "unable to export the given packages~%"))))) (define (generate-key-pair parameters) "Generate a key pair with PARAMETERS, a canonical sexp, and store it in the right place." (when (or (file-exists? %public-key-file) (file-exists? %private-key-file)) - (leave (_ "key pair exists under '~a'; remove it first~%") + (leave (G_ "key pair exists under '~a'; remove it first~%") (dirname %public-key-file))) (format (current-error-port) - (_ "Please wait while gathering entropy to generate the key pair; + (G_ "Please wait while gathering entropy to generate the key pair; this may take time...~%")) (let* ((pair (catch 'gcry-error (lambda () (generate-key parameters)) (lambda (key proc err) - (leave (_ "key generation failed: ~a: ~a~%") + (leave (G_ "key generation failed: ~a: ~a~%") (error-source err) (error-string err))))) (public (find-sexp-token pair 'public-key)) @@ -293,13 +293,13 @@ the input port." (lambda () (string->canonical-sexp (read-string (current-input-port)))) (lambda (key proc err) - (leave (_ "failed to read public key: ~a: ~a~%") + (leave (G_ "failed to read public key: ~a: ~a~%") (error-source err) (error-string err))))) (let ((key (read-key)) (acl (current-acl))) (unless (eq? 'public-key (canonical-sexp-nth-data key 0)) - (leave (_ "s-expression does not denote a public key~%"))) + (leave (G_ "s-expression does not denote a public key~%"))) ;; Add KEY to the ACL and write that. (let ((acl (public-keys->acl (cons key (acl->public-keys acl))))) @@ -345,5 +345,5 @@ the input port." (restore-file (current-input-port) target))) (else (leave - (_ "either '--export' or '--import' \ + (G_ "either '--export' or '--import' \ must be specified~%")))))))))))) diff --git a/guix/scripts/authenticate.scm b/guix/scripts/authenticate.scm index d9a312f1da..8b19dc871b 100644 --- a/guix/scripts/authenticate.scm +++ b/guix/scripts/authenticate.scm @@ -56,7 +56,7 @@ both the hash and the actual signature." ".pub") read-canonical-sexp) (leave - (_ "cannot find public key for secret key '~a'~%") + (G_ "cannot find public key for secret key '~a'~%") key-file))) (data (read-hash-data port (key-type public-key))) (signature (signature-sexp data secret-key public-key))) @@ -76,11 +76,11 @@ to stdout upon success." (let ((hash (hash-data->bytevector data))) (display (bytevector->base16-string hash)) #t) ; success - (leave (_ "error: invalid signature: ~a~%") + (leave (G_ "error: invalid signature: ~a~%") (canonical-sexp->string signature))) - (leave (_ "error: unauthorized public key: ~a~%") + (leave (G_ "error: unauthorized public key: ~a~%") (canonical-sexp->string subject))) - (leave (_ "error: corrupt signature data: ~a~%") + (leave (G_ "error: corrupt signature data: ~a~%") (canonical-sexp->string signature))))) @@ -118,12 +118,12 @@ to stdout upon success." (("rsautl" "-verify" "-inkey" _ "-pubin") (validate-signature (current-input-port))) (("--help") - (display (_ "Usage: guix authenticate OPTION... + (display (G_ "Usage: guix authenticate OPTION... Sign or verify the signature on the given file. This tool is meant to be used internally by 'guix-daemon'.\n"))) (("--version") (show-version-and-exit "guix authenticate")) (else - (leave (_ "wrong arguments")))))) + (leave (G_ "wrong arguments")))))) ;;; authenticate.scm ends here diff --git a/guix/scripts/build.scm b/guix/scripts/build.scm index 68402fda18..558e8e7719 100644 --- a/guix/scripts/build.scm +++ b/guix/scripts/build.scm @@ -51,7 +51,9 @@ options->transformation show-transformation-options-help - guix-build)) + guix-build + register-root + register-root*)) (define %default-log-urls ;; Default base URLs for build logs. @@ -119,9 +121,12 @@ found. Return #f if no build log was found." 0 paths)))) (lambda args - (leave (_ "failed to create GC root `~a': ~a~%") + (leave (G_ "failed to create GC root `~a': ~a~%") root (strerror (system-error-errno args))))))) +(define register-root* + (store-lift register-root)) + (define (package-with-source store p uri) "Return a package based on P but with its source taken from URI. Extract the new package's version number from URI." @@ -198,7 +203,7 @@ could not be found." (proc (specification->package old) (specification->package new))) (x - (leave (_ "invalid replacement specification: ~s~%") spec)))) + (leave (G_ "invalid replacement specification: ~s~%") spec)))) specs)) (define (transform-package-inputs replacement-specs) @@ -255,13 +260,13 @@ current 'gnutls' package, after which version 3.5.4 is grafted onto them." (parser 'with-graft))))) (define (show-transformation-options-help) - (display (_ " + (display (G_ " --with-source=SOURCE use SOURCE when building the corresponding package")) - (display (_ " + (display (G_ " --with-input=PACKAGE=REPLACEMENT replace dependency PACKAGE by REPLACEMENT")) - (display (_ " + (display (G_ " --with-graft=PACKAGE=REPLACEMENT graft REPLACEMENT on packages that refer to PACKAGE"))) @@ -286,7 +291,7 @@ derivation, etc.), applies the transformations specified by OPTS." (((name . transform) obj) (let ((new (transform store obj))) (when (eq? new obj) - (warning (_ "transformation '~a' had no effect on ~a~%") + (warning (G_ "transformation '~a' had no effect on ~a~%") name (if (package? obj) (package-full-name obj) @@ -304,37 +309,37 @@ derivation, etc.), applies the transformations specified by OPTS." "Display on the current output port help about the standard command-line options handled by 'set-build-options-from-command-line', and listed in '%standard-build-options'." - (display (_ " + (display (G_ " -L, --load-path=DIR prepend DIR to the package module search path")) - (display (_ " + (display (G_ " -K, --keep-failed keep build tree of failed builds")) - (display (_ " + (display (G_ " -k, --keep-going keep going when some of the derivations fail")) - (display (_ " + (display (G_ " -n, --dry-run do not build the derivations")) - (display (_ " + (display (G_ " --fallback fall back to building when the substituter fails")) - (display (_ " + (display (G_ " --no-substitutes build instead of resorting to pre-built substitutes")) - (display (_ " + (display (G_ " --substitute-urls=URLS fetch substitute from URLS if they are authorized")) - (display (_ " + (display (G_ " --no-grafts do not graft packages")) - (display (_ " + (display (G_ " --no-build-hook do not attempt to offload builds via the build hook")) - (display (_ " + (display (G_ " --max-silent-time=SECONDS mark the build as failed after SECONDS of silence")) - (display (_ " + (display (G_ " --timeout=SECONDS mark the build as failed after SECONDS of activity")) - (display (_ " + (display (G_ " --verbosity=LEVEL use the given verbosity LEVEL")) - (display (_ " + (display (G_ " --rounds=N build N times in a row to detect non-determinism")) - (display (_ " + (display (G_ " -c, --cores=N allow the use of up to N CPU cores for the build")) - (display (_ " + (display (G_ " -M, --max-jobs=N allow at most N build jobs"))) (define (set-build-options-from-command-line store opts) @@ -440,14 +445,14 @@ options handled by 'set-build-options-from-command-line', and listed in (let ((c (false-if-exception (string->number arg)))) (if c (apply values (alist-cons 'cores c result) rest) - (leave (_ "not a number: '~a' option argument: ~a~%") + (leave (G_ "not a number: '~a' option argument: ~a~%") name arg))))) (option '(#\M "max-jobs") #t #f (lambda (opt name arg result . rest) (let ((c (false-if-exception (string->number arg)))) (if c (apply values (alist-cons 'max-jobs c result) rest) - (leave (_ "not a number: '~a' option argument: ~a~%") + (leave (G_ "not a number: '~a' option argument: ~a~%") name arg))))))) @@ -466,43 +471,43 @@ options handled by 'set-build-options-from-command-line', and listed in (verbosity . 0))) (define (show-help) - (display (_ "Usage: guix build [OPTION]... PACKAGE-OR-DERIVATION... + (display (G_ "Usage: guix build [OPTION]... PACKAGE-OR-DERIVATION... Build the given PACKAGE-OR-DERIVATION and return their output paths.\n")) - (display (_ " + (display (G_ " -e, --expression=EXPR build the package or derivation EXPR evaluates to")) - (display (_ " + (display (G_ " -f, --file=FILE build the package or derivation that the code within FILE evaluates to")) - (display (_ " + (display (G_ " -S, --source build the packages' source derivations")) - (display (_ " + (display (G_ " --sources[=TYPE] build source derivations; TYPE may optionally be one of \"package\", \"all\" (default), or \"transitive\"")) - (display (_ " + (display (G_ " -s, --system=SYSTEM attempt to build for SYSTEM--e.g., \"i686-linux\"")) - (display (_ " + (display (G_ " --target=TRIPLET cross-build for TRIPLET--e.g., \"armel-linux-gnu\"")) - (display (_ " + (display (G_ " -d, --derivations return the derivation paths of the given packages")) - (display (_ " + (display (G_ " --check rebuild items to check for non-determinism issues")) - (display (_ " + (display (G_ " --repair repair the specified items")) - (display (_ " + (display (G_ " -r, --root=FILE make FILE a symlink to the result, and register it as a garbage collector root")) - (display (_ " + (display (G_ " -q, --quiet do not show the build log")) - (display (_ " + (display (G_ " --log-file return the log file names for the given derivations")) (newline) (show-build-options-help) (newline) (show-transformation-options-help) (newline) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -529,7 +534,7 @@ Build the given PACKAGE-OR-DERIVATION and return their output paths.\n")) ("transitive" (alist-cons 'source package-transitive-sources result)) (else - (leave (_ "invalid argument: '~a' option argument: ~a, ~ + (leave (G_ "invalid argument: '~a' option argument: ~a, ~ must be one of 'package', 'all', or 'transitive'~%") name arg))))) (option '("check") #f #f @@ -582,7 +587,7 @@ must be one of 'package', 'all', or 'transitive'~%") build---packages, gexps, derivations, and so on." (define (validate-type x) (unless (or (package? x) (derivation? x) (gexp? x) (procedure? x)) - (leave (_ "~s: not something we can build~%") x))) + (leave (G_ "~s: not something we can build~%") x))) (define (ensure-list x) (let ((lst (match x @@ -636,7 +641,7 @@ build." (match (package-source p) (#f (format (current-error-port) - (_ "~a: warning: \ + (G_ "~a: warning: \ package '~a' has no source~%") (location->string (package-location p)) (package-name p)) @@ -670,7 +675,7 @@ needed." (log-url store file #:base-urls urls)))) (if log (format #t "~a~%" log) - (leave (_ "no build log for '~a'~%") file)))) + (leave (G_ "no build log for '~a'~%") file)))) ;;; diff --git a/guix/scripts/challenge.scm b/guix/scripts/challenge.scm index 815bb789c3..681394f9cf 100644 --- a/guix/scripts/challenge.scm +++ b/guix/scripts/challenge.scm @@ -188,10 +188,10 @@ object. When VERBOSE?, display matches in addition to mismatches and inconclusive reports." (define (report-hashes item local narinfos) (if local - (report (_ " local hash: ~a~%") (hash->string local)) - (report (_ " no local build for '~a'~%") item)) + (report (G_ " local hash: ~a~%") (hash->string local)) + (report (G_ " no local build for '~a'~%") item)) (for-each (lambda (narinfo) - (report (_ " ~50a: ~a~%") + (report (G_ " ~50a: ~a~%") (uri->string (narinfo-uri narinfo)) (hash->string (narinfo-hash->sha256 (narinfo-hash narinfo))))) @@ -199,15 +199,15 @@ inconclusive reports." (match comparison-report (($ <comparison-report> item 'mismatch local (narinfos ...)) - (report (_ "~a contents differ:~%") item) + (report (G_ "~a contents differ:~%") item) (report-hashes item local narinfos)) (($ <comparison-report> item 'inconclusive #f narinfos) - (warning (_ "could not challenge '~a': no local build~%") item)) + (warning (G_ "could not challenge '~a': no local build~%") item)) (($ <comparison-report> item 'inconclusive locals ()) - (warning (_ "could not challenge '~a': no substitutes~%") item)) + (warning (G_ "could not challenge '~a': no substitutes~%") item)) (($ <comparison-report> item 'match local (narinfos ...)) (when verbose? - (report (_ "~a contents match:~%") item) + (report (G_ "~a contents match:~%") item) (report-hashes item local narinfos))))) @@ -216,17 +216,17 @@ inconclusive reports." ;;; (define (show-help) - (display (_ "Usage: guix challenge [PACKAGE...] + (display (G_ "Usage: guix challenge [PACKAGE...] Challenge the substitutes for PACKAGE... provided by one or more servers.\n")) - (display (_ " + (display (G_ " --substitute-urls=URLS compare build results with those at URLS")) - (display (_ " + (display (G_ " -v, --verbose show details about successful comparisons")) (newline) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) diff --git a/guix/scripts/container.scm b/guix/scripts/container.scm index cd9f345b68..10aed2be75 100644 --- a/guix/scripts/container.scm +++ b/guix/scripts/container.scm @@ -22,17 +22,17 @@ #:export (guix-container)) (define (show-help) - (display (_ "Usage: guix container ACTION ARGS... + (display (G_ "Usage: guix container ACTION ARGS... Build and manipulate Linux containers.\n")) (newline) - (display (_ "The valid values for ACTION are:\n")) + (display (G_ "The valid values for ACTION are:\n")) (newline) - (display (_ "\ + (display (G_ "\ exec execute a command inside of an existing container\n")) (newline) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -50,7 +50,7 @@ Build and manipulate Linux containers.\n")) (match args (() (format (current-error-port) - (_ "guix container: missing action~%"))) + (G_ "guix container: missing action~%"))) ((or ("-h") ("--help")) (show-help) (exit 0)) @@ -60,4 +60,4 @@ Build and manipulate Linux containers.\n")) (if (member action %actions) (apply (resolve-action action) args) (format (current-error-port) - (_ "guix container: invalid action~%"))))))) + (G_ "guix container: invalid action~%"))))))) diff --git a/guix/scripts/container/exec.scm b/guix/scripts/container/exec.scm index d6d267daff..d598f5cac4 100644 --- a/guix/scripts/container/exec.scm +++ b/guix/scripts/container/exec.scm @@ -37,12 +37,12 @@ (show-version-and-exit "guix container exec"))))) (define (show-help) - (display (_ "Usage: guix container exec PID COMMAND [ARGS...] + (display (G_ "Usage: guix container exec PID COMMAND [ARGS...] Execute COMMMAND within the container process PID.\n")) (newline) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -66,7 +66,7 @@ and the other containing arguments for the command to be executed." (define (guix-container-exec . args) (define (handle-argument arg result) (if (assoc-ref result 'pid) - (leave (_ "~a: extraneous argument~%") arg) + (leave (G_ "~a: extraneous argument~%") arg) (alist-cons 'pid (string->number* arg) result))) (with-error-handling @@ -84,13 +84,13 @@ and the other containing arguments for the command to be executed." '("TERM")))) (unless pid - (leave (_ "no pid specified~%"))) + (leave (G_ "no pid specified~%"))) (when (null? command) - (leave (_ "no command specified~%"))) + (leave (G_ "no command specified~%"))) (unless (file-exists? (string-append "/proc/" (number->string pid))) - (leave (_ "no such process ~d~%") pid)) + (leave (G_ "no such process ~d~%") pid)) (let ((result (container-excursion pid (lambda () @@ -102,4 +102,4 @@ and the other containing arguments for the command to be executed." environment) (apply execlp program program program-args))))))) (unless (zero? result) - (leave (_ "exec failed with status ~d~%") result))))))) + (leave (G_ "exec failed with status ~d~%") result))))))) diff --git a/guix/scripts/copy.scm b/guix/scripts/copy.scm index 624ef73e96..45f7cbbad5 100644 --- a/guix/scripts/copy.scm +++ b/guix/scripts/copy.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2016 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2016, 2017 Ludovic Courtès <ludo@gnu.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -25,9 +25,6 @@ #:use-module (guix derivations) #:use-module (guix scripts build) #:use-module ((guix scripts archive) #:select (options->derivations+files)) - #:use-module (ssh session) - #:use-module (ssh auth) - #:use-module (ssh key) #:use-module (srfi srfi-1) #:use-module (srfi srfi-11) #:use-module (srfi srfi-37) @@ -40,42 +37,6 @@ ;;; Exchanging store items over SSH. ;;; -(define %compression - "zlib@openssh.com,zlib") - -(define* (open-ssh-session host #:key user port) - "Open an SSH session for HOST and return it. When USER and PORT are #f, use -default values or whatever '~/.ssh/config' specifies; otherwise use them. -Throw an error on failure." - (let ((session (make-session #:user user - #:host host - #:port port - #:timeout 10 ;seconds - ;; #:log-verbosity 'protocol - - ;; We need lightweight compression when - ;; exchanging full archives. - #:compression %compression - #:compression-level 3))) - - ;; Honor ~/.ssh/config. - (session-parse-config! session) - - (match (connect! session) - ('ok - ;; Use public key authentication, via the SSH agent if it's available. - (match (userauth-public-key/auto! session) - ('success - session) - (x - (disconnect! session) - (leave (_ "SSH authentication failed for '~a': ~a~%") - host (get-error session))))) - (x - ;; Connection failed or timeout expired. - (leave (_ "SSH connection to '~a' failed: ~a~%") - host (get-error session)))))) - (define (ssh-spec->user+host+port spec) "Parse SPEC, a string like \"user@host:port\" or just \"host\", and return three values: the user name (or #f), the host name, and the TCP port @@ -95,9 +56,9 @@ number (or #f) corresponding to SPEC." ((? integer? port) (values user host port)) (x - (leave (_ "~a: invalid TCP port number~%") port)))) + (leave (G_ "~a: invalid TCP port number~%") port)))) (x - (leave (_ "~a: invalid SSH specification~%") spec)))) + (leave (G_ "~a: invalid SSH specification~%") spec)))) (define (send-to-remote-host target opts) "Send ITEMS to TARGET. ITEMS is a list of store items or package names; for ; @@ -148,18 +109,18 @@ package names, build the underlying packages before sending them." ;;; (define (show-help) - (display (_ "Usage: guix copy [OPTION]... ITEMS... + (display (G_ "Usage: guix copy [OPTION]... ITEMS... Copy ITEMS to or from the specified host over SSH.\n")) - (display (_ " + (display (G_ " --to=HOST send ITEMS to HOST")) - (display (_ " + (display (G_ " --from=HOST receive ITEMS from HOST")) (newline) (show-build-options-help) (newline) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -204,4 +165,4 @@ Copy ITEMS to or from the specified host over SSH.\n")) (target (assoc-ref opts 'destination))) (cond (target (send-to-remote-host target opts)) (source (retrieve-from-remote-host source opts)) - (else (leave (_ "use '--to' or '--from'~%"))))))) + (else (leave (G_ "use '--to' or '--from'~%"))))))) diff --git a/guix/scripts/download.scm b/guix/scripts/download.scm index 1ddfd648cd..bb3dc76741 100644 --- a/guix/scripts/download.scm +++ b/guix/scripts/download.scm @@ -64,23 +64,23 @@ (download-proc . ,download-to-store*))) (define (show-help) - (display (_ "Usage: guix download [OPTION] URL + (display (G_ "Usage: guix download [OPTION] URL Download the file at URL to the store or to the given file, and print its file name and the hash of its contents. Supported formats: 'nix-base32' (default), 'base32', and 'base16' ('hex' and 'hexadecimal' can be used as well).\n")) - (format #t (_ " + (format #t (G_ " -f, --format=FMT write the hash in the given format")) - (format #t (_ " + (format #t (G_ " --no-check-certificate do not validate the certificate of HTTPS servers ")) - (format #f (_ " + (format #f (G_ " -o, --output=FILE download to FILE")) (newline) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -98,7 +98,7 @@ Supported formats: 'nix-base32' (default), 'base32', and 'base16' ((or "base16" "hex" "hexadecimal") bytevector->base16-string) (x - (leave (_ "unsupported hash format: ~a~%") arg)))) + (leave (G_ "unsupported hash format: ~a~%") arg)))) (alist-cons 'format fmt-proc (alist-delete 'format result)))) @@ -130,10 +130,10 @@ Supported formats: 'nix-base32' (default), 'base32', and 'base16' ;; Return the alist of option values. (args-fold* args %options (lambda (opt name arg result) - (leave (_ "~A: unrecognized option~%") name)) + (leave (G_ "~A: unrecognized option~%") name)) (lambda (arg result) (when (assq 'argument result) - (leave (_ "~A: extraneous argument~%") arg)) + (leave (G_ "~A: extraneous argument~%") arg)) (alist-cons 'argument arg result)) %default-options)) @@ -141,9 +141,9 @@ Supported formats: 'nix-base32' (default), 'base32', and 'base16' (with-error-handling (let* ((opts (parse-options)) (arg (or (assq-ref opts 'argument) - (leave (_ "no download URI was specified~%")))) + (leave (G_ "no download URI was specified~%")))) (uri (or (string->uri arg) - (leave (_ "~a: failed to parse URI~%") + (leave (G_ "~a: failed to parse URI~%") arg))) (fetch (assq-ref opts 'download-proc)) (path (parameterize ((current-terminal-columns @@ -153,7 +153,7 @@ Supported formats: 'nix-base32' (default), 'base32', and 'base16' (assq-ref opts 'verify-certificate?)))) (hash (call-with-input-file (or path - (leave (_ "~a: download failed~%") + (leave (G_ "~a: download failed~%") arg)) port-sha256)) (fmt (assq-ref opts 'format))) diff --git a/guix/scripts/edit.scm b/guix/scripts/edit.scm index 555796a69c..8b2b61d76a 100644 --- a/guix/scripts/edit.scm +++ b/guix/scripts/edit.scm @@ -38,12 +38,12 @@ (show-version-and-exit "guix edit"))))) (define (show-help) - (display (_ "Usage: guix edit PACKAGE... + (display (G_ "Usage: guix edit PACKAGE... Start $VISUAL or $EDITOR to edit the definitions of PACKAGE...\n")) (newline) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -59,7 +59,7 @@ Start $VISUAL or $EDITOR to edit the definitions of PACKAGE...\n")) (let ((absolute-file-name (search-path path file))) (unless absolute-file-name ;; Shouldn't happen unless somebody fiddled with the 'location' field. - (leave (_ "file '~a' not found in search path ~s~%") + (leave (G_ "file '~a' not found in search path ~s~%") file path)) absolute-file-name)) @@ -78,7 +78,7 @@ line." ;; Return the list of package names. (args-fold* args %options (lambda (opt name arg result) - (leave (_ "~A: unrecognized option~%") name)) + (leave (G_ "~A: unrecognized option~%") name)) cons '())) @@ -87,7 +87,7 @@ line." (packages (map specification->package specs))) (for-each (lambda (package) (unless (package-location package) - (leave (_ "source location of package '~a' is unknown~%") + (leave (G_ "source location of package '~a' is unknown~%") (package-full-name package)))) packages) @@ -100,5 +100,5 @@ line." (exit (system (string-join (cons (%editor) file-names)))))) (lambda args (let ((errno (system-error-errno args))) - (leave (_ "failed to launch '~a': ~a~%") + (leave (G_ "failed to launch '~a': ~a~%") (%editor) (strerror errno)))))))) diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm index 44f490043c..af69e2b730 100644 --- a/guix/scripts/environment.scm +++ b/guix/scripts/environment.scm @@ -72,14 +72,16 @@ as 'HOME' and 'USER' are left untouched." (define (create-environment profile paths pure?) "Set the environment variables specified by PATHS for PROFILE. When PURE? is #t, unset the variables in the current environment. Otherwise, augment -existing enviroment variables with additional search paths." +existing environment variables with additional search paths." (when pure? (purify-environment)) (for-each (match-lambda ((($ <search-path-specification> variable _ separator) . value) (let ((current (getenv variable))) (setenv variable (if (and current (not pure?)) - (string-append value separator current) + (if separator + (string-append value separator current) + value) value))))) (evaluate-profile-search-paths profile paths)) @@ -130,45 +132,45 @@ and an output string." (package->bag package))))) (define (show-help) - (display (_ "Usage: guix environment [OPTION]... PACKAGE... [-- COMMAND...] + (display (G_ "Usage: guix environment [OPTION]... PACKAGE... [-- COMMAND...] Build an environment that includes the dependencies of PACKAGE and execute COMMAND or an interactive shell in that environment.\n")) - (display (_ " + (display (G_ " -e, --expression=EXPR create environment for the package that EXPR evaluates to")) - (display (_ " + (display (G_ " -l, --load=FILE create environment for the package that the code within FILE evaluates to")) - (display (_ " + (display (G_ " --ad-hoc include all specified packages in the environment instead of only their inputs")) - (display (_ " + (display (G_ " --pure unset existing environment variables")) - (display (_ " + (display (G_ " --search-paths display needed environment variable definitions")) - (display (_ " + (display (G_ " -s, --system=SYSTEM attempt to build for SYSTEM--e.g., \"i686-linux\"")) - (display (_ " + (display (G_ " -r, --root=FILE make FILE a symlink to the result, and register it as a garbage collector root")) - (display (_ " + (display (G_ " -C, --container run command within an isolated container")) - (display (_ " + (display (G_ " -N, --network allow containers to access the network")) - (display (_ " + (display (G_ " --share=SPEC for containers, share writable host file system according to SPEC")) - (display (_ " + (display (G_ " --expose=SPEC for containers, expose read-only host file system according to SPEC")) - (display (_ " + (display (G_ " --bootstrap use bootstrap binaries to build the environment")) (newline) (show-build-options-help) (newline) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -499,16 +501,16 @@ Otherwise, return the derivation for the Bash package." "Check if containers can be created and exit with an informative error message if any test fails." (unless (user-namespace-supported?) - (report-error (_ "cannot create container: user namespaces unavailable\n")) - (leave (_ "is your kernel version < 3.10?\n"))) + (report-error (G_ "cannot create container: user namespaces unavailable\n")) + (leave (G_ "is your kernel version < 3.10?\n"))) (unless (unprivileged-user-namespace-supported?) - (report-error (_ "cannot create container: unprivileged user cannot create user namespaces\n")) - (leave (_ "please set /proc/sys/kernel/unprivileged_userns_clone to \"1\"\n"))) + (report-error (G_ "cannot create container: unprivileged user cannot create user namespaces\n")) + (leave (G_ "please set /proc/sys/kernel/unprivileged_userns_clone to \"1\"\n"))) (unless (setgroups-supported?) - (report-error (_ "cannot create container: /proc/self/setgroups does not exist\n")) - (leave (_ "is your kernel version < 3.19?\n")))) + (report-error (G_ "cannot create container: /proc/self/setgroups does not exist\n")) + (leave (G_ "is your kernel version < 3.19?\n")))) (define (register-gc-root target root) "Make ROOT an indirect root to TARGET. This is procedure is idempotent." diff --git a/guix/scripts/gc.scm b/guix/scripts/gc.scm index bdfee4308c..221467a108 100644 --- a/guix/scripts/gc.scm +++ b/guix/scripts/gc.scm @@ -39,41 +39,41 @@ `((action . collect-garbage))) (define (show-help) - (display (_ "Usage: guix gc [OPTION]... PATHS... + (display (G_ "Usage: guix gc [OPTION]... PATHS... Invoke the garbage collector.\n")) - (display (_ " + (display (G_ " -C, --collect-garbage[=MIN] collect at least MIN bytes of garbage")) - (display (_ " + (display (G_ " -F, --free-space=FREE attempt to reach FREE available space in the store")) - (display (_ " + (display (G_ " -d, --delete attempt to delete PATHS")) - (display (_ " + (display (G_ " --optimize optimize the store by deduplicating identical files")) - (display (_ " + (display (G_ " --list-dead list dead paths")) - (display (_ " + (display (G_ " --list-live list live paths")) (newline) - (display (_ " + (display (G_ " --references list the references of PATHS")) - (display (_ " + (display (G_ " -R, --requisites list the requisites of PATHS")) - (display (_ " + (display (G_ " --referrers list the referrers of PATHS")) (newline) - (display (_ " + (display (G_ " --verify[=OPTS] verify the integrity of the store; OPTS is a comma-separated combination of 'repair' and 'contents'")) - (display (_ " + (display (G_ " --list-failures list cached build failures")) - (display (_ " + (display (G_ " --clear-failures remove PATHS from the set of cached failures")) (newline) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -97,7 +97,7 @@ Invoke the garbage collector.\n")) (let ((amount (size->number arg))) (if arg (alist-cons 'min-freed amount result) - (leave (_ "invalid amount of storage: ~a~%") + (leave (G_ "invalid amount of storage: ~a~%") arg)))) (#f result))))) (option '(#\F "free-space") #t #f @@ -161,7 +161,7 @@ Invoke the garbage collector.\n")) ;; Return the alist of option values. (args-fold* args %options (lambda (opt name arg result) - (leave (_ "~A: unrecognized option~%") name)) + (leave (G_ "~A: unrecognized option~%") name)) (lambda (arg result) (alist-cons 'argument arg result)) %default-options)) @@ -188,10 +188,10 @@ Invoke the garbage collector.\n")) (free (* (file-system-block-size fs) (file-system-blocks-available fs)))) (if (> free space) - (info (_ "already ~h bytes available on ~a, nothing to do~%") + (info (G_ "already ~h bytes available on ~a, nothing to do~%") free (%store-prefix)) (let ((to-free (- space free))) - (info (_ "freeing ~h bytes~%") to-free) + (info (G_ "freeing ~h bytes~%") to-free) (collect-garbage store to-free))))) (with-error-handling @@ -203,7 +203,7 @@ Invoke the garbage collector.\n")) opts))) (define (assert-no-extra-arguments) (unless (null? paths) - (leave (_ "extraneous arguments: ~{~a ~}~%") paths))) + (leave (G_ "extraneous arguments: ~{~a ~}~%") paths))) (define (list-relatives relatives) (for-each (compose (lambda (path) @@ -223,10 +223,10 @@ Invoke the garbage collector.\n")) (ensure-free-space store free-space)) (min-freed (let-values (((paths freed) (collect-garbage store min-freed))) - (info (_ "freed ~h bytes~%") freed))) + (info (G_ "freed ~h bytes~%") freed))) (else (let-values (((paths freed) (collect-garbage store))) - (info (_ "freed ~h bytes~%") freed)))))) + (info (G_ "freed ~h bytes~%") freed)))))) ((delete) (delete-paths store (map direct-store-path paths))) ((list-references) diff --git a/guix/scripts/graph.scm b/guix/scripts/graph.scm index 9804d41929..0af1fa3ad3 100644 --- a/guix/scripts/graph.scm +++ b/guix/scripts/graph.scm @@ -81,7 +81,7 @@ name." (raise (condition (&message - (message (format #f (_ "~a: invalid argument (package name expected)") + (message (format #f (G_ "~a: invalid argument (package name expected)") x)))))))) (define nodes-from-package @@ -305,7 +305,7 @@ substitutes." ((info) (values (substitutable-references info) store)) (() - (leave (_ "references for '~a' are not known~%") + (leave (G_ "references for '~a' are not known~%") item))))) (values (references store item) store)))) @@ -355,18 +355,18 @@ substitutes." (or (find (lambda (type) (string=? (node-type-name type) name)) %node-types) - (leave (_ "~a: unknown node type~%") name))) + (leave (G_ "~a: unknown node type~%") name))) (define (lookup-backend name) "Return the graph backend called NAME. Raise an error if it is not found." (or (find (lambda (backend) (string=? (graph-backend-name backend) name)) %graph-backends) - (leave (_ "~a: unknown backend~%") name))) + (leave (G_ "~a: unknown backend~%") name))) (define (list-node-types) "Print the available node types along with their synopsis." - (display (_ "The available node types are:\n")) + (display (G_ "The available node types are:\n")) (newline) (for-each (lambda (type) (format #t " - ~a: ~a~%" @@ -376,7 +376,7 @@ substitutes." (define (list-backends) "Print the available backends along with their synopsis." - (display (_ "The available backend types are:\n")) + (display (G_ "The available backend types are:\n")) (newline) (for-each (lambda (backend) (format #t " - ~a: ~a~%" @@ -420,22 +420,22 @@ substitutes." (define (show-help) ;; TRANSLATORS: Here 'dot' is the name of a program; it must not be ;; translated. - (display (_ "Usage: guix graph PACKAGE... + (display (G_ "Usage: guix graph PACKAGE... Emit a Graphviz (dot) representation of the dependencies of PACKAGE...\n")) - (display (_ " + (display (G_ " -b, --backend=TYPE produce a graph with the given backend TYPE")) - (display (_ " + (display (G_ " --list-backends list the available graph backends")) - (display (_ " + (display (G_ " -t, --type=TYPE represent nodes of the given TYPE")) - (display (_ " + (display (G_ " --list-types list the available graph types")) - (display (_ " + (display (G_ " -e, --expression=EXPR consider the package EXPR evaluates to")) (newline) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -453,7 +453,7 @@ Emit a Graphviz (dot) representation of the dependencies of PACKAGE...\n")) (with-error-handling (let* ((opts (args-fold* args %options (lambda (opt name arg . rest) - (leave (_ "~A: unrecognized option~%") name)) + (leave (G_ "~A: unrecognized option~%") name)) (lambda (arg result) (alist-cons 'argument arg result)) %default-options)) diff --git a/guix/scripts/hash.scm b/guix/scripts/hash.scm index a048b53461..1fa6bb8d1f 100644 --- a/guix/scripts/hash.scm +++ b/guix/scripts/hash.scm @@ -44,21 +44,21 @@ `((format . ,bytevector->nix-base32-string))) (define (show-help) - (display (_ "Usage: guix hash [OPTION] FILE + (display (G_ "Usage: guix hash [OPTION] FILE Return the cryptographic hash of FILE. Supported formats: 'nix-base32' (default), 'base32', and 'base16' ('hex' and 'hexadecimal' can be used as well).\n")) - (format #t (_ " + (format #t (G_ " -x, --exclude-vcs exclude version control directories")) - (format #t (_ " + (format #t (G_ " -f, --format=FMT write the hash in the given format")) - (format #t (_ " + (format #t (G_ " -r, --recursive compute the hash on FILE recursively")) (newline) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -79,7 +79,7 @@ and 'hexadecimal' can be used as well).\n")) ((or "base16" "hex" "hexadecimal") bytevector->base16-string) (x - (leave (_ "unsupported hash format: ~a~%") + (leave (G_ "unsupported hash format: ~a~%") arg)))) (alist-cons 'format fmt-proc @@ -106,7 +106,7 @@ and 'hexadecimal' can be used as well).\n")) ;; Return the alist of option values. (args-fold* args %options (lambda (opt name arg result) - (leave (_ "unrecognized option: ~a~%") + (leave (G_ "unrecognized option: ~a~%") name)) (lambda (arg result) (alist-cons 'argument arg result)) @@ -152,7 +152,7 @@ and 'hexadecimal' can be used as well).\n")) (lambda () (format #t "~a~%" (fmt (file-hash file)))) (lambda args - (leave (_ "~a~%") + (leave (G_ "~a~%") (strerror (system-error-errno args)))))) (x - (leave (_ "wrong number of arguments~%")))))) + (leave (G_ "wrong number of arguments~%")))))) diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm index 8c2f705738..203cda8049 100644 --- a/guix/scripts/import.scm +++ b/guix/scripts/import.scm @@ -83,15 +83,15 @@ rather than \\n." (module-ref module proc))) (define (show-help) - (display (_ "Usage: guix import IMPORTER ARGS ... + (display (G_ "Usage: guix import IMPORTER ARGS ... Run IMPORTER with ARGS.\n")) (newline) - (display (_ "IMPORTER must be one of the importers listed below:\n")) + (display (G_ "IMPORTER must be one of the importers listed below:\n")) (newline) (format #t "~{ ~a~%~}" importers) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -100,7 +100,7 @@ Run IMPORTER with ARGS.\n")) (match args (() (format (current-error-port) - (_ "guix import: missing importer name~%"))) + (G_ "guix import: missing importer name~%"))) ((or ("-h") ("--help")) (show-help) (exit 0)) @@ -120,5 +120,5 @@ Run IMPORTER with ARGS.\n")) (newline)) expressions)) (x - (leave (_ "'~a' import failed~%") importer)))) - (leave (_ "~a: invalid importer~%") importer))))) + (leave (G_ "'~a' import failed~%") importer)))) + (leave (G_ "~a: invalid importer~%") importer))))) diff --git a/guix/scripts/import/cpan.scm b/guix/scripts/import/cpan.scm index 3d470f684d..77ffe1f38e 100644 --- a/guix/scripts/import/cpan.scm +++ b/guix/scripts/import/cpan.scm @@ -38,11 +38,11 @@ '()) (define (show-help) - (display (_ "Usage: guix import cpan PACKAGE-NAME + (display (G_ "Usage: guix import cpan PACKAGE-NAME Import and convert the CPAN package for PACKAGE-NAME.\n")) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -68,7 +68,7 @@ Import and convert the CPAN package for PACKAGE-NAME.\n")) ;; Return the alist of option values. (args-fold* args %options (lambda (opt name arg result) - (leave (_ "~A: unrecognized option~%") name)) + (leave (G_ "~A: unrecognized option~%") name)) (lambda (arg result) (alist-cons 'argument arg result)) %default-options)) @@ -83,10 +83,10 @@ Import and convert the CPAN package for PACKAGE-NAME.\n")) ((package-name) (let ((sexp (cpan->guix-package package-name))) (unless sexp - (leave (_ "failed to download meta-data for package '~a'~%") + (leave (G_ "failed to download meta-data for package '~a'~%") package-name)) sexp)) (() - (leave (_ "too few arguments~%"))) + (leave (G_ "too few arguments~%"))) ((many ...) - (leave (_ "too many arguments~%")))))) + (leave (G_ "too many arguments~%")))))) diff --git a/guix/scripts/import/cran.scm b/guix/scripts/import/cran.scm index c9a9eab762..d65c644c05 100644 --- a/guix/scripts/import/cran.scm +++ b/guix/scripts/import/cran.scm @@ -40,13 +40,13 @@ '()) (define (show-help) - (display (_ "Usage: guix import cran PACKAGE-NAME + (display (G_ "Usage: guix import cran PACKAGE-NAME Import and convert the CRAN package for PACKAGE-NAME.\n")) - (display (_ " + (display (G_ " -a, --archive=ARCHIVE specify the archive repository")) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -79,7 +79,7 @@ Import and convert the CRAN package for PACKAGE-NAME.\n")) ;; Return the alist of option values. (args-fold* args %options (lambda (opt name arg result) - (leave (_ "~A: unrecognized option~%") name)) + (leave (G_ "~A: unrecognized option~%") name)) (lambda (arg result) (alist-cons 'argument arg result)) %default-options)) @@ -105,10 +105,10 @@ Import and convert the CRAN package for PACKAGE-NAME.\n")) (let ((sexp (cran->guix-package package-name (or (assoc-ref opts 'repo) 'cran)))) (unless sexp - (leave (_ "failed to download description for package '~a'~%") + (leave (G_ "failed to download description for package '~a'~%") package-name)) sexp))) (() - (leave (_ "too few arguments~%"))) + (leave (G_ "too few arguments~%"))) ((many ...) - (leave (_ "too many arguments~%")))))) + (leave (G_ "too many arguments~%")))))) diff --git a/guix/scripts/import/crate.scm b/guix/scripts/import/crate.scm index 4337a0b623..cab9a4397b 100644 --- a/guix/scripts/import/crate.scm +++ b/guix/scripts/import/crate.scm @@ -40,11 +40,11 @@ '()) (define (show-help) - (display (_ "Usage: guix import crate PACKAGE-NAME + (display (G_ "Usage: guix import crate PACKAGE-NAME Import and convert the crate.io package for PACKAGE-NAME.\n")) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -70,7 +70,7 @@ Import and convert the crate.io package for PACKAGE-NAME.\n")) ;; Return the alist of option values. (args-fold* args %options (lambda (opt name arg result) - (leave (_ "~A: unrecognized option~%") name)) + (leave (G_ "~A: unrecognized option~%") name)) (lambda (arg result) (alist-cons 'argument arg result)) %default-options)) @@ -85,10 +85,10 @@ Import and convert the crate.io package for PACKAGE-NAME.\n")) ((package-name) (let ((sexp (crate->guix-package package-name))) (unless sexp - (leave (_ "failed to download meta-data for package '~a'~%") + (leave (G_ "failed to download meta-data for package '~a'~%") package-name)) sexp)) (() - (leave (_ "too few arguments~%"))) + (leave (G_ "too few arguments~%"))) ((many ...) - (leave (_ "too many arguments~%")))))) + (leave (G_ "too many arguments~%")))))) diff --git a/guix/scripts/import/elpa.scm b/guix/scripts/import/elpa.scm index b22a7c4c23..34eb16485e 100644 --- a/guix/scripts/import/elpa.scm +++ b/guix/scripts/import/elpa.scm @@ -38,13 +38,13 @@ '((repo . gnu))) (define (show-help) - (display (_ "Usage: guix import elpa PACKAGE-NAME + (display (G_ "Usage: guix import elpa PACKAGE-NAME Import the latest package named PACKAGE-NAME from an ELPA repository.\n")) - (display (_ " + (display (G_ " -a, --archive=ARCHIVE specify the archive repository")) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -74,7 +74,7 @@ Import the latest package named PACKAGE-NAME from an ELPA repository.\n")) ;; Return the alist of option values. (args-fold* args %options (lambda (opt name arg result) - (leave (_ "~A: unrecognized option~%") name)) + (leave (G_ "~A: unrecognized option~%") name)) (lambda (arg result) (alist-cons 'argument arg result)) %default-options)) @@ -89,11 +89,11 @@ Import the latest package named PACKAGE-NAME from an ELPA repository.\n")) ((package-name) (let ((sexp (elpa->guix-package package-name (assoc-ref opts 'repo)))) (unless sexp - (leave (_ "failed to download package '~a'~%") package-name)) + (leave (G_ "failed to download package '~a'~%") package-name)) sexp)) (() - (leave (_ "too few arguments~%"))) + (leave (G_ "too few arguments~%"))) ((many ...) - (leave (_ "too many arguments~%")))))) + (leave (G_ "too many arguments~%")))))) ;;; elpa.scm ends here diff --git a/guix/scripts/import/gem.scm b/guix/scripts/import/gem.scm index a5dd2a7822..349a0a072a 100644 --- a/guix/scripts/import/gem.scm +++ b/guix/scripts/import/gem.scm @@ -38,11 +38,11 @@ '()) (define (show-help) - (display (_ "Usage: guix import gem PACKAGE-NAME + (display (G_ "Usage: guix import gem PACKAGE-NAME Import and convert the RubyGems package for PACKAGE-NAME.\n")) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -68,7 +68,7 @@ Import and convert the RubyGems package for PACKAGE-NAME.\n")) ;; Return the alist of option values. (args-fold* args %options (lambda (opt name arg result) - (leave (_ "~A: unrecognized option~%") name)) + (leave (G_ "~A: unrecognized option~%") name)) (lambda (arg result) (alist-cons 'argument arg result)) %default-options)) @@ -83,10 +83,10 @@ Import and convert the RubyGems package for PACKAGE-NAME.\n")) ((package-name) (let ((sexp (gem->guix-package package-name))) (unless sexp - (leave (_ "failed to download meta-data for package '~a'~%") + (leave (G_ "failed to download meta-data for package '~a'~%") package-name)) sexp)) (() - (leave (_ "too few arguments~%"))) + (leave (G_ "too few arguments~%"))) ((many ...) - (leave (_ "too many arguments~%")))))) + (leave (G_ "too many arguments~%")))))) diff --git a/guix/scripts/import/gnu.scm b/guix/scripts/import/gnu.scm index 66861f5837..ae98370037 100644 --- a/guix/scripts/import/gnu.scm +++ b/guix/scripts/import/gnu.scm @@ -37,18 +37,18 @@ '((key-download . interactive))) (define (show-help) - (display (_ "Usage: guix import gnu [OPTION...] PACKAGE + (display (G_ "Usage: guix import gnu [OPTION...] PACKAGE Return a package declaration template for PACKAGE, a GNU package.\n")) ;; '--key-download' taken from (guix scripts refresh). - (display (_ " + (display (G_ " --key-download=POLICY handle missing OpenPGP keys according to POLICY: 'always', 'never', and 'interactive', which is also used when 'key-download' is not specified")) (newline) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -69,7 +69,7 @@ Return a package declaration template for PACKAGE, a GNU package.\n")) (alist-cons 'key-download (string->symbol arg) result)) (x - (leave (_ "unsupported policy: ~a~%") + (leave (G_ "unsupported policy: ~a~%") arg))))) %standard-import-options)) @@ -83,7 +83,7 @@ Return a package declaration template for PACKAGE, a GNU package.\n")) ;; Return the alist of option values. (args-fold* args %options (lambda (opt name arg result) - (leave (_ "~A: unrecognized option~%") name)) + (leave (G_ "~A: unrecognized option~%") name)) (lambda (arg result) (alist-cons 'argument arg result)) %default-options)) @@ -100,6 +100,6 @@ Return a package declaration template for PACKAGE, a GNU package.\n")) (gnu->guix-package name #:key-download (assoc-ref opts 'key-download)))) (x - (leave (_ "wrong number of arguments~%")))))) + (leave (G_ "wrong number of arguments~%")))))) ;;; gnu.scm ends here diff --git a/guix/scripts/import/hackage.scm b/guix/scripts/import/hackage.scm index f2c20026b6..969f637846 100644 --- a/guix/scripts/import/hackage.scm +++ b/guix/scripts/import/hackage.scm @@ -44,23 +44,23 @@ (cabal-environment . ,`(("impl" . ,ghc-default-version))))) (define (show-help) - (display (_ "Usage: guix import hackage PACKAGE-NAME + (display (G_ "Usage: guix import hackage PACKAGE-NAME Import and convert the Hackage package for PACKAGE-NAME. If PACKAGE-NAME includes a suffix constituted by a at-sign followed by a numerical version (as used with Guix packages), then a definition for the specified version of the package will be generated. If no version suffix is pecified, then the generated package definition will correspond to the latest available version.\n")) - (display (_ " + (display (G_ " -e ALIST, --cabal-environment=ALIST specify environment for Cabal evaluation")) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -s, --stdin read from standard input")) - (display (_ " + (display (G_ " -t, --no-test-dependencies don't include test-only dependencies")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -101,7 +101,7 @@ version.\n")) ;; Return the alist of option values. (args-fold* args %options (lambda (opt name arg result) - (leave (_ "~A: unrecognized option~%") name)) + (leave (G_ "~A: unrecognized option~%") name)) (lambda (arg result) (alist-cons 'argument arg result)) %default-options)) @@ -130,18 +130,18 @@ version.\n")) (() (run-importer "stdin" opts (lambda () - (leave (_ "failed to import cabal file \ + (leave (G_ "failed to import cabal file \ from standard input~%"))))) ((many ...) - (leave (_ "too many arguments~%")))) + (leave (G_ "too many arguments~%")))) (match args ((package-name) (run-importer package-name opts (lambda () - (leave (_ "failed to download cabal file \ + (leave (G_ "failed to download cabal file \ for package '~a'~%") package-name)))) (() - (leave (_ "too few arguments~%"))) + (leave (G_ "too few arguments~%"))) ((many ...) - (leave (_ "too many arguments~%"))))))) + (leave (G_ "too many arguments~%"))))))) diff --git a/guix/scripts/import/nix.scm b/guix/scripts/import/nix.scm index 05e6e4b85d..45ca7e3fcf 100644 --- a/guix/scripts/import/nix.scm +++ b/guix/scripts/import/nix.scm @@ -38,11 +38,11 @@ '()) (define (show-help) - (display (_ "Usage: guix import nix NIXPKGS ATTRIBUTE + (display (G_ "Usage: guix import nix NIXPKGS ATTRIBUTE Import and convert the Nix expression ATTRIBUTE of NIXPKGS.\n")) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -68,7 +68,7 @@ Import and convert the Nix expression ATTRIBUTE of NIXPKGS.\n")) ;; Return the alist of option values. (args-fold* args %options (lambda (opt name arg result) - (leave (_ "~A: unrecognized option~%") name)) + (leave (G_ "~A: unrecognized option~%") name)) (lambda (arg result) (alist-cons 'argument arg result)) %default-options)) @@ -87,4 +87,4 @@ Import and convert the Nix expression ATTRIBUTE of NIXPKGS.\n")) (location-file loc) (location-line loc)) expr)) (x - (leave (_ "wrong number of arguments~%")))))) + (leave (G_ "wrong number of arguments~%")))))) diff --git a/guix/scripts/import/pypi.scm b/guix/scripts/import/pypi.scm index 7166b014eb..59a925a3ca 100644 --- a/guix/scripts/import/pypi.scm +++ b/guix/scripts/import/pypi.scm @@ -38,11 +38,11 @@ '()) (define (show-help) - (display (_ "Usage: guix import pypi PACKAGE-NAME + (display (G_ "Usage: guix import pypi PACKAGE-NAME Import and convert the PyPI package for PACKAGE-NAME.\n")) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -68,7 +68,7 @@ Import and convert the PyPI package for PACKAGE-NAME.\n")) ;; Return the alist of option values. (args-fold* args %options (lambda (opt name arg result) - (leave (_ "~A: unrecognized option~%") name)) + (leave (G_ "~A: unrecognized option~%") name)) (lambda (arg result) (alist-cons 'argument arg result)) %default-options)) @@ -83,10 +83,10 @@ Import and convert the PyPI package for PACKAGE-NAME.\n")) ((package-name) (let ((sexp (pypi->guix-package package-name))) (unless sexp - (leave (_ "failed to download meta-data for package '~a'~%") + (leave (G_ "failed to download meta-data for package '~a'~%") package-name)) sexp)) (() - (leave (_ "too few arguments~%"))) + (leave (G_ "too few arguments~%"))) ((many ...) - (leave (_ "too many arguments~%")))))) + (leave (G_ "too many arguments~%")))))) diff --git a/guix/scripts/import/stackage.scm b/guix/scripts/import/stackage.scm index f91b496d24..e6676e93e8 100644 --- a/guix/scripts/import/stackage.scm +++ b/guix/scripts/import/stackage.scm @@ -40,16 +40,16 @@ (include-test-dependencies? . #t))) (define (show-help) - (display (_ "Usage: guix import stackage PACKAGE-NAME + (display (G_ "Usage: guix import stackage PACKAGE-NAME Import and convert the LTS Stackage package for PACKAGE-NAME.\n")) - (display (_ " + (display (G_ " -r VERSION, --lts-version=VERSION specify the LTS version to use")) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -t, --no-test-dependencies don't include test-only dependencies")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -85,7 +85,7 @@ Import and convert the LTS Stackage package for PACKAGE-NAME.\n")) ;; Return the alist of option values. (args-fold* args %options (lambda (opt name arg result) - (leave (_ "~A: unrecognized option~%") name)) + (leave (G_ "~A: unrecognized option~%") name)) (lambda (arg result) (alist-cons 'argument arg result)) %default-options)) @@ -105,12 +105,12 @@ Import and convert the LTS Stackage package for PACKAGE-NAME.\n")) (assoc-ref opts 'include-test-dependencies?) #:lts-version (assoc-ref opts 'lts-version)))) (unless sexp - (leave (_ "failed to download cabal file for package '~a'~%") + (leave (G_ "failed to download cabal file for package '~a'~%") package-name)) sexp))) (() - (leave (_ "too few arguments~%"))) + (leave (G_ "too few arguments~%"))) ((many ...) - (leave (_ "too many arguments~%")))))) + (leave (G_ "too many arguments~%")))))) ;;; stackage.scm ends here diff --git a/guix/scripts/lint.scm b/guix/scripts/lint.scm index 811f167067..04ab852999 100644 --- a/guix/scripts/lint.scm +++ b/guix/scripts/lint.scm @@ -132,11 +132,11 @@ monad." (define (list-checkers-and-exit) ;; Print information about all available checkers and exit. - (format #t (_ "Available checkers:~%")) + (format #t (G_ "Available checkers:~%")) (for-each (lambda (checker) (format #t "- ~a: ~a~%" (lint-checker-name checker) - (_ (lint-checker-description checker)))) + (G_ (lint-checker-description checker)))) %checkers) (exit 0)) @@ -156,7 +156,7 @@ monad." (define (check-not-empty description) (when (string-null? description) (emit-warning package - (_ "description should not be empty") + (G_ "description should not be empty") 'description))) (define (check-texinfo-markup description) @@ -166,7 +166,7 @@ markup is valid return a plain-text version of DESCRIPTION, otherwise #f." (lambda () (texi->plain-text description)) (lambda (keys . args) (emit-warning package - (_ "Texinfo markup in description is invalid") + (G_ "Texinfo markup in description is invalid") 'description) #f))) @@ -176,7 +176,7 @@ http://www.gnu.org/prep/standards/html_node/Trademarks.html." (match (string-index description (char-set #\™ #\®)) ((and (? number?) index) (emit-warning package - (format #f (_ "description should not contain ~ + (format #f (G_ "description should not contain ~ trademark sign '~a' at ~d") (string-ref description index) index) 'description)) @@ -189,14 +189,14 @@ trademark sign '~a' at ~d") ;; TRANSLATORS: '@code' is Texinfo markup and must be kept ;; as is. - (_ "use @code or similar ornament instead of quotes") + (G_ "use @code or similar ornament instead of quotes") 'description))) (define (check-proper-start description) (unless (or (properly-starts-sentence? description) (string-prefix-ci? (package-name package) description)) (emit-warning package - (_ "description should start with an upper-case letter or digit") + (G_ "description should start with an upper-case letter or digit") 'description))) (define (check-end-of-sentence-space description) @@ -212,7 +212,7 @@ trademark sign '~a' at ~d") r (cons (match:start m) r))))))) (unless (null? infractions) (emit-warning package - (format #f (_ "sentences in description should be followed ~ + (format #f (G_ "sentences in description should be followed ~ by two spaces; possible infraction~p at ~{~a~^, ~}") (length infractions) infractions) @@ -230,35 +230,33 @@ by two spaces; possible infraction~p at ~{~a~^, ~}") (and=> (check-texinfo-markup description) check-proper-start)) (emit-warning package - (format #f (_ "invalid description: ~s") description) + (format #f (G_ "invalid description: ~s") description) 'description)))) -(define (warn-if-package-has-input linted inputs-to-check input-names message) - ;; Emit a warning MESSAGE if some of the inputs named in INPUT-NAMES are - ;; contained in INPUTS-TO-CHECK, which are assumed to be inputs of package - ;; LINTED. +(define (package-input-intersection inputs-to-check input-names) + "Return the intersection between INPUTS-TO-CHECK, the list of input tuples +of a package, and INPUT-NAMES, a list of package specifications such as +\"glib:bin\"." (match inputs-to-check (((labels packages . outputs) ...) - (for-each (lambda (package output) - (when (package? package) - (let ((input (string-append - (package-name package) - (if (> (length output) 0) - (string-append ":" (car output)) - "")))) - (when (member input input-names) - (emit-warning linted - (format #f (_ message) input) - 'inputs-to-check))))) - packages outputs)))) + (filter-map (lambda (package output) + (and (package? package) + (let ((input (string-append + (package-name package) + (if (> (length output) 0) + (string-append ":" (car output)) + "")))) + (and (member input input-names) + input)))) + packages outputs)))) (define (check-inputs-should-be-native package) ;; Emit a warning if some inputs of PACKAGE are likely to belong to its ;; native inputs. - (let ((message "'~a' should probably be a native input") - (inputs (package-inputs package)) + (let ((inputs (package-inputs package)) (input-names - '("pkg-config" + '("pkg-config" + "cmake" "extra-cmake-modules" "glib:bin" "intltool" @@ -274,24 +272,29 @@ by two spaces; possible infraction~p at ~{~a~^, ~}") "python-pytest-cov" "python2-pytest-cov" "python-setuptools-scm" "python2-setuptools-scm" "python-sphinx" "python2-sphinx"))) - (warn-if-package-has-input package inputs input-names message))) + (for-each (lambda (input) + (emit-warning + package + (format #f (G_ "'~a' should probably be a native input") + input) + 'inputs-to-check)) + (package-input-intersection inputs input-names)))) (define (check-inputs-should-not-be-an-input-at-all package) ;; Emit a warning if some inputs of PACKAGE are likely to should not be ;; an input at all. - (let ((message "'~a' should probably not be an input at all") - (inputs (package-inputs package)) - (input-names - '("python-setuptools" - "python2-setuptools" - "python-pip" - "python2-pip"))) - (warn-if-package-has-input package (package-inputs package) - input-names message) - (warn-if-package-has-input package (package-native-inputs package) - input-names message) - (warn-if-package-has-input package (package-propagated-inputs package) - input-names message))) + (let ((input-names '("python-setuptools" + "python2-setuptools" + "python-pip" + "python2-pip"))) + (for-each (lambda (input) + (emit-warning + package + (format #f + (G_ "'~a' should probably not be an input at all") + input))) + (package-input-intersection (package-direct-inputs package) + input-names)))) (define (package-name-regexp package) "Return a regexp that matches PACKAGE's name as a word at the beginning of a @@ -305,7 +308,7 @@ line." (define (check-not-empty synopsis) (when (string-null? synopsis) (emit-warning package - (_ "synopsis should not be empty") + (G_ "synopsis should not be empty") 'synopsis))) (define (check-final-period synopsis) @@ -313,7 +316,7 @@ line." (when (and (string-suffix? "." synopsis) (not (string-suffix? "etc." synopsis))) (emit-warning package - (_ "no period allowed at the end of the synopsis") + (G_ "no period allowed at the end of the synopsis") 'synopsis))) (define check-start-article @@ -325,27 +328,27 @@ line." (when (or (string-prefix-ci? "A " synopsis) (string-prefix-ci? "An " synopsis)) (emit-warning package - (_ "no article allowed at the beginning of \ + (G_ "no article allowed at the beginning of \ the synopsis") 'synopsis))))) (define (check-synopsis-length synopsis) (when (>= (string-length synopsis) 80) (emit-warning package - (_ "synopsis should be less than 80 characters long") + (G_ "synopsis should be less than 80 characters long") 'synopsis))) (define (check-proper-start synopsis) (unless (properly-starts-sentence? synopsis) (emit-warning package - (_ "synopsis should start with an upper-case letter or digit") + (G_ "synopsis should start with an upper-case letter or digit") 'synopsis))) (define (check-start-with-package-name synopsis) (when (and (regexp-exec (package-name-regexp package) synopsis) (not (starts-with-abbreviation? synopsis))) (emit-warning package - (_ "synopsis should not start with the package name") + (G_ "synopsis should not start with the package name") 'synopsis))) (define (check-texinfo-markup synopsis) @@ -355,7 +358,7 @@ markup is valid return a plain-text version of SYNOPSIS, otherwise #f." (lambda () (texi->plain-text synopsis)) (lambda (keys . args) (emit-warning package - (_ "Texinfo markup in synopsis is invalid") + (G_ "Texinfo markup in synopsis is invalid") 'synopsis) #f))) @@ -374,7 +377,7 @@ markup is valid return a plain-text version of SYNOPSIS, otherwise #f." (proc synopsis)) checks)) (invalid - (emit-warning package (format #f (_ "invalid synopsis: ~s") invalid) + (emit-warning package (format #f (G_ "invalid synopsis: ~s") invalid) 'synopsis)))) (define* (probe-uri uri #:key timeout) @@ -474,7 +477,7 @@ warning for PACKAGE mentionning the FIELD." (begin (emit-warning package (format #f - (_ "URI ~a returned \ + (G_ "URI ~a returned \ suspiciously small file (~a bytes)") (uri->string uri) length)) @@ -483,7 +486,7 @@ suspiciously small file (~a bytes)") (begin (emit-warning package (format #f - (_ "URI ~a not reachable: ~a (~s)") + (G_ "URI ~a not reachable: ~a (~s)") (uri->string uri) (response-code argument) (response-reason-phrase argument)) @@ -495,14 +498,14 @@ suspiciously small file (~a bytes)") (('error port command code message) (emit-warning package (format #f - (_ "URI ~a not reachable: ~a (~s)") + (G_ "URI ~a not reachable: ~a (~s)") (uri->string uri) code (string-trim-both message))) #f))) ((getaddrinfo-error) (emit-warning package (format #f - (_ "URI ~a domain not found: ~a") + (G_ "URI ~a domain not found: ~a") (uri->string uri) (gai-strerror (car argument))) field) @@ -510,7 +513,7 @@ suspiciously small file (~a bytes)") ((system-error) (emit-warning package (format #f - (_ "URI ~a unreachable: ~a") + (G_ "URI ~a unreachable: ~a") (uri->string uri) (strerror (system-error-errno @@ -519,7 +522,7 @@ suspiciously small file (~a bytes)") #f) ((tls-certificate-error) (emit-warning package - (format #f (_ "TLS certificate error: ~a") + (format #f (G_ "TLS certificate error: ~a") (tls-certificate-error-string argument)))) ((invalid-http-response gnutls-error) ;; Probably a misbehaving server; ignore. @@ -540,10 +543,10 @@ suspiciously small file (~a bytes)") (unless (or (string-contains (package-name package) "bootstrap") (string=? (package-name package) "ld-wrapper")) (emit-warning package - (_ "invalid value for home page") + (G_ "invalid value for home page") 'home-page))) (else - (emit-warning package (format #f (_ "invalid home page URL: ~s") + (emit-warning package (format #f (G_ "invalid home page URL: ~s") (package-home-page package)) 'home-page))))) @@ -563,7 +566,7 @@ patch could not be found." '())) (emit-warning package - (_ "file names of patches should start with the package name") + (G_ "file names of patches should start with the package name") 'patch-file-names)))) (define (escape-quotes str) @@ -601,7 +604,7 @@ descriptions maintained upstream." (or (not (string? downstream)) (not (string=? upstream downstream)))) (format (guix-warning-port) - (_ "~a: ~a: proposed synopsis: ~s~%") + (G_ "~a: ~a: proposed synopsis: ~s~%") (location->string loc) (package-full-name package) upstream))) @@ -614,7 +617,7 @@ descriptions maintained upstream." (not (string=? (fill-paragraph upstream 100) (fill-paragraph downstream 100))))) (format (guix-warning-port) - (_ "~a: ~a: proposed description:~% \"~a\"~%") + (G_ "~a: ~a: proposed description:~% \"~a\"~%") (location->string loc) (package-full-name package) (fill-paragraph (escape-quotes upstream) 77 7))))))) @@ -656,7 +659,7 @@ descriptions maintained upstream." ;; where *all* the URIs are unreachable. (unless success? (emit-warning package - (_ "all the source URIs are unreachable:") + (G_ "all the source URIs are unreachable:") 'source) (for-each (lambda (warning) (display warning (guix-warning-port))) @@ -665,21 +668,20 @@ descriptions maintained upstream." (define (check-source-file-name package) "Emit a warning if PACKAGE's origin has no meaningful file name." (define (origin-file-name-valid? origin) - ;; Return #t if the source file name contains only a version or is #f; + ;; Return #f if the source file name contains only a version or is #f; ;; indicates that the origin needs a 'file-name' field. (let ((file-name (origin-actual-file-name origin)) (version (package-version package))) (and file-name - (not (or (string-prefix? version file-name) - ;; Common in many projects is for the filename to start - ;; with a "v" followed by the version, - ;; e.g. "v3.2.0.tar.gz". - (string-prefix? (string-append "v" version) file-name)))))) + ;; Common in many projects is for the filename to start + ;; with a "v" followed by the version, + ;; e.g. "v3.2.0.tar.gz". + (not (string-match (string-append "^v?" version) file-name))))) (let ((origin (package-source package))) (unless (or (not origin) (origin-file-name-valid? origin)) (emit-warning package - (_ "the source file name should contain the package name") + (G_ "the source file name should contain the package name") 'source)))) (define (check-mirror-url package) @@ -695,7 +697,7 @@ descriptions maintained upstream." (loop rest)) (prefix (emit-warning package - (format #f (_ "URL should be \ + (format #f (G_ "URL should be \ 'mirror://~a/~a'") mirror-id (string-drop uri (string-length prefix))) @@ -713,11 +715,11 @@ descriptions maintained upstream." (lambda () (guard (c ((nix-protocol-error? c) (emit-warning package - (format #f (_ "failed to create derivation: ~a") + (format #f (G_ "failed to create derivation: ~a") (nix-protocol-error-message c)))) ((message-condition? c) (emit-warning package - (format #f (_ "failed to create derivation: ~a") + (format #f (G_ "failed to create derivation: ~a") (condition-message c))))) (with-store store ;; Disable grafts since it can entail rebuilds. @@ -731,7 +733,7 @@ descriptions maintained upstream." (package-derivation store replacement #:graft? #f)))))) (lambda args (emit-warning package - (format #f (_ "failed to create derivation: ~s~%") + (format #f (G_ "failed to create derivation: ~s~%") args))))) (define (check-license package) @@ -741,7 +743,7 @@ descriptions maintained upstream." ((? license?) ...)) #t) (x - (emit-warning package (_ "invalid license field") + (emit-warning package (G_ "invalid license field") 'license)))) (define (patch-file-name patch) @@ -758,26 +760,26 @@ be determined." or HTTP errors. This allows network-less operation and makes problems with the NIST server non-fatal.." (guard (c ((http-get-error? c) - (warning (_ "failed to retrieve CVE vulnerabilities \ + (warning (G_ "failed to retrieve CVE vulnerabilities \ from ~s: ~a (~s)~%") (uri->string (http-get-error-uri c)) (http-get-error-code c) (http-get-error-reason c)) - (warning (_ "assuming no CVE vulnerabilities~%")) + (warning (G_ "assuming no CVE vulnerabilities~%")) '())) (catch #t (lambda () (current-vulnerabilities)) (match-lambda* (('getaddrinfo-error errcode) - (warning (_ "failed to lookup NIST host: ~a~%") + (warning (G_ "failed to lookup NIST host: ~a~%") (gai-strerror errcode)) - (warning (_ "assuming no CVE vulnerabilities~%")) + (warning (G_ "assuming no CVE vulnerabilities~%")) '()) (('tls-certificate-error args ...) - (warning (_ "TLS certificate error: ~a") + (warning (G_ "TLS certificate error: ~a") (tls-certificate-error-string args)) - (warning (_ "assuming no CVE vulnerabilities~%")) + (warning (G_ "assuming no CVE vulnerabilities~%")) '()) (args (apply throw args)))))) @@ -815,7 +817,7 @@ from ~s: ~a (~s)~%") vulnerabilities))) (unless (null? unpatched) (emit-warning package - (format #f (_ "probably vulnerable to ~a") + (format #f (G_ "probably vulnerable to ~a") (string-join (map vulnerability-id unpatched) ", "))))))))) @@ -830,7 +832,7 @@ from ~s: ~a (~s)~%") (#f #t) (index (emit-warning package - (format #f (_ "tabulation on line ~a, column ~a") + (format #f (G_ "tabulation on line ~a, column ~a") line-number index))))) (define (report-trailing-white-space package line line-number) @@ -839,7 +841,7 @@ from ~s: ~a (~s)~%") (string=? line (string #\page))) (emit-warning package (format #f - (_ "trailing white space on line ~a") + (G_ "trailing white space on line ~a") line-number)))) (define (report-long-line package line line-number) @@ -849,7 +851,7 @@ from ~s: ~a (~s)~%") ;; much noise. (when (> (string-length line) 90) (emit-warning package - (format #f (_ "line ~a is way too long (~a characters)") + (format #f (G_ "line ~a is way too long (~a characters)") line-number (string-length line))))) (define %hanging-paren-rx @@ -860,7 +862,7 @@ from ~s: ~a (~s)~%") (when (regexp-exec %hanging-paren-rx line) (emit-warning package (format #f - (_ "line ~a: parentheses feel lonely, \ + (G_ "line ~a: parentheses feel lonely, \ move to the previous or next line") line-number)))) @@ -999,17 +1001,17 @@ or a list thereof") '()) (define (show-help) - (display (_ "Usage: guix lint [OPTION]... [PACKAGE]... + (display (G_ "Usage: guix lint [OPTION]... [PACKAGE]... Run a set of checkers on the specified package; if none is specified, run the checkers on all packages.\n")) - (display (_ " + (display (G_ " -c, --checkers=CHECKER1,CHECKER2... only run the specified checkers")) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -l, --list-checkers display the list of available lint checkers")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -1027,7 +1029,7 @@ run the checkers on all packages.\n")) (unless (memq c (map lint-checker-name %checkers)) - (leave (_ "~a: invalid checker~%") c))) + (leave (G_ "~a: invalid checker~%") c))) names) (alist-cons 'checkers (filter (lambda (checker) @@ -1056,7 +1058,7 @@ run the checkers on all packages.\n")) ;; Return the alist of option values. (args-fold* args %options (lambda (opt name arg result) - (leave (_ "~A: unrecognized option~%") name)) + (leave (G_ "~A: unrecognized option~%") name)) (lambda (arg result) (alist-cons 'argument arg result)) %default-options)) diff --git a/guix/scripts/offload.scm b/guix/scripts/offload.scm index 6a4ae28689..74c0c5484c 100644 --- a/guix/scripts/offload.scm +++ b/guix/scripts/offload.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -130,14 +130,14 @@ determined." ;; Silently ignore missing file since this is a common case. (if (= ENOENT err) '() - (leave (_ "failed to open machine file '~a': ~a~%") + (leave (G_ "failed to open machine file '~a': ~a~%") file (strerror err))))) (('syntax-error proc message properties form . rest) (let ((loc (source-properties->location properties))) - (leave (_ "~a: ~a~%") + (leave (G_ "~a: ~a~%") (location->string loc) message))) (x - (leave (_ "failed to load machine file '~a': ~s~%") + (leave (G_ "failed to load machine file '~a': ~s~%") file args)))))) (define (host-key->type+key host-key) @@ -148,7 +148,7 @@ its key type as a symbol, and the actual base64-encoded string." (string->symbol (string-drop type 4)))) (match (string-tokenize host-key) - ((type key _) + ((type key x) (values (type->symbol type) key)) ((type key) (values (type->symbol type) key)))) @@ -161,7 +161,7 @@ can interpret meaningfully." (private-key-from-file file)) (lambda (key proc str . rest) (raise (condition - (&message (message (format #f (_ "failed to load SSH \ + (&message (message (format #f (G_ "failed to load SSH \ private key from '~a': ~a") file str)))))))) @@ -204,7 +204,7 @@ private key from '~a': ~a") (string=? (public-key->string server) key)) ;; Key mismatch: something's wrong. XXX: It could be that the server ;; provided its Ed25519 key when we where expecting its RSA key. - (leave (_ "server at '~a' returned host key '~a' of type '~a' \ + (leave (G_ "server at '~a' returned host key '~a' of type '~a' \ instead of '~a' of type '~a'~%") (build-machine-name machine) (public-key->string server) (get-key-type server) @@ -213,13 +213,13 @@ instead of '~a' of type '~a'~%") (let ((auth (userauth-public-key! session private))) (unless (eq? 'success auth) (disconnect! session) - (leave (_ "SSH public key authentication failed for '~a': ~a~%") + (leave (G_ "SSH public key authentication failed for '~a': ~a~%") (build-machine-name machine) (get-error session)))) session) (x ;; Connection failed or timeout expired. - (leave (_ "failed to connect to '~a': ~a~%") + (leave (G_ "failed to connect to '~a': ~a~%") (build-machine-name machine) (get-error session)))))) @@ -346,7 +346,7 @@ MACHINE." (guard (c ((nix-protocol-error? c) (format (current-error-port) - (_ "derivation '~a' offloaded to '~a' failed: ~a~%") + (G_ "derivation '~a' offloaded to '~a' failed: ~a~%") (derivation-file-name drv) (build-machine-name machine) (nix-protocol-error-message c)) @@ -403,7 +403,7 @@ allowed on MACHINE. Return +∞ if MACHINE is unreachable." (if (eof-object? line) +inf.0 ;MACHINE does not respond, so assume it is infinitely loaded (match (string-tokenize line) - ((one five fifteen . _) + ((one five fifteen . x) (let* ((raw (string->number five)) (jobs (build-machine-parallel-builds machine)) (normalized (/ raw jobs))) @@ -411,9 +411,9 @@ allowed on MACHINE. Return +∞ if MACHINE is unreachable." (normalized: ~s)~%" (build-machine-name machine) raw normalized) normalized)) - (_ + (x +inf.0))))) ;something's fishy about MACHINE, so avoid it - (_ + (x +inf.0))) ;failed to connect to MACHINE, so avoid it (define (machine-lock-file machine hint) @@ -503,7 +503,7 @@ allowed on MACHINE. Return +∞ if MACHINE is unreachable." (() ;; We'll never be able to match REQS. (display "# decline\n")) - ((_ ...) + ((x ...) (let ((machine (choose-build-machine candidates))) (if machine (begin @@ -530,11 +530,11 @@ allowed on MACHINE. Return +∞ if MACHINE is unreachable." "Bail out if NODE is not running Guile." (match (node-guile-version node) (#f - (leave (_ "Guile could not be started on '~a'~%") + (leave (G_ "Guile could not be started on '~a'~%") name)) ((? string? version) ;; Note: The version string already contains the word "Guile". - (info (_ "'~a' is running ~a~%") + (info (G_ "'~a' is running ~a~%") name (node-guile-version node))))) (define (assert-node-has-guix node name) @@ -546,10 +546,10 @@ allowed on MACHINE. Return +∞ if MACHINE is unreachable." (add-text-to-store store "test" "Hello, build machine!")))) ((? string? str) - (info (_ "Guix is usable on '~a' (test returned ~s)~%") + (info (G_ "Guix is usable on '~a' (test returned ~s)~%") name str)) (x - (leave (_ "failed to use Guix module on '~a' (test returned ~s)~%") + (leave (G_ "failed to use Guix module on '~a' (test returned ~s)~%") name x)))) (define %random-state @@ -570,9 +570,9 @@ allowed on MACHINE. Return +∞ if MACHINE is unreachable." (send-files local (list item) remote)) (if (valid-path? remote item) - (info (_ "'~a' successfully imported '~a'~%") + (info (G_ "'~a' successfully imported '~a'~%") name item) - (leave (_ "'~a' was not properly imported on '~a'~%") + (leave (G_ "'~a' was not properly imported on '~a'~%") item name)))))) (define (assert-node-can-export node name daemon-socket) @@ -583,9 +583,9 @@ allowed on MACHINE. Return +∞ if MACHINE is unreachable." (with-store store (if (and (retrieve-files store (list item) remote) (valid-path? store item)) - (info (_ "successfully imported '~a' from '~a'~%") + (info (G_ "successfully imported '~a' from '~a'~%") item name) - (leave (_ "failed to import '~a' from '~a'~%") + (leave (G_ "failed to import '~a' from '~a'~%") item name))))) (define (check-machine-availability machine-file pred) @@ -600,7 +600,7 @@ machine." (let ((machines (filter pred (delete-duplicates (build-machines machine-file) build-machine=?)))) - (info (_ "testing ~a build machines defined in '~a'...~%") + (info (G_ "testing ~a build machines defined in '~a'...~%") (length machines) machine-file) (let* ((names (map build-machine-name machines)) (sockets (map build-machine-daemon-socket machines)) @@ -633,8 +633,8 @@ machine." ;; We rely on protocol-level compression from libssh to optimize large data ;; transfers. Warn if it's missing. (unless (zlib-support?) - (warning (_ "Guile-SSH lacks zlib support")) - (warning (_ "data transfers will *not* be compressed!"))) + (warning (G_ "Guile-SSH lacks zlib support")) + (warning (G_ "data transfers will *not* be compressed!"))) (match args ((system max-silent-time print-build-trace? build-timeout) @@ -659,7 +659,7 @@ machine." #:max-silent-time max-silent-time #:build-timeout build-timeout)))) (else - (leave (_ "invalid request line: ~s~%") line))) + (leave (G_ "invalid request line: ~s~%") line))) (loop (read-line))))))) (("test" rest ...) (with-error-handling @@ -671,20 +671,20 @@ machine." build-machine-name))) ((file) (values file (const #t))) (() (values %machine-file (const #t))) - (_ (leave (_ "wrong number of arguments~%")))))) + (x (leave (G_ "wrong number of arguments~%")))))) (check-machine-availability (or file %machine-file) pred)))) (("--version") (show-version-and-exit "guix offload")) (("--help") - (format #t (_ "Usage: guix offload SYSTEM PRINT-BUILD-TRACE + (format #t (G_ "Usage: guix offload SYSTEM PRINT-BUILD-TRACE Process build offload requests written on the standard input, possibly offloading builds to the machines listed in '~a'.~%") %machine-file) - (display (_ " + (display (G_ " This tool is meant to be used internally by 'guix-daemon'.\n")) (show-bug-report-information)) (x - (leave (_ "invalid arguments: ~{~s ~}~%") x)))) + (leave (G_ "invalid arguments: ~{~s ~}~%") x)))) ;;; Local Variables: ;;; eval: (put 'with-machine-lock 'scheme-indent-function 2) diff --git a/guix/scripts/pack.scm b/guix/scripts/pack.scm index 9e91bc22ac..1273c09f54 100644 --- a/guix/scripts/pack.scm +++ b/guix/scripts/pack.scm @@ -35,7 +35,7 @@ #:autoload (gnu packages base) (tar) #:autoload (gnu packages package-management) (guix) #:autoload (gnu packages gnupg) (libgcrypt) - #:autoload (gnu packages guile) (guile-json) + #:autoload (gnu packages guile) (guile2.0-json guile-json) #:use-module (srfi srfi-1) #:use-module (srfi srfi-9) #:use-module (srfi srfi-37) @@ -71,7 +71,7 @@ found." (($ <compressor> name*) (string=? name* name))) %compressors) - (leave (_ "~a: compressor not found~%") name))) + (leave (G_ "~a: compressor not found~%") name))) (define* (self-contained-tarball name profile #:key target @@ -217,6 +217,13 @@ the image." (define %libgcrypt #+(file-append libgcrypt "/lib/libgcrypt")))))) + (define json + ;; Pick the guile-json package that corresponds to the Guile used to build + ;; derivations. + (if (string-prefix? "2.0" (package-version (default-guile))) + guile2.0-json + guile-json)) + (define build (with-imported-modules `(,@(source-module-closure '((guix docker)) #:select? not-config?) @@ -224,7 +231,7 @@ the image." #~(begin ;; Guile-JSON is required by (guix docker). (add-to-load-path - (string-append #$guile-json "/share/guile/site/" + (string-append #+json "/share/guile/site/" (effective-version))) (use-modules (guix docker) (srfi srfi-19)) @@ -280,6 +287,9 @@ the image." (option '(#\f "format") #t #f (lambda (opt name arg result) (alist-cons 'format (string->symbol arg) result))) + (option '(#\e "expression") #t #f + (lambda (opt name arg result) + (alist-cons 'expression arg result))) (option '(#\s "system") #t #f (lambda (opt name arg result) (alist-cons 'system arg @@ -304,7 +314,7 @@ the image." `((,source -> ,target) ,@symlinks) (alist-delete 'symlinks result eq?)))) (x - (leave (_ "~a: invalid symlink specification~%") + (leave (G_ "~a: invalid symlink specification~%") arg))))) (option '("localstatedir") #f #f (lambda (opt name arg result) @@ -314,28 +324,30 @@ the image." %standard-build-options))) (define (show-help) - (display (_ "Usage: guix pack [OPTION]... PACKAGE... + (display (G_ "Usage: guix pack [OPTION]... PACKAGE... Create a bundle of PACKAGE.\n")) (show-build-options-help) (newline) (show-transformation-options-help) (newline) - (display (_ " + (display (G_ " -f, --format=FORMAT build a pack in the given FORMAT")) - (display (_ " + (display (G_ " + -e, --expression=EXPR consider the package EXPR evaluates to")) + (display (G_ " -s, --system=SYSTEM attempt to build for SYSTEM--e.g., \"i686-linux\"")) - (display (_ " + (display (G_ " --target=TRIPLET cross-build for TRIPLET--e.g., \"armel-linux-gnu\"")) - (display (_ " + (display (G_ " -C, --compression=TOOL compress using TOOL--e.g., \"lzip\"")) - (display (_ " + (display (G_ " -S, --symlink=SPEC create symlinks to the profile according to SPEC")) - (display (_ " + (display (G_ " --localstatedir include /var/guix in the resulting pack")) (newline) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -349,20 +361,22 @@ Create a bundle of PACKAGE.\n")) (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))) + (with-error-handling (parameterize ((%graft? (assoc-ref opts 'graft?))) - (let* ((dry-run? (assoc-ref opts 'dry-run?)) - (specs (filter-map (match-lambda - (('argument . name) - name) - (x #f)) - opts)) - (packages (map (lambda (spec) - (call-with-values - (lambda () - (specification->package+output spec)) - list)) - specs)) + (let* ((dry-run? (assoc-ref opts 'dry-run?)) + (packages (filter-map maybe-package-argument opts)) (pack-format (assoc-ref opts 'format)) (name (string-append (symbol->string pack-format) "-pack")) @@ -372,7 +386,7 @@ Create a bundle of PACKAGE.\n")) (build-image (match (assq-ref %formats pack-format) ((? procedure? proc) proc) (#f - (leave (_ "~a: unknown pack format") + (leave (G_ "~a: unknown pack format") format)))) (localstatedir? (assoc-ref opts 'localstatedir?))) (with-store store diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm index 6be9d00aec..f050fad976 100644 --- a/guix/scripts/package.scm +++ b/guix/scripts/package.scm @@ -104,7 +104,7 @@ indirectly, or PROFILE." (define (rtfm) (format (current-error-port) - (_ "Try \"info '(guix) Invoking guix package'\" for \ + (G_ "Try \"info '(guix) Invoking guix package'\" for \ more information.~%")) (exit 1)) @@ -126,21 +126,21 @@ more information.~%")) ;; parent directory is root-owned and we're running ;; unprivileged. (format (current-error-port) - (_ "error: while creating directory `~a': ~a~%") + (G_ "error: while creating directory `~a': ~a~%") %profile-directory (strerror (system-error-errno args))) (format (current-error-port) - (_ "Please create the `~a' directory, with you as the owner.~%") + (G_ "Please create the `~a' directory, with you as the owner.~%") %profile-directory) (rtfm)))) ;; Bail out if it's not owned by the user. (unless (or (not s) (= (stat:uid s) (getuid))) (format (current-error-port) - (_ "error: directory `~a' is not owned by you~%") + (G_ "error: directory `~a' is not owned by you~%") %profile-directory) (format (current-error-port) - (_ "Please change the owner of `~a' to user ~s.~%") + (G_ "Please change the owner of `~a' to user ~s.~%") %profile-directory (or (getenv "USER") (getenv "LOGNAME") (getuid))) @@ -175,17 +175,17 @@ denote ranges as interpreted by 'matching-generations'." => (lambda (numbers) (when (memv current numbers) - (warning (_ "not removing generation ~a, which is current~%") + (warning (G_ "not removing generation ~a, which is current~%") current)) ;; Make sure we don't inadvertently remove the current ;; generation. (let ((numbers (delv current numbers))) (when (null-list? numbers) - (leave (_ "no matching generation~%"))) + (leave (G_ "no matching generation~%"))) (delete-generations store profile numbers)))) (else - (leave (_ "invalid syntax: ~a~%") pattern))))) + (leave (G_ "invalid syntax: ~a~%") pattern))))) (define* (build-and-use-profile store profile manifest #:key @@ -211,7 +211,7 @@ specified in MANIFEST, a manifest object." (dry-run? #t) ((and (file-exists? profile) (and=> (readlink* profile) (cut string=? prof <>))) - (format (current-error-port) (_ "nothing to be done~%"))) + (format (current-error-port) (G_ "nothing to be done~%"))) (else (let* ((number (generation-number profile)) @@ -269,7 +269,7 @@ synopsis or description matches all of REGEXPS." "Return a variant of TRANSACTION that accounts for the upgrade of ENTRY, a <manifest-entry>." (define (supersede old new) - (info (_ "package '~a' has been superseded by '~a'~%") + (info (G_ "package '~a' has been superseded by '~a'~%") (manifest-entry-name old) (package-name new)) (manifest-transaction-install-entry (package->manifest-entry new (manifest-entry-output old)) @@ -341,7 +341,7 @@ ENTRIES, a list of manifest entries, in the context of PROFILE." (settings (search-path-environment-variables entries profiles #:kind kind))) (unless (null? settings) - (format #t (_ "The following environment variable definitions may be needed:~%")) + (format #t (G_ "The following environment variable definitions may be needed:~%")) (format #t "~{ ~a~%~}" settings)))) @@ -357,68 +357,68 @@ ENTRIES, a list of manifest entries, in the context of PROFILE." (substitutes? . #t))) (define (show-help) - (display (_ "Usage: guix package [OPTION]... + (display (G_ "Usage: guix package [OPTION]... Install, remove, or upgrade packages in a single transaction.\n")) - (display (_ " + (display (G_ " -i, --install PACKAGE ... install PACKAGEs")) - (display (_ " + (display (G_ " -e, --install-from-expression=EXP install the package EXP evaluates to")) - (display (_ " + (display (G_ " -f, --install-from-file=FILE install the package that the code within FILE evaluates to")) - (display (_ " + (display (G_ " -r, --remove PACKAGE ... remove PACKAGEs")) - (display (_ " + (display (G_ " -u, --upgrade[=REGEXP] upgrade all the installed packages matching REGEXP")) - (display (_ " + (display (G_ " -m, --manifest=FILE create a new profile generation with the manifest from FILE")) - (display (_ " + (display (G_ " --do-not-upgrade[=REGEXP] do not upgrade any packages matching REGEXP")) - (display (_ " + (display (G_ " --roll-back roll back to the previous generation")) - (display (_ " + (display (G_ " --search-paths[=KIND] display needed environment variable definitions")) - (display (_ " + (display (G_ " -l, --list-generations[=PATTERN] list generations matching PATTERN")) - (display (_ " + (display (G_ " -d, --delete-generations[=PATTERN] delete generations matching PATTERN")) - (display (_ " + (display (G_ " -S, --switch-generation=PATTERN switch to a generation matching PATTERN")) - (display (_ " + (display (G_ " -p, --profile=PROFILE use PROFILE instead of the user's default profile")) (newline) - (display (_ " + (display (G_ " --bootstrap use the bootstrap Guile to build the profile")) - (display (_ " + (display (G_ " --verbose produce verbose output")) (newline) - (display (_ " + (display (G_ " -s, --search=REGEXP search in synopsis and description using REGEXP")) - (display (_ " + (display (G_ " -I, --list-installed[=REGEXP] list installed packages matching REGEXP")) - (display (_ " + (display (G_ " -A, --list-available[=REGEXP] list available packages matching REGEXP")) - (display (_ " + (display (G_ " --show=PACKAGE show details about PACKAGE")) (newline) (show-build-options-help) (newline) (show-transformation-options-help) (newline) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -504,7 +504,7 @@ Install, remove, or upgrade packages in a single transaction.\n")) (#f 'exact) (x - (leave (_ "~a: unsupported \ + (leave (G_ "~a: unsupported \ kind of search path~%") x))))) (values (cons `(query search-paths ,kind) @@ -681,24 +681,26 @@ processed, #f otherwise." (unless (null-list? (cdr numbers)) (display-profile-content-diff profile (car numbers) (cadr numbers)) (diff-profiles profile (cdr numbers)))) - (cond ((not (file-exists? profile)) ; XXX: race condition - (raise (condition (&profile-not-found-error - (profile profile))))) - ((string-null? pattern) - (list-generation display-profile-content - (car (profile-generations profile))) - (diff-profiles profile (profile-generations profile))) - ((matching-generations pattern profile) - => - (lambda (numbers) - (if (null-list? numbers) - (exit 1) - (leave-on-EPIPE - (list-generation display-profile-content (car numbers)) - (diff-profiles profile numbers))))) - (else - (leave (_ "invalid syntax: ~a~%") - pattern))) + + (leave-on-EPIPE + (cond ((not (file-exists? profile)) ; XXX: race condition + (raise (condition (&profile-not-found-error + (profile profile))))) + ((string-null? pattern) + (list-generation display-profile-content + (car (profile-generations profile))) + (diff-profiles profile (profile-generations profile))) + ((matching-generations pattern profile) + => + (lambda (numbers) + (if (null-list? numbers) + (exit 1) + (begin + (list-generation display-profile-content (car numbers)) + (diff-profiles profile numbers))))) + (else + (leave (G_ "invalid syntax: ~a~%") + pattern)))) #t) (('list-installed regexp) @@ -788,7 +790,7 @@ processed, #f otherwise." (let ((number (relative-generation-spec->number profile spec))) (if number (switch-to-generation* profile number) - (leave (_ "cannot switch to generation '~a'~%") spec))))) + (leave (G_ "cannot switch to generation '~a'~%") spec))))) (define* (delete-generations-action store profile pattern opts #:key dry-run?) @@ -804,9 +806,9 @@ processed, #f otherwise." (bootstrap? (assoc-ref opts 'bootstrap?)) (substitutes? (assoc-ref opts 'substitutes?))) (if dry-run? - (format #t (_ "would install new manifest from '~a' with ~d entries~%") + (format #t (G_ "would install new manifest from '~a' with ~d entries~%") file (length (manifest-entries manifest))) - (format #t (_ "installing new manifest from '~a' with ~d entries~%") + (format #t (G_ "installing new manifest from '~a' with ~d entries~%") file (length (manifest-entries manifest)))) (build-and-use-profile store profile manifest #:bootstrap? bootstrap? @@ -859,6 +861,8 @@ processed, #f otherwise." (manifest-transaction-install step2))))) (new (manifest-perform-transaction manifest step3))) + (warn-about-old-distro) + (unless (manifest-transaction-null? step3) (show-manifest-transaction store manifest step3 #:dry-run? dry-run?) @@ -877,7 +881,7 @@ processed, #f otherwise." ;; Process non-option argument ARG by calling back ARG-HANDLER. (if arg-handler (arg-handler arg result) - (leave (_ "~A: extraneous argument~%") arg))) + (leave (G_ "~A: extraneous argument~%") arg))) (let ((opts (parse-command-line args %options (list %default-options #f) #:argument-handler handle-argument))) diff --git a/guix/scripts/perform-download.scm b/guix/scripts/perform-download.scm index 59ade0a8c1..aee506af46 100644 --- a/guix/scripts/perform-download.scm +++ b/guix/scripts/perform-download.scm @@ -54,7 +54,7 @@ actual output is different from that when we're doing a 'bmCheck' or (mirrors "mirrors") (content-addressed-mirrors "content-addressed-mirrors")) (unless url - (leave (_ "~a: missing URL~%") (derivation-file-name drv))) + (leave (G_ "~a: missing URL~%") (derivation-file-name drv))) (let* ((output (or output output*)) (url (call-with-input-string url read)) @@ -62,7 +62,7 @@ actual output is different from that when we're doing a 'bmCheck' or (algo (derivation-output-hash-algo drv-output)) (hash (derivation-output-hash drv-output))) (unless (and algo hash) - (leave (_ "~a is not a fixed-output derivation~%") + (leave (G_ "~a is not a fixed-output derivation~%") (derivation-file-name drv))) ;; We're invoked by the daemon, which gives us write access to OUTPUT. @@ -86,7 +86,7 @@ actual output is different from that when we're doing a 'bmCheck' or (define (assert-low-privileges) (when (zero? (getuid)) - (leave (_ "refusing to run with elevated privileges (UID ~a)~%") + (leave (G_ "refusing to run with elevated privileges (UID ~a)~%") (getuid)))) (define (guix-perform-download . args) @@ -115,7 +115,7 @@ of GnuTLS over HTTPS, before we have built GnuTLS. See (show-version-and-exit)) (x (leave - (_ "fixed-output derivation and output file name expected~%")))))) + (G_ "fixed-output derivation and output file name expected~%")))))) ;; Local Variables: ;; eval: (put 'derivation-let 'scheme-indent-function 2) diff --git a/guix/scripts/publish.scm b/guix/scripts/publish.scm index d8ac72f4ef..db7f6a957e 100644 --- a/guix/scripts/publish.scm +++ b/guix/scripts/publish.scm @@ -24,6 +24,7 @@ #:use-module (ice-9 match) #:use-module (ice-9 regex) #:use-module (ice-9 rdelim) + #:use-module (ice-9 threads) #:use-module (rnrs bytevectors) #:use-module (srfi srfi-1) #:use-module (srfi srfi-2) @@ -38,6 +39,7 @@ #:use-module (web response) #:use-module (web server) #:use-module (web uri) + #:autoload (sxml simple) (sxml->xml) #:use-module (guix base32) #:use-module (guix base64) #:use-module (guix config) @@ -45,44 +47,52 @@ #:use-module (guix hash) #:use-module (guix pki) #:use-module (guix pk-crypto) + #:use-module (guix workers) #:use-module (guix store) #:use-module ((guix serialization) #:select (write-file)) #:use-module (guix zlib) + #:use-module (guix cache) #:use-module (guix ui) #:use-module (guix scripts) - #:use-module ((guix utils) #:select (compressed-file?)) - #:use-module ((guix build utils) #:select (dump-port)) + #:use-module ((guix utils) + #:select (with-atomic-file-output compressed-file?)) + #:use-module ((guix build utils) + #:select (dump-port mkdir-p find-files)) #:export (%public-key %private-key guix-publish)) (define (show-help) - (format #t (_ "Usage: guix publish [OPTION]... + (format #t (G_ "Usage: guix publish [OPTION]... Publish ~a over HTTP.\n") %store-directory) - (display (_ " + (display (G_ " -p, --port=PORT listen on PORT")) - (display (_ " + (display (G_ " --listen=HOST listen on the network interface for HOST")) - (display (_ " + (display (G_ " -u, --user=USER change privileges to USER as soon as possible")) - (display (_ " + (display (G_ " -C, --compression[=LEVEL] compress archives at LEVEL")) - (display (_ " + (display (G_ " + -c, --cache=DIRECTORY cache published items to DIRECTORY")) + (display (G_ " + --workers=N use N workers to bake items")) + (display (G_ " --ttl=TTL announce narinfos can be cached for TTL seconds")) - (display (_ " + (display (G_ " --nar-path=PATH use PATH as the prefix for nar URLs")) - (display (_ " + (display (G_ " --public-key=FILE use FILE as the public key for signatures")) - (display (_ " + (display (G_ " --private-key=FILE use FILE as the private key for signatures")) - (display (_ " + (display (G_ " -r, --repl[=PORT] spawn REPL server on PORT")) (newline) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -93,7 +103,7 @@ Publish ~a over HTTP.\n") %store-directory) (lambda () (getaddrinfo host)) (lambda (key error) - (leave (_ "lookup of host '~a' failed: ~a~%") + (leave (G_ "lookup of host '~a' failed: ~a~%") host (gai-strerror error))))) ;; Nar compression parameters. @@ -110,6 +120,13 @@ Publish ~a over HTTP.\n") %store-directory) ;; Since we compress on the fly, default to fast compression. (compression 'gzip 3)) +(define (actual-compression item requested) + "Return the actual compression used for ITEM, which may be %NO-COMPRESSION +if ITEM is already compressed." + (if (compressed-file? item) + %no-compression + requested)) + (define %options (list (option '(#\h "help") #f #f (lambda _ @@ -131,7 +148,7 @@ Publish ~a over HTTP.\n") %store-directory) (alist-cons 'address (addrinfo:addr info) result)) (() - (leave (_ "lookup of host '~a' returned nothing") + (leave (G_ "lookup of host '~a' returned nothing") name))))) (option '(#\C "compression") #f #t (lambda (opt name arg result) @@ -144,14 +161,21 @@ Publish ~a over HTTP.\n") %store-directory) (compression 'gzip level) result) (begin - (warning (_ "zlib support is missing; \ + (warning (G_ "zlib support is missing; \ compression disabled~%")) result)))))) + (option '(#\c "cache") #t #f + (lambda (opt name arg result) + (alist-cons 'cache arg result))) + (option '("workers") #t #f + (lambda (opt name arg result) + (alist-cons 'workers (string->number* arg) + result))) (option '("ttl") #t #f (lambda (opt name arg result) (let ((duration (string->duration arg))) (unless duration - (leave (_ "~a: invalid duration~%") arg)) + (leave (G_ "~a: invalid duration~%") arg)) (alist-cons 'narinfo-ttl (time-second duration) result)))) (option '("nar-path") #t #f @@ -183,6 +207,9 @@ compression disabled~%")) %default-gzip-compression %no-compression)) + ;; Default number of workers when caching is enabled. + (workers . ,(current-processor-count)) + (address . ,(make-socket-address AF_INET INADDR_ANY 0)) (repl . #f))) @@ -213,14 +240,14 @@ compression disabled~%")) (define* (narinfo-string store store-path key #:key (compression %no-compression) - (nar-path "nar")) + (nar-path "nar") file-size) "Generate a narinfo key/value string for STORE-PATH; an exception is raised if STORE-PATH is invalid. Produce a URL that corresponds to COMPRESSION. The -narinfo is signed with KEY. NAR-PATH specifies the prefix for nar URLs." +narinfo is signed with KEY. NAR-PATH specifies the prefix for nar URLs. +Optionally, FILE-SIZE can specify the size in bytes of the compressed NAR; it +informs the client of how much needs to be downloaded." (let* ((path-info (query-path-info store store-path)) - (compression (if (compressed-file? store-path) - %no-compression - compression)) + (compression (actual-compression store-path compression)) (url (encode-and-join-uri-path `(,@(split-and-decode-uri-path nar-path) ,@(match compression @@ -232,6 +259,8 @@ narinfo is signed with KEY. NAR-PATH specifies the prefix for nar URLs." (hash (bytevector->nix-base32-string (path-info-hash path-info))) (size (path-info-nar-size path-info)) + (file-size (or file-size + (and (eq? compression %no-compression) size))) (references (string-join (map basename (path-info-references path-info)) " ")) @@ -243,10 +272,13 @@ URL: ~a Compression: ~a NarHash: sha256:~a NarSize: ~d -References: ~a~%" +References: ~a~%~a" store-path url (compression-type compression) - hash size references)) + hash size references + (if file-size + (format #f "FileSize: ~a~%" file-size) + ""))) ;; Do not render a "Deriver" or "System" line if we are rendering ;; info for a derivation. (info (if (not deriver) @@ -268,10 +300,15 @@ References: ~a~%" (canonical-sexp->string (signed-string info))))) (format #f "~aSignature: 1;~a;~a~%" info (gethostname) signature))) -(define (not-found request) +(define* (not-found request + #:key (phrase "Resource not found") + ttl) "Render 404 response for REQUEST." - (values (build-response #:code 404) - (string-append "Resource not found: " + (values (build-response #:code 404 + #:headers (if ttl + `((cache-control (max-age . ,ttl))) + '())) + (string-append phrase ": " (uri-path (request-uri request))))) (define (render-nix-cache-info) @@ -303,6 +340,151 @@ appropriate duration. NAR-PATH specifies the prefix for nar URLs." #:compression compression) <>))))) +(define* (nar-cache-file directory item + #:key (compression %no-compression)) + (string-append directory "/" + (symbol->string (compression-type compression)) + "/" (basename item) ".nar")) + +(define* (narinfo-cache-file directory item + #:key (compression %no-compression)) + (string-append directory "/" + (symbol->string (compression-type compression)) + "/" (basename item) + ".narinfo")) + +(define run-single-baker + (let ((baking (make-weak-value-hash-table)) + (mutex (make-mutex))) + (lambda (item thunk) + "Run THUNK, which is supposed to bake ITEM, but make sure only one +thread is baking ITEM at a given time." + (define selected? + (with-mutex mutex + (and (not (hash-ref baking item)) + (begin + (hash-set! baking item (current-thread)) + #t)))) + + (when selected? + (dynamic-wind + (const #t) + thunk + (lambda () + (with-mutex mutex + (hash-remove! baking item)))))))) + +(define-syntax-rule (single-baker item exp ...) + "Bake ITEM by evaluating EXP, but make sure there's only one baker for ITEM +at a time." + (run-single-baker item (lambda () exp ...))) + + +(define (narinfo-files cache) + "Return the list of .narinfo files under CACHE." + (if (file-is-directory? cache) + (find-files cache + (lambda (file stat) + (string-suffix? ".narinfo" file))) + '())) + +(define* (render-narinfo/cached store request hash + #:key ttl (compression %no-compression) + (nar-path "nar") + cache pool) + "Respond to the narinfo request for REQUEST. If the narinfo is available in +CACHE, then send it; otherwise, return 404 and \"bake\" that nar and narinfo +requested using POOL." + (define (delete-entry narinfo) + ;; Delete NARINFO and the corresponding nar from CACHE. + (let ((nar (string-append (string-drop-right narinfo + (string-length ".narinfo")) + ".nar"))) + (delete-file* narinfo) + (delete-file* nar))) + + (let* ((item (hash-part->path store hash)) + (compression (actual-compression item compression)) + (cached (and (not (string-null? item)) + (narinfo-cache-file cache item + #:compression compression)))) + (cond ((string-null? item) + (not-found request)) + ((file-exists? cached) + ;; Narinfo is in cache, send it. + (values `((content-type . (application/x-nix-narinfo)) + ,@(if ttl + `((cache-control (max-age . ,ttl))) + '())) + (lambda (port) + (display (call-with-input-file cached + read-string) + port)))) + ((valid-path? store item) + ;; Nothing in cache: bake the narinfo and nar in the background and + ;; return 404. + (eventually pool + (single-baker item + ;; (format #t "baking ~s~%" item) + (bake-narinfo+nar cache item + #:ttl ttl + #:compression compression + #:nar-path nar-path)) + + (when ttl + (single-baker 'cache-cleanup + (maybe-remove-expired-cache-entries cache + narinfo-files + #:entry-expiration + (file-expiration-time ttl) + #:delete-entry delete-entry + #:cleanup-period ttl)))) + (not-found request + #:phrase "We're baking it" + #:ttl 300)) ;should be available within 5m + (else + (not-found request))))) + +(define* (bake-narinfo+nar cache item + #:key ttl (compression %no-compression) + (nar-path "/nar")) + "Write the narinfo and nar for ITEM to CACHE." + (let* ((compression (actual-compression item compression)) + (nar (nar-cache-file cache item + #:compression compression)) + (narinfo (narinfo-cache-file cache item + #:compression compression))) + + (mkdir-p (dirname nar)) + (match (compression-type compression) + ('gzip + ;; Note: the file port gets closed along with the gzip port. + (call-with-gzip-output-port (open-output-file (string-append nar ".tmp")) + (lambda (port) + (write-file item port)) + #:level (compression-level compression) + #:buffer-size (* 128 1024)) + (rename-file (string-append nar ".tmp") nar)) + ('none + ;; When compression is disabled, we retrieve files directly from the + ;; store; no need to cache them. + #t)) + + (mkdir-p (dirname narinfo)) + (with-atomic-file-output narinfo + (lambda (port) + ;; Open a new connection to the store. We cannot reuse the main + ;; thread's connection to the store since we would end up sending + ;; stuff concurrently on the same channel. + (with-store store + (display (narinfo-string store item + (%private-key) + #:nar-path nar-path + #:compression compression + #:file-size (and=> (stat nar #f) + stat:size)) + port)))))) + ;; XXX: Declare the 'Guix-Compression' HTTP header, which is in fact for ;; internal consumption: it allows us to pass the compression info to ;; 'http-write', as part of the workaround to <http://bugs.gnu.org/21093>. @@ -334,6 +516,21 @@ appropriate duration. NAR-PATH specifies the prefix for nar URLs." store-path) (not-found request)))) +(define* (render-nar/cached store cache request store-item + #:key (compression %no-compression)) + "Respond to REQUEST with a nar for STORE-ITEM. If the nar is in CACHE, +return it; otherwise, return 404." + (let ((cached (nar-cache-file cache store-item + #:compression compression))) + (if (file-exists? cached) + (values `((content-type . (application/octet-stream + (charset . "ISO-8859-1")))) + ;; XXX: We're not returning the actual contents, deferring + ;; instead to 'http-write'. This is a hack to work around + ;; <http://bugs.gnu.org/21093>. + cached) + (not-found request)))) + (define (render-content-addressed-file store request name algo hash) "Return the content of the result of the fixed-output derivation NAME that @@ -353,6 +550,22 @@ has the given HASH of type ALGO." (not-found request))) (not-found request))) +(define (render-home-page request) + "Render the home page." + (values `((content-type . (text/html (charset . "UTF-8")))) + (call-with-output-string + (lambda (port) + (sxml->xml '(html + (head (title "GNU Guix Substitute Server")) + (body + (h1 "GNU Guix Substitute Server") + (p "Hi, " + (a (@ (href + "https://gnu.org/s/guix/manual/html_node/Invoking-guix-publish.html")) + (tt "guix publish")) + " speaking. Welcome!"))) + port))))) + (define extract-narinfo-hash (let ((regexp (make-regexp "^([a-df-np-sv-z0-9]{32}).narinfo$"))) (lambda (str) @@ -464,7 +677,9 @@ blocking." size) client)) (output (response-port response))) - (dump-port input output) + (if (file-port? output) + (sendfile output input size) + (dump-port input output)) (close-port output) (values))))) (lambda args @@ -488,6 +703,7 @@ blocking." (define* (make-request-handler store #:key + cache pool narinfo-ttl (nar-path "nar") (compression %no-compression)) @@ -504,14 +720,24 @@ blocking." ;; /nix-cache-info (("nix-cache-info") (render-nix-cache-info)) + ;; / + ((or () ("index.html")) + (render-home-page request)) ;; /<hash>.narinfo (((= extract-narinfo-hash (? string? hash))) ;; TODO: Register roots for HASH that will somehow remain for ;; NARINFO-TTL. - (render-narinfo store request hash - #:ttl narinfo-ttl - #:nar-path nar-path - #:compression compression)) + (if cache + (render-narinfo/cached store request hash + #:cache cache + #:pool pool + #:ttl narinfo-ttl + #:nar-path nar-path + #:compression compression) + (render-narinfo store request hash + #:ttl narinfo-ttl + #:nar-path nar-path + #:compression compression))) ;; /nar/file/NAME/sha256/HASH (("file" name "sha256" hash) (guard (c ((invalid-base32-character? c) @@ -527,13 +753,16 @@ blocking." ;; /nar/gzip/<store-item> ((components ... "gzip" store-item) (if (and (nar-path? components) (zlib-available?)) - (render-nar store request store-item - #:compression - (match compression - (($ <compression> 'gzip) - compression) - (_ - %default-gzip-compression))) + (let ((compression (match compression + (($ <compression> 'gzip) + compression) + (_ + %default-gzip-compression)))) + (if cache + (render-nar/cached store cache request store-item + #:compression compression) + (render-nar store request store-item + #:compression compression))) (not-found request))) ;; /nar/<store-item> @@ -548,8 +777,11 @@ blocking." (define* (run-publish-server socket store #:key (compression %no-compression) - (nar-path "nar") narinfo-ttl) + (nar-path "nar") narinfo-ttl + cache pool) (run-server (make-request-handler store + #:cache cache + #:pool pool #:nar-path nar-path #:narinfo-ttl narinfo-ttl #:compression compression) @@ -572,7 +804,7 @@ blocking." (setgid (passwd:gid user)) (setuid (passwd:uid user)))) (lambda (key proc message args . rest) - (leave (_ "user '~a' not found: ~a~%") + (leave (G_ "user '~a' not found: ~a~%") user (apply format #f message args))))) @@ -584,9 +816,9 @@ blocking." (with-error-handling (let* ((opts (args-fold* args %options (lambda (opt name arg result) - (leave (_ "~A: unrecognized option~%") name)) + (leave (G_ "~A: unrecognized option~%") name)) (lambda (arg result) - (leave (_ "~A: extraneous argument~%") arg)) + (leave (G_ "~A: extraneous argument~%") arg)) %default-options)) (user (assoc-ref opts 'user)) (port (assoc-ref opts 'port)) @@ -599,6 +831,8 @@ blocking." (socket (open-server-socket address)) (nar-path (assoc-ref opts 'nar-path)) (repl-port (assoc-ref opts 'repl)) + (cache (assoc-ref opts 'cache)) + (workers (assoc-ref opts 'workers)) ;; Read the key right away so that (1) we fail early on if we can't ;; access them, and (2) we can then drop privileges. @@ -611,12 +845,12 @@ blocking." (gather-user-privileges user)) (when (zero? (getuid)) - (warning (_ "server running as root; \ + (warning (G_ "server running as root; \ consider using the '--user' option!~%"))) (parameterize ((%public-key public-key) (%private-key private-key)) - (format #t (_ "publishing ~a on ~a, port ~d~%") + (format #t (G_ "publishing ~a on ~a, port ~d~%") %store-directory (inet-ntop (sockaddr:fam address) (sockaddr:addr address)) (sockaddr:port address)) @@ -624,6 +858,12 @@ consider using the '--user' option!~%"))) (repl:spawn-server (repl:make-tcp-server-socket #:port repl-port))) (with-store store (run-publish-server socket store + #:cache cache + #:pool (and cache (make-pool workers)) #:nar-path nar-path #:compression compression #:narinfo-ttl ttl)))))) + +;;; Local Variables: +;;; eval: (put 'single-baker 'scheme-indent-function 1) +;;; End: diff --git a/guix/scripts/pull.scm b/guix/scripts/pull.scm index 8e31ad620c..58b87d4df4 100644 --- a/guix/scripts/pull.scm +++ b/guix/scripts/pull.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2013, 2014, 2015, 2017 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2017 Marius Bakke <mbakke@fastmail.com> ;;; ;;; This file is part of GNU Guix. @@ -28,6 +28,7 @@ #:use-module (guix download) #:use-module (guix gexp) #:use-module (guix monads) + #:use-module (guix scripts build) #:use-module ((guix build utils) #:select (with-directory-excursion delete-file-recursively)) #:use-module ((guix build download) @@ -72,45 +73,56 @@ (define %default-options ;; Alist of default option values. - `((tarball-url . ,%snapshot-url))) + `((tarball-url . ,%snapshot-url) + (system . ,(%current-system)) + (substitutes? . #t) + (graft? . #t) + (max-silent-time . 3600) + (verbosity . 0))) (define (show-help) - (display (_ "Usage: guix pull [OPTION]... + (display (G_ "Usage: guix pull [OPTION]... Download and deploy the latest version of Guix.\n")) - (display (_ " + (display (G_ " --verbose produce verbose output")) - (display (_ " + (display (G_ " --url=URL download the Guix tarball from URL")) - (display (_ " + (display (G_ " --bootstrap use the bootstrap Guile to build the new Guix")) (newline) - (display (_ " + (show-build-options-help) + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) (define %options ;; Specifications of the command-line options. - (list (option '("verbose") #f #f - (lambda (opt name arg result) - (alist-cons 'verbose? #t result))) - (option '("url") #t #f - (lambda (opt name arg result) - (alist-cons 'tarball-url arg - (alist-delete 'tarball-url result)))) - (option '("bootstrap") #f #f - (lambda (opt name arg result) - (alist-cons 'bootstrap? #t result))) + (cons* (option '("verbose") #f #f + (lambda (opt name arg result) + (alist-cons 'verbose? #t result))) + (option '("url") #t #f + (lambda (opt name arg result) + (alist-cons 'tarball-url arg + (alist-delete 'tarball-url result)))) + (option '(#\n "dry-run") #f #f + (lambda (opt name arg result) + (alist-cons 'dry-run? #t (alist-cons 'graft? #f result)))) + (option '("bootstrap") #f #f + (lambda (opt name arg result) + (alist-cons 'bootstrap? #t result))) - (option '(#\h "help") #f #f - (lambda args - (show-help) - (exit 0))) - (option '(#\V "version") #f #f - (lambda args - (show-version-and-exit "guix pull"))))) + (option '(#\h "help") #f #f + (lambda args + (show-help) + (exit 0))) + (option '(#\V "version") #f #f + (lambda args + (show-version-and-exit "guix pull"))) + + %standard-build-options)) (define what-to-build (store-lift show-what-to-build)) @@ -153,7 +165,7 @@ store file name." (mbegin %store-monad (what-to-build (list tar gzip)) (built-derivations (list tar gzip)) - (format #t (_ "unpacking '~a'...~%") tarball) + (format #t (G_ "unpacking '~a'...~%") tarball) (let ((source (temporary-directory))) (with-directory-excursion source @@ -205,26 +217,18 @@ contained therein." (if (and (file-exists? latest) (string=? (readlink latest) source-dir)) (begin - (display (_ "Guix already up to date\n")) + (display (G_ "Guix already up to date\n")) (return #t)) (begin (switch-symlinks latest source-dir) (format #t - (_ "updated ~a successfully deployed under `~a'~%") + (G_ "updated ~a successfully deployed under `~a'~%") %guix-package-name latest) (return #t)))) - (leave (_ "failed to update Guix, check the build log~%"))))) + (leave (G_ "failed to update Guix, check the build log~%"))))) + (define (guix-pull . args) - (define (parse-options) - ;; Return the alist of option values. - (args-fold* args %options - (lambda (opt name arg result) - (leave (_ "~A: unrecognized option~%") name)) - (lambda (arg result) - (leave (_ "~A: unexpected argument~%") arg)) - %default-options)) - (define (use-le-certs? url) (string-prefix? "https://git.savannah.gnu.org/" url)) @@ -232,28 +236,31 @@ contained therein." (download-to-store store url "guix-latest.tar.gz")) (with-error-handling - (let* ((opts (parse-options)) - (store (open-connection)) + (let* ((opts (parse-command-line args %options + (list %default-options))) (url (assoc-ref opts 'tarball-url))) - (let ((tarball - (if (use-le-certs? url) - (let* ((drv (package-derivation store le-certs)) - (certs (string-append (derivation->output-path drv) - "/etc/ssl/certs"))) - (build-derivations store (list drv)) - (parameterize ((%x509-certificate-directory certs)) - (fetch-tarball store url))) - (fetch-tarball store url)))) - (unless tarball - (leave (_ "failed to download up-to-date source, exiting\n"))) - (parameterize ((%guile-for-build - (package-derivation store - (if (assoc-ref opts 'bootstrap?) - %bootstrap-guile - (canonical-package guile-2.0))))) - (run-with-store store - (build-and-install tarball (config-directory) - #:verbose? (assoc-ref opts 'verbose?)))))))) + (unless (assoc-ref opts 'dry-run?) ;XXX: not very useful + (with-store store + (set-build-options-from-command-line store opts) + (let ((tarball + (if (use-le-certs? url) + (let* ((drv (package-derivation store le-certs)) + (certs (string-append (derivation->output-path drv) + "/etc/ssl/certs"))) + (build-derivations store (list drv)) + (parameterize ((%x509-certificate-directory certs)) + (fetch-tarball store url))) + (fetch-tarball store url)))) + (unless tarball + (leave (G_ "failed to download up-to-date source, exiting\n"))) + (parameterize ((%guile-for-build + (package-derivation store + (if (assoc-ref opts 'bootstrap?) + %bootstrap-guile + (canonical-package guile-2.0))))) + (run-with-store store + (build-and-install tarball (config-directory) + #:verbose? (assoc-ref opts 'verbose?)))))))))) ;; Local Variables: ;; eval: (put 'with-PATH 'scheme-indent-function 1) diff --git a/guix/scripts/refresh.scm b/guix/scripts/refresh.scm index 4d3c695aaf..f85d6e5101 100644 --- a/guix/scripts/refresh.scm +++ b/guix/scripts/refresh.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2013, 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org> ;;; Copyright © 2014 Eric Bavier <bavier@member.fsf.org> ;;; Copyright © 2015 Alex Kost <alezost@gmail.com> @@ -28,18 +28,10 @@ #:use-module (guix utils) #:use-module (guix packages) #:use-module (guix upstream) + #:use-module (guix discovery) #:use-module (guix graph) #:use-module (guix scripts graph) #:use-module (guix monads) - #:use-module ((guix gnu-maintenance) - #:select (%gnu-updater - %gnome-updater - %kde-updater - %xorg-updater - %kernel.org-updater)) - #:use-module (guix import elpa) - #:use-module (guix import cran) - #:use-module (guix import hackage) #:use-module (guix gnupg) #:use-module (gnu packages) #:use-module ((gnu packages commencement) #:select (%final-inputs)) @@ -76,7 +68,7 @@ (alist-cons 'select (string->symbol arg) result)) (x - (leave (_ "~a: invalid selection; expected `core' or `non-core'~%") + (leave (G_ "~a: invalid selection; expected `core' or `non-core'~%") arg))))) (option '(#\t "type") #t #f (lambda (opt name arg result) @@ -107,7 +99,7 @@ (alist-cons 'key-download (string->symbol arg) result)) (x - (leave (_ "unsupported policy: ~a~%") + (leave (G_ "unsupported policy: ~a~%") arg))))) (option '(#\h "help") #f #f @@ -119,41 +111,41 @@ (show-version-and-exit "guix refresh"))))) (define (show-help) - (display (_ "Usage: guix refresh [OPTION]... [PACKAGE]... + (display (G_ "Usage: guix refresh [OPTION]... [PACKAGE]... Update package definitions to match the latest upstream version. When PACKAGE... is given, update only the specified packages. Otherwise update all the packages of the distribution, or the subset thereof specified with `--select'.\n")) - (display (_ " + (display (G_ " -e, --expression=EXPR consider the package EXPR evaluates to")) - (display (_ " + (display (G_ " -u, --update update source files in place")) - (display (_ " + (display (G_ " -s, --select=SUBSET select all the packages in SUBSET, one of `core' or `non-core'")) - (display (_ " + (display (G_ " -t, --type=UPDATER,... restrict to updates from the specified updaters (e.g., 'gnu')")) - (display (_ " + (display (G_ " -L, --list-updaters list available updaters and exit")) - (display (_ " + (display (G_ " -l, --list-dependent list top-level dependent packages that would need to be rebuilt as a result of upgrading PACKAGE...")) (newline) - (display (_ " + (display (G_ " --key-server=HOST use HOST as the OpenPGP key server")) - (display (_ " + (display (G_ " --gpg=COMMAND use COMMAND as the GnuPG 2.x command")) - (display (_ " + (display (G_ " --key-download=POLICY handle missing OpenPGP keys according to POLICY: 'always', 'never', and 'interactive', which is also used when 'key-download' is not specified")) (newline) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -163,66 +155,32 @@ specified with `--select'.\n")) ;;; Updates. ;;; -(define-syntax maybe-updater - ;; Helper macro for 'list-updaters'. - (syntax-rules (=>) - ((_ ((module => updater) rest ...) result) - (maybe-updater (rest ...) - (let ((iface (false-if-exception - (resolve-interface 'module))) - (tail result)) - (if iface - (cons (module-ref iface 'updater) tail) - tail)))) - ((_ (updater rest ...) result) - (maybe-updater (rest ...) - (cons updater result))) - ((_ () result) - (reverse result)))) - -(define-syntax-rule (list-updaters updaters ...) - "Expand to '(list UPDATERS ...)' but only the subset of UPDATERS that are -either unconditional, or have their requirement met. - -A conditional updater has this form: - - ((SOME MODULE) => UPDATER) - -meaning that UPDATER is added to the list if and only if (SOME MODULE) could -be resolved at run time. - -This is a way to discard at macro expansion time updaters that depend on -unavailable optional dependencies such as Guile-JSON." - (maybe-updater (updaters ...) '())) +(define (importer-modules) + "Return the list of importer modules." + (cons (resolve-interface '(guix gnu-maintenance)) + (all-modules (map (lambda (entry) + `(,entry . "guix/import")) + %load-path)))) (define %updaters - ;; List of "updaters" used by default. They are consulted in this order. - (list-updaters %gnu-updater - %gnome-updater - %kde-updater - %xorg-updater - %kernel.org-updater - %elpa-updater - %cran-updater - %bioconductor-updater - ((guix import stackage) => %stackage-updater) - %hackage-updater - ((guix import cpan) => %cpan-updater) - ((guix import pypi) => %pypi-updater) - ((guix import gem) => %gem-updater) - ((guix import github) => %github-updater) - ((guix import crate) => %crate-updater))) + ;; The list of publically-known updaters. + (delay (fold-module-public-variables (lambda (obj result) + (if (upstream-updater? obj) + (cons obj result) + result)) + '() + (importer-modules)))) (define (lookup-updater-by-name name) "Return the updater called NAME." (or (find (lambda (updater) (eq? name (upstream-updater-name updater))) - %updaters) - (leave (_ "~a: no such updater~%") name))) + (force %updaters)) + (leave (G_ "~a: no such updater~%") name))) (define (list-updaters-and-exit) "Display available updaters and exit." - (format #t (_ "Available updaters:~%")) + (format #t (G_ "Available updaters:~%")) (newline) (let* ((packages (fold-packages cons '())) @@ -234,22 +192,22 @@ unavailable optional dependencies such as Guile-JSON." ;; TRANSLATORS: The parenthetical expression here is rendered ;; like "(42% coverage)" and denotes the fraction of packages ;; covered by the given updater. - (format #t (_ " - ~a: ~a (~2,1f% coverage)~%") + (format #t (G_ " - ~a: ~a (~2,1f% coverage)~%") (upstream-updater-name updater) - (_ (upstream-updater-description updater)) + (G_ (upstream-updater-description updater)) (* 100. (/ matches total))) (+ covered matches))) 0 - %updaters)) + (force %updaters))) (newline) - (format #t (_ "~2,1f% of the packages are covered by these updaters.~%") + (format #t (G_ "~2,1f% of the packages are covered by these updaters.~%") (* 100. (/ covered total)))) (exit 0)) (define (warn-no-updater package) (format (current-error-port) - (_ "~a: warning: no updater for ~a~%") + (G_ "~a: warning: no updater for ~a~%") (location->string (package-location package)) (package-name package))) @@ -270,14 +228,14 @@ warn about packages that have no matching updater." (if (and=> tarball file-exists?) (begin (format (current-error-port) - (_ "~a: ~a: updating from version ~a to version ~a...~%") + (G_ "~a: ~a: updating from version ~a to version ~a...~%") (location->string loc) (package-name package) (package-version package) version) (let ((hash (call-with-input-file tarball port-sha256))) (update-package-source package version hash))) - (warning (_ "~a: version ~a could not be \ + (warning (G_ "~a: version ~a could not be \ downloaded and authenticated; not updating~%") (package-name package) version)))) (when warn? @@ -293,7 +251,7 @@ WARN? is true and no updater exists for PACKAGE, print a warning." (let ((loc (or (package-field-location package 'version) (package-location package)))) (format (current-error-port) - (_ "~a: ~a would be upgraded from ~a to ~a~%") + (G_ "~a: ~a would be upgraded from ~a to ~a~%") (location->string loc) (package-name package) (package-version package) (upstream-source-version source))))) @@ -315,6 +273,10 @@ WARN? is true and no updater exists for PACKAGE, print a warning." "List all the things that would need to be rebuilt if PACKAGES are changed." ;; Using %BAG-NODE-TYPE is more accurate than using %PACKAGE-NODE-TYPE ;; because it includes implicit dependencies. + (define (full-name package) + (string-append (package-name package) "@" + (package-version package))) + (mlet %store-monad ((edges (node-back-edges %bag-node-type (all-packages)))) (let* ((dependents (node-transitive-edges packages edges)) @@ -327,12 +289,12 @@ WARN? is true and no updater exists for PACKAGE, print a warning." (N_ "No dependents other than itself: ~{~a~}~%" "No dependents other than themselves: ~{~a~^ ~}~%" (length packages)) - (map package-full-name packages))) + (map full-name packages))) ((x) (format (current-output-port) - (_ "A single dependent package: ~a~%") - (package-full-name x))) + (G_ "A single dependent package: ~a~%") + (full-name x))) (lst (format (current-output-port) (N_ "Building the following package would ensure ~d \ @@ -341,7 +303,7 @@ dependent packages are rebuilt: ~*~{~a~^ ~}~%" dependent packages are rebuilt: ~{~a~^ ~}~%" (length covering)) (length covering) (length dependents) - (map package-full-name covering)))) + (map full-name covering)))) (return #t)))) @@ -354,7 +316,7 @@ dependent packages are rebuilt: ~{~a~^ ~}~%" ;; Return the alist of option values. (args-fold* args %options (lambda (opt name arg result) - (leave (_ "~A: unrecognized option~%") name)) + (leave (G_ "~A: unrecognized option~%") name)) (lambda (arg result) (alist-cons 'argument arg result)) %default-options)) @@ -368,7 +330,7 @@ dependent packages are rebuilt: ~{~a~^ ~}~%" opts) (() ;; Use the default updaters. - %updaters) + (force %updaters)) (lists (concatenate lists)))) diff --git a/guix/scripts/size.scm b/guix/scripts/size.scm index ea259f3758..52f7cdd972 100644 --- a/guix/scripts/size.scm +++ b/guix/scripts/size.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2015, 2016 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -74,7 +74,7 @@ if ITEM is not in the store." ;; The nar size is an approximation, but a good one. (return (substitutable-nar-size info))) (() - (leave (_ "no available substitute information for '~a'~%") + (leave (G_ "no available substitute information for '~a'~%") item))))))) (define* (display-profile profile #:optional (port (current-output-port))) @@ -82,7 +82,7 @@ if ITEM is not in the store." (define MiB (expt 2 20)) (format port "~64a ~8a ~a\n" - (_ "store item") (_ "total") (_ "self")) + (G_ "store item") (G_ "total") (G_ "self")) (let ((whole (reduce + 0 (map profile-self-size profile)))) (for-each (match-lambda (($ <profile> name self total) @@ -91,9 +91,10 @@ if ITEM is not in the store." (* 100. (/ self whole 1.))))) (sort profile (match-lambda* - ((($ <profile> _ _ total1) ($ <profile> _ _ total2)) + ((($ <profile> name1 self1 total1) + ($ <profile> name2 self2 total2)) (> total1 total2))))) - (format port (_ "total: ~,1f MiB~%") (/ whole MiB 1.)))) + (format port (G_ "total: ~,1f MiB~%") (/ whole MiB 1.)))) (define display-profile* (lift display-profile %store-monad)) @@ -200,13 +201,14 @@ the name of a PNG file." 0 (sort profiles (match-lambda* - ((($ <profile> _ _ total1) ($ <profile> _ _ total2)) + ((($ <profile> name1 self1 total1) + ($ <profile> name2 self2 total2)) (> total1 total2)))))) ;; TRANSLATORS: This is the title of a graph, meaning that the graph ;; represents a profile of the store (the "store" being the place where ;; packages are stored.) - (make-page-map (_ "store profile") data + (make-page-map (G_ "store profile") data #:write-to-png file)) @@ -215,19 +217,19 @@ the name of a PNG file." ;;; (define (show-help) - (display (_ "Usage: guix size [OPTION]... PACKAGE + (display (G_ "Usage: guix size [OPTION]... PACKAGE Report the size of PACKAGE and its dependencies.\n")) - (display (_ " + (display (G_ " --substitute-urls=URLS fetch substitute from URLS if they are authorized")) - (display (_ " + (display (G_ " -s, --system=SYSTEM consider packages for SYSTEM--e.g., \"i686-linux\"")) - (display (_ " + (display (G_ " -m, --map-file=FILE write to FILE a graphical map of disk usage")) (newline) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -276,7 +278,7 @@ Report the size of PACKAGE and its dependencies.\n")) (urls (assoc-ref opts 'substitute-urls))) (match files (() - (leave (_ "missing store item argument\n"))) + (leave (G_ "missing store item argument\n"))) ((files ..1) (leave-on-EPIPE ;; Turn off grafts because (1) hydra.gnu.org does not serve grafted diff --git a/guix/scripts/substitute.scm b/guix/scripts/substitute.scm index d3bccf4ddb..73d4f6e2eb 100755 --- a/guix/scripts/substitute.scm +++ b/guix/scripts/substitute.scm @@ -28,6 +28,7 @@ #:use-module (guix hash) #:use-module (guix base32) #:use-module (guix base64) + #:use-module (guix cache) #:use-module (guix pk-crypto) #:use-module (guix pki) #:use-module ((guix build utils) #:select (mkdir-p dump-port)) @@ -110,7 +111,7 @@ (and (and=> (getenv "GUIX_ALLOW_UNAUTHENTICATED_SUBSTITUTES") (cut string-ci=? <> "yes")) (begin - (warning (_ "authentication and authorization of substitutes \ + (warning (G_ "authentication and authorization of substitutes \ disabled!~%")) #t))) @@ -185,7 +186,7 @@ provide." (values port (stat:size (stat port))))) ((http https) (guard (c ((http-get-error? c) - (leave (_ "download from '~a' failed: ~a, ~s~%") + (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)))) @@ -198,9 +199,9 @@ provide." %fetch-timeout 0) (begin - (warning (_ "while fetching ~a: server is somewhat slow~%") + (warning (G_ "while fetching ~a: server is somewhat slow~%") (uri->string uri)) - (warning (_ "try `--no-substitutes' if the problem persists~%")) + (warning (G_ "try `--no-substitutes' if the problem persists~%")) ;; Before Guile v2.0.9-39-gfe51c7b, EINTR was reported to the user, ;; and thus PORT had to be closed and re-opened. This is not the @@ -218,7 +219,7 @@ provide." (http-fetch uri #:text? #f #:port port #:verify-certificate? #f)))))) (else - (leave (_ "unsupported substitute URI scheme: ~a~%") + (leave (G_ "unsupported substitute URI scheme: ~a~%") (uri->string uri))))) (define-record-type <cache-info> @@ -253,12 +254,12 @@ failure, return #f and #f." #:verify-certificate? #f #:timeout %fetch-timeout))) (guard (c ((http-get-error? c) - (warning (_ "while fetching '~a': ~a (~s)~%") + (warning (G_ "while fetching '~a': ~a (~s)~%") (uri->string (http-get-error-uri c)) (http-get-error-code c) (http-get-error-reason c)) (close-connection port) - (warning (_ "ignoring substitute server at '~s'~%") url) + (warning (G_ "ignoring substitute server at '~s'~%") url) (values #f #f))) (values (read-cache-info (http-fetch uri #:verify-certificate? #f @@ -308,11 +309,11 @@ Otherwise return #f." ((version host-name sig) (let ((maybe-number (string->number version))) (cond ((not (number? maybe-number)) - (leave (_ "signature version must be a number: ~s~%") + (leave (G_ "signature version must be a number: ~s~%") version)) ;; Currently, there are no other versions. ((not (= 1 maybe-number)) - (leave (_ "unsupported signature version: ~a~%") + (leave (G_ "unsupported signature version: ~a~%") maybe-number)) (else (let ((signature (utf8->string (base64-decode sig)))) @@ -320,11 +321,11 @@ Otherwise return #f." (lambda () (string->canonical-sexp signature)) (lambda (key proc err) - (leave (_ "signature is not a valid \ + (leave (G_ "signature is not a valid \ s-expression: ~s~%") signature)))))))) (x - (leave (_ "invalid format of the signature field: ~a~%") x)))) + (leave (G_ "invalid format of the signature field: ~a~%") x)))) (define (narinfo-maker str cache-url) "Return a narinfo constructor for narinfos originating from CACHE-URL. STR @@ -359,13 +360,13 @@ NARINFO, doesn't match HASH, a bytevector containing the hash of NARINFO." (signature-case (signature hash acl) (valid-signature #t) (invalid-signature - (leave (_ "invalid signature for '~a'~%") uri)) + (leave (G_ "invalid signature for '~a'~%") uri)) (hash-mismatch - (leave (_ "hash mismatch for '~a'~%") uri)) + (leave (G_ "hash mismatch for '~a'~%") uri)) (unauthorized-key - (leave (_ "'~a' is signed with an unauthorized key~%") uri)) + (leave (G_ "'~a' is signed with an unauthorized key~%") uri)) (corrupt-signature - (leave (_ "signature on '~a' is corrupt~%") uri))))) + (leave (G_ "signature on '~a' is corrupt~%") uri))))) (define* (read-narinfo port #:optional url #:key size) @@ -403,17 +404,17 @@ or is signed by an unauthorized key." (if (not hash) (if %allow-unauthenticated-substitutes? narinfo - (leave (_ "substitute at '~a' lacks a signature~%") + (leave (G_ "substitute at '~a' lacks a signature~%") (uri->string (narinfo-uri narinfo)))) (let ((signature (narinfo-signature narinfo))) (unless %allow-unauthenticated-substitutes? (assert-valid-signature narinfo signature hash acl) (when verbose? (format (current-error-port) - (_ "Found valid signature for ~a~%") + (G_ "Found valid signature for ~a~%") (narinfo-path narinfo)) (format (current-error-port) - (_ "From ~a~%") + (G_ "From ~a~%") (uri->string (narinfo-uri narinfo))))) narinfo)))) @@ -440,12 +441,6 @@ or is signed by an unauthorized key." the cache STR originates form." (call-with-input-string str (cut read-narinfo <> cache-uri))) -(define (obsolete? date now ttl) - "Return #t if DATE is obsolete compared to NOW + TTL seconds." - (time>? (subtract-duration now (make-time time-duration 0 ttl)) - (make-time time-monotonic 0 date))) - - (define (narinfo-cache-file cache-url path) "Return the name of the local file that contains an entry for PATH. The entry is stored in a sub-directory specific to CACHE-URL." @@ -453,7 +448,7 @@ entry is stored in a sub-directory specific to CACHE-URL." ;; "/gnu/store/foo". Gracefully handle that. (match (store-path-hash-part path) (#f - (leave (_ "'~a' does not name a store item~%") path)) + (leave (G_ "'~a' does not name a store item~%") path)) ((? string? hash-part) (string-append %narinfo-cache-directory "/" (bytevector->base32-string (sha256 (string->utf8 cache-url))) @@ -477,9 +472,9 @@ for PATH." (match (read p) (('narinfo ('version 2) ('cache-uri cache-uri) - ('date date) ('ttl _) ('value #f)) + ('date date) ('ttl ttl) ('value #f)) ;; A cached negative lookup. - (if (obsolete? date now %narinfo-negative-ttl) + (if (obsolete? date now ttl) (values #f #f) (values #t #f))) (('narinfo ('version 2) @@ -601,7 +596,7 @@ if file doesn't exist, and the narinfo otherwise." (display #\cr (current-error-port)) (force-output (current-error-port)) (format (current-error-port) - (_ "updating list of substitutes from '~a'... ~5,1f%") + (G_ "updating list of substitutes from '~a'... ~5,1f%") url (* 100. (/ done (length paths)))) (set! done (+ 1 done))))) @@ -656,7 +651,7 @@ if file doesn't exist, and the narinfo otherwise." paths))) (filter-map (cut narinfo-from-file <> url) files))) (else - (leave (_ "~s: unsupported server URI scheme~%") + (leave (G_ "~s: unsupported server URI scheme~%") (if uri (uri-scheme uri) url))))) (let-values (((cache-info port) @@ -666,7 +661,7 @@ if file doesn't exist, and the narinfo otherwise." (%store-prefix)) (do-fetch (string->uri url) port) ;reuse PORT (begin - (warning (_ "'~a' uses different store '~a'; ignoring it~%") + (warning (G_ "'~a' uses different store '~a'; ignoring it~%") url (cache-info-store-directory cache-info)) (close-connection port) #f))))) @@ -718,43 +713,28 @@ was found." ((answer) answer) (_ #f))) -(define (remove-expired-cached-narinfos directory) - "Remove expired narinfo entries from DIRECTORY. The sole purpose of this -function is to make sure `%narinfo-cache-directory' doesn't grow -indefinitely." - (define now - (current-time time-monotonic)) +(define (cached-narinfo-expiration-time file) + "Return the expiration time for FILE, which is a cached narinfo." + (catch 'system-error + (lambda () + (call-with-input-file file + (lambda (port) + (match (read port) + (('narinfo ('version 2) ('cache-uri uri) + ('date date) ('ttl ttl) ('value #f)) + (+ date ttl)) + (('narinfo ('version 2) ('cache-uri uri) + ('date date) ('ttl ttl) ('value value)) + (+ date ttl)) + (x + 0))))) + (lambda args + ;; FILE may have been deleted. + 0))) - (define (expired? file) - (catch 'system-error - (lambda () - (call-with-input-file file - (lambda (port) - (match (read port) - (('narinfo ('version 2) ('cache-uri _) - ('date date) ('ttl _) ('value #f)) - (obsolete? date now %narinfo-negative-ttl)) - (('narinfo ('version 2) ('cache-uri _) - ('date date) ('ttl ttl) ('value _)) - (obsolete? date now ttl)) - (_ #t))))) - (lambda args - ;; FILE may have been deleted. - #t))) - - (for-each (lambda (file) - (let ((file (string-append directory "/" file))) - (when (expired? file) - ;; Wrap in `false-if-exception' because FILE might have been - ;; deleted in the meantime (TOCTTOU). - (false-if-exception (delete-file file))))) - (scandir directory - (lambda (file) - (= (string-length file) 32))))) - -(define (narinfo-cache-directories) +(define (narinfo-cache-directories directory) "Return the list of narinfo cache directories (one per cache URL.)" - (map (cut string-append %narinfo-cache-directory "/" <>) + (map (cut string-append directory "/" <>) (scandir %narinfo-cache-directory (lambda (item) (and (not (member item '("." ".."))) @@ -762,25 +742,15 @@ indefinitely." (string-append %narinfo-cache-directory "/" item))))))) -(define (maybe-remove-expired-cached-narinfo) - "Remove expired narinfo entries from the cache if deemed necessary." - (define now - (current-time time-monotonic)) - - (define expiry-file - (string-append %narinfo-cache-directory "/last-expiry-cleanup")) - - (define last-expiry-date - (or (false-if-exception - (call-with-input-file expiry-file read)) - 0)) - - (when (obsolete? last-expiry-date now - %narinfo-expired-cache-entry-removal-delay) - (for-each remove-expired-cached-narinfos - (narinfo-cache-directories)) - (call-with-output-file expiry-file - (cute write (time-second now) <>)))) +(define* (cached-narinfo-files #:optional + (directory %narinfo-cache-directory)) + "Return the list of cached narinfo files under DIRECTORY." + (append-map (lambda (directory) + (map (cut string-append directory "/" <>) + (scandir directory + (lambda (file) + (= (string-length file) 32))))) + (narinfo-cache-directories directory))) (define (progress-report-port report-progress port) "Return a port that calls REPORT-PROGRESS every time something is read from @@ -811,12 +781,12 @@ PORT. REPORT-PROGRESS is a two-argument procedure such as that returned by (lambda () exp ...) (match-lambda* (('getaddrinfo-error error) - (leave (_ "host name lookup error: ~a~%") + (leave (G_ "host name lookup error: ~a~%") (gai-strerror error))) (('gnutls-error error proc . rest) (let ((error->string (module-ref (resolve-interface '(gnutls)) 'error->string))) - (leave (_ "TLS error in procedure '~a': ~a~%") + (leave (G_ "TLS error in procedure '~a': ~a~%") proc (error->string error)))) (args (apply throw args))))))) @@ -827,19 +797,19 @@ PORT. REPORT-PROGRESS is a two-argument procedure such as that returned by ;;; (define (show-help) - (display (_ "Usage: guix substitute [OPTION]... + (display (G_ "Usage: guix substitute [OPTION]... Internal tool to substitute a pre-built binary to a local build.\n")) - (display (_ " + (display (G_ " --query report on the availability of substitutes for the store file names passed on the standard input")) - (display (_ " + (display (G_ " --substitute STORE-FILE DESTINATION download STORE-FILE and store it as a Nar in file DESTINATION")) (newline) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -905,7 +875,7 @@ DESTINATION as a nar file. Verify the substitute against ACL." ;; TRANSLATORS: The second part of this message looks like ;; "(4.1MiB installed)"; it shows the size of the package once ;; installed. - (_ "Downloading ~a~:[~*~; (~a installed)~]...~%") + (G_ "Downloading ~a~:[~*~; (~a installed)~]...~%") (uri->string uri) ;; Use the Nar size as an estimate of the installed size. (narinfo-size narinfo) @@ -962,7 +932,7 @@ DESTINATION as a nar file. Verify the substitute against ACL." (let ((acl (acl->public-keys (current-acl)))) (when (or (null? acl) (singleton? acl)) - (warning (_ "ACL for archive imports seems to be uninitialized, \ + (warning (G_ "ACL for archive imports seems to be uninitialized, \ substitutes may be unavailable\n"))))) (define (daemon-options) @@ -1010,10 +980,19 @@ default value." (and number (max 20 (- number 1)))))) 80)) +(define (validate-uri uri) + (unless (string->uri uri) + (leave (G_ "~a: invalid URI~%") uri))) + (define (guix-substitute . args) "Implement the build daemon's substituter protocol." (mkdir-p %narinfo-cache-directory) - (maybe-remove-expired-cached-narinfo) + (maybe-remove-expired-cache-entries %narinfo-cache-directory + cached-narinfo-files + #:entry-expiration + cached-narinfo-expiration-time + #:cleanup-period + %narinfo-expired-cache-entry-removal-delay) (check-acl-initialized) ;; Starting from commit 22144afa in Nix, we are allowed to bail out directly @@ -1026,6 +1005,9 @@ default value." (newline) (force-output (current-output-port)) + ;; Sanity-check %CACHE-URLS so we can provide a meaningful error message. + (for-each validate-uri %cache-urls) + ;; Attempt to install the client's locale, mostly so that messages are ;; suitably translated. (match (or (find-daemon-option "untrusted-locale") @@ -1058,7 +1040,7 @@ default value." (("--help") (show-help)) (opts - (leave (_ "~a: unrecognized options~%") opts)))))) + (leave (G_ "~a: unrecognized options~%") opts)))))) ;;; Local Variables: ;;; eval: (put 'with-timeout 'scheme-indent-function 1) diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm index 144a7fd377..f71b1d71b8 100644 --- a/guix/scripts/system.scm +++ b/guix/scripts/system.scm @@ -1,7 +1,8 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2016 Alex Kost <alezost@gmail.com> -;;; Copyright © 2016 Chris Marusich <cmmarusich@gmail.com> +;;; Copyright © 2016, 2017 Chris Marusich <cmmarusich@gmail.com> +;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com> ;;; ;;; This file is part of GNU Guix. ;;; @@ -37,10 +38,10 @@ #:use-module (guix build utils) #:use-module (gnu build install) #:use-module (gnu system) + #:use-module (gnu bootloader) #:use-module (gnu system file-systems) #:use-module (gnu system linux-container) #:use-module (gnu system vm) - #:use-module (gnu system grub) #:use-module (gnu services) #:use-module (gnu services shepherd) #:use-module (gnu services herd) @@ -77,6 +78,29 @@ ;;; Installation. ;;; +(define-syntax-rule (save-load-path-excursion body ...) + "Save the current values of '%load-path' and '%load-compiled-path', run +BODY..., and restore them." + (let ((path %load-path) + (cpath %load-compiled-path)) + (dynamic-wind + (const #t) + (lambda () + body ...) + (lambda () + (set! %load-path path) + (set! %load-compiled-path cpath))))) + +(define-syntax-rule (save-environment-excursion body ...) + "Save the current environment variables, run BODY..., and restore them." + (let ((env (environ))) + (dynamic-wind + (const #t) + (lambda () + body ...) + (lambda () + (environ env))))) + (define topologically-sorted* (store-lift topologically-sorted)) @@ -106,7 +130,7 @@ #:prefix target #:state-directory state #:references refs) - (leave (_ "failed to register '~a' under '~a'~%") + (leave (G_ "failed to register '~a' under '~a'~%") item target)) (return #t)))) @@ -123,41 +147,50 @@ TARGET, and register them." (map (cut copy-item <> target #:log-port log-port) to-copy)))) -(define (install-grub* grub.cfg device target) - "This is a variant of 'install-grub' with error handling, lifted in -%STORE-MONAD" - (let* ((gc-root (string-append target %gc-roots-directory - "/grub.cfg")) - (temp-gc-root (string-append gc-root ".new")) - (delete-file (lift1 delete-file %store-monad)) - (make-symlink (lift2 switch-symlinks %store-monad)) - (rename (lift2 rename-file %store-monad))) - (mbegin %store-monad - ;; Prepare the symlink to GRUB.CFG to make sure that it's a GC root when - ;; 'install-grub' completes (being a bit paranoid.) - (make-symlink temp-gc-root grub.cfg) - - (munless (false-if-exception (install-grub grub.cfg device target)) +(define* (install-bootloader installer-drv + #:key + bootcfg bootcfg-file + device target) + "Call INSTALLER-DRV with error handling, in %STORE-MONAD." + (with-monad %store-monad + (let* ((gc-root (string-append target %gc-roots-directory + "/bootcfg")) + (temp-gc-root (string-append gc-root ".new")) + (install (and installer-drv + (derivation->output-path installer-drv))) + (bootcfg (derivation->output-path bootcfg))) + ;; Prepare the symlink to bootloader config file to make sure that it's + ;; a GC root when 'installer-drv' completes (being a bit paranoid.) + (switch-symlinks temp-gc-root bootcfg) + + (unless (false-if-exception + (begin + (install-boot-config bootcfg bootcfg-file target) + (when install + (save-load-path-excursion (primitive-load install))))) (delete-file temp-gc-root) - (leave (_ "failed to install GRUB on device '~a'~%") device)) + (leave (G_ "failed to install bootloader on device ~a '~a'~%") install device)) - ;; Register GRUB.CFG as a GC root so that its dependencies (background - ;; image, font, etc.) are not reclaimed. - (rename temp-gc-root gc-root)))) + ;; Register bootloader config file as a GC root so that its dependencies + ;; (background image, font, etc.) are not reclaimed. + (rename-file temp-gc-root gc-root) + (return #t)))) (define* (install os-drv target #:key (log-port (current-output-port)) - grub? grub.cfg device) - "Copy the closure of GRUB.CFG, which includes the output of OS-DRV, to + bootloader-installer install-bootloader? + bootcfg bootcfg-file + device) + "Copy the closure of BOOTCFG, which includes the output of OS-DRV, to directory TARGET. TARGET must be an absolute directory name since that's what 'guix-register' expects. -When GRUB? is true, install GRUB on DEVICE, using GRUB.CFG." +When INSTALL-BOOTLOADER? is true, install bootloader on DEVICE, using BOOTCFG." (define (maybe-copy to-copy) (with-monad %store-monad (if (string=? target "/") (begin - (warning (_ "initializing the current root file system~%")) + (warning (G_ "initializing the current root file system~%")) (return #t)) (begin ;; Make sure the target store exists. @@ -171,7 +204,7 @@ When GRUB? is true, install GRUB on DEVICE, using GRUB.CFG." ;; <http://lists.gnu.org/archive/html/guix-devel/2015-05/msg00452.html>. (if (zero? (geteuid)) (chown target 0 0) - (warning (_ "not running as 'root', so \ + (warning (G_ "not running as 'root', so \ the ownership of '~a' may be incorrect!~%") target)) @@ -181,16 +214,21 @@ the ownership of '~a' may be incorrect!~%") (populate (lift2 populate-root-file-system %store-monad))) (mbegin %store-monad - ;; Copy the closure of GRUB.CFG, which includes OS-DIR, GRUB's - ;; background image and so on. - (maybe-copy grub.cfg) + ;; Copy the closure of BOOTCFG, which includes OS-DIR, + ;; eventual background image and so on. + (maybe-copy + (derivation->output-path bootcfg)) ;; Create a bunch of additional files. (format log-port "populating '~a'...~%" target) (populate os-dir target) - (mwhen grub? - (install-grub* grub.cfg device target))))) + (mwhen install-bootloader? + (install-bootloader bootloader-installer + #:bootcfg bootcfg + #:bootcfg-file bootcfg-file + #:device device + #:target target))))) ;;; @@ -201,29 +239,6 @@ the ownership of '~a' may be incorrect!~%") ;; The system profile. (string-append %state-directory "/profiles/system")) -(define-syntax-rule (save-environment-excursion body ...) - "Save the current environment variables, run BODY..., and restore them." - (let ((env (environ))) - (dynamic-wind - (const #t) - (lambda () - body ...) - (lambda () - (environ env))))) - -(define-syntax-rule (save-load-path-excursion body ...) - "Save the current values of '%load-path' and '%load-compiled-path', run -BODY..., and restore them." - (let ((path %load-path) - (cpath %load-compiled-path)) - (dynamic-wind - (const #t) - (lambda () - body ...) - (lambda () - (set! %load-path path) - (set! %load-compiled-path cpath))))) - (define-syntax-rule (with-shepherd-error-handling mbody ...) "Catch and report Shepherd errors that arise when binding MBODY, a monadic expression in %STORE-MONAD." @@ -235,21 +250,21 @@ expression in %STORE-MONAD." (values (run-with-store store (begin mbody ...)) store))) (lambda (key proc format-string format-args errno . rest) - (warning (_ "while talking to shepherd: ~a~%") + (warning (G_ "while talking to shepherd: ~a~%") (apply format #f format-string format-args)) (values #f store))))) (define (report-shepherd-error error) "Report ERROR, a '&shepherd-error' error condition object." (cond ((service-not-found-error? error) - (report-error (_ "service '~a' could not be found~%") + (report-error (G_ "service '~a' could not be found~%") (service-not-found-error-service error))) ((action-not-found-error? error) - (report-error (_ "service '~a' does not have an action '~a'~%") + (report-error (G_ "service '~a' does not have an action '~a'~%") (action-not-found-error-service error) (action-not-found-error-action error))) ((action-exception-error? error) - (report-error (_ "exception caught while executing '~a' \ + (report-error (G_ "exception caught while executing '~a' \ on service '~a':~%") (action-exception-error-action error) (action-exception-error-service error)) @@ -257,10 +272,10 @@ on service '~a':~%") (action-exception-error-key error) (action-exception-error-arguments error))) ((unknown-shepherd-error? error) - (report-error (_ "something went wrong: ~s~%") + (report-error (G_ "something went wrong: ~s~%") (unknown-shepherd-error-sexp error))) ((shepherd-error? error) - (report-error (_ "shepherd error~%"))) + (report-error (G_ "shepherd error~%"))) ((not error) ;not an error #t))) @@ -277,7 +292,7 @@ unload." to-unload)))) (#f (with-monad %store-monad - (warning (_ "failed to obtain list of shepherd services~%")) + (warning (G_ "failed to obtain list of shepherd services~%")) (return #f))))) (define (upgrade-shepherd-services os) @@ -288,7 +303,7 @@ This is currently very conservative in that it does not stop or unload any running service. Unloading or stopping the wrong service ('udev', say) could bring the system down." (define new-services - (service-parameters + (service-value (fold-services (operating-system-services os) #:target-type shepherd-root-service-type))) @@ -297,7 +312,7 @@ bring the system down." (call-with-service-upgrade-info new-services (lambda (to-load to-unload) (for-each (lambda (unload) - (info (_ "unloading service '~a'...~%") unload) + (info (G_ "unloading service '~a'...~%") unload) (unload-service unload)) to-unload) @@ -305,7 +320,7 @@ bring the system down." (munless (null? to-load) (let ((to-load-names (map shepherd-service-canonical-name to-load)) (to-start (filter shepherd-service-auto-start? to-load))) - (info (_ "loading new services:~{ ~a~}...~%") to-load-names) + (info (G_ "loading new services:~{ ~a~}...~%") to-load-names) (mlet %store-monad ((files (mapm %store-monad shepherd-service-file to-load))) ;; Here we assume that FILES are exactly those that were computed @@ -329,7 +344,7 @@ it atomically, and then run OS's activation script." (switch-symlinks generation system) (switch-symlinks profile generation) - (format #t (_ "activating system...~%")) + (format #t (G_ "activating system...~%")) ;; The activation script may change $PATH, among others, so protect ;; against that. @@ -362,44 +377,26 @@ it atomically, and then run OS's activation script." (date->string (time-utc->date time) "~Y-~m-~d ~H:~M"))) -(define* (profile-grub-entries #:optional (profile %system-profile) +(define* (profile-boot-parameters #:optional (profile %system-profile) (numbers (generation-numbers profile))) - "Return a list of 'menu-entry' for the generations of PROFILE specified by + "Return a list of 'boot-parameters' for the generations of PROFILE specified by NUMBERS, which is a list of generation numbers." - (define (system->grub-entry system number time) + (define (system->boot-parameters system number time) (unless-file-not-found - (let* ((file (string-append system "/parameters")) - (params (call-with-input-file file - read-boot-parameters)) - (label (boot-parameters-label params)) - (root (boot-parameters-root-device params)) - (root-device (if (bytevector? root) - (uuid->string root) - root)) - (kernel (boot-parameters-kernel params)) - (kernel-arguments (boot-parameters-kernel-arguments params)) - (initrd (boot-parameters-initrd params))) - (menu-entry - (label (string-append label " (#" - (number->string number) ", " - (seconds->string time) ")")) - (device (boot-parameters-store-device params)) - (device-mount-point (boot-parameters-store-mount-point params)) - (linux kernel) - (linux-arguments - (cons* (string-append "--root=" root-device) - (string-append "--system=" system) - (string-append "--load=" system "/boot") - kernel-arguments)) - (initrd initrd))))) - + (let* ((params (read-boot-parameters-file system)) + (label (boot-parameters-label params))) + (boot-parameters + (inherit params) + (label (string-append label " (#" + (number->string number) ", " + (seconds->string time) ")")))))) (let* ((systems (map (cut generation-file-name profile <>) numbers)) (times (map (lambda (system) (unless-file-not-found (stat:mtime (lstat system)))) systems))) - (filter-map system->grub-entry systems numbers times))) + (filter-map system->boot-parameters systems numbers times))) ;;; @@ -415,50 +412,58 @@ connection to the store." ;;; (define (switch-to-system-generation store spec) "Switch the system profile to the generation specified by SPEC, and -re-install grub with a grub configuration file that uses the specified system +re-install bootloader with a configuration file that uses the specified system generation as its default entry. STORE is an open connection to the store." (let ((number (relative-generation-spec->number %system-profile spec))) (if number (begin - (reinstall-grub store number) + (reinstall-bootloader store number) (switch-to-generation* %system-profile number)) - (leave (_ "cannot switch to system generation '~a'~%") spec)))) + (leave (G_ "cannot switch to system generation '~a'~%") spec)))) + +(define* (system-bootloader-name #:optional (system %system-profile)) + "Return the bootloader name stored in SYSTEM's \"parameters\" file." + (let ((params (unless-file-not-found + (read-boot-parameters-file system)))) + (boot-parameters-boot-name params))) -(define (reinstall-grub store number) - "Re-install grub for existing system profile generation NUMBER. STORE is an -open connection to the store." +(define (reinstall-bootloader store number) + "Re-install bootloader for existing system profile generation NUMBER. +STORE is an open connection to the store." (let* ((generation (generation-file-name %system-profile number)) - (file (string-append generation "/parameters")) (params (unless-file-not-found - (call-with-input-file file read-boot-parameters))) - (root-device (boot-parameters-root-device params)) - ;; We don't currently keep track of past menu entries' details. The - ;; default values will allow the system to boot, even if they differ - ;; from the actual past values for this generation's entry. - (grub-config (grub-configuration (device root-device))) + (read-boot-parameters-file generation))) + ;; Detect the bootloader used in %system-profile. + (bootloader (lookup-bootloader-by-name (system-bootloader-name))) + + ;; Use the detected bootloader with default configuration. + ;; It will be enough to allow the system to boot. + (bootloader-config (bootloader-configuration + (bootloader bootloader))) + ;; Make the specified system generation the default entry. - (entries (profile-grub-entries %system-profile (list number))) + (entries (profile-boot-parameters %system-profile (list number))) (old-generations (delv number (generation-numbers %system-profile))) - (old-entries (profile-grub-entries %system-profile old-generations)) - (grub.cfg (run-with-store store - (grub-configuration-file grub-config - entries - #:old-entries old-entries)))) - (show-what-to-build store (list grub.cfg)) - (build-derivations store (list grub.cfg)) - ;; This is basically the same as install-grub*, but for now we avoid - ;; re-installing the GRUB boot loader itself onto a device, mainly because - ;; we don't in general have access to the same version of the GRUB package - ;; which was used when installing this other system generation. - (let* ((grub.cfg-path (derivation->output-path grub.cfg)) - (gc-root (string-append %gc-roots-directory "/grub.cfg")) - (temp-gc-root (string-append gc-root ".new"))) - (switch-symlinks temp-gc-root grub.cfg-path) - (unless (false-if-exception (install-grub-config grub.cfg-path "/")) - (delete-file temp-gc-root) - (leave (_ "failed to re-install GRUB configuration file: '~a'~%") - grub.cfg-path)) - (rename-file temp-gc-root gc-root)))) + (old-entries (profile-boot-parameters + %system-profile old-generations))) + (run-with-store store + (mlet* %store-monad + ((bootcfg ((bootloader-configuration-file-generator bootloader) + bootloader-config entries + #:old-entries old-entries)) + (bootcfg-file -> (bootloader-configuration-file bootloader)) + (target -> "/") + (drvs -> (list bootcfg))) + (mbegin %store-monad + (show-what-to-build* drvs) + (built-derivations drvs) + ;; Only install bootloader configuration file. Thus, no installer + ;; nor device is provided here. + (install-bootloader #f + #:bootcfg bootcfg + #:bootcfg-file bootcfg-file + #:device #f + #:target target)))))) ;;; @@ -468,7 +473,7 @@ open connection to the store." (define (service-node-label service) "Return a label to represent SERVICE." (let ((type (service-kind service)) - (value (service-parameters service))) + (value (service-value service))) (string-append (symbol->string (service-type-name type)) (cond ((or (number? value) (symbol? value)) (string-append " " (object->string value))) @@ -514,21 +519,22 @@ list of services." "Display a summary of system generation NUMBER in a human-readable format." (unless (zero? number) (let* ((generation (generation-file-name profile number)) - (param-file (string-append generation "/parameters")) - (params (call-with-input-file param-file read-boot-parameters)) + (params (read-boot-parameters-file generation)) (label (boot-parameters-label params)) + (boot-name (boot-parameters-boot-name params)) (root (boot-parameters-root-device params)) (root-device (if (bytevector? root) (uuid->string root) root)) (kernel (boot-parameters-kernel params))) (display-generation profile number) - (format #t (_ " file name: ~a~%") generation) - (format #t (_ " canonical file name: ~a~%") (readlink* generation)) + (format #t (G_ " file name: ~a~%") generation) + (format #t (G_ " canonical file name: ~a~%") (readlink* generation)) ;; TRANSLATORS: Please preserve the two-space indentation. - (format #t (_ " label: ~a~%") label) - (format #t (_ " root device: ~a~%") root-device) - (format #t (_ " kernel: ~a~%") kernel)))) + (format #t (G_ " label: ~a~%") label) + (format #t (G_ " bootloader: ~a~%") boot-name) + (format #t (G_ " root device: ~a~%") root-device) + (format #t (G_ " kernel: ~a~%") kernel)))) (define* (list-generations pattern #:optional (profile %system-profile)) "Display in a human-readable format all the system generations matching @@ -546,7 +552,7 @@ PATTERN, a string. When PATTERN is #f, display all the system generations." (leave-on-EPIPE (for-each display-system-generation numbers))))) (else - (leave (_ "invalid syntax: ~a~%") pattern)))) + (leave (G_ "invalid syntax: ~a~%") pattern)))) ;;; @@ -569,7 +575,7 @@ PATTERN, a string. When PATTERN is #f, display all the system generations." #:disk-image-size (if full-boot? image-size - (* 30 (expt 2 20))) + (* 70 (expt 2 20))) #:mappings mappings)) ((disk-image) (system-disk-image os #:disk-image-size image-size)))) @@ -585,23 +591,39 @@ PATTERN, a string. When PATTERN is #f, display all the system generations." (string-append (config-directory) "/latest")) (unless (file-exists? latest) - (warning (_ "~a not found: 'guix pull' was never run~%") latest) - (warning (_ "Consider running 'guix pull' before 'reconfigure'.~%")) - (warning (_ "Failing to do that may downgrade your system!~%")))) + (warning (G_ "~a not found: 'guix pull' was never run~%") latest) + (warning (G_ "Consider running 'guix pull' before 'reconfigure'.~%")) + (warning (G_ "Failing to do that may downgrade your system!~%")))) + +(define (bootloader-installer-derivation installer + bootloader device target) + "Return a file calling INSTALLER gexp with given BOOTLOADER, DEVICE +and TARGET arguments." + (with-monad %store-monad + (gexp->file "bootloader-installer" + (with-imported-modules '((guix build utils)) + #~(begin + (use-modules (guix build utils)) + (#$installer #$bootloader #$device #$target)))))) (define* (perform-action action os - #:key grub? dry-run? derivations-only? + #:key install-bootloader? + dry-run? derivations-only? use-substitutes? device target image-size full-boot? - (mappings '())) - "Perform ACTION for OS. GRUB? specifies whether to install GRUB; DEVICE is -the target devices for GRUB; TARGET is the target root directory; IMAGE-SIZE -is the size of the image to be built, for the 'vm-image' and 'disk-image' -actions. FULL-BOOT? is used for the 'vm' action; it determines whether to -boot directly to the kernel or to the bootloader. + (mappings '()) + (gc-root #f)) + "Perform ACTION for OS. INSTALL-BOOTLOADER? specifies whether to install +bootloader; DEVICE is the target devices for bootloader; TARGET is the target +root directory; IMAGE-SIZE is the size of the image to be built, for the +'vm-image' and 'disk-image' actions. FULL-BOOT? is used for the 'vm' action; +it determines whether to boot directly to the kernel or to the bootloader. When DERIVATIONS-ONLY? is true, print the derivation file name(s) without -building anything." +building anything. + +When GC-ROOT is a path, also make that path an indirect root of the build +output when building a system derivation, such as a disk image." (define println (cut format #t "~a~%" <>)) @@ -613,22 +635,37 @@ building anything." #:image-size image-size #:full-boot? full-boot? #:mappings mappings)) - (grub (package->derivation (grub-configuration-grub - (operating-system-bootloader os)))) - (grub.cfg (if (eq? 'container action) - (return #f) - (operating-system-grub.cfg os - (if (eq? 'init action) - '() - (profile-grub-entries))))) - - ;; For 'init' and 'reconfigure', always build GRUB.CFG, even if - ;; --no-grub is passed, because GRUB.CFG because we then use it as a GC - ;; root. See <http://bugs.gnu.org/21068>. + (bootloader -> (bootloader-configuration-bootloader + (operating-system-bootloader os))) + (bootloader-package + (let ((package (bootloader-package bootloader))) + (if package + (package->derivation package) + (return #f)))) + (bootcfg (if (eq? 'container action) + (return #f) + (operating-system-bootcfg + os + (if (eq? 'init action) + '() + (profile-boot-parameters))))) + (bootcfg-file -> (bootloader-configuration-file bootloader)) + (bootloader-installer + (let ((installer (bootloader-installer bootloader)) + (target (or target "/"))) + (bootloader-installer-derivation installer + bootloader-package + device target))) + + ;; For 'init' and 'reconfigure', always build BOOTCFG, even if + ;; --no-bootloader is passed, because we then use it as a GC root. + ;; See <http://bugs.gnu.org/21068>. (drvs -> (if (memq action '(init reconfigure)) - (if grub? - (list sys grub.cfg grub) - (list sys grub.cfg)) + (if (and install-bootloader? bootloader-package) + (list sys bootcfg + bootloader-package + bootloader-installer) + (list sys bootcfg)) (list sys))) (% (if derivations-only? (return (for-each (compose println derivation-file-name) @@ -642,31 +679,34 @@ building anything." (for-each (compose println derivation->output-path) drvs) - ;; Make sure GRUB is accessible. - (when grub? - (let ((prefix (derivation->output-path grub))) - (setenv "PATH" - (string-append prefix "/bin:" prefix "/sbin:" - (getenv "PATH"))))) - (case action ((reconfigure) (mbegin %store-monad (switch-to-system os) - (mwhen grub? - (install-grub* (derivation->output-path grub.cfg) - device "/")))) + (mwhen install-bootloader? + (install-bootloader bootloader-installer + #:bootcfg bootcfg + #:bootcfg-file bootcfg-file + #:device device + #:target "/")))) ((init) (newline) - (format #t (_ "initializing operating system under '~a'...~%") + (format #t (G_ "initializing operating system under '~a'...~%") target) (install sys (canonicalize-path target) - #:grub? grub? - #:grub.cfg (derivation->output-path grub.cfg) + #:install-bootloader? install-bootloader? + #:bootcfg bootcfg + #:bootcfg-file bootcfg-file + #:bootloader-installer bootloader-installer #:device device)) (else - ;; All we had to do was to build SYS. - (return (derivation->output-path sys)))))))) + ;; All we had to do was to build SYS and maybe register an + ;; indirect GC root. + (let ((output (derivation->output-path sys))) + (mbegin %store-monad + (mwhen gc-root + (register-root* (list output) gc-root)) + (return output))))))))) (define (export-extension-graph os port) "Export the service extension graph of OS to PORT." @@ -683,7 +723,7 @@ building anything." (let* ((services (operating-system-services os)) (pid1 (fold-services services #:target-type shepherd-root-service-type)) - (shepherds (service-parameters pid1)) ;list of <shepherd-service> + (shepherds (service-value pid1)) ;list of <shepherd-service> (sinks (filter (lambda (service) (null? (shepherd-service-requirement service))) shepherds))) @@ -697,57 +737,61 @@ building anything." ;;; (define (show-help) - (display (_ "Usage: guix system [OPTION ...] ACTION [ARG ...] [FILE] + (display (G_ "Usage: guix system [OPTION ...] ACTION [ARG ...] [FILE] Build the operating system declared in FILE according to ACTION. Some ACTIONS support additional ARGS.\n")) (newline) - (display (_ "The valid values for ACTION are:\n")) + (display (G_ "The valid values for ACTION are:\n")) (newline) - (display (_ "\ + (display (G_ "\ reconfigure switch to a new operating system configuration\n")) - (display (_ "\ + (display (G_ "\ roll-back switch to the previous operating system configuration\n")) - (display (_ "\ + (display (G_ "\ switch-generation switch to an existing operating system configuration\n")) - (display (_ "\ + (display (G_ "\ list-generations list the system generations\n")) - (display (_ "\ + (display (G_ "\ build build the operating system without installing anything\n")) - (display (_ "\ + (display (G_ "\ container build a container that shares the host's store\n")) - (display (_ "\ + (display (G_ "\ vm build a virtual machine image that shares the host's store\n")) - (display (_ "\ + (display (G_ "\ vm-image build a freestanding virtual machine image\n")) - (display (_ "\ + (display (G_ "\ disk-image build a disk image, suitable for a USB stick\n")) - (display (_ "\ + (display (G_ "\ init initialize a root file system to run GNU\n")) - (display (_ "\ + (display (G_ "\ extension-graph emit the service extension graph in Dot format\n")) - (display (_ "\ + (display (G_ "\ shepherd-graph emit the graph of shepherd services in Dot format\n")) (show-build-options-help) - (display (_ " + (display (G_ " -d, --derivation return the derivation of the given system")) - (display (_ " + (display (G_ " --on-error=STRATEGY apply STRATEGY when an error occurs while reading FILE")) - (display (_ " + (display (G_ " --image-size=SIZE for 'vm-image', produce an image of SIZE")) - (display (_ " - --no-grub for 'init', do not install GRUB")) - (display (_ " + (display (G_ " + --no-bootloader for 'init', do not install a bootloader")) + (display (G_ " --share=SPEC for 'vm', share host file system according to SPEC")) - (display (_ " + (display (G_ " + -r, --root=FILE for 'vm', 'vm-image', 'disk-image', 'container', + and 'build', make FILE a symlink to the result, and + register it as a garbage collector root")) + (display (G_ " --expose=SPEC for 'vm', expose host file system according to SPEC")) - (display (_ " + (display (G_ " --full-boot for 'vm', make a full boot sequence")) (newline) - (display (_ " + (display (G_ " -h, --help display this help and exit")) - (display (_ " + (display (G_ " -V, --version display version information and exit")) (newline) (show-bug-report-information)) @@ -772,9 +816,9 @@ Some ACTIONS support additional ARGS.\n")) (lambda (opt name arg result) (alist-cons 'image-size (size->number arg) result))) - (option '("no-grub") #f #f + (option '("no-bootloader" "no-grub") #f #f (lambda (opt name arg result) - (alist-cons 'install-grub? #f result))) + (alist-cons 'install-bootloader? #f result))) (option '("full-boot") #f #f (lambda (opt name arg result) (alist-cons 'full-boot? #t result))) @@ -797,6 +841,9 @@ Some ACTIONS support additional ARGS.\n")) (lambda (opt name arg result) (alist-cons 'system arg (alist-delete 'system result eq?)))) + (option '(#\r "root") #t #f + (lambda (opt name arg result) + (alist-cons 'gc-root arg result))) %standard-build-options)) (define %default-options @@ -808,7 +855,7 @@ Some ACTIONS support additional ARGS.\n")) (max-silent-time . 3600) (verbosity . 0) (image-size . ,(* 900 (expt 2 20))) - (install-grub? . #t))) + (install-bootloader? . #t))) ;;; @@ -820,23 +867,23 @@ Some ACTIONS support additional ARGS.\n")) ACTION must be one of the sub-commands that takes an operating system declaration as an argument (a file name.) OPTS is the raw alist of options resulting from command-line parsing." - (let* ((file (match args - (() #f) - ((x . _) x))) - (system (assoc-ref opts 'system)) - (os (if file - (load* file %user-module - #:on-error (assoc-ref opts 'on-error)) - (leave (_ "no configuration file specified~%")))) - - (dry? (assoc-ref opts 'dry-run?)) - (grub? (assoc-ref opts 'install-grub?)) - (target (match args - ((first second) second) - (_ #f))) - (device (and grub? - (grub-configuration-device - (operating-system-bootloader os))))) + (let* ((file (match args + (() #f) + ((x . _) x))) + (system (assoc-ref opts 'system)) + (os (if file + (load* file %user-module + #:on-error (assoc-ref opts 'on-error)) + (leave (G_ "no configuration file specified~%")))) + + (dry? (assoc-ref opts 'dry-run?)) + (bootloader? (assoc-ref opts 'install-bootloader?)) + (target (match args + ((first second) second) + (_ #f))) + (device (and bootloader? + (bootloader-configuration-device + (operating-system-bootloader os))))) (with-store store (set-build-options-from-command-line store opts) @@ -850,6 +897,10 @@ resulting from command-line parsing." ((shepherd-graph) (export-shepherd-graph os (current-output-port))) (else + (unless (memq action '(build init)) + (warn-about-old-distro #:suggested-command + "guix system reconfigure")) + (perform-action action os #:dry-run? dry? #:derivations-only? (assoc-ref opts @@ -862,8 +913,9 @@ resulting from command-line parsing." m) (_ #f)) opts) - #:grub? grub? - #:target target #:device device)))) + #:install-bootloader? bootloader? + #:target target #:device device + #:gc-root (assoc-ref opts 'gc-root))))) #:system system)))) (define (process-command command args opts) @@ -876,21 +928,21 @@ argument list and OPTS is the option alist." (let ((pattern (match args (() "") ((pattern) pattern) - (x (leave (_ "wrong number of arguments~%")))))) + (x (leave (G_ "wrong number of arguments~%")))))) (list-generations pattern))) ;; The following commands need to use the store, but they do not need an ;; operating system configuration file. ((switch-generation) (let ((pattern (match args ((pattern) pattern) - (x (leave (_ "wrong number of arguments~%")))))) + (x (leave (G_ "wrong number of arguments~%")))))) (with-store store (set-build-options-from-command-line store opts) (switch-to-system-generation store pattern)))) ((roll-back) (let ((pattern (match args (() "") - (x (leave (_ "wrong number of arguments~%")))))) + (x (leave (G_ "wrong number of arguments~%")))))) (with-store store (set-build-options-from-command-line store opts) (roll-back-system store)))) @@ -909,7 +961,7 @@ argument list and OPTS is the option alist." extension-graph shepherd-graph list-generations roll-back switch-generation) (alist-cons 'action action result)) - (else (leave (_ "~a: unknown action~%") action)))))) + (else (leave (G_ "~a: unknown action~%") action)))))) (define (match-pair car) ;; Return a procedure that matches a pair with CAR. @@ -924,14 +976,14 @@ argument list and OPTS is the option alist." (count (length args)) (action (assoc-ref opts 'action))) (define (fail) - (leave (_ "wrong number of arguments for action '~a'~%") + (leave (G_ "wrong number of arguments for action '~a'~%") action)) (unless action (format (current-error-port) - (_ "guix system: missing command name~%")) + (G_ "guix system: missing command name~%")) (format (current-error-port) - (_ "Try 'guix system --help' for more information.~%")) + (G_ "Try 'guix system --help' for more information.~%")) (exit 1)) (case action |