diff options
| author | Ludovic Courtès <ludo@gnu.org> | 2021-01-10 22:13:04 +0100 |
|---|---|---|
| committer | Ludovic Courtès <ludo@gnu.org> | 2021-02-01 17:32:35 +0100 |
| commit | aedbc5ff32a62f45aeed74c6833399a6cf2c22dc (patch) | |
| tree | 2fde6bc10da72d4aa16902f5b70c175a50eccda6 | |
| parent | 60d72f536437bcef2a4e02faa1fe0c8076049fcc (diff) | |
guix package: Add '--export-channels'.
* guix/channels.scm (sexp->channel): Export.
* guix/describe.scm: Use (guix channels).
(manifest-entry-provenance): New procedure.
* guix/scripts/package.scm (channel=?, export-channels): New
procedures.
(show-help, %options): Add '--export-channels'.
(process-query): Honor it.
* build-aux/build-self.scm (build-program)[select?]: Exclude (guix
channels) to account for the (guix describe) change above.
* doc/guix.texi (Invoking guix package): Document it.
| -rw-r--r-- | build-aux/build-self.scm | 3 | ||||
| -rw-r--r-- | doc/guix.texi | 26 | ||||
| -rw-r--r-- | guix/channels.scm | 1 | ||||
| -rw-r--r-- | guix/describe.scm | 34 | ||||
| -rw-r--r-- | guix/scripts/package.scm | 61 |
5 files changed, 122 insertions, 3 deletions
diff --git a/build-aux/build-self.scm b/build-aux/build-self.scm index 4b6e2bfae52..d5bc5fb46e4 100644 --- a/build-aux/build-self.scm +++ b/build-aux/build-self.scm | |||
| @@ -245,8 +245,11 @@ interface (FFI) of Guile.") | |||
| 245 | "Return a program that computes the derivation to build Guix from SOURCE." | 245 | "Return a program that computes the derivation to build Guix from SOURCE." |
| 246 | (define select? | 246 | (define select? |
| 247 | ;; Select every module but (guix config) and non-Guix modules. | 247 | ;; Select every module but (guix config) and non-Guix modules. |
| 248 | ;; Also exclude (guix channels): it is autoloaded by (guix describe), but | ||
| 249 | ;; only for peripheral functionality. | ||
| 248 | (match-lambda | 250 | (match-lambda |
| 249 | (('guix 'config) #f) | 251 | (('guix 'config) #f) |
| 252 | (('guix 'channels) #f) | ||
| 250 | (('guix _ ...) #t) | 253 | (('guix _ ...) #t) |
| 251 | (('gnu _ ...) #t) | 254 | (('gnu _ ...) #t) |
| 252 | (_ #f))) | 255 | (_ #f))) |
diff --git a/doc/guix.texi b/doc/guix.texi index e5872b5f247..9e62da438ee 100644 --- a/doc/guix.texi +++ b/doc/guix.texi | |||
| @@ -3616,7 +3616,31 @@ exactly what you specified. | |||
| 3616 | 3616 | ||
| 3617 | Keep in mind that a manifest is purely symbolic: it only contains | 3617 | Keep in mind that a manifest is purely symbolic: it only contains |
| 3618 | package names and possibly versions, and their meaning varies over time. | 3618 | package names and possibly versions, and their meaning varies over time. |
| 3619 | 3619 | If you wish to ``pin'' channels to the revisions that were used to build | |
| 3620 | the profile(s), see @option{--export-channels} below. | ||
| 3621 | |||
| 3622 | @cindex pinning, channel revisions of a profile | ||
| 3623 | @item --export-channels | ||
| 3624 | Write to standard output the list of channels used by the chosen | ||
| 3625 | profile(s), in a format suitable for @command{guix pull --channels} or | ||
| 3626 | @command{guix time-machine --channels} (@pxref{Channels}). | ||
| 3627 | |||
| 3628 | Together with @option{--export-manifest}, this option provides | ||
| 3629 | information allowing you to replicate the current profile | ||
| 3630 | (@pxref{Replicating Guix}). | ||
| 3631 | |||
| 3632 | However, note that the output of this command @emph{approximates} what | ||
| 3633 | was actually used to build this profile. In particular, a single | ||
| 3634 | profile might have been built from several different revisions of the | ||
| 3635 | same channel. In that case, @option{--export-manifest} chooses the last | ||
| 3636 | one and writes the list of other revisions in a comment. If you really | ||
| 3637 | need to pick packages from different channel revisions, you can use | ||
| 3638 | inferiors in your manifest to do so (@pxref{Inferiors}). | ||
| 3639 | |||
| 3640 | Together with @option{--export-manifest}, this is a good starting point | ||
| 3641 | if you are willing to migrate from the ``imperative'' model to the fully | ||
| 3642 | declarative model consisting of a manifest file along with a channels | ||
| 3643 | file pinning the exact channel revision(s) you want. | ||
| 3620 | @end table | 3644 | @end table |
| 3621 | 3645 | ||
| 3622 | Finally, since @command{guix package} may actually start build | 3646 | Finally, since @command{guix package} may actually start build |
diff --git a/guix/channels.scm b/guix/channels.scm index cdef77637d3..e7e1eb6fd01 100644 --- a/guix/channels.scm +++ b/guix/channels.scm | |||
| @@ -92,6 +92,7 @@ | |||
| 92 | 92 | ||
| 93 | profile-channels | 93 | profile-channels |
| 94 | manifest-entry-channel | 94 | manifest-entry-channel |
| 95 | sexp->channel | ||
| 95 | channel->code | 96 | channel->code |
| 96 | 97 | ||
| 97 | channel-news-entry? | 98 | channel-news-entry? |
diff --git a/guix/describe.scm b/guix/describe.scm index 05bf99eb58e..ac89fc0d7c9 100644 --- a/guix/describe.scm +++ b/guix/describe.scm | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | 1 | ;;; GNU Guix --- Functional package management for GNU |
| 2 | ;;; Copyright © 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org> | 2 | ;;; Copyright © 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org> |
| 3 | ;;; | 3 | ;;; |
| 4 | ;;; This file is part of GNU Guix. | 4 | ;;; This file is part of GNU Guix. |
| 5 | ;;; | 5 | ;;; |
| @@ -23,6 +23,7 @@ | |||
| 23 | #:use-module ((guix utils) #:select (location-file)) | 23 | #:use-module ((guix utils) #:select (location-file)) |
| 24 | #:use-module ((guix store) #:select (%store-prefix store-path?)) | 24 | #:use-module ((guix store) #:select (%store-prefix store-path?)) |
| 25 | #:use-module ((guix config) #:select (%state-directory)) | 25 | #:use-module ((guix config) #:select (%state-directory)) |
| 26 | #:autoload (guix channels) (sexp->channel) | ||
| 26 | #:use-module (srfi srfi-1) | 27 | #:use-module (srfi srfi-1) |
| 27 | #:use-module (ice-9 match) | 28 | #:use-module (ice-9 match) |
| 28 | #:export (current-profile | 29 | #:export (current-profile |
| @@ -31,7 +32,8 @@ | |||
| 31 | package-path-entries | 32 | package-path-entries |
| 32 | 33 | ||
| 33 | package-provenance | 34 | package-provenance |
| 34 | manifest-entry-with-provenance)) | 35 | manifest-entry-with-provenance |
| 36 | manifest-entry-provenance)) | ||
| 35 | 37 | ||
| 36 | ;;; Commentary: | 38 | ;;; Commentary: |
| 37 | ;;; | 39 | ;;; |
| @@ -166,3 +168,31 @@ there." | |||
| 166 | (#f properties) | 168 | (#f properties) |
| 167 | (sexp `((provenance ,@sexp) | 169 | (sexp `((provenance ,@sexp) |
| 168 | ,@properties))))))))) | 170 | ,@properties))))))))) |
| 171 | |||
| 172 | (define (manifest-entry-provenance entry) | ||
| 173 | "Return the list of channels ENTRY comes from. Return the empty list if | ||
| 174 | that information is missing." | ||
| 175 | (match (assq-ref (manifest-entry-properties entry) 'provenance) | ||
| 176 | ((main extras ...) | ||
| 177 | ;; XXX: Until recently, channel sexps lacked the channel name. For | ||
| 178 | ;; entries created by 'manifest-entry-with-provenance', the first sexp | ||
| 179 | ;; is known to be the 'guix channel, and for the other ones, invent a | ||
| 180 | ;; fallback name (it's OK as the name is just a "pet name"). | ||
| 181 | (match (sexp->channel main 'guix) | ||
| 182 | (#f '()) | ||
| 183 | (channel | ||
| 184 | (let loop ((extras extras) | ||
| 185 | (counter 1) | ||
| 186 | (channels (list channel))) | ||
| 187 | (match extras | ||
| 188 | (() | ||
| 189 | (reverse channels)) | ||
| 190 | ((head . tail) | ||
| 191 | (let* ((name (string->symbol | ||
| 192 | (format #f "channel~a" counter))) | ||
| 193 | (extra (sexp->channel head name))) | ||
| 194 | (if extra | ||
| 195 | (loop tail (+ 1 counter) (cons extra channels)) | ||
| 196 | (loop tail counter channels))))))))) | ||
| 197 | (_ | ||
| 198 | '()))) | ||
diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm index 2b52016c671..8234a1703de 100644 --- a/guix/scripts/package.scm +++ b/guix/scripts/package.scm | |||
| @@ -43,6 +43,7 @@ | |||
| 43 | #:use-module (guix scripts build) | 43 | #:use-module (guix scripts build) |
| 44 | #:use-module (guix transformations) | 44 | #:use-module (guix transformations) |
| 45 | #:use-module (guix describe) | 45 | #:use-module (guix describe) |
| 46 | #:autoload (guix channels) (channel-name channel-commit channel->code) | ||
| 46 | #:autoload (guix store roots) (gc-roots user-owned?) | 47 | #:autoload (guix store roots) (gc-roots user-owned?) |
| 47 | #:use-module ((guix build utils) | 48 | #:use-module ((guix build utils) |
| 48 | #:select (directory-exists? mkdir-p)) | 49 | #:select (directory-exists? mkdir-p)) |
| @@ -363,6 +364,54 @@ Alternately, see @command{guix package --search-paths -p ~s}.") | |||
| 363 | (pretty-print exp port)) | 364 | (pretty-print exp port)) |
| 364 | exp)))) | 365 | exp)))) |
| 365 | 366 | ||
| 367 | (define (channel=? a b) | ||
| 368 | (and (channel-commit a) (channel-commit b) | ||
| 369 | (string=? (channel-commit a) (channel-commit b)))) | ||
| 370 | |||
| 371 | (define* (export-channels manifest | ||
| 372 | #:optional (port (current-output-port))) | ||
| 373 | (define channels | ||
| 374 | (delete-duplicates | ||
| 375 | (append-map manifest-entry-provenance (manifest-entries manifest)) | ||
| 376 | channel=?)) | ||
| 377 | |||
| 378 | (define channel-names | ||
| 379 | (delete-duplicates (map channel-name channels))) | ||
| 380 | |||
| 381 | (define table | ||
| 382 | (fold (lambda (channel table) | ||
| 383 | (vhash-consq (channel-name channel) channel table)) | ||
| 384 | vlist-null | ||
| 385 | channels)) | ||
| 386 | |||
| 387 | (when (null? channels) | ||
| 388 | (leave (G_ "no provenance information for this profile~%"))) | ||
| 389 | |||
| 390 | (format port (G_ "\ | ||
| 391 | ;; This channel file can be passed to 'guix pull -C' or to | ||
| 392 | ;; 'guix time-machine -C' to obtain the Guix revision that was | ||
| 393 | ;; used to populate this profile.\n")) | ||
| 394 | (newline port) | ||
| 395 | (display "(list\n" port) | ||
| 396 | (for-each (lambda (name) | ||
| 397 | (define indent " ") | ||
| 398 | (match (vhash-foldq* cons '() name table) | ||
| 399 | ((channel extra ...) | ||
| 400 | (unless (null? extra) | ||
| 401 | (display indent port) | ||
| 402 | (format port (G_ "\ | ||
| 403 | ;; Note: these other commits were also used to install \ | ||
| 404 | some of the packages in this profile:~%")) | ||
| 405 | (for-each (lambda (channel) | ||
| 406 | (format port "~a;; ~s~%" | ||
| 407 | indent (channel-commit channel))) | ||
| 408 | extra)) | ||
| 409 | (pretty-print (channel->code channel) port | ||
| 410 | #:per-line-prefix indent)))) | ||
| 411 | channel-names) | ||
| 412 | (display ")\n" port) | ||
| 413 | #t) | ||
| 414 | |||
| 366 | 415 | ||
| 367 | ;;; | 416 | ;;; |
| 368 | ;;; Command-line options. | 417 | ;;; Command-line options. |
| @@ -419,6 +468,8 @@ Install, remove, or upgrade packages in a single transaction.\n")) | |||
| 419 | (display (G_ " | 468 | (display (G_ " |
| 420 | --export-manifest print a manifest for the chosen profile")) | 469 | --export-manifest print a manifest for the chosen profile")) |
| 421 | (display (G_ " | 470 | (display (G_ " |
| 471 | --export-channels print channels for the chosen profile")) | ||
| 472 | (display (G_ " | ||
| 422 | -p, --profile=PROFILE use PROFILE instead of the user's default profile")) | 473 | -p, --profile=PROFILE use PROFILE instead of the user's default profile")) |
| 423 | (display (G_ " | 474 | (display (G_ " |
| 424 | --list-profiles list the user's profiles")) | 475 | --list-profiles list the user's profiles")) |
| @@ -556,6 +607,10 @@ kind of search path~%") | |||
| 556 | (lambda (opt name arg result arg-handler) | 607 | (lambda (opt name arg result arg-handler) |
| 557 | (values (cons `(query export-manifest) result) | 608 | (values (cons `(query export-manifest) result) |
| 558 | #f))) | 609 | #f))) |
| 610 | (option '("export-channels") #f #f | ||
| 611 | (lambda (opt name arg result arg-handler) | ||
| 612 | (values (cons `(query export-channels) result) | ||
| 613 | #f))) | ||
| 559 | (option '(#\p "profile") #t #f | 614 | (option '(#\p "profile") #t #f |
| 560 | (lambda (opt name arg result arg-handler) | 615 | (lambda (opt name arg result arg-handler) |
| 561 | (values (alist-cons 'profile (canonicalize-profile arg) | 616 | (values (alist-cons 'profile (canonicalize-profile arg) |
| @@ -882,6 +937,12 @@ processed, #f otherwise." | |||
| 882 | (export-manifest manifest (current-output-port)) | 937 | (export-manifest manifest (current-output-port)) |
| 883 | #t)) | 938 | #t)) |
| 884 | 939 | ||
| 940 | (('export-channels) | ||
| 941 | (let ((manifest (concatenate-manifests | ||
| 942 | (map profile-manifest profiles)))) | ||
| 943 | (export-channels manifest (current-output-port)) | ||
| 944 | #t)) | ||
| 945 | |||
| 885 | (_ #f)))) | 946 | (_ #f)))) |
| 886 | 947 | ||
| 887 | 948 | ||
