GNU bug report logs - #72803
Add restic commands to the restic-guix package

Previous Next

Package: guix-patches;

Reported by: paul <goodoldpaul <at> autistici.org>

Date: Sun, 25 Aug 2024 13:57:02 UTC

Severity: normal

Done: paul <goodoldpaul <at> autistici.org>

To reply to this bug, email your comments to 72803 AT debbugs.gnu.org.
There is no need to reopen the bug first.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Sun, 25 Aug 2024 13:57:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to paul <goodoldpaul <at> autistici.org>:
New bug report received and forwarded. Copy sent to guix-patches <at> gnu.org. (Sun, 25 Aug 2024 13:57:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: paul <goodoldpaul <at> autistici.org>
To: guix-patches <at> gnu.org
Subject: Add restic commands to the restic-guix package
Date: Sun, 25 Aug 2024 15:54:55 +0200
[Message part 1 (text/plain, inline)]
Dear all,

I'm sending a patch adding some more restic commands to the restic-guix 
package provided by the restic-backup-service-type. It allows for 
commands like the following:

restic-guix restore remote-ftp -t `pwd`/restored -i .config/guix/channels.scm latest


Thank you for your work,

giacomo
[Message part 2 (text/html, inline)]

Information forwarded to pelzflorian <at> pelzflorian.de, ludo <at> gnu.org, matt <at> excalamus.com, maxim.cournoyer <at> gmail.com, guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Sun, 25 Aug 2024 13:58:02 GMT) Full text and rfc822 format available.

Message #8 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: Giacomo Leidi <goodoldpaul <at> autistici.org>
To: 72803 <at> debbugs.gnu.org
Cc: Giacomo Leidi <goodoldpaul <at> autistici.org>
Subject: [PATCH] services: restic-backup: Add more restic commands to the
 restic-guix package.
Date: Sun, 25 Aug 2024 15:56:41 +0200
This patch refactors the way restic commands can be added to the
restic-guix package with a more general approach.  This way new
subcommands for restic-guix can be added more easily.

* gnu/services/backup.scm (restic-backup-job-program): Generalize to
restic-action-program;
(restic-guix): allow for multiple actions.

* doc/guix.texi: Document it.

Change-Id: Ib2b5d74bebc51e35f1ae6e1aa32cedee0da59697
---
 doc/guix.texi           |  10 +++-
 gnu/services/backup.scm | 116 +++++++++++++++++++++++++++++-----------
 2 files changed, 93 insertions(+), 33 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index fcaf6b3fbb..9bbc2694ec 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -41589,7 +41589,15 @@ Miscellaneous Services
 configuration, without waiting for the scheduled job:
 
 @example
-restic-guix backup remote-ftp
+restic-guix run remote-ftp
+@end example
+
+All arguments passed after the job name will be passed to the underlying
+@code{restic} command, together with the @code{extra-flags} field from the
+@code{restic-backup-job} record:
+
+@example
+restic-guix restore remote-ftp -t `pwd`/restored -i .config/guix/channels.scm latest
 @end example
 
 @c %start of fragment
diff --git a/gnu/services/backup.scm b/gnu/services/backup.scm
index 555e9fc959..f304361263 100644
--- a/gnu/services/backup.scm
+++ b/gnu/services/backup.scm
@@ -46,7 +46,7 @@ (define-module (gnu services backup)
             restic-backup-configuration-fields
             restic-backup-configuration-jobs
 
-            restic-backup-job-program
+            restic-action-program
             restic-backup-job->mcron-job
             restic-guix
             restic-guix-wrapper-package
@@ -107,15 +107,18 @@ (define-configuration/no-serialization restic-backup-configuration
    (list-of-restic-backup-jobs '())
    "The list of backup jobs for the current system."))
 
-(define (restic-backup-job-program config)
+(define %restic-guix-supported-actions
+  '("backup" "mount" "prune" "restore" "run" "unlock"))
+
+(define* (restic-action-program config action)
   (let ((restic
          (file-append (restic-backup-job-restic config) "/bin/restic"))
+        (name
+         (restic-backup-job-name config))
         (repository
          (restic-backup-job-repository config))
         (password-file
          (restic-backup-job-password-file config))
-        (files
-         (restic-backup-job-files config))
         (extra-flags
          (restic-backup-job-extra-flags config))
         (verbose
@@ -123,55 +126,104 @@ (define (restic-backup-job-program config)
              '("--verbose")
              '())))
     (program-file
-     "restic-backup-job.scm"
+     (string-append "restic-" action "-" name "-program.scm")
      #~(begin
          (use-modules (ice-9 popen)
-                      (ice-9 rdelim))
+                      (ice-9 rdelim)
+                      (srfi srfi-1))
+
+         (define cli-arguments
+           (let* ((cl (command-line))
+                  (argc (length cl)))
+             (if (> argc 1)
+                 (take-right cl (- argc 1))
+                 '())))
+
          (setenv "RESTIC_PASSWORD"
                  (with-input-from-file #$password-file read-line))
 
-         (execlp #$restic #$restic #$@verbose
-                 "-r" #$repository
-                 #$@extra-flags
-                 "backup" #$@files)))))
+         (apply execlp `(#$restic #$restic #$@verbose
+                         "-r" #$repository
+                         #$@extra-flags
+                         #$action ,@cli-arguments))))))
+
+(define* (restic-guix jobs #:key (supported-actions
+                                  %restic-guix-supported-actions))
+  (define action-table
+    (map
+     (lambda (action)
+       (list action
+             (map (lambda (job)
+                    (list (restic-backup-job-name job)
+                          (restic-action-program job action)))
+                  jobs)))
+     ;; run is an alias for backup
+     (filter (lambda (a) (not (string=? a "run"))) supported-actions)))
 
-(define (restic-guix jobs)
   (program-file
    "restic-guix"
    #~(begin
        (use-modules (ice-9 match)
                     (srfi srfi-1))
 
+       (define action-table '#$action-table)
+       (define (assoc-table key table)
+         (first
+          (filter-map
+           (match-lambda
+             ((k v)
+              (and (string=? key k) v)))
+           table)))
        (define names '#$(map restic-backup-job-name jobs))
-       (define programs '#$(map restic-backup-job-program jobs))
+       (define backup-files
+         '#$(map restic-backup-job-files jobs))
+
+       (define (get-program action name)
+         (assoc-table name (assoc-table action action-table)))
 
-       (define (get-program name)
+       (define (get-backup-files name)
          (define idx
            (list-index (lambda (n) (string=? n name)) names))
-         (unless idx
-           (error (string-append "Unknown job name " name "\n\n"
-                                 "Possible job names are: "
-                                 (string-join names " "))))
-         (list-ref programs idx))
-
-       (define (backup args)
-         (define name (third args))
-         (define program (get-program name))
-         (execlp program program))
+         (list-ref backup-files idx))
 
        (define (validate-args args)
-         (when (not (>= (length args) 3))
-           (error (string-append "Usage: " (basename (car args))
-                                 " backup NAME"))))
+         (unless (>= (length args) 2)
+           (error (string-append "Usage: " (basename (first args))
+                                 " ACTION [ARGS]\n\nSupported actions are: "
+                                 #$(string-join supported-actions ", ") ".")))
+         (unless (member (second args) '#$supported-actions)
+           (error (string-append "Unknown action: " (second args) ". Supported"
+                                 "actions are: "
+                                 #$(string-join supported-actions ", ") "."))))
+
+       (define (validate-action-args action args)
+         (define argc (length args))
+         (when (not (>= argc 3))
+           (error (string-append "Usage: " (basename (first args))
+                                 " " action " JOB_NAME [ARGS]\n\nPossible job "
+                                 "names are: " (string-join names ", ") ".")))
+         (define job-name (third args))
+         (unless (member job-name names)
+           (error (string-append "Unknown job name: " job-name ". Possible job "
+                                 "names are: " (string-join names ", ") ".")))
+         (let ((program
+                (get-program
+                 ;; run is just backup called with restic-backup-job-files
+                 (if (string=? action "run") "backup" action)
+                 job-name))
+               (rest (if (> argc 3)
+                         (take-right args (- argc 3))
+                         '())))
+           (values program
+                   (if (string=? action "run")
+                       (append rest (get-backup-files job-name))
+                       rest))))
 
        (define (main args)
          (validate-args args)
          (define action (second args))
-         (match action
-           ("backup"
-            (backup args))
-           (_
-            (error (string-append "Unknown action: " action)))))
+         (define-values (program action-args) (validate-action-args action args))
+         (apply execlp (append (list program program) action-args)))
 
        (main (command-line)))))
 
@@ -183,7 +235,7 @@ (define (restic-backup-job->mcron-job config)
         (name
          (restic-backup-job-name config)))
     #~(job #$schedule
-           #$(string-append "restic-guix backup " name)
+           #$(string-append "restic-guix run " name)
            #:user #$user)))
 
 (define (restic-guix-wrapper-package jobs)

base-commit: d48af5cca84914d44b032d0bf0820640ebbe7a4b
-- 
2.45.2





Information forwarded to guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Mon, 02 Sep 2024 22:52:02 GMT) Full text and rfc822 format available.

Message #11 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: Fabio Natali <me <at> fabionatali.com>
To: 72803 <at> debbugs.gnu.org
Cc: Giacomo Leidi <goodoldpaul <at> autistici.org>
Subject: Re: Add restic commands to the restic-guix package
Date: Mon, 02 Sep 2024 23:50:17 +0100
Hi Giacomo,

Thanks for the patch and for the Restic service in the first place.

> diff --git a/doc/guix.texi b/doc/guix.texi

In the manual, consider the "extra-flags" section where we say:

> A list of values that are lowered to strings. These will be passed as
> command-line arguments to the current job restic backup invokation.

Perhaps this should now read "...the current job restic invokation..."
or "...the current restic invokation...", as the action is no longer
limited to "backup"?

>      (program-file
> -     "restic-backup-job.scm"
> +     (string-append "restic-" action "-" name "-program.scm")

Should 'name' be slug-ified in any way here? E.g. to avoid spaces,
capital letters, symbols that might be confusing when part of a file
name, etc.

> +  (define action-table
> +    (map
> +     (lambda (action)
> +       (list action
> +             (map (lambda (job)
> +                    (list (restic-backup-job-name job)
> +                          (restic-action-program job action)))
> +                  jobs)))
> +     ;; run is an alias for backup
> +     (filter (lambda (a) (not (string=? a "run"))) supported-actions)))

Could this be (marginally) simpler if we used two nested association
lists? That way, 'get-program' might simply use 'assoc-ref' (twice) and
'assoc-table' would be redundant?

Everything else looks fine to me. For what it's worth, here's how I've
been testing this.

Initialise a Restic repository as follows (warning: this overwrites
'/some-temporary-folder/password'):

--8<---------------cut here---------------start------------->8---
mkdir /some-temporary-folder
export RESTIC_PASSWORD=password
restic init --repo=/some-temporary-folder/repository
echo "${RESTIC_PASSWORD}" > /some-temporary-folder/password
--8<---------------cut here---------------end--------------->8---

Save the following system definition as
'/some-temporary-folder/config.scm'.

--8<---------------cut here---------------start------------->8---
(use-modules (gnu))
(use-package-modules backup)
(use-service-modules backup)

(operating-system
  (host-name "host")
  (bootloader (bootloader-configuration
               (bootloader grub-bootloader)
               (targets '("/dev/vda"))))
  (file-systems (cons (file-system
                        (device "/dev/vda1")
                        (mount-point "/")
                        (type "ext4"))
                      %base-file-systems))
  (packages (cons* restic %base-packages))
  (services (cons*
             (service restic-backup-service-type
                      (restic-backup-configuration
                       (jobs
                        (list (restic-backup-job
                               (name "test")
                               (repository "/restic/repository")
                               (password-file "/restic/password")
                               (schedule "* * * * *")
                               (files '("/root")))))))
             %base-services)))
--8<---------------cut here---------------end--------------->8---

From a Guix checkout where this patch has been applied, launch a test VM
as follows:

--8<---------------cut here---------------start------------->8---
$(./pre-inst-env guix system vm \
    --no-graphic \
    --share=/some-temporary-folder=/restic \
    /tmp/config.scm) \
    -m 2048 -smp 2
--8<---------------cut here---------------end--------------->8---

Log in as root, then check that the cron schedule is correctly defined
with 'herd schedule mcron', backup jobs should be scheduled every
minute.

Mount the Restic repository to see that snapshots have been actually
created every minute since boot. This can be done either on the guest or
on the host system. E.g. on the guest:

--8<---------------cut here---------------start------------->8---
restic mount \
    --password-file=/restic/password \
    --repo=/restic/repository \
    /mnt
--8<---------------cut here---------------end--------------->8---

Unfortunately I don't have commit access to push this, but hopefully
someone else will have a second look and push it soon.

It'd be nice to have a little test suite for this, but in case this can
be part of a future patch.

HTH, thanks, Fabio.




Information forwarded to guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Mon, 02 Sep 2024 23:04:01 GMT) Full text and rfc822 format available.

Message #14 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: Fabio Natali <me <at> fabionatali.com>
To: 72803 <at> debbugs.gnu.org
Cc: Giacomo Leidi <goodoldpaul <at> autistici.org>,
 Fabio Natali <me <at> fabionatali.com>
Subject: Re: Add restic commands to the restic-guix package
Date: Tue, 03 Sep 2024 00:01:53 +0100
> Mount the Restic repository to see that snapshots have been actually
> created every minute since boot.

Ha, sorry, I should have mentioned the revised 'restic-guix' script too,
which I tested with various commands and that also seemed to be working
fine.

Thanks, cheers, Fabio.




Information forwarded to guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Wed, 04 Sep 2024 22:29:02 GMT) Full text and rfc822 format available.

Message #17 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: paul <goodoldpaul <at> autistici.org>
To: Fabio Natali <me <at> fabionatali.com>, 72803 <at> debbugs.gnu.org
Subject: Re: Add restic commands to the restic-guix package
Date: Thu, 5 Sep 2024 00:19:30 +0200
Hi Fabio,

thank you very much for your detailed testing and review.

On 9/3/24 00:50, Fabio Natali wrote:
> Perhaps this should now read "...the current job restic invokation..."
> or "...the current restic invokation...", as the action is no longer
> limited to "backup"?

Definitely, good catch.

>>       (program-file
>> -     "restic-backup-job.scm"
>> +     (string-append "restic-" action "-" name "-program.scm")
> Should 'name' be slug-ified in any way here? E.g. to avoid spaces,
> capital letters, symbols that might be confusing when part of a file
> name, etc.
It should, right. I'll use the same approach used for the 
home-dotfiles-service-type (i.e. replacing illegal characters with "-").
>> +  (define action-table
>> +    (map
>> +     (lambda (action)
>> +       (list action
>> +             (map (lambda (job)
>> +                    (list (restic-backup-job-name job)
>> +                          (restic-action-program job action)))
>> +                  jobs)))
>> +     ;; run is an alias for backup
>> +     (filter (lambda (a) (not (string=? a "run"))) supported-actions)))
> Could this be (marginally) simpler if we used two nested association
> lists? That way, 'get-program' might simply use 'assoc-ref' (twice) and
> 'assoc-table' would be redundant?
I thought that as well, in fact my first implementation was with Guile's 
vhashes but it appears that neither alists nor vhashesh can be correctly 
ungexped, or at least I didn't find a way to do so. This is why I'm 
using plain lists and I need assoc-table. If you have some pointer where 
I could look how to lower alists it would be very helpful.
> It'd be nice to have a little test suite for this, but in case this can
> be part of a future patch.

There are already some tests Richard made at #71639 , once they get in 
I'll make sure to expand them for additional restic-guix subcommands.

Thank your for your review Fabio, I'm sending a patchset addressing your 
comments.

giacomo





Information forwarded to pelzflorian <at> pelzflorian.de, ludo <at> gnu.org, maxim.cournoyer <at> gmail.com, guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Wed, 04 Sep 2024 22:31:02 GMT) Full text and rfc822 format available.

Message #20 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: Giacomo Leidi <goodoldpaul <at> autistici.org>
To: 72803 <at> debbugs.gnu.org
Cc: Giacomo Leidi <goodoldpaul <at> autistici.org>
Subject: [PATCH v2] services: restic-backup: Add more restic commands to the
 restic-guix package.
Date: Thu,  5 Sep 2024 00:29:04 +0200
This patch refactors the way restic commands can be added to the
restic-guix package with a more general approach.  This way new
subcommands for restic-guix can be added more easily.

* gnu/services/backup.scm (restic-backup-job-program): Generalize to
restic-action-program;
(restic-guix): allow for multiple actions.

* doc/guix.texi: Document it.

Change-Id: Ib2b5d74bebc51e35f1ae6e1aa32cedee0da59697
---
 doc/guix.texi           |  13 +++-
 gnu/services/backup.scm | 127 +++++++++++++++++++++++++++++-----------
 2 files changed, 104 insertions(+), 36 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 16c697586a..8e3ecb80c2 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -41611,7 +41611,15 @@ Miscellaneous Services
 configuration, without waiting for the scheduled job:
 
 @example
-restic-guix backup remote-ftp
+restic-guix run remote-ftp
+@end example
+
+All arguments passed after the job name will be passed to the underlying
+@code{restic} command, together with the @code{extra-flags} field from the
+@code{restic-backup-job} record:
+
+@example
+restic-guix restore remote-ftp -t `pwd`/restored -i .config/guix/channels.scm latest
 @end example
 
 @c %start of fragment
@@ -41667,8 +41675,7 @@ Miscellaneous Services
 
 @item @code{extra-flags} (default: @code{'()}) (type: list-of-lowerables)
 A list of values that are lowered to strings.  These will be passed as
-command-line arguments to the current job @command{restic backup}
-invokation.
+command-line arguments to the current @command{restic} invokation.
 
 @end table
 
diff --git a/gnu/services/backup.scm b/gnu/services/backup.scm
index 555e9fc959..83d388143e 100644
--- a/gnu/services/backup.scm
+++ b/gnu/services/backup.scm
@@ -46,7 +46,7 @@ (define-module (gnu services backup)
             restic-backup-configuration-fields
             restic-backup-configuration-jobs
 
-            restic-backup-job-program
+            restic-action-program
             restic-backup-job->mcron-job
             restic-guix
             restic-guix-wrapper-package
@@ -97,7 +97,7 @@ (define-configuration/no-serialization restic-backup-job
   (extra-flags
    (list-of-lowerables '())
    "A list of values that are lowered to strings.  These will be passed as
-command-line arguments to the current job @command{restic backup} invokation."))
+command-line arguments to the current @command{restic} invokation."))
 
 (define list-of-restic-backup-jobs?
   (list-of restic-backup-job?))
@@ -107,15 +107,27 @@ (define-configuration/no-serialization restic-backup-configuration
    (list-of-restic-backup-jobs '())
    "The list of backup jobs for the current system."))
 
-(define (restic-backup-job-program config)
+(define %restic-guix-supported-actions
+  '("backup" "mount" "prune" "restore" "run" "snapshots" "unlock"))
+
+(define* (restic-action-program config action)
+  (define (format name)
+    ;; Remove from NAME characters that cannot be used in the store.
+    (string-map (lambda (chr)
+                  (if (and (char-set-contains? char-set:ascii chr)
+                           (char-set-contains? char-set:graphic chr)
+                           (not (memv chr '(#\. #\/ #\space))))
+                      chr
+                      #\-))
+                name))
   (let ((restic
          (file-append (restic-backup-job-restic config) "/bin/restic"))
+        (name
+         (restic-backup-job-name config))
         (repository
          (restic-backup-job-repository config))
         (password-file
          (restic-backup-job-password-file config))
-        (files
-         (restic-backup-job-files config))
         (extra-flags
          (restic-backup-job-extra-flags config))
         (verbose
@@ -123,55 +135,104 @@ (define (restic-backup-job-program config)
              '("--verbose")
              '())))
     (program-file
-     "restic-backup-job.scm"
+     (string-append "restic-" action "-" (format name) "-program.scm")
      #~(begin
          (use-modules (ice-9 popen)
-                      (ice-9 rdelim))
+                      (ice-9 rdelim)
+                      (srfi srfi-1))
+
+         (define cli-arguments
+           (let* ((cl (command-line))
+                  (argc (length cl)))
+             (if (> argc 1)
+                 (take-right cl (- argc 1))
+                 '())))
+
          (setenv "RESTIC_PASSWORD"
                  (with-input-from-file #$password-file read-line))
 
-         (execlp #$restic #$restic #$@verbose
-                 "-r" #$repository
-                 #$@extra-flags
-                 "backup" #$@files)))))
+         (apply execlp `(#$restic #$restic #$@verbose
+                         "-r" #$repository
+                         #$@extra-flags
+                         #$action ,@cli-arguments))))))
+
+(define* (restic-guix jobs #:key (supported-actions
+                                  %restic-guix-supported-actions))
+  (define action-table
+    (map
+     (lambda (action)
+       (list action
+             (map (lambda (job)
+                    (list (restic-backup-job-name job)
+                          (restic-action-program job action)))
+                  jobs)))
+     ;; run is an alias for backup
+     (filter (lambda (a) (not (string=? a "run"))) supported-actions)))
 
-(define (restic-guix jobs)
   (program-file
    "restic-guix"
    #~(begin
        (use-modules (ice-9 match)
                     (srfi srfi-1))
 
+       (define action-table '#$action-table)
+       (define (assoc-table key table)
+         (first
+          (filter-map
+           (match-lambda
+             ((k v)
+              (and (string=? key k) v)))
+           table)))
        (define names '#$(map restic-backup-job-name jobs))
-       (define programs '#$(map restic-backup-job-program jobs))
+       (define backup-files
+         '#$(map restic-backup-job-files jobs))
+
+       (define (get-program action name)
+         (assoc-table name (assoc-table action action-table)))
 
-       (define (get-program name)
+       (define (get-backup-files name)
          (define idx
            (list-index (lambda (n) (string=? n name)) names))
-         (unless idx
-           (error (string-append "Unknown job name " name "\n\n"
-                                 "Possible job names are: "
-                                 (string-join names " "))))
-         (list-ref programs idx))
-
-       (define (backup args)
-         (define name (third args))
-         (define program (get-program name))
-         (execlp program program))
+         (list-ref backup-files idx))
 
        (define (validate-args args)
-         (when (not (>= (length args) 3))
-           (error (string-append "Usage: " (basename (car args))
-                                 " backup NAME"))))
+         (unless (>= (length args) 2)
+           (error (string-append "Usage: " (basename (first args))
+                                 " ACTION [ARGS]\n\nSupported actions are: "
+                                 #$(string-join supported-actions ", ") ".")))
+         (unless (member (second args) '#$supported-actions)
+           (error (string-append "Unknown action: " (second args) ". Supported"
+                                 "actions are: "
+                                 #$(string-join supported-actions ", ") "."))))
+
+       (define (validate-action-args action args)
+         (define argc (length args))
+         (when (not (>= argc 3))
+           (error (string-append "Usage: " (basename (first args))
+                                 " " action " JOB_NAME [ARGS]\n\nPossible job "
+                                 "names are: " (string-join names ", ") ".")))
+         (define job-name (third args))
+         (unless (member job-name names)
+           (error (string-append "Unknown job name: " job-name ". Possible job "
+                                 "names are: " (string-join names ", ") ".")))
+         (let ((program
+                (get-program
+                 ;; run is just backup called with restic-backup-job-files
+                 (if (string=? action "run") "backup" action)
+                 job-name))
+               (rest (if (> argc 3)
+                         (take-right args (- argc 3))
+                         '())))
+           (values program
+                   (if (string=? action "run")
+                       (append rest (get-backup-files job-name))
+                       rest))))
 
        (define (main args)
          (validate-args args)
          (define action (second args))
-         (match action
-           ("backup"
-            (backup args))
-           (_
-            (error (string-append "Unknown action: " action)))))
+         (define-values (program action-args) (validate-action-args action args))
+         (apply execlp (append (list program program) action-args)))
 
        (main (command-line)))))
 
@@ -183,7 +244,7 @@ (define (restic-backup-job->mcron-job config)
         (name
          (restic-backup-job-name config)))
     #~(job #$schedule
-           #$(string-append "restic-guix backup " name)
+           #$(string-append "restic-guix run " name)
            #:user #$user)))
 
 (define (restic-guix-wrapper-package jobs)

base-commit: 9a03ab25ba889be27b34d5cebea05d5ac3b0a033
-- 
2.45.2





Information forwarded to guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Sun, 20 Oct 2024 22:59:02 GMT) Full text and rfc822 format available.

Message #23 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: paul <goodoldpaul <at> autistici.org>
To: 72803 <at> debbugs.gnu.org
Subject: Re: Add restic commands to the restic-guix package
Date: Mon, 21 Oct 2024 00:58:26 +0200
[Message part 1 (text/plain, inline)]
Hi Guix , this is a friendly ping. I'm sending a patchset rebased on 
current master.

Thank you for your work,

giacomo
[Message part 2 (text/html, inline)]

Information forwarded to ludo <at> gnu.org, maxim.cournoyer <at> gmail.com, guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Sun, 20 Oct 2024 23:00:02 GMT) Full text and rfc822 format available.

Message #26 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: Giacomo Leidi <goodoldpaul <at> autistici.org>
To: 72803 <at> debbugs.gnu.org
Cc: Giacomo Leidi <goodoldpaul <at> autistici.org>
Subject: [PATCH v2] services: restic-backup: Add more restic commands to the
 restic-guix package.
Date: Mon, 21 Oct 2024 00:58:31 +0200
This patch refactors the way restic commands can be added to the
restic-guix package with a more general approach.  This way new
subcommands for restic-guix can be added more easily.

* gnu/services/backup.scm (restic-backup-job-program): Generalize to
restic-action-program;
(restic-guix): allow for multiple actions.

* doc/guix.texi: Document it.

Change-Id: Ib2b5d74bebc51e35f1ae6e1aa32cedee0da59697
---
 doc/guix.texi           |  13 +++-
 gnu/services/backup.scm | 127 +++++++++++++++++++++++++++++-----------
 2 files changed, 104 insertions(+), 36 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index ac3a7adef0..f8a73abdce 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -41711,7 +41711,15 @@ Miscellaneous Services
 configuration, without waiting for the scheduled job:
 
 @example
-restic-guix backup remote-ftp
+restic-guix run remote-ftp
+@end example
+
+All arguments passed after the job name will be passed to the underlying
+@code{restic} command, together with the @code{extra-flags} field from the
+@code{restic-backup-job} record:
+
+@example
+restic-guix restore remote-ftp -t `pwd`/restored -i .config/guix/channels.scm latest
 @end example
 
 @c %start of fragment
@@ -41767,8 +41775,7 @@ Miscellaneous Services
 
 @item @code{extra-flags} (default: @code{'()}) (type: list-of-lowerables)
 A list of values that are lowered to strings.  These will be passed as
-command-line arguments to the current job @command{restic backup}
-invokation.
+command-line arguments to the current @command{restic} invokation.
 
 @end table
 
diff --git a/gnu/services/backup.scm b/gnu/services/backup.scm
index 555e9fc959..83d388143e 100644
--- a/gnu/services/backup.scm
+++ b/gnu/services/backup.scm
@@ -46,7 +46,7 @@ (define-module (gnu services backup)
             restic-backup-configuration-fields
             restic-backup-configuration-jobs
 
-            restic-backup-job-program
+            restic-action-program
             restic-backup-job->mcron-job
             restic-guix
             restic-guix-wrapper-package
@@ -97,7 +97,7 @@ (define-configuration/no-serialization restic-backup-job
   (extra-flags
    (list-of-lowerables '())
    "A list of values that are lowered to strings.  These will be passed as
-command-line arguments to the current job @command{restic backup} invokation."))
+command-line arguments to the current @command{restic} invokation."))
 
 (define list-of-restic-backup-jobs?
   (list-of restic-backup-job?))
@@ -107,15 +107,27 @@ (define-configuration/no-serialization restic-backup-configuration
    (list-of-restic-backup-jobs '())
    "The list of backup jobs for the current system."))
 
-(define (restic-backup-job-program config)
+(define %restic-guix-supported-actions
+  '("backup" "mount" "prune" "restore" "run" "snapshots" "unlock"))
+
+(define* (restic-action-program config action)
+  (define (format name)
+    ;; Remove from NAME characters that cannot be used in the store.
+    (string-map (lambda (chr)
+                  (if (and (char-set-contains? char-set:ascii chr)
+                           (char-set-contains? char-set:graphic chr)
+                           (not (memv chr '(#\. #\/ #\space))))
+                      chr
+                      #\-))
+                name))
   (let ((restic
          (file-append (restic-backup-job-restic config) "/bin/restic"))
+        (name
+         (restic-backup-job-name config))
         (repository
          (restic-backup-job-repository config))
         (password-file
          (restic-backup-job-password-file config))
-        (files
-         (restic-backup-job-files config))
         (extra-flags
          (restic-backup-job-extra-flags config))
         (verbose
@@ -123,55 +135,104 @@ (define (restic-backup-job-program config)
              '("--verbose")
              '())))
     (program-file
-     "restic-backup-job.scm"
+     (string-append "restic-" action "-" (format name) "-program.scm")
      #~(begin
          (use-modules (ice-9 popen)
-                      (ice-9 rdelim))
+                      (ice-9 rdelim)
+                      (srfi srfi-1))
+
+         (define cli-arguments
+           (let* ((cl (command-line))
+                  (argc (length cl)))
+             (if (> argc 1)
+                 (take-right cl (- argc 1))
+                 '())))
+
          (setenv "RESTIC_PASSWORD"
                  (with-input-from-file #$password-file read-line))
 
-         (execlp #$restic #$restic #$@verbose
-                 "-r" #$repository
-                 #$@extra-flags
-                 "backup" #$@files)))))
+         (apply execlp `(#$restic #$restic #$@verbose
+                         "-r" #$repository
+                         #$@extra-flags
+                         #$action ,@cli-arguments))))))
+
+(define* (restic-guix jobs #:key (supported-actions
+                                  %restic-guix-supported-actions))
+  (define action-table
+    (map
+     (lambda (action)
+       (list action
+             (map (lambda (job)
+                    (list (restic-backup-job-name job)
+                          (restic-action-program job action)))
+                  jobs)))
+     ;; run is an alias for backup
+     (filter (lambda (a) (not (string=? a "run"))) supported-actions)))
 
-(define (restic-guix jobs)
   (program-file
    "restic-guix"
    #~(begin
        (use-modules (ice-9 match)
                     (srfi srfi-1))
 
+       (define action-table '#$action-table)
+       (define (assoc-table key table)
+         (first
+          (filter-map
+           (match-lambda
+             ((k v)
+              (and (string=? key k) v)))
+           table)))
        (define names '#$(map restic-backup-job-name jobs))
-       (define programs '#$(map restic-backup-job-program jobs))
+       (define backup-files
+         '#$(map restic-backup-job-files jobs))
+
+       (define (get-program action name)
+         (assoc-table name (assoc-table action action-table)))
 
-       (define (get-program name)
+       (define (get-backup-files name)
          (define idx
            (list-index (lambda (n) (string=? n name)) names))
-         (unless idx
-           (error (string-append "Unknown job name " name "\n\n"
-                                 "Possible job names are: "
-                                 (string-join names " "))))
-         (list-ref programs idx))
-
-       (define (backup args)
-         (define name (third args))
-         (define program (get-program name))
-         (execlp program program))
+         (list-ref backup-files idx))
 
        (define (validate-args args)
-         (when (not (>= (length args) 3))
-           (error (string-append "Usage: " (basename (car args))
-                                 " backup NAME"))))
+         (unless (>= (length args) 2)
+           (error (string-append "Usage: " (basename (first args))
+                                 " ACTION [ARGS]\n\nSupported actions are: "
+                                 #$(string-join supported-actions ", ") ".")))
+         (unless (member (second args) '#$supported-actions)
+           (error (string-append "Unknown action: " (second args) ". Supported"
+                                 "actions are: "
+                                 #$(string-join supported-actions ", ") "."))))
+
+       (define (validate-action-args action args)
+         (define argc (length args))
+         (when (not (>= argc 3))
+           (error (string-append "Usage: " (basename (first args))
+                                 " " action " JOB_NAME [ARGS]\n\nPossible job "
+                                 "names are: " (string-join names ", ") ".")))
+         (define job-name (third args))
+         (unless (member job-name names)
+           (error (string-append "Unknown job name: " job-name ". Possible job "
+                                 "names are: " (string-join names ", ") ".")))
+         (let ((program
+                (get-program
+                 ;; run is just backup called with restic-backup-job-files
+                 (if (string=? action "run") "backup" action)
+                 job-name))
+               (rest (if (> argc 3)
+                         (take-right args (- argc 3))
+                         '())))
+           (values program
+                   (if (string=? action "run")
+                       (append rest (get-backup-files job-name))
+                       rest))))
 
        (define (main args)
          (validate-args args)
          (define action (second args))
-         (match action
-           ("backup"
-            (backup args))
-           (_
-            (error (string-append "Unknown action: " action)))))
+         (define-values (program action-args) (validate-action-args action args))
+         (apply execlp (append (list program program) action-args)))
 
        (main (command-line)))))
 
@@ -183,7 +244,7 @@ (define (restic-backup-job->mcron-job config)
         (name
          (restic-backup-job-name config)))
     #~(job #$schedule
-           #$(string-append "restic-guix backup " name)
+           #$(string-append "restic-guix run " name)
            #:user #$user)))
 
 (define (restic-guix-wrapper-package jobs)

base-commit: 5ab3c4c1e43ebb637551223791db0ea3519986e1
-- 
2.46.0





Information forwarded to guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Mon, 23 Dec 2024 11:25:02 GMT) Full text and rfc822 format available.

Message #29 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: paul <goodoldpaul <at> autistici.org>
To: 72803 <at> debbugs.gnu.org
Subject: Re: Add restic commands to the restic-guix package
Date: Mon, 23 Dec 2024 12:24:07 +0100
Hi,


I'm sending a v3 based on issue#75045.


Thank you for your work,

cheers

giacomo





Information forwarded to ludo <at> gnu.org, maxim.cournoyer <at> gmail.com, guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Mon, 23 Dec 2024 11:25:02 GMT) Full text and rfc822 format available.

Message #32 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: Giacomo Leidi <goodoldpaul <at> autistici.org>
To: 72803 <at> debbugs.gnu.org
Cc: Giacomo Leidi <goodoldpaul <at> autistici.org>
Subject: [PATCH v3] services: restic-backup: Add more restic commands to the
 restic-guix package.
Date: Mon, 23 Dec 2024 12:24:35 +0100
This patch refactors the way restic commands can be added to the
restic-guix package with a more general approach.  This way new
subcommands for restic-guix can be added more easily.

* gnu/services/backup.scm (restic-backup-job-program): Generalize to
restic-action-program;
(restic-guix): allow for multiple actions.

* doc/guix.texi: Document it.

Change-Id: Ib2b5d74bebc51e35f1ae6e1aa32cedee0da59697
---
 doc/guix.texi           |  20 ++++++-
 gnu/services/backup.scm | 125 ++++++++++++++++++++++++++++++----------
 2 files changed, 111 insertions(+), 34 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index f77b765933..aca87c7274 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -41999,6 +41999,23 @@ Miscellaneous Services
 sudo herd trigger remote-ftp-job
 @end example
 
+The @code{restic-backup-service-type} installs as well @code{restic-guix}
+to the system profile, a @code{restic} utility wrapper that allows for easier
+interaction with the Guix configured backup jobs.  For example the following
+could be used to list all the shapshots available on a given job's repository:
+
+@example
+restic-guix snapshots remote-ftp
+@end example
+
+All arguments passed after the job name will be passed to the underlying
+@code{restic} command, together with the @code{extra-flags} field from the
+@code{restic-backup-job} record:
+
+@example
+restic-guix restore remote-ftp -t `pwd`/restored -i .config/guix/channels.scm latest
+@end example
+
 @c %start of fragment
 
 @deftp {Data Type} restic-backup-configuration
@@ -42071,8 +42088,7 @@ Miscellaneous Services
 
 @item @code{extra-flags} (default: @code{'()}) (type: list-of-lowerables)
 A list of values that are lowered to strings.  These will be passed as
-command-line arguments to the current job @command{restic backup}
-invokation.
+command-line arguments to the current @command{restic} invokation.
 
 @end table
 
diff --git a/gnu/services/backup.scm b/gnu/services/backup.scm
index fc8934873b..8d1959f9bf 100644
--- a/gnu/services/backup.scm
+++ b/gnu/services/backup.scm
@@ -52,7 +52,7 @@ (define-module (gnu services backup)
             restic-backup-configuration-fields
             restic-backup-configuration-jobs
 
-            restic-backup-job-program
+            restic-action-program
             restic-backup-job->mcron-job
             restic-guix
             restic-guix-wrapper-package
@@ -128,7 +128,7 @@ (define-configuration/no-serialization restic-backup-job
   (extra-flags
    (list-of-lowerables '())
    "A list of values that are lowered to strings.  These will be passed as
-command-line arguments to the current job @command{restic backup} invokation."))
+command-line arguments to the current @command{restic} invokation."))
 
 (define list-of-restic-backup-jobs?
   (list-of restic-backup-job?))
@@ -138,15 +138,27 @@ (define-configuration/no-serialization restic-backup-configuration
    (list-of-restic-backup-jobs '())
    "The list of backup jobs for the current system."))
 
-(define (restic-backup-job-program config)
+(define %restic-guix-supported-actions
+  '("backup" "mount" "prune" "restore" "run" "snapshots" "unlock"))
+
+(define* (restic-action-program config action)
+  (define (format name)
+    ;; Remove from NAME characters that cannot be used in the store.
+    (string-map (lambda (chr)
+                  (if (and (char-set-contains? char-set:ascii chr)
+                           (char-set-contains? char-set:graphic chr)
+                           (not (memv chr '(#\. #\/ #\space))))
+                      chr
+                      #\-))
+                name))
   (let ((restic
          (file-append (restic-backup-job-restic config) "/bin/restic"))
+        (name
+         (restic-backup-job-name config))
         (repository
          (restic-backup-job-repository config))
         (password-file
          (restic-backup-job-password-file config))
-        (files
-         (restic-backup-job-files config))
         (extra-flags
          (restic-backup-job-extra-flags config))
         (verbose
@@ -154,55 +166,104 @@ (define (restic-backup-job-program config)
              '("--verbose")
              '())))
     (program-file
-     "restic-backup-job.scm"
+     (string-append "restic-" action "-" (format name) "-program.scm")
      #~(begin
          (use-modules (ice-9 popen)
-                      (ice-9 rdelim))
+                      (ice-9 rdelim)
+                      (srfi srfi-1))
+
+         (define cli-arguments
+           (let* ((cl (command-line))
+                  (argc (length cl)))
+             (if (> argc 1)
+                 (take-right cl (- argc 1))
+                 '())))
+
          (setenv "RESTIC_PASSWORD"
                  (with-input-from-file #$password-file read-line))
 
-         (execlp #$restic #$restic #$@verbose
-                 "-r" #$repository
-                 #$@extra-flags
-                 "backup" #$@files)))))
+         (apply execlp `(#$restic #$restic #$@verbose
+                         "-r" #$repository
+                         #$@extra-flags
+                         #$action ,@cli-arguments))))))
+
+(define* (restic-guix jobs #:key (supported-actions
+                                  %restic-guix-supported-actions))
+  (define action-table
+    (map
+     (lambda (action)
+       (list action
+             (map (lambda (job)
+                    (list (restic-backup-job-name job)
+                          (restic-action-program job action)))
+                  jobs)))
+     ;; run is an alias for backup
+     (filter (lambda (a) (not (string=? a "run"))) supported-actions)))
 
-(define (restic-guix jobs)
   (program-file
    "restic-guix"
    #~(begin
        (use-modules (ice-9 match)
                     (srfi srfi-1))
 
+       (define action-table '#$action-table)
+       (define (assoc-table key table)
+         (first
+          (filter-map
+           (match-lambda
+             ((k v)
+              (and (string=? key k) v)))
+           table)))
        (define names '#$(map restic-backup-job-name jobs))
-       (define programs '#$(map restic-backup-job-program jobs))
+       (define backup-files
+         '#$(map restic-backup-job-files jobs))
 
-       (define (get-program name)
+       (define (get-program action name)
+         (assoc-table name (assoc-table action action-table)))
+
+       (define (get-backup-files name)
          (define idx
            (list-index (lambda (n) (string=? n name)) names))
-         (unless idx
-           (error (string-append "Unknown job name " name "\n\n"
-                                 "Possible job names are: "
-                                 (string-join names " "))))
-         (list-ref programs idx))
-
-       (define (backup args)
-         (define name (third args))
-         (define program (get-program name))
-         (execlp program program))
+         (list-ref backup-files idx))
 
        (define (validate-args args)
-         (when (not (>= (length args) 3))
-           (error (string-append "Usage: " (basename (car args))
-                                 " backup NAME"))))
+         (unless (>= (length args) 2)
+           (error (string-append "Usage: " (basename (first args))
+                                 " ACTION [ARGS]\n\nSupported actions are: "
+                                 #$(string-join supported-actions ", ") ".")))
+         (unless (member (second args) '#$supported-actions)
+           (error (string-append "Unknown action: " (second args) ". Supported"
+                                 "actions are: "
+                                 #$(string-join supported-actions ", ") "."))))
+
+       (define (validate-action-args action args)
+         (define argc (length args))
+         (when (not (>= argc 3))
+           (error (string-append "Usage: " (basename (first args))
+                                 " " action " JOB_NAME [ARGS]\n\nPossible job "
+                                 "names are: " (string-join names ", ") ".")))
+         (define job-name (third args))
+         (unless (member job-name names)
+           (error (string-append "Unknown job name: " job-name ". Possible job "
+                                 "names are: " (string-join names ", ") ".")))
+         (let ((program
+                (get-program
+                 ;; run is just backup called with restic-backup-job-files
+                 (if (string=? action "run") "backup" action)
+                 job-name))
+               (rest (if (> argc 3)
+                         (take-right args (- argc 3))
+                         '())))
+           (values program
+                   (if (string=? action "run")
+                       (append rest (get-backup-files job-name))
+                       rest))))
 
        (define (main args)
          (validate-args args)
          (define action (second args))
-         (match action
-           ("backup"
-            (backup args))
-           (_
-            (error (string-append "Unknown action: " action)))))
+         (define-values (program action-args) (validate-action-args action args))
+         (apply execlp (append (list program program) action-args)))
 
        (main (command-line)))))
 

base-commit: f52cde358b609d18f43bf62f1dfe63835c1a57b9
-- 
2.46.0





Added blocking bug(s) 75045 Request was from paul <goodoldpaul <at> autistici.org> to control <at> debbugs.gnu.org. (Mon, 23 Dec 2024 11:27:02 GMT) Full text and rfc822 format available.

Information forwarded to guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Mon, 23 Dec 2024 11:33:02 GMT) Full text and rfc822 format available.

Message #37 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: paul <goodoldpaul <at> autistici.org>
To: 72803 <at> debbugs.gnu.org
Subject: Re: Add restic commands to the restic-guix package
Date: Mon, 23 Dec 2024 12:32:43 +0100
Actually I'm sending a v4 dropping the "run" subcommand from 
restic-guix, since now we can use


sudo herd trigger job-name


Apologies for the noise,

giacomo





Information forwarded to ludo <at> gnu.org, maxim.cournoyer <at> gmail.com, guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Mon, 23 Dec 2024 14:18:01 GMT) Full text and rfc822 format available.

Message #40 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: Giacomo Leidi <goodoldpaul <at> autistici.org>
To: 72803 <at> debbugs.gnu.org
Cc: Giacomo Leidi <goodoldpaul <at> autistici.org>
Subject: [PATCH v4] services: restic-backup: Add more restic commands to the
 restic-guix package.
Date: Mon, 23 Dec 2024 15:17:18 +0100
This patch refactors the way restic commands can be added to the
restic-guix package with a more general approach.  This way new
subcommands for restic-guix can be added more easily.

* gnu/services/backup.scm (restic-backup-job-program): Generalize to
restic-action-program;
(restic-guix): allow for multiple actions.

* doc/guix.texi: Document it.

Change-Id: Ib2b5d74bebc51e35f1ae6e1aa32cedee0da59697
---
 doc/guix.texi           |  20 ++++++-
 gnu/services/backup.scm | 129 ++++++++++++++++++++++++++++------------
 2 files changed, 109 insertions(+), 40 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index f77b765933..aca87c7274 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -41999,6 +41999,23 @@ Miscellaneous Services
 sudo herd trigger remote-ftp-job
 @end example
 
+The @code{restic-backup-service-type} installs as well @code{restic-guix}
+to the system profile, a @code{restic} utility wrapper that allows for easier
+interaction with the Guix configured backup jobs.  For example the following
+could be used to list all the shapshots available on a given job's repository:
+
+@example
+restic-guix snapshots remote-ftp
+@end example
+
+All arguments passed after the job name will be passed to the underlying
+@code{restic} command, together with the @code{extra-flags} field from the
+@code{restic-backup-job} record:
+
+@example
+restic-guix restore remote-ftp -t `pwd`/restored -i .config/guix/channels.scm latest
+@end example
+
 @c %start of fragment
 
 @deftp {Data Type} restic-backup-configuration
@@ -42071,8 +42088,7 @@ Miscellaneous Services
 
 @item @code{extra-flags} (default: @code{'()}) (type: list-of-lowerables)
 A list of values that are lowered to strings.  These will be passed as
-command-line arguments to the current job @command{restic backup}
-invokation.
+command-line arguments to the current @command{restic} invokation.
 
 @end table
 
diff --git a/gnu/services/backup.scm b/gnu/services/backup.scm
index fc8934873b..5c693660e3 100644
--- a/gnu/services/backup.scm
+++ b/gnu/services/backup.scm
@@ -52,11 +52,12 @@ (define-module (gnu services backup)
             restic-backup-configuration-fields
             restic-backup-configuration-jobs
 
-            restic-backup-job-program
-            restic-backup-job->mcron-job
+            restic-action-program
+            restic-backup-job->shepherd-service
             restic-guix
             restic-guix-wrapper-package
             restic-backup-service-profile
+            restic-backup-service-activation
             restic-backup-service-type))
 
 (define (gexp-or-string? value)
@@ -128,7 +129,7 @@ (define-configuration/no-serialization restic-backup-job
   (extra-flags
    (list-of-lowerables '())
    "A list of values that are lowered to strings.  These will be passed as
-command-line arguments to the current job @command{restic backup} invokation."))
+command-line arguments to the current @command{restic} invokation."))
 
 (define list-of-restic-backup-jobs?
   (list-of restic-backup-job?))
@@ -138,15 +139,27 @@ (define-configuration/no-serialization restic-backup-configuration
    (list-of-restic-backup-jobs '())
    "The list of backup jobs for the current system."))
 
-(define (restic-backup-job-program config)
+(define %restic-guix-supported-actions
+  '("backup" "mount" "prune" "restore" "snapshots" "unlock"))
+
+(define* (restic-action-program config action)
+  (define (format name)
+    ;; Remove from NAME characters that cannot be used in the store.
+    (string-map (lambda (chr)
+                  (if (and (char-set-contains? char-set:ascii chr)
+                           (char-set-contains? char-set:graphic chr)
+                           (not (memv chr '(#\. #\/ #\space))))
+                      chr
+                      #\-))
+                name))
   (let ((restic
          (file-append (restic-backup-job-restic config) "/bin/restic"))
+        (name
+         (restic-backup-job-name config))
         (repository
          (restic-backup-job-repository config))
         (password-file
          (restic-backup-job-password-file config))
-        (files
-         (restic-backup-job-files config))
         (extra-flags
          (restic-backup-job-extra-flags config))
         (verbose
@@ -154,55 +167,90 @@ (define (restic-backup-job-program config)
              '("--verbose")
              '())))
     (program-file
-     "restic-backup-job.scm"
+     (string-append "restic-" action "-" (format name) "-program.scm")
      #~(begin
          (use-modules (ice-9 popen)
-                      (ice-9 rdelim))
+                      (ice-9 rdelim)
+                      (srfi srfi-1))
+
+         (define cli-arguments
+           (let* ((cl (command-line))
+                  (argc (length cl)))
+             (if (> argc 1)
+                 (take-right cl (- argc 1))
+                 '())))
+
          (setenv "RESTIC_PASSWORD"
                  (with-input-from-file #$password-file read-line))
 
-         (execlp #$restic #$restic #$@verbose
-                 "-r" #$repository
-                 #$@extra-flags
-                 "backup" #$@files)))))
+         (apply execlp `(#$restic #$restic #$@verbose
+                         "-r" #$repository
+                         #$@extra-flags
+                         #$action ,@cli-arguments))))))
+
+(define* (restic-guix jobs #:key (supported-actions
+                                  %restic-guix-supported-actions))
+  (define action-table
+    (map
+     (lambda (action)
+       (list action
+             (map (lambda (job)
+                    (list (restic-backup-job-name job)
+                          (restic-action-program job action)))
+                  jobs)))
+     supported-actions))
 
-(define (restic-guix jobs)
   (program-file
    "restic-guix"
    #~(begin
        (use-modules (ice-9 match)
                     (srfi srfi-1))
 
+       (define action-table '#$action-table)
+       (define (assoc-table key table)
+         (first
+          (filter-map
+           (match-lambda
+             ((k v)
+              (and (string=? key k) v)))
+           table)))
        (define names '#$(map restic-backup-job-name jobs))
-       (define programs '#$(map restic-backup-job-program jobs))
 
-       (define (get-program name)
-         (define idx
-           (list-index (lambda (n) (string=? n name)) names))
-         (unless idx
-           (error (string-append "Unknown job name " name "\n\n"
-                                 "Possible job names are: "
-                                 (string-join names " "))))
-         (list-ref programs idx))
-
-       (define (backup args)
-         (define name (third args))
-         (define program (get-program name))
-         (execlp program program))
+       (define (get-program action name)
+         (assoc-table name (assoc-table action action-table)))
 
        (define (validate-args args)
-         (when (not (>= (length args) 3))
-           (error (string-append "Usage: " (basename (car args))
-                                 " backup NAME"))))
+         (unless (>= (length args) 2)
+           (error (string-append "Usage: " (basename (first args))
+                                 " ACTION [ARGS]\n\nSupported actions are: "
+                                 #$(string-join supported-actions ", ") ".")))
+         (unless (member (second args) '#$supported-actions)
+           (error (string-append "Unknown action: " (second args) ". Supported"
+                                 "actions are: "
+                                 #$(string-join supported-actions ", ") "."))))
+
+       (define (validate-action-args action args)
+         (define argc (length args))
+         (when (not (>= argc 3))
+           (error (string-append "Usage: " (basename (first args))
+                                 " " action " JOB_NAME [ARGS]\n\nPossible job "
+                                 "names are: " (string-join names ", ") ".")))
+         (define job-name (third args))
+         (unless (member job-name names)
+           (error (string-append "Unknown job name: " job-name ". Possible job "
+                                 "names are: " (string-join names ", ") ".")))
+         (let ((program
+                (get-program action job-name))
+               (rest (if (> argc 3)
+                         (take-right args (- argc 3))
+                         '())))
+           (values program rest)))
 
        (define (main args)
          (validate-args args)
          (define action (second args))
-         (match action
-           ("backup"
-            (backup args))
-           (_
-            (error (string-append "Unknown action: " action)))))
+         (define-values (program action-args) (validate-action-args action args))
+         (apply execlp (append (list program program) action-args)))
 
        (main (command-line)))))
 
@@ -216,6 +264,10 @@ (define (restic-job-log-file job)
 (define (restic-backup-job->shepherd-service config)
   (let ((schedule (restic-backup-job-schedule config))
         (name (restic-backup-job-name config))
+        (files (string-join
+                (map (lambda (f) (string-append "'" f "'"))
+                     (restic-backup-job-files config))
+                " "))
         (user (restic-backup-job-user config))
         (group (restic-backup-job-group config))
         (max-duration (restic-backup-job-max-duration config))
@@ -238,7 +290,8 @@ (define (restic-backup-job->shepherd-service config)
                            (list
                             (string-append #+bash-minimal "/bin/bash")
                             "-l" "-c"
-                            (string-append "restic-guix backup " #$name))
+                            (string-append
+                             "restic-guix backup " #$name " " #$files))
                            #:user #$user
                            #:group #$group
                            #:environment-variables
@@ -283,7 +336,7 @@ (define restic-backup-service-profile
          (restic-guix-wrapper-package jobs))
         '())))
 
-(define (restic-backup-activation config)
+(define (restic-backup-service-activation config)
   #~(for-each
      (lambda (log-file)
        (mkdir-p (dirname log-file)))
@@ -295,7 +348,7 @@ (define restic-backup-service-type
                 (extensions
                  (list
                   (service-extension activation-service-type
-                                     restic-backup-activation)
+                                     restic-backup-service-activation)
                   (service-extension profile-service-type
                                      restic-backup-service-profile)
                   (service-extension shepherd-root-service-type

base-commit: f52cde358b609d18f43bf62f1dfe63835c1a57b9
-- 
2.46.0





Information forwarded to guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Fri, 24 Jan 2025 23:48:01 GMT) Full text and rfc822 format available.

Message #43 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: paul <goodoldpaul <at> autistici.org>
To: 72803 <at> debbugs.gnu.org
Subject: Re: Add restic commands to the restic-guix package
Date: Sat, 25 Jan 2025 00:47:30 +0100
Hi Guix, I'm sending a v5 rebased on current master, thank you for your 
time!




Information forwarded to ludo <at> gnu.org, maxim.cournoyer <at> gmail.com, guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Fri, 24 Jan 2025 23:49:02 GMT) Full text and rfc822 format available.

Message #46 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: Giacomo Leidi <goodoldpaul <at> autistici.org>
To: 72803 <at> debbugs.gnu.org
Cc: Giacomo Leidi <goodoldpaul <at> autistici.org>
Subject: [PATCH v5] services: restic-backup: Add more restic commands to the
 restic-guix package.
Date: Sat, 25 Jan 2025 00:47:54 +0100
This patch refactors the way restic commands can be added to the
restic-guix package with a more general approach.  This way new
subcommands for restic-guix can be added more easily.

* gnu/services/backup.scm (restic-backup-job-program): Generalize to
restic-action-program;
(restic-guix): allow for multiple actions.

* doc/guix.texi: Document it.

Change-Id: Ib2b5d74bebc51e35f1ae6e1aa32cedee0da59697
---
 doc/guix.texi           |  20 ++++++-
 gnu/services/backup.scm | 129 ++++++++++++++++++++++++++++------------
 2 files changed, 109 insertions(+), 40 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 9a53bdcd374..716dd312cd2 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -42722,6 +42722,23 @@ Miscellaneous Services
 sudo herd trigger remote-ftp
 @end example
 
+The @code{restic-backup-service-type} installs as well @code{restic-guix}
+to the system profile, a @code{restic} utility wrapper that allows for easier
+interaction with the Guix configured backup jobs.  For example the following
+could be used to list all the shapshots available on a given job's repository:
+
+@example
+restic-guix snapshots remote-ftp
+@end example
+
+All arguments passed after the job name will be passed to the underlying
+@code{restic} command, together with the @code{extra-flags} field from the
+@code{restic-backup-job} record:
+
+@example
+restic-guix restore remote-ftp -t `pwd`/restored -i .config/guix/channels.scm latest
+@end example
+
 @c %start of fragment
 
 @deftp {Data Type} restic-backup-configuration
@@ -42795,8 +42812,7 @@ Miscellaneous Services
 
 @item @code{extra-flags} (default: @code{'()}) (type: list-of-lowerables)
 A list of values that are lowered to strings.  These will be passed as
-command-line arguments to the current job @command{restic backup}
-invokation.
+command-line arguments to the current @command{restic} invokation.
 
 @end table
 
diff --git a/gnu/services/backup.scm b/gnu/services/backup.scm
index 99a79ff5fbe..49655d1d930 100644
--- a/gnu/services/backup.scm
+++ b/gnu/services/backup.scm
@@ -52,11 +52,12 @@ (define-module (gnu services backup)
             restic-backup-configuration-fields
             restic-backup-configuration-jobs
 
-            restic-backup-job-program
-            restic-backup-job->mcron-job
+            restic-action-program
+            restic-backup-job->shepherd-service
             restic-guix
             restic-guix-wrapper-package
             restic-backup-service-profile
+            restic-backup-service-activation
             restic-backup-service-type))
 
 (define (gexp-or-string? value)
@@ -129,7 +130,7 @@ (define-configuration/no-serialization restic-backup-job
   (extra-flags
    (list-of-lowerables '())
    "A list of values that are lowered to strings.  These will be passed as
-command-line arguments to the current job @command{restic backup} invokation."))
+command-line arguments to the current @command{restic} invokation."))
 
 (define list-of-restic-backup-jobs?
   (list-of restic-backup-job?))
@@ -139,15 +140,27 @@ (define-configuration/no-serialization restic-backup-configuration
    (list-of-restic-backup-jobs '())
    "The list of backup jobs for the current system."))
 
-(define (restic-backup-job-program config)
+(define %restic-guix-supported-actions
+  '("backup" "mount" "prune" "restore" "snapshots" "unlock"))
+
+(define* (restic-action-program config action)
+  (define (format name)
+    ;; Remove from NAME characters that cannot be used in the store.
+    (string-map (lambda (chr)
+                  (if (and (char-set-contains? char-set:ascii chr)
+                           (char-set-contains? char-set:graphic chr)
+                           (not (memv chr '(#\. #\/ #\space))))
+                      chr
+                      #\-))
+                name))
   (let ((restic
          (file-append (restic-backup-job-restic config) "/bin/restic"))
+        (name
+         (restic-backup-job-name config))
         (repository
          (restic-backup-job-repository config))
         (password-file
          (restic-backup-job-password-file config))
-        (files
-         (restic-backup-job-files config))
         (extra-flags
          (restic-backup-job-extra-flags config))
         (verbose
@@ -155,55 +168,90 @@ (define (restic-backup-job-program config)
              '("--verbose")
              '())))
     (program-file
-     "restic-backup-job.scm"
+     (string-append "restic-" action "-" (format name) "-program.scm")
      #~(begin
          (use-modules (ice-9 popen)
-                      (ice-9 rdelim))
+                      (ice-9 rdelim)
+                      (srfi srfi-1))
+
+         (define cli-arguments
+           (let* ((cl (command-line))
+                  (argc (length cl)))
+             (if (> argc 1)
+                 (take-right cl (- argc 1))
+                 '())))
+
          (setenv "RESTIC_PASSWORD"
                  (with-input-from-file #$password-file read-line))
 
-         (execlp #$restic #$restic #$@verbose
-                 "-r" #$repository
-                 #$@extra-flags
-                 "backup" #$@files)))))
+         (apply execlp `(#$restic #$restic #$@verbose
+                         "-r" #$repository
+                         #$@extra-flags
+                         #$action ,@cli-arguments))))))
+
+(define* (restic-guix jobs #:key (supported-actions
+                                  %restic-guix-supported-actions))
+  (define action-table
+    (map
+     (lambda (action)
+       (list action
+             (map (lambda (job)
+                    (list (restic-backup-job-name job)
+                          (restic-action-program job action)))
+                  jobs)))
+     supported-actions))
 
-(define (restic-guix jobs)
   (program-file
    "restic-guix"
    #~(begin
        (use-modules (ice-9 match)
                     (srfi srfi-1))
 
+       (define action-table '#$action-table)
+       (define (assoc-table key table)
+         (first
+          (filter-map
+           (match-lambda
+             ((k v)
+              (and (string=? key k) v)))
+           table)))
        (define names '#$(map restic-backup-job-name jobs))
-       (define programs '#$(map restic-backup-job-program jobs))
 
-       (define (get-program name)
-         (define idx
-           (list-index (lambda (n) (string=? n name)) names))
-         (unless idx
-           (error (string-append "Unknown job name " name "\n\n"
-                                 "Possible job names are: "
-                                 (string-join names " "))))
-         (list-ref programs idx))
-
-       (define (backup args)
-         (define name (third args))
-         (define program (get-program name))
-         (execlp program program))
+       (define (get-program action name)
+         (assoc-table name (assoc-table action action-table)))
 
        (define (validate-args args)
-         (when (not (>= (length args) 3))
-           (error (string-append "Usage: " (basename (car args))
-                                 " backup NAME"))))
+         (unless (>= (length args) 2)
+           (error (string-append "Usage: " (basename (first args))
+                                 " ACTION [ARGS]\n\nSupported actions are: "
+                                 #$(string-join supported-actions ", ") ".")))
+         (unless (member (second args) '#$supported-actions)
+           (error (string-append "Unknown action: " (second args) ". Supported"
+                                 "actions are: "
+                                 #$(string-join supported-actions ", ") "."))))
+
+       (define (validate-action-args action args)
+         (define argc (length args))
+         (when (not (>= argc 3))
+           (error (string-append "Usage: " (basename (first args))
+                                 " " action " JOB_NAME [ARGS]\n\nPossible job "
+                                 "names are: " (string-join names ", ") ".")))
+         (define job-name (third args))
+         (unless (member job-name names)
+           (error (string-append "Unknown job name: " job-name ". Possible job "
+                                 "names are: " (string-join names ", ") ".")))
+         (let ((program
+                (get-program action job-name))
+               (rest (if (> argc 3)
+                         (take-right args (- argc 3))
+                         '())))
+           (values program rest)))
 
        (define (main args)
          (validate-args args)
          (define action (second args))
-         (match action
-           ("backup"
-            (backup args))
-           (_
-            (error (string-append "Unknown action: " action)))))
+         (define-values (program action-args) (validate-action-args action args))
+         (apply execlp (append (list program program) action-args)))
 
        (main (command-line)))))
 
@@ -217,6 +265,10 @@ (define (restic-job-log-file job)
 (define (restic-backup-job->shepherd-service config)
   (let ((schedule (restic-backup-job-schedule config))
         (name (restic-backup-job-name config))
+        (files (string-join
+                (map (lambda (f) (string-append "'" f "'"))
+                     (restic-backup-job-files config))
+                " "))
         (user (restic-backup-job-user config))
         (group (restic-backup-job-group config))
         (max-duration (restic-backup-job-max-duration config))
@@ -242,7 +294,8 @@ (define (restic-backup-job->shepherd-service config)
                             ;; backends require, such as rclone.
                             (string-append #+bash-minimal "/bin/bash")
                             "-l" "-c"
-                            (string-append "restic-guix backup " #$name))
+                            (string-append
+                             "restic-guix backup " #$name " " #$files))
                            #:user #$user
                            #:group #$group
                            #:environment-variables
@@ -287,7 +340,7 @@ (define restic-backup-service-profile
          (restic-guix-wrapper-package jobs))
         '())))
 
-(define (restic-backup-activation config)
+(define (restic-backup-service-activation config)
   #~(for-each
      (lambda (log-file)
        (mkdir-p (dirname log-file)))
@@ -299,7 +352,7 @@ (define restic-backup-service-type
                 (extensions
                  (list
                   (service-extension activation-service-type
-                                     restic-backup-activation)
+                                     restic-backup-service-activation)
                   (service-extension profile-service-type
                                      restic-backup-service-profile)
                   (service-extension shepherd-root-service-type

base-commit: 646202bf73f90de4f9b7cc66248b8f8e6e381014
-- 
2.47.1





Information forwarded to guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Sun, 09 Feb 2025 23:01:01 GMT) Full text and rfc822 format available.

Message #49 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: paul <goodoldpaul <at> autistici.org>
To: 72803 <at> debbugs.gnu.org
Subject: Re: Add restic commands to the restic-guix package
Date: Mon, 10 Feb 2025 00:00:41 +0100
Hi Guix,

I'm sending a v6. Compared to v5 it has the nice property of greatly 
simplifying the restic-guix script. Now there are no more multiple guile 
entrypoints (it used to be number of jobs * number of supported actions, 
so quite bad), there is only a single script which has embedded the 
information of all jobs, implements multiple actions and should be 
easily extendible to include more actions (like the init one proposed in 
https://issues.guix.gnu.org/71639 ).


Please let me know your thoughts on this!


Thank you all for your work,

giacomo





Information forwarded to ludo <at> gnu.org, maxim.cournoyer <at> gmail.com, guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Sun, 09 Feb 2025 23:02:02 GMT) Full text and rfc822 format available.

Message #52 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: Giacomo Leidi <goodoldpaul <at> autistici.org>
To: 72803 <at> debbugs.gnu.org
Cc: Giacomo Leidi <goodoldpaul <at> autistici.org>
Subject: [PATCH v6] services: restic-backup: Add more restic commands to the
 restic-guix package.
Date: Mon, 10 Feb 2025 00:01:19 +0100
This patch refactors the way restic commands can be added to the
restic-guix package with a more general approach.  This way new
subcommands for restic-guix can be added more easily.

* gnu/services/backup.scm (restic-backup-job-program): Generalize to
restic-program;
(restic-guix): allow for multiple actions.

* doc/guix.texi: Document it.

Change-Id: Ib2b5d74bebc51e35f1ae6e1aa32cedee0da59697
---
 doc/guix.texi           |  20 +++++-
 gnu/services/backup.scm | 138 ++++++++++++++++++++++++++--------------
 2 files changed, 108 insertions(+), 50 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index ce780682ed0..86582fb4785 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -42837,6 +42837,23 @@ Miscellaneous Services
 sudo herd trigger remote-ftp
 @end example
 
+The @code{restic-backup-service-type} installs as well @code{restic-guix}
+to the system profile, a @code{restic} utility wrapper that allows for easier
+interaction with the Guix configured backup jobs.  For example the following
+could be used to list all the shapshots available on a given job's repository:
+
+@example
+restic-guix snapshots remote-ftp
+@end example
+
+All arguments passed after the job name will be passed to the underlying
+@code{restic} command, together with the @code{extra-flags} field from the
+@code{restic-backup-job} record:
+
+@example
+restic-guix restore remote-ftp -t `pwd`/restored -i .config/guix/channels.scm latest
+@end example
+
 @c %start of fragment
 
 @deftp {Data Type} restic-backup-configuration
@@ -42910,8 +42927,7 @@ Miscellaneous Services
 
 @item @code{extra-flags} (default: @code{'()}) (type: list-of-lowerables)
 A list of values that are lowered to strings.  These will be passed as
-command-line arguments to the current job @command{restic backup}
-invokation.
+command-line arguments to the current @command{restic} invokation.
 
 @end table
 
diff --git a/gnu/services/backup.scm b/gnu/services/backup.scm
index 99a79ff5fbe..dcbed890e13 100644
--- a/gnu/services/backup.scm
+++ b/gnu/services/backup.scm
@@ -52,11 +52,12 @@ (define-module (gnu services backup)
             restic-backup-configuration-fields
             restic-backup-configuration-jobs
 
-            restic-backup-job-program
-            restic-backup-job->mcron-job
+            restic-program
+            restic-backup-job->shepherd-service
             restic-guix
             restic-guix-wrapper-package
             restic-backup-service-profile
+            restic-backup-service-activation
             restic-backup-service-type))
 
 (define (gexp-or-string? value)
@@ -129,7 +130,7 @@ (define-configuration/no-serialization restic-backup-job
   (extra-flags
    (list-of-lowerables '())
    "A list of values that are lowered to strings.  These will be passed as
-command-line arguments to the current job @command{restic backup} invokation."))
+command-line arguments to the current @command{restic} invokation."))
 
 (define list-of-restic-backup-jobs?
   (list-of restic-backup-job?))
@@ -139,71 +140,107 @@ (define-configuration/no-serialization restic-backup-configuration
    (list-of-restic-backup-jobs '())
    "The list of backup jobs for the current system."))
 
-(define (restic-backup-job-program config)
+(define %restic-guix-supported-actions
+  '("backup" "mount" "prune" "restore" "snapshots" "unlock"))
+
+(define (restic-backup-job->kv config)
   (let ((restic
          (file-append (restic-backup-job-restic config) "/bin/restic"))
+        (name
+         (restic-backup-job-name config))
         (repository
          (restic-backup-job-repository config))
         (password-file
          (restic-backup-job-password-file config))
-        (files
-         (restic-backup-job-files config))
         (extra-flags
          (restic-backup-job-extra-flags config))
-        (verbose
+        (verbose?
          (if (restic-backup-job-verbose? config)
              '("--verbose")
              '())))
-    (program-file
-     "restic-backup-job.scm"
-     #~(begin
-         (use-modules (ice-9 popen)
-                      (ice-9 rdelim))
-         (setenv "RESTIC_PASSWORD"
-                 (with-input-from-file #$password-file read-line))
+    #~(list #$name (list #$restic #$repository #$password-file
+                         (list #$@verbose?) (list #$@extra-flags)))))
+
+(define (restic-program config)
+  #~(lambda* (action action-args job-restic repository password-file verbose? extra-flags)
+      (use-modules (ice-9 format)
+                   (ice-9 popen)
+                   (ice-9 rdelim))
+      ;; This can be extended later, i.e. to have a
+      ;; centrally defined restic package.
+      ;; See https://issues.guix.gnu.org/71639
+      (define restic job-restic)
+
+      (define command
+        `(,restic ,@verbose?
+          "-r" ,repository
+          ,@extra-flags
+          ,action ,@action-args))
+
+      (setenv "RESTIC_PASSWORD"
+              (with-input-from-file password-file read-line))
 
-         (execlp #$restic #$restic #$@verbose
-                 "-r" #$repository
-                 #$@extra-flags
-                 "backup" #$@files)))))
+      (when (> (length verbose?) 0)
+        (format #t "Running~{ ~a~}~%" command))
 
-(define (restic-guix jobs)
+      (apply execlp `(,restic ,@command))))
+
+(define* (restic-guix config #:key (supported-actions
+                                    %restic-guix-supported-actions))
   (program-file
    "restic-guix"
    #~(begin
        (use-modules (ice-9 match)
                     (srfi srfi-1))
 
-       (define names '#$(map restic-backup-job-name jobs))
-       (define programs '#$(map restic-backup-job-program jobs))
-
-       (define (get-program name)
-         (define idx
-           (list-index (lambda (n) (string=? n name)) names))
-         (unless idx
-           (error (string-append "Unknown job name " name "\n\n"
-                                 "Possible job names are: "
-                                 (string-join names " "))))
-         (list-ref programs idx))
+       (define jobs
+         (list
+          #$@(map restic-backup-job->kv
+                  (restic-backup-configuration-jobs config))))
+       (define names (map first jobs))
+       (define (get-job key)
+         (first
+          (filter-map
+           (match-lambda
+             ((k v)
+              (and (string=? key k) v)))
+           jobs)))
 
-       (define (backup args)
-         (define name (third args))
-         (define program (get-program name))
-         (execlp program program))
+       (define restic-exec
+         #$(restic-program config))
 
        (define (validate-args args)
-         (when (not (>= (length args) 3))
-           (error (string-append "Usage: " (basename (car args))
-                                 " backup NAME"))))
+         (unless (>= (length args) 2)
+           (error (string-append "Usage: " (basename (first args))
+                                 " ACTION [ARGS]\n\nSupported actions are: "
+                                 #$(string-join supported-actions ", ") ".")))
+         (unless (member (second args) '#$supported-actions)
+           (error (string-append "Unknown action: " (second args) ". Supported"
+                                 "actions are: "
+                                 #$(string-join supported-actions ", ") "."))))
+
+       (define (validate-action-args action args)
+         (define argc (length args))
+         (when (not (>= argc 3))
+           (error (string-append "Usage: " (basename (first args))
+                                 " " action " JOB_NAME [ARGS]\n\nPossible job "
+                                 "names are: " (string-join names ", ") ".")))
+         (define job-name (third args))
+         (unless (member job-name names)
+           (error (string-append "Unknown job name: " job-name ". Possible job "
+                                 "names are: " (string-join names ", ") ".")))
+         (let ((job (get-job job-name))
+               (action-args
+                (if (> argc 3)
+                    (take-right args (- argc 3))
+                    '())))
+           (values job action-args)))
 
        (define (main args)
          (validate-args args)
          (define action (second args))
-         (match action
-           ("backup"
-            (backup args))
-           (_
-            (error (string-append "Unknown action: " action)))))
+         (define-values (job action-args) (validate-action-args action args))
+         (apply restic-exec `(,action ,action-args ,@job)))
 
        (main (command-line)))))
 
@@ -217,6 +254,10 @@ (define (restic-job-log-file job)
 (define (restic-backup-job->shepherd-service config)
   (let ((schedule (restic-backup-job-schedule config))
         (name (restic-backup-job-name config))
+        (files (string-join
+                (map (lambda (f) (string-append "'" f "'"))
+                     (restic-backup-job-files config))
+                " "))
         (user (restic-backup-job-user config))
         (group (restic-backup-job-group config))
         (max-duration (restic-backup-job-max-duration config))
@@ -242,7 +283,8 @@ (define (restic-backup-job->shepherd-service config)
                             ;; backends require, such as rclone.
                             (string-append #+bash-minimal "/bin/bash")
                             "-l" "-c"
-                            (string-append "restic-guix backup " #$name))
+                            (string-append
+                             "restic-guix backup " #$name " " #$files))
                            #:user #$user
                            #:group #$group
                            #:environment-variables
@@ -261,11 +303,11 @@ (define (restic-backup-job->shepherd-service config)
 without waiting for the scheduled time.")
                                       (procedure #~trigger-timer)))))))
 
-(define (restic-guix-wrapper-package jobs)
+(define (restic-guix-wrapper-package config)
   (package
     (name "restic-backup-service-wrapper")
     (version "0.0.0")
-    (source (restic-guix jobs))
+    (source (restic-guix config))
     (build-system copy-build-system)
     (arguments
      (list #:install-plan #~'(("./" "/bin"))))
@@ -284,10 +326,10 @@ (define restic-backup-service-profile
     (define jobs (restic-backup-configuration-jobs config))
     (if (> (length jobs) 0)
         (list
-         (restic-guix-wrapper-package jobs))
+         (restic-guix-wrapper-package config))
         '())))
 
-(define (restic-backup-activation config)
+(define (restic-backup-service-activation config)
   #~(for-each
      (lambda (log-file)
        (mkdir-p (dirname log-file)))
@@ -299,7 +341,7 @@ (define restic-backup-service-type
                 (extensions
                  (list
                   (service-extension activation-service-type
-                                     restic-backup-activation)
+                                     restic-backup-service-activation)
                   (service-extension profile-service-type
                                      restic-backup-service-profile)
                   (service-extension shepherd-root-service-type

base-commit: e27e63e6fe72d3a6cb6a8755f290ec710d339a9a
-- 
2.48.1





Added indication that bug 72803 blocks76169 Request was from paul <goodoldpaul <at> autistici.org> to control <at> debbugs.gnu.org. (Mon, 10 Feb 2025 00:11:02 GMT) Full text and rfc822 format available.

Information forwarded to guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Sun, 23 Feb 2025 16:42:01 GMT) Full text and rfc822 format available.

Message #57 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: paul <goodoldpaul <at> autistici.org>
To: 72803 <at> debbugs.gnu.org
Subject: Re: Add restic commands to the restic-guix package
Date: Sun, 23 Feb 2025 17:41:09 +0100
Hi,

I'm sending a v6 rebased on current master. Compared to v5 it adds 
support for the restic ls an restic list commands.

cheers,


giacomo





Information forwarded to guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Sun, 23 Feb 2025 16:44:01 GMT) Full text and rfc822 format available.

Message #60 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: paul <goodoldpaul <at> autistici.org>
To: 72803 <at> debbugs.gnu.org
Subject: Re: Add restic commands to the restic-guix package
Date: Sun, 23 Feb 2025 17:43:15 +0100
Hi again, sorry for the noise, I meant v7 :)

Thank you for your work!

giacomo




Information forwarded to ludo <at> gnu.org, maxim.cournoyer <at> gmail.com, guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Sun, 23 Feb 2025 16:45:02 GMT) Full text and rfc822 format available.

Message #63 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: Giacomo Leidi <goodoldpaul <at> autistici.org>
To: 72803 <at> debbugs.gnu.org
Cc: Giacomo Leidi <goodoldpaul <at> autistici.org>
Subject: [PATCH v7] services: restic-backup: Add more restic commands to the
 restic-guix package.
Date: Sun, 23 Feb 2025 17:43:24 +0100
This patch refactors the way restic commands can be added to the
restic-guix package with a more general approach.  This way new
subcommands for restic-guix can be added more easily.

* gnu/services/backup.scm (restic-backup-job-program): Generalize to
restic-program;
(restic-guix): allow for multiple actions.

* doc/guix.texi: Document it.

Change-Id: Ib2b5d74bebc51e35f1ae6e1aa32cedee0da59697
---
 doc/guix.texi           |  20 +++++-
 gnu/services/backup.scm | 138 ++++++++++++++++++++++++++--------------
 2 files changed, 108 insertions(+), 50 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 83ba0f32923..5c99521f8e6 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -43271,6 +43271,23 @@ Miscellaneous Services
 sudo herd trigger remote-ftp
 @end example
 
+The @code{restic-backup-service-type} installs as well @code{restic-guix}
+to the system profile, a @code{restic} utility wrapper that allows for easier
+interaction with the Guix configured backup jobs.  For example the following
+could be used to list all the shapshots available on a given job's repository:
+
+@example
+restic-guix snapshots remote-ftp
+@end example
+
+All arguments passed after the job name will be passed to the underlying
+@code{restic} command, together with the @code{extra-flags} field from the
+@code{restic-backup-job} record:
+
+@example
+restic-guix restore remote-ftp -t `pwd`/restored -i .config/guix/channels.scm latest
+@end example
+
 @c %start of fragment
 
 @deftp {Data Type} restic-backup-configuration
@@ -43344,8 +43361,7 @@ Miscellaneous Services
 
 @item @code{extra-flags} (default: @code{'()}) (type: list-of-lowerables)
 A list of values that are lowered to strings.  These will be passed as
-command-line arguments to the current job @command{restic backup}
-invocation.
+command-line arguments to the current @command{restic} invocation.
 
 @end table
 
diff --git a/gnu/services/backup.scm b/gnu/services/backup.scm
index 4d8cf167f04..dc095593432 100644
--- a/gnu/services/backup.scm
+++ b/gnu/services/backup.scm
@@ -52,11 +52,12 @@ (define-module (gnu services backup)
             restic-backup-configuration-fields
             restic-backup-configuration-jobs
 
-            restic-backup-job-program
-            restic-backup-job->mcron-job
+            restic-program
+            restic-backup-job->shepherd-service
             restic-guix
             restic-guix-wrapper-package
             restic-backup-service-profile
+            restic-backup-service-activation
             restic-backup-service-type))
 
 (define (gexp-or-string? value)
@@ -129,7 +130,7 @@ (define-configuration/no-serialization restic-backup-job
   (extra-flags
    (list-of-lowerables '())
    "A list of values that are lowered to strings.  These will be passed as
-command-line arguments to the current job @command{restic backup} invocation."))
+command-line arguments to the current @command{restic} invocation."))
 
 (define list-of-restic-backup-jobs?
   (list-of restic-backup-job?))
@@ -139,71 +140,107 @@ (define-configuration/no-serialization restic-backup-configuration
    (list-of-restic-backup-jobs '())
    "The list of backup jobs for the current system."))
 
-(define (restic-backup-job-program config)
+(define %restic-guix-supported-actions
+  '("backup" "list" "ls" "mount" "prune" "restore" "snapshots" "unlock"))
+
+(define (restic-backup-job->kv config)
   (let ((restic
          (file-append (restic-backup-job-restic config) "/bin/restic"))
+        (name
+         (restic-backup-job-name config))
         (repository
          (restic-backup-job-repository config))
         (password-file
          (restic-backup-job-password-file config))
-        (files
-         (restic-backup-job-files config))
         (extra-flags
          (restic-backup-job-extra-flags config))
-        (verbose
+        (verbose?
          (if (restic-backup-job-verbose? config)
              '("--verbose")
              '())))
-    (program-file
-     "restic-backup-job.scm"
-     #~(begin
-         (use-modules (ice-9 popen)
-                      (ice-9 rdelim))
-         (setenv "RESTIC_PASSWORD"
-                 (with-input-from-file #$password-file read-line))
+    #~(list #$name (list #$restic #$repository #$password-file
+                         (list #$@verbose?) (list #$@extra-flags)))))
+
+(define (restic-program config)
+  #~(lambda* (action action-args job-restic repository password-file verbose? extra-flags)
+      (use-modules (ice-9 format)
+                   (ice-9 popen)
+                   (ice-9 rdelim))
+      ;; This can be extended later, i.e. to have a
+      ;; centrally defined restic package.
+      ;; See https://issues.guix.gnu.org/71639
+      (define restic job-restic)
+
+      (define command
+        `(,restic ,@verbose?
+          "-r" ,repository
+          ,@extra-flags
+          ,action ,@action-args))
+
+      (setenv "RESTIC_PASSWORD"
+              (with-input-from-file password-file read-line))
 
-         (execlp #$restic #$restic #$@verbose
-                 "-r" #$repository
-                 #$@extra-flags
-                 "backup" #$@files)))))
+      (when (> (length verbose?) 0)
+        (format #t "Running~{ ~a~}~%" command))
 
-(define (restic-guix jobs)
+      (apply execlp `(,restic ,@command))))
+
+(define* (restic-guix config #:key (supported-actions
+                                    %restic-guix-supported-actions))
   (program-file
    "restic-guix"
    #~(begin
        (use-modules (ice-9 match)
                     (srfi srfi-1))
 
-       (define names '#$(map restic-backup-job-name jobs))
-       (define programs '#$(map restic-backup-job-program jobs))
-
-       (define (get-program name)
-         (define idx
-           (list-index (lambda (n) (string=? n name)) names))
-         (unless idx
-           (error (string-append "Unknown job name " name "\n\n"
-                                 "Possible job names are: "
-                                 (string-join names " "))))
-         (list-ref programs idx))
+       (define jobs
+         (list
+          #$@(map restic-backup-job->kv
+                  (restic-backup-configuration-jobs config))))
+       (define names (map first jobs))
+       (define (get-job key)
+         (first
+          (filter-map
+           (match-lambda
+             ((k v)
+              (and (string=? key k) v)))
+           jobs)))
 
-       (define (backup args)
-         (define name (third args))
-         (define program (get-program name))
-         (execlp program program))
+       (define restic-exec
+         #$(restic-program config))
 
        (define (validate-args args)
-         (when (not (>= (length args) 3))
-           (error (string-append "Usage: " (basename (car args))
-                                 " backup NAME"))))
+         (unless (>= (length args) 2)
+           (error (string-append "Usage: " (basename (first args))
+                                 " ACTION [ARGS]\n\nSupported actions are: "
+                                 #$(string-join supported-actions ", ") ".")))
+         (unless (member (second args) '#$supported-actions)
+           (error (string-append "Unknown action: " (second args) ". Supported"
+                                 "actions are: "
+                                 #$(string-join supported-actions ", ") "."))))
+
+       (define (validate-action-args action args)
+         (define argc (length args))
+         (when (not (>= argc 3))
+           (error (string-append "Usage: " (basename (first args))
+                                 " " action " JOB_NAME [ARGS]\n\nPossible job "
+                                 "names are: " (string-join names ", ") ".")))
+         (define job-name (third args))
+         (unless (member job-name names)
+           (error (string-append "Unknown job name: " job-name ". Possible job "
+                                 "names are: " (string-join names ", ") ".")))
+         (let ((job (get-job job-name))
+               (action-args
+                (if (> argc 3)
+                    (take-right args (- argc 3))
+                    '())))
+           (values job action-args)))
 
        (define (main args)
          (validate-args args)
          (define action (second args))
-         (match action
-           ("backup"
-            (backup args))
-           (_
-            (error (string-append "Unknown action: " action)))))
+         (define-values (job action-args) (validate-action-args action args))
+         (apply restic-exec `(,action ,action-args ,@job)))
 
        (main (command-line)))))
 
@@ -217,6 +254,10 @@ (define (restic-job-log-file job)
 (define (restic-backup-job->shepherd-service config)
   (let ((schedule (restic-backup-job-schedule config))
         (name (restic-backup-job-name config))
+        (files (string-join
+                (map (lambda (f) (string-append "'" f "'"))
+                     (restic-backup-job-files config))
+                " "))
         (user (restic-backup-job-user config))
         (group (restic-backup-job-group config))
         (max-duration (restic-backup-job-max-duration config))
@@ -242,7 +283,8 @@ (define (restic-backup-job->shepherd-service config)
                             ;; backends require, such as rclone.
                             (string-append #+bash-minimal "/bin/bash")
                             "-l" "-c"
-                            (string-append "restic-guix backup " #$name))
+                            (string-append
+                             "restic-guix backup " #$name " " #$files))
                            #:user #$user
                            #:group #$group
                            #:environment-variables
@@ -261,11 +303,11 @@ (define (restic-backup-job->shepherd-service config)
 without waiting for the scheduled time.")
                                       (procedure #~trigger-timer)))))))
 
-(define (restic-guix-wrapper-package jobs)
+(define (restic-guix-wrapper-package config)
   (package
     (name "restic-backup-service-wrapper")
     (version "0.0.0")
-    (source (restic-guix jobs))
+    (source (restic-guix config))
     (build-system copy-build-system)
     (arguments
      (list #:install-plan #~'(("./" "/bin"))))
@@ -284,10 +326,10 @@ (define restic-backup-service-profile
     (define jobs (restic-backup-configuration-jobs config))
     (if (> (length jobs) 0)
         (list
-         (restic-guix-wrapper-package jobs))
+         (restic-guix-wrapper-package config))
         '())))
 
-(define (restic-backup-activation config)
+(define (restic-backup-service-activation config)
   #~(for-each
      (lambda (log-file)
        (mkdir-p (dirname log-file)))
@@ -299,7 +341,7 @@ (define restic-backup-service-type
                 (extensions
                  (list
                   (service-extension activation-service-type
-                                     restic-backup-activation)
+                                     restic-backup-service-activation)
                   (service-extension profile-service-type
                                      restic-backup-service-profile)
                   (service-extension shepherd-root-service-type

base-commit: 23b068c036223e70bdea9d7d579850a1cffc02a7
-- 
2.48.1





Information forwarded to guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Wed, 05 Mar 2025 22:45:01 GMT) Full text and rfc822 format available.

Message #66 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: paul <goodoldpaul <at> autistici.org>
To: 72803 <at> debbugs.gnu.org
Subject: Re: Add restic commands to the restic-guix package
Date: Wed, 5 Mar 2025 23:44:13 +0100
Hi, I'm sending a v8 rebased on current master.


thank you for your work





Information forwarded to ludo <at> gnu.org, maxim.cournoyer <at> gmail.com, guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Wed, 05 Mar 2025 22:46:02 GMT) Full text and rfc822 format available.

Message #69 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: Giacomo Leidi <goodoldpaul <at> autistici.org>
To: 72803 <at> debbugs.gnu.org
Cc: Giacomo Leidi <goodoldpaul <at> autistici.org>
Subject: [PATCH v8] services: restic-backup: Add more restic commands to the
 restic-guix package.
Date: Wed,  5 Mar 2025 23:44:47 +0100
This patch refactors the way restic commands can be added to the
restic-guix package with a more general approach.  This way new
subcommands for restic-guix can be added more easily.

* gnu/services/backup.scm (restic-backup-job-program): Generalize to
restic-program;
(restic-guix): allow for multiple actions.

* doc/guix.texi: Document it.

Change-Id: Ib2b5d74bebc51e35f1ae6e1aa32cedee0da59697
---
 doc/guix.texi           |  20 +++++-
 gnu/services/backup.scm | 138 ++++++++++++++++++++++++++--------------
 2 files changed, 108 insertions(+), 50 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 6844470ce2f..e4c5c86e91f 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -43709,6 +43709,23 @@ Miscellaneous Services
 sudo herd trigger remote-ftp
 @end example
 
+The @code{restic-backup-service-type} installs as well @code{restic-guix}
+to the system profile, a @code{restic} utility wrapper that allows for easier
+interaction with the Guix configured backup jobs.  For example the following
+could be used to list all the shapshots available on a given job's repository:
+
+@example
+restic-guix snapshots remote-ftp
+@end example
+
+All arguments passed after the job name will be passed to the underlying
+@code{restic} command, together with the @code{extra-flags} field from the
+@code{restic-backup-job} record:
+
+@example
+restic-guix restore remote-ftp -t `pwd`/restored -i .config/guix/channels.scm latest
+@end example
+
 @c %start of fragment
 
 @deftp {Data Type} restic-backup-configuration
@@ -43782,8 +43799,7 @@ Miscellaneous Services
 
 @item @code{extra-flags} (default: @code{'()}) (type: list-of-lowerables)
 A list of values that are lowered to strings.  These will be passed as
-command-line arguments to the current job @command{restic backup}
-invocation.
+command-line arguments to the current @command{restic} invocation.
 
 @end table
 
diff --git a/gnu/services/backup.scm b/gnu/services/backup.scm
index 4d8cf167f04..dc095593432 100644
--- a/gnu/services/backup.scm
+++ b/gnu/services/backup.scm
@@ -52,11 +52,12 @@ (define-module (gnu services backup)
             restic-backup-configuration-fields
             restic-backup-configuration-jobs
 
-            restic-backup-job-program
-            restic-backup-job->mcron-job
+            restic-program
+            restic-backup-job->shepherd-service
             restic-guix
             restic-guix-wrapper-package
             restic-backup-service-profile
+            restic-backup-service-activation
             restic-backup-service-type))
 
 (define (gexp-or-string? value)
@@ -129,7 +130,7 @@ (define-configuration/no-serialization restic-backup-job
   (extra-flags
    (list-of-lowerables '())
    "A list of values that are lowered to strings.  These will be passed as
-command-line arguments to the current job @command{restic backup} invocation."))
+command-line arguments to the current @command{restic} invocation."))
 
 (define list-of-restic-backup-jobs?
   (list-of restic-backup-job?))
@@ -139,71 +140,107 @@ (define-configuration/no-serialization restic-backup-configuration
    (list-of-restic-backup-jobs '())
    "The list of backup jobs for the current system."))
 
-(define (restic-backup-job-program config)
+(define %restic-guix-supported-actions
+  '("backup" "list" "ls" "mount" "prune" "restore" "snapshots" "unlock"))
+
+(define (restic-backup-job->kv config)
   (let ((restic
          (file-append (restic-backup-job-restic config) "/bin/restic"))
+        (name
+         (restic-backup-job-name config))
         (repository
          (restic-backup-job-repository config))
         (password-file
          (restic-backup-job-password-file config))
-        (files
-         (restic-backup-job-files config))
         (extra-flags
          (restic-backup-job-extra-flags config))
-        (verbose
+        (verbose?
          (if (restic-backup-job-verbose? config)
              '("--verbose")
              '())))
-    (program-file
-     "restic-backup-job.scm"
-     #~(begin
-         (use-modules (ice-9 popen)
-                      (ice-9 rdelim))
-         (setenv "RESTIC_PASSWORD"
-                 (with-input-from-file #$password-file read-line))
+    #~(list #$name (list #$restic #$repository #$password-file
+                         (list #$@verbose?) (list #$@extra-flags)))))
+
+(define (restic-program config)
+  #~(lambda* (action action-args job-restic repository password-file verbose? extra-flags)
+      (use-modules (ice-9 format)
+                   (ice-9 popen)
+                   (ice-9 rdelim))
+      ;; This can be extended later, i.e. to have a
+      ;; centrally defined restic package.
+      ;; See https://issues.guix.gnu.org/71639
+      (define restic job-restic)
+
+      (define command
+        `(,restic ,@verbose?
+          "-r" ,repository
+          ,@extra-flags
+          ,action ,@action-args))
+
+      (setenv "RESTIC_PASSWORD"
+              (with-input-from-file password-file read-line))
 
-         (execlp #$restic #$restic #$@verbose
-                 "-r" #$repository
-                 #$@extra-flags
-                 "backup" #$@files)))))
+      (when (> (length verbose?) 0)
+        (format #t "Running~{ ~a~}~%" command))
 
-(define (restic-guix jobs)
+      (apply execlp `(,restic ,@command))))
+
+(define* (restic-guix config #:key (supported-actions
+                                    %restic-guix-supported-actions))
   (program-file
    "restic-guix"
    #~(begin
        (use-modules (ice-9 match)
                     (srfi srfi-1))
 
-       (define names '#$(map restic-backup-job-name jobs))
-       (define programs '#$(map restic-backup-job-program jobs))
-
-       (define (get-program name)
-         (define idx
-           (list-index (lambda (n) (string=? n name)) names))
-         (unless idx
-           (error (string-append "Unknown job name " name "\n\n"
-                                 "Possible job names are: "
-                                 (string-join names " "))))
-         (list-ref programs idx))
+       (define jobs
+         (list
+          #$@(map restic-backup-job->kv
+                  (restic-backup-configuration-jobs config))))
+       (define names (map first jobs))
+       (define (get-job key)
+         (first
+          (filter-map
+           (match-lambda
+             ((k v)
+              (and (string=? key k) v)))
+           jobs)))
 
-       (define (backup args)
-         (define name (third args))
-         (define program (get-program name))
-         (execlp program program))
+       (define restic-exec
+         #$(restic-program config))
 
        (define (validate-args args)
-         (when (not (>= (length args) 3))
-           (error (string-append "Usage: " (basename (car args))
-                                 " backup NAME"))))
+         (unless (>= (length args) 2)
+           (error (string-append "Usage: " (basename (first args))
+                                 " ACTION [ARGS]\n\nSupported actions are: "
+                                 #$(string-join supported-actions ", ") ".")))
+         (unless (member (second args) '#$supported-actions)
+           (error (string-append "Unknown action: " (second args) ". Supported"
+                                 "actions are: "
+                                 #$(string-join supported-actions ", ") "."))))
+
+       (define (validate-action-args action args)
+         (define argc (length args))
+         (when (not (>= argc 3))
+           (error (string-append "Usage: " (basename (first args))
+                                 " " action " JOB_NAME [ARGS]\n\nPossible job "
+                                 "names are: " (string-join names ", ") ".")))
+         (define job-name (third args))
+         (unless (member job-name names)
+           (error (string-append "Unknown job name: " job-name ". Possible job "
+                                 "names are: " (string-join names ", ") ".")))
+         (let ((job (get-job job-name))
+               (action-args
+                (if (> argc 3)
+                    (take-right args (- argc 3))
+                    '())))
+           (values job action-args)))
 
        (define (main args)
          (validate-args args)
          (define action (second args))
-         (match action
-           ("backup"
-            (backup args))
-           (_
-            (error (string-append "Unknown action: " action)))))
+         (define-values (job action-args) (validate-action-args action args))
+         (apply restic-exec `(,action ,action-args ,@job)))
 
        (main (command-line)))))
 
@@ -217,6 +254,10 @@ (define (restic-job-log-file job)
 (define (restic-backup-job->shepherd-service config)
   (let ((schedule (restic-backup-job-schedule config))
         (name (restic-backup-job-name config))
+        (files (string-join
+                (map (lambda (f) (string-append "'" f "'"))
+                     (restic-backup-job-files config))
+                " "))
         (user (restic-backup-job-user config))
         (group (restic-backup-job-group config))
         (max-duration (restic-backup-job-max-duration config))
@@ -242,7 +283,8 @@ (define (restic-backup-job->shepherd-service config)
                             ;; backends require, such as rclone.
                             (string-append #+bash-minimal "/bin/bash")
                             "-l" "-c"
-                            (string-append "restic-guix backup " #$name))
+                            (string-append
+                             "restic-guix backup " #$name " " #$files))
                            #:user #$user
                            #:group #$group
                            #:environment-variables
@@ -261,11 +303,11 @@ (define (restic-backup-job->shepherd-service config)
 without waiting for the scheduled time.")
                                       (procedure #~trigger-timer)))))))
 
-(define (restic-guix-wrapper-package jobs)
+(define (restic-guix-wrapper-package config)
   (package
     (name "restic-backup-service-wrapper")
     (version "0.0.0")
-    (source (restic-guix jobs))
+    (source (restic-guix config))
     (build-system copy-build-system)
     (arguments
      (list #:install-plan #~'(("./" "/bin"))))
@@ -284,10 +326,10 @@ (define restic-backup-service-profile
     (define jobs (restic-backup-configuration-jobs config))
     (if (> (length jobs) 0)
         (list
-         (restic-guix-wrapper-package jobs))
+         (restic-guix-wrapper-package config))
         '())))
 
-(define (restic-backup-activation config)
+(define (restic-backup-service-activation config)
   #~(for-each
      (lambda (log-file)
        (mkdir-p (dirname log-file)))
@@ -299,7 +341,7 @@ (define restic-backup-service-type
                 (extensions
                  (list
                   (service-extension activation-service-type
-                                     restic-backup-activation)
+                                     restic-backup-service-activation)
                   (service-extension profile-service-type
                                      restic-backup-service-profile)
                   (service-extension shepherd-root-service-type

base-commit: 310adf4ce70cbb864859274fcc7842bd519bbddc
-- 
2.48.1





Information forwarded to guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Mon, 10 Mar 2025 13:53:02 GMT) Full text and rfc822 format available.

Message #72 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: Ludovic Courtès <ludo <at> gnu.org>
To: Giacomo Leidi <goodoldpaul <at> autistici.org>
Cc: 72803 <at> debbugs.gnu.org, Maxim Cournoyer <maxim.cournoyer <at> gmail.com>
Subject: Re: bug#72803: Add restic commands to the restic-guix package
Date: Mon, 10 Mar 2025 14:52:32 +0100
Hi,

Giacomo Leidi <goodoldpaul <at> autistici.org> skribis:

> This patch refactors the way restic commands can be added to the
> restic-guix package with a more general approach.  This way new
> subcommands for restic-guix can be added more easily.
>
> * gnu/services/backup.scm (restic-backup-job-program): Generalize to
> restic-program;
> (restic-guix): allow for multiple actions.
>
> * doc/guix.texi: Document it.
>
> Change-Id: Ib2b5d74bebc51e35f1ae6e1aa32cedee0da59697
> +(define (restic-program config)
> +  #~(lambda* (action action-args job-restic repository password-file verbose? extra-flags)
> +      (use-modules (ice-9 format)
> +                   (ice-9 popen)
> +                   (ice-9 rdelim))

Please move ‘use-modules’ to the top-level; that’s the only guaranteed
way to use it.

> +(define* (restic-guix config #:key (supported-actions
> +                                    %restic-guix-supported-actions))
>    (program-file
>     "restic-guix"
>     #~(begin
>         (use-modules (ice-9 match)
>                      (srfi srfi-1))
>  
> -       (define names '#$(map restic-backup-job-name jobs))
> -       (define programs '#$(map restic-backup-job-program jobs))
> -
> -       (define (get-program name)
> -         (define idx
> -           (list-index (lambda (n) (string=? n name)) names))
> -         (unless idx
> -           (error (string-append "Unknown job name " name "\n\n"
> -                                 "Possible job names are: "
> -                                 (string-join names " "))))
> -         (list-ref programs idx))
> +       (define jobs
> +         (list
> +          #$@(map restic-backup-job->kv
> +                  (restic-backup-configuration-jobs config))))
> +       (define names (map first jobs))
> +       (define (get-job key)
> +         (first
> +          (filter-map
> +           (match-lambda
> +             ((k v)
> +              (and (string=? key k) v)))
> +           jobs)))
>  
> -       (define (backup args)
> -         (define name (third args))
> -         (define program (get-program name))
> -         (execlp program program))
> +       (define restic-exec
> +         #$(restic-program config))
>  
>         (define (validate-args args)
> -         (when (not (>= (length args) 3))
> -           (error (string-append "Usage: " (basename (car args))
> -                                 " backup NAME"))))
> +         (unless (>= (length args) 2)
> +           (error (string-append "Usage: " (basename (first args))
> +                                 " ACTION [ARGS]\n\nSupported actions are: "
> +                                 #$(string-join supported-actions ", ") ".")))
> +         (unless (member (second args) '#$supported-actions)
> +           (error (string-append "Unknown action: " (second args) ". Supported"
> +                                 "actions are: "
> +                                 #$(string-join supported-actions ", ") "."))))
> +
> +       (define (validate-action-args action args)
> +         (define argc (length args))
> +         (when (not (>= argc 3))
> +           (error (string-append "Usage: " (basename (first args))
> +                                 " " action " JOB_NAME [ARGS]\n\nPossible job "
> +                                 "names are: " (string-join names ", ") ".")))
> +         (define job-name (third args))
> +         (unless (member job-name names)
> +           (error (string-append "Unknown job name: " job-name ". Possible job "
> +                                 "names are: " (string-join names ", ") ".")))
> +         (let ((job (get-job job-name))
> +               (action-args
> +                (if (> argc 3)
> +                    (take-right args (- argc 3))
> +                    '())))
> +           (values job action-args)))
>  
>         (define (main args)
>           (validate-args args)
>           (define action (second args))
> -         (match action
> -           ("backup"
> -            (backup args))
> -           (_
> -            (error (string-append "Unknown action: " action)))))
> +         (define-values (job action-args) (validate-action-args action args))
> +         (apply restic-exec `(,action ,action-args ,@job)))

I see two issues here:

  1. This is stepping on the toes of upstream: why are we providing a
     non-trivial program like this downstream?

  2. There are stylistic issues: use of ‘first’ & co. (info "(guix) Data
     Types and Pattern Matching"), use of ‘error’ (it is too generic and
     user-unfriendly), custom argument parsing procedure.

Thanks,
Ludo’.




Information forwarded to guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Mon, 10 Mar 2025 15:52:02 GMT) Full text and rfc822 format available.

Message #75 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: paul <goodoldpaul <at> autistici.org>
To: Ludovic Courtès <ludo <at> gnu.org>
Cc: 72803 <at> debbugs.gnu.org, Maxim Cournoyer <maxim.cournoyer <at> gmail.com>
Subject: Re: bug#72803: Add restic commands to the restic-guix package
Date: Mon, 10 Mar 2025 16:50:57 +0100
[Message part 1 (text/plain, inline)]
Hi Ludo’ ,

first thanks a lot for your review,

On 3/10/25 14:52, Ludovic Courtès wrote:
> I see two issues here:
>
>    1. This is stepping on the toes of upstream: why are we providing a
>       non-trivial program like this downstream?

In my understanding this is the fundamental issue, which could be a 
shipstopper. Please correct me if I'm wrong. We kind of are obviously 
even if restic-guix is already in the master branch ( ) . In my opinion 
the way forward should be: a. In this scenario we merge the current 
72803 (after addressing your other comments) and we take this risk

b. In this scenario we remove completely the current incomplete 
restic-guix command implementation from master, as it makes not much 
sense to have it incomplete as it is right now.

I view scenario a and scenario b as mutually exclusive but I may be 
missing some implication, what is your opinion on this?

>    2. There are stylistic issues: use of ‘first’ & co. (info "(guix) Data
>       Types and Pattern Matching"), use of ‘error’ (it is too generic and
>       user-unfriendly), custom argument parsing procedure.

I will address these comments only if we decide to go forward with 
scenario a.


Thank you so much for your work,


cheers

giacomo
[Message part 2 (text/html, inline)]

Information forwarded to guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Mon, 10 Mar 2025 15:55:02 GMT) Full text and rfc822 format available.

Message #78 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: paul <goodoldpaul <at> autistici.org>
To: Ludovic Courtès <ludo <at> gnu.org>
Cc: 72803 <at> debbugs.gnu.org, Maxim Cournoyer <maxim.cournoyer <at> gmail.com>
Subject: Re: bug#72803: Add restic commands to the restic-guix package
Date: Mon, 10 Mar 2025 16:54:21 +0100
[Message part 1 (text/plain, inline)]
Ah I hit return too soon :/ Apologies for the noise. This is what I 
wanted to add to my previous message:


... We kind of are obviously even if restic-guix is already in the 
master branch ( 
https://git.savannah.gnu.org/cgit/guix.git/tree/gnu/services/backup.scm#n170 
), which suffers from many of the shortcomings you noticed in your 
review, such as: use of ‘first & co., use of ‘error’, custom argument 
parsing procedure. In my opinion ...

thank you again for your review,

giacomo
[Message part 2 (text/html, inline)]

Information forwarded to guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Mon, 10 Mar 2025 21:42:02 GMT) Full text and rfc822 format available.

Message #81 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: Ludovic Courtès <ludo <at> gnu.org>
To: paul <goodoldpaul <at> autistici.org>
Cc: 72803 <at> debbugs.gnu.org, Maxim Cournoyer <maxim.cournoyer <at> gmail.com>
Subject: Re: bug#72803: Add restic commands to the restic-guix package
Date: Mon, 10 Mar 2025 22:41:12 +0100
Hi,

paul <goodoldpaul <at> autistici.org> skribis:

> On 3/10/25 14:52, Ludovic Courtès wrote:
>> I see two issues here:
>>
>>    1. This is stepping on the toes of upstream: why are we providing a
>>       non-trivial program like this downstream?
>
> In my understanding this is the fundamental issue, which could be a
> shipstopper. Please correct me if I'm wrong. We kind of are obviously
> even if restic-guix is already in the master branch ( ) . In my
> opinion the way forward should be: a. In this scenario we merge the
> current 72803 (after addressing your other comments) and we take this
> risk
>
> b. In this scenario we remove completely the current incomplete
> restic-guix command implementation from master, as it makes not much
> sense to have it incomplete as it is right now.
>
> I view scenario a and scenario b as mutually exclusive but I may be
> missing some implication, what is your opinion on this?

I’m not a restic user so I’m not super qualified, but I think the
general direction should be to stick to our role of downstream users; if
we go too far in terms of tooling around the software, then that
suggests something’s missing from what upstream provides, and perhaps
more importantly that’s a maintenance burden on us.

From that perspective, I lean towards scenario b, but I trust you can
find the right middle ground.

WDYT?

Ludo’.




Information forwarded to guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Tue, 29 Apr 2025 00:00:03 GMT) Full text and rfc822 format available.

Message #84 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: paul <goodoldpaul <at> autistici.org>
To: Ludovic Courtès <ludo <at> gnu.org>
Cc: 72803 <at> debbugs.gnu.org, Maxim Cournoyer <maxim.cournoyer <at> gmail.com>
Subject: Re: bug#72803: Add restic commands to the restic-guix package
Date: Tue, 29 Apr 2025 01:59:44 +0200
[Message part 1 (text/plain, inline)]
Hi Ludo',

On 3/10/25 22:41, Ludovic Courtès wrote:
> I’m not a restic user so I’m not super qualified, but I think the
> general direction should be to stick to our role of downstream users; if
> we go too far in terms of tooling around the software, then that
> suggests something’s missing from what upstream provides, and perhaps
> more importantly that’s a maintenance burden on us.
You were definitely right, I found out this has been known upstream for 
at least 10 years :( .  I found 
https://github.com/restic/restic/issues/16 which proves this is a 
missing feature upstream.  To avoid the maintenance
cost I'll drop the restic-guix package.  Its functionality can be 
implemented in a separate Guix based project or by using one of the 
different FOSS projects implementing a configuration file for restic.
>  From that perspective, I lean towards scenario b, but I trust you can
> find the right middle ground.

Thank you for your help, I'm sending a v9 which can hopefully be the 
final revision.


cheers,
giacomo
[Message part 2 (text/html, inline)]

Information forwarded to guix-patches <at> gnu.org:
bug#72803; Package guix-patches. (Tue, 29 Apr 2025 00:02:05 GMT) Full text and rfc822 format available.

Message #87 received at 72803 <at> debbugs.gnu.org (full text, mbox):

From: Giacomo Leidi <goodoldpaul <at> autistici.org>
To: 72803 <at> debbugs.gnu.org
Cc: Giacomo Leidi <goodoldpaul <at> autistici.org>
Subject: [PATCH v9] services: restic-backup: Drop restic-guix command.
Date: Tue, 29 Apr 2025 02:00:16 +0200
restic-guix has always been close to a reimplementation of a restic
command line.  https://github.com/restic/restic/issues/16 was then found
out, indicating a missing feature upstream.  To avoid the maintenance
cost we drop the restic-guix package.  Its functionality can be
implemented in a separate project or by using one of the different FOSS
projects implementing a configuration file for restic.

* gnu/services/backup.scm: Drop mcron obsolete export.
(restic-backup-job-program): Generalize to restic-program.
(lower-restic-backup-job): New procedure implementing a standard way to
lower restic-backup-job records into lists.
(restic-guix): Drop procedure;
(restic-program): Implement general way to run restic commands, for
example to initialize repositories.
(restic-backup): New procedure returning a gexp for the entrypoint of
the backup job.
(restic-job-logfile): Rename to restic-backup-log-file.
(restic-backup-job-command): New procedure returning the restic command
file for the Shepherd timer as a gexped list.
(restic-backup-job-requirement): New procedure returning the Shepherd
timer Shepherd dependencies.
(restic-backup-job-modules): New procedure returning the Guile modules
that will be loaded in the Shepherd timer.
(restic-backup-job->shepherd-service): Use the new procedures and use
the trigger action from (shepherd service timer).
(restic-guix-wrapper-package): Drop procedure.
(restic-backup-service-profile): Drop procedure.
(restic-backup-service-activation): Drop procedure as now the Shepherd
takes care of creating timers log file directories.
(restic-backup-service-type): Drop profile and activation services extensions.

Change-Id: Ib2b5d74bebc51e35f1ae6e1aa32cedee0da59697
---
 gnu/services/backup.scm | 178 ++++++++++++++++------------------------
 1 file changed, 71 insertions(+), 107 deletions(-)

diff --git a/gnu/services/backup.scm b/gnu/services/backup.scm
index 6e066bd3d66..4fff815e168 100644
--- a/gnu/services/backup.scm
+++ b/gnu/services/backup.scm
@@ -47,16 +47,19 @@ (define-module (gnu services backup)
             restic-backup-job-verbose?
             restic-backup-job-extra-flags
 
+            lower-restic-backup-job
+
             restic-backup-configuration
             restic-backup-configuration?
             restic-backup-configuration-fields
             restic-backup-configuration-jobs
 
-            restic-backup-job-program
-            restic-backup-job->mcron-job
-            restic-guix
-            restic-guix-wrapper-package
-            restic-backup-service-profile
+            restic-program
+            restic-backup-job-log-file
+            restic-backup-job-command
+            restic-backup-job-requirement
+            restic-backup-job-modules
+            restic-backup-job->shepherd-service
             restic-backup-service-type))
 
 (define (gexp-or-string? value)
@@ -139,110 +142,104 @@ (define-configuration/no-serialization restic-backup-configuration
    (list-of-restic-backup-jobs '())
    "The list of backup jobs for the current system."))
 
-(define (restic-backup-job-program config)
+(define (lower-restic-backup-job config)
   (let ((restic
          (file-append (restic-backup-job-restic config) "/bin/restic"))
+        (name
+         (restic-backup-job-name config))
+        (files
+         (restic-backup-job-files config))
         (repository
          (restic-backup-job-repository config))
         (password-file
          (restic-backup-job-password-file config))
-        (files
-         (restic-backup-job-files config))
         (extra-flags
          (restic-backup-job-extra-flags config))
-        (verbose
+        (verbose?
          (if (restic-backup-job-verbose? config)
              '("--verbose")
              '())))
-    (program-file
-     "restic-backup-job.scm"
-     #~(begin
-         (use-modules (ice-9 popen)
-                      (ice-9 rdelim))
-         (setenv "RESTIC_PASSWORD"
-                 (with-input-from-file #$password-file read-line))
+    #~(list (list #$@files) #$restic #$repository #$password-file
+            (list #$@verbose?) (list #$@extra-flags))))
 
-         (execlp #$restic #$restic #$@verbose
-                 "-r" #$repository
-                 #$@extra-flags
-                 "backup" #$@files)))))
-
-(define (restic-guix jobs)
-  (program-file
-   "restic-guix"
-   #~(begin
-       (use-modules (ice-9 match)
-                    (srfi srfi-1))
+(define restic-program
+  #~(lambda (action action-args job-restic repository password-file verbose? extra-flags)
+      (use-modules (ice-9 format))
+      ;; This can be extended later, i.e. to have a
+      ;; centrally defined restic package.
+      ;; See https://issues.guix.gnu.org/71639
+      (define restic job-restic)
 
-       (define names '#$(map restic-backup-job-name jobs))
-       (define programs '#$(map restic-backup-job-program jobs))
+      (define command
+        `(,restic ,@verbose?
+          "-r" ,repository
+          ,@extra-flags
+          ,action ,@action-args))
 
-       (define (get-program name)
-         (define idx
-           (list-index (lambda (n) (string=? n name)) names))
-         (unless idx
-           (error (string-append "Unknown job name " name "\n\n"
-                                 "Possible job names are: "
-                                 (string-join names " "))))
-         (list-ref programs idx))
+      (setenv "RESTIC_PASSWORD_FILE" password-file)
 
-       (define (backup args)
-         (define name (third args))
-         (define program (get-program name))
-         (execlp program program))
+      (when (> (length verbose?) 0)
+        (format #t "Running~{ ~a~}~%" command))
 
-       (define (validate-args args)
-         (when (not (>= (length args) 3))
-           (error (string-append "Usage: " (basename (car args))
-                                 " backup NAME"))))
+      (apply execlp `(,restic ,@command))))
 
-       (define (main args)
-         (validate-args args)
-         (define action (second args))
-         (match action
-           ("backup"
-            (backup args))
-           (_
-            (error (string-append "Unknown action: " action)))))
+(define (restic-backup config)
+  (program-file
+   "restic-backup"
+   #~(let ((restic-exec
+            #$restic-program)
+           (job #$(lower-restic-backup-job config)))
 
-       (main (command-line)))))
+       (apply restic-exec `("backup" ,@job)))))
 
-(define (restic-job-log-file job)
+(define (restic-backup-job-log-file job)
   (let ((name (restic-backup-job-name job))
         (log-file (restic-backup-job-log-file job)))
     (if (maybe-value-set? log-file)
         log-file
         (string-append "/var/log/restic-backup/" name ".log"))))
 
+(define (restic-backup-job-command config)
+  ;; We go through bash, instead of executing
+  ;; restic-guix directly, because the login shell
+  ;; gives us the correct user environment that some
+  ;; backends require, such as rclone.
+  #~(list
+     (string-append #$bash-minimal "/bin/bash")
+     "-l" "-c"
+     (string-join (list #$(restic-backup config))
+                  " ")))
+
+(define (restic-backup-job-requirement requirement)
+  (append '(user-processes file-systems) requirement))
+
+(define (restic-backup-job-modules)
+ `((shepherd service timer)))
+
 (define (restic-backup-job->shepherd-service config)
   (let ((schedule (restic-backup-job-schedule config))
         (name (restic-backup-job-name config))
+        (files (restic-backup-job-files config))
         (user (restic-backup-job-user config))
         (group (restic-backup-job-group config))
         (max-duration (restic-backup-job-max-duration config))
         (wait-for-termination? (restic-backup-job-wait-for-termination? config))
-        (log-file (restic-job-log-file config))
-        (requirement (restic-backup-job-requirement config)))
+        (log-file (restic-backup-job-log-file config))
+        (requirement
+         (restic-backup-job-requirement
+          (restic-backup-job-requirement config))))
     (shepherd-service (provision `(,(string->symbol name)))
-                      (requirement
-                       `(user-processes file-systems ,@requirement))
+                      (requirement requirement)
                       (documentation
-                       "Run @code{restic} backed backups on a regular basis.")
-                      (modules '((shepherd service timer)))
+                       "Run restic backed backups on a regular basis.")
+                      (modules (restic-backup-job-modules))
                       (start
                        #~(make-timer-constructor
                           (if (string? #$schedule)
                               (cron-string->calendar-event #$schedule)
                               #$schedule)
                           (command
-                           (list
-                            ;; We go through bash, instead of executing
-                            ;; restic-guix directly, because the login shell
-                            ;; gives us the correct user environment that some
-                            ;; backends require, such as rclone.
-                            (string-append #+bash-minimal "/bin/bash")
-                            "-l" "-c"
-                            (string-append "restic-guix backup " #$name))
+                           #$(restic-backup-job-command config)
                            #:user #$user
                            #:group #$group
                            #:environment-variables
@@ -255,49 +252,16 @@ (define (restic-backup-job->shepherd-service config)
                                                 max-duration)))
                       (stop
                        #~(make-timer-destructor))
-                      (actions (list shepherd-trigger-action)))))
-
-(define (restic-guix-wrapper-package jobs)
-  (package
-    (name "restic-backup-service-wrapper")
-    (version "0.0.0")
-    (source (restic-guix jobs))
-    (build-system copy-build-system)
-    (arguments
-     (list #:install-plan #~'(("./" "/bin"))))
-    (home-page "https://restic.net")
-    (synopsis
-     "Easily interact from the CLI with Guix configured backups")
-    (description
-     "This package provides a simple wrapper around @code{restic}, handled
-by the @code{restic-backup-service-type}.  It allows for easily interacting
-with Guix configured backup jobs, for example for manually triggering a backup
-without waiting for the scheduled job to run.")
-    (license license:gpl3+)))
-
-(define restic-backup-service-profile
-  (lambda (config)
-    (define jobs (restic-backup-configuration-jobs config))
-    (if (> (length jobs) 0)
-        (list
-         (restic-guix-wrapper-package jobs))
-        '())))
-
-(define (restic-backup-activation config)
-  #~(for-each
-     (lambda (log-file)
-       (mkdir-p (dirname log-file)))
-     (list #$@(map restic-job-log-file
-                   (restic-backup-configuration-jobs config)))))
+                      (actions (list (shepherd-action
+                                      (name 'trigger)
+                                      (documentation "Manually trigger a backup,
+without waiting for the scheduled time.")
+                                      (procedure #~trigger-timer)))))))
 
 (define restic-backup-service-type
   (service-type (name 'restic-backup)
                 (extensions
                  (list
-                  (service-extension activation-service-type
-                                     restic-backup-activation)
-                  (service-extension profile-service-type
-                                     restic-backup-service-profile)
                   (service-extension shepherd-root-service-type
                                      (lambda (config)
                                        (map restic-backup-job->shepherd-service

base-commit: 1710c0941db517453ac2b88c0e854e8348172603
-- 
2.49.0





Reply sent to paul <goodoldpaul <at> autistici.org>:
You have taken responsibility. (Mon, 19 May 2025 16:56:01 GMT) Full text and rfc822 format available.

Notification sent to paul <goodoldpaul <at> autistici.org>:
bug acknowledged by developer. (Mon, 19 May 2025 16:56:02 GMT) Full text and rfc822 format available.

Message #92 received at 72803-done <at> debbugs.gnu.org (full text, mbox):

From: paul <goodoldpaul <at> autistici.org>
To: 72803-done <at> debbugs.gnu.org
Date: Mon, 19 May 2025 18:55:38 +0200
[Message part 1 (text/plain, inline)]
Closing this as there seems to be no consensus on how to proceed. I guess we can figure it out in a later patch.

Thank you for your help,

cheers
giacomo
[Message part 2 (text/html, inline)]

This bug report was last modified 26 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.