diff options
| author | Ludovic Courtès <ludo@gnu.org> | 2013-12-22 01:08:21 +0100 |
|---|---|---|
| committer | Ludovic Courtès <ludo@gnu.org> | 2013-12-22 01:08:21 +0100 |
| commit | 760c60d68491bd6803e86e405e765f3337663f17 (patch) | |
| tree | 46745d190762aabea5dc16299c2b9f8780fb69eb | |
| parent | 7edccf4d62c299d2c52f0c55d80e9189924562d3 (diff) | |
Add 'guix archive'.
* guix/scripts/archive.scm, tests/guix-archive.sh: New files.
* Makefile.am (MODULES): Add 'archive.scm'.
(SH_TESTS): Add 'guix-archive.sh'.
* doc/guix.texi (Invoking guix archive): New section.
* guix/scripts/build.scm: Export 'derivation-from-expression'.
* guix/scripts/package.scm: Export 'specification->package+output'.
| -rw-r--r-- | Makefile.am | 2 | ||||
| -rw-r--r-- | doc/guix.texi | 59 | ||||
| -rw-r--r-- | guix/scripts/archive.scm | 232 | ||||
| -rw-r--r-- | guix/scripts/build.scm | 3 | ||||
| -rw-r--r-- | guix/scripts/package.scm | 5 | ||||
| -rw-r--r-- | tests/guix-archive.sh | 45 |
6 files changed, 342 insertions, 4 deletions
diff --git a/Makefile.am b/Makefile.am index 4815c55fba3..ba54f8c582e 100644 --- a/Makefile.am +++ b/Makefile.am | |||
| @@ -67,6 +67,7 @@ MODULES = \ | |||
| 67 | guix/snix.scm \ | 67 | guix/snix.scm \ |
| 68 | guix/scripts/download.scm \ | 68 | guix/scripts/download.scm \ |
| 69 | guix/scripts/build.scm \ | 69 | guix/scripts/build.scm \ |
| 70 | guix/scripts/archive.scm \ | ||
| 70 | guix/scripts/import.scm \ | 71 | guix/scripts/import.scm \ |
| 71 | guix/scripts/package.scm \ | 72 | guix/scripts/package.scm \ |
| 72 | guix/scripts/gc.scm \ | 73 | guix/scripts/gc.scm \ |
| @@ -130,6 +131,7 @@ SH_TESTS = \ | |||
| 130 | tests/guix-gc.sh \ | 131 | tests/guix-gc.sh \ |
| 131 | tests/guix-hash.sh \ | 132 | tests/guix-hash.sh \ |
| 132 | tests/guix-package.sh \ | 133 | tests/guix-package.sh \ |
| 134 | tests/guix-archive.sh \ | ||
| 133 | tests/guix-authenticate.sh | 135 | tests/guix-authenticate.sh |
| 134 | 136 | ||
| 135 | if BUILD_DAEMON | 137 | if BUILD_DAEMON |
diff --git a/doc/guix.texi b/doc/guix.texi index fcffa5a22bc..c78e0d0d055 100644 --- a/doc/guix.texi +++ b/doc/guix.texi | |||
| @@ -407,9 +407,10 @@ management tools it provides. | |||
| 407 | @menu | 407 | @menu |
| 408 | * Features:: How Guix will make your life brighter. | 408 | * Features:: How Guix will make your life brighter. |
| 409 | * Invoking guix package:: Package installation, removal, etc. | 409 | * Invoking guix package:: Package installation, removal, etc. |
| 410 | * Packages with Multiple Outputs:: Single source package, multiple outputs. | 410 | * Packages with Multiple Outputs:: Single source package, multiple outputs. |
| 411 | * Invoking guix gc:: Running the garbage collector. | 411 | * Invoking guix gc:: Running the garbage collector. |
| 412 | * Invoking guix pull:: Fetching the latest Guix and distribution. | 412 | * Invoking guix pull:: Fetching the latest Guix and distribution. |
| 413 | * Invoking guix archive:: Exporting and importing store files. | ||
| 413 | @end menu | 414 | @end menu |
| 414 | 415 | ||
| 415 | @node Features | 416 | @node Features |
| @@ -914,6 +915,62 @@ Use the bootstrap Guile to build the latest Guix. This option is only | |||
| 914 | useful to Guix developers. | 915 | useful to Guix developers. |
| 915 | @end table | 916 | @end table |
| 916 | 917 | ||
| 918 | |||
| 919 | @node Invoking guix archive | ||
| 920 | @section Invoking @command{guix archive} | ||
| 921 | |||
| 922 | The @command{guix archive} command allows users to @dfn{export} files | ||
| 923 | from the store into a single archive, and to later @dfn{import} them. | ||
| 924 | In particular, it allows store files to be transferred from one machine | ||
| 925 | to another machine's store. For example, to transfer the @code{emacs} | ||
| 926 | package to a machine connected over SSH, one would run: | ||
| 927 | |||
| 928 | @example | ||
| 929 | guix archive --export emacs | ssh the-machine guix archive --import | ||
| 930 | @end example | ||
| 931 | |||
| 932 | Archives are stored in the ``Nix archive'' or ``Nar'' format, which is | ||
| 933 | comparable in spirit to `tar'. When exporting, the daemon digitally | ||
| 934 | signs the contents of the archive, and that digital signature is | ||
| 935 | appended. When importing, the daemon verifies the signature and rejects | ||
| 936 | the import in case of an invalid signature. | ||
| 937 | @c FIXME: Add xref to daemon doc about signatures. | ||
| 938 | |||
| 939 | The main options are: | ||
| 940 | |||
| 941 | @table @code | ||
| 942 | @item --export | ||
| 943 | Export the specified store files or packages (see below.) Write the | ||
| 944 | resulting archive to the standard output. | ||
| 945 | |||
| 946 | @item --import | ||
| 947 | Read an archive from the standard input, and import the files listed | ||
| 948 | therein into the store. Abort if the archive has an invalid digital | ||
| 949 | signature. | ||
| 950 | @end table | ||
| 951 | |||
| 952 | To export store files as an archive to the standard output, run: | ||
| 953 | |||
| 954 | @example | ||
| 955 | guix archive --export @var{options} @var{specifications}... | ||
| 956 | @end example | ||
| 957 | |||
| 958 | @var{specifications} may be either store file names or package | ||
| 959 | specifications, as for @command{guix package} (@pxref{Invoking guix | ||
| 960 | package}). For instance, the following command creates an archive | ||
| 961 | containing the @code{gui} output of the @code{git} package and the main | ||
| 962 | output of @code{emacs}: | ||
| 963 | |||
| 964 | @example | ||
| 965 | guix archive --export git:gui /nix/store/...-emacs-24.3 > great.nar | ||
| 966 | @end example | ||
| 967 | |||
| 968 | If the specified packages are not built yet, @command{guix archive} | ||
| 969 | automatically builds them. The build process may be controlled with the | ||
| 970 | same options that can be passed to the @command{guix build} command | ||
| 971 | (@pxref{Invoking guix build}). | ||
| 972 | |||
| 973 | |||
| 917 | @c ********************************************************************* | 974 | @c ********************************************************************* |
| 918 | @node Programming Interface | 975 | @node Programming Interface |
| 919 | @chapter Programming Interface | 976 | @chapter Programming Interface |
diff --git a/guix/scripts/archive.scm b/guix/scripts/archive.scm new file mode 100644 index 00000000000..df538ed1b7d --- /dev/null +++ b/guix/scripts/archive.scm | |||
| @@ -0,0 +1,232 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | ||
| 2 | ;;; Copyright © 2013 Ludovic Courtès <ludo@gnu.org> | ||
| 3 | ;;; | ||
| 4 | ;;; This file is part of GNU Guix. | ||
| 5 | ;;; | ||
| 6 | ;;; GNU Guix is free software; you can redistribute it and/or modify it | ||
| 7 | ;;; under the terms of the GNU General Public License as published by | ||
| 8 | ;;; the Free Software Foundation; either version 3 of the License, or (at | ||
| 9 | ;;; your option) any later version. | ||
| 10 | ;;; | ||
| 11 | ;;; GNU Guix is distributed in the hope that it will be useful, but | ||
| 12 | ;;; WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | ;;; GNU General Public License for more details. | ||
| 15 | ;;; | ||
| 16 | ;;; You should have received a copy of the GNU General Public License | ||
| 17 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | |||
| 19 | (define-module (guix scripts archive) | ||
| 20 | #:use-module (guix config) | ||
| 21 | #:use-module (guix utils) | ||
| 22 | #:use-module (guix store) | ||
| 23 | #:use-module (guix packages) | ||
| 24 | #:use-module (guix derivations) | ||
| 25 | #:use-module (guix ui) | ||
| 26 | #:use-module (ice-9 match) | ||
| 27 | #:use-module (srfi srfi-1) | ||
| 28 | #:use-module (srfi srfi-11) | ||
| 29 | #:use-module (srfi srfi-26) | ||
| 30 | #:use-module (srfi srfi-37) | ||
| 31 | #:use-module (guix scripts build) | ||
| 32 | #:use-module (guix scripts package) | ||
| 33 | #:export (guix-archive)) | ||
| 34 | |||
| 35 | |||
| 36 | ;;; | ||
| 37 | ;;; Command-line options. | ||
| 38 | ;;; | ||
| 39 | |||
| 40 | (define %default-options | ||
| 41 | ;; Alist of default option values. | ||
| 42 | `((system . ,(%current-system)) | ||
| 43 | (substitutes? . #t) | ||
| 44 | (max-silent-time . 3600) | ||
| 45 | (verbosity . 0))) | ||
| 46 | |||
| 47 | (define (show-help) | ||
| 48 | (display (_ "Usage: guix archive [OPTION]... PACKAGE... | ||
| 49 | Export/import one or more packages from/to the store.\n")) | ||
| 50 | (display (_ " | ||
| 51 | --export export the specified files/packages to stdout")) | ||
| 52 | (display (_ " | ||
| 53 | --import import from the archive passed on stdin")) | ||
| 54 | (newline) | ||
| 55 | (display (_ " | ||
| 56 | -e, --expression=EXPR build the package or derivation EXPR evaluates to")) | ||
| 57 | (display (_ " | ||
| 58 | -S, --source build the packages' source derivations")) | ||
| 59 | (display (_ " | ||
| 60 | -s, --system=SYSTEM attempt to build for SYSTEM--e.g., \"i686-linux\"")) | ||
| 61 | (display (_ " | ||
| 62 | --target=TRIPLET cross-build for TRIPLET--e.g., \"armel-linux-gnu\"")) | ||
| 63 | (display (_ " | ||
| 64 | -n, --dry-run do not build the derivations")) | ||
| 65 | (display (_ " | ||
| 66 | --fallback fall back to building when the substituter fails")) | ||
| 67 | (display (_ " | ||
| 68 | --no-substitutes build instead of resorting to pre-built substitutes")) | ||
| 69 | (display (_ " | ||
| 70 | --max-silent-time=SECONDS | ||
| 71 | mark the build as failed after SECONDS of silence")) | ||
| 72 | (display (_ " | ||
| 73 | -c, --cores=N allow the use of up to N CPU cores for the build")) | ||
| 74 | (newline) | ||
| 75 | (display (_ " | ||
| 76 | -h, --help display this help and exit")) | ||
| 77 | (display (_ " | ||
| 78 | -V, --version display version information and exit")) | ||
| 79 | (newline) | ||
| 80 | (show-bug-report-information)) | ||
| 81 | |||
| 82 | (define %options | ||
| 83 | ;; Specifications of the command-line options. | ||
| 84 | (list (option '(#\h "help") #f #f | ||
| 85 | (lambda args | ||
| 86 | (show-help) | ||
| 87 | (exit 0))) | ||
| 88 | (option '(#\V "version") #f #f | ||
| 89 | (lambda args | ||
| 90 | (show-version-and-exit "guix build"))) | ||
| 91 | |||
| 92 | (option '("export") #f #f | ||
| 93 | (lambda (opt name arg result) | ||
| 94 | (alist-cons 'export #t result))) | ||
| 95 | (option '("import") #f #f | ||
| 96 | (lambda (opt name arg result) | ||
| 97 | (alist-cons 'import #t result))) | ||
| 98 | |||
| 99 | (option '(#\S "source") #f #f | ||
| 100 | (lambda (opt name arg result) | ||
| 101 | (alist-cons 'source? #t result))) | ||
| 102 | (option '(#\s "system") #t #f | ||
| 103 | (lambda (opt name arg result) | ||
| 104 | (alist-cons 'system arg | ||
| 105 | (alist-delete 'system result eq?)))) | ||
| 106 | (option '("target") #t #f | ||
| 107 | (lambda (opt name arg result) | ||
| 108 | (alist-cons 'target arg | ||
| 109 | (alist-delete 'target result eq?)))) | ||
| 110 | (option '(#\e "expression") #t #f | ||
| 111 | (lambda (opt name arg result) | ||
| 112 | (alist-cons 'expression arg result))) | ||
| 113 | (option '(#\c "cores") #t #f | ||
| 114 | (lambda (opt name arg result) | ||
| 115 | (let ((c (false-if-exception (string->number arg)))) | ||
| 116 | (if c | ||
| 117 | (alist-cons 'cores c result) | ||
| 118 | (leave (_ "~a: not a number~%") arg))))) | ||
| 119 | (option '(#\n "dry-run") #f #f | ||
| 120 | (lambda (opt name arg result) | ||
| 121 | (alist-cons 'dry-run? #t result))) | ||
| 122 | (option '("fallback") #f #f | ||
| 123 | (lambda (opt name arg result) | ||
| 124 | (alist-cons 'fallback? #t | ||
| 125 | (alist-delete 'fallback? result)))) | ||
| 126 | (option '("no-substitutes") #f #f | ||
| 127 | (lambda (opt name arg result) | ||
| 128 | (alist-cons 'substitutes? #f | ||
| 129 | (alist-delete 'substitutes? result)))) | ||
| 130 | (option '("max-silent-time") #t #f | ||
| 131 | (lambda (opt name arg result) | ||
| 132 | (alist-cons 'max-silent-time (string->number* arg) | ||
| 133 | result))) | ||
| 134 | (option '(#\r "root") #t #f | ||
| 135 | (lambda (opt name arg result) | ||
| 136 | (alist-cons 'gc-root arg result))) | ||
| 137 | (option '("verbosity") #t #f | ||
| 138 | (lambda (opt name arg result) | ||
| 139 | (let ((level (string->number arg))) | ||
| 140 | (alist-cons 'verbosity level | ||
| 141 | (alist-delete 'verbosity result))))))) | ||
| 142 | |||
| 143 | (define (options->derivations+files store opts) | ||
| 144 | "Given OPTS, the result of 'args-fold', return a list of derivations to | ||
| 145 | build and a list of store files to transfer." | ||
| 146 | (define package->derivation | ||
| 147 | (match (assoc-ref opts 'target) | ||
| 148 | (#f package-derivation) | ||
| 149 | (triplet | ||
| 150 | (cut package-cross-derivation <> <> triplet <>)))) | ||
| 151 | |||
| 152 | (define src? (assoc-ref opts 'source?)) | ||
| 153 | (define sys (assoc-ref opts 'system)) | ||
| 154 | |||
| 155 | (fold2 (lambda (arg derivations files) | ||
| 156 | (match arg | ||
| 157 | (('expression . str) | ||
| 158 | (let ((drv (derivation-from-expression store str | ||
| 159 | package->derivation | ||
| 160 | sys src?))) | ||
| 161 | (values (cons drv derivations) | ||
| 162 | (cons (derivation->output-path drv) files)))) | ||
| 163 | (('argument . (? store-path? file)) | ||
| 164 | (values derivations (cons file files))) | ||
| 165 | (('argument . (? string? spec)) | ||
| 166 | (let-values (((p output) | ||
| 167 | (specification->package+output spec))) | ||
| 168 | (if src? | ||
| 169 | (let* ((s (package-source p)) | ||
| 170 | (drv (package-source-derivation store s))) | ||
| 171 | (values (cons drv derivations) | ||
| 172 | (cons (derivation->output-path drv) | ||
| 173 | files))) | ||
| 174 | (let ((drv (package->derivation store p sys))) | ||
| 175 | (values (cons drv derivations) | ||
| 176 | (cons (derivation->output-path drv output) | ||
| 177 | files)))))) | ||
| 178 | (_ | ||
| 179 | (values derivations files)))) | ||
| 180 | '() | ||
| 181 | '() | ||
| 182 | opts)) | ||
| 183 | |||
| 184 | |||
| 185 | ;;; | ||
| 186 | ;;; Entry point. | ||
| 187 | ;;; | ||
| 188 | |||
| 189 | (define (export-from-store store opts) | ||
| 190 | "Export the packages or derivations specified in OPTS from STORE. Write the | ||
| 191 | resulting archive to the standard output port." | ||
| 192 | (let-values (((drv files) | ||
| 193 | (options->derivations+files store opts))) | ||
| 194 | (show-what-to-build store drv | ||
| 195 | #:use-substitutes? (assoc-ref opts 'substitutes?) | ||
| 196 | #:dry-run? (assoc-ref opts 'dry-run?)) | ||
| 197 | |||
| 198 | (set-build-options store | ||
| 199 | #:build-cores (or (assoc-ref opts 'cores) 0) | ||
| 200 | #:fallback? (assoc-ref opts 'fallback?) | ||
| 201 | #:use-substitutes? (assoc-ref opts 'substitutes?) | ||
| 202 | #:max-silent-time (assoc-ref opts 'max-silent-time)) | ||
| 203 | |||
| 204 | (if (or (assoc-ref opts 'dry-run?) | ||
| 205 | (build-derivations store drv)) | ||
| 206 | (export-paths store files (current-output-port)) | ||
| 207 | (leave (_ "unable to export the given packages"))))) | ||
| 208 | |||
| 209 | (define (guix-archive . args) | ||
| 210 | (define (parse-options) | ||
| 211 | ;; Return the alist of option values. | ||
| 212 | (args-fold* args %options | ||
| 213 | (lambda (opt name arg result) | ||
| 214 | (leave (_ "~A: unrecognized option~%") name)) | ||
| 215 | (lambda (arg result) | ||
| 216 | (alist-cons 'argument arg result)) | ||
| 217 | %default-options)) | ||
| 218 | |||
| 219 | (with-error-handling | ||
| 220 | ;; Ask for absolute file names so that .drv file names passed from the | ||
| 221 | ;; user to 'read-derivation' are absolute when it returns. | ||
| 222 | (with-fluids ((%file-port-name-canonicalization 'absolute)) | ||
| 223 | (let* ((opts (parse-options)) | ||
| 224 | (store (open-connection))) | ||
| 225 | |||
| 226 | (cond ((assoc-ref opts 'export) | ||
| 227 | (export-from-store store opts)) | ||
| 228 | ((assoc-ref opts 'import) | ||
| 229 | (import-paths store (current-input-port))) | ||
| 230 | (else | ||
| 231 | (leave | ||
| 232 | (_ "either '--export' or '--import' must be specified")))))))) | ||
diff --git a/guix/scripts/build.scm b/guix/scripts/build.scm index b3d852e950d..90187094c1c 100644 --- a/guix/scripts/build.scm +++ b/guix/scripts/build.scm | |||
| @@ -33,7 +33,8 @@ | |||
| 33 | #:use-module (srfi srfi-34) | 33 | #:use-module (srfi srfi-34) |
| 34 | #:use-module (srfi srfi-37) | 34 | #:use-module (srfi srfi-37) |
| 35 | #:autoload (gnu packages) (find-best-packages-by-name) | 35 | #:autoload (gnu packages) (find-best-packages-by-name) |
| 36 | #:export (guix-build)) | 36 | #:export (derivation-from-expression |
| 37 | guix-build)) | ||
| 37 | 38 | ||
| 38 | (define (derivation-from-expression store str package-derivation | 39 | (define (derivation-from-expression store str package-derivation |
| 39 | system source?) | 40 | system source?) |
diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm index 8c197a741ed..7cebf6b4d40 100644 --- a/guix/scripts/package.scm +++ b/guix/scripts/package.scm | |||
| @@ -41,7 +41,8 @@ | |||
| 41 | #:use-module ((gnu packages base) #:select (guile-final)) | 41 | #:use-module ((gnu packages base) #:select (guile-final)) |
| 42 | #:use-module ((gnu packages bootstrap) #:select (%bootstrap-guile)) | 42 | #:use-module ((gnu packages bootstrap) #:select (%bootstrap-guile)) |
| 43 | #:use-module (guix gnu-maintenance) | 43 | #:use-module (guix gnu-maintenance) |
| 44 | #:export (guix-package)) | 44 | #:export (specification->package+output |
| 45 | guix-package)) | ||
| 45 | 46 | ||
| 46 | (define %store | 47 | (define %store |
| 47 | (make-parameter #f)) | 48 | (make-parameter #f)) |
| @@ -293,7 +294,7 @@ return its return value." | |||
| 293 | #f)))) | 294 | #f)))) |
| 294 | 295 | ||
| 295 | (define* (specification->package+output spec #:optional (output "out")) | 296 | (define* (specification->package+output spec #:optional (output "out")) |
| 296 | "Find the package and output specified by SPEC, or #f and #f; SPEC may | 297 | "Return the package and output specified by SPEC, or #f and #f; SPEC may |
| 297 | optionally contain a version number and an output name, as in these examples: | 298 | optionally contain a version number and an output name, as in these examples: |
| 298 | 299 | ||
| 299 | guile | 300 | guile |
diff --git a/tests/guix-archive.sh b/tests/guix-archive.sh new file mode 100644 index 00000000000..ef048354690 --- /dev/null +++ b/tests/guix-archive.sh | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | # GNU Guix --- Functional package management for GNU | ||
| 2 | # Copyright © 2013 Ludovic Courtès <ludo@gnu.org> | ||
| 3 | # | ||
| 4 | # This file is part of GNU Guix. | ||
| 5 | # | ||
| 6 | # GNU Guix is free software; you can redistribute it and/or modify it | ||
| 7 | # under the terms of the GNU General Public License as published by | ||
| 8 | # the Free Software Foundation; either version 3 of the License, or (at | ||
| 9 | # your option) any later version. | ||
| 10 | # | ||
| 11 | # GNU Guix is distributed in the hope that it will be useful, but | ||
| 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | # GNU General Public License for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License | ||
| 17 | # along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | |||
| 19 | # | ||
| 20 | # Test the 'guix archive' command-line utility. | ||
| 21 | # | ||
| 22 | |||
| 23 | guix archive --version | ||
| 24 | |||
| 25 | archive="t-archive-$$" | ||
| 26 | archive_alt="t-archive-alt-$$" | ||
| 27 | rm -f "$archive" "$archive_alt" | ||
| 28 | |||
| 29 | trap 'rm -f "$archive" "$archive_alt"' EXIT | ||
| 30 | |||
| 31 | guix archive --export guile-bootstrap > "$archive" | ||
| 32 | guix archive --export guile-bootstrap:out > "$archive_alt" | ||
| 33 | cmp "$archive" "$archive_alt" | ||
| 34 | |||
| 35 | guix archive --export \ | ||
| 36 | -e '(@ (gnu packages bootstrap) %bootstrap-guile)' > "$archive_alt" | ||
| 37 | cmp "$archive" "$archive_alt" | ||
| 38 | |||
| 39 | guix archive --export `guix build guile-bootstrap` > "$archive_alt" | ||
| 40 | cmp "$archive" "$archive_alt" | ||
| 41 | |||
| 42 | guix archive --import < "$archive" 2>&1 | grep "import.*guile-bootstrap" | ||
| 43 | |||
| 44 | if guix archive something-that-does-not-exist | ||
| 45 | then false; else true; fi | ||
