[PATCH] home-services: Add symlink-manager

  • Done
  • quality assurance status badge
Details
4 participants
  • Andrew Tropin
  • Oleg Pykhalov
  • Jelle Licht
  • Xinglu Chen
Owner
unassigned
Submitted by
Andrew Tropin
Severity
normal

Debbugs page

Andrew Tropin wrote 4 years ago
(address . guix-patches@gnu.org)
87bl5kbsk8.fsf@trop.in
---
This patch is targeted against wip-guix-home branch.

It's not a part of any patch series to make sure it will get enough attention,
because it's most unpure part of the Guix Home and operates on user's files.

gnu/home-services/symlink-manager.scm | 248 ++++++++++++++++++++++++++
1 file changed, 248 insertions(+)
create mode 100644 gnu/home-services/symlink-manager.scm

Toggle diff (256 lines)
diff --git a/gnu/home-services/symlink-manager.scm b/gnu/home-services/symlink-manager.scm
new file mode 100644
index 0000000000..f13c9f4dbe
--- /dev/null
+++ b/gnu/home-services/symlink-manager.scm
@@ -0,0 +1,248 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
+;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu home-services symlink-manager)
+ #:use-module (gnu home-services)
+ #:use-module (guix gexp)
+
+ #:export (home-symlink-manager-service-type))
+
+;;; Comment:
+;;;
+;;; symlink-manager cares about configuration files: it backups files
+;;; created by user, removes symlinks and directories created by
+;;; previous generation, and creates new directories and symlinks to
+;;; configs according to content of files/ directory of current home
+;;; environment generation (created by home-files-service).
+;;;
+;;; Code:
+
+(define (update-symlinks-script)
+ (program-file
+ "update-symlinks"
+ #~(begin
+ (use-modules (ice-9 ftw)
+ (ice-9 curried-definitions)
+ (ice-9 match)
+ (srfi srfi-1))
+ (define ((simplify-file-tree parent) file)
+ "Convert the result produced by `file-system-tree' to less
+verbose and more suitable for further processing format.
+
+Extract dir/file info from stat and compose a relative path to the
+root of the file tree.
+
+Sample output:
+
+((dir . \".\")
+ ((dir . \"config\")
+ ((dir . \"config/fontconfig\")
+ (file . \"config/fontconfig/fonts.conf\"))
+ ((dir . \"config/isync\")
+ (file . \"config/isync/mbsyncrc\"))))
+"
+ (match file
+ ((name stat) `(file . ,(string-append parent name)))
+ ((name stat children ...)
+ (cons `(dir . ,(string-append parent name))
+ (map (simplify-file-tree
+ (if (equal? name ".")
+ ""
+ (string-append parent name "/")))
+ children)))))
+
+ (define ((file-tree-traverse preordering) node)
+ "Traverses the file tree in different orders, depending on PREORDERING.
+
+if PREORDERING is @code{#t} resulting list will contain folders before
+files located in those folders, otherwise folders will appear only
+after all nested items already listed."
+ (let ((prepend (lambda (a b) (append b a))))
+ (match node
+ (('file . path) (list node))
+ ((('dir . path) . rest)
+ ((if preordering append prepend)
+ (list (cons 'dir path))
+ (append-map (file-tree-traverse preordering) rest))))))
+
+ (use-modules (guix build utils))
+
+ (let* ((he-path (string-append (getenv "HOME") "/.guix-home"))
+ (new-he-tmp-path (string-append he-path ".new"))
+ (new-home (getenv "GUIX_NEW_HOME")))
+ (symlink new-home new-he-tmp-path)
+ (rename-file new-he-tmp-path he-path))
+
+ (let* ((config-home (or (getenv "XDG_CONFIG_HOME")
+ (string-append (getenv "HOME") "/.config")))
+
+ (he-path (string-append (getenv "HOME") "/.guix-home"))
+ (new-he-tmp-path (string-append he-path ".new"))
+
+ (files-path (string-append he-path "/files"))
+ ;; Leading dot is required, because files itself is symlink and
+ ;; to make file-system-tree works it should be a directory.
+ (files-dir-path (string-append files-path "/."))
+ (new-files-path (string-append new-he-tmp-path "/files"))
+ (new-files-dir-path (string-append files-path "/."))
+
+ (home-path (getenv "HOME"))
+ (backup-dir (string-append home-path "/"
+ (number->string (current-time))
+ "-guix-home-legacy-configs-backup"))
+
+ (old-tree (if (file-exists? files-dir-path)
+ ((simplify-file-tree "")
+ (file-system-tree files-dir-path))
+ #f))
+ (new-tree ((simplify-file-tree "")
+ (file-system-tree new-files-dir-path)))
+
+ (get-source-path
+ (lambda (path)
+ (readlink (string-append files-path "/" path))))
+
+ (get-target-path
+ (lambda (path)
+ (string-append home-path "/." path)))
+
+ (get-backup-path
+ (lambda (path)
+ (string-append backup-dir "/." path)))
+
+ (directory?
+ (lambda (path)
+ (equal? (stat:type (stat path)) 'directory)))
+
+ (empty-directory?
+ (lambda (dir)
+ (equal? (scandir dir) '("." ".."))))
+
+ (symlink-to-store?
+ (lambda (path)
+ (and
+ (equal? (stat:type (lstat path)) 'symlink)
+ (store-file-name? (readlink path)))))
+
+ (backup-file
+ (lambda (path)
+ (mkdir-p backup-dir)
+ (format #t "Backing up ~a..." (get-target-path path))
+ (mkdir-p (dirname (get-backup-path path)))
+ (rename-file (get-target-path path) (get-backup-path path))
+ (display " done\n")))
+
+ (cleanup-symlinks
+ (lambda ()
+ (let ((to-delete ((file-tree-traverse #f) old-tree)))
+ (display
+ "Cleaning up symlinks from previous home-environment.\n\n")
+ (map
+ (match-lambda
+ (('dir . ".")
+ (display "Cleanup finished.\n\n"))
+
+ (('dir . path)
+ (if (and
+ (file-exists? (get-target-path path))
+ (directory? (get-target-path path))
+ (empty-directory? (get-target-path path)))
+ (begin
+ (format #t "Removing ~a..."
+ (get-target-path path))
+ (rmdir (get-target-path path))
+ (display " done\n"))
+ (format
+ #t "Skipping ~a (not an empty directory)... done\n"
+ (get-target-path path))))
+
+ (('file . path)
+ (when (file-exists? (get-target-path path))
+ ;; DO NOT remove the file if it was modified
+ ;; by user (not a symlink to the /gnu/store
+ ;; anymore) it will be backed up later during
+ ;; create-symlinks phase.
+ (if (symlink-to-store? (get-target-path path))
+ (begin
+ (format #t "Removing ~a..." (get-target-path path))
+ (delete-file (get-target-path path))
+ (display " done\n"))
+ (format
+ #t
+ "Skipping ~a (not a symlink to store)... done\n"
+ (get-target-path path))))))
+ to-delete))))
+
+ (create-symlinks
+ (lambda ()
+ (let ((to-create ((file-tree-traverse #t) new-tree)))
+ (map
+ (match-lambda
+ (('dir . ".")
+ (display
+ "New symlinks to home-environment will be created soon.\n")
+ (format
+ #t "All conflicting files will go to ~a.\n\n" backup-dir))
+
+ (('dir . path)
+ (let ((target-path (get-target-path path)))
+ (when (and (file-exists? target-path)
+ (not (directory? target-path)))
+ (backup-file path))
+
+ (if (file-exists? target-path)
+ (format
+ #t "Skipping ~a (directory already exists)... done\n"
+ target-path)
+ (begin
+ (format #t "Creating ~a..." target-path)
+ (mkdir target-path)
+ (display " done\n")))))
+
+ (('file . path)
+ (when (file-exists? (get-target-path path))
+ (backup-file path))
+ (format #t "Symlinking ~a -> ~a..."
+ (get-target-path path) (get-source-path path))
+ (symlink (get-source-path path) (get-target-path path))
+ (display " done\n")))
+ to-create)))))
+
+ (when old-tree
+ (cleanup-symlinks))
+
+ (create-symlinks)
+
+ (display " done\nFinished updating symlinks.\n\n")))))
+
+
+(define (update-symlinks-gexp _)
+ #~(primitive-load #$(update-symlinks-script)))
+
+(define home-symlink-manager-service-type
+ (service-type (name 'home-symlink-manager)
+ (extensions
+ (list
+ (service-extension
+ home-activation-service-type
+ update-symlinks-gexp)))
+ (default-value #f)
+ (description "Provide an @code{update-symlinks}
+script, which create and remove symlinks on every activation. If the
+target is occupied by a file created by user, back it up.")))
--
2.33.0
-----BEGIN PGP SIGNATURE-----

iQJDBAEBCgAtFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmEnO6cPHGFuZHJld0B0
cm9wLmluAAoJECII0glYwd6wy8QQAICPi55NlYod4+OKRJJTrzqpNzWeIBdzbzlu
6Jh9f3+eKhY4FJhDaO6Os8+FOMDUZOwbt2XLQiJuJIsHaTtzfoSAaL1eTTHtcOdp
uyjBnTVvqfhjj3C6Zu9YQYWlKfAkxmQLmTNoU51J1QcaqKi3Xz8N/usvVQFIQZhr
Z9zvK7bSv2UNhudxmJmG2cBNv1t3ZW1SrRzk5WgLnGG4itYgzD7+sE5HZh5LszIx
byTQOJ2Xd8D/C4+pXTXU+i8Yfxxcontux0wDUuaGTA6RGIyy02ccDb4mEMTsUocV
qlX81hN8dH37cADH5qfAQKAQPUdglMrf4P+SOuctpFpLSYT00gV8XRTpa1WKXZej
wbYJmdVJFZ22YP5Ix5QS22PrqluULnngN+q0K5dPwW7rek/g6vXeNDcuzQXLpg7q
QYgOziPXKcnstFSVJn0v7s9/NQCYumOs2I8lK1lkHKSRrqZtuLsh1mXb2kthE2Bp
e8CNVeUjMxm8zH/mnpEntsh6Bvp9NRNtSkaV8Lbd3yQypJ4ngbzfaRsWLKY2+qGu
axoqz9R6RqziCeK/6LzlQl7Ciur2RBZzO/YpkWYoPTFql6UXbp15cwrWLnNgy4Zw
j6CfuJCHiLdOxuQ2akERbb1X440r7KCkWZTAzehJUfmKYV5hjhNjJsUSqPSZSXb4
S2ZW7JUz
=Td/5
-----END PGP SIGNATURE-----

Oleg Pykhalov wrote 4 years ago
(name . Andrew Tropin)(address . andrew@trop.in)(address . 50208@debbugs.gnu.org)
87r1eg8obm.fsf@gmail.com
Hi Andrew,

Andrew Tropin <andrew@trop.in> writes:

Toggle quote (11 lines)
> ---
> This patch is targeted against wip-guix-home branch.
>
> It's not a part of any patch series to make sure it will get enough attention,
> because it's most unpure part of the Guix Home and operates on user's files.
>
> gnu/home-services/symlink-manager.scm | 248 ++++++++++++++++++++++++++
> 1 file changed, 248 insertions(+)
> create mode 100644 gnu/home-services/symlink-manager.scm
>

[…]

I applied your patch, replaces tabs with spaces, modified commit message
according to GNU standards, added the file to gnu/local.mk for
compilation (I forgot to do it for previous patch series, apologies).


I would like to squash the patch for home-services.scm with a previous
series (hope force push will work), but I should ask you could I do it?
Otherwise I could just push two patches to wip-guix-home.

Updated patches are attached below.
From 99f1b412fd76d9813dccc96cf30a943375d0d5a8 Mon Sep 17 00:00:00 2001
From: Oleg Pykhalov <go.wigust@gmail.com>
Date: Thu, 26 Aug 2021 13:18:54 +0300
Subject: [PATCH 1/2] gnu: Compile home-services.

This commit follows b784de19.

* gnu/local.mk (GNU_SYSTEM_MODULES): Add home-services.scm.
---
gnu/local.mk | 1 +
1 file changed, 1 insertion(+)

Toggle diff (14 lines)
diff --git a/gnu/local.mk b/gnu/local.mk
index 14cd1cc6ad..bd3aed77e8 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -72,6 +72,7 @@ GNU_SYSTEM_MODULES = \
%D%/bootloader/u-boot.scm \
%D%/bootloader/depthcharge.scm \
%D%/ci.scm \
+ %D%/home-services.scm \
%D%/image.scm \
%D%/packages.scm \
%D%/packages/abduco.scm \
--
2.32.0
Oleg.
-----BEGIN PGP SIGNATURE-----

iQJIBAEBCgAyFiEEcjhxI46s62NFSFhXFn+OpQAa+pwFAmEnc90UHGdvLndpZ3Vz
dEBnbWFpbC5jb20ACgkQFn+OpQAa+pzy+hAApLF5W6wXdnWEntQAu8Qxa6NEeu5+
IPMd7W/i/WnUaON2N5uyLjHS+k2INLz7bPZCtEkJXMMV9eOPgb0g9GuwHvnjOmjj
DdUIkDxInn1wVyDkyg5ca0BK5DEo/y+N9LfXQKhLfr5Tg25LTerxXcYBrtCqNJSI
TqgkTu/E8zcwwwZgcSkLHf3ebnIhvhW86/ErP8plFe1zUZo3SU2s5PBJ3FEjyCga
JbGXdBanxEzHqDYBiDTn0/ADwy41qJhnxzwc1J/jZHo08xtuw3VMqGd04tPGQtVg
ohoRQZNj39tTlXZTfm+Zxc2zuBInESc90iR2FrD3be1YnFypCSTj3ipFmArC26Ze
YbMK4HWb3mUGn8Oip+ufJBEbr8+x3L90e8bTMfTVHz0IXf0XjDHewpWuCiDa5FY8
zFGaO3cyVDnAOXebQ1yugDwU0u8Z7v2Ciuk3Bn6qwt9uAy/52KiWkxh9BJpoJPLS
XvxlyLWnHg7FsiQgA4x+I/3Q75HkZ0e/dQAiKei31L2deUtTSEi6Pzn0QPvCQEBt
2SWEbqAuqWvyWmBjeOGFjardw9JC6+1l56XnAZ7FEsSqtnmqPbtBQcPBCGqSLxuA
YhDvX3sLEJDK6xXV06z6EGwWfRgoZTm9HV1rqa4x6ZMj0vZuPKviSYWCTS3/m/ks
9zjiWST/yhsutSQ=
=pGCs
-----END PGP SIGNATURE-----

Andrew Tropin wrote 4 years ago
(name . Oleg Pykhalov)(address . go.wigust@gmail.com)(address . 50208@debbugs.gnu.org)
87k0k7fqzn.fsf@trop.in
On 2021-08-26 13:58, Oleg Pykhalov wrote:

Toggle quote (22 lines)
> Hi Andrew,
>
> Andrew Tropin <andrew@trop.in> writes:
>
>> ---
>> This patch is targeted against wip-guix-home branch.
>>
>> It's not a part of any patch series to make sure it will get enough attention,
>> because it's most unpure part of the Guix Home and operates on user's files.
>>
>> gnu/home-services/symlink-manager.scm | 248 ++++++++++++++++++++++++++
>> 1 file changed, 248 insertions(+)
>> create mode 100644 gnu/home-services/symlink-manager.scm
>>
>
> […]
>
> I applied your patch, replaces tabs with spaces, modified commit message
> according to GNU standards, added the file to gnu/local.mk for
> compilation (I forgot to do it for previous patch series, apologies).
>

Thank you!

Toggle quote (7 lines)
>
>
> I would like to squash the patch for home-services.scm with a previous
> series (hope force push will work), but I should ask you could I do it?
> Otherwise I could just push two patches to wip-guix-home.
>

Yes, squash works for me.

Toggle quote (310 lines)
>
> Updated patches are attached below.
>
> From 99f1b412fd76d9813dccc96cf30a943375d0d5a8 Mon Sep 17 00:00:00 2001
> From: Oleg Pykhalov <go.wigust@gmail.com>
> Date: Thu, 26 Aug 2021 13:18:54 +0300
> Subject: [PATCH 1/2] gnu: Compile home-services.
>
> This commit follows b784de19.
>
> * gnu/local.mk (GNU_SYSTEM_MODULES): Add home-services.scm.
> ---
> gnu/local.mk | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/gnu/local.mk b/gnu/local.mk
> index 14cd1cc6ad..bd3aed77e8 100644
> --- a/gnu/local.mk
> +++ b/gnu/local.mk
> @@ -72,6 +72,7 @@ GNU_SYSTEM_MODULES = \
> %D%/bootloader/u-boot.scm \
> %D%/bootloader/depthcharge.scm \
> %D%/ci.scm \
> + %D%/home-services.scm \
> %D%/image.scm \
> %D%/packages.scm \
> %D%/packages/abduco.scm \
> --
> 2.32.0
>
> From 8938342edec4dda6ff2b7b5d47f63809bb309084 Mon Sep 17 00:00:00 2001
> From: Andrew Tropin <andrew@trop.in>
> Date: Thu, 26 Aug 2021 09:39:38 +0300
> Subject: [PATCH 2/2] home-services: Add symlink-manager.
>
> * gnu/home-services/symlink-manager.scm: New file.
> * gnu/local.mk (GNU_SYSTEM_MODULES): Add this.
>
> Signed-off-by: Oleg Pykhalov <go.wigust@gmail.com>
> ---
> gnu/home-services/symlink-manager.scm | 247 ++++++++++++++++++++++++++
> gnu/local.mk | 1 +
> 2 files changed, 248 insertions(+)
> create mode 100644 gnu/home-services/symlink-manager.scm
>
> diff --git a/gnu/home-services/symlink-manager.scm b/gnu/home-services/symlink-manager.scm
> new file mode 100644
> index 0000000000..47fee8db3b
> --- /dev/null
> +++ b/gnu/home-services/symlink-manager.scm
> @@ -0,0 +1,247 @@
> +;;; GNU Guix --- Functional package management for GNU
> +;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
> +;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
> +;;;
> +;;; This file is part of GNU Guix.
> +;;;
> +;;; GNU Guix is free software; you can redistribute it and/or modify it
> +;;; under the terms of the GNU General Public License as published by
> +;;; the Free Software Foundation; either version 3 of the License, or (at
> +;;; your option) any later version.
> +;;;
> +;;; GNU Guix is distributed in the hope that it will be useful, but
> +;;; WITHOUT ANY WARRANTY; without even the implied warranty of
> +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +;;; GNU General Public License for more details.
> +;;;
> +;;; You should have received a copy of the GNU General Public License
> +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
> +
> +(define-module (gnu home-services symlink-manager)
> + #:use-module (gnu home-services)
> + #:use-module (guix gexp)
> + #:export (home-symlink-manager-service-type))
> +
> +;;; Comment:
> +;;;
> +;;; symlink-manager cares about configuration files: it backups files
> +;;; created by user, removes symlinks and directories created by
> +;;; previous generation, and creates new directories and symlinks to
> +;;; configs according to content of files/ directory of current home
> +;;; environment generation (created by home-files-service).
> +;;;
> +;;; Code:
> +
> +(define (update-symlinks-script)
> + (program-file
> + "update-symlinks"
> + #~(begin
> + (use-modules (ice-9 ftw)
> + (ice-9 curried-definitions)
> + (ice-9 match)
> + (srfi srfi-1))
> + (define ((simplify-file-tree parent) file)
> + "Convert the result produced by `file-system-tree' to less
> +verbose and more suitable for further processing format.
> +
> +Extract dir/file info from stat and compose a relative path to the
> +root of the file tree.
> +
> +Sample output:
> +
> +((dir . \".\")
> + ((dir . \"config\")
> + ((dir . \"config/fontconfig\")
> + (file . \"config/fontconfig/fonts.conf\"))
> + ((dir . \"config/isync\")
> + (file . \"config/isync/mbsyncrc\"))))
> +"
> + (match file
> + ((name stat) `(file . ,(string-append parent name)))
> + ((name stat children ...)
> + (cons `(dir . ,(string-append parent name))
> + (map (simplify-file-tree
> + (if (equal? name ".")
> + ""
> + (string-append parent name "/")))
> + children)))))
> +
> + (define ((file-tree-traverse preordering) node)
> + "Traverses the file tree in different orders, depending on PREORDERING.
> +
> +if PREORDERING is @code{#t} resulting list will contain folders before
> +files located in those folders, otherwise folders will appear only
> +after all nested items already listed."
> + (let ((prepend (lambda (a b) (append b a))))
> + (match node
> + (('file . path) (list node))
> + ((('dir . path) . rest)
> + ((if preordering append prepend)
> + (list (cons 'dir path))
> + (append-map (file-tree-traverse preordering) rest))))))
> +
> + (use-modules (guix build utils))
> +
> + (let* ((he-path (string-append (getenv "HOME") "/.guix-home"))
> + (new-he-tmp-path (string-append he-path ".new"))
> + (new-home (getenv "GUIX_NEW_HOME")))
> + (symlink new-home new-he-tmp-path)
> + (rename-file new-he-tmp-path he-path))
> +
> + (let* ((config-home (or (getenv "XDG_CONFIG_HOME")
> + (string-append (getenv "HOME") "/.config")))
> +
> + (he-path (string-append (getenv "HOME") "/.guix-home"))
> + (new-he-tmp-path (string-append he-path ".new"))
> +
> + (files-path (string-append he-path "/files"))
> + ;; Leading dot is required, because files itself is symlink and
> + ;; to make file-system-tree works it should be a directory.
> + (files-dir-path (string-append files-path "/."))
> + (new-files-path (string-append new-he-tmp-path "/files"))
> + (new-files-dir-path (string-append files-path "/."))
> +
> + (home-path (getenv "HOME"))
> + (backup-dir (string-append home-path "/"
> + (number->string (current-time))
> + "-guix-home-legacy-configs-backup"))
> +
> + (old-tree (if (file-exists? files-dir-path)
> + ((simplify-file-tree "")
> + (file-system-tree files-dir-path))
> + #f))
> + (new-tree ((simplify-file-tree "")
> + (file-system-tree new-files-dir-path)))
> +
> + (get-source-path
> + (lambda (path)
> + (readlink (string-append files-path "/" path))))
> +
> + (get-target-path
> + (lambda (path)
> + (string-append home-path "/." path)))
> +
> + (get-backup-path
> + (lambda (path)
> + (string-append backup-dir "/." path)))
> +
> + (directory?
> + (lambda (path)
> + (equal? (stat:type (stat path)) 'directory)))
> +
> + (empty-directory?
> + (lambda (dir)
> + (equal? (scandir dir) '("." ".."))))
> +
> + (symlink-to-store?
> + (lambda (path)
> + (and
> + (equal? (stat:type (lstat path)) 'symlink)
> + (store-file-name? (readlink path)))))
> +
> + (backup-file
> + (lambda (path)
> + (mkdir-p backup-dir)
> + (format #t "Backing up ~a..." (get-target-path path))
> + (mkdir-p (dirname (get-backup-path path)))
> + (rename-file (get-target-path path) (get-backup-path path))
> + (display " done\n")))
> +
> + (cleanup-symlinks
> + (lambda ()
> + (let ((to-delete ((file-tree-traverse #f) old-tree)))
> + (display
> + "Cleaning up symlinks from previous home-environment.\n\n")
> + (map
> + (match-lambda
> + (('dir . ".")
> + (display "Cleanup finished.\n\n"))
> +
> + (('dir . path)
> + (if (and
> + (file-exists? (get-target-path path))
> + (directory? (get-target-path path))
> + (empty-directory? (get-target-path path)))
> + (begin
> + (format #t "Removing ~a..."
> + (get-target-path path))
> + (rmdir (get-target-path path))
> + (display " done\n"))
> + (format
> + #t "Skipping ~a (not an empty directory)... done\n"
> + (get-target-path path))))
> +
> + (('file . path)
> + (when (file-exists? (get-target-path path))
> + ;; DO NOT remove the file if it was modified
> + ;; by user (not a symlink to the /gnu/store
> + ;; anymore) it will be backed up later during
> + ;; create-symlinks phase.
> + (if (symlink-to-store? (get-target-path path))
> + (begin
> + (format #t "Removing ~a..." (get-target-path path))
> + (delete-file (get-target-path path))
> + (display " done\n"))
> + (format
> + #t
> + "Skipping ~a (not a symlink to store)... done\n"
> + (get-target-path path))))))
> + to-delete))))
> +
> + (create-symlinks
> + (lambda ()
> + (let ((to-create ((file-tree-traverse #t) new-tree)))
> + (map
> + (match-lambda
> + (('dir . ".")
> + (display
> + "New symlinks to home-environment will be created soon.\n")
> + (format
> + #t "All conflicting files will go to ~a.\n\n" backup-dir))
> +
> + (('dir . path)
> + (let ((target-path (get-target-path path)))
> + (when (and (file-exists? target-path)
> + (not (directory? target-path)))
> + (backup-file path))
> +
> + (if (file-exists? target-path)
> + (format
> + #t "Skipping ~a (directory already exists)... done\n"
> + target-path)
> + (begin
> + (format #t "Creating ~a..." target-path)
> + (mkdir target-path)
> + (display " done\n")))))
> +
> + (('file . path)
> + (when (file-exists? (get-target-path path))
> + (backup-file path))
> + (format #t "Symlinking ~a -> ~a..."
> + (get-target-path path) (get-source-path path))
> + (symlink (get-source-path path) (get-target-path path))
> + (display " done\n")))
> + to-create)))))
> +
> + (when old-tree
> + (cleanup-symlinks))
> +
> + (create-symlinks)
> +
> + (display " done\nFinished updating symlinks.\n\n")))))
> +
> +
> +(define (update-symlinks-gexp _)
> + #~(primitive-load #$(update-symlinks-script)))
> +
> +(define home-symlink-manager-service-type
> + (service-type (name 'home-symlink-manager)
> + (extensions
> + (list
> + (service-extension
> + home-activation-service-type
> + update-symlinks-gexp)))
> + (default-value #f)
> + (description "Provide an @code{update-symlinks}
> +script, which create and remove symlinks on every activation. If the
> +target is occupied by a file created by user, back it up.")))
> diff --git a/gnu/local.mk b/gnu/local.mk
> index bd3aed77e8..91c3b0da3d 100644
> --- a/gnu/local.mk
> +++ b/gnu/local.mk
> @@ -73,6 +73,7 @@ GNU_SYSTEM_MODULES = \
> %D%/bootloader/depthcharge.scm \
> %D%/ci.scm \
> %D%/home-services.scm \
> + %D%/home-services/symlink-manager.scm \
> %D%/image.scm \
> %D%/packages.scm \
> %D%/packages/abduco.scm \
-----BEGIN PGP SIGNATURE-----

iQJDBAEBCgAtFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmEoap0PHGFuZHJld0B0
cm9wLmluAAoJECII0glYwd6wIMUQAJV91sfCTBkpIkgem3U+nsy2sZPxhd4rxAo+
jEPmn5+rCE5KF+lZ7g6yKmYeWZKP4Z5vzC3u2xmeGhp0+W/Yh1lAwswXgMd6X7g6
SpXLSAoxE5C81VrkdED9h3dD/0cGZeHEg4tRUxGGuLE7p3A6cZe5R8yLNFq3Zw5M
O9XInHNVBk2UKivZwFavMvlbt4tTjM8b5W3CtA1ysSl1mwTZY/RitwYkXb+85EMh
FRyEgW9lnAjY+8qr4mlcm1jhRRND3MJ2Puyvh7H+hrIyiKcqBH7CPFlTzmhcXW3x
Ry3NHS5m3qVH7cmKF1vh6IZWYT3NCxgvzpmRSV+SKePfoToPLVpt4PPOQbiJ5N91
ddOgcL6xrLUCU7nw1jvms+KU2b6p6q/hW8amvvA07HAW0FHdmyuZWNzVfuKYUOIz
9BhhClR8KXDovFQm+K5s+1LUM7x/VLN+6M2LuupT5hLF5MmhGFalsGdBkKIdE/VP
wNCyZRsfI7/rQ0/PPeOyhpFa7GWmDztMavlDKbKWEg86QhK0dsk3YSrmUc5on99L
RFeWa+xvm5TG3RtJbco0SpWS3R+A+aKHll09OhJLCUjb+ElSDxJWehni8m0bmn47
irE3ftR7XMlosCyy3CmH8xTb4auUrhpuoRHrwumhnZTyefhO9Mq87bbmEmD5ef99
UGVU5uOq
=7B4U
-----END PGP SIGNATURE-----

Andrew Tropin wrote 4 years ago
[PATCH 0/5] Add home-environment and related services
(name . Oleg Pykhalov)(address . go.wigust@gmail.com)(address . 50208@debbugs.gnu.org)
871r6ffklu.fsf@trop.in
On 2021-08-26 13:58, Oleg Pykhalov wrote:

Toggle quote (11 lines)
> I applied your patch, replaces tabs with spaces, modified commit message
> according to GNU standards, added the file to gnu/local.mk for
> compilation (I forgot to do it for previous patch series, apologies).
>
>
> I would like to squash the patch for home-services.scm with a previous
> series (hope force push will work), but I should ask you could I do it?
> Otherwise I could just push two patches to wip-guix-home.
>
> Updated patches are attached below.

On top of the patches above I made a new patch series, which introduces
home-environment and a set of default services, which are expected to be
present in most Guix Home configurations.

Andrew Tropin (5):
home-services: Add fontutils.
home-services: Add helper functions for service configurations.
home-services: Add shells.
home-services: Add xdg.
home: Add home-environment.

gnu/home-services/configuration.scm | 63 +++
gnu/home-services/fontutils.scm | 65 +++
gnu/home-services/shells.scm | 637 ++++++++++++++++++++++++++++
gnu/home-services/xdg.scm | 475 +++++++++++++++++++++
gnu/home.scm | 97 +++++
gnu/local.mk | 5 +
6 files changed, 1342 insertions(+)
create mode 100644 gnu/home-services/configuration.scm
create mode 100644 gnu/home-services/fontutils.scm
create mode 100644 gnu/home-services/shells.scm
create mode 100644 gnu/home-services/xdg.scm
create mode 100644 gnu/home.scm

--
2.33.0
-----BEGIN PGP SIGNATURE-----

iQJDBAEBCgAtFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmEoiu0PHGFuZHJld0B0
cm9wLmluAAoJECII0glYwd6wL/wP/2J1+8Ya8Z+oL1lElfilioUCKr4GyJgQ5TlM
DPSONpDawn7/4DV4eXTQEASWhJAlz/rkQOv+Ffl896ZntZJ+Gd+t1ZkxPq926+iR
B9uyH4TqJZobSClEv2zSMgCA7VbMjDYpPEgPrOe/PUUsTkZgwIKsFTZCMqqmjptF
Qb0ZIrDpUHt1YlqdvQLNpdX6QFFCEp7mVyIilIvYjdgoBSk0/nfZ4rPc/GESdRJH
EmgYJnQm6FMxugfPia+9EtjXBB7I/N1w+YGfJeeFoWq+OSGuc/AkQnKshvKi3YUb
2K5HxrHyDunp4HTe45uzrSTkaC2WZfm6IPDy6TADTSbqV5ZjN66QSnNnSVDW0vLy
l++PI+weg6M0wlJw1DygDhSkCkS1seiMHN2LzVmEL+SKMNuNfpKKkgvmVxaWc8ot
kiQUaWiTuYwYWt3d1QwyvMEj9kwWTU95Mi3qK/v6Ugw/pmdpTOjYM1qFH+pxyffv
VZKzbmqH904pYzmasfJhCyMOSY0SZinyVpAp+ztdPzqOuVPyW4vkc9t+kgEGcpRO
8dxum5WiKZViQgZ6RrGmTLZnsAeknDHsoP43YVLIL7dWe2TLBnMZRUHYHZgjTRYm
NJhpMXTqxsVytK7Q31CUb5Te8WhwrkbZ5Mkj6UBetdZ6+EENq9cHpNgJS6S2Wulw
gLS667aL
=+QZd
-----END PGP SIGNATURE-----

Andrew Tropin wrote 4 years ago
[PATCH 1/5] home-services: Add fontutils.
(name . Oleg Pykhalov)(address . go.wigust@gmail.com)(address . 50208@debbugs.gnu.org)
87y28ne5wr.fsf@trop.in
* gnu/home-services/fontutils.scm (home-fontconfig-service-type): New
variable.
* gnu/local.mk (GNU_SYSTEM_MODULES): Add home-services/fontutils.scm.
---
gnu/home-services/fontutils.scm | 65 +++++++++++++++++++++++++++++++++
gnu/local.mk | 1 +
2 files changed, 66 insertions(+)
create mode 100644 gnu/home-services/fontutils.scm

Toggle diff (85 lines)
diff --git a/gnu/home-services/fontutils.scm b/gnu/home-services/fontutils.scm
new file mode 100644
index 0000000000..28bfc3d3f7
--- /dev/null
+++ b/gnu/home-services/fontutils.scm
@@ -0,0 +1,65 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
+;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu home-services fontutils)
+ #:use-module (gnu home-services)
+ #:use-module (gnu packages fontutils)
+ #:use-module (guix gexp)
+
+ #:export (home-fontconfig-service-type))
+
+;;; Commentary:
+;;;
+;;; Services related to fonts. home-fontconfig service provides
+;;; fontconfig configuration, which allows fc-* utilities to find
+;;; fonts in Guix Home's profile and regenerates font cache on
+;;; activation.
+;;;
+;;; Code:
+
+(define (add-fontconfig-config-file he-symlink-path)
+ `(("config/fontconfig/fonts.conf"
+ ,(mixed-text-file
+ "fonts.conf"
+ "<?xml version='1.0'?>
+<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
+<fontconfig>
+ <dir>~/.guix-home/profile/share/fonts</dir>
+</fontconfig>"))))
+
+(define (regenerate-font-cache-gexp _)
+ `(("profile/share/fonts"
+ ,#~(system* #$(file-append fontconfig "/bin/fc-cache") "-fv"))))
+
+(define home-fontconfig-service-type
+ (service-type (name 'home-fontconfig)
+ (extensions
+ (list (service-extension
+ home-files-service-type
+ add-fontconfig-config-file)
+ (service-extension
+ home-run-on-change-service-type
+ regenerate-font-cache-gexp)
+ (service-extension
+ home-profile-service-type
+ (const (list fontconfig)))))
+ (default-value #f)
+ (description
+ "Provides configuration file for fontconfig and make
+fc-* utilities aware of font packages installed in Guix Home's profile.")))
diff --git a/gnu/local.mk b/gnu/local.mk
index 91c3b0da3d..e25ff3db53 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -74,6 +74,7 @@ GNU_SYSTEM_MODULES = \
%D%/ci.scm \
%D%/home-services.scm \
%D%/home-services/symlink-manager.scm \
+ %D%/home-services/fontutils.scm \
%D%/image.scm \
%D%/packages.scm \
%D%/packages/abduco.scm \
--
2.33.0
-----BEGIN PGP SIGNATURE-----

iQJDBAEBCgAtFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmEoi5QPHGFuZHJld0B0
cm9wLmluAAoJECII0glYwd6w6QgP/1wfBHS66EnoqZAUOJIWOq/2yHYsE4QXos58
mLwpbG5bqBhMYaSQLX80b432s/uvG4CghqfuH3jo/JrIJ0T70Yo90ENF/tMZ3VOw
V3UKb1mCmGhkKZ9btP30UXFbmqMDHKJRNGsPhZLl/TtpoZC/ScAwg6wIBItM3Hxm
7DeSuOVD/jdirgPnoqrZ3LtZwk8SXgDB/b8CXDTyBIYbdzGP+6UjafeDf393VVY5
eqoWsLrHAtudtyb3oJXGMlqQS3axm+T6VEWkomrbS0lGTnS9CMdo56gmGFxNobCK
Bd8R0LCMFOWZO2xw2SLfltZKlzbWPoQknPTIPL4ZbDM9MrJg9uuu4K8T27YinV6y
m/vsNrpxL3daQ9kOmDLs3/ABha6zj4KWoO3MFc2vU38HKfAi+nvTEbug5CKXn9LR
tQmBmeICGWhst0lCl7MHQzVIHIT6EvGCaWfKa7e9Hq4fRYFDs/Yd6BIkQtUS0x+f
s9Gwl11Ai4DsIpRUqLsQSAVQpfU2FxdqNLCXQ59rPRzqRvgO2CICLosH0/+amMGC
i4NO7reH9bOn3mmqr51JQkuQctsKypYDpsqRpb/M+Gfk4lNu5bd0GdAEcenS7iWz
DqhukhOuIHeCT5DtUedvJUrDPuBw8+NM6RcHrs2ZdBgDOq9RO5gjdYN297J6dBAz
4QttUKjz
=Z4DY
-----END PGP SIGNATURE-----

Andrew Tropin wrote 4 years ago
[PATCH 2/5] home-services: Add helper functions for service configurations.
(name . Oleg Pykhalov)(address . go.wigust@gmail.com)(address . 50208@debbugs.gnu.org)
87v93re5lb.fsf@trop.in
* gnu/home-services/configuration.scm (helper functions): New variables.
* gnu/local.mk (GNU_SYSTEM_MODULES): Add home-services/configuration.scm.
---
gnu/home-services/configuration.scm | 63 +++++++++++++++++++++++++++++
gnu/local.mk | 1 +
2 files changed, 64 insertions(+)
create mode 100644 gnu/home-services/configuration.scm

Toggle diff (83 lines)
diff --git a/gnu/home-services/configuration.scm b/gnu/home-services/configuration.scm
new file mode 100644
index 0000000000..b7487fc49f
--- /dev/null
+++ b/gnu/home-services/configuration.scm
@@ -0,0 +1,63 @@
+(define-module (gnu home-services configuration)
+ #:use-module (gnu services configuration)
+ #:use-module (guix gexp)
+ #:use-module (srfi srfi-1)
+
+ #:export (filter-configuration-fields
+
+ interpose
+ list-of
+
+ list-of-strings?
+ alist?
+ string-or-gexp?
+ serialize-string-or-gexp
+ text-config?
+ serialize-text-config))
+
+(define* (filter-configuration-fields configuration-fields fields
+ #:optional negate?)
+ "Retrieve the fields listed in FIELDS from CONFIGURATION-FIELDS.
+If NEGATE? is @code{#t}, retrieve all fields except FIELDS."
+ (filter (lambda (field)
+ (let ((member? (member (configuration-field-name field) fields)))
+ (if (not negate?) member? (not member?))))
+ configuration-fields))
+
+
+(define* (interpose ls #:optional (delimiter "\n") (grammar 'infix))
+ "Same as @code{string-join}, but without join and string, returns an
+DELIMITER interposed LS. Support 'infix and 'suffix GRAMMAR values."
+ (when (not (member grammar '(infix suffix)))
+ (raise
+ (formatted-message
+ (G_ "The GRAMMAR value must be 'infix or 'suffix, but ~a provided.")
+ grammar)))
+ (fold-right (lambda (e acc)
+ (cons e
+ (if (and (null? acc) (eq? grammar 'infix))
+ acc
+ (cons delimiter acc))))
+ '() ls))
+
+(define (list-of pred?)
+ "Return a procedure that takes a list and check if all the elements of
+the list result in @code{#t} when applying PRED? on them."
+ (lambda (x)
+ (if (list? x)
+ (every pred? x)
+ #f)))
+
+
+(define list-of-strings?
+ (list-of string?))
+
+(define alist? list?)
+
+(define (string-or-gexp? sg) (or (string? sg) (gexp? sg)))
+(define (serialize-string-or-gexp field-name val) "")
+
+(define (text-config? config)
+ (and (list? config) (every string-or-gexp? config)))
+(define (serialize-text-config field-name val)
+ #~(string-append #$@(interpose val "\n" 'suffix)))
diff --git a/gnu/local.mk b/gnu/local.mk
index e25ff3db53..e24da4716f 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -75,6 +75,7 @@ GNU_SYSTEM_MODULES = \
%D%/home-services.scm \
%D%/home-services/symlink-manager.scm \
%D%/home-services/fontutils.scm \
+ %D%/home-services/configuration.scm \
%D%/image.scm \
%D%/packages.scm \
%D%/packages/abduco.scm \
--
2.33.0
-----BEGIN PGP SIGNATURE-----

iQJDBAEBCgAtFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmEojTEPHGFuZHJld0B0
cm9wLmluAAoJECII0glYwd6w5KwQAIn8zBbexmoWqzsuj+wS2O21tGLzq+MiB6eW
cG+WISSz7O477aqiosFraIOFNbn3OELbQW9w5C/+ZN79KHSOr4JzhriENlrQ3BQR
cqTVVsygr1Dp5IYllyf2fbIbH50c6iozFmzU8Ga8aE8v6SHOYT/z9yTx1TjwAhEC
NqdvhHBIMM+vVu+NFYrKXPLndFKGDb6+8aL83gCDMu7T6+fFdFbGxltbVuruJ2dR
CWbqDc+Q18XXxTlj13xIjzFgZL8hivpjlQ+IBVsPWYqCc7NnjxF5LtvtG7WV+Gwl
+/LEIQwJEOYYTFC+ursuU0om9+LLIyMIxzLGA4kVmocp32bcWnmlc33SP2xuP2j+
lti4c9yCbglCirfFvtbxK+f8MXm4deAyzbZRMjQIcTq6NsMjFiWs4kq4uvbiMara
DyKK8/XuBWCJ9C2R9AdpcDUP43qpWdP0m36DPvil+MU4wqzVIXYMnx91YO4scGVw
Pjx9UbARIxHuYGZ1Qwwsh6BcLsytwCXiG5FAovnkpxX2IP28h/kPp4rjQM067Ijc
QMAKSPvcG0gT/ZnaYsPoh3YtS6yad456g/af2tDR7yauXyHY9Jctrhhx8ZTb0St7
AvxhhULdwOB8PsRolLxooBJXOd1xxTwOKkPRgJiNUMAVUddlSA3g9ZEsCvL7SpmD
johGmvf7
=vo+E
-----END PGP SIGNATURE-----

Andrew Tropin wrote 4 years ago
[PATCH 3/5] home-services: Add shells.
(name . Oleg Pykhalov)(address . go.wigust@gmail.com)(address . 50208@debbugs.gnu.org)
87r1efe5eh.fsf@trop.in
* gnu/home-services/shells.scm
(home-shell-profile-service-type, home-shell-profile-configuration)
(home-bash-service-type, home-bash-configuration, home-bash-extension)
(home-zsh-service-type, home-zsh-configuration, home-zsh-extension)
(home-fish-service-type, home-fish-configuration, home-fish-extension): New
variables.
* gnu/local.mk (GNU_SYSTEM_MODULES): Add home-services/shells.scm.
---
gnu/home-services/shells.scm | 637 +++++++++++++++++++++++++++++++++++
gnu/local.mk | 1 +
2 files changed, 638 insertions(+)
create mode 100644 gnu/home-services/shells.scm

Toggle diff (577 lines)
diff --git a/gnu/home-services/shells.scm b/gnu/home-services/shells.scm
new file mode 100644
index 0000000000..0643019361
--- /dev/null
+++ b/gnu/home-services/shells.scm
@@ -0,0 +1,637 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
+;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu home-services shells)
+ #:use-module (gnu services configuration)
+ #:use-module (gnu home-services configuration)
+ #:use-module (gnu home-services)
+ #:use-module (gnu packages shells)
+ #:use-module (gnu packages bash)
+ #:use-module (guix gexp)
+ #:use-module (guix packages)
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-26)
+ #:use-module (ice-9 match)
+
+ #:export (home-shell-profile-service-type
+ home-shell-profile-configuration
+
+ home-bash-service-type
+ home-bash-configuration
+ home-bash-extension
+
+ home-zsh-service-type
+ home-zsh-configuration
+ home-zsh-extension
+
+ home-fish-service-type
+ home-fish-configuration
+ home-fish-extension))
+
+;;; Commentary:
+;;;
+;;; This module contains shell related services like Zsh.
+;;;
+;;; Code:
+
+
+;;;
+;;; Shell profile.
+;;;
+
+(define path? string?)
+(define (serialize-path field-name val) val)
+
+(define-configuration home-shell-profile-configuration
+ (profile
+ (text-config '())
+ "\
+@code{home-shell-profile} is instantiated automatically by
+@code{home-environment}, DO NOT create this service manually, it can
+only be extended.
+
+@code{profile} is a list of strings or gexps, which will go to
+@file{~/.profile}. By default @file{~/.profile} contains the
+initialization code, which have to be evaluated by login shell to make
+home-environment's profile avaliable to the user, but other commands
+can be added to the file if it is really necessary.
+
+In most cases shell's configuration files are preferred places for
+user's customizations. Extend home-shell-profile service only if you
+really know what you do."))
+
+(define (add-shell-profile-file config)
+ `(("profile"
+ ,(mixed-text-file
+ "shell-profile"
+ "\
+HOME_ENVIRONMENT=$HOME/.guix-home
+. $HOME_ENVIRONMENT/setup-environment
+$HOME_ENVIRONMENT/on-first-login\n"
+ (serialize-configuration
+ config
+ (filter-configuration-fields
+ home-shell-profile-configuration-fields '(profile)))))))
+
+(define (add-profile-extensions config extensions)
+ (home-shell-profile-configuration
+ (inherit config)
+ (profile
+ (append (home-shell-profile-configuration-profile config)
+ extensions))))
+
+(define home-shell-profile-service-type
+ (service-type (name 'home-shell-profile)
+ (extensions
+ (list (service-extension
+ home-files-service-type
+ add-shell-profile-file)))
+ (compose concatenate)
+ (extend add-profile-extensions)
+ (default-value (home-shell-profile-configuration))
+ (description "Create @file{~/.profile}, which is used
+for environment initialization of POSIX compliant login shells. This
+service type can be extended with a list of strings or gexps.")))
+
+(define (serialize-boolean field-name val) "")
+(define (serialize-posix-env-vars field-name val)
+ #~(string-append
+ #$@(map
+ (match-lambda
+ ((key . #f)
+ "")
+ ((key . #t)
+ #~(string-append "export " #$key "\n"))
+ ((key . value)
+ #~(string-append "export " #$key "=" #$value "\n")))
+ val)))
+
+
+;;;
+;;; Zsh.
+;;;
+
+(define-configuration home-zsh-configuration
+ (package
+ (package zsh)
+ "The Zsh package to use.")
+ (xdg-flavor?
+ (boolean #t)
+ "Place all the configs to @file{$XDG_CONFIG_HOME/zsh}. Makes
+@file{~/.zshenv} to set @env{ZDOTDIR} to @file{$XDG_CONFIG_HOME/zsh}.
+Shell startup process will continue with
+@file{$XDG_CONFIG_HOME/zsh/.zshenv}.")
+ (environment-variables
+ (alist '())
+ "Association list of environment variables to set for the Zsh session."
+ serialize-posix-env-vars)
+ (zshenv
+ (text-config '())
+ "List of strings or gexps, which will be added to @file{.zshenv}.
+Used for setting user's shell environment variables. Must not contain
+commands assuming the presence of tty or producing output. Will be
+read always. Will be read before any other file in @env{ZDOTDIR}.")
+ (zprofile
+ (text-config '())
+ "List of strings or gexps, which will be added to @file{.zprofile}.
+Used for executing user's commands at start of login shell (In most
+cases the shell started on tty just after login). Will be read before
+@file{.zlogin}.")
+ (zshrc
+ (text-config '())
+ "List of strings or gexps, which will be added to @file{.zshrc}.
+Used for executing user's commands at start of interactive shell (The
+shell for interactive usage started by typing @code{zsh} or by
+terminal app or any other program).")
+ (zlogin
+ (text-config '())
+ "List of strings or gexps, which will be added to @file{.zlogin}.
+Used for executing user's commands at the end of starting process of
+login shell.")
+ (zlogout
+ (text-config '())
+ "List of strings or gexps, which will be added to @file{.zlogout}.
+Used for executing user's commands at the exit of login shell. It
+won't be read in some cases (if the shell terminates by exec'ing
+another process for example)."))
+
+(define (add-zsh-configuration config)
+ (let* ((xdg-flavor? (home-zsh-configuration-xdg-flavor? config)))
+
+ (define prefix-file
+ (cut string-append
+ (if xdg-flavor?
+ "config/zsh/."
+ "") <>))
+
+ (define (filter-fields field)
+ (filter-configuration-fields home-zsh-configuration-fields
+ (list field)))
+
+ (define (serialize-field field)
+ (serialize-configuration
+ config
+ (filter-fields field)))
+
+ (define (file-if-not-empty field)
+ (let ((file-name (symbol->string field))
+ (field-obj (car (filter-fields field))))
+ (if (not (null? ((configuration-field-getter field-obj) config)))
+ `(,(prefix-file file-name)
+ ,(mixed-text-file
+ file-name
+ (serialize-field field)))
+ '())))
+
+ (filter
+ (compose not null?)
+ `(,(if xdg-flavor?
+ `("zshenv"
+ ,(mixed-text-file
+ "auxiliary-zshenv"
+ (if xdg-flavor?
+ "source ${XDG_CONFIG_HOME:-$HOME/.config}/zsh/.zshenv\n"
+ "")))
+ '())
+ (,(prefix-file "zshenv")
+ ,(mixed-text-file
+ "zshenv"
+ (if xdg-flavor?
+ "export ZDOTDIR=${XDG_CONFIG_HOME:-$HOME/.config}/zsh\n"
+ "")
+ (serialize-field 'zshenv)
+ (serialize-field 'environment-variables)))
+ (,(prefix-file "zprofile")
+ ,(mixed-text-file
+ "zprofile"
+ "\
+# Setups system and user profiles and related variables
+source /etc/profile
+# Setups home environment profile
+source ~/.profile
+
+# It's only necessary if zsh is a login shell, otherwise profiles will
+# be already sourced by bash
+"
+ (serialize-field 'zprofile)))
+
+ ,@(list (file-if-not-empty 'zshrc)
+ (file-if-not-empty 'zlogin)
+ (file-if-not-empty 'zlogout))))))
+
+(define (add-zsh-packages config)
+ (list (home-zsh-configuration-package config)))
+
+(define-configuration/no-serialization home-zsh-extension
+ (environment-variables
+ (alist '())
+ "Association list of environment variables to set.")
+ (zshrc
+ (text-config '())
+ "List of strings or gexps.")
+ (zshenv
+ (text-config '())
+ "List of strings or gexps.")
+ (zprofile
+ (text-config '())
+ "List of strings or gexps.")
+ (zlogin
+ (text-config '())
+ "List of strings or gexps.")
+ (zlogout
+ (text-config '())
+ "List of strings or gexps."))
+
+(define (home-zsh-extensions original-config extension-configs)
+ (home-zsh-configuration
+ (inherit original-config)
+ (environment-variables
+ (append (home-zsh-configuration-environment-variables original-config)
+ (append-map
+ home-zsh-extension-environment-variables extension-configs)))
+ (zshrc
+ (append (home-zsh-configuration-zshrc original-config)
+ (append-map
+ home-zsh-extension-zshrc extension-configs)))
+ (zshenv
+ (append (home-zsh-configuration-zshenv original-config)
+ (append-map
+ home-zsh-extension-zshenv extension-configs)))
+ (zprofile
+ (append (home-zsh-configuration-zprofile original-config)
+ (append-map
+ home-zsh-extension-zprofile extension-configs)))
+ (zlogin
+ (append (home-zsh-configuration-zlogin original-config)
+ (append-map
+ home-zsh-extension-zlogin extension-configs)))
+ (zlogout
+ (append (home-zsh-configuration-zlogout original-config)
+ (append-map
+ home-zsh-extension-zlogout extension-configs)))))
+
+(define home-zsh-service-type
+ (service-type (name 'home-zsh)
+ (extensions
+ (list (service-extension
+ home-files-service-type
+ add-zsh-configuration)
+ (service-extension
+ home-profile-service-type
+ add-zsh-packages)))
+ (compose identity)
+ (extend home-zsh-extensions)
+ (default-value (home-zsh-configuration))
+ (description "Install and configure Zsh.")))
+
+
+;;;
+;;; Bash.
+;;;
+
+(define-configuration home-bash-configuration
+ (package
+ (package bash)
+ "The Bash package to use.")
+ (guix-defaults?
+ (boolean #t)
+ "Add sane defaults like reading @file{/etc/bashrc}, coloring output
+for @code{ls} provided by guix to @file{.bashrc}.")
+ (environment-variables
+ (alist '())
+ "Association list of environment variables to set for the Bash session."
+ serialize-posix-env-vars)
+ (bash-profile
+ (text-config '())
+ "List of strings or gexps, which will be added to @file{.bash_profile}.
+Used for executing user's commands at start of login shell (In most
+cases the shell started on tty just after login). @file{.bash_login}
+won't be ever read, because @file{.bash_profile} always present.")
+ (bashrc
+ (text-config '())
+ "List of strings or gexps, which will be added to @file{.bashrc}.
+Used for executing user's commands at start of interactive shell (The
+shell for interactive usage started by typing @code{bash} or by
+terminal app or any other program).")
+ (bash-logout
+ (text-config '())
+ "List of strings or gexps, which will be added to @file{.bash_logout}.
+Used for executing user's commands at the exit of login shell. It
+won't be read in some cases (if the shell terminates by exec'ing
+another process for example)."))
+
+;; TODO: Use value from (gnu system shadow)
+(define guix-bashrc
+ "\
+# Bash initialization for interactive non-login shells and
+# for remote shells (info \"(bash) Bash Startup Files\").
+
+# Export 'SHELL' to child processes. Programs such as 'screen'
+# honor it and otherwise use /bin/sh.
+export SHELL
+
+if [[ $- != *i* ]]
+then
+ # We are being invoked from a non-interactive shell. If this
+ # is an SSH session (as in \"ssh host command\"), source
+ # /etc/profile so we get PATH and other essential variables.
+ [[ -n \"$SSH_CLIENT\" ]] && source /etc/profile
+
+ # Don't do anything else.
+ return
+fi
+
+# Source the system-wide file.
+source /etc/bashrc
+
+# Adjust the prompt depending on whether we're in 'guix environment'.
+if [ -n \"$GUIX_ENVIRONMENT\" ]
+then
+ PS1='\\u@\\h \\w [env]\\$ '
+else
+ PS1='\\u@\\h \\w\\$ '
+fi
+alias ls='ls -p --color=auto'
+alias ll='ls -l'
+alias grep='grep --color=auto'\n")
+
+(define (add-bash-configuration config)
+ (define (filter-fields field)
+ (filter-configuration-fields home-bash-configuration-fields
+ (list field)))
+
+ (define (serialize-field field)
+ (serialize-configuration
+ config
+ (filter-fields field)))
+
+ (define* (file-if-not-empty field #:optional (extra-content #f))
+ (let ((file-name (symbol->string field))
+ (field-obj (car (filter-fields field))))
+ (if (or extra-content
+ (not (null? ((configuration-field-getter field-obj) config))))
+ `(,(object->snake-case-string file-name)
+ ,(mixed-text-file
+ (object->snake-case-string file-name)
+ (if extra-content extra-content "")
+ (serialize-field field)))
+ '())))
+
+ (filter
+ (compose not null?)
+ `(("bash_profile"
+ ,(mixed-text-file
+ "bash_profile"
+ "\
+# Setups system and user profiles and related variables
+# /etc/profile will be sourced by bash automatically
+# Setups home environment profile
+if [ -f ~/.profile ]; then source ~/.profile; fi
+
+# Honor per-interactive-shell startup file
+if [ -f ~/.bashrc ]; then source ~/.bashrc; fi
+"
+ (serialize-field 'bash-profile)
+ (serialize-field 'environment-variables)))
+
+ ,@(list (file-if-not-empty
+ 'bashrc
+ (if (home-bash-configuration-guix-defaults? config)
+ guix-bashrc
+ #f))
+ (file-if-not-empty 'bash-logout)))))
+
+(define (add-bash-packages config)
+ (list (home-bash-configuration-package config)))
+
+(define-configuration/no-serialization home-bash-extension
+ (environment-variables
+ (alist '())
+ "Association list of environment variables to set.")
+ (bash-profile
+ (text-config '())
+ "List of strings or gexps.")
+ (bashrc
+ (text-config '())
+ "List of strings or gexps.")
+ (bash-logout
+ (text-config '())
+ "List of strings or gexps."))
+
+(define (home-bash-extensions original-config extension-configs)
+ (home-bash-configuration
+ (inherit original-config)
+ (environment-variables
+ (append (home-bash-configuration-environment-variables original-config)
+ (append-map
+ home-bash-extension-environment-variables extension-configs)))
+ (bash-profile
+ (append (home-bash-configuration-bash-profile original-config)
+ (append-map
+ home-bash-extension-bash-profile extension-configs)))
+ (bashrc
+ (append (home-bash-configuration-bashrc original-config)
+ (append-map
+ home-bash-extension-bashrc extension-configs)))
+ (bash-logout
+ (append (home-bash-configuration-bash-logout original-config)
+ (append-map
+ home-bash-extension-bash-logout extension-configs)))))
+
+(define home-bash-service-type
+ (service-type (name 'home-bash)
+ (extensions
+ (list (service-extension
+ home-files-service-type
+ add-bash-configuration)
+ (service-extension
+ home-profile-service-type
+ add-bash-packages)))
+ (compose identity)
+ (extend home-bash-extensions)
+ (default-value (home-bash-configuration))
+ (description "Install and configure GNU Bash.")))
+
+
+;;;
+;;; Fish.
+;;;
+
+(define (serialize-fish-aliases field-name val)
+ #~(string-append
+ #$@(map (match-lambda
+ ((key . value)
+ #~(string-append "alias " #$key " \"" #$value "\"\n"))
+ (_ ""))
+ val)))
+
+(define (serialize-fish-abbreviations field-name val)
+ #~(string-append
+ #$@(map (match-lambda
+ ((key . value)
+ #~(string-append "abbr --add " #$key " " #$value "\n"))
+ (_ ""))
+ val)))
+
+(define (serialize-fish-env-vars field-name val)
+ #~(string-append
+ #$@(map (match-lambda
+ ((key . #f)
+ "")
+ ((key . #t)
+ #~(string-append "set " #$key "\n"))
+ ((key . value)
+ #~(string-append "set " #$key " " #$value "\n")))
+ val)))
+
+(define-configuration home-fish-configuration
+ (package
+ (package fish)
+ "The Fish package to use.")
+ (config
+ (text-config '())
+ "List of strings or gexps, which will be added to
+@file{$XDG_CONFIG_HOME/fish/config.fish}.")
+ (environment-variables
+ (alist '())
+ "Association list of environment variables to set in Fish."
+ serialize-fish-env-vars)
+ (aliases
+ (alist '())
+ "Association list of aliases for Fish, both the key and the value
+should be a string. An alias is just a simple function that wraps a
+command, If you want something more akin to @dfn{aliases} in POSIX
+shells, see the @code{abbreviations} field."
+ serialize-fish-aliases)
+ (abbreviations
+ (alist '())
+ "Association list of abbreviations for Fish. These are words that,
+when typed in the shell, will automatically expand to the full text."
+ serialize-fish-abbreviations))
+
+(define (fish-files-service config)
+ `(("config/fish/config.fish"
+ ,(mixed-text-file
+ "fish-config.fish"
+ #~(string-append "\
+# if we haven't sourced the login config, do it
+status --is-login; and not set -q __fish_login_config_sourced
+and begin
+
+ set --prepend fish_function_path "
+ #$fish-foreign-env
+ "/share/fish/functions
+ fenv source $HOME/.profile
+ set -e fish_function_path[1]
+
+ set -g __fish_login_config_sourced 1
+
+end\n\n")
+ (serialize-configuration
+ config
+ home-fish-configuration-fields)))))
+
+(define (fish-profile-service config)
+ (list (home-fish-configuration-package config)))
+
+(define-configuration/no-serialization home-fish-extension
+ (config
+ (text-config '())
+ "List of strings or gexps for extending the Fish initialization file.")
+ (environment-variables
+ (alist '())
+ "Association list of environment variables to set.")
+ (aliases
+ (alist '())
+ "Association list of Fish aliases.")
+ (abbreviations
+ (alist '())
+ "Association list of Fish abbreviations."))
+
+(define (home-fish-extensions original-config extension-configs)
+ (home-fish-configuration
+ (inherit original-config)
+ (config
+ (append (home-fis
This message was truncated. Download the full message here.
-----BEGIN PGP SIGNATURE-----

iQJDBAEBCgAtFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmEojiYPHGFuZHJld0B0
cm9wLmluAAoJECII0glYwd6wQg0P/3p4X/z2of3V2xDBLb6/RFUf8Zd/IJMdLsZm
GYIYdR161AGe4VNfg3eqi+/gKaRkDOPIlLq07C8hLAWCddi8nvcSjXUgvIqd1lcD
zZDI3psu1rxPwbq5GpF67rnZAI+ddr6x33z5ALOWlpOtOVqLLp9nYRTodJD1NjJC
RB75LLEdoGYc1HOwsPYMAgPEPKWQ/HH1K7FI6HW269ez9mtLZj5ERjcSmlDK3oDY
s30gqr+Kfg291VlgVTMb4ksOf+pzoZjafZih1qTShmOpUPsLriDv6iNYG5AehxN6
TUGBAIVm0m+yyUCEiTVrQnuZz3jDAOpFkQdxdcxPTtahavVObPaRjpmNPXcnzuTg
ZwPo5tvZtIuejQ5oyDNqXqDIukQyYEr48IoT939+DGnV/B5x2Y6jr+9TMDJ9sx3b
u9KmsjWvav28hepJmZwC5Ejl5wEA0lSrZOO8OwXu8au0GSLW+7r8r+T1drfBgRg1
FHrq3B3O6l5Zn1HVqGtnJXvGsSWERxzbAFH3yUyA9Oke0rFy6QGgRCog6sldqme8
Zm1YMmuGX4jWJ6dG0hIvlM5EGltGgwZ6tg+swLxem8XWuvIw7PLn2Gf7Gv9Y7Xd/
YaSMGCa7EQ3BFWlREIaKka+t3AYxxY7v3DO2mUA9buq4HfO1SWdQAn5ANmbwNSAz
N+TbNVNT
=vu+M
-----END PGP SIGNATURE-----

Andrew Tropin wrote 4 years ago
[PATCH 4/5] home-services: Add xdg.
(name . Oleg Pykhalov)(address . go.wigust@gmail.com)(address . 50208@debbugs.gnu.org)
87o89je585.fsf@trop.in
* gnu/home-services/xdg.scm
(home-xdg-base-directories-service-type)
(home-xdg-base-directories-configuration)
(home-xdg-base-directories-configuration?)
(home-xdg-user-directories-service-type)
(home-xdg-user-directories-configuration)
(home-xdg-user-directories-configuration?)
(xdg-desktop-action, xdg-desktop-entry)
(home-xdg-mime-applications-service-type)
(home-xdg-mime-applications-configuration): New variables.
* gnu/local.mk (GNU_SYSTEM_MODULES): Add home-services/xdg.scm.
---
gnu/home-services/xdg.scm | 475 ++++++++++++++++++++++++++++++++++++++
gnu/local.mk | 1 +
2 files changed, 476 insertions(+)
create mode 100644 gnu/home-services/xdg.scm

Toggle diff (495 lines)
diff --git a/gnu/home-services/xdg.scm b/gnu/home-services/xdg.scm
new file mode 100644
index 0000000000..acacaa1218
--- /dev/null
+++ b/gnu/home-services/xdg.scm
@@ -0,0 +1,475 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
+;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu home-services xdg)
+ #:use-module (gnu services configuration)
+ #:use-module (gnu home-services configuration)
+ #:use-module (gnu home-services)
+ #:use-module (gnu packages freedesktop)
+ #:use-module (gnu home-services-utils)
+ #:use-module (guix gexp)
+ #:use-module (guix records)
+ #:use-module (guix i18n)
+
+ #:use-module (ice-9 match)
+ #:use-module (srfi srfi-1)
+ #:use-module (rnrs enums)
+
+ #:export (home-xdg-base-directories-service-type
+ home-xdg-base-directories-configuration
+ home-xdg-base-directories-configuration?
+
+ home-xdg-user-directories-service-type
+ home-xdg-user-directories-configuration
+ home-xdg-user-directories-configuration?
+
+ xdg-desktop-action
+ xdg-desktop-entry
+ home-xdg-mime-applications-service-type
+ home-xdg-mime-applications-configuration))
+
+;;; Commentary:
+;;
+;; This module contains services related to XDG directories and
+;; applications.
+;;
+;; - XDG base directories
+;; - XDG user directories
+;; - XDG MIME applications
+;;
+;;; Code:
+
+
+;;;
+;;; XDG base directories.
+;;;
+
+(define (serialize-path field-name val) "")
+(define path? string?)
+
+(define-configuration home-xdg-base-directories-configuration
+ (cache-home
+ (path "$HOME/.cache")
+ "Base directory for programs to store user-specific non-essential
+(cached) data. Files in this directory can be deleted anytime without
+loss of important data.")
+ (config-home
+ (path "$HOME/.config")
+ "Base directory for programs to store configuration files.
+Some programs store here log or state files, but it's not desired,
+this directory should contain static configurations.")
+ (data-home
+ (path "$HOME/.local/share")
+ "Base directory for programs to store architecture independent
+read-only shared data, analogus to @file{/usr/share}, but for user.")
+ (runtime-dir
+ (path "${XDG_RUNTIME_DIR:-/run/user/$UID}")
+ "Base directory for programs to store user-specific runtime files,
+like sockets.")
+ (log-home
+ (path "$HOME/.local/var/log")
+ "Base directory for programs to store log files, analogus to
+@file{/var/log}, but for user. It is not a part of XDG Base Directory
+Specification, but helps to make implementation of home services more
+consistent.")
+ (state-home
+ (path "$HOME/.local/var/lib")
+ "Base directory for programs to store state files, like databases,
+analogus to @file{/var/lib}, but for user. It is not a part of XDG
+Base Directory Specification, but helps to make implementation of home
+services more consistent."))
+
+(define (home-xdg-base-directories-environment-variables-service config)
+ (map
+ (lambda (field)
+ (cons (format
+ #f "XDG_~a"
+ (object->snake-case-string (configuration-field-name field) 'upper))
+ ((configuration-field-getter field) config)))
+ home-xdg-base-directories-configuration-fields))
+
+(define (ensure-xdg-base-dirs-on-activation config)
+ #~(map (lambda (xdg-base-dir-variable)
+ ((@@ (guix build utils) mkdir-p)
+ (getenv
+ xdg-base-dir-variable)))
+ '#$(map (lambda (field)
+ (format
+ #f "XDG_~a"
+ (object->snake-case-string
+ (configuration-field-name field) 'upper)))
+ home-xdg-base-directories-configuration-fields)))
+
+(define (last-extension-or-cfg config extensions)
+ "Picks configuration value from last provided extension. If there
+are no extensions use configuration instead."
+ (or (and (not (null? extensions)) (last extensions)) config))
+
+(define home-xdg-base-directories-service-type
+ (service-type (name 'home-xdg-base-directories)
+ (extensions
+ (list (service-extension
+ home-environment-variables-service-type
+ home-xdg-base-directories-environment-variables-service)
+ (service-extension
+ home-activation-service-type
+ ensure-xdg-base-dirs-on-activation)))
+ (default-value (home-xdg-base-directories-configuration))
+ (compose identity)
+ (extend last-extension-or-cfg)
+ (description "Configure XDG base directories. This
+service introduces two additional variables @env{XDG_STATE_HOME},
+@env{XDG_LOG_HOME}. They are not a part of XDG specification, at
+least yet, but are convinient to have, it improves the consistency
+between different home services. The services of this service-type is
+instantiated by default, to provide non-default value, extend the
+service-type (using @code{simple-service} for example).")))
+
+(define (generate-home-xdg-base-directories-documentation)
+ (generate-documentation
+ `((home-xdg-base-directories-configuration
+ ,home-xdg-base-directories-configuration-fields))
+ 'home-xdg-base-directories-configuration))
+
+
+;;;
+;;; XDG user directories.
+;;;
+
+(define (serialize-string field-name val)
+ ;; The path has to be quoted
+ (format #f "XDG_~a_DIR=\"~a\"\n"
+ (object->snake-case-string field-name 'upper) val))
+
+(define-configuration home-xdg-user-directories-configuration
+ (desktop
+ (string "$HOME/Desktop")
+ "Default ``desktop'' directory, this is what you see on your
+desktop when using a desktop environment,
+e.g. GNOME (@pxref{XWindow,,,guix.info}).")
+ (documents
+ (string "$HOME/Documents")
+ "Default directory to put documents like PDFs.")
+ (download
+ (string "$HOME/Downloads")
+ "Default directory downloaded files, this is where your Web-broser
+will put downloaded files in.")
+ (music
+ (string "$HOME/Music")
+ "Default directory for audio files.")
+ (pictures
+ (string "$HOME/Pictures")
+ "Default directory for pictures and images.")
+ (publicshare
+ (string "$HOME/Public")
+ "Default directory for shared files, which can be accessed by other
+users on local machine or via network.")
+ (templates
+ (string "$HOME/Templates")
+ "Default directory for templates. They can be used by graphical
+file manager or other apps for creating new files with some
+pre-populated content.")
+ (videos
+ (string "$HOME/Videos")
+ "Default directory for videos."))
+
+(define (home-xdg-user-directories-files-service config)
+ `(("config/user-dirs.conf"
+ ,(mixed-text-file
+ "user-dirs.conf"
+ "enabled=False\n"))
+ ("config/user-dirs.dirs"
+ ,(mixed-text-file
+ "user-dirs.dirs"
+ (serialize-configuration
+ config
+ home-xdg-user-directories-configuration-fields)))))
+
+(define (home-xdg-user-directories-activation-service config)
+ (let ((dirs (map (lambda (field)
+ ((configuration-field-getter field) config))
+ home-xdg-user-directories-configuration-fields)))
+ #~(let ((ensure-dir
+ (lambda (path)
+ (mkdir-p
+ ((@@ (ice-9 string-fun) string-replace-substring)
+ path "$HOME" (getenv "HOME"))))))
+ (display "Creating XDG user directories...")
+ (map ensure-dir '#$dirs)
+ (display " done\n"))))
+
+(define home-xdg-user-directories-service-type
+ (service-type (name 'home-xdg-user-directories)
+ (extensions
+ (list (service-extension
+ home-files-service-type
+ home-xdg-user-directories-files-service)
+ (service-extension
+ home-activation-service-type
+ home-xdg-user-directories-activation-service)))
+ (default-value (home-xdg-user-directories-configuration))
+ (description "Configure XDG user directories. To
+disable a directory, point it to the $HOME.")))
+
+(define (generate-home-xdg-user-directories-documentation)
+ (generate-documentation
+ `((home-xdg-user-directories-configuration
+ ,home-xdg-user-directories-configuration-fields))
+ 'home-xdg-user-directories-configuration))
+
+
+;;;
+;;; XDG MIME applications.
+;;;
+
+;; Example config
+;;
+;; (home-xdg-mime-applications-configuration
+;; (added '((x-scheme-handler/magnet . torrent.desktop)))
+;; (default '((inode/directory . file.desktop)))
+;; (removed '((inode/directory . thunar.desktop)))
+;; (desktop-entries
+;; (list (xdg-desktop-entry
+;; (file "file")
+;; (name "File manager")
+;; (type 'application)
+;; (config
+;; '((exec . "emacsclient -c -a emacs %u"))))
+;; (xdg-desktop-entry
+;; (file "text")
+;; (name "Text editor")
+;; (type 'application)
+;; (config
+;; '((exec . "emacsclient -c -a emacs %u")))
+;; (actions
+;; (list (xdg-desktop-action
+;; (action 'create)
+;; (name "Create an action")
+;; (config
+;; '((exec . "echo hi"))))))))))
+
+;; See
+;; <https://specifications.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html>
+;; <https://specifications.freedesktop.org/mime-apps-spec/mime-apps-spec-latest.html>
+
+(define (serialize-alist field-name val)
+ (define (serialize-mimelist-entry key val)
+ (let ((val (cond
+ ((list? val)
+ (string-join (map maybe-object->string val) ";"))
+ ((or (string? val) (symbol? val))
+ val)
+ (else (raise (formatted-message
+ (G_ "\
+The value of an XDG MIME entry must be a list, string or symbol, was given ~a")
+ val))))))
+ (format #f "~a=~a\n" key val)))
+
+ (define (merge-duplicates alist acc)
+ "Merge values that have the same key.
+
+@example
+(merge-duplicates '((key1 . value1)
+ (key2 . value2)
+ (key1 . value3)
+ (key1 . value4)) '())
+
+@result{} ((key1 . (value4 value3 value1)) (key2 . value2))
+@end example"
+ (cond
+ ((null? alist) acc)
+ (else (let* ((head (first alist))
+ (tail (cdr alist))
+ (key (first head))
+ (value (cdr head))
+ (duplicate? (assoc key acc)))
+ (if duplicate?
+ ;; XXX: This will change the order of things,
+ ;; though, it shouldn't be a problem for XDG MIME.
+ (merge-duplicates
+ tail
+ (alist-cons key
+ (cons value (maybe-list (cdr duplicate?)))
+ (alist-delete key acc)))
+ (merge-duplicates tail (cons head acc)))))))
+
+ (string-append (if (equal? field-name 'default)
+ "\n[Default Applications]\n"
+ (format #f "\n[~a Associations]\n"
+ (string-capitalize (symbol->string field-name))))
+ (generic-serialize-alist string-append
+ serialize-mimelist-entry
+ (merge-duplicates val '()))))
+
+(define xdg-desktop-types (make-enumeration
+ '(application
+ link
+ directory)))
+
+(define (xdg-desktop-type? type)
+ (unless (enum-set-member? type xdg-desktop-types)
+ (raise (formatted-message
+ (G_ "XDG desktop type must be of of ~a, was given: ~a")
+ (list->human-readable-list (enum-set->list xdg-desktop-types))
+ type))))
+
+;; TODO: Add proper docs for this
+;; XXX: 'define-configuration' require that fields have a default
+;; value.
+(define-record-type* <xdg-desktop-action>
+ xdg-desktop-action make-xdg-desktop-action
+ xdg-desktop-action?
+ (action xdg-desktop-action-action) ; symbol
+ (name xdg-desktop-action-name) ; string
+ (config xdg-desktop-action-config ; alist
+ (default '())))
+
+(define-record-type* <xdg-desktop-entry>
+ xdg-desktop-entry make-xdg-desktop-entry
+ xdg-desktop-entry?
+ ;; ".desktop" will automatically be added
+ (file xdg-desktop-entry-file) ; string
+ (name xdg-desktop-entry-name) ; string
+ (type xdg-desktop-entry-type) ; xdg-desktop-type
+ (config xdg-desktop-entry-config ; alist
+ (default '()))
+ (actions xdg-desktop-entry-actions ; list of <xdg-desktop-action>
+ (default '())))
+
+(define desktop-entries? (list-of xdg-desktop-entry?))
+(define (serialize-desktop-entries field-name val) "")
+
+(define (serialize-xdg-desktop-entry entry)
+ "Return a tuple of the file name for ENTRY and the serialized
+configuration."
+ (define (format-config key val)
+ (let ((val (cond
+ ((list? val)
+ (string-join (map maybe-object->string val) ";"))
+ ((boolean? val)
+ (if val "true" "false"))
+ (else val)))
+ (key (string-capitalize (maybe-object->string key))))
+ (list (if (string-suffix? key "?")
+ (string-drop-right key (- (string-length key) 1))
+ key)
+ "=" val "\n")))
+
+ (define (serialize-alist config)
+ (generic-serialize-alist identity format-config config))
+
+ (define (serialize-xdg-desktop-action action)
+ (match action
+ (($ <xdg-desktop-action> action name config)
+ `(,(format #f "[Desktop Action ~a]\n"
+ (string-capitalize (maybe-object->string action)))
+ ,(format #f "Name=~a\n" name)
+ ,@(serialize-alist config)))))
+
+ (match entry
+ (($ <xdg-desktop-entry> file name type config actions)
+ (list (if (string-suffix? file ".desktop")
+ file
+ (string-append file ".desktop"))
+ `("[Desktop Entry]\n"
+ ,(format #f "Name=~a\n" name)
+ ,(format #f "Type=~a\n"
+ (string-capitalize (symbol->string type)))
+ ,@(serialize-alist config)
+ ,@(append-map serialize-xdg-desktop-action actions))))))
+
+(define-configuration home-xdg-mime-applications-configuration
+ (added
+ (alist '())
+ "An association list of MIME types and desktop entries which indicate
+that the application should used to open the specified MIME type. The
+value has to be string, symbol, or list of strings or symbols, this
+applies to the `@code{default}', and `@code{removed}' fields as well.")
+ (default
+ (alist '())
+ "An association list of MIME types and desktop entries which indicate
+that the application should be the default for opening the specified
+MIME type.")
+ (removed
+ (alist '())
+ "An association list of MIME types and desktop entries which indicate
+that the application cannot open the specified MIME type.")
+ (desktop-entries
+ (desktop-entries '())
+ "A list of XDG desktop entries to create. See
+@code{xdg-desktop-entry}."))
+
+(define (home-xdg-mime-applications-files-service config)
+ (define (add-xdg-desktop-entry-file entry)
+ (let ((file (first entry))
+ (config (second entry)))
+ (list (format #f "local/share/applications/~a" file)
+ (apply mixed-text-file
+ (format #f "xdg-desktop-~a-entry" file)
+ config))))
+
+ (append
+ `(("config/mimeapps.list"
+ ,(mixed-text-file
+ "xdg-mime-appplications"
+ (serialize-configuration
+ config
+ home-xdg-mime-applications-configuration-fields))))
+ (map (compose add-xdg-desktop-entry-file serialize-xdg-desktop-entry)
+ (home-xdg-mime-applications-configuration-desktop-entries config))))
+
+(define (home-xdg-mime-applications-extension old-config extension-configs)
+ (define (extract-fields config)
+ ;; return '(added default removed desktop-entries)
+ (list (home-xdg-mime-applications-configuration-added config)
+ (home-xdg-mime-applications-configuration-default config)
+ (home-xdg-mime-applications-configuration-removed config)
+ (home-xdg-mime-applications-configuration-desktop-entries config)))
+
+ (define (append-configs elem acc)
+ (list (append (first elem) (first acc))
+ (append (second elem) (second acc))
+ (append (third elem) (third acc))
+ (append (fourth elem) (fourth acc))))
+
+ ;; TODO: Implement procedure to check for duplicates without
+ ;; sacrificing performance.
+ ;;
+ ;; Combine all the alists from 'added', 'default' and 'removed'
+ ;; into one big alist.
+ (let ((folded-configs (fold append-configs
+ (extract-fields old-config)
+ (map extract-fields extension-configs))))
+ (home-xdg-mime-applications-configuration
+ (added (first folded-configs))
+ (default (second folded-configs))
+ (removed (third folded-configs))
+ (desktop-entries (fourth folded-configs)))))
+
+(define home-xdg-mime-applications-service-type
+ (service-type (name 'home-xdg-mime-applications)
+ (extensions
+ (list (service-extension
+ home-files-service-type
+ home-xdg-mime-applications-files-service)))
+ (compose identity)
+ (extend home-xdg-mime-applications-extension)
+ (default-value (home-xdg-mime-applications-configuration))
+ (description
+ "Configure XDG MIME applications, and XDG desktop entries.")))
diff --git a/gnu/local.mk b/gnu/local.mk
index dc0e732114..8c44c143af 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -77,6 +77,7 @@ GNU_SYSTEM_MODULES = \
%D%/home-services/fontutils.scm \
%D%/home-services/configuration.scm \
%D%/home-services/shells.scm \
+ %D%/home-services/xdg.scm \
%D%/image.scm \
%D%/packages.scm \
%D%/packages/abduco.scm \
--
2.33.0
-----BEGIN PGP SIGNATURE-----

iQJDBAEBCgAtFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmEojwoPHGFuZHJld0B0
cm9wLmluAAoJECII0glYwd6wQuMP/2pHUeQeM7CHlRcGaHcsT6UTogIOJ75Rx643
WNoc01gsjDo4CVIUAXpAMSuOnuWMNvPM9pg42PPvECy1fIxPiZG+ebcLgR2ZdFWR
BIfhoqKKEx0sUrutvdsBZT6uZeeiJTJYZrGmUzMjDC5ksbV3Ja9FsaQrzg/nuWn5
GIusoalXPqj2AEmcBjjprrLQ5y763LT5hzQkRRZxpO42VKn/OsQEHSftNKstYYMt
SJEWvVvtmPhcZW5oElOy+LPB4Xm22lrYXgWpaXj0E9dpspzDamsviGYG109idS8w
TS06eoJg9V/JAov7hMj18ScvmACBZGLOcPNQ45I33quWEQ7zNCNik0oEFyUYSEfy
2rN926FVAbrx/Lbst/7sxTQF0yq5Q9GGDUNJVV44I1U2buKmdO23ztCviMVEZC7E
kcTUIzDOUZOfEgzx0fbaVFBgXv+7MMAiSMItre/iu+xHQybfRkBUTZyxnqp8u1kO
/WjFVHERIK5sJgS9k1sGEmOj6l2GMAs80QpMxQYX95cJkxS076IrESNUlUrIHn4P
lryn+/XWkzxXIyTq4B3Lx/aOfU4pH7Z2PzOM/L9LKrAgn9K9NdmAGXQwiuo55N+L
1zCAZ8u76Vch3UEk/8xR+iVKv+zmAlTB9bnPW7jABvd9faBWbnR3FMST8Mbc78HT
c3qbftsT
=/Yh0
-----END PGP SIGNATURE-----

Andrew Tropin wrote 4 years ago
[PATCH 5/5] home: Add home-environment.
(name . Oleg Pykhalov)(address . go.wigust@gmail.com)(address . 50208@debbugs.gnu.org)
87lf4ne56w.fsf@trop.in
* gnu/home.scm
(home-environment, home-environment?, this-home-environment)
(home-environment-derivation, home-environment-user-services)
(home-environment-essential-services, home-environment-services)
(home-environment-location, home-environment-with-provenance): New variables.
* gnu/local.mk (GNU_SYSTEM_MODULES): Add home.scm.
---
gnu/home.scm | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++
gnu/local.mk | 1 +
2 files changed, 98 insertions(+)
create mode 100644 gnu/home.scm

Toggle diff (117 lines)
diff --git a/gnu/home.scm b/gnu/home.scm
new file mode 100644
index 0000000000..220cc49846
--- /dev/null
+++ b/gnu/home.scm
@@ -0,0 +1,97 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu home)
+ #:use-module (gnu home-services)
+ #:use-module (gnu home-services symlink-manager)
+ #:use-module (gnu home-services shells)
+ #:use-module (gnu home-services xdg)
+ #:use-module (gnu home-services fontutils)
+ #:use-module (gnu services)
+ #:use-module (guix records)
+ #:use-module (guix diagnostics)
+
+ #:export (home-environment
+ home-environment?
+ this-home-environment
+
+ home-environment-derivation
+ home-environment-user-services
+ home-environment-essential-services
+ home-environment-services
+ home-environment-location
+
+ home-environment-with-provenance))
+
+(define-record-type* <home-environment> home-environment
+ make-home-environment
+ home-environment?
+ this-home-environment
+
+ (packages home-environment-packages ; list of (PACKAGE OUTPUT...)
+ (default '()))
+
+ (essential-services home-environment-essential-services ; list of services
+ (thunked)
+ (default (home-environment-default-essential-services
+ this-home-environment)))
+ (services home-environment-user-services
+ (default '()))
+
+ (location home-environment-location ; <location>
+ (default (and=> (current-source-location)
+ source-properties->location))
+ (innate)))
+
+(define (home-environment-default-essential-services he)
+ "Return the list of essential services for home environment."
+ (list
+ (service home-run-on-first-login-service-type)
+ (service home-activation-service-type)
+ (service home-environment-variables-service-type)
+
+ (service home-symlink-manager-service-type)
+
+ (service home-fontconfig-service-type)
+ (service home-xdg-base-directories-service-type)
+ (service home-shell-profile-service-type)
+
+ (service home-service-type)
+ (service home-profile-service-type (home-environment-packages he))))
+
+(define* (home-environment-services he)
+ "Return all the services of home environment."
+ (instantiate-missing-services
+ (append (home-environment-user-services he)
+ (home-environment-essential-services he))))
+
+(define* (home-environment-derivation he)
+ "Return a derivation that builds OS."
+ (let* ((services (home-environment-services he))
+ (home (fold-services services
+ #:target-type home-service-type)))
+ (service-value home)))
+
+(define* (home-environment-with-provenance he config-file)
+ "Return a variant of HE that stores its own provenance information,
+including CONFIG-FILE, if available. This is achieved by adding an instance
+of HOME-PROVENANCE-SERVICE-TYPE to its services."
+ (home-environment
+ (inherit he)
+ (services (cons (service home-provenance-service-type config-file)
+ (home-environment-user-services he)))))
diff --git a/gnu/local.mk b/gnu/local.mk
index 8c44c143af..bbaee51140 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -72,6 +72,7 @@ GNU_SYSTEM_MODULES = \
%D%/bootloader/u-boot.scm \
%D%/bootloader/depthcharge.scm \
%D%/ci.scm \
+ %D%/home.scm \
%D%/home-services.scm \
%D%/home-services/symlink-manager.scm \
%D%/home-services/fontutils.scm \
--
2.33.0
-----BEGIN PGP SIGNATURE-----

iQJDBAEBCgAtFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmEojzcPHGFuZHJld0B0
cm9wLmluAAoJECII0glYwd6weEgP/3ULj2So54R12l43fRefig3Uf+wZ6PgaSvFu
AFLxcjOZpVguSCq1jh+pz93uDAFmTTFQ7xSbDjDBr3EEICjIEs4o/LcXPi3q672n
hrcqjQXlYo+lYuXAN4MvM+sxYSBHksUj0aAWnX/kfD5xZWWb6C1BjqwKIBuNifvi
j+qU5gvKDxUdVq395h6vgEA2nlPuFqkhWuogFFVPAK1cElB+LYD7k5C5rzqruZw7
6sODAuIJh3gooDMFZPxQXa+ZvKbu8VEyDjJo50/BIxv4Lk1uVY28HfVHTv7OdURv
V/+k86YtbJwRMD+Bjt+D4awFBWIeiBCr0sUv95yGDxwSNr58G6pQuQ9PTTKHjcLH
izR1mr8/wHYcGyFW/8ckdYPI+3oQllGB7ZOAqLtBLOKS3WDcAOj6ibOPhH2xbRTb
+TPpALx+WxsWgRkSJjxlxRj5tnkxb5E5GYskinozVY1lZdSOAhMP3jKqZqv9qxeG
8YXBOLPN9v86moFtIbXOA8bIBMXwt7yj6qaA6pLVNGw8MIewoWCvEhgXd/LxhIRI
cY9Vklby2Ymemtw13lm1cwoiDPTSd+/BYnB+upuvdJJfYyZTVy/EAWbvR+NwJzLd
yuNZsgtDAZ3gGzyf3mI5TQvq685lYWX4VHwEL1ZOArxmq0xsqtRZta2VCwBr5N00
H+cRUeOa
=AWns
-----END PGP SIGNATURE-----

Jelle Licht wrote 4 years ago
Re: [bug#50208] [PATCH] home-services: Add symlink-manager
86zgt38dx3.fsf@fsfe.org
Hey Andrew,

some nits, as requested!

Andrew Tropin <andrew@trop.in> writes:

Toggle quote (45 lines)
> ---
> This patch is targeted against wip-guix-home branch.
>
> It's not a part of any patch series to make sure it will get enough attention,
> because it's most unpure part of the Guix Home and operates on user's files.
>
> gnu/home-services/symlink-manager.scm | 248 ++++++++++++++++++++++++++
> 1 file changed, 248 insertions(+)
> create mode 100644 gnu/home-services/symlink-manager.scm
>
> diff --git a/gnu/home-services/symlink-manager.scm b/gnu/home-services/symlink-manager.scm
> new file mode 100644
> index 0000000000..f13c9f4dbe
> --- /dev/null
> +++ b/gnu/home-services/symlink-manager.scm
> @@ -0,0 +1,248 @@
> +;;; GNU Guix --- Functional package management for GNU
> +;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
> +;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
> +;;;
> +;;; This file is part of GNU Guix.
> +;;;
> +;;; GNU Guix is free software; you can redistribute it and/or modify it
> +;;; under the terms of the GNU General Public License as published by
> +;;; the Free Software Foundation; either version 3 of the License, or (at
> +;;; your option) any later version.
> +;;;
> +;;; GNU Guix is distributed in the hope that it will be useful, but
> +;;; WITHOUT ANY WARRANTY; without even the implied warranty of
> +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +;;; GNU General Public License for more details.
> +;;;
> +;;; You should have received a copy of the GNU General Public License
> +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
> +
> +(define-module (gnu home-services symlink-manager)
> + #:use-module (gnu home-services)
> + #:use-module (guix gexp)
> +
> + #:export (home-symlink-manager-service-type))
> +
> +;;; Comment:
> +;;;
> +;;; symlink-manager cares about configuration files: it backups files

s/backups/backs up

Toggle quote (1 lines)
> +;;; created by user, removes symlinks and directories created by
missing the/a
Toggle quote (3 lines)
> +;;; previous generation, and creates new directories and symlinks to
> +;;; configs according to content of files/ directory of current home

I don't really get the last part of this sentence.

Toggle quote (12 lines)
> +;;; environment generation (created by home-files-service).
> +;;;
> +;;; Code:
> +
> +(define (update-symlinks-script)
> + (program-file
> + "update-symlinks"
> + #~(begin
> + (use-modules (ice-9 ftw)
> + (ice-9 curried-definitions)
> + (ice-9 match)
> + (srfi srfi-1))
The formatting seems off. In addition, I notice there are tab characters
in the patch for some reason, you should be able to have emacs Do The
Right Thing if you hack within a Guix git checkout.

Toggle quote (32 lines)
> + (define ((simplify-file-tree parent) file)
> + "Convert the result produced by `file-system-tree' to less
> +verbose and more suitable for further processing format.
> +
> +Extract dir/file info from stat and compose a relative path to the
> +root of the file tree.
> +
> +Sample output:
> +
> +((dir . \".\")
> + ((dir . \"config\")
> + ((dir . \"config/fontconfig\")
> + (file . \"config/fontconfig/fonts.conf\"))
> + ((dir . \"config/isync\")
> + (file . \"config/isync/mbsyncrc\"))))
> +"
> + (match file
> + ((name stat) `(file . ,(string-append parent name)))
> + ((name stat children ...)
> + (cons `(dir . ,(string-append parent name))
> + (map (simplify-file-tree
> + (if (equal? name ".")
> + ""
> + (string-append parent name "/")))
> + children)))))
> +
> + (define ((file-tree-traverse preordering) node)
> + "Traverses the file tree in different orders, depending on PREORDERING.
> +
> +if PREORDERING is @code{#t} resulting list will contain folders before
> +files located in those folders, otherwise folders will appear only
> +after all nested items already listed."
s/folders/(sub-)directories
Toggle quote (22 lines)
> + (let ((prepend (lambda (a b) (append b a))))
> + (match node
> + (('file . path) (list node))
> + ((('dir . path) . rest)
> + ((if preordering append prepend)
> + (list (cons 'dir path))
> + (append-map (file-tree-traverse preordering) rest))))))
> +
> + (use-modules (guix build utils))
> +
> + (let* ((he-path (string-append (getenv "HOME") "/.guix-home"))
> + (new-he-tmp-path (string-append he-path ".new"))
> + (new-home (getenv "GUIX_NEW_HOME")))
> + (symlink new-home new-he-tmp-path)
> + (rename-file new-he-tmp-path he-path))
> +
> + (let* ((config-home (or (getenv "XDG_CONFIG_HOME")
> + (string-append (getenv "HOME") "/.config")))
> +
> + (he-path (string-append (getenv "HOME") "/.guix-home"))
> + (new-he-tmp-path (string-append he-path ".new"))

This is a path to a transient location for the new home environment, correct?
tmp-path, to me at least, evokes a place where temporary files are
stored, contrasted to a temporary home for important files.

Toggle quote (55 lines)
> +
> + (files-path (string-append he-path "/files"))
> + ;; Leading dot is required, because files itself is symlink and
> + ;; to make file-system-tree works it should be a directory.
> + (files-dir-path (string-append files-path "/."))
> + (new-files-path (string-append new-he-tmp-path "/files"))
> + (new-files-dir-path (string-append files-path "/."))
> +
> + (home-path (getenv "HOME"))
> + (backup-dir (string-append home-path "/"
> + (number->string (current-time))
> + "-guix-home-legacy-configs-backup"))
> +
> + (old-tree (if (file-exists? files-dir-path)
> + ((simplify-file-tree "")
> + (file-system-tree files-dir-path))
> + #f))
> + (new-tree ((simplify-file-tree "")
> + (file-system-tree new-files-dir-path)))
> +

> + (get-source-path
> + (lambda (path)
> + (readlink (string-append files-path "/" path))))
> +
> + (get-target-path
> + (lambda (path)
> + (string-append home-path "/." path)))
> +
> + (get-backup-path
> + (lambda (path)
> + (string-append backup-dir "/." path)))
> +
> + (directory?
> + (lambda (path)
> + (equal? (stat:type (stat path)) 'directory)))
> +
> + (empty-directory?
> + (lambda (dir)
> + (equal? (scandir dir) '("." ".."))))
> +
> + (symlink-to-store?
> + (lambda (path)
> + (and
> + (equal? (stat:type (lstat path)) 'symlink)
> + (store-file-name? (readlink path)))))
> +
> + (backup-file
> + (lambda (path)
> + (mkdir-p backup-dir)
> + (format #t "Backing up ~a..." (get-target-path path))
> + (mkdir-p (dirname (get-backup-path path)))
> + (rename-file (get-target-path path) (get-backup-path path))
> + (display " done\n")))

A couple of the previous lambdas could have been `define'd (as a nested
define) instead of put in this binding form.

Toggle quote (22 lines)
> +
> + (cleanup-symlinks
> + (lambda ()
> + (let ((to-delete ((file-tree-traverse #f) old-tree)))
> + (display
> + "Cleaning up symlinks from previous home-environment.\n\n")
> + (map
> + (match-lambda
> + (('dir . ".")
> + (display "Cleanup finished.\n\n"))
> +
> + (('dir . path)
> + (if (and
> + (file-exists? (get-target-path path))
> + (directory? (get-target-path path))
> + (empty-directory? (get-target-path path)))
> + (begin
> + (format #t "Removing ~a..."
> + (get-target-path path))
> + (rmdir (get-target-path path))
> + (display " done\n"))

I think a let-binding for (get-target-path path) would work well here.

Toggle quote (11 lines)
> + (format
> + #t "Skipping ~a (not an empty directory)... done\n"
> + (get-target-path path))))
> +
> + (('file . path)
> + (when (file-exists? (get-target-path path))
> + ;; DO NOT remove the file if it was modified
> + ;; by user (not a symlink to the /gnu/store
> + ;; anymore) it will be backed up later during
> + ;; create-symlinks phase.

`by user' does not add anything; Referring to modified is slightly
confusing, as I can change the symlink to point to a different file in
the store and it will happily be deleted at this point in time.

what about:
DO NOT remote the file if it is no longer a symblink to the store. It
will be backed up later during the create-symlinks phase.

Toggle quote (67 lines)
> + (if (symlink-to-store? (get-target-path path))
> + (begin
> + (format #t "Removing ~a..." (get-target-path path))
> + (delete-file (get-target-path path))
> + (display " done\n"))
> + (format
> + #t
> + "Skipping ~a (not a symlink to store)... done\n"
> + (get-target-path path))))))
> + to-delete))))
> +
> + (create-symlinks
> + (lambda ()
> + (let ((to-create ((file-tree-traverse #t) new-tree)))
> + (map
> + (match-lambda
> + (('dir . ".")
> + (display
> + "New symlinks to home-environment will be created soon.\n")
> + (format
> + #t "All conflicting files will go to ~a.\n\n" backup-dir))
> +
> + (('dir . path)
> + (let ((target-path (get-target-path path)))
> + (when (and (file-exists? target-path)
> + (not (directory? target-path)))
> + (backup-file path))
> +
> + (if (file-exists? target-path)
> + (format
> + #t "Skipping ~a (directory already exists)... done\n"
> + target-path)
> + (begin
> + (format #t "Creating ~a..." target-path)
> + (mkdir target-path)
> + (display " done\n")))))
> +
> + (('file . path)
> + (when (file-exists? (get-target-path path))
> + (backup-file path))
> + (format #t "Symlinking ~a -> ~a..."
> + (get-target-path path) (get-source-path path))
> + (symlink (get-source-path path) (get-target-path path))
> + (display " done\n")))
> + to-create)))))
> +
> + (when old-tree
> + (cleanup-symlinks))
> +
> + (create-symlinks)
> +
> + (display " done\nFinished updating symlinks.\n\n")))))
> +
> +
> +(define (update-symlinks-gexp _)
> + #~(primitive-load #$(update-symlinks-script)))
> +
> +(define home-symlink-manager-service-type
> + (service-type (name 'home-symlink-manager)
> + (extensions
> + (list
> + (service-extension
> + home-activation-service-type
> + update-symlinks-gexp)))
> + (default-value #f)
> + (description "Provide an @code{update-symlinks}
> +script, which create and remove symlinks on every activation. If the
creates,removes.
Toggle quote (1 lines)
> +target is occupied by a file created by user, back it up.")))
What is target? Why should I care as a user of this service :)?
Perhaps rather than describing how the service does what it does, something in
the spirit of;

If an existing file would be overwritten by a symlink, back up
the exiting file first.

Toggle quote (3 lines)
> --
> 2.33.0

A nitpick I'm much less certain about is your use of display (and
format) without using the G_ macro; Perhaps you can try to reach out to
the folks who are most involved with the translation effort to see if
there is something that needs to be addressed now, of whether that can
still easily happen at a later point?

Thanks again for working on this!
- Jelle
Andrew Tropin wrote 4 years ago
877dg6di76.fsf@trop.in
On 2021-08-27 10:55, Jelle Licht wrote:

Toggle quote (61 lines)
> Hey Andrew,
>
> some nits, as requested!
>
> Andrew Tropin <andrew@trop.in> writes:
>
>> ---
>> This patch is targeted against wip-guix-home branch.
>>
>> It's not a part of any patch series to make sure it will get enough attention,
>> because it's most unpure part of the Guix Home and operates on user's files.
>>
>> gnu/home-services/symlink-manager.scm | 248 ++++++++++++++++++++++++++
>> 1 file changed, 248 insertions(+)
>> create mode 100644 gnu/home-services/symlink-manager.scm
>>
>> diff --git a/gnu/home-services/symlink-manager.scm b/gnu/home-services/symlink-manager.scm
>> new file mode 100644
>> index 0000000000..f13c9f4dbe
>> --- /dev/null
>> +++ b/gnu/home-services/symlink-manager.scm
>> @@ -0,0 +1,248 @@
>> +;;; GNU Guix --- Functional package management for GNU
>> +;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
>> +;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
>> +;;;
>> +;;; This file is part of GNU Guix.
>> +;;;
>> +;;; GNU Guix is free software; you can redistribute it and/or modify it
>> +;;; under the terms of the GNU General Public License as published by
>> +;;; the Free Software Foundation; either version 3 of the License, or (at
>> +;;; your option) any later version.
>> +;;;
>> +;;; GNU Guix is distributed in the hope that it will be useful, but
>> +;;; WITHOUT ANY WARRANTY; without even the implied warranty of
>> +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> +;;; GNU General Public License for more details.
>> +;;;
>> +;;; You should have received a copy of the GNU General Public License
>> +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
>> +
>> +(define-module (gnu home-services symlink-manager)
>> + #:use-module (gnu home-services)
>> + #:use-module (guix gexp)
>> +
>> + #:export (home-symlink-manager-service-type))
>> +
>> +;;; Comment:
>> +;;;
>> +;;; symlink-manager cares about configuration files: it backups files
>
> s/backups/backs up
>
>> +;;; created by user, removes symlinks and directories created by
> missing the/a
>> +;;; previous generation, and creates new directories and symlinks to
>> +;;; configs according to content of files/ directory of current home
>
> I don't really get the last part of this sentence.
>

Slightly rewrote it, hope now it's easier to understand:

;;; symlink-manager cares about configuration files: it backs up files
;;; created by user, removes symlinks and directories created by a
;;; previous generation, and creates new directories and symlinks to
;;; configuration files according to the content of files/ directory
;;; (created by home-files-service) of the current home environment
;;; generation.

Toggle quote (17 lines)
>
>> +;;; environment generation (created by home-files-service).
>> +;;;
>> +;;; Code:
>> +
>> +(define (update-symlinks-script)
>> + (program-file
>> + "update-symlinks"
>> + #~(begin
>> + (use-modules (ice-9 ftw)
>> + (ice-9 curried-definitions)
>> + (ice-9 match)
>> + (srfi srfi-1))
> The formatting seems off. In addition, I notice there are tab characters
> in the patch for some reason, you should be able to have emacs Do The
> Right Thing if you hack within a Guix git checkout.

Already fixed.

Toggle quote (35 lines)
>
>> + (define ((simplify-file-tree parent) file)
>> + "Convert the result produced by `file-system-tree' to less
>> +verbose and more suitable for further processing format.
>> +
>> +Extract dir/file info from stat and compose a relative path to the
>> +root of the file tree.
>> +
>> +Sample output:
>> +
>> +((dir . \".\")
>> + ((dir . \"config\")
>> + ((dir . \"config/fontconfig\")
>> + (file . \"config/fontconfig/fonts.conf\"))
>> + ((dir . \"config/isync\")
>> + (file . \"config/isync/mbsyncrc\"))))
>> +"
>> + (match file
>> + ((name stat) `(file . ,(string-append parent name)))
>> + ((name stat children ...)
>> + (cons `(dir . ,(string-append parent name))
>> + (map (simplify-file-tree
>> + (if (equal? name ".")
>> + ""
>> + (string-append parent name "/")))
>> + children)))))
>> +
>> + (define ((file-tree-traverse preordering) node)
>> + "Traverses the file tree in different orders, depending on PREORDERING.
>> +
>> +if PREORDERING is @code{#t} resulting list will contain folders before
>> +files located in those folders, otherwise folders will appear only
>> +after all nested items already listed."
> s/folders/(sub-)directories

Done.

Toggle quote (25 lines)
>> + (let ((prepend (lambda (a b) (append b a))))
>> + (match node
>> + (('file . path) (list node))
>> + ((('dir . path) . rest)
>> + ((if preordering append prepend)
>> + (list (cons 'dir path))
>> + (append-map (file-tree-traverse preordering) rest))))))
>> +
>> + (use-modules (guix build utils))
>> +
>> + (let* ((he-path (string-append (getenv "HOME") "/.guix-home"))
>> + (new-he-tmp-path (string-append he-path ".new"))
>> + (new-home (getenv "GUIX_NEW_HOME")))
>> + (symlink new-home new-he-tmp-path)
>> + (rename-file new-he-tmp-path he-path))
>> +
>> + (let* ((config-home (or (getenv "XDG_CONFIG_HOME")
>> + (string-append (getenv "HOME") "/.config")))
>> +
>> + (he-path (string-append (getenv "HOME") "/.guix-home"))
>> + (new-he-tmp-path (string-append he-path ".new"))
>
> This is a path to a transient location for the new home environment,
> correct?

Yup.

Toggle quote (5 lines)
>
> tmp-path, to me at least, evokes a place where temporary files are
> stored, contrasted to a temporary home for important files.
>

Removed tmp suffix.

Toggle quote (60 lines)
>
>> +
>> + (files-path (string-append he-path "/files"))
>> + ;; Leading dot is required, because files itself is symlink and
>> + ;; to make file-system-tree works it should be a directory.
>> + (files-dir-path (string-append files-path "/."))
>> + (new-files-path (string-append new-he-tmp-path "/files"))
>> + (new-files-dir-path (string-append files-path "/."))
>> +
>> + (home-path (getenv "HOME"))
>> + (backup-dir (string-append home-path "/"
>> + (number->string (current-time))
>> + "-guix-home-legacy-configs-backup"))
>> +
>> + (old-tree (if (file-exists? files-dir-path)
>> + ((simplify-file-tree "")
>> + (file-system-tree files-dir-path))
>> + #f))
>> + (new-tree ((simplify-file-tree "")
>> + (file-system-tree new-files-dir-path)))
>> +
>
>> + (get-source-path
>> + (lambda (path)
>> + (readlink (string-append files-path "/" path))))
>> +
>> + (get-target-path
>> + (lambda (path)
>> + (string-append home-path "/." path)))
>> +
>> + (get-backup-path
>> + (lambda (path)
>> + (string-append backup-dir "/." path)))
>> +
>> + (directory?
>> + (lambda (path)
>> + (equal? (stat:type (stat path)) 'directory)))
>> +
>> + (empty-directory?
>> + (lambda (dir)
>> + (equal? (scandir dir) '("." ".."))))
>> +
>> + (symlink-to-store?
>> + (lambda (path)
>> + (and
>> + (equal? (stat:type (lstat path)) 'symlink)
>> + (store-file-name? (readlink path)))))
>> +
>> + (backup-file
>> + (lambda (path)
>> + (mkdir-p backup-dir)
>> + (format #t "Backing up ~a..." (get-target-path path))
>> + (mkdir-p (dirname (get-backup-path path)))
>> + (rename-file (get-target-path path) (get-backup-path path))
>> + (display " done\n")))
>
> A couple of the previous lambdas could have been `define'd (as a nested
> define) instead of put in this binding form.
>

Yes, but some of them are closures and have to be in the let or deeper
in the tree, so I decided to put them all in the let.

Toggle quote (45 lines)
>
>> +
>> + (cleanup-symlinks
>> + (lambda ()
>> + (let ((to-delete ((file-tree-traverse #f) old-tree)))
>> + (display
>> + "Cleaning up symlinks from previous home-environment.\n\n")
>> + (map
>> + (match-lambda
>> + (('dir . ".")
>> + (display "Cleanup finished.\n\n"))
>> +
>> + (('dir . path)
>> + (if (and
>> + (file-exists? (get-target-path path))
>> + (directory? (get-target-path path))
>> + (empty-directory? (get-target-path path)))
>> + (begin
>> + (format #t "Removing ~a..."
>> + (get-target-path path))
>> + (rmdir (get-target-path path))
>> + (display " done\n"))
>
> I think a let-binding for (get-target-path path) would work well here.
>
>> + (format
>> + #t "Skipping ~a (not an empty directory)... done\n"
>> + (get-target-path path))))
>> +
>> + (('file . path)
>> + (when (file-exists? (get-target-path path))
>> + ;; DO NOT remove the file if it was modified
>> + ;; by user (not a symlink to the /gnu/store
>> + ;; anymore) it will be backed up later during
>> + ;; create-symlinks phase.
>
> `by user' does not add anything; Referring to modified is slightly
> confusing, as I can change the symlink to point to a different file in
> the store and it will happily be deleted at this point in time.
>
> what about:
> DO NOT remote the file if it is no longer a symblink to the store. It
> will be backed up later during the create-symlinks phase.
>

Sounds good, picked this one.

Toggle quote (77 lines)
>
>> + (if (symlink-to-store? (get-target-path path))
>> + (begin
>> + (format #t "Removing ~a..." (get-target-path path))
>> + (delete-file (get-target-path path))
>> + (display " done\n"))
>> + (format
>> + #t
>> + "Skipping ~a (not a symlink to store)... done\n"
>> + (get-target-path path))))))
>> + to-delete))))
>> +
>> + (create-symlinks
>> + (lambda ()
>> + (let ((to-create ((file-tree-traverse #t) new-tree)))
>> + (map
>> + (match-lambda
>> + (('dir . ".")
>> + (display
>> + "New symlinks to home-environment will be created soon.\n")
>> + (format
>> + #t "All conflicting files will go to ~a.\n\n" backup-dir))
>> +
>> + (('dir . path)
>> + (let ((target-path (get-target-path path)))
>> + (when (and (file-exists? target-path)
>> + (not (directory? target-path)))
>> + (backup-file path))
>> +
>> + (if (file-exists? target-path)
>> + (format
>> + #t "Skipping ~a (directory already exists)... done\n"
>> + target-path)
>> + (begin
>> + (format #t "Creating ~a..." target-path)
>> + (mkdir target-path)
>> + (display " done\n")))))
>> +
>> + (('file . path)
>> + (when (file-exists? (get-target-path path))
>> + (backup-file path))
>> + (format #t "Symlinking ~a -> ~a..."
>> + (get-target-path path) (get-source-path path))
>> + (symlink (get-source-path path) (get-target-path path))
>> + (display " done\n")))
>> + to-create)))))
>> +
>> + (when old-tree
>> + (cleanup-symlinks))
>> +
>> + (create-symlinks)
>> +
>> + (display " done\nFinished updating symlinks.\n\n")))))
>> +
>> +
>> +(define (update-symlinks-gexp _)
>> + #~(primitive-load #$(update-symlinks-script)))
>> +
>> +(define home-symlink-manager-service-type
>> + (service-type (name 'home-symlink-manager)
>> + (extensions
>> + (list
>> + (service-extension
>> + home-activation-service-type
>> + update-symlinks-gexp)))
>> + (default-value #f)
>> + (description "Provide an @code{update-symlinks}
>> +script, which create and remove symlinks on every activation. If the
> creates,removes.
>> +target is occupied by a file created by user, back it up.")))
> What is target? Why should I care as a user of this service :)?
> Perhaps rather than describing how the service does what it does, something in
> the spirit of;
>
> If an existing file would be overwritten by a symlink, back up
> the exiting file first.

Updated.

Toggle quote (11 lines)
>
>> --
>> 2.33.0
>
> A nitpick I'm much less certain about is your use of display (and
> format) without using the G_ macro; Perhaps you can try to reach out to
> the folks who are most involved with the translation effort to see if
> there is something that needs to be addressed now, of whether that can
> still easily happen at a later point?
>

Yep, it's very likely that there is a better mechanism for providing
output than display function, but I think it can be easily updated
later.

Toggle quote (3 lines)
>
> Thanks again for working on this! - Jelle

Cleaned up and updated the script.
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmEpA50ACgkQIgjSCVjB
3rBg0Q//aVX25FamMjeS5tdarecXbavq973ZQA4rsZF7I1LuXfcCWbvGlxWIk641
9SPcMCkU0zG9h4nzrW5xlCrcC2NqCZHM2iGY5wbrc5ExHMZXbiq4VCC7S3/KsrMV
NHbHgHMD/dczdiUr5AtCVoQYWFpPm3xHl4yKcIYaUZBYyiEizce2+/JII7u8pEXo
oQnCdI4B36rwjz/Yky973oDG0UnBush4Cua7fu6SfrutrPkHb292uPoczS0pIuo2
K29UPqFqDrhBZ+J+P4IerL4wC1nfCwMNjD23Y8UxwRiXsda/2wTHiaMAR9mYImMm
FRbfMWMi4Ar+goZpRaTdLaHjYN606p5w/j7bzN1uWBH0N3keLbtbNk6C+mWfd/Wi
HfBsQhbPH1hcf9BXxXumoO2JAs+jXt2+Rsp2bFbMhKDWnTG1Wc1bMfaqTL4Z74xV
kW6+dpJEWR12gOwmUSTAlM/Now1nNmDbU/KL1mDwjnnM9DuZVDmNdKfkvQX16CBp
ThSGmOPp3jjUvIfgkgMC5wMbyQ6HiwDrYSYQdCq/l1QC7a2l31NDk2a6QKEdlTs/
LOoDpXgfRNbBc4Kq6wi3+WnFForEYw6NnOZn5YmfAny5Lg6/rtCULswIsPoMcp1U
5Gab/aZGNoghHn8SXGtcNc9ApvGPl1I7dJq5XrguMZ3x7VVKc8Y=
=Y18q
-----END PGP SIGNATURE-----

Andrew Tropin wrote 4 years ago
Re: [PATCH 3/5] home-services: Add shells.
(name . Oleg Pykhalov)(address . go.wigust@gmail.com)(address . 50208@debbugs.gnu.org)
874kbadi4v.fsf@trop.in
On 2021-08-27 10:03, Andrew Tropin wrote:

Toggle quote (409 lines)
> * gnu/home-services/shells.scm
> (home-shell-profile-service-type, home-shell-profile-configuration)
> (home-bash-service-type, home-bash-configuration, home-bash-extension)
> (home-zsh-service-type, home-zsh-configuration, home-zsh-extension)
> (home-fish-service-type, home-fish-configuration, home-fish-extension): New
> variables.
> * gnu/local.mk (GNU_SYSTEM_MODULES): Add home-services/shells.scm.
> ---
> gnu/home-services/shells.scm | 637 +++++++++++++++++++++++++++++++++++
> gnu/local.mk | 1 +
> 2 files changed, 638 insertions(+)
> create mode 100644 gnu/home-services/shells.scm
>
> diff --git a/gnu/home-services/shells.scm b/gnu/home-services/shells.scm
> new file mode 100644
> index 0000000000..0643019361
> --- /dev/null
> +++ b/gnu/home-services/shells.scm
> @@ -0,0 +1,637 @@
> +;;; GNU Guix --- Functional package management for GNU
> +;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
> +;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
> +;;;
> +;;; This file is part of GNU Guix.
> +;;;
> +;;; GNU Guix is free software; you can redistribute it and/or modify it
> +;;; under the terms of the GNU General Public License as published by
> +;;; the Free Software Foundation; either version 3 of the License, or (at
> +;;; your option) any later version.
> +;;;
> +;;; GNU Guix is distributed in the hope that it will be useful, but
> +;;; WITHOUT ANY WARRANTY; without even the implied warranty of
> +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +;;; GNU General Public License for more details.
> +;;;
> +;;; You should have received a copy of the GNU General Public License
> +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
> +
> +(define-module (gnu home-services shells)
> + #:use-module (gnu services configuration)
> + #:use-module (gnu home-services configuration)
> + #:use-module (gnu home-services)
> + #:use-module (gnu packages shells)
> + #:use-module (gnu packages bash)
> + #:use-module (guix gexp)
> + #:use-module (guix packages)
> + #:use-module (srfi srfi-1)
> + #:use-module (srfi srfi-26)
> + #:use-module (ice-9 match)
> +
> + #:export (home-shell-profile-service-type
> + home-shell-profile-configuration
> +
> + home-bash-service-type
> + home-bash-configuration
> + home-bash-extension
> +
> + home-zsh-service-type
> + home-zsh-configuration
> + home-zsh-extension
> +
> + home-fish-service-type
> + home-fish-configuration
> + home-fish-extension))
> +
> +;;; Commentary:
> +;;;
> +;;; This module contains shell related services like Zsh.
> +;;;
> +;;; Code:
> +
> +
> +;;;
> +;;; Shell profile.
> +;;;
> +
> +(define path? string?)
> +(define (serialize-path field-name val) val)
> +
> +(define-configuration home-shell-profile-configuration
> + (profile
> + (text-config '())
> + "\
> +@code{home-shell-profile} is instantiated automatically by
> +@code{home-environment}, DO NOT create this service manually, it can
> +only be extended.
> +
> +@code{profile} is a list of strings or gexps, which will go to
> +@file{~/.profile}. By default @file{~/.profile} contains the
> +initialization code, which have to be evaluated by login shell to make
> +home-environment's profile avaliable to the user, but other commands
> +can be added to the file if it is really necessary.
> +
> +In most cases shell's configuration files are preferred places for
> +user's customizations. Extend home-shell-profile service only if you
> +really know what you do."))
> +
> +(define (add-shell-profile-file config)
> + `(("profile"
> + ,(mixed-text-file
> + "shell-profile"
> + "\
> +HOME_ENVIRONMENT=$HOME/.guix-home
> +. $HOME_ENVIRONMENT/setup-environment
> +$HOME_ENVIRONMENT/on-first-login\n"
> + (serialize-configuration
> + config
> + (filter-configuration-fields
> + home-shell-profile-configuration-fields '(profile)))))))
> +
> +(define (add-profile-extensions config extensions)
> + (home-shell-profile-configuration
> + (inherit config)
> + (profile
> + (append (home-shell-profile-configuration-profile config)
> + extensions))))
> +
> +(define home-shell-profile-service-type
> + (service-type (name 'home-shell-profile)
> + (extensions
> + (list (service-extension
> + home-files-service-type
> + add-shell-profile-file)))
> + (compose concatenate)
> + (extend add-profile-extensions)
> + (default-value (home-shell-profile-configuration))
> + (description "Create @file{~/.profile}, which is used
> +for environment initialization of POSIX compliant login shells. This
> +service type can be extended with a list of strings or gexps.")))
> +
> +(define (serialize-boolean field-name val) "")
> +(define (serialize-posix-env-vars field-name val)
> + #~(string-append
> + #$@(map
> + (match-lambda
> + ((key . #f)
> + "")
> + ((key . #t)
> + #~(string-append "export " #$key "\n"))
> + ((key . value)
> + #~(string-append "export " #$key "=" #$value "\n")))
> + val)))
> +
> +
> +;;;
> +;;; Zsh.
> +;;;
> +
> +(define-configuration home-zsh-configuration
> + (package
> + (package zsh)
> + "The Zsh package to use.")
> + (xdg-flavor?
> + (boolean #t)
> + "Place all the configs to @file{$XDG_CONFIG_HOME/zsh}. Makes
> +@file{~/.zshenv} to set @env{ZDOTDIR} to @file{$XDG_CONFIG_HOME/zsh}.
> +Shell startup process will continue with
> +@file{$XDG_CONFIG_HOME/zsh/.zshenv}.")
> + (environment-variables
> + (alist '())
> + "Association list of environment variables to set for the Zsh session."
> + serialize-posix-env-vars)
> + (zshenv
> + (text-config '())
> + "List of strings or gexps, which will be added to @file{.zshenv}.
> +Used for setting user's shell environment variables. Must not contain
> +commands assuming the presence of tty or producing output. Will be
> +read always. Will be read before any other file in @env{ZDOTDIR}.")
> + (zprofile
> + (text-config '())
> + "List of strings or gexps, which will be added to @file{.zprofile}.
> +Used for executing user's commands at start of login shell (In most
> +cases the shell started on tty just after login). Will be read before
> +@file{.zlogin}.")
> + (zshrc
> + (text-config '())
> + "List of strings or gexps, which will be added to @file{.zshrc}.
> +Used for executing user's commands at start of interactive shell (The
> +shell for interactive usage started by typing @code{zsh} or by
> +terminal app or any other program).")
> + (zlogin
> + (text-config '())
> + "List of strings or gexps, which will be added to @file{.zlogin}.
> +Used for executing user's commands at the end of starting process of
> +login shell.")
> + (zlogout
> + (text-config '())
> + "List of strings or gexps, which will be added to @file{.zlogout}.
> +Used for executing user's commands at the exit of login shell. It
> +won't be read in some cases (if the shell terminates by exec'ing
> +another process for example)."))
> +
> +(define (add-zsh-configuration config)
> + (let* ((xdg-flavor? (home-zsh-configuration-xdg-flavor? config)))
> +
> + (define prefix-file
> + (cut string-append
> + (if xdg-flavor?
> + "config/zsh/."
> + "") <>))
> +
> + (define (filter-fields field)
> + (filter-configuration-fields home-zsh-configuration-fields
> + (list field)))
> +
> + (define (serialize-field field)
> + (serialize-configuration
> + config
> + (filter-fields field)))
> +
> + (define (file-if-not-empty field)
> + (let ((file-name (symbol->string field))
> + (field-obj (car (filter-fields field))))
> + (if (not (null? ((configuration-field-getter field-obj) config)))
> + `(,(prefix-file file-name)
> + ,(mixed-text-file
> + file-name
> + (serialize-field field)))
> + '())))
> +
> + (filter
> + (compose not null?)
> + `(,(if xdg-flavor?
> + `("zshenv"
> + ,(mixed-text-file
> + "auxiliary-zshenv"
> + (if xdg-flavor?
> + "source ${XDG_CONFIG_HOME:-$HOME/.config}/zsh/.zshenv\n"
> + "")))
> + '())
> + (,(prefix-file "zshenv")
> + ,(mixed-text-file
> + "zshenv"
> + (if xdg-flavor?
> + "export ZDOTDIR=${XDG_CONFIG_HOME:-$HOME/.config}/zsh\n"
> + "")
> + (serialize-field 'zshenv)
> + (serialize-field 'environment-variables)))
> + (,(prefix-file "zprofile")
> + ,(mixed-text-file
> + "zprofile"
> + "\
> +# Setups system and user profiles and related variables
> +source /etc/profile
> +# Setups home environment profile
> +source ~/.profile
> +
> +# It's only necessary if zsh is a login shell, otherwise profiles will
> +# be already sourced by bash
> +"
> + (serialize-field 'zprofile)))
> +
> + ,@(list (file-if-not-empty 'zshrc)
> + (file-if-not-empty 'zlogin)
> + (file-if-not-empty 'zlogout))))))
> +
> +(define (add-zsh-packages config)
> + (list (home-zsh-configuration-package config)))
> +
> +(define-configuration/no-serialization home-zsh-extension
> + (environment-variables
> + (alist '())
> + "Association list of environment variables to set.")
> + (zshrc
> + (text-config '())
> + "List of strings or gexps.")
> + (zshenv
> + (text-config '())
> + "List of strings or gexps.")
> + (zprofile
> + (text-config '())
> + "List of strings or gexps.")
> + (zlogin
> + (text-config '())
> + "List of strings or gexps.")
> + (zlogout
> + (text-config '())
> + "List of strings or gexps."))
> +
> +(define (home-zsh-extensions original-config extension-configs)
> + (home-zsh-configuration
> + (inherit original-config)
> + (environment-variables
> + (append (home-zsh-configuration-environment-variables original-config)
> + (append-map
> + home-zsh-extension-environment-variables extension-configs)))
> + (zshrc
> + (append (home-zsh-configuration-zshrc original-config)
> + (append-map
> + home-zsh-extension-zshrc extension-configs)))
> + (zshenv
> + (append (home-zsh-configuration-zshenv original-config)
> + (append-map
> + home-zsh-extension-zshenv extension-configs)))
> + (zprofile
> + (append (home-zsh-configuration-zprofile original-config)
> + (append-map
> + home-zsh-extension-zprofile extension-configs)))
> + (zlogin
> + (append (home-zsh-configuration-zlogin original-config)
> + (append-map
> + home-zsh-extension-zlogin extension-configs)))
> + (zlogout
> + (append (home-zsh-configuration-zlogout original-config)
> + (append-map
> + home-zsh-extension-zlogout extension-configs)))))
> +
> +(define home-zsh-service-type
> + (service-type (name 'home-zsh)
> + (extensions
> + (list (service-extension
> + home-files-service-type
> + add-zsh-configuration)
> + (service-extension
> + home-profile-service-type
> + add-zsh-packages)))
> + (compose identity)
> + (extend home-zsh-extensions)
> + (default-value (home-zsh-configuration))
> + (description "Install and configure Zsh.")))
> +
> +
> +;;;
> +;;; Bash.
> +;;;
> +
> +(define-configuration home-bash-configuration
> + (package
> + (package bash)
> + "The Bash package to use.")
> + (guix-defaults?
> + (boolean #t)
> + "Add sane defaults like reading @file{/etc/bashrc}, coloring output
> +for @code{ls} provided by guix to @file{.bashrc}.")
> + (environment-variables
> + (alist '())
> + "Association list of environment variables to set for the Bash session."
> + serialize-posix-env-vars)
> + (bash-profile
> + (text-config '())
> + "List of strings or gexps, which will be added to @file{.bash_profile}.
> +Used for executing user's commands at start of login shell (In most
> +cases the shell started on tty just after login). @file{.bash_login}
> +won't be ever read, because @file{.bash_profile} always present.")
> + (bashrc
> + (text-config '())
> + "List of strings or gexps, which will be added to @file{.bashrc}.
> +Used for executing user's commands at start of interactive shell (The
> +shell for interactive usage started by typing @code{bash} or by
> +terminal app or any other program).")
> + (bash-logout
> + (text-config '())
> + "List of strings or gexps, which will be added to @file{.bash_logout}.
> +Used for executing user's commands at the exit of login shell. It
> +won't be read in some cases (if the shell terminates by exec'ing
> +another process for example)."))
> +
> +;; TODO: Use value from (gnu system shadow)
> +(define guix-bashrc
> + "\
> +# Bash initialization for interactive non-login shells and
> +# for remote shells (info \"(bash) Bash Startup Files\").
> +
> +# Export 'SHELL' to child processes. Programs such as 'screen'
> +# honor it and otherwise use /bin/sh.
> +export SHELL
> +
> +if [[ $- != *i* ]]
> +then
> + # We are being invoked from a non-interactive shell. If this
> + # is an SSH session (as in \"ssh host command\"), source
> + # /etc/profile so we get PATH and other essential variables.
> + [[ -n \"$SSH_CLIENT\" ]] && source /etc/profile
> +
> + # Don't do anything else.
> + return
> +fi
> +
> +# Source the system-wide file.
> +source /etc/bashrc
> +
> +# Adjust the prompt depending on whether we're in 'guix environment'.
> +if [ -n \"$GUIX_ENVIRONMENT\" ]
> +then
> + PS1='\\u@\\h \\w [env]\\$ '
> +else
> + PS1='\\u@\\h \\w\\$ '
> +fi
> +alias ls='ls -p --color=auto'
> +alias ll='ls -l'
> +alias grep='grep --color=auto'\n")
> +
> +(define (add-bash-configuration config)
> + (define (filter-fields field)
> + (filter-configuration-fields home-bash-configuration-fields
> + (list field)))
> +
> + (define (serialize-field field)
> + (serialize-configuration
> + config
> + (filter-fields field)))
> +
> + (define* (file-if-not-empty field #:optional (extra-content #f))
> + (let ((file-name (symbol->string field))
> + (field-obj (car (filter-fields field))))
> + (if (or extra-content
> + (not (null? ((configuration-field-getter field-obj) config))))
> + `(,(object->snake-case-string file-name)

Didn't add object->snake-case-string function to this patch series, will
add it in v2.

Toggle quote (140 lines)
> + ,(mixed-text-file
> + (object->snake-case-string file-name)
> + (if extra-content extra-content "")
> + (serialize-field field)))
> + '())))
> +
> + (filter
> + (compose not null?)
> + `(("bash_profile"
> + ,(mixed-text-file
> + "bash_profile"
> + "\
> +# Setups system and user profiles and related variables
> +# /etc/profile will be sourced by bash automatically
> +# Setups home environment profile
> +if [ -f ~/.profile ]; then source ~/.profile; fi
> +
> +# Honor per-interactive-shell startup file
> +if [ -f ~/.bashrc ]; then source ~/.bashrc; fi
> +"
> + (serialize-field 'bash-profile)
> + (serialize-field 'environment-variables)))
> +
> + ,@(list (file-if-not-empty
> + 'bashrc
> + (if (home-bash-configuration-guix-defaults? config)
> + guix-bashrc
> + #f))
> + (file-if-not-empty 'bash-logout)))))
> +
> +(define (add-bash-packages config)
> + (list (home-bash-configuration-package config)))
> +
> +(define-configuration/no-serialization home-bash-extension
> + (environment-variables
> + (alist '())
> + "Association list of environment variables to set.")
> + (bash-profile
> + (text-config '())
> + "List of strings or gexps.")
> + (bashrc
> + (text-config '())
> + "List of strings or gexps.")
> + (bash-logout
> + (text-config '())
> + "List of strings or gexps."))
> +
> +(define (home-bash-extensions original-config extension-configs)
> + (home-bash-configuration
> + (inherit original-config)
> + (environment-variables
> + (append (home-bash-configuration-environment-variables original-config)
> + (append-map
> + home-bash-extension-environment-variables extension-configs)))
> + (bash-profile
> + (append (home-bash-configuration-bash-profile original-config)
> + (append-map
> + home-bash-extension-bash-profile extension-configs)))
> + (bashrc
> + (append (home-bash-configuration-bashrc original-config)
> + (append-map
> + home-bash-extension-bashrc extension-configs)))
> + (bash-logout
> + (append (home-bash-configuration-bash-logout original-config)
> + (append-map
> + home-bash-extension-bash-logout extension-configs)))))
> +
> +(define home-bash-service-type
> + (service-type (name 'home-bash)
> + (extensions
> + (list (service-extension
> + home-files-service-type
> + add-bash-configuration)
> + (service-extension
> + home-profile-service-type
> + add-bash-packages)))
> + (compose identity)
> + (extend home-bash-extensions)
> + (default-value (home-bash-configuration))
> + (description "Install and configure GNU Bash.")))
> +
> +
> +;;;
> +;;; Fish.
> +;;;
> +
> +(define (serialize-fish-aliases field-name val)
> + #~(string-append
> + #$@(map (match-lambda
> + ((key . value)
> + #~(string-append "alias " #$key " \"" #$value "\"\n"))
> + (_ ""))
> + val)))
> +
> +(define (serialize-fish-abbreviations field-name val)
> + #~(string-append
> + #$@(map (match-lambda
> + ((key . value)
> + #~(string-append "abbr --add " #$key " " #$value "\n"))
> + (_ ""))
> + val)))
> +
> +(define (serialize-fish-env-vars field-name val)
> + #~(string-append
> + #$@(map (match-lambda
> + ((key . #f)
> + "")
> + ((key . #t)
> + #~(string-append "set " #$key "\n"))
> + ((key . value)
> + #~(string-append "set " #$key " " #$value "\n")))
> + val)))
> +
> +(define-configuration home-fish-configuration
> + (package
> + (package fish)
> + "The Fish package to use.")
> + (config
> + (text-config '())
> + "List of strings or gexps, which will be added to
> +@file{$XDG_CONFIG_HOME/fish/config.fish}.")
> + (environment-variables
> + (alist '())
> + "Association list of environment variables to set in Fish."
> + serialize-fish-env-vars)
> + (aliases
> + (alist '())
> + "Association list of aliases for Fish, both the key and the value
> +should be a string. An alias is just a simple function that wraps a
> +command, If you want something more akin to @dfn{aliases} in POSIX
> +shells, see the @code{abbreviations} field."
> + serialize-fish-aliases)
> + (abbreviations
> + (alist '())
> + "Association list of abbreviations for Fish. These are words that,
> +when typed in the shell, will automatically expand to the full text."
> + serialize-fish-abbreviations))
> +
> +(define (fish-files-service config)
> + `(("config/fish/confi
This message was truncated. Download the full message here.
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmEpA/AACgkQIgjSCVjB
3rCWLg//TNp7Axgv68YStSS6kPMqM1lk8rvyw8Fwge4xQayHMvCbWt9gO2FV6uH9
5uZa6kV0FIKFfE5FpiJujkwkBELR33mWfPEWMhLSS9tZnXsCoSJ/jT1yULqTt75Z
QRvn1r8xZESqimUu3MU7lLrwcqFfd+VfKIWWiFjTl2dORXtsEl/pnuqJsN0wOOpp
wSpYFbr18qY319gSXJG8vUeNgx1bdQFGlLDTr6z+bQCzU63HGoXP5GJGw5K1Mg21
hMVQKdqoUuGUqKuBri45JpMjGPFBYuZkOyObS6LNEDPPsYHfN2X4gPGouuKDdPWJ
NlvCNeAK9Z7bpUYzBCkGua7N/VZfQVn51gD21PMzthmNNKKxPz+TkQjuXpCDjPJw
XKMmvOgn9yfr1jotIiH1M0z8Lvynj+XPXuV8NC+6hyZ4pqn0a4AzbnvYG2klpkN+
lV6+95UhvWRgrXXYbZRR/McEHC2sNAjrflVGNaIW1wL/daCaqZFw31Qenxf5k8sw
2FuR86fRqdprjaUpZUNxebTgf5cNwTR7+SCogk2GPz+a9NeO0jIASE/x07VA4YS8
msIR+J5vYPvA+W9UR8pvz0eqtNF3mvYmRhjmB22iDwbhY5AVsXVSXJ2xWtzrtdgC
GufLG2ZapTi48ppVPn/l5hLU35uLlSFd0WjIexG8nv0F9nVo3P0=
=fRhY
-----END PGP SIGNATURE-----

Andrew Tropin wrote 4 years ago
Re: [PATCH 0/5] Add home-environment and related services
(name . Oleg Pykhalov)(address . go.wigust@gmail.com)(address . 50208@debbugs.gnu.org)
871r6edi0h.fsf@trop.in
On 2021-08-27 09:49, Andrew Tropin wrote:

Toggle quote (37 lines)
> On 2021-08-26 13:58, Oleg Pykhalov wrote:
>
>> I applied your patch, replaces tabs with spaces, modified commit message
>> according to GNU standards, added the file to gnu/local.mk for
>> compilation (I forgot to do it for previous patch series, apologies).
>>
>>
>> I would like to squash the patch for home-services.scm with a previous
>> series (hope force push will work), but I should ask you could I do it?
>> Otherwise I could just push two patches to wip-guix-home.
>>
>> Updated patches are attached below.
>
> On top of the patches above I made a new patch series, which introduces
> home-environment and a set of default services, which are expected to be
> present in most Guix Home configurations.
>
> Andrew Tropin (5):
> home-services: Add fontutils.
> home-services: Add helper functions for service configurations.
> home-services: Add shells.
> home-services: Add xdg.
> home: Add home-environment.
>
> gnu/home-services/configuration.scm | 63 +++
> gnu/home-services/fontutils.scm | 65 +++
> gnu/home-services/shells.scm | 637 ++++++++++++++++++++++++++++
> gnu/home-services/xdg.scm | 475 +++++++++++++++++++++
> gnu/home.scm | 97 +++++
> gnu/local.mk | 5 +
> 6 files changed, 1342 insertions(+)
> create mode 100644 gnu/home-services/configuration.scm
> create mode 100644 gnu/home-services/fontutils.scm
> create mode 100644 gnu/home-services/shells.scm
> create mode 100644 gnu/home-services/xdg.scm
> create mode 100644 gnu/home.scm

Is it ok to keep discussion and review of the patch series in this
thread or better create a new ticket for that?

I posted it here, because it relies on symlink-manager, but not sure if
it's handy for reviewers.
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmEpBI8ACgkQIgjSCVjB
3rBJKw/5ATNrX8qzWxeEY3KoU9gw41VECGTgJ5mx6iZ7HZU0H65mlgXc8jjxBWq6
pdxL1s8zwM917FaPV7iQrRPqOwwJVyzhIOIgZdL+F6ChHw5FXQcu/2jjffZ3CgvV
59wF1uEcOQhAiNr38AK1Ow0YME4NwP6rH0dcKq/MwwJ2RoATVzXuGBOSiDZ9gkxm
fDMAi+v4z3LQas5F9nqbje6ZBj/4RGw3arGKfIH1K3FZN+tEg2hcmWhfe/NGC/DV
e9SbWoXEtnlYVvyGPSQ31MAAlmuVD1AfY5H6o8Ln+6u61lGdel0JXAWVBEn/DsHw
Oz98HQo6PrCYP3n7/O6Hv+PUrYwUV04TlcH9QA0+6lBWZtSl4r3rTKQlH6C7JUry
ZuHhd1QW5Fow64KL+mUvfgTIobvRIwDS33m96DO5l2c78Wxam+8M/hrgzyyCB+rp
t/8727wylEFtrWZT7aQdQZl+k3sILFR0j0Dai17LXUjU9CSY/ckTl4b8ixw6a+LH
q1R2ylPhAEsvEgP6P5QAUvAPo/E7ZQIyWUY5Wq9hcYM5pGR0T9HwBFJnpqlP9H1d
zMfp+Ozdz6GtpL+/SGw9stFIlpEZG2GFJo+7R/SYncCuJPukQMKs+v4+cf6+zDSo
ar5849E9OWTHyMMM9ftu8v+7VPB1r66cRazpxbkE2FHzRvBlzrY=
=KF4c
-----END PGP SIGNATURE-----

Oleg Pykhalov wrote 4 years ago
(name . Andrew Tropin)(address . andrew@trop.in)(address . 50208-done@debbugs.gnu.org)
87v93q3dix.fsf@gmail.com
Andrew Tropin <andrew@trop.in> writes:

[…]

Toggle quote (4 lines)
>> On top of the patches above I made a new patch series, which introduces
>> home-environment and a set of default services, which are expected to be
>> present in most Guix Home configurations.

I added a copyright in gnu/home-services/configuration.scm and a
copyright line in gnu/local.mk files.

From gnu/home-services/shells.scm removed 3 comment lines at the bottom,
because I don't see this practice in other Guix documentation generation
functions:
Toggle snippet (5 lines)
;; (display (generate-home-shell-profile-documentation))
;; (display (generate-home-bash-documentation))
;; (display (generate-home-zsh-documentation))

In gnu/home.scm and gnu/home-services/xdg.scm alligned
define-record-type* with Emacs's ‘M-x aggressive-indent-mode’ and
‘M-x align-regexp’ <SPC ;>.

Unfortunately force push is disallowed, removed origin/wip-guix-home and
pushed again with squashed local.mk and slightly modified commit
messages (missing dots at the commit messages).

[…]

Toggle quote (6 lines)
> Is it ok to keep discussion and review of the patch series in this
> thread or better create a new ticket for that?
>
> I posted it here, because it relies on symlink-manager, but not sure if
> it's handy for reviewers.

I think it's OK to keep discussion here, because every patch is a part
of guix-home. Not a strong opinion on that.

I'll close the issue for now, it should reopen in case you send an email
to 50208@debbugs.gnu.org

Oleg.
-----BEGIN PGP SIGNATURE-----

iQJIBAEBCgAyFiEEcjhxI46s62NFSFhXFn+OpQAa+pwFAmEpOcYUHGdvLndpZ3Vz
dEBnbWFpbC5jb20ACgkQFn+OpQAa+pzGRRAAskrX3YGeDq8HY1OFKuDVhJpHMcIe
jRo/7s51OvkZXPLyrsC579N+Z27wiFD4clOnq6f03hEuftqnS1hv+y/SXclQxRjJ
t+X7Ym2f5yzplJg6BNp3ZS/HdfTweDMVxaHvRpyNX3OadUWdCkr1NwkT/P4QC7Uv
MiiDBerNsfxHQlmlcdiP3OWhYGVwJGgYUDq6E9P6ALOrLG+hX1t4S8+1PdEL80ye
EF7380GtnhaBNrJsAWWHqR+YfFDcxCIB3jGodd7mHS2Ff59XL+TTkjm2B29JgaAO
p/012FhODHcZmHUpl5+IEp2XmN2lujB2izc5oJISolWvC8FxgcWuSxCq/RsTTxqg
VI5JRyrO2sOlmzggwBL0x+GaExRhTNwPjKCZYlftxD+XQN1jVDovA3H2H73PPE0C
T1FgaPPe7bNo39HvBB5H7Tyt5boNhu8ghXRrFjXcZAUVikPFVc/rDptK1i/B7yCK
Alj2BntsfwxALdU9XGzfq0rLUb3cxqBM/z4bpIABv0xcfGW81cwfo2f6FA6cHRts
/9qJWauZO9WTocqpQuhGWPL09VLckxtUYWnJ06os1MyNY6e9JIMQFuIag57UIR4j
c4oJiFS621pItki9lr6TkTaoruuAOseWfcopANgHRhs6XzDBpP4MWoaCd91/Knu4
WQPYa0c0UV95dck=
=XxgN
-----END PGP SIGNATURE-----

Closed
Xinglu Chen wrote 4 years ago
Re: [bug#50208] [PATCH 5/5] home: Add home-environment.
(address . 50208@debbugs.gnu.org)
87mtp1vofg.fsf@yoctocell.xyz
On Fri, Aug 27 2021, Andrew Tropin wrote:

Toggle quote (59 lines)
> * gnu/home.scm
> (home-environment, home-environment?, this-home-environment)
> (home-environment-derivation, home-environment-user-services)
> (home-environment-essential-services, home-environment-services)
> (home-environment-location, home-environment-with-provenance): New variables.
> * gnu/local.mk (GNU_SYSTEM_MODULES): Add home.scm.
> ---
> gnu/home.scm | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> gnu/local.mk | 1 +
> 2 files changed, 98 insertions(+)
> create mode 100644 gnu/home.scm
>
> diff --git a/gnu/home.scm b/gnu/home.scm
> new file mode 100644
> index 0000000000..220cc49846
> --- /dev/null
> +++ b/gnu/home.scm
> @@ -0,0 +1,97 @@
> +;;; GNU Guix --- Functional package management for GNU
> +;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
> +;;;
> +;;; This file is part of GNU Guix.
> +;;;
> +;;; GNU Guix is free software; you can redistribute it and/or modify it
> +;;; under the terms of the GNU General Public License as published by
> +;;; the Free Software Foundation; either version 3 of the License, or (at
> +;;; your option) any later version.
> +;;;
> +;;; GNU Guix is distributed in the hope that it will be useful, but
> +;;; WITHOUT ANY WARRANTY; without even the implied warranty of
> +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +;;; GNU General Public License for more details.
> +;;;
> +;;; You should have received a copy of the GNU General Public License
> +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
> +
> +(define-module (gnu home)
> + #:use-module (gnu home-services)
> + #:use-module (gnu home-services symlink-manager)
> + #:use-module (gnu home-services shells)
> + #:use-module (gnu home-services xdg)
> + #:use-module (gnu home-services fontutils)
> + #:use-module (gnu services)
> + #:use-module (guix records)
> + #:use-module (guix diagnostics)
> +
> + #:export (home-environment
> + home-environment?
> + this-home-environment
> +
> + home-environment-derivation
> + home-environment-user-services
> + home-environment-essential-services
> + home-environment-services
> + home-environment-location
> +
> + home-environment-with-provenance))
> +

It should probably have a ‘Commentary’ section. Maybe something like

This module provides a <home-environment> record for managing per-user
packages and 'dotfiles'.

?
-----BEGIN PGP SIGNATURE-----

iQJJBAEBCAAzFiEEAVhh4yyK5+SEykIzrPUJmaL7XHkFAmEqE5MVHHB1YmxpY0B5
b2N0b2NlbGwueHl6AAoJEKz1CZmi+1x53NUP/Rnxqd2dNrpbH9oKQBtLm7IyXVSW
HugeTcYq0u4k5xW9Qm3mUg8hg4TnBuXsRMji18Q+Gx/lS0SMmqgKIyg0AyBXIzaS
WWVK6sGaDWv1SnmmbOYsKdNVTBJCssFk4F5w8Esy2vxRR7CT6XaVaoQKZAka4vHB
4VXwP9iXPmZgL4+Tcee26DGBnxOAH+M23Sax98Tw7ieKd6VWuVRUGx21MwdHYaA1
hcPlUzmJqhZVuoXHpilZwXM01bNNVlnm83g/kulz/UGIC26k+v7sIWcCkj6CEL9B
HOcfBVJr9MpljYglrQabz31AYwuyXOTr/B/MfYkST7JhT9BxBcDYwd75RfcS+POI
aW/YaXL4RmTRJ6fb5mabNDuxKxhbAF1VYL9gxtT1o5oa/5vrX/Gvt8KXObkn+q9C
amI3SRl6ABrGCEgM7LnAxpsG1y8fvLPJzMpxrQ2LV/Ww5ipy1nymopY2yiooOPaz
AK+GyUpKUzULcwQ7bRPYxpWtg3++f3snBAQUryKwMVilVVpbcR3RS0sCvqopO2t8
caoijQvJRSalamydhOShCvq4Dzc2/KIfZgoH4934gY05th/pSQFH0ke3ERh68kly
VyL5h8zIquVEJ9/hHJkMjyQMEn7Ezd/Fv6LXJ0T9st4k0Mz0Li+S3dl6qGSZPPgq
lZjZMeXQP3D/SqWu
=A+CL
-----END PGP SIGNATURE-----

Andrew Tropin wrote 4 years ago
(address . 50208@debbugs.gnu.org)
87ilzn8fhy.fsf@trop.in
On 2021-08-28 12:44, Xinglu Chen wrote:

Toggle quote (68 lines)
> On Fri, Aug 27 2021, Andrew Tropin wrote:
>
>> * gnu/home.scm
>> (home-environment, home-environment?, this-home-environment)
>> (home-environment-derivation, home-environment-user-services)
>> (home-environment-essential-services, home-environment-services)
>> (home-environment-location, home-environment-with-provenance): New variables.
>> * gnu/local.mk (GNU_SYSTEM_MODULES): Add home.scm.
>> ---
>> gnu/home.scm | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>> gnu/local.mk | 1 +
>> 2 files changed, 98 insertions(+)
>> create mode 100644 gnu/home.scm
>>
>> diff --git a/gnu/home.scm b/gnu/home.scm
>> new file mode 100644
>> index 0000000000..220cc49846
>> --- /dev/null
>> +++ b/gnu/home.scm
>> @@ -0,0 +1,97 @@
>> +;;; GNU Guix --- Functional package management for GNU
>> +;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
>> +;;;
>> +;;; This file is part of GNU Guix.
>> +;;;
>> +;;; GNU Guix is free software; you can redistribute it and/or modify it
>> +;;; under the terms of the GNU General Public License as published by
>> +;;; the Free Software Foundation; either version 3 of the License, or (at
>> +;;; your option) any later version.
>> +;;;
>> +;;; GNU Guix is distributed in the hope that it will be useful, but
>> +;;; WITHOUT ANY WARRANTY; without even the implied warranty of
>> +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> +;;; GNU General Public License for more details.
>> +;;;
>> +;;; You should have received a copy of the GNU General Public License
>> +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
>> +
>> +(define-module (gnu home)
>> + #:use-module (gnu home-services)
>> + #:use-module (gnu home-services symlink-manager)
>> + #:use-module (gnu home-services shells)
>> + #:use-module (gnu home-services xdg)
>> + #:use-module (gnu home-services fontutils)
>> + #:use-module (gnu services)
>> + #:use-module (guix records)
>> + #:use-module (guix diagnostics)
>> +
>> + #:export (home-environment
>> + home-environment?
>> + this-home-environment
>> +
>> + home-environment-derivation
>> + home-environment-user-services
>> + home-environment-essential-services
>> + home-environment-services
>> + home-environment-location
>> +
>> + home-environment-with-provenance))
>> +
>
> It should probably have a ‘Commentary’ section. Maybe something like
>
> This module provides a <home-environment> record for managing per-user
> packages and 'dotfiles'.
>
> ?

Thank you for the idea, added a doc comment.
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmEsoIkACgkQIgjSCVjB
3rBoqA//Y0gUiBWtPlkfS/ph39Ul3oNM4vBZ1OTRn5tXhpA6zNHIfWMPV1LYNZpN
U4SGYg0cnM2WcxQHNocWs676HjP99IQLglqDEcOQbsbSPSg1reT9AJlN0wYo1wZq
eYAmLjluvcoDMTa7OX0kPDp8+DMG/gFyy5L6LlY+vYxPyA2ricRmSuyNsIq+On9w
iQktMKompWz1S5EsgQ3Ig1an46jxbxBSxhThl0w9DDaYyKbecgYS595YrEjYhcbp
dlxwFxEyqPdOnWVJvVUc0nahlsKxaUnjwUvXUTGynNTBZqn1nyZxo+dJjSOrFY0g
7IWCMhK2gUGEpmLGJz9zZDWTDwKFlpICAaxQAg1NU0dJ+zx0XTIPxylnNt5iFcUs
pYgTV+RYtOs+M80m7KOYhlIjPK75Z0ou41O+xlLBFPJcLnefLbRsl70T67owS6ne
GMagPtDr5rsAp8YiQYNLmUFBpmaQkUnFfuoj74L4h8ZwI4StLsXVbn79LmysXUBl
CdyXZZ449zJTjT13C/QEFgTogCuh3lmaza9y9Pz/MD15TVc+qMVA3qp7uZ5mh0EK
LLXMb2eZRzmJmSHoJAfit/+Kz6yJPFYknlu//aGWFKcuOFL/i68JkeN3AJroTCBA
lAI18sXHamXhlxaPtU410V7+NzBNazehHc5Wso73rf9W4ZUQoPY=
=SG8Z
-----END PGP SIGNATURE-----

Andrew Tropin wrote 4 years ago
[PATCH 0/4] Fixes and improvements for home-services
(name . Oleg Pykhalov)(address . go.wigust@gmail.com)(address . 50208@debbugs.gnu.org)
87fsur8e4q.fsf@trop.in
There are a few follow up patches for the current wip-guix-home branch:
- Add utils ns with helpers for converting cases, which was missing.
- Fix issue with creating first home-environment generation.
- Add support to activation script for multiline values for environment
variables.
- Add a doc comment.

The patches are attached to this messages.

Andrew Tropin (4):
home-services: Add utils module.
home-services: symlink-manager: Properly handle 1st generation case
home-services: activation: Add support for multiline env vars
gnu: home: Add doc comment about the module

gnu/home-services.scm | 4 +-
gnu/home-services/shells.scm | 1 +
gnu/home-services/symlink-manager.scm | 2 +-
gnu/home-services/utils.scm | 77 +++++++++++++++++++++++++++
gnu/home.scm | 8 +++
5 files changed, 89 insertions(+), 3 deletions(-)
create mode 100644 gnu/home-services/utils.scm

--
2.33.0
From 93ae498296b37e5b21b6a824d090b0898b870a39 Mon Sep 17 00:00:00 2001
From: Andrew Tropin <andrew@trop.in>
Date: Mon, 30 Aug 2021 12:17:11 +0300
Subject: [PATCH 1/4] home-services: Add utils module.

* gnu/home-services/utils.scm (maybe-object->string object->snake-case-string)
(object->snake-case-string): New variables.
---
gnu/home-services/shells.scm | 1 +
gnu/home-services/utils.scm | 77 ++++++++++++++++++++++++++++++++++++
2 files changed, 78 insertions(+)
create mode 100644 gnu/home-services/utils.scm

Toggle diff (97 lines)
diff --git a/gnu/home-services/shells.scm b/gnu/home-services/shells.scm
index b8065d28d2..ecb02098f7 100644
--- a/gnu/home-services/shells.scm
+++ b/gnu/home-services/shells.scm
@@ -20,6 +20,7 @@
(define-module (gnu home-services shells)
#:use-module (gnu services configuration)
#:use-module (gnu home-services configuration)
+ #:use-module (gnu home-services utils)
#:use-module (gnu home-services)
#:use-module (gnu packages shells)
#:use-module (gnu packages bash)
diff --git a/gnu/home-services/utils.scm b/gnu/home-services/utils.scm
new file mode 100644
index 0000000000..3e490a0515
--- /dev/null
+++ b/gnu/home-services/utils.scm
@@ -0,0 +1,77 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
+;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu home-services utils)
+ #:use-module (ice-9 string-fun)
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-26)
+
+ #:export (maybe-object->string
+ object->snake-case-string
+ object->camel-case-string))
+
+(define (maybe-object->string object)
+ "Like @code{object->string} but don't do anyting if OBJECT already is
+a string."
+ (if (string? object)
+ object
+ (object->string object)))
+
+;; Snake case: <https://en.wikipedia.org/wiki/Snake_case>
+(define* (object->snake-case-string object #:optional (style 'lower))
+ "Convert the object OBJECT to the equivalent string in ``snake
+case''. STYLE can be three `@code{lower}', `@code{upper}', or
+`@code{capitalize}', defaults to `@code{lower}'.
+
+@example
+(object->snake-case-string 'variable-name 'upper)
+@result{} \"VARIABLE_NAME\" @end example"
+ (if (not (member style '(lower upper capitalize)))
+ (error 'invalid-style (format #f "~a is not a valid style" style))
+ (let ((stringified (maybe-object->string object)))
+ (string-replace-substring
+ (cond
+ ((equal? style 'lower) stringified)
+ ((equal? style 'upper) (string-upcase stringified))
+ (else (string-capitalize stringified)))
+ "-" "_"))))
+
+(define* (object->camel-case-string object #:optional (style 'lower))
+ "Convert the object OBJECT to the equivalent string in ``camel case''.
+STYLE can be three `@code{lower}', `@code{upper}', defaults to
+`@code{lower}'.
+
+@example
+(object->camel-case-string 'variable-name 'upper)
+@result{} \"VariableName\"
+@end example"
+ (if (not (member style '(lower upper)))
+ (error 'invalid-style (format #f "~a is not a valid style" style))
+ (let ((stringified (maybe-object->string object)))
+ (cond
+ ((eq? style 'upper)
+ (string-concatenate
+ (map string-capitalize
+ (string-split stringified (cut eqv? <> #\-)))))
+ ((eq? style 'lower)
+ (let ((splitted-string (string-split stringified (cut eqv? <> #\-))))
+ (string-concatenate
+ (cons (first splitted-string)
+ (map string-capitalize
+ (cdr splitted-string))))))))))
--
2.33.0
From eebdfd72d2e20b18154f66fc0f84c723340e3b5f Mon Sep 17 00:00:00 2001
From: Andrew Tropin <andrew@trop.in>
Date: Mon, 30 Aug 2021 12:23:48 +0300
Subject: [PATCH 2/4] home-services: symlink-manager: Properly handle 1st
generation case

---
gnu/home-services/symlink-manager.scm | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

Toggle diff (15 lines)
diff --git a/gnu/home-services/symlink-manager.scm b/gnu/home-services/symlink-manager.scm
index dc409d2ae2..11f5d503d4 100644
--- a/gnu/home-services/symlink-manager.scm
+++ b/gnu/home-services/symlink-manager.scm
@@ -102,7 +102,7 @@ appear only after all nested items already listed."
(number->string (current-time))
"-guix-home-legacy-configs-backup"))
- (old-tree (if (file-exists? old-home)
+ (old-tree (if old-home
((simplify-file-tree "")
(file-system-tree
(string-append old-home "/files/.")))
--
2.33.0
From 25f61084e11fccc50dc1fbec3b28e7dea091e625 Mon Sep 17 00:00:00 2001
From: Andrew Tropin <andrew@trop.in>
Date: Mon, 30 Aug 2021 12:26:19 +0300
Subject: [PATCH 3/4] home-services: activation: Add support for multiline env
vars

---
gnu/home-services.scm | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

Toggle diff (24 lines)
diff --git a/gnu/home-services.scm b/gnu/home-services.scm
index 16b9736d64..2a773496f0 100644
--- a/gnu/home-services.scm
+++ b/gnu/home-services.scm
@@ -324,7 +324,7 @@ extended with one gexp.")))
#f))))
(if (file-exists? (he-init-file new-home))
(let* ((port ((@ (ice-9 popen) open-input-pipe)
- (format #f "source ~a && env"
+ (format #f "source ~a && env -0"
(he-init-file new-home))))
(result ((@ (ice-9 rdelim) read-delimited) "" port))
(vars (map (lambda (x)
@@ -333,7 +333,7 @@ extended with one gexp.")))
(string-drop x (1+ si)))))
((@ (srfi srfi-1) remove)
string-null?
- (string-split result #\newline)))))
+ (string-split result #\nul)))))
(close-port port)
(map (lambda (x) (setenv (car x) (cdr x))) vars)
--
2.33.0
From ec05edf310609dd1424ce7bfdcaaf6758a77fe29 Mon Sep 17 00:00:00 2001
From: Andrew Tropin <andrew@trop.in>
Date: Mon, 30 Aug 2021 12:07:48 +0300
Subject: [PATCH 4/4] gnu: home: Add doc comment about the module

---
gnu/home.scm | 8 ++++++++
1 file changed, 8 insertions(+)

Toggle diff (21 lines)
diff --git a/gnu/home.scm b/gnu/home.scm
index a53d27163d..f4c9359e25 100644
--- a/gnu/home.scm
+++ b/gnu/home.scm
@@ -38,6 +38,14 @@
home-environment-with-provenance))
+;;; Comment:
+;;;
+;;; This module provides a <home-environment> record for managing
+;;; per-user packages and configuration files in the similar way as
+;;; <operating-system> do for system packages and configuration files.
+;;;
+;;; Code:
+
(define-record-type* <home-environment> home-environment
make-home-environment
home-environment?
--
2.33.0
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmEsp3UACgkQIgjSCVjB
3rA/mw/8CNlwof5gj8DibO8CBvGN41PfNIgQh6K0388kXws+l0YkKtiqfe4U4S3L
5cvLCxuNmqra/jf2i9qYCOxokN1fkyJz1oBdJLkP7bKmuji3fj1VbbPka338xc2U
B3h0ZmpJ3Ednzr/tCMdMA2Kx4XqYyktNPiLb65KOiVyHanuzvNag+kuw+js2c8wo
BRArfkslYeq3mNeHbKE8XuItujeYTwgLnddgdtpFdWpl46U7TS3Md1uaCs+Od4cP
PX1cN5XVX8lVWBdQ+1gbZyVZipMTYvREOAVNXXbWVETaektC1moGI7DAn42WtDu1
eo95Fd2Ke4fImnopS4rE9/qEBvexF04/7yR/fAz3kPCVVb4KEHTm57ez7tjDFF3f
OWU2UlVxfL4Mq1Xe8raQsifFfpQRSUHHaM+Bg+L/f9DpU88bdbEh1kRbQO1ih/zU
P/SAChAhDQw9i8vagZiJn1Q4rSITRJdljlqDPa1yxRp7/JV0QH7F1yb8AQbFF1c/
lxh79BI26EEOpL9QH9V62S9ChtMnN4EeLbadPtyzjh08mBnlAnb/7B5QjKB+XqBd
WVM9r0yuOmYw+WJNxgmty28mfwfwYsKpcAvFtGdmT2BVDtAzIfYIzZA9PKRfy9da
B09Pyvn+0MqhybjNguV7ns2SKfQJOyRKm9iD4BxPjYNH6BlRBao=
=0AqG
-----END PGP SIGNATURE-----

Andrew Tropin wrote 4 years ago
[PATCH v2 0/5] Fixes and improvements for home-services
(name . Oleg Pykhalov)(address . go.wigust@gmail.com)(address . 50208@debbugs.gnu.org)
87czpv8bw5.fsf@trop.in
Changes since v1:
Added missing import to xdg via a separate commit.
Added trailing dots to commit messages.

Andrew Tropin (5):
home-services: Add utils module.
home-services: symlink-manager: Properly handle 1st generation case.
home-services: activation: Add support for multiline env vars.
gnu: home: Add doc comment about the module.
home-services: xdg: Add missing import.

gnu/home-services.scm | 4 +-
gnu/home-services/shells.scm | 1 +
gnu/home-services/symlink-manager.scm | 2 +-
gnu/home-services/utils.scm | 77 +++++++++++++++++++++++++++
gnu/home-services/xdg.scm | 1 +
gnu/home.scm | 8 +++
6 files changed, 90 insertions(+), 3 deletions(-)
create mode 100644 gnu/home-services/utils.scm

--
2.33.0
From 93ae498296b37e5b21b6a824d090b0898b870a39 Mon Sep 17 00:00:00 2001
From: Andrew Tropin <andrew@trop.in>
Date: Mon, 30 Aug 2021 12:17:11 +0300
Subject: [PATCH v2 1/5] home-services: Add utils module.

* gnu/home-services/utils.scm (maybe-object->string object->snake-case-string)
(object->snake-case-string): New variables.
---
gnu/home-services/shells.scm | 1 +
gnu/home-services/utils.scm | 77 ++++++++++++++++++++++++++++++++++++
2 files changed, 78 insertions(+)
create mode 100644 gnu/home-services/utils.scm

Toggle diff (97 lines)
diff --git a/gnu/home-services/shells.scm b/gnu/home-services/shells.scm
index b8065d28d2..ecb02098f7 100644
--- a/gnu/home-services/shells.scm
+++ b/gnu/home-services/shells.scm
@@ -20,6 +20,7 @@
(define-module (gnu home-services shells)
#:use-module (gnu services configuration)
#:use-module (gnu home-services configuration)
+ #:use-module (gnu home-services utils)
#:use-module (gnu home-services)
#:use-module (gnu packages shells)
#:use-module (gnu packages bash)
diff --git a/gnu/home-services/utils.scm b/gnu/home-services/utils.scm
new file mode 100644
index 0000000000..3e490a0515
--- /dev/null
+++ b/gnu/home-services/utils.scm
@@ -0,0 +1,77 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
+;;; Copyright © 2021 Andrew Tropin <andrew@trop.in>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu home-services utils)
+ #:use-module (ice-9 string-fun)
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-26)
+
+ #:export (maybe-object->string
+ object->snake-case-string
+ object->camel-case-string))
+
+(define (maybe-object->string object)
+ "Like @code{object->string} but don't do anyting if OBJECT already is
+a string."
+ (if (string? object)
+ object
+ (object->string object)))
+
+;; Snake case: <https://en.wikipedia.org/wiki/Snake_case>
+(define* (object->snake-case-string object #:optional (style 'lower))
+ "Convert the object OBJECT to the equivalent string in ``snake
+case''. STYLE can be three `@code{lower}', `@code{upper}', or
+`@code{capitalize}', defaults to `@code{lower}'.
+
+@example
+(object->snake-case-string 'variable-name 'upper)
+@result{} \"VARIABLE_NAME\" @end example"
+ (if (not (member style '(lower upper capitalize)))
+ (error 'invalid-style (format #f "~a is not a valid style" style))
+ (let ((stringified (maybe-object->string object)))
+ (string-replace-substring
+ (cond
+ ((equal? style 'lower) stringified)
+ ((equal? style 'upper) (string-upcase stringified))
+ (else (string-capitalize stringified)))
+ "-" "_"))))
+
+(define* (object->camel-case-string object #:optional (style 'lower))
+ "Convert the object OBJECT to the equivalent string in ``camel case''.
+STYLE can be three `@code{lower}', `@code{upper}', defaults to
+`@code{lower}'.
+
+@example
+(object->camel-case-string 'variable-name 'upper)
+@result{} \"VariableName\"
+@end example"
+ (if (not (member style '(lower upper)))
+ (error 'invalid-style (format #f "~a is not a valid style" style))
+ (let ((stringified (maybe-object->string object)))
+ (cond
+ ((eq? style 'upper)
+ (string-concatenate
+ (map string-capitalize
+ (string-split stringified (cut eqv? <> #\-)))))
+ ((eq? style 'lower)
+ (let ((splitted-string (string-split stringified (cut eqv? <> #\-))))
+ (string-concatenate
+ (cons (first splitted-string)
+ (map string-capitalize
+ (cdr splitted-string))))))))))
--
2.33.0
From 710a4983790ecdae7aa53acb5361669b6061e551 Mon Sep 17 00:00:00 2001
From: Andrew Tropin <andrew@trop.in>
Date: Mon, 30 Aug 2021 12:23:48 +0300
Subject: [PATCH v2 2/5] home-services: symlink-manager: Properly handle 1st
generation case.

---
gnu/home-services/symlink-manager.scm | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

Toggle diff (15 lines)
diff --git a/gnu/home-services/symlink-manager.scm b/gnu/home-services/symlink-manager.scm
index dc409d2ae2..11f5d503d4 100644
--- a/gnu/home-services/symlink-manager.scm
+++ b/gnu/home-services/symlink-manager.scm
@@ -102,7 +102,7 @@ appear only after all nested items already listed."
(number->string (current-time))
"-guix-home-legacy-configs-backup"))
- (old-tree (if (file-exists? old-home)
+ (old-tree (if old-home
((simplify-file-tree "")
(file-system-tree
(string-append old-home "/files/.")))
--
2.33.0
From 78b9527c368549af63d8fb987d7f9ce3e472d6ae Mon Sep 17 00:00:00 2001
From: Andrew Tropin <andrew@trop.in>
Date: Mon, 30 Aug 2021 12:26:19 +0300
Subject: [PATCH v2 3/5] home-services: activation: Add support for multiline
env vars.

---
gnu/home-services.scm | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

Toggle diff (24 lines)
diff --git a/gnu/home-services.scm b/gnu/home-services.scm
index 16b9736d64..2a773496f0 100644
--- a/gnu/home-services.scm
+++ b/gnu/home-services.scm
@@ -324,7 +324,7 @@ extended with one gexp.")))
#f))))
(if (file-exists? (he-init-file new-home))
(let* ((port ((@ (ice-9 popen) open-input-pipe)
- (format #f "source ~a && env"
+ (format #f "source ~a && env -0"
(he-init-file new-home))))
(result ((@ (ice-9 rdelim) read-delimited) "" port))
(vars (map (lambda (x)
@@ -333,7 +333,7 @@ extended with one gexp.")))
(string-drop x (1+ si)))))
((@ (srfi srfi-1) remove)
string-null?
- (string-split result #\newline)))))
+ (string-split result #\nul)))))
(close-port port)
(map (lambda (x) (setenv (car x) (cdr x))) vars)
--
2.33.0
From e2257d5b134a52b67a2e4b3b1e95b73eef975401 Mon Sep 17 00:00:00 2001
From: Andrew Tropin <andrew@trop.in>
Date: Mon, 30 Aug 2021 12:07:48 +0300
Subject: [PATCH v2 4/5] gnu: home: Add doc comment about the module.

---
gnu/home.scm | 8 ++++++++
1 file changed, 8 insertions(+)

Toggle diff (21 lines)
diff --git a/gnu/home.scm b/gnu/home.scm
index a53d27163d..f4c9359e25 100644
--- a/gnu/home.scm
+++ b/gnu/home.scm
@@ -38,6 +38,14 @@
home-environment-with-provenance))
+;;; Comment:
+;;;
+;;; This module provides a <home-environment> record for managing
+;;; per-user packages and configuration files in the similar way as
+;;; <operating-system> do for system packages and configuration files.
+;;;
+;;; Code:
+
(define-record-type* <home-environment> home-environment
make-home-environment
home-environment?
--
2.33.0
From 2c7a295468aecd4f40e98ac0651800f561d89a71 Mon Sep 17 00:00:00 2001
From: Andrew Tropin <andrew@trop.in>
Date: Mon, 30 Aug 2021 13:22:16 +0300
Subject: [PATCH v2 5/5] home-services: xdg: Add missing import.

---
gnu/home-services/xdg.scm | 1 +
1 file changed, 1 insertion(+)

Toggle diff (14 lines)
diff --git a/gnu/home-services/xdg.scm b/gnu/home-services/xdg.scm
index 6e4a2542a3..535c8667a1 100644
--- a/gnu/home-services/xdg.scm
+++ b/gnu/home-services/xdg.scm
@@ -26,6 +26,7 @@
#:use-module (guix gexp)
#:use-module (guix records)
#:use-module (guix i18n)
+ #:use-module (guix diagnostics)
#:use-module (ice-9 match)
#:use-module (srfi srfi-1)
--
2.33.0
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmEsssoACgkQIgjSCVjB
3rBbrRAAg+ZQDx6cKdcXMbIfp1zw5TL8UsyPdCYLoVe1rB9zo9Mt5MreMQRUZBi0
1jjLZoCGcoKnmxs4HvaNyti2oCZm6suS+W4K7f2mzMJ+CJRkTZrh1XkojuubopjX
lf/9TB56a29QAPpl7v52Ew6D3OY5xcnEZl08uOJBwmCp7+X6AE1YprJxOQfd2PZx
t6RIdfKOy7K+lI1Lu53h9Mn4iprK1jgLY0wWJnFyIrSRpWgwR70yaglh9m6Cpjub
AC5EUO+SgSxhL+ZVXS5/Z9ph5E4YHIeQVulz1ADZYuGiJ+XRLiFwzEk3PPy8jX8m
Gl07n3cMcy5Y3Xfqp0qlGdTXRA7BIfVoDgW5308WXSPYRe6sm+ovRwKSpaxlsi3p
4kzkme2QEBf6OJNWl1IqwWSXwWlr8U+jttbF4j8+LqSnzQPsnJLzSeAmeGpiKA1W
MphgMCjbq/KDgOW+DYGIcc6okQDKUJ0sryuRHcytgQAYnGtrKI98pWbZWY/XgA9X
eyIOWj0YzNEW7LTdfFAZh1x5ireLlYHKCQiPx+BLFFWriCEXRNov7xotEBkGaHy1
LGLorwEjh1ejt/Mat/ZyBLdeRRioKxTYW4xFxT2TCFTS0MIhMXaclXB8jgGgZJB3
QTMvHT/WZDDMjZH8gAn6Sw41uKMLfkoYQEyn6LJIyFIfDaQighw=
=KKS4
-----END PGP SIGNATURE-----

Oleg Pykhalov wrote 4 years ago
Re: bug#50208: [PATCH] home-services: Add symlink-manager
(name . Andrew Tropin)(address . andrew@trop.in)(address . 50208-done@debbugs.gnu.org)
87pmtu8qrg.fsf_-_@gmail.com
Andrew Tropin <andrew@trop.in> writes:

Toggle quote (23 lines)
> Changes since v1:
> Added missing import to xdg via a separate commit.
> Added trailing dots to commit messages.
>
> Andrew Tropin (5):
> home-services: Add utils module.
> home-services: symlink-manager: Properly handle 1st generation case.
> home-services: activation: Add support for multiline env vars.
> gnu: home: Add doc comment about the module.
> home-services: xdg: Add missing import.
>
> gnu/home-services.scm | 4 +-
> gnu/home-services/shells.scm | 1 +
> gnu/home-services/symlink-manager.scm | 2 +-
> gnu/home-services/utils.scm | 77 +++++++++++++++++++++++++++
> gnu/home-services/xdg.scm | 1 +
> gnu/home.scm | 8 +++
> 6 files changed, 90 insertions(+), 3 deletions(-)
> create mode 100644 gnu/home-services/utils.scm
>
> --
> 2.33.0

[…]

Tabified local.mk, pushed to wip-guix-home.

Oleg.
-----BEGIN PGP SIGNATURE-----

iQJIBAEBCgAyFiEEcjhxI46s62NFSFhXFn+OpQAa+pwFAmEtZ4MUHGdvLndpZ3Vz
dEBnbWFpbC5jb20ACgkQFn+OpQAa+pyJZRAAu2tBEHCMrNX07/8aWDLihrgcHCeb
xeuxt4vKCozTuERruDNj51/IvAXK+IOqyPz83r6Bv4k5EKUM7Cw2m+3WHFJeypsn
L3qZ1STAVqt+j1QWskdzPh8TLHDKOqZUP7oj7YYE9Owo509eLp8X8UwXZX7I+Dv7
BCAOIvvGqPvafwqzoaPNzqI8yC4Uug1DJQsdnvl/ALjHKV3L4ZI103DuhQ+i/XaT
qOg7VpEd9YWGhM8dzu02Bxng6HS232IDCQG13eLtZySreyvkGJ0NIFUQOD92wxoO
IGF0hTi6IwXZpap2Tl0hPR/9IqFWSVjg5KBJp4Bw+77KsFfZ9LQSpE4AFqdryMaH
XR9ET/CqVgyh4D3Z0cSg5Ssjzs/Q4AIl9UlJITfylG/0NO5ql2aPlUw6ib/sTElw
RHByZUP+j+rW39k51qiTIZJXWtlBvu2FHUPLoDh4qZ7E+7A6o3KTwI6eWTmsZpq2
ns0DN8NHAMEYCHTtAaM1g+AsltnQB2ljENHJOJHv/Q9UprnGm2aBy3Y4Ax5CSONh
MNLPcwG8UPdj1elD/S3zEhDEULtTKw7wiIl94e0yQAbZt8E7U/lSOWJ8+gxOg4c7
YNKrWbI8hFBm0dtD9VJ8UcO0zNBChSt2oB88tK5Jx//oR3BKVF6ea2uOizT5Zjto
VIBvUrUFTFJ/8dM=
=YQ/G
-----END PGP SIGNATURE-----

Closed
Andrew Tropin wrote 4 years ago
(name . Oleg Pykhalov)(address . go.wigust@gmail.com)(address . 50208-done@debbugs.gnu.org)
877dg2jdub.fsf@trop.in
On 2021-08-31 02:19, Oleg Pykhalov wrote:

Toggle quote (31 lines)
> Andrew Tropin <andrew@trop.in> writes:
>
>> Changes since v1:
>> Added missing import to xdg via a separate commit.
>> Added trailing dots to commit messages.
>>
>> Andrew Tropin (5):
>> home-services: Add utils module.
>> home-services: symlink-manager: Properly handle 1st generation case.
>> home-services: activation: Add support for multiline env vars.
>> gnu: home: Add doc comment about the module.
>> home-services: xdg: Add missing import.
>>
>> gnu/home-services.scm | 4 +-
>> gnu/home-services/shells.scm | 1 +
>> gnu/home-services/symlink-manager.scm | 2 +-
>> gnu/home-services/utils.scm | 77 +++++++++++++++++++++++++++
>> gnu/home-services/xdg.scm | 1 +
>> gnu/home.scm | 8 +++
>> 6 files changed, 90 insertions(+), 3 deletions(-)
>> create mode 100644 gnu/home-services/utils.scm
>>
>> --
>> 2.33.0
>
> […]
>
> Tabified local.mk, pushed to wip-guix-home.
>
> Oleg.

It seems we are finished with basic home-services, refactoring and
preparing CLI now, will send it in a separate thread.

Thank you very much!)
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmEt1CwACgkQIgjSCVjB
3rDT2A//XGL7dh+QFzhqM0jFT3mkD1qC++tAVzj4DQLg1BeCxTUgKW7+SeZSoLje
yPERDKxvsOBD+WSI9IyJTBumaumhDa49xmtu3Su1yT3TRFms9dbl8QqVueHfAecc
W8Z0wkDymeaj0oZUvrzdy/JPJTShr6tBO5U5uB3YSGkSJlIwruAEgq94+MuV8cr3
YI4kKN2DAAHFzD1MxuUJ1bonw0qWOsJ9m8JBg3sE1fD1vyIbzpsvpoLnoBRLYNhH
augjUtg2gxIkS3RiRZsdYpsExwwRF/L6OUae+Cg1QDS729sk4tyrBo+WLXKa0jKD
+nh/gt/tiMEEV/s/UBK9y47Ly1j+QoF/mp0UocoK5s2yJuCUY7nzASq3rf8nJzSX
lw0bNdh9oriK1s5MuovhGnoFEK6dU4Ifs3NNDmZTCcIoNJxqXjph/U0AUWjXV2lU
3C0AEF7dYeIX+UUHvViRLm2Ql8fFTGPnPRpW2ZvwQRjIUSDaNcnCUDeVoKmvUr4/
v8NE2h/VLAcCh1ILDTrl5k37tUo6KESpcgNY2LB/SqNRDFyXwVrklexemgbz/YRj
MOi0Lg0oQFMV11b4RU+4QJqmAbMnSU0UJHn5MulnzW9IKzGlWvX5WlqVFsevXdMm
Mmrh6Az/8txi7u+FK3q/wsl3Si/1KtUYLX74ppK1LpBW5L3Eqng=
=rxjX
-----END PGP SIGNATURE-----

Closed
?
Your comment

This issue is archived.

To comment on this conversation send an email to 50208@debbugs.gnu.org

To respond to this issue using the mumi CLI, first switch to it
mumi current 50208
Then, you may apply the latest patchset in this issue (with sign off)
mumi am -- -s
Or, compose a reply to this issue
mumi compose
Or, send patches to this issue
mumi send-email *.patch
You may also tag this issue. See list of standard tags. For example, to set the confirmed and easy tags
mumi command -t +confirmed -t +easy
Or, remove the moreinfo tag and set the help tag
mumi command -t -moreinfo -t +help