* guix/scripts/archive.scm (show-help, %options): Add --extract.
(guix-archive): Honor it.
* tests/guix-archive.sh: Test it.
* doc/guix.texi (Invoking guix archive): Document it.
s-expressions''} and is structured as an access-control list in the
@url{http://theworld.com/~cme/spki.txt, Simple Public-Key Infrastructure
(SPKI)}.
+
+@item --extract=@var{directory}
+@itemx -x @var{directory}
+Read a single-item archive as served by substitute servers
+(@pxref{Substitutes}) and extract it to @var{directory}. This is a
+low-level operation needed in only very narrow use cases; see below.
+
+For example, the following command extracts the substitute for Emacs
+served by @code{hydra.gnu.org} to @file{/tmp/emacs}:
+
+@example
+$ wget -O - \
+ http://hydra.gnu.org/nar/@dots{}-emacs-24.5 \
+ | bunzip2 | guix archive -x /tmp/emacs
+@end example
+
+Single-item archives are different from multiple-item archives produced
+by @command{guix archive --export}; they contain a single store item,
+and they do @emph{not} embed a signature. Thus this operation does
+@emph{no} signature verification and its output should be considered
+unsafe.
+
+The primary purpose of this operation is to facilitate inspection of
+archive contents coming from possibly untrusted substitute servers.
+
@end table
To export store files as an archive to the standard output, run:
#:use-module (guix config)
#:use-module (guix utils)
#:use-module ((guix build utils) #:select (mkdir-p))
+ #:use-module ((guix serialization) #:select (restore-file))
#:use-module (guix store)
#:use-module (guix packages)
#:use-module (guix derivations)
--import import from the archive passed on stdin"))
(display (_ "
--missing print the files from stdin that are missing"))
+ (display (_ "
+ -x, --extract=DIR extract the archive on stdin to DIR"))
(newline)
(display (_ "
--generate-key[=PARAMETERS]
(option '("missing") #f #f
(lambda (opt name arg result)
(alist-cons 'missing #t result)))
+ (option '("extract" #\x) #t #f
+ (lambda (opt name arg result)
+ (alist-cons 'extract arg result)))
(option '("generate-key") #f #t
(lambda (opt name arg result)
(catch 'gcry-error
(missing (remove (cut valid-path? store <>)
files)))
(format #t "~{~a~%~}" missing)))
+ ((assoc-ref opts 'extract)
+ =>
+ (lambda (target)
+ (restore-file (current-input-port) target)))
(else
(leave
(_ "either '--export' or '--import' \
archive="t-archive-$$"
archive_alt="t-archive-alt-$$"
+tmpdir="t-archive-dir-$$"
rm -f "$archive" "$archive_alt"
+rm -rf "$tmpdir"
-trap 'rm -f "$archive" "$archive_alt"' EXIT
+trap 'rm -f "$archive" "$archive_alt"; rm -rf "$tmpdir"' EXIT
guix archive --export guile-bootstrap > "$archive"
guix archive --export guile-bootstrap:out > "$archive_alt"
guix archive --export `guix build guile-bootstrap` > "$archive_alt"
cmp "$archive" "$archive_alt"
-# Check the exit value and stderr upon import.
+# Check the exit value upon import.
guix archive --import < "$archive"
if guix archive something-that-does-not-exist
if guix archive --missing < "$archive"
then false; else true; fi
+# Check '--extract'.
+guile -c "(use-modules (guix serialization))
+ (call-with-output-file \"$archive\"
+ (lambda (port)
+ (write-file \"$(guix build guile-bootstrap)\" port)))"
+guix archive -x "$tmpdir" < "$archive"
+test -x "$tmpdir/bin/guile"
+test -d "$tmpdir/lib/guile"
+
if echo foo | guix archive --authorize
then false; else true; fi