From 041a9466ea23d6ae811491bcf529bf9487317b48 Mon Sep 17 00:00:00 2001 From: Mathieu Othacehe Date: Fri, 29 Jan 2021 13:48:44 +0100 Subject: guix: channels: Introduce "channel-with-substitutes-available". * guix/channels.scm (find-latest-commit-with-substitutes, channel-with-substitutes-available): New procedures. * guix/scripts/pull.scm (guix-pull): Move "channel-list" call inside the %current-system parameter scope. * doc/guix.texi (Channels with substitutes): New section. --- guix/channels.scm | 1 + 1 file changed, 1 insertion(+) (limited to 'guix/channels.scm') diff --git a/guix/channels.scm b/guix/channels.scm index 0c84eed477..9ab8cd8749 100644 --- a/guix/channels.scm +++ b/guix/channels.scm @@ -20,6 +20,7 @@ (define-module (guix channels) #:use-module (git) + #:use-module (guix ci) #:use-module (guix git) #:use-module (guix git-authenticate) #:use-module ((guix openpgp) -- cgit v1.2.3 From 246c0c60da7623fdf8956687a1c11299056d4b1a Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Sun, 31 Jan 2021 21:48:26 +0100 Subject: ci: Add missing imports. This is a followup to 041a9466ea23d6ae811491bcf529bf9487317b48. * guix/ci.scm: Add missing imports. * guix/channels.scm: Remove (guix ci) import. --- guix/channels.scm | 1 - guix/ci.scm | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'guix/channels.scm') diff --git a/guix/channels.scm b/guix/channels.scm index 9ab8cd8749..0c84eed477 100644 --- a/guix/channels.scm +++ b/guix/channels.scm @@ -20,7 +20,6 @@ (define-module (guix channels) #:use-module (git) - #:use-module (guix ci) #:use-module (guix git) #:use-module (guix git-authenticate) #:use-module ((guix openpgp) diff --git a/guix/ci.scm b/guix/ci.scm index 95325b4bfe..f04109112c 100644 --- a/guix/ci.scm +++ b/guix/ci.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2018, 2019, 2020 Ludovic Courtès +;;; Copyright © 2018, 2019, 2020, 2021 Ludovic Courtès ;;; Copyright © 2020 Mathieu Othacehe ;;; ;;; This file is part of GNU Guix. @@ -23,6 +23,8 @@ #:use-module (json) #:use-module (srfi srfi-1) #:use-module (ice-9 match) + #:use-module (guix i18n) + #:use-module (guix diagnostics) #:autoload (guix channels) (channel) #:export (build-product? build-product-id -- cgit v1.2.3 From 9272cc700efbc5b80f1d3e0d43017304f37a3aeb Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Sun, 10 Jan 2021 18:30:57 +0100 Subject: channels: Factorize 'manifest-entry-channel' and channel serialization. * guix/channels.scm (sexp->channel, manifest-entry-channel): New procedures. (profile-channels): Replace lambda by 'manifest-entry-channel'. (channel-instance->sexp): New procedure. (channel-instances->manifest)[instance->entry]: Use 'channel-instance->sexp' instead of inline code. --- guix/channels.scm | 106 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 63 insertions(+), 43 deletions(-) (limited to 'guix/channels.scm') diff --git a/guix/channels.scm b/guix/channels.scm index 0c84eed477..65a0d849ec 100644 --- a/guix/channels.scm +++ b/guix/channels.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2018, 2019, 2020 Ludovic Courtès +;;; Copyright © 2018, 2019, 2020, 2021 Ludovic Courtès ;;; Copyright © 2018 Ricardo Wurmus ;;; Copyright © 2019 Jan (janneke) Nieuwenhuizen ;;; @@ -802,13 +802,35 @@ derivation." (derivation-input-derivation input)))) (derivation-inputs drv)))) +(define (channel-instance->sexp instance) + "Return an sexp representation of INSTANCE, a channel instance." + (let* ((commit (channel-instance-commit instance)) + (channel (channel-instance-channel instance)) + (intro (channel-introduction channel))) + `(repository + (version 0) + (url ,(channel-url channel)) + (branch ,(channel-branch channel)) + (commit ,commit) + ,@(if intro + `((introduction + (channel-introduction + (version 0) + (commit + ,(channel-introduction-first-signed-commit + intro)) + (signer + ,(openpgp-format-fingerprint + (channel-introduction-first-commit-signer + intro)))))) + '())))) + (define (channel-instances->manifest instances) "Return a profile manifest with entries for all of INSTANCES, a list of channel instances." (define (instance->entry instance drv) - (let* ((commit (channel-instance-commit instance)) - (channel (channel-instance-channel instance)) - (intro (channel-introduction channel))) + (let ((commit (channel-instance-commit instance)) + (channel (channel-instance-channel instance))) (manifest-entry (name (symbol->string (channel-name channel))) (version (string-take commit 7)) @@ -819,23 +841,7 @@ channel instances." drv) drv)) (properties - `((source (repository - (version 0) - (url ,(channel-url channel)) - (branch ,(channel-branch channel)) - (commit ,commit) - ,@(if intro - `((introduction - (channel-introduction - (version 0) - (commit - ,(channel-introduction-first-signed-commit - intro)) - (signer - ,(openpgp-format-fingerprint - (channel-introduction-first-commit-signer - intro)))))) - '())))))))) + `((source ,(channel-instance->sexp instance))))))) (mlet* %store-monad ((derivations (channel-instance-derivations instances)) (entries -> (map instance->entry instances derivations))) @@ -900,31 +906,45 @@ to 'latest-channel-instances'." validate-pull))) (channel-instances->derivation instances))) +(define* (sexp->channel sexp #:optional (name 'channel)) + "Read SEXP, a provenance sexp as created by 'channel-instance->sexp', +and return a channel called NAME. Return #f if the sexp does not have the +expected structure." + (match sexp + (('repository ('version 0) + ('url url) + ('branch branch) + ('commit commit) + rest ...) + (channel (name name) + (url url) + (commit commit) + (introduction + (match (assq 'introduction rest) + (#f #f) + (('introduction intro) + (sexp->channel-introduction intro)))))) + + (_ #f))) + +(define (manifest-entry-channel entry) + "Return the channel ENTRY corresponds to, or #f if that information is +missing or unreadable. ENTRY must be an entry created by +'channel-instances->manifest', with the 'source' property." + (let ((name (string->symbol (manifest-entry-name entry)))) + (match (assq-ref (manifest-entry-properties entry) 'source) + ((sexp) + (sexp->channel sexp name)) + (_ + ;; No channel information for this manifest entry. + ;; XXX: Pre-0.15.0 Guix did not provide that information, + ;; but there's not much we can do in that case. + #f)))) + (define (profile-channels profile) "Return the list of channels corresponding to entries in PROFILE. If PROFILE is not a profile created by 'guix pull', return the empty list." - (filter-map (lambda (entry) - (match (assq 'source (manifest-entry-properties entry)) - (('source ('repository ('version 0) - ('url url) - ('branch branch) - ('commit commit) - rest ...)) - (channel (name (string->symbol - (manifest-entry-name entry))) - (url url) - (commit commit) - (introduction - (match (assq 'introduction rest) - (#f #f) - (('introduction intro) - (sexp->channel-introduction intro)))))) - - ;; No channel information for this manifest entry. - ;; XXX: Pre-0.15.0 Guix did not provide that information, - ;; but there's not much we can do in that case. - (_ #f))) - + (filter-map manifest-entry-channel ;; Show most recently installed packages last. (reverse (manifest-entries (profile-manifest profile))))) -- cgit v1.2.3 From a47f16a874356ca6a1459176561ec7e66c00ba19 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Sun, 10 Jan 2021 18:57:01 +0100 Subject: channels: Add the channel name to channel sexps. * guix/channels.scm (channel-instance->sexp): Add 'name'. (sexp->channel): Extract the name from SEXP, using the optional argument as a fallback. --- guix/channels.scm | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'guix/channels.scm') diff --git a/guix/channels.scm b/guix/channels.scm index 65a0d849ec..6449221c3f 100644 --- a/guix/channels.scm +++ b/guix/channels.scm @@ -812,6 +812,7 @@ derivation." (url ,(channel-url channel)) (branch ,(channel-branch channel)) (commit ,commit) + (name ,(channel-name channel)) ,@(if intro `((introduction (channel-introduction @@ -907,16 +908,22 @@ to 'latest-channel-instances'." (channel-instances->derivation instances))) (define* (sexp->channel sexp #:optional (name 'channel)) - "Read SEXP, a provenance sexp as created by 'channel-instance->sexp', -and return a channel called NAME. Return #f if the sexp does not have the -expected structure." + "Read SEXP, a provenance sexp as created by 'channel-instance->sexp'; use +NAME as the channel name if SEXP does not specify it. Return #f if the sexp +does not have the expected structure." (match sexp (('repository ('version 0) ('url url) ('branch branch) ('commit commit) rest ...) - (channel (name name) + ;; Historically channel sexps did not include the channel name. It's OK + ;; for channels created by 'channel-instances->manifest' because the + ;; entry name is the channel name, but it was missing for entries created + ;; by 'manifest-entry-with-provenance'. + (channel (name (match (assq 'name rest) + (#f name) + (('name name) name))) (url url) (commit commit) (introduction -- cgit v1.2.3 From 1b88b7bad297a97bbbe5334eacb501aadc8ddf8a Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Sun, 10 Jan 2021 21:37:48 +0100 Subject: guix describe: Use 'manifest-entry-channel'. * guix/channels.scm (manifest-entry-channel): Export. * guix/scripts/describe.scm (display-profile-content): Use it. --- guix/channels.scm | 1 + guix/scripts/describe.scm | 30 ++++++++++++------------------ 2 files changed, 13 insertions(+), 18 deletions(-) (limited to 'guix/channels.scm') diff --git a/guix/channels.scm b/guix/channels.scm index 6449221c3f..743b4a25b7 100644 --- a/guix/channels.scm +++ b/guix/channels.scm @@ -91,6 +91,7 @@ ensure-forward-channel-update profile-channels + manifest-entry-channel channel-news-entry? channel-news-entry-commit diff --git a/guix/scripts/describe.scm b/guix/scripts/describe.scm index c3667516eb..b7ec029ba8 100644 --- a/guix/scripts/describe.scm +++ b/guix/scripts/describe.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2018, 2019, 2020 Ludovic Courtès +;;; Copyright © 2018, 2019, 2020, 2021 Ludovic Courtès ;;; Copyright © 2018 Oleg Pykhalov ;;; Copyright © 2020 Ekaitz Zarraga ;;; @@ -237,23 +237,17 @@ way and displaying details about the channel's source code." (format #t " ~a ~a~%" (manifest-entry-name entry) (manifest-entry-version entry)) - (match (assq 'source (manifest-entry-properties entry)) - (('source ('repository ('version 0) - ('url url) - ('branch branch) - ('commit commit) - _ ...)) - (let ((channel (channel (name 'nameless) - (url url) - (branch branch) - (commit commit)))) - (format #t (G_ " repository URL: ~a~%") url) - (when branch - (format #t (G_ " branch: ~a~%") branch)) - (format #t (G_ " commit: ~a~%") - (if (supports-hyperlinks?) - (channel-commit-hyperlink channel commit) - commit)))) + (match (manifest-entry-channel entry) + ((? channel? channel) + (format #t (G_ " repository URL: ~a~%") + (channel-url channel)) + (when (channel-branch channel) + (format #t (G_ " branch: ~a~%") + (channel-branch channel))) + (format #t (G_ " commit: ~a~%") + (if (supports-hyperlinks?) + (channel-commit-hyperlink channel) + (channel-commit channel)))) (_ #f))) ;; Show most recently installed packages last. -- cgit v1.2.3 From 60d72f536437bcef2a4e02faa1fe0c8076049fcc Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Sun, 10 Jan 2021 21:51:18 +0100 Subject: channels: Add 'channel->code'. * guix/channels.scm (channel->code): New procedure, taken from... * guix/scripts/describe.scm (channel->sexp): ... here. Adjust callers accordingly. --- guix/channels.scm | 19 +++++++++++++++++++ guix/scripts/describe.scm | 22 +++------------------- 2 files changed, 22 insertions(+), 19 deletions(-) (limited to 'guix/channels.scm') diff --git a/guix/channels.scm b/guix/channels.scm index 743b4a25b7..cdef77637d 100644 --- a/guix/channels.scm +++ b/guix/channels.scm @@ -92,6 +92,7 @@ profile-channels manifest-entry-channel + channel->code channel-news-entry? channel-news-entry-commit @@ -957,6 +958,24 @@ PROFILE is not a profile created by 'guix pull', return the empty list." (reverse (manifest-entries (profile-manifest profile))))) +(define* (channel->code channel #:key (include-introduction? #t)) + "Return code (an sexp) to build CHANNEL. When INCLUDE-INTRODUCTION? is +true, include its introduction, if any." + (let ((intro (and include-introduction? + (channel-introduction channel)))) + `(channel + (name ',(channel-name channel)) + (url ,(channel-url channel)) + (commit ,(channel-commit channel)) + ,@(if intro + `((introduction (make-channel-introduction + ,(channel-introduction-first-signed-commit intro) + (openpgp-fingerprint + ,(openpgp-format-fingerprint + (channel-introduction-first-commit-signer + intro)))))) + '())))) + ;;; ;;; News. diff --git a/guix/scripts/describe.scm b/guix/scripts/describe.scm index b7ec029ba8..e47d207ee0 100644 --- a/guix/scripts/describe.scm +++ b/guix/scripts/describe.scm @@ -113,22 +113,6 @@ Display information about the channels currently in use.\n")) (_ (warning (G_ "'GUIX_PACKAGE_PATH' is set but it is not captured~%"))))))) -(define* (channel->sexp channel #:key (include-introduction? #t)) - (let ((intro (and include-introduction? - (channel-introduction channel)))) - `(channel - (name ',(channel-name channel)) - (url ,(channel-url channel)) - (commit ,(channel-commit channel)) - ,@(if intro - `((introduction (make-channel-introduction - ,(channel-introduction-first-signed-commit intro) - (openpgp-fingerprint - ,(openpgp-format-fingerprint - (channel-introduction-first-commit-signer - intro)))))) - '())))) - (define (channel->json channel) (scm->json-string (let ((intro (channel-introduction channel))) @@ -183,7 +167,7 @@ string is ~a.~%") (format #t (G_ " branch: ~a~%") (reference-shorthand head)) (format #t (G_ " commit: ~a~%") commit)) ('channels - (pretty-print `(list ,(channel->sexp (channel (name 'guix) + (pretty-print `(list ,(channel->code (channel (name 'guix) (url (dirname directory)) (commit commit)))))) ('json @@ -213,9 +197,9 @@ in the format specified by FMT." ('human (display-profile-content profile number)) ('channels - (pretty-print `(list ,@(map channel->sexp channels)))) + (pretty-print `(list ,@(map channel->code channels)))) ('channels-sans-intro - (pretty-print `(list ,@(map (cut channel->sexp <> + (pretty-print `(list ,@(map (cut channel->code <> #:include-introduction? #f) channels)))) ('json -- cgit v1.2.3 From aedbc5ff32a62f45aeed74c6833399a6cf2c22dc Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Sun, 10 Jan 2021 22:13:04 +0100 Subject: 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. --- build-aux/build-self.scm | 3 +++ doc/guix.texi | 26 ++++++++++++++++++++- guix/channels.scm | 1 + guix/describe.scm | 34 +++++++++++++++++++++++++-- guix/scripts/package.scm | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 122 insertions(+), 3 deletions(-) (limited to 'guix/channels.scm') diff --git a/build-aux/build-self.scm b/build-aux/build-self.scm index 4b6e2bfae5..d5bc5fb46e 100644 --- a/build-aux/build-self.scm +++ b/build-aux/build-self.scm @@ -245,8 +245,11 @@ interface (FFI) of Guile.") "Return a program that computes the derivation to build Guix from SOURCE." (define select? ;; Select every module but (guix config) and non-Guix modules. + ;; Also exclude (guix channels): it is autoloaded by (guix describe), but + ;; only for peripheral functionality. (match-lambda (('guix 'config) #f) + (('guix 'channels) #f) (('guix _ ...) #t) (('gnu _ ...) #t) (_ #f))) diff --git a/doc/guix.texi b/doc/guix.texi index e5872b5f24..9e62da438e 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -3616,7 +3616,31 @@ exactly what you specified. Keep in mind that a manifest is purely symbolic: it only contains package names and possibly versions, and their meaning varies over time. - +If you wish to ``pin'' channels to the revisions that were used to build +the profile(s), see @option{--export-channels} below. + +@cindex pinning, channel revisions of a profile +@item --export-channels +Write to standard output the list of channels used by the chosen +profile(s), in a format suitable for @command{guix pull --channels} or +@command{guix time-machine --channels} (@pxref{Channels}). + +Together with @option{--export-manifest}, this option provides +information allowing you to replicate the current profile +(@pxref{Replicating Guix}). + +However, note that the output of this command @emph{approximates} what +was actually used to build this profile. In particular, a single +profile might have been built from several different revisions of the +same channel. In that case, @option{--export-manifest} chooses the last +one and writes the list of other revisions in a comment. If you really +need to pick packages from different channel revisions, you can use +inferiors in your manifest to do so (@pxref{Inferiors}). + +Together with @option{--export-manifest}, this is a good starting point +if you are willing to migrate from the ``imperative'' model to the fully +declarative model consisting of a manifest file along with a channels +file pinning the exact channel revision(s) you want. @end table Finally, since @command{guix package} may actually start build diff --git a/guix/channels.scm b/guix/channels.scm index cdef77637d..e7e1eb6fd0 100644 --- a/guix/channels.scm +++ b/guix/channels.scm @@ -92,6 +92,7 @@ profile-channels manifest-entry-channel + sexp->channel channel->code channel-news-entry? diff --git a/guix/describe.scm b/guix/describe.scm index 05bf99eb58..ac89fc0d7c 100644 --- a/guix/describe.scm +++ b/guix/describe.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2018, 2019, 2020 Ludovic Courtès +;;; Copyright © 2018, 2019, 2020, 2021 Ludovic Courtès ;;; ;;; This file is part of GNU Guix. ;;; @@ -23,6 +23,7 @@ #:use-module ((guix utils) #:select (location-file)) #:use-module ((guix store) #:select (%store-prefix store-path?)) #:use-module ((guix config) #:select (%state-directory)) + #:autoload (guix channels) (sexp->channel) #:use-module (srfi srfi-1) #:use-module (ice-9 match) #:export (current-profile @@ -31,7 +32,8 @@ package-path-entries package-provenance - manifest-entry-with-provenance)) + manifest-entry-with-provenance + manifest-entry-provenance)) ;;; Commentary: ;;; @@ -166,3 +168,31 @@ there." (#f properties) (sexp `((provenance ,@sexp) ,@properties))))))))) + +(define (manifest-entry-provenance entry) + "Return the list of channels ENTRY comes from. Return the empty list if +that information is missing." + (match (assq-ref (manifest-entry-properties entry) 'provenance) + ((main extras ...) + ;; XXX: Until recently, channel sexps lacked the channel name. For + ;; entries created by 'manifest-entry-with-provenance', the first sexp + ;; is known to be the 'guix channel, and for the other ones, invent a + ;; fallback name (it's OK as the name is just a "pet name"). + (match (sexp->channel main 'guix) + (#f '()) + (channel + (let loop ((extras extras) + (counter 1) + (channels (list channel))) + (match extras + (() + (reverse channels)) + ((head . tail) + (let* ((name (string->symbol + (format #f "channel~a" counter))) + (extra (sexp->channel head name))) + (if extra + (loop tail (+ 1 counter) (cons extra channels)) + (loop tail counter channels))))))))) + (_ + '()))) diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm index 2b52016c67..8234a1703d 100644 --- a/guix/scripts/package.scm +++ b/guix/scripts/package.scm @@ -43,6 +43,7 @@ #:use-module (guix scripts build) #:use-module (guix transformations) #:use-module (guix describe) + #:autoload (guix channels) (channel-name channel-commit channel->code) #:autoload (guix store roots) (gc-roots user-owned?) #:use-module ((guix build utils) #:select (directory-exists? mkdir-p)) @@ -363,6 +364,54 @@ Alternately, see @command{guix package --search-paths -p ~s}.") (pretty-print exp port)) exp)))) +(define (channel=? a b) + (and (channel-commit a) (channel-commit b) + (string=? (channel-commit a) (channel-commit b)))) + +(define* (export-channels manifest + #:optional (port (current-output-port))) + (define channels + (delete-duplicates + (append-map manifest-entry-provenance (manifest-entries manifest)) + channel=?)) + + (define channel-names + (delete-duplicates (map channel-name channels))) + + (define table + (fold (lambda (channel table) + (vhash-consq (channel-name channel) channel table)) + vlist-null + channels)) + + (when (null? channels) + (leave (G_ "no provenance information for this profile~%"))) + + (format port (G_ "\ +;; This channel file can be passed to 'guix pull -C' or to +;; 'guix time-machine -C' to obtain the Guix revision that was +;; used to populate this profile.\n")) + (newline port) + (display "(list\n" port) + (for-each (lambda (name) + (define indent " ") + (match (vhash-foldq* cons '() name table) + ((channel extra ...) + (unless (null? extra) + (display indent port) + (format port (G_ "\ +;; Note: these other commits were also used to install \ +some of the packages in this profile:~%")) + (for-each (lambda (channel) + (format port "~a;; ~s~%" + indent (channel-commit channel))) + extra)) + (pretty-print (channel->code channel) port + #:per-line-prefix indent)))) + channel-names) + (display ")\n" port) + #t) + ;;; ;;; Command-line options. @@ -418,6 +467,8 @@ Install, remove, or upgrade packages in a single transaction.\n")) switch to a generation matching PATTERN")) (display (G_ " --export-manifest print a manifest for the chosen profile")) + (display (G_ " + --export-channels print channels for the chosen profile")) (display (G_ " -p, --profile=PROFILE use PROFILE instead of the user's default profile")) (display (G_ " @@ -556,6 +607,10 @@ kind of search path~%") (lambda (opt name arg result arg-handler) (values (cons `(query export-manifest) result) #f))) + (option '("export-channels") #f #f + (lambda (opt name arg result arg-handler) + (values (cons `(query export-channels) result) + #f))) (option '(#\p "profile") #t #f (lambda (opt name arg result arg-handler) (values (alist-cons 'profile (canonicalize-profile arg) @@ -882,6 +937,12 @@ processed, #f otherwise." (export-manifest manifest (current-output-port)) #t)) + (('export-channels) + (let ((manifest (concatenate-manifests + (map profile-manifest profiles)))) + (export-channels manifest (current-output-port)) + #t)) + (_ #f)))) -- cgit v1.2.3