diff options
| author | Giacomo Leidi <goodoldpaul@autistici.org> | 2024-03-06 21:52:42 +0100 |
|---|---|---|
| committer | Ludovic Courtès <ludo@gnu.org> | 2024-03-06 23:25:51 +0100 |
| commit | 01f685d56016ae529381a73daedccc1949b808ec (patch) | |
| tree | 61935a2682dcfa69ae4929acd7c896ca6433b4f2 /gnu/home | |
| parent | 9e3061a163abcae5ccd3823ba3d8f757a0478e40 (diff) | |
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>
Diffstat (limited to 'gnu/home')
| -rw-r--r-- | gnu/home/services/dotfiles.scm | 115 |
1 files changed, 88 insertions, 27 deletions
diff --git a/gnu/home/services/dotfiles.scm b/gnu/home/services/dotfiles.scm index 6a740c42ce4..823bdb03fb4 100644 --- a/gnu/home/services/dotfiles.scm +++ b/gnu/home/services/dotfiles.scm | |||
| @@ -20,17 +20,25 @@ | |||
| 20 | (define-module (gnu home services dotfiles) | 20 | (define-module (gnu home services dotfiles) |
| 21 | #:use-module (gnu home services) | 21 | #:use-module (gnu home services) |
| 22 | #:use-module (gnu services) | 22 | #:use-module (gnu services) |
| 23 | #:use-module (gnu services configuration) | ||
| 23 | #:autoload (guix build utils) (find-files) | 24 | #:autoload (guix build utils) (find-files) |
| 25 | #:use-module (guix diagnostics) | ||
| 24 | #:use-module (guix gexp) | 26 | #:use-module (guix gexp) |
| 25 | #:use-module (guix records) | 27 | #:use-module (guix i18n) |
| 26 | #:use-module ((guix utils) #:select (current-source-directory)) | 28 | #:use-module ((guix utils) #:select (current-source-directory)) |
| 27 | #:use-module (srfi srfi-1) | 29 | #:use-module (srfi srfi-1) |
| 28 | #:use-module (ice-9 ftw) | 30 | #:use-module (ice-9 ftw) |
| 31 | #:use-module (ice-9 match) | ||
| 29 | #:use-module (ice-9 regex) | 32 | #:use-module (ice-9 regex) |
| 30 | #:export (home-dotfiles-service-type | 33 | #:export (home-dotfiles-service-type |
| 34 | home-dotfiles-configuration->files | ||
| 35 | |||
| 31 | home-dotfiles-configuration | 36 | home-dotfiles-configuration |
| 32 | home-dotfiles-configuration? | 37 | home-dotfiles-configuration? |
| 38 | home-dotfiles-configuration-fields | ||
| 39 | home-dotfiles-configuration-layout | ||
| 33 | home-dotfiles-configuration-source-directory | 40 | home-dotfiles-configuration-source-directory |
| 41 | home-dotfiles-configuration-packages | ||
| 34 | home-dotfiles-configuration-directories | 42 | home-dotfiles-configuration-directories |
| 35 | home-dotfiles-configuration-excluded)) | 43 | home-dotfiles-configuration-excluded)) |
| 36 | 44 | ||
| @@ -40,26 +48,64 @@ | |||
| 40 | "\\.git" | 48 | "\\.git" |
| 41 | "\\.gitignore")) | 49 | "\\.gitignore")) |
| 42 | 50 | ||
| 43 | (define-record-type* <home-dotfiles-configuration> | 51 | (define %home-dotfiles-layouts |
| 44 | home-dotfiles-configuration make-home-dotfiles-configuration | 52 | '(plain stow)) |
| 45 | home-dotfiles-configuration? | 53 | |
| 46 | (source-directory home-dotfiles-configuration-source-directory | 54 | (define (sanitize-layout value) |
| 47 | (default (current-source-directory)) | 55 | (if (member value %home-dotfiles-layouts) |
| 48 | (innate)) | 56 | value |
| 49 | (directories home-dotfiles-configuration-directories ;list of strings | 57 | (raise |
| 50 | (default '())) | 58 | (formatted-message |
| 51 | (excluded home-dotfiles-configuration-excluded ;list of strings | 59 | (G_ "layout field of home-dotfiles-configuration should be either 'plain |
| 52 | (default %home-dotfiles-excluded))) | 60 | or 'stow, but ~a was found.") |
| 53 | 61 | value)))) | |
| 54 | (define (import-dotfiles directory files) | 62 | |
| 63 | (define list-of-strings? | ||
| 64 | (list-of string?)) | ||
| 65 | |||
| 66 | (define-maybe list-of-strings) | ||
| 67 | |||
| 68 | (define-configuration/no-serialization home-dotfiles-configuration | ||
| 69 | (source-directory | ||
| 70 | (string (current-source-directory)) | ||
| 71 | "The path where dotfile directories are resolved. By default dotfile | ||
| 72 | directories are resolved relative the source location where | ||
| 73 | @code{home-dotfiles-configuration} appears.") | ||
| 74 | (layout | ||
| 75 | (symbol 'plain) | ||
| 76 | "The intended layout of the specified @code{directory}. It can be either | ||
| 77 | @code{'stow} or @code{'plain}." | ||
| 78 | (sanitizer sanitize-layout)) | ||
| 79 | (directories | ||
| 80 | (list-of-strings '()) | ||
| 81 | "The list of dotfiles directories where @code{home-dotfiles-service-type} | ||
| 82 | will look for application dotfiles.") | ||
| 83 | (packages | ||
| 84 | (maybe-list-of-strings) | ||
| 85 | "The names of a subset of the GNU Stow package layer directories. When provided | ||
| 86 | the @code{home-dotfiles-service-type} will only provision dotfiles from this | ||
| 87 | subset of applications. This field will be ignored if @code{layout} is set | ||
| 88 | to @code{'plain}.") | ||
| 89 | (excluded | ||
| 90 | (list-of-strings %home-dotfiles-excluded) | ||
| 91 | "The list of file patterns @code{home-dotfiles-service-type} will exclude | ||
| 92 | while visiting @code{directory}.")) | ||
| 93 | |||
| 94 | (define (strip-stow-dotfile file-name directory) | ||
| 95 | (let ((dotfile-name (string-drop file-name (1+ (string-length directory))))) | ||
| 96 | (match (string-split dotfile-name #\/) | ||
| 97 | ((package parts ...) | ||
| 98 | (string-join parts "/"))))) | ||
| 99 | |||
| 100 | (define (strip-plain-dotfile file-name directory) | ||
| 101 | (string-drop file-name (+ 1 (string-length directory)))) | ||
| 102 | |||
| 103 | (define (import-dotfiles directory files strip) | ||
| 55 | "Return a list of objects compatible with @code{home-files-service-type}'s | 104 | "Return a list of objects compatible with @code{home-files-service-type}'s |
| 56 | value. Each object is a pair where the first element is the relative path | 105 | value. Each object is a pair where the first element is the relative path |
| 57 | of a file and the second is a gexp representing the file content. Objects are | 106 | of a file and the second is a gexp representing the file content. Objects are |
| 58 | generated by recursively visiting DIRECTORY and mapping its contents to the | 107 | generated by recursively visiting DIRECTORY and mapping its contents to the |
| 59 | user's home directory, excluding files that match any of the patterns in EXCLUDED." | 108 | user's home directory, excluding files that match any of the patterns in EXCLUDED." |
| 60 | (define (strip file) | ||
| 61 | (string-drop file (+ 1 (string-length directory)))) | ||
| 62 | |||
| 63 | (define (format file) | 109 | (define (format file) |
| 64 | ;; Remove from FILE characters that cannot be used in the store. | 110 | ;; Remove from FILE characters that cannot be used in the store. |
| 65 | (string-append | 111 | (string-append |
| @@ -73,7 +119,7 @@ user's home directory, excluding files that match any of the patterns in EXCLUDE | |||
| 73 | file))) | 119 | file))) |
| 74 | 120 | ||
| 75 | (map (lambda (file) | 121 | (map (lambda (file) |
| 76 | (let ((stripped (strip file))) | 122 | (let ((stripped (strip file directory))) |
| 77 | (list stripped | 123 | (list stripped |
| 78 | (local-file file (format stripped) | 124 | (local-file file (format stripped) |
| 79 | #:recursive? #t)))) | 125 | #:recursive? #t)))) |
| @@ -81,18 +127,25 @@ user's home directory, excluding files that match any of the patterns in EXCLUDE | |||
| 81 | 127 | ||
| 82 | (define (home-dotfiles-configuration->files config) | 128 | (define (home-dotfiles-configuration->files config) |
| 83 | "Return a list of objects compatible with @code{home-files-service-type}'s | 129 | "Return a list of objects compatible with @code{home-files-service-type}'s |
| 84 | value, generated following GNU Stow's algorithm for each of the | 130 | value, excluding files that match any of the patterns configured." |
| 85 | directories in CONFIG, excluding files that match any of the patterns configured." | 131 | (define stow? (eq? (home-dotfiles-configuration-layout config) 'stow)) |
| 86 | (define excluded | 132 | (define excluded |
| 87 | (home-dotfiles-configuration-excluded config)) | 133 | (home-dotfiles-configuration-excluded config)) |
| 88 | (define exclusion-rx | 134 | (define exclusion-rx |
| 89 | (make-regexp (string-append "^.*(" (string-join excluded "|") ")$"))) | 135 | (make-regexp (string-append "^.*(" (string-join excluded "|") ")$"))) |
| 90 | 136 | ||
| 91 | (define (directory-contents directory) | 137 | (define* (directory-contents directory #:key (packages #f)) |
| 92 | (find-files directory | 138 | (define (filter-files directory) |
| 93 | (lambda (file stat) | 139 | (find-files directory |
| 94 | (not (regexp-exec exclusion-rx | 140 | (lambda (file stat) |
| 95 | (basename file)))))) | 141 | (not (regexp-exec exclusion-rx |
| 142 | (basename file)))))) | ||
| 143 | (if (and stow? packages (maybe-value-set? packages)) | ||
| 144 | (append-map filter-files | ||
| 145 | (map (lambda (pkg) | ||
| 146 | (string-append directory "/" pkg)) | ||
| 147 | packages)) | ||
| 148 | (filter-files directory))) | ||
| 96 | 149 | ||
| 97 | (define (resolve directory) | 150 | (define (resolve directory) |
| 98 | ;; Resolve DIRECTORY relative to the 'source-directory' field of CONFIG. | 151 | ;; 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 | |||
| 103 | 156 | ||
| 104 | (append-map (lambda (directory) | 157 | (append-map (lambda (directory) |
| 105 | (let* ((directory (resolve directory)) | 158 | (let* ((directory (resolve directory)) |
| 106 | (contents (directory-contents directory))) | 159 | (packages |
| 107 | (import-dotfiles directory contents))) | 160 | (home-dotfiles-configuration-packages config)) |
| 161 | (contents | ||
| 162 | (directory-contents directory | ||
| 163 | #:packages packages)) | ||
| 164 | (strip | ||
| 165 | (if stow? strip-stow-dotfile strip-plain-dotfile))) | ||
| 166 | (import-dotfiles directory contents strip))) | ||
| 108 | (home-dotfiles-configuration-directories config))) | 167 | (home-dotfiles-configuration-directories config))) |
| 109 | 168 | ||
| 110 | (define-public home-dotfiles-service-type | 169 | (define-public home-dotfiles-service-type |
| 111 | (service-type (name 'home-dotfiles) | 170 | (service-type (name 'home-dotfiles) |
| 112 | (extensions | 171 | (extensions |
| 113 | (list (service-extension home-files-service-type | 172 | (list (service-extension home-files-service-type |
| 114 | home-dotfiles-configuration->files))) | 173 | (lambda (config) |
| 174 | (when config | ||
| 175 | (home-dotfiles-configuration->files config)))))) | ||
| 115 | (default-value (home-dotfiles-configuration)) | 176 | (default-value (home-dotfiles-configuration)) |
| 116 | (description "Files that will be put in the user's home directory | 177 | (description "Files that will be put in the user's home directory |
| 117 | following GNU Stow's algorithm, and further processed during activation."))) | 178 | following GNU Stow's algorithm, and further processed during activation."))) |
