diff mbox series

[bug#60521,v3] home: Add home-dotfiles-service.

Message ID 20230412203217.32606-1-goodoldpaul@autistici.org
State New
Headers show
Series [bug#60521,v3] home: Add home-dotfiles-service. | expand

Commit Message

Giacomo Leidi April 12, 2023, 8:32 p.m. UTC
* gnu/home/services.scm (dotfiles-for-app): New variable;
(home-dotfiles-configuration): new variable;
(home-dotfiles-service-type): new variable.
* doc/guix.texi: Document it.
---
 doc/guix.texi         | 85 ++++++++++++++++++++++++++++++++++++++++++-
 gnu/home/services.scm | 54 +++++++++++++++++++++++++++
 2 files changed, 138 insertions(+), 1 deletion(-)


base-commit: dd3e5e71104a2bcbad80e52e062a144ea96b8c6a

Comments

Ludovic Courtès April 24, 2023, 8:33 p.m. UTC | #1
Hi Giacomo,

Giacomo Leidi <goodoldpaul@autistici.org> skribis:

> * gnu/home/services.scm (dotfiles-for-app): New variable;
> (home-dotfiles-configuration): new variable;
> (home-dotfiles-service-type): new variable.
> * doc/guix.texi: Document it.

Apologies for the loong delay.

> +The @code{home-dotfiles-service-type} is designed to ease the way into using
> +Guix Home for this kind of users, allowing them to point the service to their
> +dotfiles directory (which must follow
> +@uref{https://www.gnu.org/software/stow/, GNU Stow}'s layout) and have their

Rather, for proper rendering:

  dotfiles directory, which must follow the layout prescribed by
  @uref{https://…, GNU Stow}, and have their …

> +For a more formal specification please refer to the
> +@pxref{Top,,, stow, GNU Stow Manual}.

Rather: please refer to the Stow manual (@pxref{…}).

Maybe a node other than “Top” would be advisable?  I can’t see where
that formal spec might be at
<https://www.gnu.org/software/stow/manual/html_node/>.

> +@lisp
> +  (simple-service 'home-dotfiles
> +                  home-dotfiles-service-type
> +                  (list (string-append (getcwd)
> +                                       "/.dotfiles")))

Replace (getcwd) by (current-source-directory), though hmm that’s part
of (guix utils).

(Using (getcwd) is wrong because it gives the current directory of the
‘guix’ command that evaluates this code, not the directory the file
lives in.)

> +(define (dotfiles-for-app directory)
> +  "Return a list of objects compatible with @code{home-files-service-type}'s
> +value.  Each object is a pair where the first element is the relative path
> +of a file and the second is a gexp representing the file content.  Objects are
> +generated by recursively visiting DIRECTORY and mapping its contents to the
> +user's home directory."
> +  (map (lambda (file)
> +         (let ((file-relative-path
> +                (string-drop file (1+ (string-length directory)))))
> +           (list file-relative-path
> +                 (local-file file
> +                             (string-append "home-dotfiles-"
> +                                            (string-replace-substring
> +                                             file-relative-path
> +                                             "/" "-"))))))
> +       (find-files directory)))

In general, use the term “file name”, not “path”.

The variable name can become, say, ‘file-relative’.

Maybe s/dotfiles-for-app/import-dotfiles/ ?  But see below.

(Sorry for not noticing these earlier!)

> +(define-public (home-dotfiles-configuration dotfiles-directories)

s/define-public/define/ since it’s already exported at the top.

> +  "Return a list of objects compatible with @code{home-files-service-type}'s
> +value, generated following GNU Stow's algorithm for each of the
> +DOTFILES-DIRECTORIES."
> +  (define (directory-contents directories)
> +    (append-map
> +     (lambda (directory)
> +       (map
> +        (lambda (content)
> +          (with-directory-excursion directory
> +              (canonicalize-path content)))
> +        (scandir directory
> +          (lambda (name)
> +            (not (member name '("." "..")))))))
> +     directories))
> +  (append-map
> +   dotfiles-for-app
> +   (directory-contents dotfiles-directories)))

Am I right that this is the same as:

  (append-map (lambda (directory)
                (let ((parent (basename directory))
                      (files (find-files directory)))
                  (define (strip file)
                    (string-drop file (+ 1 (string-length directory))))

                  (map (lambda (file)
                         (list (strip file) (local-file file)))
                       (find-files directory))))
              directories)

?

(In that case, we wouldn’t even need ‘dotfiles-for-app’.)

Also, should we pass ‘find-files’ a predicate to exclude editor backup
files, VCS files, etc.?

Thanks,
Ludo’.
diff mbox series

Patch

diff --git a/doc/guix.texi b/doc/guix.texi
index acb6f0c2e1..b95053039f 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -111,9 +111,9 @@  Copyright @copyright{} 2022 (@*
 Copyright @copyright{} 2022 John Kehayias@*
 Copyright @copyright{} 2022⁠–⁠2023 Bruno Victal@*
 Copyright @copyright{} 2022 Ivan Vilata-i-Balaguer@*
-Copyright @copyright{} 2023 Giacomo Leidi@*
 Copyright @copyright{} 2022 Antero Mejr@*
 Copyright @copyright{} 2023 Karl Hallsby
+Copyright @copyright{} 2023 Giacomo Leidi@*
 
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -42029,6 +42029,89 @@  to use alternative services to implement more advanced use cases like
 read-only home.  Feel free to experiment and share your results.
 @end defvar
 
+It is often the case that Guix Home users already have a setup for versioning
+their user configuration files (also known as @emph{dotfiles}) in a single
+directory, and some way of automatically deploy changes to their user home.
+
+The @code{home-dotfiles-service-type} is designed to ease the way into using
+Guix Home for this kind of users, allowing them to point the service to their
+dotfiles directory (which must follow
+@uref{https://www.gnu.org/software/stow/, GNU Stow}'s layout) and have their
+dotfiles automatically deployed to their user home, without migrating them to
+Guix native configurations.
+
+The dotfiles directory layout is expected to be structured as follows:
+
+@example
+~$ tree -a .dotfiles/
+.dotfiles/
+├── git
+│   └── .gitconfig
+├── gpg
+│   └── .gnupg
+│       ├── gpg-agent.conf
+│       └── gpg.conf
+├── guile
+│   └── .guile
+├── guix
+│   └── .config
+│       └── guix
+│           └── channels.scm
+├── nix
+│   ├── .config
+│   │   └── nixpkgs
+│   │       └── config.nix
+│   └── .nix-channels
+├── tmux
+│   └── .tmux.conf
+└── vim
+    └── .vimrc
+
+13 directories, 10 files
+@end example
+
+For a more formal specification please refer to the
+@pxref{Top,,, stow, GNU Stow Manual}. It is advisable to keep your dotfiles
+directories under version control, for example in the same repository where
+you'd track your Guix Home configuration. A suitable configuration would then
+be:
+
+@lisp
+  (simple-service 'home-dotfiles
+                  home-dotfiles-service-type
+                  (list (string-append (getcwd)
+                                       "/.dotfiles")))
+@end lisp
+
+The expected home directory state would be:
+
+@example
+.
+├── .config
+│   ├── guix
+│   │   └── channels.scm
+│   └── nixpkgs
+│       └── config.nix
+├── .gitconfig
+├── .gnupg
+│   ├── gpg-agent.conf
+│   └── gpg.conf
+├── .guile
+├── .nix-channels
+├── .tmux.conf
+└── .vimrc
+@end example
+
+@defvar home-dotfiles-service-type
+Return a service which is very similiar to @code{home-files-service-type}
+(and actually extends it), but designed to ease the way into using Guix
+Home for users that already track their dotfiles under some kind of version
+control.  This service allows users to point Guix Home to their dotfiles
+directory and have their file automatically deployed to their home directory
+just like Stow would, without migrating all of their dotfiles to Guix native
+configurations.
+@end defvar
+
 @defvar home-xdg-configuration-files-service-type
 The service is very similiar to @code{home-files-service-type} (and
 actually extends it), but used for defining files, which will go to
diff --git a/gnu/home/services.scm b/gnu/home/services.scm
index b17a34d19d..c45b8cbe24 100644
--- a/gnu/home/services.scm
+++ b/gnu/home/services.scm
@@ -2,6 +2,7 @@ 
 ;;; Copyright © 2021-2023 Andrew Tropin <andrew@trop.in>
 ;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
 ;;; Copyright © 2022-2023 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2023 Giacomo Leidi <goodoldpaul@autistici.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -22,6 +23,7 @@  (define-module (gnu home services)
   #:use-module (gnu services)
   #:use-module ((gnu packages package-management) #:select (guix))
   #:use-module ((gnu packages base) #:select (coreutils))
+  #:use-module (guix build utils)
   #:use-module (guix channels)
   #:use-module (guix monads)
   #:use-module (guix store)
@@ -35,13 +37,17 @@  (define-module (gnu home services)
   #:use-module (guix modules)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-9)
+  #:use-module (ice-9 ftw)
   #:use-module (ice-9 match)
+  #:use-module (ice-9 string-fun)
   #:use-module (ice-9 vlist)
 
   #:export (home-service-type
             home-profile-service-type
             home-environment-variables-service-type
             home-files-service-type
+            home-dotfiles-service-type
+            home-dotfiles-configuration
             home-xdg-configuration-files-service-type
             home-xdg-data-files-service-type
             home-run-on-first-login-service-type
@@ -341,6 +347,54 @@  (define home-files-service-type
                 (description "Files that will be put in
 @file{~/.guix-home/files}, and further processed during activation.")))
 
+(define (dotfiles-for-app directory)
+  "Return a list of objects compatible with @code{home-files-service-type}'s
+value.  Each object is a pair where the first element is the relative path
+of a file and the second is a gexp representing the file content.  Objects are
+generated by recursively visiting DIRECTORY and mapping its contents to the
+user's home directory."
+  (map (lambda (file)
+         (let ((file-relative-path
+                (string-drop file (1+ (string-length directory)))))
+           (list file-relative-path
+                 (local-file file
+                             (string-append "home-dotfiles-"
+                                            (string-replace-substring
+                                             file-relative-path
+                                             "/" "-"))))))
+       (find-files directory)))
+
+(define-public (home-dotfiles-configuration dotfiles-directories)
+  "Return a list of objects compatible with @code{home-files-service-type}'s
+value, generated following GNU Stow's algorithm for each of the
+DOTFILES-DIRECTORIES."
+  (define (directory-contents directories)
+    (append-map
+     (lambda (directory)
+       (map
+        (lambda (content)
+          (with-directory-excursion directory
+              (canonicalize-path content)))
+        (scandir directory
+          (lambda (name)
+            (not (member name '("." "..")))))))
+     directories))
+  (append-map
+   dotfiles-for-app
+   (directory-contents dotfiles-directories)))
+
+(define-public home-dotfiles-service-type
+  (service-type (name 'home-dotfiles)
+                (extensions
+                 (list (service-extension home-files-service-type
+                                          home-dotfiles-configuration)))
+                (default-value '())
+                (extend append)
+                (compose concatenate)
+                (description "Files contained is these directories will be put
+in the user's home directory according to GNU Stow's algorithm, and further
+processed during activation.")))
+
 (define xdg-configuration-files-directory ".config")
 
 (define (xdg-configuration-files files)