diff options
| author | Sergio Pastor Pérez <sergio.pastorperez@gmail.com> | 2026-06-06 14:13:26 +0200 |
|---|---|---|
| committer | Ludovic Courtès <ludo@gnu.org> | 2026-06-24 15:34:44 +0200 |
| commit | 2949c187f600841cdcddfc4f955506b34b79244f (patch) | |
| tree | 31fe464218cbd4ecd9877dd4114187fb4d9c4cd0 | |
| parent | 247245fbef1923a3bc17a23627e9c016900b4edc (diff) | |
pull: Add channel filtering options to the CLI.
* doc/guix.texi (Invoking guix pull): Document channel selection and exclusion
flags.
* etc/news.scm: Add entry.
* guix/scripts/pull.scm (show-help): Add help strings for channel selection
and exclusion flags.
(%options): Handle channel selection and exclusion flags.
(collect-alist-values): New procedure.
(options->channel-transformation): New procedure.
(channel-list): Implement channel selection and exclusion logic.
* guix/scripts/time-machine.scm (show-help): Add help strings for channel
selection and exclusion flags.
(%options): Handle channel selection and exclusion flags.
Change-Id: Ia22c5c38903ed1a2b9a9353ff94b70795820376d
Signed-off-by: Ludovic Courtès <ludo@gnu.org>
Modified-by: Ludovic Courtès <ludo@gnu.org>
| -rw-r--r-- | doc/guix.texi | 24 | ||||
| -rw-r--r-- | guix/scripts/pull.scm | 117 | ||||
| -rw-r--r-- | guix/scripts/time-machine.scm | 10 |
3 files changed, 140 insertions, 11 deletions
diff --git a/doc/guix.texi b/doc/guix.texi index 7950843c3c2..127c87f7f48 100644 --- a/doc/guix.texi +++ b/doc/guix.texi | |||
| @@ -140,7 +140,7 @@ Copyright @copyright{} 2024 Greg Hogan@* | |||
| 140 | Copyright @copyright{} 2025 Sören Tempel@* | 140 | Copyright @copyright{} 2025 Sören Tempel@* |
| 141 | Copyright @copyright{} 2025 Rostislav Svoboda@* | 141 | Copyright @copyright{} 2025 Rostislav Svoboda@* |
| 142 | Copyright @copyright{} 2025 Zacchaeus@* | 142 | Copyright @copyright{} 2025 Zacchaeus@* |
| 143 | Copyright @copyright{} 2025 Sergio Pastor Pérez@* | 143 | Copyright @copyright{} 2025, 2026 Sergio Pastor Pérez@* |
| 144 | Copyright @copyright{} 2024 Evgeny Pisemsky@* | 144 | Copyright @copyright{} 2024 Evgeny Pisemsky@* |
| 145 | Copyright @copyright{} 2025 jgart@* | 145 | Copyright @copyright{} 2025 jgart@* |
| 146 | Copyright @copyright{} 2025 Artur Wroblewski@* | 146 | Copyright @copyright{} 2025 Artur Wroblewski@* |
| @@ -5014,6 +5014,21 @@ understand the code of the channel files you use! | |||
| 5014 | Inhibit loading of the user and system channel files, | 5014 | Inhibit loading of the user and system channel files, |
| 5015 | @file{~/.config/guix/channels.scm} and @file{/etc/guix/channels.scm}. | 5015 | @file{~/.config/guix/channels.scm} and @file{/etc/guix/channels.scm}. |
| 5016 | 5016 | ||
| 5017 | @cindex pinning channels, with @command{guix pull} | ||
| 5018 | @anchor{pull-select} | ||
| 5019 | @item --select=@var{channel} | ||
| 5020 | @itemx -e | ||
| 5021 | Update only @var{channel}, keeping the commit of any other non-selected | ||
| 5022 | channel unchanged. In other words, any channel not selected with this | ||
| 5023 | option is effectively @dfn{pinned} to its current commit. This option | ||
| 5024 | can be repeated. | ||
| 5025 | |||
| 5026 | @item --exclude=@var{channel} | ||
| 5027 | @itemx -x | ||
| 5028 | Prevent @var{channel} from being updated, effectively @dfn{pinning} it | ||
| 5029 | to its current commit as shown by @command{guix describe}. All the | ||
| 5030 | other channels will be updated. This option can be repeated. | ||
| 5031 | |||
| 5017 | @cindex channel news | 5032 | @cindex channel news |
| 5018 | @item --news | 5033 | @item --news |
| 5019 | @itemx -N | 5034 | @itemx -N |
| @@ -5325,6 +5340,13 @@ Substitution,,, bash, The GNU Bash Reference Manual}): | |||
| 5325 | guix time-machine -C <(echo %default-channels) @dots{} | 5340 | guix time-machine -C <(echo %default-channels) @dots{} |
| 5326 | @end example | 5341 | @end example |
| 5327 | 5342 | ||
| 5343 | @item --select | ||
| 5344 | @itemx -e | ||
| 5345 | @itemx --exclude | ||
| 5346 | @itemx -x | ||
| 5347 | Select or exclude channels that need to be updated. @xref{pull-select}, for | ||
| 5348 | more info. | ||
| 5349 | |||
| 5328 | @end table | 5350 | @end table |
| 5329 | 5351 | ||
| 5330 | Note that @command{guix time-machine} can trigger builds of channels and | 5352 | Note that @command{guix time-machine} can trigger builds of channels and |
diff --git a/guix/scripts/pull.scm b/guix/scripts/pull.scm index 7fba0efa2a6..681354f6e3e 100644 --- a/guix/scripts/pull.scm +++ b/guix/scripts/pull.scm | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | ;;; Copyright © 2013-2015, 2017-2024, 2026 Ludovic Courtès <ludo@gnu.org> | 2 | ;;; Copyright © 2013-2015, 2017-2024, 2026 Ludovic Courtès <ludo@gnu.org> |
| 3 | ;;; Copyright © 2017 Marius Bakke <mbakke@fastmail.com> | 3 | ;;; Copyright © 2017 Marius Bakke <mbakke@fastmail.com> |
| 4 | ;;; Copyright © 2020, 2021 Tobias Geerinckx-Rice <me@tobias.gr> | 4 | ;;; Copyright © 2020, 2021 Tobias Geerinckx-Rice <me@tobias.gr> |
| 5 | ;;; Copyright © 2026 Sergio Pastor Pérez <sergio.pastorperez@gmail.com> | ||
| 5 | ;;; | 6 | ;;; |
| 6 | ;;; This file is part of GNU Guix. | 7 | ;;; This file is part of GNU Guix. |
| 7 | ;;; | 8 | ;;; |
| @@ -94,6 +95,10 @@ Download and deploy the latest version of Guix.\n")) | |||
| 94 | -q, --no-channel-files | 95 | -q, --no-channel-files |
| 95 | inhibit loading of user and system 'channels.scm'")) | 96 | inhibit loading of user and system 'channels.scm'")) |
| 96 | (display (G_ " | 97 | (display (G_ " |
| 98 | -e, --select=CHANNEL select CHANNEL to update")) | ||
| 99 | (display (G_ " | ||
| 100 | -x, --exclude=CHANNEL exclude CHANNEL from being updated")) | ||
| 101 | (display (G_ " | ||
| 97 | --url=URL download \"guix\" channel from the Git repository at URL")) | 102 | --url=URL download \"guix\" channel from the Git repository at URL")) |
| 98 | (display (G_ " | 103 | (display (G_ " |
| 99 | --commit=COMMIT download the specified \"guix\" channel COMMIT")) | 104 | --commit=COMMIT download the specified \"guix\" channel COMMIT")) |
| @@ -155,6 +160,12 @@ Download and deploy the latest version of Guix.\n")) | |||
| 155 | (option '(#\q "no-channel-files") #f #f | 160 | (option '(#\q "no-channel-files") #f #f |
| 156 | (lambda (opt name arg result) | 161 | (lambda (opt name arg result) |
| 157 | (alist-cons 'ignore-channel-files? #t result))) | 162 | (alist-cons 'ignore-channel-files? #t result))) |
| 163 | (option '(#\e "select") #t #f | ||
| 164 | (lambda (opt name arg result) | ||
| 165 | (alist-cons 'select (string->symbol arg) result))) | ||
| 166 | (option '(#\x "exclude") #t #f | ||
| 167 | (lambda (opt name arg result) | ||
| 168 | (alist-cons 'exclude (string->symbol arg) result))) | ||
| 158 | (option '(#\l "list-generations") #f #t | 169 | (option '(#\l "list-generations") #f #t |
| 159 | (lambda (opt name arg result) | 170 | (lambda (opt name arg result) |
| 160 | (cons `(query list-generations ,arg) | 171 | (cons `(query list-generations ,arg) |
| @@ -807,6 +818,69 @@ identifier." | |||
| 807 | (#f (leave (G_ "~a: invalid content SWHID~%") swhid)) | 818 | (#f (leave (G_ "~a: invalid content SWHID~%") swhid)) |
| 808 | (port port))) | 819 | (port port))) |
| 809 | 820 | ||
| 821 | (define (collect-alist-values key alist) | ||
| 822 | "Return a list of all values from ALIST that matches KEY." | ||
| 823 | (filter-map (match-lambda | ||
| 824 | ((k . value) | ||
| 825 | (and (eq? k key) value))) | ||
| 826 | alist)) | ||
| 827 | |||
| 828 | (define (options->channel-transformation opts) | ||
| 829 | "Return a procedure that, when passed a channel, applies the transformations | ||
| 830 | specified by OPTS and returns the resulting channel. OPTS must be a list of | ||
| 831 | symbol/string pairs such as: | ||
| 832 | |||
| 833 | ((select . \"channelA\") | ||
| 834 | (exclude . \"channelB\")) | ||
| 835 | |||
| 836 | Each symbol names a transformation and the corresponding string is an argument | ||
| 837 | to that transformation." | ||
| 838 | (define selected-channels | ||
| 839 | (collect-alist-values 'select opts)) | ||
| 840 | |||
| 841 | (define excluded-channels | ||
| 842 | (collect-alist-values 'exclude opts)) | ||
| 843 | |||
| 844 | (define current-channels | ||
| 845 | (let ((profile (or (assoc-ref opts 'profile) %current-profile))) | ||
| 846 | (profile-channels profile))) | ||
| 847 | |||
| 848 | (define (find-channel name lst) | ||
| 849 | (find (lambda (c) | ||
| 850 | (eq? (channel-name c) name)) | ||
| 851 | lst)) | ||
| 852 | |||
| 853 | (when (and (not (null? selected-channels)) | ||
| 854 | (not (null? excluded-channels))) | ||
| 855 | (raise | ||
| 856 | (condition | ||
| 857 | (&message | ||
| 858 | (message (G_ "mixing incompatible '--select' and '--exclude' options")))))) | ||
| 859 | |||
| 860 | (lambda (c) | ||
| 861 | (let* ((name (channel-name c)) | ||
| 862 | (raise-unknown (lambda () | ||
| 863 | (raise | ||
| 864 | (make-exception | ||
| 865 | (formatted-message | ||
| 866 | (G_ "unknown channel '~a': cannot \ | ||
| 867 | select/exclude a channel that has never been pulled") | ||
| 868 | name)))))) | ||
| 869 | (cond | ||
| 870 | ;; Selection. | ||
| 871 | ((not (null? selected-channels)) | ||
| 872 | (if (member name selected-channels) | ||
| 873 | (channel (inherit c) (commit #f)) ;unpin selected. | ||
| 874 | (or (find-channel name current-channels) ;pin others. | ||
| 875 | (raise-unknown)))) | ||
| 876 | ;; Exclusion. | ||
| 877 | ((not (null? excluded-channels)) | ||
| 878 | (if (member name excluded-channels) | ||
| 879 | (or (find-channel name current-channels) ;pin excluded. | ||
| 880 | (raise-unknown)) | ||
| 881 | (channel (inherit c) (commit #f)))) ;unpin others. | ||
| 882 | (else c))))) ;do nothing. | ||
| 883 | |||
| 810 | (define (channel-list opts) | 884 | (define (channel-list opts) |
| 811 | "Return the list of channels to use. If OPTS specify a channel file, | 885 | "Return the list of channels to use. If OPTS specify a channel file, |
| 812 | channels are read from there; otherwise, if ~/.config/guix/channels.scm | 886 | channels are read from there; otherwise, if ~/.config/guix/channels.scm |
| @@ -856,17 +930,40 @@ transformations specified in OPTS (resulting from '--url', '--commit', or | |||
| 856 | result) | 930 | result) |
| 857 | (leave (G_ "'~a' did not return a list of channels~%") file)))) | 931 | (leave (G_ "'~a' did not return a list of channels~%") file)))) |
| 858 | 932 | ||
| 933 | (define selected-channels | ||
| 934 | (collect-alist-values 'select opts)) | ||
| 935 | |||
| 936 | (define excluded-channels | ||
| 937 | (collect-alist-values 'exclude opts)) | ||
| 938 | |||
| 859 | (define channels | 939 | (define channels |
| 860 | (cond (file | 940 | (let* ((channels (cond (file |
| 861 | (load-channels file)) | 941 | (load-channels file)) |
| 862 | ((and (not ignore-channel-files?) | 942 | ((and (not ignore-channel-files?) |
| 863 | (file-exists? default-file)) | 943 | (file-exists? default-file)) |
| 864 | (load-channels default-file)) | 944 | (load-channels default-file)) |
| 865 | ((and (not ignore-channel-files?) | 945 | ((and (not ignore-channel-files?) |
| 866 | (file-exists? global-file)) | 946 | (file-exists? global-file)) |
| 867 | (load-channels global-file)) | 947 | (load-channels global-file)) |
| 868 | (else | 948 | (else |
| 869 | %default-channels))) | 949 | %default-channels)))) |
| 950 | ;; Validate options. | ||
| 951 | (let ((names (cond | ||
| 952 | ((not (null? selected-channels)) | ||
| 953 | selected-channels) | ||
| 954 | ((not (null? excluded-channels)) | ||
| 955 | excluded-channels) | ||
| 956 | (else '()))) | ||
| 957 | (valid-names (map channel-name channels))) | ||
| 958 | (unless (null? names) | ||
| 959 | (for-each | ||
| 960 | (lambda (name) | ||
| 961 | (unless (member name valid-names) | ||
| 962 | (leave (G_ "channel '~a' is missing from channel list~%") | ||
| 963 | name))) | ||
| 964 | names))) | ||
| 965 | |||
| 966 | (map (options->channel-transformation opts) channels))) | ||
| 870 | 967 | ||
| 871 | (define (environment-variable) | 968 | (define (environment-variable) |
| 872 | (match (getenv "GUIX_PULL_URL") | 969 | (match (getenv "GUIX_PULL_URL") |
diff --git a/guix/scripts/time-machine.scm b/guix/scripts/time-machine.scm index ffba7ffc355..030819f6052 100644 --- a/guix/scripts/time-machine.scm +++ b/guix/scripts/time-machine.scm | |||
| @@ -62,6 +62,10 @@ If COMMAND is not provided, print path to the time-machine profile.\n")) | |||
| 62 | -q, --no-channel-files | 62 | -q, --no-channel-files |
| 63 | inhibit loading of user and system 'channels.scm'")) | 63 | inhibit loading of user and system 'channels.scm'")) |
| 64 | (display (G_ " | 64 | (display (G_ " |
| 65 | -e, --select=CHANNEL select CHANNEL to update")) | ||
| 66 | (display (G_ " | ||
| 67 | -x, --exclude=CHANNEL exclude CHANNEL from being updated")) | ||
| 68 | (display (G_ " | ||
| 65 | --url=URL use the Git repository at URL")) | 69 | --url=URL use the Git repository at URL")) |
| 66 | (display (G_ " | 70 | (display (G_ " |
| 67 | --commit=COMMIT use the specified COMMIT")) | 71 | --commit=COMMIT use the specified COMMIT")) |
| @@ -98,6 +102,12 @@ If COMMAND is not provided, print path to the time-machine profile.\n")) | |||
| 98 | (option '(#\q "no-channel-files") #f #f | 102 | (option '(#\q "no-channel-files") #f #f |
| 99 | (lambda (opt name arg result) | 103 | (lambda (opt name arg result) |
| 100 | (alist-cons 'ignore-channel-files? #t result))) | 104 | (alist-cons 'ignore-channel-files? #t result))) |
| 105 | (option '(#\e "select") #t #f | ||
| 106 | (lambda (opt name arg result) | ||
| 107 | (alist-cons 'select (string->symbol arg) result))) | ||
| 108 | (option '(#\x "exclude") #t #f | ||
| 109 | (lambda (opt name arg result) | ||
| 110 | (alist-cons 'exclude (string->symbol arg) result))) | ||
| 101 | (option '("url") #t #f | 111 | (option '("url") #t #f |
| 102 | (lambda (opt name arg result) | 112 | (lambda (opt name arg result) |
| 103 | (alist-cons 'repository-url arg | 113 | (alist-cons 'repository-url arg |
