[bug#78580] pull: allow filtering which channels to pull from the CLI

Message ID e6dd2ed103f3474b5c1f66d8391b910a4dd81d67.1748106755.git.sergio.pastorperez@gmail.com
State New
Headers
Series [bug#78580] pull: allow filtering which channels to pull from the CLI |

Commit Message

Sergio Pastor Pérez May 24, 2025, 5:12 p.m. UTC
* guix/scripts/pull.scm (guix-pull): treat non-prefix CLI arguments as a list
of channels to pull.

Change-Id: I5d08c4b1cc84ab58a9c4e7600eb86468f92d10f0
---
 guix/scripts/pull.scm | 33 +++++++++++++++++++++++++++------
 1 file changed, 27 insertions(+), 6 deletions(-)


base-commit: 096dedd0bb13523002c814b001429c2f65b6f10d
  

Comments

Sergey Trofimov May 25, 2025, 7:06 a.m. UTC | #1
Hi Sergio,

Sergio Pastor Pérez <sergio.pastorperez@gmail.com> writes:

> * guix/scripts/pull.scm (guix-pull): treat non-prefix CLI arguments as a list
> of channels to pull.
>
> Change-Id: I5d08c4b1cc84ab58a9c4e7600eb86468f92d10f0
> ---
>  doc/guix.texi         | 11 +++++++++--
>  guix/scripts/pull.scm | 42 ++++++++++++++++++++++++++++++++++--------
>  2 files changed, 43 insertions(+), 10 deletions(-)
>
> diff --git a/doc/guix.texi b/doc/guix.texi
> index e4e2b853f1..e3de7ce47b 100644
> --- a/doc/guix.texi
> +++ b/doc/guix.texi
> @@ -4656,8 +4656,15 @@ Invoking guix pull
>  deleting /var/guix/profiles/per-user/charlie/current-guix-1-link
>  @end example
>  
> -The @command{guix pull} command is usually invoked with no arguments,
> -but it supports the following options:
> +The general syntax is:
> +
> +@example
> +guix pull [@var{options}] [@var{CHANNELS}@dots{}]
> +@end example
> +
> +The optional @var{channels} argument filters the list of pulled channels
> +to those whose names match the given list.  The channel named @dfn{guix}
> +is always pulled.
>

wouldn't it be better to let user decide whether `guix` channel has to
be pulled? The use-case is simple - I've made a change in my personal
channel and I want to apply it without risking to build missing /
download new substitutes of the main channel.
  
Sergio Pastor Pérez May 25, 2025, 7:22 a.m. UTC | #2
Hello Sergey.

Sergey Trofimov <sarg@sarg.org.ru> writes:
>> +The optional @var{channels} argument filters the list of pulled channels
>> +to those whose names match the given list.  The channel named @dfn{guix}
>> +is always pulled.
>>
>
> wouldn't it be better to let user decide whether `guix` channel has to
> be pulled? The use-case is simple - I've made a change in my personal
> channel and I want to apply it without risking to build missing /
> download new substitutes of the main channel.

Unfortunately this is not possible. That was my initial idea as well,
but the `guix' channel is required. If you allow it to compose the list
of channels to pull without the `guix' channel, you get this error:
--8<---------------cut here---------------start------------->8---
$ ./pre-inst-env guix pull rde
Updating channel 'rde' from Git repository at 'https://git.sr.ht/~abcdw/rde'...
Building from this channel:
  rde       https://git.sr.ht/~abcdw/rde        bf8f628
/home/pastor/projects/guix/puntos/dots/.config/guix/channels.scm:12:6: error: 'guix' channel is lacking
hint: Make sure your list of channels contains one channel named `guix' providing the core of Guix.
--8<---------------cut here---------------end--------------->8---

Once thing we could do, is to pin the Guix channel to the current commit
so it does not pull. I can try to implement that if you would like to
have that behaviour.
  
Sergey Trofimov May 25, 2025, 7:30 a.m. UTC | #3
Hi Sergio, 

Sergio Pastor Pérez <sergio.pastorperez@gmail.com> writes:

> Hello Sergey.
>
> Sergey Trofimov <sarg@sarg.org.ru> writes:
>>> +The optional @var{channels} argument filters the list of pulled channels
>>> +to those whose names match the given list.  The channel named @dfn{guix}
>>> +is always pulled.
>>>
>>
>> wouldn't it be better to let user decide whether `guix` channel has to
>> be pulled? The use-case is simple - I've made a change in my personal
>> channel and I want to apply it without risking to build missing /
>> download new substitutes of the main channel.
>
> Unfortunately this is not possible. That was my initial idea as well,
> but the `guix' channel is required. If you allow it to compose the list
> of channels to pull without the `guix' channel, you get this error:
> --8<---------------cut here---------------start------------->8---
> $ ./pre-inst-env guix pull rde
> Updating channel 'rde' from Git repository at 'https://git.sr.ht/~abcdw/rde'...
> Building from this channel:
>   rde       https://git.sr.ht/~abcdw/rde        bf8f628
> /home/pastor/projects/guix/puntos/dots/.config/guix/channels.scm:12:6: error: 'guix' channel is lacking
> hint: Make sure your list of channels contains one channel named `guix' providing the core of Guix.
> --8<---------------cut here---------------end--------------->8---
>
> Once thing we could do, is to pin the Guix channel to the current commit
> so it does not pull. I can try to implement that if you would like to
> have that behaviour.

It'd be nice, otherwise one would need to use `--commit=$(guix describe
...)` which might work, but is not that user friendly.
  
Sergio Pastor Pérez May 25, 2025, 8:23 a.m. UTC | #4
Sergey Trofimov <sarg@sarg.org.ru> writes:
>> Once thing we could do, is to pin the Guix channel to the current commit
>> so it does not pull. I can try to implement that if you would like to
>> have that behaviour.
>
> It'd be nice, otherwise one would need to use `--commit=$(guix describe
> ...)` which might work, but is not that user friendly.

Done[1] :)

Please let me know if you have any more feedback!

[1] https://issues.guix.gnu.org/78580#5
  
Sergey Trofimov May 25, 2025, 9:54 a.m. UTC | #5
Hi, 

Sergio Pastor Pérez <sergio.pastorperez@gmail.com> writes:

> Sergey Trofimov <sarg@sarg.org.ru> writes:
>>> Once thing we could do, is to pin the Guix channel to the current commit
>>> so it does not pull. I can try to implement that if you would like to
>>> have that behaviour.
>>
>> It'd be nice, otherwise one would need to use `--commit=$(guix describe
>> ...)` which might work, but is not that user friendly.
>
> Done[1] :)
>
> Please let me know if you have any more feedback!
>
> [1] https://issues.guix.gnu.org/78580#5

Ok, after a test I see it does something unexpected. I have 4 channels
in my system (guix/nonguix/sops/personal). After `guix pull nonguix`
I've ended up with a generation containing only guix and nonguix, other
channels were gone. If I get your intent right, then instead of
`filter-channels` you need to implement `unpin-channels`, so that the
new generation is built from the current channels and the ones specified
by the user are updated.
  
Sergio Pastor Pérez May 25, 2025, 10:20 a.m. UTC | #6
Sergey Trofimov <sarg@sarg.org.ru> writes:
> Hi, 
>
> Sergio Pastor Pérez <sergio.pastorperez@gmail.com> writes:
>
>> Sergey Trofimov <sarg@sarg.org.ru> writes:
>>>> Once thing we could do, is to pin the Guix channel to the current commit
>>>> so it does not pull. I can try to implement that if you would like to
>>>> have that behaviour.
>>>
>>> It'd be nice, otherwise one would need to use `--commit=$(guix describe
>>> ...)` which might work, but is not that user friendly.
>>
>> Done[1] :)
>>
>> Please let me know if you have any more feedback!
>>
>> [1] https://issues.guix.gnu.org/78580#5
>
> Ok, after a test I see it does something unexpected. I have 4 channels
> in my system (guix/nonguix/sops/personal). After `guix pull nonguix`
> I've ended up with a generation containing only guix and nonguix, other
> channels were gone. If I get your intent right, then instead of
> `filter-channels` you need to implement `unpin-channels`, so that the
> new generation is built from the current channels and the ones specified
> by the user are updated.

You are right. I did not realise that the internals of `guix pull' does
not take a list of channels to update but a whole channel profile to
deploy I will correct.

Thanks for pointing it out.
  
Sergio Pastor Pérez May 25, 2025, 11:03 a.m. UTC | #7
Sergey Trofimov <sarg@sarg.org.ru> writes:
> Hi, 
>
> Sergio Pastor Pérez <sergio.pastorperez@gmail.com> writes:
>
>> Sergey Trofimov <sarg@sarg.org.ru> writes:
>>>> Once thing we could do, is to pin the Guix channel to the current commit
>>>> so it does not pull. I can try to implement that if you would like to
>>>> have that behaviour.
>>>
>>> It'd be nice, otherwise one would need to use `--commit=$(guix describe
>>> ...)` which might work, but is not that user friendly.
>>
>> Done[1] :)
>>
>> Please let me know if you have any more feedback!
>>
>> [1] https://issues.guix.gnu.org/78580#5
>
> Ok, after a test I see it does something unexpected. I have 4 channels
> in my system (guix/nonguix/sops/personal). After `guix pull nonguix`
> I've ended up with a generation containing only guix and nonguix, other
> channels were gone. If I get your intent right, then instead of
> `filter-channels` you need to implement `unpin-channels`, so that the
> new generation is built from the current channels and the ones specified
> by the user are updated.

Alright, now you should get the expected behaviour[1]. Please let me
know if you see any problem.

[1] https://issues.guix.gnu.org/78580#9
  
Sergey Trofimov May 25, 2025, 2:20 p.m. UTC | #8
X-Draft-From: ("nndoc+ephemeral:bug#78580" 3)
Hi, 

Pérez <sergio.pastorperez@gmail.com> writes:

[...]
>
> Alright, now you should get the expected behaviour[1]. Please let me
> know if you see any problem.
>
> [1] https://issues.guix.gnu.org/78580#9

Confirming it works now correctly.
Date: Sun, 25 May 2025 16:20:59 +0200
  

Patch

diff --git a/guix/scripts/pull.scm b/guix/scripts/pull.scm
index 76aed0b5cc..61a68b8d70 100644
--- a/guix/scripts/pull.scm
+++ b/guix/scripts/pull.scm
@@ -839,21 +839,41 @@  (define (validate-cache-directory-ownership)
 (define-command (guix-pull . args)
   (synopsis "pull the latest revision of Guix")
 
-  (define (no-arguments arg _)
-    (leave (G_ "~A: extraneous argument~%") arg))
+  (define (filter-channels channels names)
+    "Filter CHANNELS whose name symbol is present in NAMES list.
+If NAMES is an empty list, don't filter anything.  Warn when a name is not
+available in the channels list."
+    (if (null? names)
+        channels
+        (let ((available-names (map channel-name
+                                    channels)))
+          (for-each (lambda (name)
+                      (unless (member name available-names)
+                        (warning (G_ "Channel '~a' not present in channel list~%")
+                                 name)))
+                    names)
+          (filter (lambda (ch)
+                    (member (channel-name ch)
+                            ;; A channel named guix must always be present.
+                            (cons* 'guix names)))
+                  channels))))
 
   (with-error-handling
     (with-git-error-handling
      (let* ((opts         (parse-command-line args %options
-                                              (list %default-options)
-                                              #:argument-handler no-arguments))
+                                              (list %default-options)))
             (substitutes? (assoc-ref opts 'substitutes?))
             (dry-run?     (assoc-ref opts 'dry-run?))
             (profile      (or (assoc-ref opts 'profile) %current-profile))
             (current-channels (profile-channels profile))
             (validate-pull    (assoc-ref opts 'validate-pull))
             (authenticate?    (assoc-ref opts 'authenticate-channels?))
-            (verify-certificate? (assoc-ref opts 'verify-certificate?)))
+            (verify-certificate? (assoc-ref opts 'verify-certificate?))
+            (selected-channels (filter-map
+                                (match-lambda
+                                  (('argument . name) (string->symbol name))
+                                  (_ #f))
+                                opts)))
        (cond
         ((assoc-ref opts 'query)
          (process-query opts profile))
@@ -877,7 +897,8 @@  (define-command (guix-pull . args)
                  (ensure-default-profile)
                  (honor-x509-certificates store)
 
-                 (let* ((channels (channel-list opts))
+                 (let* ((channels (filter-channels (channel-list opts)
+                                                   selected-channels))
                         (instances
                          (latest-channel-instances store channels
                                                    #:current-channels