Subject: [PATCH] home: Add home-restic-backup service.

From: Giacomo Leidi <[email-masked]>
Date: Mon, 10 Feb 2025 01:06:42 +0100

* gnu/home/services/backup.scm: New file.
* gnu/local.mk: Add this.
* doc/guix.texi: Document this.

Change-Id: Ied1c0a5756b715fba176a0e42ea154246089e6be
---
 doc/guix.texi                |  49 ++++++++++++++++
 gnu/home/services/backup.scm | 107 +++++++++++++++++++++++++++++++++++
 gnu/local.mk                 |   1 +
 3 files changed, 157 insertions(+)
 create mode 100644 gnu/home/services/backup.scm

diff --git a/doc/guix.texi b/doc/guix.texi
index 86582fb4785..f8ad6769306 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -462,6 +462,7 @@ Top
 * GPG: GNU Privacy Guard.       Setting up GPG and related tools.
 * Desktop: Desktop Home Services.  Services for graphical environments.
 * Guix: Guix Home Services.     Services for Guix.
+* Backup: Backup Home Services.   Services for backing up User's files.
 * Fonts: Fonts Home Services.   Services for managing User's fonts.
 * Sound: Sound Home Services.   Dealing with audio.
 * Mail: Mail Home Services.     Services for managing mail.
@@ -46729,6 +46730,7 @@ Home Services
 * GPG: GNU Privacy Guard.       Setting up GPG and related tools.
 * Desktop: Desktop Home Services.  Services for graphical environments.
 * Guix: Guix Home Services.     Services for Guix.
+* Backup: Backup Home Services.   Services for backing up User's files.
 * Fonts: Fonts Home Services.   Services for managing User's fonts.
 * Sound: Sound Home Services.   Dealing with audio.
 * Mail: Mail Home Services.     Services for managing mail.
@@ -48275,6 +48277,53 @@ Guix Home Services
 @end lisp
 @end defvar
 
+@node Backup Home Services
+@subsection Backup Home Services
+
+The @code{(gnu services backup)} module offers services for backing up
+file system trees.  For now, it provides the @code{restic-backup-service-type}.
+
+With @code{restic-backup-service-type}, you can periodically back up
+directories and files with @uref{https://restic.net/, Restic}, which
+supports end-to-end encryption and deduplication.  Consider the
+following configuration:
+
+@lisp
+(use-modules (gnu services backup)      ;for 'restic-backup-job' and 'restic-backup-configuration'
+             (gnu home services backup) ;for 'restic-backup-service-type'
+             (gnu packages sync)        ;for 'rclone'
+             @dots{})
+
+(home-environment
+
+  (packages (list rclone    ;for use by restic
+                  @dots{}))
+  (services
+    (list
+      (service home-restic-backup-service-type
+               (restic-backup-configuration
+                 (jobs
+                   (list (restic-backup-job
+                           (name "remote-ftp")
+                           (repository "rclone:remote-ftp:backup/restic")
+                           (password-file "/home/alice/.restic")
+                           ;; Every day at 23.
+                           (schedule "0 23 * * *")
+                           (files '("/home/alice/.restic"
+                                    "/home/alice/.config/rclone"
+                                    "/home/alice/Pictures"))))))))))
+@end lisp
+
+You can refer to @pxref{Miscellaneous Services,
+@code{restic-backup-service-type}} for details about
+@code{restic-backup-configuration} and @code{restic-job-configuration}.
+The only difference is that the @code{home-restic-backup-service-type}
+will ignore the @code{user} and @code{group} field of
+@code{restic-job-configuration}.
+
+It will also install the @command{restic-guix} package to the user's Home
+profile.
+
 @node Fonts Home Services
 @subsection Fonts Home Services
 
diff --git a/gnu/home/services/backup.scm b/gnu/home/services/backup.scm
new file mode 100644
index 00000000000..421737eef74
--- /dev/null
+++ b/gnu/home/services/backup.scm
@@ -0,0 +1,107 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2025 Giacomo Leidi <[email-masked]>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu home services backup)
+  #:use-module (guix gexp)
+  #:use-module (guix packages)
+  #:use-module (gnu services)
+  #:use-module (gnu services backup)
+  #:use-module (gnu services configuration)
+  #:use-module (gnu home services)
+  #:use-module (gnu home services shepherd)
+  #:use-module (srfi srfi-1)
+  #:export (home-restic-backup-service-type))
+
+(define (home-restic-job-log-file job)
+  (let ((name (restic-backup-job-name job))
+        (log-file (restic-backup-job-log-file job)))
+    (and (maybe-value-set? log-file) log-file)))
+
+(define (restic-backup-job->home-shepherd-service config)
+  (let ((schedule (restic-backup-job-schedule config))
+        (name (restic-backup-job-name config))
+        (files (restic-backup-job-files config))
+        (max-duration (restic-backup-job-max-duration config))
+        (wait-for-termination? (restic-backup-job-wait-for-termination? config))
+        (log-file (home-restic-job-log-file config))
+        (requirement (restic-backup-job-requirement config)))
+    (shepherd-service (provision `(,(string->symbol name)))
+                      (requirement
+                       `(,@requirement))
+                      (documentation
+                       "Run @code{restic} backed backups on a regular basis.")
+                      (modules '((shepherd service timer)
+                                 ;;for %user-log-dir
+                                 (shepherd support)))
+                      (start
+                       #~(make-timer-constructor
+                          (if (string? #$schedule)
+                              (cron-string->calendar-event #$schedule)
+                              #$schedule)
+                          (command
+                           (list
+                            "restic-guix" "backup" #$name #$@files))
+                          #:log-file (if (string? #$log-file)
+                                         #$log-file
+                                         (string-append %user-log-dir "/restic-backup/" #$name ".log"))
+                          #:wait-for-termination? #$wait-for-termination?
+                          #:max-duration #$(and (maybe-value-set? max-duration)
+                                                max-duration)))
+                      (stop
+                       #~(make-timer-destructor))
+                      (actions (list (shepherd-action
+                                      (name 'trigger)
+                                      (documentation "Manually trigger a backup,
+without waiting for the scheduled time.")
+                                      (procedure #~trigger-timer)))))))
+
+(define (home-restic-backup-activation config)
+  #~(begin
+      (use-modules (shepherd support))
+      (mkdir-p (string-append %user-log-dir "/restic-backup/"))
+      (for-each
+       (lambda (log-file)
+         (when (string? log-file)
+           (mkdir-p (dirname log-file))))
+       (list #$@(map home-restic-job-log-file
+                     (restic-backup-configuration-jobs config))))))
+
+(define home-restic-backup-service-type
+  (service-type (name 'home-restic-backup)
+                (extensions
+                 (list
+                  (service-extension home-activation-service-type
+                                     home-restic-backup-activation)
+                  (service-extension home-profile-service-type
+                                     restic-backup-service-profile)
+                  (service-extension home-shepherd-service-type
+                                     (lambda (config)
+                                       (map restic-backup-job->home-shepherd-service
+                                            (restic-backup-configuration-jobs
+                                             config))))))
+                (compose concatenate)
+                (extend
+                 (lambda (config jobs)
+                   (restic-backup-configuration
+                    (inherit config)
+                    (jobs (append (restic-backup-configuration-jobs config)
+                                  jobs)))))
+                (default-value (restic-backup-configuration))
+                (description
+                 "This service configures Shepherd timers for running backups
+with restic.")))
diff --git a/gnu/local.mk b/gnu/local.mk
index 117280fc11b..b78c6755f12 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -102,6 +102,7 @@ GNU_SYSTEM_MODULES =				\
   %D%/home.scm					\
   %D%/home/services.scm			\
   %D%/home/services/admin.scm			\
+  %D%/home/services/backup.scm			\
   %D%/home/services/desktop.scm			\
   %D%/home/services/dict.scm			\
   %D%/home/services/dotfiles.scm		\

base-commit: a1fac696c4ef5e20d0412ec22ae6a0d77ea26682
-- 
2.48.1