[PATCH] home: Add home-stow-migration-service.

  • Open
  • quality assurance status badge
Details
4 participants
  • Andrew Tropin
  • goodoldpaul
  • Ludovic Courtès
  • Bruno Victal
Owner
unassigned
Submitted by
goodoldpaul
Severity
normal
G
G
goodoldpaul wrote on 3 Jan 17:51 +0100
(address . guix-patches@gnu.org)
0a8d7bce31856292baa06a08260494c0@autistici.org
Dear Guixers,

I'm upstreaming a Guix Home service I've been using for quite some time
in my personal channel (
) with some small improvements to make it suitable for Guix mainline.

The point of this service is to allow GNU Stow users to switch to Guix
Home without any change to their Stow directory structure, in the hope
of easing the way into Guix Home allowing users to avoid convert all of
their dotfiles to Guix native configurations.

Thank you for your time and efforts,

giacomo
G
G
Giacomo Leidi wrote on 3 Jan 17:55 +0100
(address . 60521@debbugs.gnu.org)(name . Giacomo Leidi)(address . goodoldpaul@autistici.org)
20230103165534.25644-1-goodoldpaul@autistici.org
* gnu/home/services.scm (dotfiles-for-app): New variable;
(home-stow-migration-configuration): new variable;
(home-stow-migration-service): new variable.
* doc/guix.texi: Document it.
---
doc/guix.texi | 50 +++++++++++++++++++++++++++++++++++++++++++
gnu/home/services.scm | 49 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 99 insertions(+)

Toggle diff (167 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index 5c85680831..40c36f65c4 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -109,6 +109,7 @@ Copyright @copyright{} 2022 Reily Siegel@*
Copyright @copyright{} 2022 Simon Streit@*
Copyright @copyright{} 2022 (@*
Copyright @copyright{} 2022 John Kehayias@*
+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
@@ -41119,6 +41120,55 @@ to use alternative services to implement more advanced use cases like
read-only home. Feel free to experiment and share your results.
@end defvr
+@deffn {Scheme Procedure} home-stow-migration-service
+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 GNU Stow users. This service allows users to point Guix Home to
+their Stow 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.
+
+A typical Stow setup consists of a source directory and a target directory.
+The source directory must 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
+│ └── .gitignore
+├── nix
+│ ├── .config
+│ │ └── nixpkgs
+│ │ └── config.nix
+│ └── .nix-channels
+├── tmux
+│ └── .tmux.conf
+└── vim
+ └── .vimrc
+
+13 directories, 10 files
+@end example
+
+A suitable configuration would then be:
+
+@lisp
+ (home-stow-migration-service
+ (string-append (getenv "HOME")
+ "/.dotfiles"))
+@end lisp
+@end deffn
+
@defvr {Scheme Variable} 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 99035686f1..996647c592 100644
--- a/gnu/home/services.scm
+++ b/gnu/home/services.scm
@@ -1,6 +1,7 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
+;;; Copyright © 2023 Giacomo Leidi <goodoldpaul@autistici.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -21,6 +22,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)
@@ -33,13 +35,16 @@ (define-module (gnu home services)
#:use-module (guix i18n)
#:use-module (guix modules)
#:use-module (srfi srfi-1)
+ #: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-stow-migration-service
home-xdg-configuration-files-service-type
home-xdg-data-files-service-type
home-run-on-first-login-service-type
@@ -49,6 +54,7 @@ (define-module (gnu home services)
environment-variable-shell-definitions
home-files-directory
+ home-stow-migration-configuration
xdg-configuration-files-directory
xdg-data-files-directory
@@ -315,6 +321,49 @@ (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 app-dir)
+ "Return a list of objects compatible with @{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 APP-DIR and mapping its contents to the
+user's home directory."
+ (let ((app-absolute-path (canonicalize-path app-dir)))
+ (map (lambda (path)
+ (let ((app-file-relative-path
+ (string-replace-substring path
+ (string-append app-absolute-path "/")
+ "")))
+ (list app-file-relative-path
+ (local-file path
+ (string-append "home-stow-migration-"
+ (string-replace-substring
+ app-file-relative-path
+ "/" "-"))))))
+ (find-files app-absolute-path))))
+
+(define (home-stow-migration-configuration stow-dir)
+ "Return a list of objects compatible with @{home-files-service-type}'s
+value, generated following GNU Stow's algorithm using STOW-DIR as input
+directory."
+ (define (dir-contents dir)
+ (scandir dir
+ (lambda (name)
+ (not (member name '("." ".."))))))
+ (fold append
+ '()
+ (map (lambda (app-dir)
+ (dotfiles-for-app
+ (string-append stow-dir "/" app-dir)))
+ (dir-contents stow-dir))))
+
+(define-public (home-stow-migration-service stow-dir)
+ "Return a service extending @{home-files-service-type} with files from
+STOW-DIR. Files will be put in the user's home directory following GNU
+Stow's algorithm, and further processed during activation."
+ (simple-service 'home-stow-migration-service
+ home-files-service-type
+ (home-stow-migration-configuration stow-dir)))
+
(define xdg-configuration-files-directory ".config")
(define (xdg-configuration-files files)

base-commit: 473692b812b4ab4267d9bddad0fb27787d2112ff
--
2.38.1
L
L
Ludovic Courtès wrote on 17 Jan 14:09 +0100
(name . Giacomo Leidi)(address . goodoldpaul@autistici.org)(address . 60521@debbugs.gnu.org)
87o7qxi9ym.fsf_-_@gnu.org
Hi!

Giacomo Leidi <goodoldpaul@autistici.org> skribis:

Toggle quote (5 lines)
> * gnu/home/services.scm (dotfiles-for-app): New variable;
> (home-stow-migration-configuration): new variable;
> (home-stow-migration-service): new variable.
> * doc/guix.texi: Document it.

That looks very useful!

Toggle quote (6 lines)
> @@ -41119,6 +41120,55 @@ to use alternative services to implement more advanced use cases like
> read-only home. Feel free to experiment and share your results.
> @end defvr
>
> +@deffn {Scheme Procedure} home-stow-migration-service

Perhaps write a short intro (one or two sentences) above?

Toggle quote (47 lines)
> +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 GNU Stow users. This service allows users to point Guix Home to
> +their Stow 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.
> +
> +A typical Stow setup consists of a source directory and a target directory.
> +The source directory must 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
> +│ └── .gitignore
> +├── nix
> +│ ├── .config
> +│ │ └── nixpkgs
> +│ │ └── config.nix
> +│ └── .nix-channels
> +├── tmux
> +│ └── .tmux.conf
> +└── vim
> + └── .vimrc
> +
> +13 directories, 10 files
> +@end example
> +
> +A suitable configuration would then be:
> +
> +@lisp
> + (home-stow-migration-service
> + (string-append (getenv "HOME")
> + "/.dotfiles"))
> +@end lisp

Maybe add a description of what it’s going to do with those files? It’s
kinda implicit but better be clear.

Also, I feel like there’s nothing really Stow-specific here; it just
happens to be a file layout convention that’s used by Stow, right? So I
wonder if could frame it differently, by describing the expected file
tree structure first, and mentioning Stow only then?

Last, I suggest adding a cross-reference to the Stow manual, as in:

@pxref{Top,,, stow, GNU Stow Manual}

Toggle quote (2 lines)
> +(define (dotfiles-for-app app-dir)
> + "Return a list of objects compatible with @{home-files-service-type}'s
^
Typo, should be @code.

Toggle quote (11 lines)
> +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 APP-DIR and mapping its contents to the
> +user's home directory."
> + (let ((app-absolute-path (canonicalize-path app-dir)))
> + (map (lambda (path)
> + (let ((app-file-relative-path
> + (string-replace-substring path
> + (string-append app-absolute-path "/")
> + "")))

Or just (string-drop path (string-length app-absolute-path)).

Toggle quote (8 lines)
> + (list app-file-relative-path
> + (local-file path
> + (string-append "home-stow-migration-"
> + (string-replace-substring
> + app-file-relative-path
> + "/" "-"))))))
> + (find-files app-absolute-path))))

Nitpick: by convention, the term “path” refers to “search paths”; here
we’d instead use “file name”, but you can also call the variable just
‘file’.

The other convention is to avoid abbreviations in identifiers, and to
avoid long identifiers for local variables.

So s/app-dir/directory/ etc.

Toggle quote (15 lines)
> +(define (home-stow-migration-configuration stow-dir)
> + "Return a list of objects compatible with @{home-files-service-type}'s
> +value, generated following GNU Stow's algorithm using STOW-DIR as input
> +directory."
> + (define (dir-contents dir)
> + (scandir dir
> + (lambda (name)
> + (not (member name '("." ".."))))))
> + (fold append
> + '()
> + (map (lambda (app-dir)
> + (dotfiles-for-app
> + (string-append stow-dir "/" app-dir)))
> + (dir-contents stow-dir))))

You can replace (fold append …) with (append-map …).

Toggle quote (2 lines)
> +(define-public (home-stow-migration-service stow-dir)

You can drop this procedure. Users are expected to write:

(service home-stow-migration-service)

Could you send an updated patch?

Thanks!

Ludo’.
A
A
Andrew Tropin wrote on 17 Jan 16:21 +0100
Re: [bug#60521] [PATCH] home: Add home-stow-migration-service.
(address . 60521@debbugs.gnu.org)
87tu0p89wf.fsf@trop.in
On 2023-01-17 14:09, Ludovic Courtès wrote:

Toggle quote (66 lines)
> Hi!
>
> Giacomo Leidi <goodoldpaul@autistici.org> skribis:
>
>> * gnu/home/services.scm (dotfiles-for-app): New variable;
>> (home-stow-migration-configuration): new variable;
>> (home-stow-migration-service): new variable.
>> * doc/guix.texi: Document it.
>
> That looks very useful!
>
>> @@ -41119,6 +41120,55 @@ to use alternative services to implement more advanced use cases like
>> read-only home. Feel free to experiment and share your results.
>> @end defvr
>>
>> +@deffn {Scheme Procedure} home-stow-migration-service
>
> Perhaps write a short intro (one or two sentences) above?
>
>> +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 GNU Stow users. This service allows users to point Guix Home to
>> +their Stow 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.
>> +
>> +A typical Stow setup consists of a source directory and a target directory.
>> +The source directory must 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
>> +│ └── .gitignore
>> +├── nix
>> +│ ├── .config
>> +│ │ └── nixpkgs
>> +│ │ └── config.nix
>> +│ └── .nix-channels
>> +├── tmux
>> +│ └── .tmux.conf
>> +└── vim
>> + └── .vimrc
>> +
>> +13 directories, 10 files
>> +@end example
>> +
>> +A suitable configuration would then be:
>> +
>> +@lisp
>> + (home-stow-migration-service
>> + (string-append (getenv "HOME")
>> + "/.dotfiles"))
>> +@end lisp

The service looks neat! Thank you, Giacomo.

Ludo, wouldn't it be better and safer to use (local-file "./dotfiles"
#:recursive? #t) here? I find it kinda dangerous for reproducibility to
reference local files and make logic inside the service to depend on it.

Toggle quote (80 lines)
>
> Maybe add a description of what it’s going to do with those files? It’s
> kinda implicit but better be clear.
>
> Also, I feel like there’s nothing really Stow-specific here; it just
> happens to be a file layout convention that’s used by Stow, right? So I
> wonder if could frame it differently, by describing the expected file
> tree structure first, and mentioning Stow only then?
>
> Last, I suggest adding a cross-reference to the Stow manual, as in:
>
> @pxref{Top,,, stow, GNU Stow Manual}
>
>> +(define (dotfiles-for-app app-dir)
>> + "Return a list of objects compatible with @{home-files-service-type}'s
> ^
> Typo, should be @code.
>
>> +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 APP-DIR and mapping its contents to the
>> +user's home directory."
>> + (let ((app-absolute-path (canonicalize-path app-dir)))
>> + (map (lambda (path)
>> + (let ((app-file-relative-path
>> + (string-replace-substring path
>> + (string-append app-absolute-path "/")
>> + "")))
>
> Or just (string-drop path (string-length app-absolute-path)).
>
>> + (list app-file-relative-path
>> + (local-file path
>> + (string-append "home-stow-migration-"
>> + (string-replace-substring
>> + app-file-relative-path
>> + "/" "-"))))))
>> + (find-files app-absolute-path))))
>
> Nitpick: by convention, the term “path” refers to “search paths”; here
> we’d instead use “file name”, but you can also call the variable just
> ‘file’.
>
> The other convention is to avoid abbreviations in identifiers, and to
> avoid long identifiers for local variables.
>
> So s/app-dir/directory/ etc.
>
>> +(define (home-stow-migration-configuration stow-dir)
>> + "Return a list of objects compatible with @{home-files-service-type}'s
>> +value, generated following GNU Stow's algorithm using STOW-DIR as input
>> +directory."
>> + (define (dir-contents dir)
>> + (scandir dir
>> + (lambda (name)
>> + (not (member name '("." ".."))))))
>> + (fold append
>> + '()
>> + (map (lambda (app-dir)
>> + (dotfiles-for-app
>> + (string-append stow-dir "/" app-dir)))
>> + (dir-contents stow-dir))))
>
> You can replace (fold append …) with (append-map …).
>
>> +(define-public (home-stow-migration-service stow-dir)
>
> You can drop this procedure. Users are expected to write:
>
> (service home-stow-migration-service)
>
> Could you send an updated patch?
>
> Thanks!
>
> Ludo’.
>
>
>

--
Best regards,
Andrew Tropin
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmPGvOAACgkQIgjSCVjB
3rD4BA//fWFIt2fMw42Pd/Fag7aiHJL6QDvgo0fSNRvbrf7mySUlGfbDrJBX6mn7
DvQ6GnuiNr6y/PPswA3kIUaODwxlAeB1bHX1QU3S7Kjk3GCdi/h53rLFhlO4hXxj
g+PJ5pJ/ATr5+zd9XdekhT6a1aIPZYGqJHfNM7nMFQeoH+qptgvlkEUqqqdILyxi
1NJJgQUIxyuCGDqqW9RmjKN6b7kN9dIag0F8mRFcReIkBwknwTf9ohGeDcBU5i8T
GUVbp/5NGDs7cErsz8Lu9uS0GQpKVbcpnoLnMrnlxAGVJU6Caexen06LR1wUDXnS
WJ7MeOaeuJ3BRcODZJqMlOSf6kI68KeSmjHQIwZ80j7ui6EhtEsbjjx3bf93wxe8
arUGJo/mXLaJj7w7W2Xv8Ke+1EXY0WBr0x89ZEoQf5LZWVeCrz255+mXDsQDleFa
0REDqiXvoHGAbGfW3D7A6B157it1J4BUzeghp9irSFBZD2RYhgMExChAbvMD3ZU8
VfUe0rOi2Y1yofqS/eFNme4SiE4BxhjlNhSEuut2Ljb05fiXIYe4iwfBzCm/Ly+x
qMT+/6AA5cyZGdzcZLA4CjNFduoVmG0XRrqFW8NKNb19KncQrWpwVxjszdB8Cisq
B/fqVUMxg0W1kUPHiJKxgZj/nyaxiozoWL6mTpcsr0yPtPPxjZk=
=Zozo
-----END PGP SIGNATURE-----

B
B
Bruno Victal wrote on 17 Jan 18:09 +0100
(name . Giacomo Leidi)(address . goodoldpaul@autistici.org)(address . 60521@debbugs.gnu.org)
c8c49872-37f1-a0e0-46a1-91942023f00b@makinata.eu
On 2023-01-03 16:55, Giacomo Leidi via Guix-patches via wrote:
Toggle quote (29 lines)
> * gnu/home/services.scm (dotfiles-for-app): New variable;
> (home-stow-migration-configuration): new variable;
> (home-stow-migration-service): new variable.
> * doc/guix.texi: Document it.
> ---
> doc/guix.texi | 50 +++++++++++++++++++++++++++++++++++++++++++
> gnu/home/services.scm | 49 ++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 99 insertions(+)
>
> diff --git a/doc/guix.texi b/doc/guix.texi
> index 5c85680831..40c36f65c4 100644
> --- a/doc/guix.texi
> +++ b/doc/guix.texi
> @@ -109,6 +109,7 @@ Copyright @copyright{} 2022 Reily Siegel@*
> Copyright @copyright{} 2022 Simon Streit@*
> Copyright @copyright{} 2022 (@*
> Copyright @copyright{} 2022 John Kehayias@*
> +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
> @@ -41119,6 +41120,55 @@ to use alternative services to implement more advanced use cases like
> read-only home. Feel free to experiment and share your results.
> @end defvr
>
> +@deffn {Scheme Procedure} home-stow-migration-service
> +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

Procedures in Guix are almost always Scheme functions, perhaps you could write this as:
@defun home-stow-migration-service

Toggle quote (50 lines)
> +Home for GNU Stow users. This service allows users to point Guix Home to
> +their Stow 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.
> +
> +A typical Stow setup consists of a source directory and a target directory.
> +The source directory must 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
> +│ └── .gitignore
> +├── nix
> +│ ├── .config
> +│ │ └── nixpkgs
> +│ │ └── config.nix
> +│ └── .nix-channels
> +├── tmux
> +│ └── .tmux.conf
> +└── vim
> + └── .vimrc
> +
> +13 directories, 10 files
> +@end example
> +
> +A suitable configuration would then be:
> +
> +@lisp
> + (home-stow-migration-service
> + (string-append (getenv "HOME")
> + "/.dotfiles"))
> +@end lisp
> +@end deffn
> +
> @defvr {Scheme Variable} 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

In a similar vein, this could be written as:
@defvar home-xdg-configuration-files-service-type

Toggle quote (55 lines)
> diff --git a/gnu/home/services.scm b/gnu/home/services.scm
> index 99035686f1..996647c592 100644
> --- a/gnu/home/services.scm
> +++ b/gnu/home/services.scm
> @@ -1,6 +1,7 @@
> ;;; GNU Guix --- Functional package management for GNU
> ;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
> ;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
> +;;; Copyright © 2023 Giacomo Leidi <goodoldpaul@autistici.org>
> ;;;
> ;;; This file is part of GNU Guix.
> ;;;
> @@ -21,6 +22,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)
> @@ -33,13 +35,16 @@ (define-module (gnu home services)
> #:use-module (guix i18n)
> #:use-module (guix modules)
> #:use-module (srfi srfi-1)
> + #: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-stow-migration-service
> home-xdg-configuration-files-service-type
> home-xdg-data-files-service-type
> home-run-on-first-login-service-type
> @@ -49,6 +54,7 @@ (define-module (gnu home services)
>
> environment-variable-shell-definitions
> home-files-directory
> + home-stow-migration-configuration
> xdg-configuration-files-directory
> xdg-data-files-directory
>
> @@ -315,6 +321,49 @@ (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 app-dir)
> + "Return a list of objects compatible with @{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 APP-DIR and mapping its contents to the

Instead of `APP-DIR', you can use the @var command:
@var{app-dir}

Toggle quote (20 lines)
> +user's home directory."
> + (let ((app-absolute-path (canonicalize-path app-dir)))
> + (map (lambda (path)
> + (let ((app-file-relative-path
> + (string-replace-substring path
> + (string-append app-absolute-path "/")
> + "")))
> + (list app-file-relative-path
> + (local-file path
> + (string-append "home-stow-migration-"
> + (string-replace-substring
> + app-file-relative-path
> + "/" "-"))))))
> + (find-files app-absolute-path))))
> +
> +(define (home-stow-migration-configuration stow-dir)
> + "Return a list of objects compatible with @{home-files-service-type}'s
> +value, generated following GNU Stow's algorithm using STOW-DIR as input
> +directory."

Same as above.

Toggle quote (15 lines)
> + (define (dir-contents dir)
> + (scandir dir
> + (lambda (name)
> + (not (member name '("." ".."))))))
> + (fold append
> + '()
> + (map (lambda (app-dir)
> + (dotfiles-for-app
> + (string-append stow-dir "/" app-dir)))
> + (dir-contents stow-dir))))
> +
> +(define-public (home-stow-migration-service stow-dir)
> + "Return a service extending @{home-files-service-type} with files from
> +STOW-DIR. Files will be put in the user's home directory following GNU

Same as above.

Toggle quote (12 lines)
> +Stow's algorithm, and further processed during activation."
> + (simple-service 'home-stow-migration-service
> + home-files-service-type
> + (home-stow-migration-configuration stow-dir)))
> +
> (define xdg-configuration-files-directory ".config")
>
> (define (xdg-configuration-files files)
>
> base-commit: 473692b812b4ab4267d9bddad0fb27787d2112ff


Cheers,
Bruno
L
L
Ludovic Courtès wrote on 23 Jan 11:23 +0100
(name . Andrew Tropin)(address . andrew@trop.in)
87edrl4kio.fsf@gnu.org
Hi,

Andrew Tropin <andrew@trop.in> skribis:

Toggle quote (14 lines)
>>> +A suitable configuration would then be:
>>> +
>>> +@lisp
>>> + (home-stow-migration-service
>>> + (string-append (getenv "HOME")
>>> + "/.dotfiles"))
>>> +@end lisp
>
> The service looks neat! Thank you, Giacomo.
>
> Ludo, wouldn't it be better and safer to use (local-file "./dotfiles"
> #:recursive? #t) here? I find it kinda dangerous for reproducibility to
> reference local files and make logic inside the service to depend on it.

Currently I don’t think that’s possible because the service imports
those files at configuration time, but the end result is the same: those
dot files are copied to the store and that’s what’s referenced.

I think it’s okay like this, but I don’t have a strong opinion.

That said, from a usability viewpoint, it does mean that users would
typically have to version-controlled directories (one with the Home
config file, and one with the Stow-style dot file tree), which is not
great. Perhaps the manual could say something about it.

Thanks,
Ludo’.
A
A
Andrew Tropin wrote on 25 Jan 07:32 +0100
(name . Ludovic Courtès)(address . ludo@gnu.org)
874jsft98i.fsf@trop.in
On 2023-01-23 11:23, Ludovic Courtès wrote:

Toggle quote (30 lines)
> Hi,
>
> Andrew Tropin <andrew@trop.in> skribis:
>
>>>> +A suitable configuration would then be:
>>>> +
>>>> +@lisp
>>>> + (home-stow-migration-service
>>>> + (string-append (getenv "HOME")
>>>> + "/.dotfiles"))
>>>> +@end lisp
>>
>> The service looks neat! Thank you, Giacomo.
>>
>> Ludo, wouldn't it be better and safer to use (local-file "./dotfiles"
>> #:recursive? #t) here? I find it kinda dangerous for reproducibility to
>> reference local files and make logic inside the service to depend on it.
>
> Currently I don’t think that’s possible because the service imports
> those files at configuration time, but the end result is the same: those
> dot files are copied to the store and that’s what’s referenced.
>
> I think it’s okay like this, but I don’t have a strong opinion.
>
> That said, from a usability viewpoint, it does mean that users would
> typically have to version-controlled directories (one with the Home
> config file, and one with the Stow-style dot file tree), which is not
> great. Perhaps the manual could say something about it.
>

The long-term idea I have is to provide a hermetic evaluation mode (not
only for home environments, but for guix in general), which allows to
make sure programmatically that all files referenced comes from either
origins with hash explicitly specified or commited in the current vcs
repository. This way by changing things like

(local-file "./dotfiles" #:recursive? #t) to something like
(file-append (current-repo) "/dotfiles") or
(vcs-file "dotfiles" #:recursive? #t)

we will be able to guarantee that one didn't forget to copy all needed
dependencies for the configuration and to keep API "future compatible"
looks like a good idea.

Just thinking out loud, someday will make a separate
thread/note/prototype on this topic.

Anyway, this service looks good enough to me with the current
implementation and seems potentially helpful.

--
Best regards,
Andrew Tropin
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmPQzP0ACgkQIgjSCVjB
3rAy0g//fVupV4O+bUINCEZFcfV8sPddnl89rEdJ9nISb/XlcHEiMMqRZ9x8d2mk
tLGU/SlW9ZydZn5UQCGt5WsXFR0O9Pc1lpJCcBhOVudbNpR7c+FDBMd5KhfeSEae
paYeT1w6UtD+rhKU2n6Y8cNDa8YmYwWvz1XQBU56nsRZlVRN76n4522fLAw4QgeQ
QspAdPhY91V13+cAGrbc6ksNfzCM/n9M+sCnN9kH+scpawBIkLR5UboFvtGOSWGY
MPVWzLVA7EXcGX8mZb+bIyEDSRfLAPFYhOG1HZ3cCjbnPaZ1nnEDfy/uJuJLqYKj
nh6ryD66ErdL3r4O52ycqSg9DAT+3MEBPvRzwp8kBJW2ynKbMjNNtsGf22g/C+tN
KyR22U3V1I9Jgh8uzLRzMxAcwuhLYLVM8nDVjU3bfxwbm384+AjAjm7kb4nJXZWH
S4f18MvZ8lqvJr/zDdscgxomlNKXe7pnnoDpcqkYF7RiEbFCu+62iTuL7t4B1Y6j
o8DO60BMGnx3pHCb3sMljimIcMpeGGH4ooDIEHSkPURy9ocmS2VjEikwRP2E09Zc
1x8yEpK8i3GgIwv1XBoaoNc5Rs/rYpwHo87KWTShSpYzZwZXnzI/keDddzg0Jb+Q
iRnjRA7oR9m+AW0A3jDwufAZkd/Hcf6bhzcUf8Fd01Cfz50cYoE=
=jT1l
-----END PGP SIGNATURE-----

L
L
Ludovic Courtès wrote on 31 Jan 22:54 +0100
control message for bug #60521
(address . control@debbugs.gnu.org)
87cz6utlnv.fsf@gnu.org
tags 60521 + moreinfo
quit
G
G
goodoldpaul wrote on 12 Feb 18:36 +0100
Re: [PATCH] home: Add home-stow-migration-service.
(name . 60521)(address . 60521@debbugs.gnu.org)
a1a16eaeb8c5e311bcb1f7d3ffae1807@autistici.org
Dear Ludo, Andy and Bruno,
I apologize for the delay. I'm sending a v2, I should have addressed all
of your concerns:

- I agree with you that this is not really Stow specific, so I renamed
the service to home-dotfiles-service-type.
- I didn't think about this last time, but the way I use this service is
by having an etc/ directory in my Guix Home git repository. I specified
this in the manual to address reproducibility concerns.
- In general i gave some polish to everything.
- a nice future improvement could be adding an optional flag to guix
home import to have your Stow directory automatically configured in your
home-environment definition.

I hope everything is okay, thank you for your time.

giacomo
G
G
Giacomo Leidi wrote on 12 Feb 18:36 +0100
[v2] home: Add home-dotfiles-service.
(address . 60521@debbugs.gnu.org)(name . Giacomo Leidi)(address . goodoldpaul@autistici.org)
20230212173640.12008-1-goodoldpaul@autistici.org
* 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(-)

Toggle diff (202 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index 44e2165a82..a6223d69eb 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -111,9 +111,9 @@ Copyright @copyright{} 2022 (@*
Copyright @copyright{} 2022 John Kehayias@*
Copyright @copyright{} 2022 Bruno Victal@*
Copyright @copyright{} 2022 Ivan Vilata-i-Balaguer@*
-Copyright @copyright{} 2023 Giacomo Leidi@*
Copyright @copyright{} 2022 Antero Mejr@*
Copyright @copyright{} 2023 Bruno Victal@*
+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
@@ -41620,6 +41620,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)

base-commit: 2b1383c0a2f79117103b142440c64f6a751d545d
--
2.39.1
G
G
goodoldpaul wrote on 12 Apr 22:31 +0200
Re: [PATCH] home: Add home-stow-migration-service.
13cf3fe05ad572d3385b7e8a16317478@autistici.org
Dear Guixers,

this is a friendly ping :) . I'm sending an updated patchset.

Thank you for your time and efforts,

giacomo
G
G
Giacomo Leidi wrote on 12 Apr 22:32 +0200
[v3] home: Add home-dotfiles-service.
(address . 60521@debbugs.gnu.org)(name . Giacomo Leidi)(address . goodoldpaul@autistici.org)
20230412203217.32606-1-goodoldpaul@autistici.org
* 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(-)

Toggle diff (202 lines)
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)

base-commit: dd3e5e71104a2bcbad80e52e062a144ea96b8c6a
--
2.39.2
L
L
Ludovic Courtès wrote on 24 Apr 22:33 +0200
Re: bug#60521: [PATCH] home: Add home-stow-migration-service.
(name . Giacomo Leidi)(address . goodoldpaul@autistici.org)(address . 60521@debbugs.gnu.org)
87zg6x10lm.fsf_-_@gnu.org
Hi Giacomo,

Giacomo Leidi <goodoldpaul@autistici.org> skribis:

Toggle quote (5 lines)
> * 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.

Toggle quote (5 lines)
> +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 …

Toggle quote (3 lines)
> +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

Toggle quote (6 lines)
> +@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.)

Toggle quote (17 lines)
> +(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!)

Toggle quote (2 lines)
> +(define-public (home-dotfiles-configuration dotfiles-directories)

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

Toggle quote (18 lines)
> + "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’.
P
e4e11cee-8728-0c92-6d5c-64e77dc3a874@autistici.org
Dear Ludo,

I apologize for the long delay. I did not receive a notification of your
post somehow, I may need to change email provider.

> Maybe a node other than “Top” would be advisable? I can’t see where
that formal spec might be at

There may have been a misunderstanding here, I didn't want to imply that
there was a formal specification. I just assumed that being a GNU
project it would have been documented. Anyway I tried to get to the
bottom of this and the only mention/apparent endorsement from the Stow
manual to this layout is in the Introduction [0], which references [1]
as the original source.

[1] explains pretty clearly the layout in a natural language informal
fashion, but searching for "stow" and "dotfiles" on the internet it
appears to be an established de-facto standard. I changed the manual to
"which must follow the layout suggested by". What do you think?

> Am I right that this is the same as:

> [ ... ]

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

It's not the same I believe. The whole (string-append "home-dotfiles"
... is there because at guix/nix/libstore/store-api.cc line 64 and 71
for . and / respectively an exception is thrown if those characters are
in first position or inside the store name. (append-map ...
(dir-contents ... is needed due to the Stow layout: suppose you have a
directory like this one

.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

The most common Stow workflow would be to have this directory at
~/.dotfiles and then


$ cd ~/.dotfiles

$ stow git

$ stow nix

This additional git,nix,gpg,guile etc... layer is not covered by your
code, but I tried my best to simplify import-dotfiles. Please let me
know what are your feeling about the current state of the service.

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

Yes, that's an awesome idea. I implemented a simple filter (currently
'("\\.gitignore" ".*\\.swp" ".*~") ) since I wasn't sure how much we can
assume about this use case.


I should have addressed all of your suggestions, thank you for your time
and help Ludo’ ! I'm sending an update patch.


giacomo


[0]:

[1]:

Attachment: file
G
G
Giacomo Leidi wrote on 24 Jun 18:01 +0200
[PATCH-v4] home: Add home-dotfiles-service.
(address . 60521@debbugs.gnu.org)(name . Giacomo Leidi)(address . goodoldpaul@autistici.org)
b85ed5e41596e6035669cf826df19e7913ceda15.1687622514.git.goodoldpaul@autistici.org
* 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 | 108 ++++++++++++++++++++++++++++++++++++++++++
gnu/home/services.scm | 78 ++++++++++++++++++++++++++++++
2 files changed, 186 insertions(+)

Toggle diff (242 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index c961f706ec..cb3b0d05b0 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -42659,6 +42659,114 @@ Essential Home Services
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 the layout suggested by
+@uref{https://www.gnu.org/software/stow/, GNU Stow},
+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. Please
+keep in mind that 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.
+
+@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 an informal specification please refer to the Stow manual
+(@pxref{Top,,, stow, Introduction}). A suitable configuration would then
+be:
+
+@lisp
+(use-modules (guix utils))
+
+(home-environment
+
+ [...]
+
+ (services
+ (service home-dotfiles-service-type
+ (home-dotfiles-configuration
+ (directories
+ (list (string-append (current-source-directory)
+ "/.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
+
+@deftp {Data Type} home-dotfiles-configuration
+Available @code{home-dotfiles-configuration} fields are:
+
+@table @asis
+@item @code{directories} (type: list-of-strings)
+The list of dotfiles directories where @code{home-dotfiles-service-type} will
+look for application dotfiles.
+
+@item @code{exclude} (default: @code{'(".*~" ".*\\.swp" "\\.gitignore")})
+The list of file patterns @code{home-dotfiles-service-type} will exclude while
+visiting @code{directories}.
+
+@end table
+
+@end deftp
+
@defvar home-xdg-configuration-files-service-type
The service is very similar 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..2fe6508a9a 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)
@@ -33,15 +35,24 @@ (define-module (gnu home services)
#:use-module (guix diagnostics)
#:use-module (guix i18n)
#:use-module (guix modules)
+ #:use-module (guix records)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-9)
+ #:use-module (ice-9 ftw)
#:use-module (ice-9 match)
+ #:use-module (ice-9 regex)
+ #: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-dotfiles-configuration?
+ home-dotfiles-configuration-directories
+ home-dotfiles-configuration-excluded
home-xdg-configuration-files-service-type
home-xdg-data-files-service-type
home-run-on-first-login-service-type
@@ -341,6 +352,73 @@ (define home-files-service-type
(description "Files that will be put in
@file{~/.guix-home/files}, and further processed during activation.")))
+(define %home-dotfiles-excluded
+ '(".*~"
+ ".*\\.swp"
+ "\\.gitignore"))
+
+(define-record-type* <home-dotfiles-configuration>
+ home-dotfiles-configuration make-home-dotfiles-configuration
+ home-dotfiles-configuration?
+ (directories home-dotfiles-configuration-directories ;list of strings
+ (default '()))
+ (excluded home-dotfiles-configuration-excluded ;list of strings
+ (default %home-dotfiles-excluded)))
+
+(define* (import-dotfiles directory excluded)
+ "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, excluding files that match any of the patterns in EXCLUDED."
+ (define filtered
+ (find-files directory
+ (lambda (file stat)
+ (not (string-match
+ (string-append
+ "^.*(" (string-join excluded "|") ")$") file)))))
+ (define (strip file)
+ (string-drop file (+ 1 (string-length directory))))
+ (define (format file)
+ (string-append "home-dotfiles-"
+ (string-replace-substring file "/" "-")))
+
+ (map (lambda (file)
+ (let* ((stripped (strip file)))
+ (list stripped
+ (local-file file (format stripped)))))
+ filtered))
+
+(define (home-dotfiles-configuration->files config)
+ "Return a list of objects compatible with @code{home-files-service-type}'s
+value, generated following GNU Stow's algorithm for each of the
+directories in CONFIG, excluding files that match any of the patterns configured."
+ (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
+ (lambda (app)
+ (import-dotfiles app (home-dotfiles-configuration-excluded config)))
+ (directory-contents
+ (home-dotfiles-configuration-directories config))))
+
+(define-public home-dotfiles-service-type
+ (service-type (name 'home-dotfiles)
+ (extensions
+ (list (service-extension home-files-service-type
+ home-dotfiles-configuration->files)))
+ (default-value (home-dotfiles-configuration))
+ (description "Files that will be put in the user's home directory
+following GNU Stow's algorithm, and further processed during activation.")))
+
(define xdg-configuration-files-directory ".config")
(define (xdg-configuration-files files)

base-commit: d6dc82e8cdb2d6114a12b06d449ce7f1150c7f70
--
2.40.1
G
G
goodoldpaul wrote on 26 Aug 11:34 +0200
Re: bug#60521: [PATCH] home: Add home-stow-migration-service.
6178cf42812efc69a1eb22a04994c2e7@autistici.org
Hi,

I'm sending an updated patchset based on the latest master.

Thank you for your time!

giacomo
G
G
Giacomo Leidi wrote on 26 Aug 11:39 +0200
[PATCH-v4] home: Add home-dotfiles-service.
(address . 60521@debbugs.gnu.org)(name . Giacomo Leidi)(address . goodoldpaul@autistici.org)
cd829d7c1a963205e916102ef224f7983e6e79ff.1693042740.git.goodoldpaul@autistici.org
* 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 | 108 ++++++++++++++++++++++++++++++++++++++++++
gnu/home/services.scm | 78 ++++++++++++++++++++++++++++++
2 files changed, 186 insertions(+)

Toggle diff (242 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index 6105195bd9..87f0fdf8a1 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -43153,6 +43153,114 @@ Essential Home Services
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 the layout suggested by
+@uref{https://www.gnu.org/software/stow/, GNU Stow},
+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. Please
+keep in mind that 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.
+
+@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 an informal specification please refer to the Stow manual
+(@pxref{Top,,, stow, Introduction}). A suitable configuration would then
+be:
+
+@lisp
+(use-modules (guix utils))
+
+(home-environment
+
+ [...]
+
+ (services
+ (service home-dotfiles-service-type
+ (home-dotfiles-configuration
+ (directories
+ (list (string-append (current-source-directory)
+ "/.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
+
+@deftp {Data Type} home-dotfiles-configuration
+Available @code{home-dotfiles-configuration} fields are:
+
+@table @asis
+@item @code{directories} (type: list-of-strings)
+The list of dotfiles directories where @code{home-dotfiles-service-type} will
+look for application dotfiles.
+
+@item @code{exclude} (default: @code{'(".*~" ".*\\.swp" "\\.gitignore")})
+The list of file patterns @code{home-dotfiles-service-type} will exclude while
+visiting @code{directories}.
+
+@end table
+
+@end deftp
+
@defvar home-xdg-configuration-files-service-type
The service is very similar 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 8d53f2f4d3..8a74052b5a 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)
@@ -34,15 +36,24 @@ (define-module (gnu home services)
#:use-module (guix i18n)
#:use-module (guix modules)
#:use-module (guix memoization)
+ #:use-module (guix records)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-9)
+ #:use-module (ice-9 ftw)
#:use-module (ice-9 match)
+ #:use-module (ice-9 regex)
+ #: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-dotfiles-configuration?
+ home-dotfiles-configuration-directories
+ home-dotfiles-configuration-excluded
home-xdg-configuration-files-service-type
home-xdg-data-files-service-type
home-run-on-first-login-service-type
@@ -354,6 +365,73 @@ (define home-files-service-type
(description "Files that will be put in
@file{~/.guix-home/files}, and further processed during activation.")))
+(define %home-dotfiles-excluded
+ '(".*~"
+ ".*\\.swp"
+ "\\.gitignore"))
+
+(define-record-type* <home-dotfiles-configuration>
+ home-dotfiles-configuration make-home-dotfiles-configuration
+ home-dotfiles-configuration?
+ (directories home-dotfiles-configuration-directories ;list of strings
+ (default '()))
+ (excluded home-dotfiles-configuration-excluded ;list of strings
+ (default %home-dotfiles-excluded)))
+
+(define* (import-dotfiles directory excluded)
+ "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, excluding files that match any of the patterns in EXCLUDED."
+ (define filtered
+ (find-files directory
+ (lambda (file stat)
+ (not (string-match
+ (string-append
+ "^.*(" (string-join excluded "|") ")$") file)))))
+ (define (strip file)
+ (string-drop file (+ 1 (string-length directory))))
+ (define (format file)
+ (string-append "home-dotfiles-"
+ (string-replace-substring file "/" "-")))
+
+ (map (lambda (file)
+ (let* ((stripped (strip file)))
+ (list stripped
+ (local-file file (format stripped)))))
+ filtered))
+
+(define (home-dotfiles-configuration->files config)
+ "Return a list of objects compatible with @code{home-files-service-type}'s
+value, generated following GNU Stow's algorithm for each of the
+directories in CONFIG, excluding files that match any of the patterns configured."
+ (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
+ (lambda (app)
+ (import-dotfiles app (home-dotfiles-configuration-excluded config)))
+ (directory-contents
+ (home-dotfiles-configuration-directories config))))
+
+(define-public home-dotfiles-service-type
+ (service-type (name 'home-dotfiles)
+ (extensions
+ (list (service-extension home-files-service-type
+ home-dotfiles-configuration->files)))
+ (default-value (home-dotfiles-configuration))
+ (description "Files that will be put in the user's home directory
+following GNU Stow's algorithm, and further processed during activation.")))
+
(define xdg-configuration-files-directory ".config")
(define (xdg-configuration-files files)

base-commit: eeb71d778f149834015858467fbeeb1276d96d1d
--
2.41.0
P
Re: bug#60521: [PATCH] home: Add home-stow-migration-service.
96a1d2be-bf39-f15c-1947-0a6ddeb2e44b@autistici.org
Hi,

I'm sending an updated patchset rebased on current master.


Thank you for your time,


giacomo
G
G
Giacomo Leidi wrote on 22 Sep 15:01 +0200
[PATCH] home: Add home-dotfiles-service.
(address . 60521@debbugs.gnu.org)(name . Giacomo Leidi)(address . goodoldpaul@autistici.org)
88eee8890b69cd58052188348f89fc673fa1c922.1695387663.git.goodoldpaul@autistici.org
* 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 | 108 ++++++++++++++++++++++++++++++++++++++++++
gnu/home/services.scm | 78 ++++++++++++++++++++++++++++++
2 files changed, 186 insertions(+)

Toggle diff (242 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index 617b8463e3..9d75253c2b 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -43239,6 +43239,114 @@ Essential Home Services
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 the layout suggested by
+@uref{https://www.gnu.org/software/stow/, GNU Stow},
+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. Please
+keep in mind that 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.
+
+@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 an informal specification please refer to the Stow manual
+(@pxref{Top,,, stow, Introduction}). A suitable configuration would then
+be:
+
+@lisp
+(use-modules (guix utils))
+
+(home-environment
+
+ [...]
+
+ (services
+ (service home-dotfiles-service-type
+ (home-dotfiles-configuration
+ (directories
+ (list (string-append (current-source-directory)
+ "/.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
+
+@deftp {Data Type} home-dotfiles-configuration
+Available @code{home-dotfiles-configuration} fields are:
+
+@table @asis
+@item @code{directories} (type: list-of-strings)
+The list of dotfiles directories where @code{home-dotfiles-service-type} will
+look for application dotfiles.
+
+@item @code{exclude} (default: @code{'(".*~" ".*\\.swp" "\\.gitignore")})
+The list of file patterns @code{home-dotfiles-service-type} will exclude while
+visiting @code{directories}.
+
+@end table
+
+@end deftp
+
@defvar home-xdg-configuration-files-service-type
The service is very similar 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 8d53f2f4d3..8a74052b5a 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)
@@ -34,15 +36,24 @@ (define-module (gnu home services)
#:use-module (guix i18n)
#:use-module (guix modules)
#:use-module (guix memoization)
+ #:use-module (guix records)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-9)
+ #:use-module (ice-9 ftw)
#:use-module (ice-9 match)
+ #:use-module (ice-9 regex)
+ #: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-dotfiles-configuration?
+ home-dotfiles-configuration-directories
+ home-dotfiles-configuration-excluded
home-xdg-configuration-files-service-type
home-xdg-data-files-service-type
home-run-on-first-login-service-type
@@ -354,6 +365,73 @@ (define home-files-service-type
(description "Files that will be put in
@file{~/.guix-home/files}, and further processed during activation.")))
+(define %home-dotfiles-excluded
+ '(".*~"
+ ".*\\.swp"
+ "\\.gitignore"))
+
+(define-record-type* <home-dotfiles-configuration>
+ home-dotfiles-configuration make-home-dotfiles-configuration
+ home-dotfiles-configuration?
+ (directories home-dotfiles-configuration-directories ;list of strings
+ (default '()))
+ (excluded home-dotfiles-configuration-excluded ;list of strings
+ (default %home-dotfiles-excluded)))
+
+(define* (import-dotfiles directory excluded)
+ "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, excluding files that match any of the patterns in EXCLUDED."
+ (define filtered
+ (find-files directory
+ (lambda (file stat)
+ (not (string-match
+ (string-append
+ "^.*(" (string-join excluded "|") ")$") file)))))
+ (define (strip file)
+ (string-drop file (+ 1 (string-length directory))))
+ (define (format file)
+ (string-append "home-dotfiles-"
+ (string-replace-substring file "/" "-")))
+
+ (map (lambda (file)
+ (let* ((stripped (strip file)))
+ (list stripped
+ (local-file file (format stripped)))))
+ filtered))
+
+(define (home-dotfiles-configuration->files config)
+ "Return a list of objects compatible with @code{home-files-service-type}'s
+value, generated following GNU Stow's algorithm for each of the
+directories in CONFIG, excluding files that match any of the patterns configured."
+ (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
+ (lambda (app)
+ (import-dotfiles app (home-dotfiles-configuration-excluded config)))
+ (directory-contents
+ (home-dotfiles-configuration-directories config))))
+
+(define-public home-dotfiles-service-type
+ (service-type (name 'home-dotfiles)
+ (extensions
+ (list (service-extension home-files-service-type
+ home-dotfiles-configuration->files)))
+ (default-value (home-dotfiles-configuration))
+ (description "Files that will be put in the user's home directory
+following GNU Stow's algorithm, and further processed during activation.")))
+
(define xdg-configuration-files-directory ".config")
(define (xdg-configuration-files files)

base-commit: f45c0c82289d409b4fac00464ea8b323839ba53f
--
2.41.0
?