Subject: [bug#71639] [PATCH WIP 1/5] services: backup: Support bootstrapping an initial restic backup

From: Richard Sent <[email-masked]>
Date: Tue, 18 Jun 2024 18:08:48 -0400

* gnu/services/backup.scm: (restic-backup-job): Add init? field.
(restic-backup-job-program): Initialize repository if init? is set and
repository does not already exist.
* doc/guix.texi (Miscellaneous Services): Document it.

Change-Id: I71d0cbaac646b9d160e662b69286f229b9a9f64d
---
 doc/guix.texi           |  4 ++++
 gnu/services/backup.scm | 20 ++++++++++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/doc/guix.texi b/doc/guix.texi
index 0102fd0fad..63c9cbd1a7 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -41353,6 +41353,10 @@ Miscellaneous Services
 The list of files or directories to be backed up.  It must be a list of
 values that can be lowered to strings.
 
+@item @code{init?} (default: @code{#f}) (type: boolean)
+Whether restic-backup-service should check and (if it does not exist)
+initialize the repository before running the backup.
+
 @item @code{verbose?} (default: @code{#f}) (type: boolean)
 Whether to enable verbose output for the current backup job.
 
diff --git a/gnu/services/backup.scm b/gnu/services/backup.scm
index 555e9fc959..eeef11eae7 100644
--- a/gnu/services/backup.scm
+++ b/gnu/services/backup.scm
@@ -1,5 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2024 Giacomo Leidi <[email-masked]>
+;;; Copyright © 2024 Richard Sent <[email-masked]>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -38,6 +39,7 @@ (define-module (gnu services backup)
             restic-backup-job-password-file
             restic-backup-job-schedule
             restic-backup-job-files
+            restic-backup-job-init?
             restic-backup-job-verbose?
             restic-backup-job-extra-flags
 
@@ -94,6 +96,9 @@ (define-configuration/no-serialization restic-backup-job
   (verbose?
    (boolean #f)
    "Whether to enable verbose output for the current backup job.")
+  (init?
+   (boolean #f)
+   "Whether to attempt to initialize a new repository for automated bootstrap purposes.")
   (extra-flags
    (list-of-lowerables '())
    "A list of values that are lowered to strings.  These will be passed as
@@ -118,6 +123,8 @@ (define (restic-backup-job-program config)
          (restic-backup-job-files config))
         (extra-flags
          (restic-backup-job-extra-flags config))
+        (init?
+         (restic-backup-job-init? config))
         (verbose
          (if (restic-backup-job-verbose? config)
              '("--verbose")
@@ -130,6 +137,19 @@ (define (restic-backup-job-program config)
          (setenv "RESTIC_PASSWORD"
                  (with-input-from-file #$password-file read-line))
 
+         (when #$init?
+           ;; Check if the repository exists. See
+           ;; https://github.com/restic/restic/issues/1690 and
+           ;; https://github.com/NixOS/nixpkgs/pull/307962.
+           ;;
+           ;; XXX: restic returns values other than 1 on failure. Use
+           ;; unless EXIT_SUCCESS instead of when EXIT_FAILURE.
+           (unless (equal? EXIT_SUCCESS (system* #$restic "cat" "config"
+                                               "-r" #$repository))
+             ;; Initialize it.
+             (unless (equal? EXIT_SUCCESS (system* #$restic "init"
+                                                 "-r" #$repository))
+               (error "Failed to initialize restic repository: " #$repository))))
          (execlp #$restic #$restic #$@verbose
                  "-r" #$repository
                  #$@extra-flags
-- 
2.45.1