* [bug#45919] [PATCH 2/8] utils: Add 'version-unique-prefix'.
2021-01-16 18:34 ` [bug#45919] [PATCH 1/8] profiles: Add 'manifest->code' Ludovic Courtès
@ 2021-01-16 18:34 ` Ludovic Courtès
2021-01-16 18:34 ` [bug#45919] [PATCH 3/8] guix package: Add '--export-manifest' Ludovic Courtès
` (5 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: Ludovic Courtès @ 2021-01-16 18:34 UTC (permalink / raw)
To: 45919
* guix/utils.scm (version-unique-prefix): New procedure.
* tests/utils.scm ("version-unique-prefix"): New test.
---
guix/utils.scm | 35 ++++++++++++++++++++++++++++++++++-
tests/utils.scm | 8 +++++++-
2 files changed, 41 insertions(+), 2 deletions(-)
diff --git a/guix/utils.scm b/guix/utils.scm
index f8b05e7e80..a85e2f495c 100644
--- a/guix/utils.scm
+++ b/guix/utils.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2013, 2014, 2015 Mark H Weaver <mhw@netris.org>
;;; Copyright © 2014 Eric Bavier <bavier@member.fsf.org>
;;; Copyright © 2014 Ian Denhardt <ian@zenhack.net>
@@ -88,6 +88,7 @@
version-major+minor+point
version-major+minor
version-major
+ version-unique-prefix
guile-version>?
version-prefix?
string-replace-substring
@@ -589,6 +590,38 @@ minor version numbers from version-string."
"Return the major version number as string from the version-string."
(version-prefix version-string 1))
+(define (version-unique-prefix version versions)
+ "Return the shortest version prefix to unambiguously identify VERSION among
+VERSIONS. For example:
+
+ (version-unique-prefix \"2.0\" '(\"3.0\" \"2.0\"))
+ => \"2\"
+
+ (version-unique-prefix \"2.2\" '(\"3.0.5\" \"2.0.9\" \"2.2.7\"))
+ => \"2.2\"
+
+ (version-unique-prefix \"27.1\" '(\"27.1\"))
+ => \"\"
+"
+ (define not-dot
+ (char-set-complement (char-set #\.)))
+
+ (define other-versions
+ (delete version versions))
+
+ (let loop ((prefix '())
+ (components (string-tokenize version not-dot)))
+ (define prefix-str
+ (string-join prefix "."))
+
+ (if (any (cut string-prefix? prefix-str <>) other-versions)
+ (match components
+ ((head . tail)
+ (loop `(,@prefix ,head) tail))
+ (()
+ version))
+ prefix-str)))
+
(define (version>? a b)
"Return #t when A denotes a version strictly newer than B."
(eq? '> (version-compare a b)))
diff --git a/tests/utils.scm b/tests/utils.scm
index 9bce446d98..62ec7e8b4c 100644
--- a/tests/utils.scm
+++ b/tests/utils.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2014 Eric Bavier <bavier@member.fsf.org>
;;; Copyright © 2016 Mathieu Lirzin <mthl@gnu.org>
;;;
@@ -78,6 +78,12 @@
(not (version-prefix? "4.1" "4.16.2"))
(not (version-prefix? "4.1" "4"))))
+(test-equal "version-unique-prefix"
+ '("2" "2.2" "")
+ (list (version-unique-prefix "2.0" '("3.0" "2.0"))
+ (version-unique-prefix "2.2" '("3.0.5" "2.0.9" "2.2.7"))
+ (version-unique-prefix "27.1" '("27.1"))))
+
(test-equal "string-tokenize*"
'(("foo")
("foo" "bar" "baz")
--
2.30.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [bug#45919] [PATCH 3/8] guix package: Add '--export-manifest'.
2021-01-16 18:34 ` [bug#45919] [PATCH 1/8] profiles: Add 'manifest->code' Ludovic Courtès
2021-01-16 18:34 ` [bug#45919] [PATCH 2/8] utils: Add 'version-unique-prefix' Ludovic Courtès
@ 2021-01-16 18:34 ` Ludovic Courtès
2021-01-16 18:34 ` [bug#45919] [PATCH 4/8] channels: Factorize 'manifest-entry-channel' and channel serialization Ludovic Courtès
` (4 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: Ludovic Courtès @ 2021-01-16 18:34 UTC (permalink / raw)
To: 45919
* guix/scripts/package.scm (export-manifest): New procedure.
(show-help, %options): Add '--export-manifest'.
(process-query): Honor it.
* guix/build/profiles.scm (build-profile): Mention it.
* tests/guix-package.sh: Test it.
* doc/guix.texi (Invoking guix package): Document it.
---
doc/guix.texi | 21 +++++++++++++++
guix/build/profiles.scm | 6 +++--
guix/scripts/package.scm | 57 +++++++++++++++++++++++++++++++++++++++-
tests/guix-package.sh | 10 ++++++-
4 files changed, 90 insertions(+), 4 deletions(-)
diff --git a/doc/guix.texi b/doc/guix.texi
index cea7f8a8cf..e524464e9f 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -3269,6 +3269,9 @@ objects, like this:
'("emacs" "guile@@2.2" "guile@@2.2:debug"))
@end lisp
+@xref{export-manifest, @option{--export-manifest}}, to learn how to
+obtain a manifest file from an existing profile.
+
@item --roll-back
@cindex rolling back
@cindex undoing transactions
@@ -3571,6 +3574,24 @@ zeroth generation is never deleted.
Note that deleting generations prevents rolling back to them.
Consequently, this command must be used with care.
+@cindex manifest, exporting
+@anchor{export-manifest}
+@item --export-manifest
+Write to standard output a manifest suitable for @option{--manifest}
+corresponding to the chosen profile(s).
+
+This option is meant to help you migrate from the ``imperative''
+operating mode---running @command{guix install}, @command{guix upgrade},
+etc.---to the declarative mode that @option{--manifest} offers.
+
+Be aware that the resulting manifest @emph{approximates} what your
+profile actually contains; for instance, depending on how your profile
+was created, it can refer to packages or package versions that are not
+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.
+
@end table
Finally, since @command{guix package} may actually start build
diff --git a/guix/build/profiles.scm b/guix/build/profiles.scm
index 67ee9b665a..b42f498a80 100644
--- a/guix/build/profiles.scm
+++ b/guix/build/profiles.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2015, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2015, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -169,7 +169,9 @@ SEARCH-PATHS."
(lambda (p)
(display "\
;; This file was automatically generated and is for internal use only.
-;; It cannot be passed to the '--manifest' option.\n\n"
+;; It cannot be passed to the '--manifest' option.
+;; Run 'guix package --export-manifest' if to export a file suitable
+;; for '--manifest'.\n\n"
p)
(pretty-print manifest p)))
diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm
index 6faf2adb7a..2b52016c67 100644
--- a/guix/scripts/package.scm
+++ b/guix/scripts/package.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org>
;;; Copyright © 2013, 2015 Mark H Weaver <mhw@netris.org>
;;; Copyright © 2014, 2016 Alex Kost <alezost@gmail.com>
@@ -48,6 +48,7 @@
#:select (directory-exists? mkdir-p))
#:use-module (ice-9 format)
#:use-module (ice-9 match)
+ #:autoload (ice-9 pretty-print) (pretty-print)
#:use-module (ice-9 regex)
#:use-module (ice-9 vlist)
#:use-module (srfi srfi-1)
@@ -320,6 +321,48 @@ GUIX_PROFILE=\"~a\"
Alternately, see @command{guix package --search-paths -p ~s}.")
profile profile)))))
+\f
+;;;
+;;; Export a manifest.
+;;;
+
+(define* (export-manifest manifest
+ #:optional (port (current-output-port)))
+ "Write to PORT a manifest corresponding to MANIFEST."
+ (define (version-spec entry)
+ (let ((name (manifest-entry-name entry)))
+ (match (map package-version (find-packages-by-name name))
+ ((_)
+ ;; A single version of NAME is available, so do not specify the
+ ;; version number, even if the available version doesn't match ENTRY.
+ "")
+ (versions
+ ;; If ENTRY uses the latest version, don't specify any version.
+ ;; Otherwise return the shortest unique version prefix. Note that
+ ;; this is based on the currently available packages, which could
+ ;; differ from the packages available in the revision that was used
+ ;; to build MANIFEST.
+ (let ((current (manifest-entry-version entry)))
+ (if (every (cut version>? current <>)
+ (delete current versions))
+ ""
+ (version-unique-prefix (manifest-entry-version entry)
+ versions)))))))
+
+ (match (manifest->code manifest
+ #:entry-package-version version-spec)
+ (('begin exp ...)
+ (format port (G_ "\
+;; This \"manifest\" file can be passed to 'guix package -m' to reproduce
+;; the content of your profile. This is \"symbolic\": it only specifies
+;; package names. To reproduce the exact same profile, you also need to
+;; capture the channels being used, as returned by \"guix describe\".
+;; See the \"Replicating Guix\" section in the manual.\n"))
+ (for-each (lambda (exp)
+ (newline port)
+ (pretty-print exp port))
+ exp))))
+
\f
;;;
;;; Command-line options.
@@ -373,6 +416,8 @@ Install, remove, or upgrade packages in a single transaction.\n"))
(display (G_ "
-S, --switch-generation=PATTERN
switch to a generation matching PATTERN"))
+ (display (G_ "
+ --export-manifest print a manifest for the chosen profile"))
(display (G_ "
-p, --profile=PROFILE use PROFILE instead of the user's default profile"))
(display (G_ "
@@ -507,6 +552,10 @@ kind of search path~%")
(values (cons `(query search-paths ,kind)
result)
#f))))
+ (option '("export-manifest") #f #f
+ (lambda (opt name arg result arg-handler)
+ (values (cons `(query export-manifest) result)
+ #f)))
(option '(#\p "profile") #t #f
(lambda (opt name arg result arg-handler)
(values (alist-cons 'profile (canonicalize-profile arg)
@@ -827,6 +876,12 @@ processed, #f otherwise."
(format #t "~{~a~%~}" settings)
#t))
+ (('export-manifest)
+ (let* ((manifest (concatenate-manifests
+ (map profile-manifest profiles))))
+ (export-manifest manifest (current-output-port))
+ #t))
+
(_ #f))))
diff --git a/tests/guix-package.sh b/tests/guix-package.sh
index 3e5fa71d20..7eaad6823f 100644
--- a/tests/guix-package.sh
+++ b/tests/guix-package.sh
@@ -1,5 +1,5 @@
# GNU Guix --- Functional package management for GNU
-# Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
+# Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
# Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org>
#
# This file is part of GNU Guix.
@@ -395,6 +395,14 @@ EOF
guix package --bootstrap -m "$module_dir/manifest.scm"
guix package -I | grep guile
test `guix package -I | wc -l` -eq 1
+
+# Export a manifest, instantiate it, and make sure we get the same profile.
+profile_directory="$(readlink -f "$default_profile")"
+guix package --export-manifest > "$tmpfile"
+guix package --rollback --bootstrap
+guix package --bootstrap -m "$tmpfile"
+test "$(readlink -f "$default_profile")" = "$profile_directory"
+
guix package --rollback --bootstrap
# Applying two manifests.
--
2.30.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [bug#45919] [PATCH 4/8] channels: Factorize 'manifest-entry-channel' and channel serialization.
2021-01-16 18:34 ` [bug#45919] [PATCH 1/8] profiles: Add 'manifest->code' Ludovic Courtès
2021-01-16 18:34 ` [bug#45919] [PATCH 2/8] utils: Add 'version-unique-prefix' Ludovic Courtès
2021-01-16 18:34 ` [bug#45919] [PATCH 3/8] guix package: Add '--export-manifest' Ludovic Courtès
@ 2021-01-16 18:34 ` Ludovic Courtès
2021-01-16 18:34 ` [bug#45919] [PATCH 5/8] channels: Add the channel name to channel sexps Ludovic Courtès
` (3 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: Ludovic Courtès @ 2021-01-16 18:34 UTC (permalink / raw)
To: 45919
* 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(-)
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 <ludo@gnu.org>
+;;; Copyright © 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2019 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
;;;
@@ -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)))))
--
2.30.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [bug#45919] [PATCH 5/8] channels: Add the channel name to channel sexps.
2021-01-16 18:34 ` [bug#45919] [PATCH 1/8] profiles: Add 'manifest->code' Ludovic Courtès
` (2 preceding siblings ...)
2021-01-16 18:34 ` [bug#45919] [PATCH 4/8] channels: Factorize 'manifest-entry-channel' and channel serialization Ludovic Courtès
@ 2021-01-16 18:34 ` Ludovic Courtès
2021-01-16 18:34 ` [bug#45919] [PATCH 6/8] guix describe: Use 'manifest-entry-channel' Ludovic Courtès
` (2 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: Ludovic Courtès @ 2021-01-16 18:34 UTC (permalink / raw)
To: 45919
* 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(-)
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
--
2.30.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [bug#45919] [PATCH 6/8] guix describe: Use 'manifest-entry-channel'.
2021-01-16 18:34 ` [bug#45919] [PATCH 1/8] profiles: Add 'manifest->code' Ludovic Courtès
` (3 preceding siblings ...)
2021-01-16 18:34 ` [bug#45919] [PATCH 5/8] channels: Add the channel name to channel sexps Ludovic Courtès
@ 2021-01-16 18:34 ` Ludovic Courtès
2021-01-16 18:34 ` [bug#45919] [PATCH 7/8] channels: Add 'channel->code' Ludovic Courtès
2021-01-16 18:34 ` [bug#45919] [PATCH 8/8] guix package: Add '--export-channels' Ludovic Courtès
6 siblings, 0 replies; 12+ messages in thread
From: Ludovic Courtès @ 2021-01-16 18:34 UTC (permalink / raw)
To: 45919
* 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(-)
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 <ludo@gnu.org>
+;;; Copyright © 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
;;; Copyright © 2020 Ekaitz Zarraga <ekaitz@elenq.tech>
;;;
@@ -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.
--
2.30.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [bug#45919] [PATCH 7/8] channels: Add 'channel->code'.
2021-01-16 18:34 ` [bug#45919] [PATCH 1/8] profiles: Add 'manifest->code' Ludovic Courtès
` (4 preceding siblings ...)
2021-01-16 18:34 ` [bug#45919] [PATCH 6/8] guix describe: Use 'manifest-entry-channel' Ludovic Courtès
@ 2021-01-16 18:34 ` Ludovic Courtès
2021-01-16 18:34 ` [bug#45919] [PATCH 8/8] guix package: Add '--export-channels' Ludovic Courtès
6 siblings, 0 replies; 12+ messages in thread
From: Ludovic Courtès @ 2021-01-16 18:34 UTC (permalink / raw)
To: 45919
* 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(-)
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))))))
+ '()))))
+
\f
;;;
;;; 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
--
2.30.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [bug#45919] [PATCH 8/8] guix package: Add '--export-channels'.
2021-01-16 18:34 ` [bug#45919] [PATCH 1/8] profiles: Add 'manifest->code' Ludovic Courtès
` (5 preceding siblings ...)
2021-01-16 18:34 ` [bug#45919] [PATCH 7/8] channels: Add 'channel->code' Ludovic Courtès
@ 2021-01-16 18:34 ` Ludovic Courtès
6 siblings, 0 replies; 12+ messages in thread
From: Ludovic Courtès @ 2021-01-16 18:34 UTC (permalink / raw)
To: 45919
* 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 | 24 ++++++++++++++++
guix/channels.scm | 1 +
guix/describe.scm | 34 ++++++++++++++++++++--
guix/scripts/package.scm | 61 ++++++++++++++++++++++++++++++++++++++++
5 files changed, 121 insertions(+), 2 deletions(-)
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 e524464e9f..cfb2f8a296 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -3591,7 +3591,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 <ludo@gnu.org>
+;;; Copyright © 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;;
;;; 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)
+
\f
;;;
;;; 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))))
--
2.30.0
^ permalink raw reply related [flat|nested] 12+ messages in thread