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>master
parent
9e3061a163
commit
01f685d560
|
@ -111,7 +111,7 @@ 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{} 2023-2024 Giacomo Leidi@*
|
||||
Copyright @copyright{} 2022 Antero Mejr@*
|
||||
Copyright @copyright{} 2023 Karl Hallsby@*
|
||||
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
|
||||
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,
|
||||
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
|
||||
allowing them to point the service to their dotfiles directory 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
|
||||
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.
|
||||
|
||||
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
|
||||
~$ tree -a ./dotfiles/
|
||||
dotfiles/
|
||||
|
@ -44707,8 +44732,10 @@ dotfiles/
|
|||
@end example
|
||||
|
||||
For an informal specification please refer to the Stow manual
|
||||
(@pxref{Top,,, stow, Introduction}). A suitable configuration would then
|
||||
be:
|
||||
(@pxref{Top,,, stow, Introduction}). This tree structure is installed following
|
||||
GNU Stow's logic to the home directory upon @command{guix home reconfigure}.
|
||||
|
||||
A suitable configuration with a @code{'plain} layout could be:
|
||||
|
||||
@lisp
|
||||
(home-environment
|
||||
|
@ -44716,7 +44743,7 @@ be:
|
|||
(services
|
||||
(service home-dotfiles-service-type
|
||||
(home-dotfiles-configuration
|
||||
(directories (list "./dotfiles"))))))
|
||||
(directories '("./dotfiles"))))))
|
||||
@end lisp
|
||||
|
||||
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
|
||||
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 files automatically deployed to their home directory
|
||||
just like Stow would, without migrating all of their dotfiles to Guix native
|
||||
directory and have their files automatically provisioned to their home
|
||||
directory, without migrating all of their dotfiles to Guix native
|
||||
configurations.
|
||||
@end defvar
|
||||
|
||||
@c %start of fragment
|
||||
|
||||
@deftp {Data Type} home-dotfiles-configuration
|
||||
Available @code{home-dotfiles-configuration} fields are:
|
||||
|
||||
@table @asis
|
||||
@item @code{source-directory} (default: @code{(current-source-directory)})
|
||||
The path where dotfile directories are resolved. By default dotfile directories
|
||||
are resolved relative the source location where
|
||||
@item @code{source-directory} (default: @code{(current-source-directory)}) (type: string)
|
||||
The path where dotfile directories are resolved. By default dotfile
|
||||
directories are resolved relative the source location where
|
||||
@code{home-dotfiles-configuration} appears.
|
||||
|
||||
@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{layout} (default: @code{'plain}) (type: symbol)
|
||||
The intended layout of the specified @code{directory}. It can be either
|
||||
@code{'stow} or @code{'plain}.
|
||||
|
||||
@item @code{exclude} (default: @code{'(".*~" ".*\\.swp" "\\.git" "\\.gitignore")})
|
||||
The list of file patterns @code{home-dotfiles-service-type} will exclude while
|
||||
visiting each one of the @code{directories}.
|
||||
@item @code{directories} (default: @code{'()}) (type: list-of-strings)
|
||||
The list of dotfiles directories where @code{home-dotfiles-service-type}
|
||||
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 deftp
|
||||
|
||||
|
||||
@c %end of fragment
|
||||
|
||||
@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
|
||||
|
|
|
@ -20,17 +20,25 @@
|
|||
(define-module (gnu home services dotfiles)
|
||||
#:use-module (gnu home services)
|
||||
#:use-module (gnu services)
|
||||
#:use-module (gnu services configuration)
|
||||
#:autoload (guix build utils) (find-files)
|
||||
#:use-module (guix diagnostics)
|
||||
#:use-module (guix gexp)
|
||||
#:use-module (guix records)
|
||||
#:use-module (guix i18n)
|
||||
#:use-module ((guix utils) #:select (current-source-directory))
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module (ice-9 ftw)
|
||||
#:use-module (ice-9 match)
|
||||
#:use-module (ice-9 regex)
|
||||
#:export (home-dotfiles-service-type
|
||||
home-dotfiles-configuration->files
|
||||
|
||||
home-dotfiles-configuration
|
||||
home-dotfiles-configuration?
|
||||
home-dotfiles-configuration-fields
|
||||
home-dotfiles-configuration-layout
|
||||
home-dotfiles-configuration-source-directory
|
||||
home-dotfiles-configuration-packages
|
||||
home-dotfiles-configuration-directories
|
||||
home-dotfiles-configuration-excluded))
|
||||
|
||||
|
@ -40,26 +48,64 @@
|
|||
"\\.git"
|
||||
"\\.gitignore"))
|
||||
|
||||
(define-record-type* <home-dotfiles-configuration>
|
||||
home-dotfiles-configuration make-home-dotfiles-configuration
|
||||
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 %home-dotfiles-layouts
|
||||
'(plain stow))
|
||||
|
||||
(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
|
||||
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 (strip file)
|
||||
(string-drop file (+ 1 (string-length directory))))
|
||||
|
||||
(define (format file)
|
||||
;; Remove from FILE characters that cannot be used in the store.
|
||||
(string-append
|
||||
|
@ -73,7 +119,7 @@ user's home directory, excluding files that match any of the patterns in EXCLUDE
|
|||
file)))
|
||||
|
||||
(map (lambda (file)
|
||||
(let ((stripped (strip file)))
|
||||
(let ((stripped (strip file directory)))
|
||||
(list stripped
|
||||
(local-file file (format stripped)
|
||||
#:recursive? #t))))
|
||||
|
@ -81,18 +127,25 @@ user's home directory, excluding files that match any of the patterns in EXCLUDE
|
|||
|
||||
(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."
|
||||
value, excluding files that match any of the patterns configured."
|
||||
(define stow? (eq? (home-dotfiles-configuration-layout config) 'stow))
|
||||
(define excluded
|
||||
(home-dotfiles-configuration-excluded config))
|
||||
(define exclusion-rx
|
||||
(make-regexp (string-append "^.*(" (string-join excluded "|") ")$")))
|
||||
|
||||
(define (directory-contents directory)
|
||||
(find-files directory
|
||||
(lambda (file stat)
|
||||
(not (regexp-exec exclusion-rx
|
||||
(basename file))))))
|
||||
(define* (directory-contents directory #:key (packages #f))
|
||||
(define (filter-files directory)
|
||||
(find-files directory
|
||||
(lambda (file stat)
|
||||
(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)
|
||||
;; Resolve DIRECTORY relative to the 'source-directory' field of CONFIG.
|
||||
|
@ -103,15 +156,23 @@ directories in CONFIG, excluding files that match any of the patterns configured
|
|||
|
||||
(append-map (lambda (directory)
|
||||
(let* ((directory (resolve directory))
|
||||
(contents (directory-contents directory)))
|
||||
(import-dotfiles directory contents)))
|
||||
(packages
|
||||
(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)))
|
||||
|
||||
(define-public home-dotfiles-service-type
|
||||
(service-type (name 'home-dotfiles)
|
||||
(extensions
|
||||
(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))
|
||||
(description "Files that will be put in the user's home directory
|
||||
following GNU Stow's algorithm, and further processed during activation.")))
|
||||
|
|
Reference in New Issue