gnu: home: dotfiles: Properly support both plain and Stow directory layouts.
Fixes <https://issues.guix.gnu.org/68848>. The current implementation of the home-dotfiles-service-type contradicts the Guix manual. This patch properly implements both the plain and Stow dotfiles directory layouts. It does so by refactoring home-dotfiles-configuration adding a new packages field to support GNU Stow's users workflow and introducing a new layout field to switch between the two directory layouts. * gnu/home/services/dotfiles (home-dotfiles-configuration): Migrate to (gnu services configuration); [packages]: new field; [layout]: new field; (strip-stow-dotfile): new variable; (strip-plain-dotfile): new variable; (home-dotfiles-configuration->files): use the new fields; [directory-contents]: allow for selecting a subset of application dotfile directories; * doc/guix.texi: document the new layouts. Change-Id: I2e96037608353e360828290f055ec5271cfdfd48 Signed-off-by: Ludovic Courtès <ludo@gnu.org>
This commit is contained in:
parent
9e3061a163
commit
01f685d560
|
@ -111,7 +111,7 @@ Copyright @copyright{} 2022 (@*
|
||||||
Copyright @copyright{} 2022 John Kehayias@*
|
Copyright @copyright{} 2022 John Kehayias@*
|
||||||
Copyright @copyright{} 2022–2023 Bruno Victal@*
|
Copyright @copyright{} 2022–2023 Bruno Victal@*
|
||||||
Copyright @copyright{} 2022 Ivan Vilata-i-Balaguer@*
|
Copyright @copyright{} 2022 Ivan Vilata-i-Balaguer@*
|
||||||
Copyright @copyright{} 2023 Giacomo Leidi@*
|
Copyright @copyright{} 2023-2024 Giacomo Leidi@*
|
||||||
Copyright @copyright{} 2022 Antero Mejr@*
|
Copyright @copyright{} 2022 Antero Mejr@*
|
||||||
Copyright @copyright{} 2023 Karl Hallsby@*
|
Copyright @copyright{} 2023 Karl Hallsby@*
|
||||||
Copyright @copyright{} 2023 Nathaniel Nicandro@*
|
Copyright @copyright{} 2023 Nathaniel Nicandro@*
|
||||||
|
@ -44667,17 +44667,42 @@ directory, and some way of automatically deploy changes to their user home.
|
||||||
@cindex Stow-like dot file management
|
@cindex Stow-like dot file management
|
||||||
The @code{home-dotfiles-service-type} from @code{(gnu home services dotfiles)}
|
The @code{home-dotfiles-service-type} from @code{(gnu home services dotfiles)}
|
||||||
is designed to ease the way into using Guix Home for this kind of users,
|
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
|
allowing them to point the service to their dotfiles directory without
|
||||||
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.
|
migrating them to Guix native configurations.
|
||||||
|
|
||||||
The dotfiles directory layout is expected to be structured as follows. Please
|
Please keep in mind that it is advisable to keep your dotfiles directories under
|
||||||
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
|
version control, for example in the same repository where you'd track your
|
||||||
Guix Home configuration.
|
Guix Home configuration.
|
||||||
|
|
||||||
|
There are two supported dotfiles directory layouts, for now. The
|
||||||
|
@code{'plain} layout, which is structured as follows:
|
||||||
|
|
||||||
|
@example
|
||||||
|
~$ tree -a ./dotfiles/
|
||||||
|
dotfiles/
|
||||||
|
├── .gitconfig
|
||||||
|
├── .gnupg
|
||||||
|
│ ├── gpg-agent.conf
|
||||||
|
│ └── gpg.conf
|
||||||
|
├── .guile
|
||||||
|
├── .config
|
||||||
|
│ ├── guix
|
||||||
|
│ │ └── channels.scm
|
||||||
|
│ └── nixpkgs
|
||||||
|
│ └── config.nix
|
||||||
|
├── .nix-channels
|
||||||
|
├── .tmux.conf
|
||||||
|
└── .vimrc
|
||||||
|
@end example
|
||||||
|
|
||||||
|
This tree structure is installed as is to the
|
||||||
|
home directory upon @command{guix home reconfigure}.
|
||||||
|
|
||||||
|
The @code{'stow} layout, which must
|
||||||
|
follow the layout suggested by
|
||||||
|
@uref{https://www.gnu.org/software/stow/, GNU Stow} presents an additional
|
||||||
|
application specific directory layer, just like:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
~$ tree -a ./dotfiles/
|
~$ tree -a ./dotfiles/
|
||||||
dotfiles/
|
dotfiles/
|
||||||
|
@ -44707,8 +44732,10 @@ dotfiles/
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
For an informal specification please refer to the Stow manual
|
For an informal specification please refer to the Stow manual
|
||||||
(@pxref{Top,,, stow, Introduction}). A suitable configuration would then
|
(@pxref{Top,,, stow, Introduction}). This tree structure is installed following
|
||||||
be:
|
GNU Stow's logic to the home directory upon @command{guix home reconfigure}.
|
||||||
|
|
||||||
|
A suitable configuration with a @code{'plain} layout could be:
|
||||||
|
|
||||||
@lisp
|
@lisp
|
||||||
(home-environment
|
(home-environment
|
||||||
|
@ -44716,7 +44743,7 @@ be:
|
||||||
(services
|
(services
|
||||||
(service home-dotfiles-service-type
|
(service home-dotfiles-service-type
|
||||||
(home-dotfiles-configuration
|
(home-dotfiles-configuration
|
||||||
(directories (list "./dotfiles"))))))
|
(directories '("./dotfiles"))))))
|
||||||
@end lisp
|
@end lisp
|
||||||
|
|
||||||
The expected home directory state would then be:
|
The expected home directory state would then be:
|
||||||
|
@ -44743,32 +44770,47 @@ 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
|
(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
|
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
|
control. This service allows users to point Guix Home to their dotfiles
|
||||||
directory and have their files automatically deployed to their home directory
|
directory and have their files automatically provisioned to their home
|
||||||
just like Stow would, without migrating all of their dotfiles to Guix native
|
directory, without migrating all of their dotfiles to Guix native
|
||||||
configurations.
|
configurations.
|
||||||
@end defvar
|
@end defvar
|
||||||
|
|
||||||
|
@c %start of fragment
|
||||||
|
|
||||||
@deftp {Data Type} home-dotfiles-configuration
|
@deftp {Data Type} home-dotfiles-configuration
|
||||||
Available @code{home-dotfiles-configuration} fields are:
|
Available @code{home-dotfiles-configuration} fields are:
|
||||||
|
|
||||||
@table @asis
|
@table @asis
|
||||||
@item @code{source-directory} (default: @code{(current-source-directory)})
|
@item @code{source-directory} (default: @code{(current-source-directory)}) (type: string)
|
||||||
The path where dotfile directories are resolved. By default dotfile directories
|
The path where dotfile directories are resolved. By default dotfile
|
||||||
are resolved relative the source location where
|
directories are resolved relative the source location where
|
||||||
@code{home-dotfiles-configuration} appears.
|
@code{home-dotfiles-configuration} appears.
|
||||||
|
|
||||||
@item @code{directories} (type: list-of-strings)
|
@item @code{layout} (default: @code{'plain}) (type: symbol)
|
||||||
The list of dotfiles directories where @code{home-dotfiles-service-type} will
|
The intended layout of the specified @code{directory}. It can be either
|
||||||
look for application dotfiles.
|
@code{'stow} or @code{'plain}.
|
||||||
|
|
||||||
@item @code{exclude} (default: @code{'(".*~" ".*\\.swp" "\\.git" "\\.gitignore")})
|
@item @code{directories} (default: @code{'()}) (type: list-of-strings)
|
||||||
The list of file patterns @code{home-dotfiles-service-type} will exclude while
|
The list of dotfiles directories where @code{home-dotfiles-service-type}
|
||||||
visiting each one of the @code{directories}.
|
will look for application dotfiles.
|
||||||
|
|
||||||
|
@item @code{packages} (type: maybe-list-of-strings)
|
||||||
|
The names of a subset of the GNU Stow package layer directories. When provided
|
||||||
|
the @code{home-dotfiles-service-type} will only provision dotfiles from this
|
||||||
|
subset of applications. This field will be ignored if @code{layout} is set
|
||||||
|
to @code{'plain}.
|
||||||
|
|
||||||
|
@item @code{excluded} (default: @code{'(".*~" ".*\\.swp" "\\.git" "\\.gitignore")}) (type: list-of-strings)
|
||||||
|
The list of file patterns @code{home-dotfiles-service-type} will exclude
|
||||||
|
while visiting each one of the @code{directories}.
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@end deftp
|
@end deftp
|
||||||
|
|
||||||
|
|
||||||
|
@c %end of fragment
|
||||||
|
|
||||||
@defvar home-xdg-configuration-files-service-type
|
@defvar home-xdg-configuration-files-service-type
|
||||||
The service is very similar to @code{home-files-service-type} (and
|
The service is very similar to @code{home-files-service-type} (and
|
||||||
actually extends it), but used for defining files, which will go to
|
actually extends it), but used for defining files, which will go to
|
||||||
|
|
|
@ -20,17 +20,25 @@
|
||||||
(define-module (gnu home services dotfiles)
|
(define-module (gnu home services dotfiles)
|
||||||
#:use-module (gnu home services)
|
#:use-module (gnu home services)
|
||||||
#:use-module (gnu services)
|
#:use-module (gnu services)
|
||||||
|
#:use-module (gnu services configuration)
|
||||||
#:autoload (guix build utils) (find-files)
|
#:autoload (guix build utils) (find-files)
|
||||||
|
#:use-module (guix diagnostics)
|
||||||
#:use-module (guix gexp)
|
#:use-module (guix gexp)
|
||||||
#:use-module (guix records)
|
#:use-module (guix i18n)
|
||||||
#:use-module ((guix utils) #:select (current-source-directory))
|
#:use-module ((guix utils) #:select (current-source-directory))
|
||||||
#:use-module (srfi srfi-1)
|
#:use-module (srfi srfi-1)
|
||||||
#:use-module (ice-9 ftw)
|
#:use-module (ice-9 ftw)
|
||||||
|
#:use-module (ice-9 match)
|
||||||
#:use-module (ice-9 regex)
|
#:use-module (ice-9 regex)
|
||||||
#:export (home-dotfiles-service-type
|
#:export (home-dotfiles-service-type
|
||||||
|
home-dotfiles-configuration->files
|
||||||
|
|
||||||
home-dotfiles-configuration
|
home-dotfiles-configuration
|
||||||
home-dotfiles-configuration?
|
home-dotfiles-configuration?
|
||||||
|
home-dotfiles-configuration-fields
|
||||||
|
home-dotfiles-configuration-layout
|
||||||
home-dotfiles-configuration-source-directory
|
home-dotfiles-configuration-source-directory
|
||||||
|
home-dotfiles-configuration-packages
|
||||||
home-dotfiles-configuration-directories
|
home-dotfiles-configuration-directories
|
||||||
home-dotfiles-configuration-excluded))
|
home-dotfiles-configuration-excluded))
|
||||||
|
|
||||||
|
@ -40,26 +48,64 @@ (define %home-dotfiles-excluded
|
||||||
"\\.git"
|
"\\.git"
|
||||||
"\\.gitignore"))
|
"\\.gitignore"))
|
||||||
|
|
||||||
(define-record-type* <home-dotfiles-configuration>
|
(define %home-dotfiles-layouts
|
||||||
home-dotfiles-configuration make-home-dotfiles-configuration
|
'(plain stow))
|
||||||
home-dotfiles-configuration?
|
|
||||||
(source-directory home-dotfiles-configuration-source-directory
|
|
||||||
(default (current-source-directory))
|
|
||||||
(innate))
|
|
||||||
(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 files)
|
(define (sanitize-layout value)
|
||||||
|
(if (member value %home-dotfiles-layouts)
|
||||||
|
value
|
||||||
|
(raise
|
||||||
|
(formatted-message
|
||||||
|
(G_ "layout field of home-dotfiles-configuration should be either 'plain
|
||||||
|
or 'stow, but ~a was found.")
|
||||||
|
value))))
|
||||||
|
|
||||||
|
(define list-of-strings?
|
||||||
|
(list-of string?))
|
||||||
|
|
||||||
|
(define-maybe list-of-strings)
|
||||||
|
|
||||||
|
(define-configuration/no-serialization home-dotfiles-configuration
|
||||||
|
(source-directory
|
||||||
|
(string (current-source-directory))
|
||||||
|
"The path where dotfile directories are resolved. By default dotfile
|
||||||
|
directories are resolved relative the source location where
|
||||||
|
@code{home-dotfiles-configuration} appears.")
|
||||||
|
(layout
|
||||||
|
(symbol 'plain)
|
||||||
|
"The intended layout of the specified @code{directory}. It can be either
|
||||||
|
@code{'stow} or @code{'plain}."
|
||||||
|
(sanitizer sanitize-layout))
|
||||||
|
(directories
|
||||||
|
(list-of-strings '())
|
||||||
|
"The list of dotfiles directories where @code{home-dotfiles-service-type}
|
||||||
|
will look for application dotfiles.")
|
||||||
|
(packages
|
||||||
|
(maybe-list-of-strings)
|
||||||
|
"The names of a subset of the GNU Stow package layer directories. When provided
|
||||||
|
the @code{home-dotfiles-service-type} will only provision dotfiles from this
|
||||||
|
subset of applications. This field will be ignored if @code{layout} is set
|
||||||
|
to @code{'plain}.")
|
||||||
|
(excluded
|
||||||
|
(list-of-strings %home-dotfiles-excluded)
|
||||||
|
"The list of file patterns @code{home-dotfiles-service-type} will exclude
|
||||||
|
while visiting @code{directory}."))
|
||||||
|
|
||||||
|
(define (strip-stow-dotfile file-name directory)
|
||||||
|
(let ((dotfile-name (string-drop file-name (1+ (string-length directory)))))
|
||||||
|
(match (string-split dotfile-name #\/)
|
||||||
|
((package parts ...)
|
||||||
|
(string-join parts "/")))))
|
||||||
|
|
||||||
|
(define (strip-plain-dotfile file-name directory)
|
||||||
|
(string-drop file-name (+ 1 (string-length directory))))
|
||||||
|
|
||||||
|
(define (import-dotfiles directory files strip)
|
||||||
"Return a list of objects compatible with @code{home-files-service-type}'s
|
"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
|
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
|
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
|
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."
|
user's home directory, excluding files that match any of the patterns in EXCLUDED."
|
||||||
(define (strip file)
|
|
||||||
(string-drop file (+ 1 (string-length directory))))
|
|
||||||
|
|
||||||
(define (format file)
|
(define (format file)
|
||||||
;; Remove from FILE characters that cannot be used in the store.
|
;; Remove from FILE characters that cannot be used in the store.
|
||||||
(string-append
|
(string-append
|
||||||
|
@ -73,7 +119,7 @@ (define (format file)
|
||||||
file)))
|
file)))
|
||||||
|
|
||||||
(map (lambda (file)
|
(map (lambda (file)
|
||||||
(let ((stripped (strip file)))
|
(let ((stripped (strip file directory)))
|
||||||
(list stripped
|
(list stripped
|
||||||
(local-file file (format stripped)
|
(local-file file (format stripped)
|
||||||
#:recursive? #t))))
|
#:recursive? #t))))
|
||||||
|
@ -81,18 +127,25 @@ (define (format file)
|
||||||
|
|
||||||
(define (home-dotfiles-configuration->files config)
|
(define (home-dotfiles-configuration->files config)
|
||||||
"Return a list of objects compatible with @code{home-files-service-type}'s
|
"Return a list of objects compatible with @code{home-files-service-type}'s
|
||||||
value, generated following GNU Stow's algorithm for each of the
|
value, excluding files that match any of the patterns configured."
|
||||||
directories in CONFIG, excluding files that match any of the patterns configured."
|
(define stow? (eq? (home-dotfiles-configuration-layout config) 'stow))
|
||||||
(define excluded
|
(define excluded
|
||||||
(home-dotfiles-configuration-excluded config))
|
(home-dotfiles-configuration-excluded config))
|
||||||
(define exclusion-rx
|
(define exclusion-rx
|
||||||
(make-regexp (string-append "^.*(" (string-join excluded "|") ")$")))
|
(make-regexp (string-append "^.*(" (string-join excluded "|") ")$")))
|
||||||
|
|
||||||
(define (directory-contents directory)
|
(define* (directory-contents directory #:key (packages #f))
|
||||||
(find-files directory
|
(define (filter-files directory)
|
||||||
(lambda (file stat)
|
(find-files directory
|
||||||
(not (regexp-exec exclusion-rx
|
(lambda (file stat)
|
||||||
(basename file))))))
|
(not (regexp-exec exclusion-rx
|
||||||
|
(basename file))))))
|
||||||
|
(if (and stow? packages (maybe-value-set? packages))
|
||||||
|
(append-map filter-files
|
||||||
|
(map (lambda (pkg)
|
||||||
|
(string-append directory "/" pkg))
|
||||||
|
packages))
|
||||||
|
(filter-files directory)))
|
||||||
|
|
||||||
(define (resolve directory)
|
(define (resolve directory)
|
||||||
;; Resolve DIRECTORY relative to the 'source-directory' field of CONFIG.
|
;; Resolve DIRECTORY relative to the 'source-directory' field of CONFIG.
|
||||||
|
@ -103,15 +156,23 @@ (define (resolve directory)
|
||||||
|
|
||||||
(append-map (lambda (directory)
|
(append-map (lambda (directory)
|
||||||
(let* ((directory (resolve directory))
|
(let* ((directory (resolve directory))
|
||||||
(contents (directory-contents directory)))
|
(packages
|
||||||
(import-dotfiles directory contents)))
|
(home-dotfiles-configuration-packages config))
|
||||||
|
(contents
|
||||||
|
(directory-contents directory
|
||||||
|
#:packages packages))
|
||||||
|
(strip
|
||||||
|
(if stow? strip-stow-dotfile strip-plain-dotfile)))
|
||||||
|
(import-dotfiles directory contents strip)))
|
||||||
(home-dotfiles-configuration-directories config)))
|
(home-dotfiles-configuration-directories config)))
|
||||||
|
|
||||||
(define-public home-dotfiles-service-type
|
(define-public home-dotfiles-service-type
|
||||||
(service-type (name 'home-dotfiles)
|
(service-type (name 'home-dotfiles)
|
||||||
(extensions
|
(extensions
|
||||||
(list (service-extension home-files-service-type
|
(list (service-extension home-files-service-type
|
||||||
home-dotfiles-configuration->files)))
|
(lambda (config)
|
||||||
|
(when config
|
||||||
|
(home-dotfiles-configuration->files config))))))
|
||||||
(default-value (home-dotfiles-configuration))
|
(default-value (home-dotfiles-configuration))
|
||||||
(description "Files that will be put in the user's home directory
|
(description "Files that will be put in the user's home directory
|
||||||
following GNU Stow's algorithm, and further processed during activation.")))
|
following GNU Stow's algorithm, and further processed during activation.")))
|
||||||
|
|
Loading…
Reference in a new issue