diff --git a/doc/guix.texi b/doc/guix.texi index d5884008f4..93d1c2be3b 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -938,6 +938,12 @@ package to a machine connected over SSH, one would run: guix archive --export emacs | ssh the-machine guix archive --import @end example +@noindent +However, note that, in this example, all of @code{emacs} and its +dependencies are transferred, regardless of what is already available in +the target machine's store. The @code{--missing} option can help figure +out which items are missing from the target's store. + Archives are stored in the ``Nix archive'' or ``Nar'' format, which is comparable in spirit to `tar'. When exporting, the daemon digitally signs the contents of the archive, and that digital signature is @@ -959,6 +965,11 @@ therein into the store. Abort if the archive has an invalid digital signature, or if it is signed by a public key not among the authorized keys (see @code{--authorize} below.) +@item --missing +Read a list of store file names from the standard input, one per line, +and write on the standard output the subset of these files missing from +the store. + @item --generate-key[=@var{parameters}] @cindex signing, archives Generate a new key pair for the daemons. This is a prerequisite before diff --git a/guix/scripts/archive.scm b/guix/scripts/archive.scm index 3b778d8151..32690c6b45 100644 --- a/guix/scripts/archive.scm +++ b/guix/scripts/archive.scm @@ -27,6 +27,8 @@ (define-module (guix scripts archive) #:use-module (guix pki) #:use-module (guix pk-crypto) #:use-module (ice-9 match) + #:use-module (ice-9 format) + #:use-module (ice-9 rdelim) #:use-module (srfi srfi-1) #:use-module (srfi srfi-11) #:use-module (srfi srfi-26) @@ -55,6 +57,8 @@ (define (show-help) --export export the specified files/packages to stdout")) (display (_ " --import import from the archive passed on stdin")) + (display (_ " + --missing print the files from stdin that are missing")) (newline) (display (_ " --generate-key[=PARAMETERS] @@ -102,6 +106,9 @@ (define %options (option '("import") #f #f (lambda (opt name arg result) (alist-cons 'import #t result))) + (option '("missing") #f #f + (lambda (opt name arg result) + (alist-cons 'missing #t result))) (option '("generate-key") #f #t (lambda (opt name arg result) (catch 'gcry-error @@ -294,6 +301,15 @@ (define (parse-options) (alist-cons 'argument arg result)) %default-options)) + (define (lines port) + ;; Return lines read from PORT. + (let loop ((line (read-line port)) + (result '())) + (if (eof-object? line) + (reverse result) + (loop (read-line port) + (cons line result))))) + (with-error-handling ;; Ask for absolute file names so that .drv file names passed from the ;; user to 'read-derivation' are absolute when it returns. @@ -310,6 +326,11 @@ (define (parse-options) (export-from-store store opts)) ((assoc-ref opts 'import) (import-paths store (current-input-port))) + ((assoc-ref opts 'missing) + (let* ((files (lines (current-input-port))) + (missing (remove (cut valid-path? store <>) + files))) + (format #t "~{~a~%~}" missing))) (else (leave (_ "either '--export' or '--import' \ diff --git a/tests/guix-archive.sh b/tests/guix-archive.sh index 3ac618ae33..0de7395145 100644 --- a/tests/guix-archive.sh +++ b/tests/guix-archive.sh @@ -1,5 +1,5 @@ # GNU Guix --- Functional package management for GNU -# Copyright © 2013 Ludovic Courtès +# Copyright © 2013, 2014 Ludovic Courtès # # This file is part of GNU Guix. # @@ -44,5 +44,23 @@ guix archive --import < "$archive" 2>&1 | grep "import.*guile-bootstrap" if guix archive something-that-does-not-exist then false; else true; fi +# This one must not be listed as missing. +guix build guile-bootstrap > "$archive" +guix archive --missing < "$archive" +test "`guix archive --missing < "$archive"`" = "" + +# Two out of three should be listed as missing. +echo "$NIX_STORE_DIR/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo" >> "$archive" +echo "$NIX_STORE_DIR/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-bar" >> "$archive" +guix archive --missing < "$archive" > "$archive_alt" +echo "$NIX_STORE_DIR/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo" > "$archive" +echo "$NIX_STORE_DIR/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-bar" >> "$archive" +cmp "$archive" "$archive_alt" + +# This is not a valid store file name, so an error. +echo something invalid > "$archive" +if guix archive --missing < "$archive" +then false; else true; fi + if echo foo | guix archive --authorize then false; else true; fi