* [bug#49419] [PATCH 0/4] Essential home services @ 2021-07-05 15:35 Andrew Tropin 2021-07-05 15:37 ` [bug#49419] [PATCH 1/4] home-services: Add most essential " Andrew Tropin ` (6 more replies) 0 siblings, 7 replies; 38+ messages in thread From: Andrew Tropin @ 2021-07-05 15:35 UTC (permalink / raw) To: 49419 [-- Attachment #1: Type: text/plain, Size: 513 bytes --] This patch series contains most crucial home services and few helper functions required for Guix Home. Andrew Tropin (4): home-services: Add most essential home services home-services: Add home-run-on-change-service-type home-services: Add home-provenance-service-type home-services: Add fold-home-service-types function gnu/home-services.scm | 472 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 472 insertions(+) create mode 100644 gnu/home-services.scm -- 2.32.0 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH 1/4] home-services: Add most essential home services 2021-07-05 15:35 [bug#49419] [PATCH 0/4] Essential home services Andrew Tropin @ 2021-07-05 15:37 ` Andrew Tropin 2021-07-05 15:47 ` Maxime Devos 2021-07-05 15:39 ` [bug#49419] [PATCH 2/4] home-services: Add home-run-on-change-service-type Andrew Tropin ` (5 subsequent siblings) 6 siblings, 1 reply; 38+ messages in thread From: Andrew Tropin @ 2021-07-05 15:37 UTC (permalink / raw) To: 49419 [-- Attachment #1: Type: text/plain, Size: 15749 bytes --] home-service-type is a root of home services DAG. home-profile-service-type is almost the same as profile-service-type, at least for now. home-environment-variables-service-type generates a @file{setup-environment} shell script, which is expected to be sourced by login shell or other program, which starts early and spawns all other processes. Home services for shells automatically add code for sourcing this file, if person do not use those home services they have to source this script manually in their's shell *profile file (details described in the manual). home-files-service-type is similar to etc-service-type, but doesn't extend home-activation, because deploy mechanism for config files is pluggable and can be different for different home environments: The default one is called symlink-manager (will be introudced in a separate patch series), which creates links for various dotfiles (like $XDG_CONFIG_HOME/$APP/...) to store, but is possible to implement alternative approaches like read-only home from Julien's guix-home-manager. home-run-on-first-login-service-type provides an @file{on-first-login} guile script, which runs provided gexps once, when user makes first login. It can be used to start user's Shepherd and maybe some other process. It relies on assumption that /run/user/$UID will be created on login by some login manager (elogind for example). home-activation-service-type provides an @file{activate} guile script, which do three main things: - Sets environment variables to the values declared in @file{setup-environment} shell script. It's necessary, because user can set for example XDG_CONFIG_HOME and it should be respected by activation gexp of symlink-manager. - Sets GUIX_NEW_HOME and possibly GUIX_OLD_HOME vars to paths in the store. Later those variables can be used by activation gexps, for example by symlink-manager or run-on-change services. - Run all activation gexps provided by other home services. --- gnu/home-services.scm | 328 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 gnu/home-services.scm diff --git a/gnu/home-services.scm b/gnu/home-services.scm new file mode 100644 index 0000000000..44a7e68934 --- /dev/null +++ b/gnu/home-services.scm @@ -0,0 +1,328 @@ +;;; 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) + #:use-module (gnu services) + #:use-module (guix channels) + #:use-module (guix monads) + #:use-module (guix store) + #:use-module (guix gexp) + #:use-module (guix profiles) + #:use-module (guix sets) + #:use-module (guix ui) + #:use-module (guix discovery) + #:use-module (guix diagnostics) + + #:use-module (srfi srfi-1) + #:use-module (ice-9 match) + + #:export (home-service-type + home-profile-service-type + home-environment-variables-service-type + home-files-service-type + home-run-on-first-login-service-type + home-activation-service-type) + + #:re-export (service + service-type + service-extension)) + +;;; Comment: +;;; +;;; This module is similar to (gnu system services) module, but +;;; provides Home Services, which are supposed to be used for building +;;; home-environment. +;;; +;;; Home Services use the same extension as System Services. Consult +;;; (gnu system services) module or manual for more information. +;;; +;;; Code: + + +(define (home-derivation entries mextensions) + "Return as a monadic value the derivation of the 'home' +directory containing the given entries." + (mlet %store-monad ((extensions (mapm/accumulate-builds identity + mextensions))) + (lower-object + (file-union "home" (append entries (concatenate extensions)))))) + +(define home-service-type + ;; This is the ultimate service type, the root of the home service + ;; DAG. The service of this type is extended by monadic name/item + ;; pairs. These items end up in the "home-environment directory" as + ;; returned by 'home-environment-derivation'. + (service-type (name 'home) + (extensions '()) + (compose identity) + (extend home-derivation) + (default-value '()) + (description + "Build the home environment top-level directory, +which in turn refers to everything the home environment needs: its +packages, configuration files, activation script, and so on."))) + +(define (packages->profile-entry packages) + "Return a system entry for the profile containing PACKAGES." + ;; XXX: 'mlet' is needed here for one reason: to get the proper + ;; '%current-target' and '%current-target-system' bindings when + ;; 'packages->manifest' is called, and thus when the 'package-inputs' + ;; etc. procedures are called on PACKAGES. That way, conditionals in those + ;; inputs see the "correct" value of these two parameters. See + ;; <https://issues.guix.gnu.org/44952>. + (mlet %store-monad ((_ (current-target-system))) + (return `(("profile" ,(profile + (content (packages->manifest + (map identity + ;;(options->transformation transformations) + (delete-duplicates packages eq?)))))))))) + +;; MAYBE: Add a list of transformations for packages. It's better to +;; place it in home-profile-service-type to affect all profile +;; packages and prevent conflicts, when other packages relies on +;; non-transformed version of package. +(define home-profile-service-type + (service-type (name 'home-profile) + (extensions + (list (service-extension home-service-type + packages->profile-entry))) + (compose concatenate) + (extend append) + (description + "This is the @dfn{home profile} and can be found in +@file{~/.guix-home/profile}. It contains packages and +configuration files that the user has declared in their +@code{home-environment} record."))) + +(define (environment-variables->setup-environment-script vars) + "Return a file that can be sourced by a POSIX compliant shell which +initializes the environment. The file will source the home +environment profile, set some default environment variables, and set +environment variables provided in @code{vars}. @code{vars} is a list +of pairs (@code{(key . value)}), @code{key} is a string and +@code{value} is a string or gexp. + +If value is @code{#f} variable will be omitted. +If value is @code{#t} variable will be just exported. +For any other, value variable will be set to the @code{value} and +exported." + (define (warn-about-duplicate-defenitions) + (fold + (lambda (x acc) + (when (equal? (car x) (car acc)) + (warning + (G_ "duplicate definition for `~a' environment variable ~%") (car x))) + x) + (cons "" "") + (sort vars (lambda (a b) + (string<? (car a) (car b)))))) + + (warn-about-duplicate-defenitions) + (with-monad + %store-monad + (return + `(("setup-environment" + ;; TODO: It's necessary to source ~/.guix-profile too + ;; on foreign distros + ,(apply mixed-text-file "setup-environment" + "\ +HOME_ENVIRONMENT=$HOME/.guix-home +GUIX_PROFILE=\"$HOME_ENVIRONMENT/profile\" +PROFILE_FILE=\"$HOME_ENVIRONMENT/profile/etc/profile\" +[ -f $PROFILE_FILE ] && . $PROFILE_FILE + +case $XDG_DATA_DIRS in + *$HOME_ENVIRONMENT/profile/share*) ;; + *) export XDG_DATA_DIRS=$HOME_ENVIRONMENT/profile/share:$XDG_DATA_DIRS ;; +esac +case $MANPATH in + *$HOME_ENVIRONMENT/profile/share/man*) ;; + *) export MANPATH=$HOME_ENVIRONMENT/profile/share/man:$MANPATH +esac +case $INFOPATH in + *$HOME_ENVIRONMENT/profile/share/info*) ;; + *) export INFOPATH=$HOME_ENVIRONMENT/profile/share/info:$INFOPATH ;; +esac +case $XDG_CONFIG_DIRS in + *$HOME_ENVIRONMENT/profile/etc/xdg*) ;; + *) export XDG_CONFIG_DIRS=$HOME_ENVIRONMENT/profile/etc/xdg:$XDG_CONFIG_DIRS ;; +esac +case $XCURSOR_PATH in + *$HOME_ENVIRONMENT/profile/share/icons*) ;; + *) export XCURSOR_PATH=$HOME_ENVIRONMENT/profile/share/icons:$XCURSOR_PATH ;; +esac + +" + + (append-map + (match-lambda + ((key . #f) + '()) + ((key . #t) + (list "export " key "\n")) + ((key . value) + (list "export " key "=" value "\n"))) + vars))))))) + +(define home-environment-variables-service-type + (service-type (name 'home-environment-variables) + (extensions + (list (service-extension + home-service-type + environment-variables->setup-environment-script))) + (compose concatenate) + (extend append) + (default-value '()) + (description "Set the environment variables."))) + +(define (files->files-directory files) + "Return a @code{files} directory that contains FILES." + (define (assert-no-duplicates files) + (let loop ((files files) + (seen (set))) + (match files + (() #t) + (((file _) rest ...) + (when (set-contains? seen file) + (raise (formatted-message (G_ "duplicate '~a' entry for files/") + file))) + (loop rest (set-insert file seen)))))) + + ;; Detect duplicates early instead of letting them through, eventually + ;; leading to a build failure of "files.drv". + (assert-no-duplicates files) + + (file-union "files" files)) + +(define (files-entry files) + "Return an entry for the @file{~/.guix-home/files} +directory containing FILES." + (with-monad %store-monad + (return `(("files" ,(files->files-directory files)))))) + +(define home-files-service-type + (service-type (name 'home-files) + (extensions + (list (service-extension home-service-type + files-entry))) + (compose concatenate) + (extend append) + (default-value '()) + (description "Configuration files for programs that +will be put in @file{~/.guix-home/files}."))) + +(define (compute-on-first-login-script _ gexps) + (gexp->script + "on-first-login" + #~(let* ((xdg-runtime-dir (or (getenv "XDG_RUNTIME_DIR") + (format #f "/run/user/~a" (getuid)))) + (flag-file-path (string-append + xdg-runtime-dir "/on-first-login-executed")) + (touch (lambda (file-name) + (call-with-output-file file-name (const #t))))) + ;; XDG_RUNTIME_DIR dissapears on logout, that means such trick + ;; allows to launch on-first-login script on first login only + ;; after complete logout/reboot. + (when (not (file-exists? flag-file-path)) + (begin #$@gexps (touch flag-file-path)))))) + +(define (on-first-login-script-entry m-on-first-login) + "Return, as a monadic value, an entry for the on-first-login script +in the home environment directory." + (mlet %store-monad ((on-first-login m-on-first-login)) + (return `(("on-first-login" ,on-first-login))))) + +(define home-run-on-first-login-service-type + (service-type (name 'home-run-on-first-login) + (extensions + (list (service-extension + home-service-type + on-first-login-script-entry))) + (compose identity) + (extend compute-on-first-login-script) + (default-value #f) + (description "Run gexps on first user login. Can be +extended with one gexp."))) + + +(define (compute-activation-script init-gexp gexps) + (gexp->script + "activate" + #~(let* ((he-init-file (lambda (he) (string-append he "/setup-environment"))) + (he-path (string-append (getenv "HOME") "/.guix-home")) + (new-home-env (getenv "GUIX_NEW_HOME")) + (new-home (or new-home-env + ;; Path of the activation file if called interactively + (dirname (car (command-line))))) + (old-home-env (getenv "GUIX_OLD_HOME")) + (old-home (or old-home-env + (if (file-exists? (he-init-file he-path)) + (readlink he-path) + #f)))) + (if (file-exists? (he-init-file new-home)) + (let* ((port ((@@ (ice-9 popen) open-input-pipe) + (format #f "source ~a && env" + (he-init-file new-home)))) + (result ((@@ (ice-9 rdelim) read-delimited) "" port)) + (vars (map (lambda (x) + (let ((si (string-index x #\=))) + (cons (string-take x si) + (string-drop x (1+ si))))) + ((@@ (srfi srfi-1) remove) + string-null? + (string-split result #\newline))))) + (close-port port) + (map (lambda (x) (setenv (car x) (cdr x))) vars) + + (setenv "GUIX_NEW_HOME" new-home) + (setenv "GUIX_OLD_HOME" old-home) + + #$@gexps + + ;; Do not unset env variable if it was set outside. + (unless new-home-env (setenv "GUIX_NEW_HOME" #f)) + (unless old-home-env (setenv "GUIX_OLD_HOME" #f))) + (format #t "\ +Activation script was either called or loaded by file from this direcotry: +~a +It doesn't seem that home environment is somewhere around. +Make sure that you call ./activate by symlink from -home store item.\n" + new-home))))) + +(define (activation-script-entry m-activation) + "Return, as a monadic value, an entry for the activation script +in the home environment directory." + (mlet %store-monad ((activation m-activation)) + (return `(("activate" ,activation))))) + +(define home-activation-service-type + (service-type (name 'home-activation) + (extensions + (list (service-extension + home-service-type + activation-script-entry))) + (compose identity) + (extend compute-activation-script) + (default-value #f) + (description "Run gexps to activate the current +generation of home environment and update the state of the home +directory. @command{activate} script automatically called during +reconfiguration or generation switching. This service can be extended +with one gexp, but many times, and all gexps must be idempotent."))) + -- 2.32.0 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH 1/4] home-services: Add most essential home services 2021-07-05 15:37 ` [bug#49419] [PATCH 1/4] home-services: Add most essential " Andrew Tropin @ 2021-07-05 15:47 ` Maxime Devos 2021-07-05 16:19 ` Andrew Tropin 2021-07-06 7:23 ` Andrew Tropin 0 siblings, 2 replies; 38+ messages in thread From: Maxime Devos @ 2021-07-05 15:47 UTC (permalink / raw) To: Andrew Tropin, 49419 [-- Attachment #1: Type: text/plain, Size: 1525 bytes --] Hi, Andrew Tropin schreef op ma 05-07-2021 om 18:37 [+0300]: > + (if (file-exists? (he-init-file new-home)) > + (let* ((port ((@@ (ice-9 popen) open-input-pipe) > + (format #f "source ~a && env" > + (he-init-file new-home)))) > + (result ((@@ (ice-9 rdelim) read-delimited) "" port)) > + (vars (map (lambda (x) > + (let ((si (string-index x #\=))) > + (cons (string-take x si) > + (string-drop x (1+ si))))) > + ((@@ (srfi srfi-1) remove) > + string-null? > + (string-split result #\newline))))) Why are you using @@ here? 'open-input-pipe', 'read-delimited' and 'remove' are exported variables, so you can just use @ instead of the magic evil @@ operator. From the guile manual: -- syntax: @ module-name binding-name Refer to the binding named BINDING-NAME in module MODULE-NAME. The binding must have been exported by the module. -- syntax: @@ module-name binding-name Refer to the binding named BINDING-NAME in module MODULE-NAME. The binding must not have been exported by the module. This syntax is only intended for debugging purposes or as a last resort. *Note Declarative Modules::, for some limitations on the use of ‘@@’. Greetings, Maxime. [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 260 bytes --] ^ permalink raw reply [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH 1/4] home-services: Add most essential home services 2021-07-05 15:47 ` Maxime Devos @ 2021-07-05 16:19 ` Andrew Tropin 2021-07-05 19:19 ` Maxime Devos 2021-07-06 7:23 ` Andrew Tropin 1 sibling, 1 reply; 38+ messages in thread From: Andrew Tropin @ 2021-07-05 16:19 UTC (permalink / raw) To: Maxime Devos, 49419 [-- Attachment #1: Type: text/plain, Size: 1315 bytes --] Maxime Devos <maximedevos@telenet.be> writes: > Hi, > > Andrew Tropin schreef op ma 05-07-2021 om 18:37 [+0300]: >> + (if (file-exists? (he-init-file new-home)) >> + (let* ((port ((@@ (ice-9 popen) open-input-pipe) >> + (format #f "source ~a && env" >> + (he-init-file new-home)))) >> + (result ((@@ (ice-9 rdelim) read-delimited) "" port)) >> + (vars (map (lambda (x) >> + (let ((si (string-index x #\=))) >> + (cons (string-take x si) >> + (string-drop x (1+ si))))) >> + ((@@ (srfi srfi-1) remove) >> + string-null? >> + (string-split result #\newline))))) > > Why are you using @@ here? 'open-input-pipe', 'read-delimited' and 'remove' > are exported variables, so you can just use @ instead of the magic evil @@ > operator. Because of a bad habbit, I needed it once and after that started to use it uncoditionally. It should be @, thanks for pointing! BTW, how to add changes to the patches? Do I need to resend a particular patch with required updates or have to wait other reviews and send a v2 patch series? [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH 1/4] home-services: Add most essential home services 2021-07-05 16:19 ` Andrew Tropin @ 2021-07-05 19:19 ` Maxime Devos 2021-07-06 7:09 ` Andrew Tropin 0 siblings, 1 reply; 38+ messages in thread From: Maxime Devos @ 2021-07-05 19:19 UTC (permalink / raw) To: Andrew Tropin, 49419 [-- Attachment #1: Type: text/plain, Size: 1212 bytes --] Andrew Tropin schreef op ma 05-07-2021 om 19:19 [+0300]: > Maxime Devos <maximedevos@telenet.be> writes: > > [...] > > BTW, how to add changes to the patches? Do I need to resend a > particular patch with required updates or have to wait other reviews and > send a v2 patch series? I would do a combination of those: reply to the mail of the reviewer with a revised patch attached. When you have received a ‘sufficient’ number of reviews from others on the other patches in the series as well, send a v2. Some benefits of this method: (1) it should be clear which patches should be applied, as the number of 'revised patches' without sending a new series version is limited. This is also the case if you send a new version after each little change, but can easily become _not_ the cas if you always respond with a revised patch without starting a new series version. (2) you don't clutter the mailboxes with new version after new version after each little change. This is particularily important if you have large patch series (say 13 or more patches), which doesn't seem to apply here. WDYT? Greetings, Maxime. [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 260 bytes --] ^ permalink raw reply [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH 1/4] home-services: Add most essential home services 2021-07-05 19:19 ` Maxime Devos @ 2021-07-06 7:09 ` Andrew Tropin 2021-07-06 8:26 ` Maxime Devos 0 siblings, 1 reply; 38+ messages in thread From: Andrew Tropin @ 2021-07-06 7:09 UTC (permalink / raw) To: Maxime Devos, 49419 [-- Attachment #1: Type: text/plain, Size: 2292 bytes --] Maxime Devos <maximedevos@telenet.be> writes: > Andrew Tropin schreef op ma 05-07-2021 om 19:19 [+0300]: >> Maxime Devos <maximedevos@telenet.be> writes: >> >> [...] >> >> BTW, how to add changes to the patches? Do I need to resend a >> particular patch with required updates or have to wait other reviews and >> send a v2 patch series? > > I would do a combination of those: reply to the mail of the reviewer with a > revised patch attached. When you have received a ‘sufficient’ number of reviews > from others on the other patches in the series as well, send a v2. > > Some benefits of this method: > > (1) it should be clear which patches should be applied, > as the number of 'revised patches' without sending a new series > version is limited. > > This is also the case if you send a new version after each little change, > but can easily become _not_ the cas if you always respond with a revised > patch without starting a new series version. > > (2) you don't clutter the mailboxes with new version after new version > after each little change. > > This is particularily important if you have large patch series (say 13 or > more patches), which doesn't seem to apply here. > > WDYT? I came up with one more approach: I can send a patch, which address the issues reviewer mentioned and after getting more reviews from other peers I can rebase my original commits and incorparate all the later patches to them and prepare v2 series. [PATCH 0/4] [PATCH 1/4] fix1 to address issue from subthread1 reported by r1 fix2 to address issue from subthread2 reported by r2 fix3 to address issue from subthread2 came during discussion with r1 and r2 [PATCH 2/4] ... Such approach makes it clear how the comments were addressed, because now you see a diff, not the whole new patch. On the other hand it can be a little harder to reply, because you don't have the latest version of the patch, but have only original patch and updates to it, so you need to pick, which one you want to reply to. I will try this one, to find its weak points. It's better to practice on this small patch series, rather something huge) Another question: Is it better to inline or attach patches? [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH 1/4] home-services: Add most essential home services 2021-07-06 7:09 ` Andrew Tropin @ 2021-07-06 8:26 ` Maxime Devos 0 siblings, 0 replies; 38+ messages in thread From: Maxime Devos @ 2021-07-06 8:26 UTC (permalink / raw) To: Andrew Tropin, 49419 [-- Attachment #1: Type: text/plain, Size: 476 bytes --] Andrew Tropin schreef op di 06-07-2021 om 10:09 [+0300]: > Another question: Is it better to inline or attach patches? FWIW, I can read both just fine in my e-mail application (evolution). When it's inline, I can read the patch directly but also have an option to save it somewhere. When it is attached, there is some button for ‘expanding’ the attachement so I can read it. Both work for me. I don't know about other mail applications. Greetings, Maxime. [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 260 bytes --] ^ permalink raw reply [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH 1/4] home-services: Add most essential home services 2021-07-05 15:47 ` Maxime Devos 2021-07-05 16:19 ` Andrew Tropin @ 2021-07-06 7:23 ` Andrew Tropin 1 sibling, 0 replies; 38+ messages in thread From: Andrew Tropin @ 2021-07-06 7:23 UTC (permalink / raw) To: Maxime Devos, 49419 [-- Attachment #1.1: Type: text/plain, Size: 1072 bytes --] Maxime Devos <maximedevos@telenet.be> writes: > Hi, > > Andrew Tropin schreef op ma 05-07-2021 om 18:37 [+0300]: >> + (if (file-exists? (he-init-file new-home)) >> + (let* ((port ((@@ (ice-9 popen) open-input-pipe) >> + (format #f "source ~a && env" >> + (he-init-file new-home)))) >> + (result ((@@ (ice-9 rdelim) read-delimited) "" port)) >> + (vars (map (lambda (x) >> + (let ((si (string-index x #\=))) >> + (cons (string-take x si) >> + (string-drop x (1+ si))))) >> + ((@@ (srfi srfi-1) remove) >> + string-null? >> + (string-split result #\newline))))) > > Why are you using @@ here? 'open-input-pipe', 'read-delimited' and 'remove' > are exported variables, so you can just use @ instead of the magic evil @@ > operator. Addressed the issue with the following patch. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1.2: patch changing @@ to @ --] [-- Type: text/x-patch, Size: 1957 bytes --] From 27998096bf5b4ccd1c66ef71c1280faf0e11be72 Mon Sep 17 00:00:00 2001 From: Andrew Tropin <andrew@trop.in> Date: Mon, 5 Jul 2021 19:22:40 +0300 Subject: [PATCH] (toberebased) home-services: Use @ instead of @@ --- gnu/home-services.scm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gnu/home-services.scm b/gnu/home-services.scm index a06cd72459..78e5603edf 100644 --- a/gnu/home-services.scm +++ b/gnu/home-services.scm @@ -280,15 +280,15 @@ extended with one gexp."))) (readlink he-path) #f)))) (if (file-exists? (he-init-file new-home)) - (let* ((port ((@@ (ice-9 popen) open-input-pipe) + (let* ((port ((@ (ice-9 popen) open-input-pipe) (format #f "source ~a && env" (he-init-file new-home)))) - (result ((@@ (ice-9 rdelim) read-delimited) "" port)) + (result ((@ (ice-9 rdelim) read-delimited) "" port)) (vars (map (lambda (x) (let ((si (string-index x #\=))) (cons (string-take x si) (string-drop x (1+ si))))) - ((@@ (srfi srfi-1) remove) + ((@ (srfi srfi-1) remove) string-null? (string-split result #\newline))))) (close-port port) @@ -340,7 +340,7 @@ with one gexp, but many times, and all gexps must be idempotent."))) (define (equal-regulars? file1 file2) "Check if FILE1 and FILE2 are bit for bit identical." (let* ((cmp-binary #$(file-append - (@@ (gnu packages base) diffutils) "/bin/cmp")) + (@ (gnu packages base) diffutils) "/bin/cmp")) (status (system* cmp-binary file1 file2))) (= status 0))) -- 2.32.0 [-- Attachment #1.3: Type: text/plain, Size: 190 bytes --] I can use different methods to attach/prepare/send patches and reply to the reviews, sorry for any inconveniences in advance) I'll stick to some approach, once I'll practice a few of them. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH 2/4] home-services: Add home-run-on-change-service-type 2021-07-05 15:35 [bug#49419] [PATCH 0/4] Essential home services Andrew Tropin 2021-07-05 15:37 ` [bug#49419] [PATCH 1/4] home-services: Add most essential " Andrew Tropin @ 2021-07-05 15:39 ` Andrew Tropin 2021-07-05 15:41 ` [bug#49419] [PATCH 3/4] home-services: Add home-provenance-service-type Andrew Tropin ` (4 subsequent siblings) 6 siblings, 0 replies; 38+ messages in thread From: Andrew Tropin @ 2021-07-05 15:39 UTC (permalink / raw) To: 49419 [-- Attachment #1: Type: text/plain, Size: 4734 bytes --] Service allows to trigger actions during activation if file or directory specified by pattern is changed. --- gnu/home-services.scm | 95 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-) diff --git a/gnu/home-services.scm b/gnu/home-services.scm index 44a7e68934..002a003d65 100644 --- a/gnu/home-services.scm +++ b/gnu/home-services.scm @@ -37,7 +37,8 @@ home-environment-variables-service-type home-files-service-type home-run-on-first-login-service-type - home-activation-service-type) + home-activation-service-type + home-run-on-change-service-type) #:re-export (service service-type @@ -326,3 +327,95 @@ directory. @command{activate} script automatically called during reconfiguration or generation switching. This service can be extended with one gexp, but many times, and all gexps must be idempotent."))) +\f +;;; +;;; On-change. +;;; + +(define (compute-on-change-gexp eval-gexps? pattern-gexp-tuples) + #~(begin + (define (equal-regulars? file1 file2) + "Check if FILE1 and FILE2 are bit for bit identical." + (let* ((cmp-binary #$(file-append + (@@ (gnu packages base) diffutils) "/bin/cmp")) + (status (system* cmp-binary file1 file2))) + (= status 0))) + + (define (equal-symlinks? symlink1 symlink2) + "Check if SYMLINK1 and SYMLINK2 are pointing to the same target." + (string=? (readlink symlink1) (readlink symlink2))) + + (define (equal-directories? dir1 dir2) + "Check if DIR1 and DIR2 have the same content." + (define (ordinary-file file) + (not (or (string=? file ".") + (string=? file "..")))) + (let* ((files1 (scandir dir1 ordinary-file)) + (files2 (scandir dir2 ordinary-file))) + (if (equal? files1 files2) + (map (lambda (file) + (equal-files? + (string-append dir1 "/" file) + (string-append dir2 "/" file))) + files1) + #f))) + + (define (equal-files? file1 file2) + "Compares files, symlinks or directories of the same type." + (case (file-type file1) + ((directory) (equal-directories? file1 file2)) + ((symlink) (equal-symlinks? file1 file2)) + ((regular) (equal-regulars? file1 file2)) + (else + (display "The file type is unsupported by on-change service.\n") + #f))) + + (define (file-type file) + (stat:type (lstat file))) + + (define (something-changed? file1 file2) + (cond + ((and (not (file-exists? file1)) + (not (file-exists? file2))) #f) + ((or (not (file-exists? file1)) + (not (file-exists? file2))) #t) + + ((not (eq? (file-type file1) (file-type file2))) #t) + + (else + (not (equal-files? file1 file2))))) + + (define expressions-to-eval + (map + (lambda (x) + (let* ((file1 (string-append (getenv "GUIX_OLD_HOME") "/" (car x))) + (file2 (string-append (getenv "GUIX_NEW_HOME") "/" (car x))) + (_ (format #t "Comparing ~a and\n~10t~a..." file1 file2)) + (any-changes? (something-changed? file1 file2)) + (_ (format #t " done (~a)\n" + (if any-changes? "changed" "same")))) + (if any-changes? (cadr x) ""))) + '#$pattern-gexp-tuples)) + + (if #$eval-gexps? + (begin + (display "Evaling on-change gexps.\n\n") + (for-each primitive-eval expressions-to-eval) + (display "On-change gexps evaluation finished.\n\n")) + (display "\ +On-change gexps won't evaluated, disabled by service configuration.\n")))) + +(define home-run-on-change-service-type + (service-type (name 'home-run-on-change) + (extensions + (list (service-extension + home-activation-service-type + identity))) + (compose concatenate) + (extend compute-on-change-gexp) + (default-value #t) + (description "\ +G-expressions to run if the specified files have changed since the +last generation. The extension should be a list of lists where the +first element is the pattern for file or directory that expected to be +changed, and the second element is the G-expression to be evaluated."))) -- 2.32.0 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH 3/4] home-services: Add home-provenance-service-type 2021-07-05 15:35 [bug#49419] [PATCH 0/4] Essential home services Andrew Tropin 2021-07-05 15:37 ` [bug#49419] [PATCH 1/4] home-services: Add most essential " Andrew Tropin 2021-07-05 15:39 ` [bug#49419] [PATCH 2/4] home-services: Add home-run-on-change-service-type Andrew Tropin @ 2021-07-05 15:41 ` Andrew Tropin 2021-07-05 15:41 ` [bug#49419] [PATCH 4/4] home-services: Add fold-home-service-types function Andrew Tropin ` (3 subsequent siblings) 6 siblings, 0 replies; 38+ messages in thread From: Andrew Tropin @ 2021-07-05 15:41 UTC (permalink / raw) To: 49419 [-- Attachment #1: Type: text/plain, Size: 1784 bytes --] * gnu/home-services.scm (home-provenance-service-type, sexp->home-provenance, home-provenance): New variables. --- gnu/home-services.scm | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/gnu/home-services.scm b/gnu/home-services.scm index 002a003d65..20a9537650 100644 --- a/gnu/home-services.scm +++ b/gnu/home-services.scm @@ -38,7 +38,10 @@ home-files-service-type home-run-on-first-login-service-type home-activation-service-type - home-run-on-change-service-type) + home-run-on-change-service-type + home-provenance-service-type + + fold-home-service-types) #:re-export (service service-type @@ -419,3 +422,25 @@ G-expressions to run if the specified files have changed since the last generation. The extension should be a list of lists where the first element is the pattern for file or directory that expected to be changed, and the second element is the G-expression to be evaluated."))) + +\f +;;; +;;; Provenance tracking. +;;; + +(define home-provenance-service-type + (service-type + (name 'home-provenance) + (extensions + (list (service-extension + home-service-type + (service-extension-compute + (first (service-type-extensions provenance-service-type)))))) + (default-value #f) ;the HE config file + (description "\ +Store provenance information about the home environment in the home +environment itself: the channels used when building the home +environment, and its configuration file, when available."))) + +(define sexp->home-provenance sexp->system-provenance) +(define home-provenance system-provenance) -- 2.32.0 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH 4/4] home-services: Add fold-home-service-types function 2021-07-05 15:35 [bug#49419] [PATCH 0/4] Essential home services Andrew Tropin ` (2 preceding siblings ...) 2021-07-05 15:41 ` [bug#49419] [PATCH 3/4] home-services: Add home-provenance-service-type Andrew Tropin @ 2021-07-05 15:41 ` Andrew Tropin 2021-07-13 16:17 ` [bug#49419] [PATCH v2 0/4] Essential home services Andrew Tropin ` (2 subsequent siblings) 6 siblings, 0 replies; 38+ messages in thread From: Andrew Tropin @ 2021-07-05 15:41 UTC (permalink / raw) To: 49419 [-- Attachment #1: Type: text/plain, Size: 1480 bytes --] * gnu/home-services.scm (parent-directory, %guix-home-root-directory, %service-type-path, all-home-service-modules, fold-home-service-types): New variables. --- gnu/home-services.scm | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/gnu/home-services.scm b/gnu/home-services.scm index 20a9537650..a06cd72459 100644 --- a/gnu/home-services.scm +++ b/gnu/home-services.scm @@ -444,3 +444,29 @@ environment, and its configuration file, when available."))) (define sexp->home-provenance sexp->system-provenance) (define home-provenance system-provenance) + +\f +;;; +;;; Searching +;;; + +(define (parent-directory directory) + "Get the parent directory of DIRECTORY" + (string-join (drop-right (string-split directory #\/) 1) "/")) + +(define %guix-home-root-directory + ;; Absolute file name of the module hierarchy. + (parent-directory (dirname (search-path %load-path "gnu/home-services.scm")))) + +(define %service-type-path + ;; Search path for service types. + (make-parameter `((,%guix-home-root-directory . "gnu/home-services")))) + +(define (all-home-service-modules) + "Return the default set of home-service modules." + (cons (resolve-interface '(gnu home-services)) + (all-modules (%service-type-path) + #:warn warn-about-load-error))) + +(define* (fold-home-service-types proc seed) + (fold-service-types proc seed (all-home-service-modules))) -- 2.32.0 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH v2 0/4] Essential home services 2021-07-05 15:35 [bug#49419] [PATCH 0/4] Essential home services Andrew Tropin ` (3 preceding siblings ...) 2021-07-05 15:41 ` [bug#49419] [PATCH 4/4] home-services: Add fold-home-service-types function Andrew Tropin @ 2021-07-13 16:17 ` Andrew Tropin 2021-07-05 15:37 ` [bug#49546] [PATCH v2 1/4] home-services: Add most essential " Andrew Tropin ` (4 more replies) 2021-07-19 8:04 ` [bug#49419] [PATCH v3 0/4] Essential home services Andrew Tropin [not found] ` <handler.49419.B.162549932625345.ack@debbugs.gnu.org> 6 siblings, 5 replies; 38+ messages in thread From: Andrew Tropin @ 2021-07-13 16:17 UTC (permalink / raw) To: 49419 Changes since v1: Use @ instead of @@ Andrew Tropin (4): home-services: Add most essential home services home-services: Add home-run-on-change-service-type home-services: Add home-provenance-service-type home-services: Add fold-home-service-types function gnu/home-services.scm | 472 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 472 insertions(+) create mode 100644 gnu/home-services.scm -- 2.32.0 ^ permalink raw reply [flat|nested] 38+ messages in thread
* [bug#49546] [PATCH v2 1/4] home-services: Add most essential home services 2021-07-13 16:17 ` [bug#49419] [PATCH v2 0/4] Essential home services Andrew Tropin @ 2021-07-05 15:37 ` Andrew Tropin [not found] ` <handler.49546.B.16262002971832.ack@debbugs.gnu.org> 2021-07-05 15:39 ` [bug#49547] [PATCH v2 2/4] home-services: Add home-run-on-change-service-type Andrew Tropin ` (3 subsequent siblings) 4 siblings, 1 reply; 38+ messages in thread From: Andrew Tropin @ 2021-07-05 15:37 UTC (permalink / raw) To: 49546 home-service-type is a root of home services DAG. home-profile-service-type is almost the same as profile-service-type, at least for now. home-environment-variables-service-type generates a @file{setup-environment} shell script, which is expected to be sourced by login shell or other program, which starts early and spawns all other processes. Home services for shells automatically add code for sourcing this file, if person do not use those home services they have to source this script manually in their's shell *profile file (details described in the manual). home-files-service-type is similar to etc-service-type, but doesn't extend home-activation, because deploy mechanism for config files is pluggable and can be different for different home environments: The default one is called symlink-manager (will be introudced in a separate patch series), which creates links for various dotfiles (like $XDG_CONFIG_HOME/$APP/...) to store, but is possible to implement alternative approaches like read-only home from Julien's guix-home-manager. home-run-on-first-login-service-type provides an @file{on-first-login} guile script, which runs provided gexps once, when user makes first login. It can be used to start user's Shepherd and maybe some other process. It relies on assumption that /run/user/$UID will be created on login by some login manager (elogind for example). home-activation-service-type provides an @file{activate} guile script, which do three main things: - Sets environment variables to the values declared in @file{setup-environment} shell script. It's necessary, because user can set for example XDG_CONFIG_HOME and it should be respected by activation gexp of symlink-manager. - Sets GUIX_NEW_HOME and possibly GUIX_OLD_HOME vars to paths in the store. Later those variables can be used by activation gexps, for example by symlink-manager or run-on-change services. - Run all activation gexps provided by other home services. --- gnu/home-services.scm | 328 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 gnu/home-services.scm diff --git a/gnu/home-services.scm b/gnu/home-services.scm new file mode 100644 index 0000000000..a89a061a81 --- /dev/null +++ b/gnu/home-services.scm @@ -0,0 +1,328 @@ +;;; 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) + #:use-module (gnu services) + #:use-module (guix channels) + #:use-module (guix monads) + #:use-module (guix store) + #:use-module (guix gexp) + #:use-module (guix profiles) + #:use-module (guix sets) + #:use-module (guix ui) + #:use-module (guix discovery) + #:use-module (guix diagnostics) + + #:use-module (srfi srfi-1) + #:use-module (ice-9 match) + + #:export (home-service-type + home-profile-service-type + home-environment-variables-service-type + home-files-service-type + home-run-on-first-login-service-type + home-activation-service-type) + + #:re-export (service + service-type + service-extension)) + +;;; Comment: +;;; +;;; This module is similar to (gnu system services) module, but +;;; provides Home Services, which are supposed to be used for building +;;; home-environment. +;;; +;;; Home Services use the same extension as System Services. Consult +;;; (gnu system services) module or manual for more information. +;;; +;;; Code: + + +(define (home-derivation entries mextensions) + "Return as a monadic value the derivation of the 'home' +directory containing the given entries." + (mlet %store-monad ((extensions (mapm/accumulate-builds identity + mextensions))) + (lower-object + (file-union "home" (append entries (concatenate extensions)))))) + +(define home-service-type + ;; This is the ultimate service type, the root of the home service + ;; DAG. The service of this type is extended by monadic name/item + ;; pairs. These items end up in the "home-environment directory" as + ;; returned by 'home-environment-derivation'. + (service-type (name 'home) + (extensions '()) + (compose identity) + (extend home-derivation) + (default-value '()) + (description + "Build the home environment top-level directory, +which in turn refers to everything the home environment needs: its +packages, configuration files, activation script, and so on."))) + +(define (packages->profile-entry packages) + "Return a system entry for the profile containing PACKAGES." + ;; XXX: 'mlet' is needed here for one reason: to get the proper + ;; '%current-target' and '%current-target-system' bindings when + ;; 'packages->manifest' is called, and thus when the 'package-inputs' + ;; etc. procedures are called on PACKAGES. That way, conditionals in those + ;; inputs see the "correct" value of these two parameters. See + ;; <https://issues.guix.gnu.org/44952>. + (mlet %store-monad ((_ (current-target-system))) + (return `(("profile" ,(profile + (content (packages->manifest + (map identity + ;;(options->transformation transformations) + (delete-duplicates packages eq?)))))))))) + +;; MAYBE: Add a list of transformations for packages. It's better to +;; place it in home-profile-service-type to affect all profile +;; packages and prevent conflicts, when other packages relies on +;; non-transformed version of package. +(define home-profile-service-type + (service-type (name 'home-profile) + (extensions + (list (service-extension home-service-type + packages->profile-entry))) + (compose concatenate) + (extend append) + (description + "This is the @dfn{home profile} and can be found in +@file{~/.guix-home/profile}. It contains packages and +configuration files that the user has declared in their +@code{home-environment} record."))) + +(define (environment-variables->setup-environment-script vars) + "Return a file that can be sourced by a POSIX compliant shell which +initializes the environment. The file will source the home +environment profile, set some default environment variables, and set +environment variables provided in @code{vars}. @code{vars} is a list +of pairs (@code{(key . value)}), @code{key} is a string and +@code{value} is a string or gexp. + +If value is @code{#f} variable will be omitted. +If value is @code{#t} variable will be just exported. +For any other, value variable will be set to the @code{value} and +exported." + (define (warn-about-duplicate-defenitions) + (fold + (lambda (x acc) + (when (equal? (car x) (car acc)) + (warning + (G_ "duplicate definition for `~a' environment variable ~%") (car x))) + x) + (cons "" "") + (sort vars (lambda (a b) + (string<? (car a) (car b)))))) + + (warn-about-duplicate-defenitions) + (with-monad + %store-monad + (return + `(("setup-environment" + ;; TODO: It's necessary to source ~/.guix-profile too + ;; on foreign distros + ,(apply mixed-text-file "setup-environment" + "\ +HOME_ENVIRONMENT=$HOME/.guix-home +GUIX_PROFILE=\"$HOME_ENVIRONMENT/profile\" +PROFILE_FILE=\"$HOME_ENVIRONMENT/profile/etc/profile\" +[ -f $PROFILE_FILE ] && . $PROFILE_FILE + +case $XDG_DATA_DIRS in + *$HOME_ENVIRONMENT/profile/share*) ;; + *) export XDG_DATA_DIRS=$HOME_ENVIRONMENT/profile/share:$XDG_DATA_DIRS ;; +esac +case $MANPATH in + *$HOME_ENVIRONMENT/profile/share/man*) ;; + *) export MANPATH=$HOME_ENVIRONMENT/profile/share/man:$MANPATH +esac +case $INFOPATH in + *$HOME_ENVIRONMENT/profile/share/info*) ;; + *) export INFOPATH=$HOME_ENVIRONMENT/profile/share/info:$INFOPATH ;; +esac +case $XDG_CONFIG_DIRS in + *$HOME_ENVIRONMENT/profile/etc/xdg*) ;; + *) export XDG_CONFIG_DIRS=$HOME_ENVIRONMENT/profile/etc/xdg:$XDG_CONFIG_DIRS ;; +esac +case $XCURSOR_PATH in + *$HOME_ENVIRONMENT/profile/share/icons*) ;; + *) export XCURSOR_PATH=$HOME_ENVIRONMENT/profile/share/icons:$XCURSOR_PATH ;; +esac + +" + + (append-map + (match-lambda + ((key . #f) + '()) + ((key . #t) + (list "export " key "\n")) + ((key . value) + (list "export " key "=" value "\n"))) + vars))))))) + +(define home-environment-variables-service-type + (service-type (name 'home-environment-variables) + (extensions + (list (service-extension + home-service-type + environment-variables->setup-environment-script))) + (compose concatenate) + (extend append) + (default-value '()) + (description "Set the environment variables."))) + +(define (files->files-directory files) + "Return a @code{files} directory that contains FILES." + (define (assert-no-duplicates files) + (let loop ((files files) + (seen (set))) + (match files + (() #t) + (((file _) rest ...) + (when (set-contains? seen file) + (raise (formatted-message (G_ "duplicate '~a' entry for files/") + file))) + (loop rest (set-insert file seen)))))) + + ;; Detect duplicates early instead of letting them through, eventually + ;; leading to a build failure of "files.drv". + (assert-no-duplicates files) + + (file-union "files" files)) + +(define (files-entry files) + "Return an entry for the @file{~/.guix-home/files} +directory containing FILES." + (with-monad %store-monad + (return `(("files" ,(files->files-directory files)))))) + +(define home-files-service-type + (service-type (name 'home-files) + (extensions + (list (service-extension home-service-type + files-entry))) + (compose concatenate) + (extend append) + (default-value '()) + (description "Configuration files for programs that +will be put in @file{~/.guix-home/files}."))) + +(define (compute-on-first-login-script _ gexps) + (gexp->script + "on-first-login" + #~(let* ((xdg-runtime-dir (or (getenv "XDG_RUNTIME_DIR") + (format #f "/run/user/~a" (getuid)))) + (flag-file-path (string-append + xdg-runtime-dir "/on-first-login-executed")) + (touch (lambda (file-name) + (call-with-output-file file-name (const #t))))) + ;; XDG_RUNTIME_DIR dissapears on logout, that means such trick + ;; allows to launch on-first-login script on first login only + ;; after complete logout/reboot. + (when (not (file-exists? flag-file-path)) + (begin #$@gexps (touch flag-file-path)))))) + +(define (on-first-login-script-entry m-on-first-login) + "Return, as a monadic value, an entry for the on-first-login script +in the home environment directory." + (mlet %store-monad ((on-first-login m-on-first-login)) + (return `(("on-first-login" ,on-first-login))))) + +(define home-run-on-first-login-service-type + (service-type (name 'home-run-on-first-login) + (extensions + (list (service-extension + home-service-type + on-first-login-script-entry))) + (compose identity) + (extend compute-on-first-login-script) + (default-value #f) + (description "Run gexps on first user login. Can be +extended with one gexp."))) + + +(define (compute-activation-script init-gexp gexps) + (gexp->script + "activate" + #~(let* ((he-init-file (lambda (he) (string-append he "/setup-environment"))) + (he-path (string-append (getenv "HOME") "/.guix-home")) + (new-home-env (getenv "GUIX_NEW_HOME")) + (new-home (or new-home-env + ;; Path of the activation file if called interactively + (dirname (car (command-line))))) + (old-home-env (getenv "GUIX_OLD_HOME")) + (old-home (or old-home-env + (if (file-exists? (he-init-file he-path)) + (readlink he-path) + #f)))) + (if (file-exists? (he-init-file new-home)) + (let* ((port ((@ (ice-9 popen) open-input-pipe) + (format #f "source ~a && env" + (he-init-file new-home)))) + (result ((@ (ice-9 rdelim) read-delimited) "" port)) + (vars (map (lambda (x) + (let ((si (string-index x #\=))) + (cons (string-take x si) + (string-drop x (1+ si))))) + ((@ (srfi srfi-1) remove) + string-null? + (string-split result #\newline))))) + (close-port port) + (map (lambda (x) (setenv (car x) (cdr x))) vars) + + (setenv "GUIX_NEW_HOME" new-home) + (setenv "GUIX_OLD_HOME" old-home) + + #$@gexps + + ;; Do not unset env variable if it was set outside. + (unless new-home-env (setenv "GUIX_NEW_HOME" #f)) + (unless old-home-env (setenv "GUIX_OLD_HOME" #f))) + (format #t "\ +Activation script was either called or loaded by file from this direcotry: +~a +It doesn't seem that home environment is somewhere around. +Make sure that you call ./activate by symlink from -home store item.\n" + new-home))))) + +(define (activation-script-entry m-activation) + "Return, as a monadic value, an entry for the activation script +in the home environment directory." + (mlet %store-monad ((activation m-activation)) + (return `(("activate" ,activation))))) + +(define home-activation-service-type + (service-type (name 'home-activation) + (extensions + (list (service-extension + home-service-type + activation-script-entry))) + (compose identity) + (extend compute-activation-script) + (default-value #f) + (description "Run gexps to activate the current +generation of home environment and update the state of the home +directory. @command{activate} script automatically called during +reconfiguration or generation switching. This service can be extended +with one gexp, but many times, and all gexps must be idempotent."))) + -- 2.32.0 ^ permalink raw reply related [flat|nested] 38+ messages in thread
[parent not found: <handler.49546.B.16262002971832.ack@debbugs.gnu.org>]
* [bug#49546] Acknowledgement ([PATCH v2 1/4] home-services: Add most essential home services) [not found] ` <handler.49546.B.16262002971832.ack@debbugs.gnu.org> @ 2021-07-13 18:24 ` Andrew Tropin 0 siblings, 0 replies; 38+ messages in thread From: Andrew Tropin @ 2021-07-13 18:24 UTC (permalink / raw) To: 49546 [-- Attachment #1: Type: text/plain, Size: 742 bytes --] help-debbugs@gnu.org (GNU bug Tracking System) writes: > Thank you for filing a new bug report with debbugs.gnu.org. > > This is an automatically generated reply to let you know your message > has been received. > > Your message is being forwarded to the package maintainers and other > interested parties for their attention; they will reply in due course. > > Your message has been sent to the package maintainer(s): > guix-patches@gnu.org > > If you wish to submit further information on this problem, please > send it to 49546@debbugs.gnu.org. > > Please do not send mail to help-debbugs@gnu.org unless you wish > to report a problem with the Bug-tracking system. It's strange, do I need to wait more, before replying to cover letter? [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply [flat|nested] 38+ messages in thread
* [bug#49547] [PATCH v2 2/4] home-services: Add home-run-on-change-service-type 2021-07-13 16:17 ` [bug#49419] [PATCH v2 0/4] Essential home services Andrew Tropin 2021-07-05 15:37 ` [bug#49546] [PATCH v2 1/4] home-services: Add most essential " Andrew Tropin @ 2021-07-05 15:39 ` Andrew Tropin 2021-07-14 10:41 ` Maxime Devos 2021-07-05 15:41 ` [bug#49548] [PATCH v2 3/4] home-services: Add home-provenance-service-type Andrew Tropin ` (2 subsequent siblings) 4 siblings, 1 reply; 38+ messages in thread From: Andrew Tropin @ 2021-07-05 15:39 UTC (permalink / raw) To: 49547 Service allows to trigger actions during activation if file or directory specified by pattern is changed. --- gnu/home-services.scm | 95 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-) diff --git a/gnu/home-services.scm b/gnu/home-services.scm index a89a061a81..fadad3133e 100644 --- a/gnu/home-services.scm +++ b/gnu/home-services.scm @@ -37,7 +37,8 @@ home-environment-variables-service-type home-files-service-type home-run-on-first-login-service-type - home-activation-service-type) + home-activation-service-type + home-run-on-change-service-type) #:re-export (service service-type @@ -326,3 +327,95 @@ directory. @command{activate} script automatically called during reconfiguration or generation switching. This service can be extended with one gexp, but many times, and all gexps must be idempotent."))) +\f +;;; +;;; On-change. +;;; + +(define (compute-on-change-gexp eval-gexps? pattern-gexp-tuples) + #~(begin + (define (equal-regulars? file1 file2) + "Check if FILE1 and FILE2 are bit for bit identical." + (let* ((cmp-binary #$(file-append + (@ (gnu packages base) diffutils) "/bin/cmp")) + (status (system* cmp-binary file1 file2))) + (= status 0))) + + (define (equal-symlinks? symlink1 symlink2) + "Check if SYMLINK1 and SYMLINK2 are pointing to the same target." + (string=? (readlink symlink1) (readlink symlink2))) + + (define (equal-directories? dir1 dir2) + "Check if DIR1 and DIR2 have the same content." + (define (ordinary-file file) + (not (or (string=? file ".") + (string=? file "..")))) + (let* ((files1 (scandir dir1 ordinary-file)) + (files2 (scandir dir2 ordinary-file))) + (if (equal? files1 files2) + (map (lambda (file) + (equal-files? + (string-append dir1 "/" file) + (string-append dir2 "/" file))) + files1) + #f))) + + (define (equal-files? file1 file2) + "Compares files, symlinks or directories of the same type." + (case (file-type file1) + ((directory) (equal-directories? file1 file2)) + ((symlink) (equal-symlinks? file1 file2)) + ((regular) (equal-regulars? file1 file2)) + (else + (display "The file type is unsupported by on-change service.\n") + #f))) + + (define (file-type file) + (stat:type (lstat file))) + + (define (something-changed? file1 file2) + (cond + ((and (not (file-exists? file1)) + (not (file-exists? file2))) #f) + ((or (not (file-exists? file1)) + (not (file-exists? file2))) #t) + + ((not (eq? (file-type file1) (file-type file2))) #t) + + (else + (not (equal-files? file1 file2))))) + + (define expressions-to-eval + (map + (lambda (x) + (let* ((file1 (string-append (getenv "GUIX_OLD_HOME") "/" (car x))) + (file2 (string-append (getenv "GUIX_NEW_HOME") "/" (car x))) + (_ (format #t "Comparing ~a and\n~10t~a..." file1 file2)) + (any-changes? (something-changed? file1 file2)) + (_ (format #t " done (~a)\n" + (if any-changes? "changed" "same")))) + (if any-changes? (cadr x) ""))) + '#$pattern-gexp-tuples)) + + (if #$eval-gexps? + (begin + (display "Evaling on-change gexps.\n\n") + (for-each primitive-eval expressions-to-eval) + (display "On-change gexps evaluation finished.\n\n")) + (display "\ +On-change gexps won't evaluated, disabled by service configuration.\n")))) + +(define home-run-on-change-service-type + (service-type (name 'home-run-on-change) + (extensions + (list (service-extension + home-activation-service-type + identity))) + (compose concatenate) + (extend compute-on-change-gexp) + (default-value #t) + (description "\ +G-expressions to run if the specified files have changed since the +last generation. The extension should be a list of lists where the +first element is the pattern for file or directory that expected to be +changed, and the second element is the G-expression to be evaluated."))) -- 2.32.0 ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [bug#49547] [PATCH v2 2/4] home-services: Add home-run-on-change-service-type 2021-07-05 15:39 ` [bug#49547] [PATCH v2 2/4] home-services: Add home-run-on-change-service-type Andrew Tropin @ 2021-07-14 10:41 ` Maxime Devos 2021-07-15 8:46 ` Andrew Tropin 0 siblings, 1 reply; 38+ messages in thread From: Maxime Devos @ 2021-07-14 10:41 UTC (permalink / raw) To: Andrew Tropin, 49547 [-- Attachment #1: Type: text/plain, Size: 1267 bytes --] Andrew Tropin schreef op ma 05-07-2021 om 18:39 [+0300]: > + (define (equal-regulars? file1 file2) > + "Check if FILE1 and FILE2 are bit for bit identical." > + (let* ((cmp-binary #$(file-append > + (@ (gnu packages base) diffutils) "/bin/cmp")) > + (status (system* cmp-binary file1 file2))) > + (= status 0))) Is there any particular reason to shell out to "cmp" instead of doing the comparison in Guile? Starting a process isn't the most efficient thing. Try "time /run/current-system/profile/bin echo", on my system, it takes about 2--3 milliseconds for "echo" to finish even though it only had to print a newline character. Compare with "time echo" (to use the shell built-in "echo"), it takes 0.000s seconds on my system. 3 milliseconds isn't much by itself, but this can accumulate, so I would implement the comparison in Guile. As an optimisation, you could look at the value returned by "lstat". If the 'size' is different, then 'equal-regulars?' can return #f without reading the file. If the 'inode' and 'device' are equal, then 'equal-regulars?' can return #t I think (at least on conventional file systems like btrfs and ext4). Greetings, Maxime. [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 260 bytes --] ^ permalink raw reply [flat|nested] 38+ messages in thread
* [bug#49547] [PATCH v2 2/4] home-services: Add home-run-on-change-service-type 2021-07-14 10:41 ` Maxime Devos @ 2021-07-15 8:46 ` Andrew Tropin 2021-07-18 16:17 ` Maxime Devos 0 siblings, 1 reply; 38+ messages in thread From: Andrew Tropin @ 2021-07-15 8:46 UTC (permalink / raw) To: Maxime Devos, 49547 [-- Attachment #1.1: Type: text/plain, Size: 2261 bytes --] Maxime Devos <maximedevos@telenet.be> writes: > Andrew Tropin schreef op ma 05-07-2021 om 18:39 [+0300]: >> + (define (equal-regulars? file1 file2) >> + "Check if FILE1 and FILE2 are bit for bit identical." >> + (let* ((cmp-binary #$(file-append >> + (@ (gnu packages base) diffutils) "/bin/cmp")) >> + (status (system* cmp-binary file1 file2))) >> + (= status 0))) > > Is there any particular reason to shell out to "cmp" instead > of doing the comparison in Guile? Starting a process isn't > the most efficient thing. > > Try "time /run/current-system/profile/bin echo", on my system, > it takes about 2--3 milliseconds for "echo" to finish > even though it only had to print a newline character. > Compare with "time echo" (to use the shell built-in "echo"), > it takes 0.000s seconds on my system. > > 3 milliseconds isn't much by itself, but this can accumulate, > so I would implement the comparison in Guile. > > As an optimisation, you could look at the value returned by "lstat". > If the 'size' is different, then 'equal-regulars?' can return #f > without reading the file. If the 'inode' and 'device' are equal, > then 'equal-regulars?' can return #t I think (at least on conventional > file systems like btrfs and ext4). No specific reason. Yep, spawning a new process can be expensive, but it's not clear how much time will take the comparison itself and if it worth it to optimize "startup time". I'm not very fluent with guile internals and not sure if reimplementation of cmp in guile would improve or worsen the performance, but it obviously could intoduce some bugs. I found Xinglu's idea of the usage of well-tested cmp to be a reasonable solution here. Also, this service is expected to be used with small amount of files and because many of them are symlinks to the store even smaller number of them will trigger the execution of cmp, so I find the performance optimization to be preliminary here and propose to address the issue when and if it appear someday. However, the ideas about size and inodes are good, easy to implement and I find them potentially useful to prevent unecessary external process spawning. The patch with those improvements are below: [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1.2: 0001-toberebased-home-services-Prevent-unecessary-system-.patch --] [-- Type: text/x-patch, Size: 1295 bytes --] From 8dd0c06fb64c8b516418cbdf8c385a6c817e7f26 Mon Sep 17 00:00:00 2001 From: Andrew Tropin <andrew@trop.in> Date: Thu, 15 Jul 2021 09:44:30 +0300 Subject: [PATCH] (toberebased) home-services: Prevent unecessary system* call --- gnu/home-services.scm | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/gnu/home-services.scm b/gnu/home-services.scm index 78e5603edf..9afb70f0a7 100644 --- a/gnu/home-services.scm +++ b/gnu/home-services.scm @@ -341,8 +341,13 @@ with one gexp, but many times, and all gexps must be idempotent."))) "Check if FILE1 and FILE2 are bit for bit identical." (let* ((cmp-binary #$(file-append (@ (gnu packages base) diffutils) "/bin/cmp")) - (status (system* cmp-binary file1 file2))) - (= status 0))) + (stats1 (lstat file1)) + (stats2 (lstat file2))) + (cond + ((= (stat:ino stats1) (stat:ino stats2)) #t) + ((not (= (stat:size stats1) (stat:size stats2))) #f) + + (else (= (system* cmp-binary file1 file2) 0))))) (define (equal-symlinks? symlink1 symlink2) "Check if SYMLINK1 and SYMLINK2 are pointing to the same target." -- 2.32.0 [-- Attachment #1.3: Type: text/plain, Size: 29 bytes --] Thank you for suggestions!) [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [bug#49547] [PATCH v2 2/4] home-services: Add home-run-on-change-service-type 2021-07-15 8:46 ` Andrew Tropin @ 2021-07-18 16:17 ` Maxime Devos 0 siblings, 0 replies; 38+ messages in thread From: Maxime Devos @ 2021-07-18 16:17 UTC (permalink / raw) To: Andrew Tropin, 49547 [-- Attachment #1: Type: text/plain, Size: 1116 bytes --] Andrew Tropin schreef op do 15-07-2021 om 11:46 [+0300]: > No specific reason. Yep, spawning a new process can be expensive, but > it's not clear how much time will take the comparison itself and if it > worth it to optimize "startup time". I'm not very fluent with guile > internals and not sure if reimplementation of cmp in guile would improve > or worsen the performance, but it obviously could intoduce some bugs. I > found Xinglu's idea of the usage of well-tested cmp to be a reasonable > solution here. Sounds reasonable to me. > Also, this service is expected to be used with small amount of files and > because many of them are symlinks to the store even smaller number of > them will trigger the execution of cmp, so I find the performance > optimization to be preliminary here and propose to address the issue > when and if it appear someday. > > However, the ideas about size and inodes are good, easy to implement and > I find them potentially useful to prevent unecessary external process > spawning. The patch with those improvements are below: [...] Greetings, Maxime. [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 260 bytes --] ^ permalink raw reply [flat|nested] 38+ messages in thread
* [bug#49548] [PATCH v2 3/4] home-services: Add home-provenance-service-type 2021-07-13 16:17 ` [bug#49419] [PATCH v2 0/4] Essential home services Andrew Tropin 2021-07-05 15:37 ` [bug#49546] [PATCH v2 1/4] home-services: Add most essential " Andrew Tropin 2021-07-05 15:39 ` [bug#49547] [PATCH v2 2/4] home-services: Add home-run-on-change-service-type Andrew Tropin @ 2021-07-05 15:41 ` Andrew Tropin 2021-07-05 15:41 ` [bug#49549] [PATCH v2 4/4] home-services: Add fold-home-service-types function Andrew Tropin 2021-07-15 9:59 ` [bug#49568] Testing reply without debbugs address Andrew Tropin 4 siblings, 0 replies; 38+ messages in thread From: Andrew Tropin @ 2021-07-05 15:41 UTC (permalink / raw) To: 49548 * gnu/home-services.scm (home-provenance-service-type, sexp->home-provenance, home-provenance): New variables. --- gnu/home-services.scm | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/gnu/home-services.scm b/gnu/home-services.scm index fadad3133e..ffcee22bb8 100644 --- a/gnu/home-services.scm +++ b/gnu/home-services.scm @@ -38,7 +38,10 @@ home-files-service-type home-run-on-first-login-service-type home-activation-service-type - home-run-on-change-service-type) + home-run-on-change-service-type + home-provenance-service-type + + fold-home-service-types) #:re-export (service service-type @@ -419,3 +422,25 @@ G-expressions to run if the specified files have changed since the last generation. The extension should be a list of lists where the first element is the pattern for file or directory that expected to be changed, and the second element is the G-expression to be evaluated."))) + +\f +;;; +;;; Provenance tracking. +;;; + +(define home-provenance-service-type + (service-type + (name 'home-provenance) + (extensions + (list (service-extension + home-service-type + (service-extension-compute + (first (service-type-extensions provenance-service-type)))))) + (default-value #f) ;the HE config file + (description "\ +Store provenance information about the home environment in the home +environment itself: the channels used when building the home +environment, and its configuration file, when available."))) + +(define sexp->home-provenance sexp->system-provenance) +(define home-provenance system-provenance) -- 2.32.0 ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [bug#49549] [PATCH v2 4/4] home-services: Add fold-home-service-types function 2021-07-13 16:17 ` [bug#49419] [PATCH v2 0/4] Essential home services Andrew Tropin ` (2 preceding siblings ...) 2021-07-05 15:41 ` [bug#49548] [PATCH v2 3/4] home-services: Add home-provenance-service-type Andrew Tropin @ 2021-07-05 15:41 ` Andrew Tropin 2021-07-15 9:59 ` [bug#49568] Testing reply without debbugs address Andrew Tropin 4 siblings, 0 replies; 38+ messages in thread From: Andrew Tropin @ 2021-07-05 15:41 UTC (permalink / raw) To: 49549 * gnu/home-services.scm (parent-directory, %guix-home-root-directory, %service-type-path, all-home-service-modules, fold-home-service-types): New variables. --- gnu/home-services.scm | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/gnu/home-services.scm b/gnu/home-services.scm index ffcee22bb8..78e5603edf 100644 --- a/gnu/home-services.scm +++ b/gnu/home-services.scm @@ -444,3 +444,29 @@ environment, and its configuration file, when available."))) (define sexp->home-provenance sexp->system-provenance) (define home-provenance system-provenance) + +\f +;;; +;;; Searching +;;; + +(define (parent-directory directory) + "Get the parent directory of DIRECTORY" + (string-join (drop-right (string-split directory #\/) 1) "/")) + +(define %guix-home-root-directory + ;; Absolute file name of the module hierarchy. + (parent-directory (dirname (search-path %load-path "gnu/home-services.scm")))) + +(define %service-type-path + ;; Search path for service types. + (make-parameter `((,%guix-home-root-directory . "gnu/home-services")))) + +(define (all-home-service-modules) + "Return the default set of home-service modules." + (cons (resolve-interface '(gnu home-services)) + (all-modules (%service-type-path) + #:warn warn-about-load-error))) + +(define* (fold-home-service-types proc seed) + (fold-service-types proc seed (all-home-service-modules))) -- 2.32.0 ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [bug#49568] Testing reply without debbugs address 2021-07-13 16:17 ` [bug#49419] [PATCH v2 0/4] Essential home services Andrew Tropin ` (3 preceding siblings ...) 2021-07-05 15:41 ` [bug#49549] [PATCH v2 4/4] home-services: Add fold-home-service-types function Andrew Tropin @ 2021-07-15 9:59 ` Andrew Tropin 4 siblings, 0 replies; 38+ messages in thread From: Andrew Tropin @ 2021-07-15 9:59 UTC (permalink / raw) To: 49568 [-- Attachment #1: Type: text/plain, Size: 146 bytes --] Replying to guix-patches to check if the message will be correctly attached to the thread by In-Reply-To header without creating debbugs ticket. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH v3 0/4] Essential home services 2021-07-05 15:35 [bug#49419] [PATCH 0/4] Essential home services Andrew Tropin ` (4 preceding siblings ...) 2021-07-13 16:17 ` [bug#49419] [PATCH v2 0/4] Essential home services Andrew Tropin @ 2021-07-19 8:04 ` Andrew Tropin 2021-07-05 15:37 ` [bug#49419] [PATCH v3 1/4] home-services: Add most essential " Andrew Tropin ` (4 more replies) [not found] ` <handler.49419.B.162549932625345.ack@debbugs.gnu.org> 6 siblings, 5 replies; 38+ messages in thread From: Andrew Tropin @ 2021-07-19 8:04 UTC (permalink / raw) To: 49419 [-- Attachment #1: Type: text/plain, Size: 527 bytes --] Diff with v2: Prevents unecessary calls to system* Please, when review finished, apply against guix-home-wip branch. Andrew Tropin (4): home-services: Add most essential home services home-services: Add home-run-on-change-service-type home-services: Add home-provenance-service-type home-services: Add fold-home-service-types function gnu/home-services.scm | 477 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 477 insertions(+) create mode 100644 gnu/home-services.scm -- 2.32.0 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH v3 1/4] home-services: Add most essential home services 2021-07-19 8:04 ` [bug#49419] [PATCH v3 0/4] Essential home services Andrew Tropin @ 2021-07-05 15:37 ` Andrew Tropin 2021-07-05 15:39 ` [bug#49419] [PATCH v3 2/4] home-services: Add home-run-on-change-service-type Andrew Tropin ` (3 subsequent siblings) 4 siblings, 0 replies; 38+ messages in thread From: Andrew Tropin @ 2021-07-05 15:37 UTC (permalink / raw) To: 49419 [-- Attachment #1: Type: text/plain, Size: 15746 bytes --] home-service-type is a root of home services DAG. home-profile-service-type is almost the same as profile-service-type, at least for now. home-environment-variables-service-type generates a @file{setup-environment} shell script, which is expected to be sourced by login shell or other program, which starts early and spawns all other processes. Home services for shells automatically add code for sourcing this file, if person do not use those home services they have to source this script manually in their's shell *profile file (details described in the manual). home-files-service-type is similar to etc-service-type, but doesn't extend home-activation, because deploy mechanism for config files is pluggable and can be different for different home environments: The default one is called symlink-manager (will be introudced in a separate patch series), which creates links for various dotfiles (like $XDG_CONFIG_HOME/$APP/...) to store, but is possible to implement alternative approaches like read-only home from Julien's guix-home-manager. home-run-on-first-login-service-type provides an @file{on-first-login} guile script, which runs provided gexps once, when user makes first login. It can be used to start user's Shepherd and maybe some other process. It relies on assumption that /run/user/$UID will be created on login by some login manager (elogind for example). home-activation-service-type provides an @file{activate} guile script, which do three main things: - Sets environment variables to the values declared in @file{setup-environment} shell script. It's necessary, because user can set for example XDG_CONFIG_HOME and it should be respected by activation gexp of symlink-manager. - Sets GUIX_NEW_HOME and possibly GUIX_OLD_HOME vars to paths in the store. Later those variables can be used by activation gexps, for example by symlink-manager or run-on-change services. - Run all activation gexps provided by other home services. --- gnu/home-services.scm | 328 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 gnu/home-services.scm diff --git a/gnu/home-services.scm b/gnu/home-services.scm new file mode 100644 index 0000000000..a89a061a81 --- /dev/null +++ b/gnu/home-services.scm @@ -0,0 +1,328 @@ +;;; 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) + #:use-module (gnu services) + #:use-module (guix channels) + #:use-module (guix monads) + #:use-module (guix store) + #:use-module (guix gexp) + #:use-module (guix profiles) + #:use-module (guix sets) + #:use-module (guix ui) + #:use-module (guix discovery) + #:use-module (guix diagnostics) + + #:use-module (srfi srfi-1) + #:use-module (ice-9 match) + + #:export (home-service-type + home-profile-service-type + home-environment-variables-service-type + home-files-service-type + home-run-on-first-login-service-type + home-activation-service-type) + + #:re-export (service + service-type + service-extension)) + +;;; Comment: +;;; +;;; This module is similar to (gnu system services) module, but +;;; provides Home Services, which are supposed to be used for building +;;; home-environment. +;;; +;;; Home Services use the same extension as System Services. Consult +;;; (gnu system services) module or manual for more information. +;;; +;;; Code: + + +(define (home-derivation entries mextensions) + "Return as a monadic value the derivation of the 'home' +directory containing the given entries." + (mlet %store-monad ((extensions (mapm/accumulate-builds identity + mextensions))) + (lower-object + (file-union "home" (append entries (concatenate extensions)))))) + +(define home-service-type + ;; This is the ultimate service type, the root of the home service + ;; DAG. The service of this type is extended by monadic name/item + ;; pairs. These items end up in the "home-environment directory" as + ;; returned by 'home-environment-derivation'. + (service-type (name 'home) + (extensions '()) + (compose identity) + (extend home-derivation) + (default-value '()) + (description + "Build the home environment top-level directory, +which in turn refers to everything the home environment needs: its +packages, configuration files, activation script, and so on."))) + +(define (packages->profile-entry packages) + "Return a system entry for the profile containing PACKAGES." + ;; XXX: 'mlet' is needed here for one reason: to get the proper + ;; '%current-target' and '%current-target-system' bindings when + ;; 'packages->manifest' is called, and thus when the 'package-inputs' + ;; etc. procedures are called on PACKAGES. That way, conditionals in those + ;; inputs see the "correct" value of these two parameters. See + ;; <https://issues.guix.gnu.org/44952>. + (mlet %store-monad ((_ (current-target-system))) + (return `(("profile" ,(profile + (content (packages->manifest + (map identity + ;;(options->transformation transformations) + (delete-duplicates packages eq?)))))))))) + +;; MAYBE: Add a list of transformations for packages. It's better to +;; place it in home-profile-service-type to affect all profile +;; packages and prevent conflicts, when other packages relies on +;; non-transformed version of package. +(define home-profile-service-type + (service-type (name 'home-profile) + (extensions + (list (service-extension home-service-type + packages->profile-entry))) + (compose concatenate) + (extend append) + (description + "This is the @dfn{home profile} and can be found in +@file{~/.guix-home/profile}. It contains packages and +configuration files that the user has declared in their +@code{home-environment} record."))) + +(define (environment-variables->setup-environment-script vars) + "Return a file that can be sourced by a POSIX compliant shell which +initializes the environment. The file will source the home +environment profile, set some default environment variables, and set +environment variables provided in @code{vars}. @code{vars} is a list +of pairs (@code{(key . value)}), @code{key} is a string and +@code{value} is a string or gexp. + +If value is @code{#f} variable will be omitted. +If value is @code{#t} variable will be just exported. +For any other, value variable will be set to the @code{value} and +exported." + (define (warn-about-duplicate-defenitions) + (fold + (lambda (x acc) + (when (equal? (car x) (car acc)) + (warning + (G_ "duplicate definition for `~a' environment variable ~%") (car x))) + x) + (cons "" "") + (sort vars (lambda (a b) + (string<? (car a) (car b)))))) + + (warn-about-duplicate-defenitions) + (with-monad + %store-monad + (return + `(("setup-environment" + ;; TODO: It's necessary to source ~/.guix-profile too + ;; on foreign distros + ,(apply mixed-text-file "setup-environment" + "\ +HOME_ENVIRONMENT=$HOME/.guix-home +GUIX_PROFILE=\"$HOME_ENVIRONMENT/profile\" +PROFILE_FILE=\"$HOME_ENVIRONMENT/profile/etc/profile\" +[ -f $PROFILE_FILE ] && . $PROFILE_FILE + +case $XDG_DATA_DIRS in + *$HOME_ENVIRONMENT/profile/share*) ;; + *) export XDG_DATA_DIRS=$HOME_ENVIRONMENT/profile/share:$XDG_DATA_DIRS ;; +esac +case $MANPATH in + *$HOME_ENVIRONMENT/profile/share/man*) ;; + *) export MANPATH=$HOME_ENVIRONMENT/profile/share/man:$MANPATH +esac +case $INFOPATH in + *$HOME_ENVIRONMENT/profile/share/info*) ;; + *) export INFOPATH=$HOME_ENVIRONMENT/profile/share/info:$INFOPATH ;; +esac +case $XDG_CONFIG_DIRS in + *$HOME_ENVIRONMENT/profile/etc/xdg*) ;; + *) export XDG_CONFIG_DIRS=$HOME_ENVIRONMENT/profile/etc/xdg:$XDG_CONFIG_DIRS ;; +esac +case $XCURSOR_PATH in + *$HOME_ENVIRONMENT/profile/share/icons*) ;; + *) export XCURSOR_PATH=$HOME_ENVIRONMENT/profile/share/icons:$XCURSOR_PATH ;; +esac + +" + + (append-map + (match-lambda + ((key . #f) + '()) + ((key . #t) + (list "export " key "\n")) + ((key . value) + (list "export " key "=" value "\n"))) + vars))))))) + +(define home-environment-variables-service-type + (service-type (name 'home-environment-variables) + (extensions + (list (service-extension + home-service-type + environment-variables->setup-environment-script))) + (compose concatenate) + (extend append) + (default-value '()) + (description "Set the environment variables."))) + +(define (files->files-directory files) + "Return a @code{files} directory that contains FILES." + (define (assert-no-duplicates files) + (let loop ((files files) + (seen (set))) + (match files + (() #t) + (((file _) rest ...) + (when (set-contains? seen file) + (raise (formatted-message (G_ "duplicate '~a' entry for files/") + file))) + (loop rest (set-insert file seen)))))) + + ;; Detect duplicates early instead of letting them through, eventually + ;; leading to a build failure of "files.drv". + (assert-no-duplicates files) + + (file-union "files" files)) + +(define (files-entry files) + "Return an entry for the @file{~/.guix-home/files} +directory containing FILES." + (with-monad %store-monad + (return `(("files" ,(files->files-directory files)))))) + +(define home-files-service-type + (service-type (name 'home-files) + (extensions + (list (service-extension home-service-type + files-entry))) + (compose concatenate) + (extend append) + (default-value '()) + (description "Configuration files for programs that +will be put in @file{~/.guix-home/files}."))) + +(define (compute-on-first-login-script _ gexps) + (gexp->script + "on-first-login" + #~(let* ((xdg-runtime-dir (or (getenv "XDG_RUNTIME_DIR") + (format #f "/run/user/~a" (getuid)))) + (flag-file-path (string-append + xdg-runtime-dir "/on-first-login-executed")) + (touch (lambda (file-name) + (call-with-output-file file-name (const #t))))) + ;; XDG_RUNTIME_DIR dissapears on logout, that means such trick + ;; allows to launch on-first-login script on first login only + ;; after complete logout/reboot. + (when (not (file-exists? flag-file-path)) + (begin #$@gexps (touch flag-file-path)))))) + +(define (on-first-login-script-entry m-on-first-login) + "Return, as a monadic value, an entry for the on-first-login script +in the home environment directory." + (mlet %store-monad ((on-first-login m-on-first-login)) + (return `(("on-first-login" ,on-first-login))))) + +(define home-run-on-first-login-service-type + (service-type (name 'home-run-on-first-login) + (extensions + (list (service-extension + home-service-type + on-first-login-script-entry))) + (compose identity) + (extend compute-on-first-login-script) + (default-value #f) + (description "Run gexps on first user login. Can be +extended with one gexp."))) + + +(define (compute-activation-script init-gexp gexps) + (gexp->script + "activate" + #~(let* ((he-init-file (lambda (he) (string-append he "/setup-environment"))) + (he-path (string-append (getenv "HOME") "/.guix-home")) + (new-home-env (getenv "GUIX_NEW_HOME")) + (new-home (or new-home-env + ;; Path of the activation file if called interactively + (dirname (car (command-line))))) + (old-home-env (getenv "GUIX_OLD_HOME")) + (old-home (or old-home-env + (if (file-exists? (he-init-file he-path)) + (readlink he-path) + #f)))) + (if (file-exists? (he-init-file new-home)) + (let* ((port ((@ (ice-9 popen) open-input-pipe) + (format #f "source ~a && env" + (he-init-file new-home)))) + (result ((@ (ice-9 rdelim) read-delimited) "" port)) + (vars (map (lambda (x) + (let ((si (string-index x #\=))) + (cons (string-take x si) + (string-drop x (1+ si))))) + ((@ (srfi srfi-1) remove) + string-null? + (string-split result #\newline))))) + (close-port port) + (map (lambda (x) (setenv (car x) (cdr x))) vars) + + (setenv "GUIX_NEW_HOME" new-home) + (setenv "GUIX_OLD_HOME" old-home) + + #$@gexps + + ;; Do not unset env variable if it was set outside. + (unless new-home-env (setenv "GUIX_NEW_HOME" #f)) + (unless old-home-env (setenv "GUIX_OLD_HOME" #f))) + (format #t "\ +Activation script was either called or loaded by file from this direcotry: +~a +It doesn't seem that home environment is somewhere around. +Make sure that you call ./activate by symlink from -home store item.\n" + new-home))))) + +(define (activation-script-entry m-activation) + "Return, as a monadic value, an entry for the activation script +in the home environment directory." + (mlet %store-monad ((activation m-activation)) + (return `(("activate" ,activation))))) + +(define home-activation-service-type + (service-type (name 'home-activation) + (extensions + (list (service-extension + home-service-type + activation-script-entry))) + (compose identity) + (extend compute-activation-script) + (default-value #f) + (description "Run gexps to activate the current +generation of home environment and update the state of the home +directory. @command{activate} script automatically called during +reconfiguration or generation switching. This service can be extended +with one gexp, but many times, and all gexps must be idempotent."))) + -- 2.32.0 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH v3 2/4] home-services: Add home-run-on-change-service-type 2021-07-19 8:04 ` [bug#49419] [PATCH v3 0/4] Essential home services Andrew Tropin 2021-07-05 15:37 ` [bug#49419] [PATCH v3 1/4] home-services: Add most essential " Andrew Tropin @ 2021-07-05 15:39 ` Andrew Tropin 2021-07-05 15:41 ` [bug#49419] [PATCH v3 3/4] home-services: Add home-provenance-service-type Andrew Tropin ` (2 subsequent siblings) 4 siblings, 0 replies; 38+ messages in thread From: Andrew Tropin @ 2021-07-05 15:39 UTC (permalink / raw) To: 49419 [-- Attachment #1: Type: text/plain, Size: 4951 bytes --] Service allows to trigger actions during activation if file or directory specified by pattern is changed. --- gnu/home-services.scm | 100 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/gnu/home-services.scm b/gnu/home-services.scm index a89a061a81..bcb6dd80df 100644 --- a/gnu/home-services.scm +++ b/gnu/home-services.scm @@ -37,7 +37,8 @@ home-environment-variables-service-type home-files-service-type home-run-on-first-login-service-type - home-activation-service-type) + home-activation-service-type + home-run-on-change-service-type) #:re-export (service service-type @@ -326,3 +327,100 @@ directory. @command{activate} script automatically called during reconfiguration or generation switching. This service can be extended with one gexp, but many times, and all gexps must be idempotent."))) +\f +;;; +;;; On-change. +;;; + +(define (compute-on-change-gexp eval-gexps? pattern-gexp-tuples) + #~(begin + (define (equal-regulars? file1 file2) + "Check if FILE1 and FILE2 are bit for bit identical." + (let* ((cmp-binary #$(file-append + (@ (gnu packages base) diffutils) "/bin/cmp")) + (stats1 (lstat file1)) + (stats2 (lstat file2))) + (cond + ((= (stat:ino stats1) (stat:ino stats2)) #t) + ((not (= (stat:size stats1) (stat:size stats2))) #f) + + (else (= (system* cmp-binary file1 file2) 0))))) + + (define (equal-symlinks? symlink1 symlink2) + "Check if SYMLINK1 and SYMLINK2 are pointing to the same target." + (string=? (readlink symlink1) (readlink symlink2))) + + (define (equal-directories? dir1 dir2) + "Check if DIR1 and DIR2 have the same content." + (define (ordinary-file file) + (not (or (string=? file ".") + (string=? file "..")))) + (let* ((files1 (scandir dir1 ordinary-file)) + (files2 (scandir dir2 ordinary-file))) + (if (equal? files1 files2) + (map (lambda (file) + (equal-files? + (string-append dir1 "/" file) + (string-append dir2 "/" file))) + files1) + #f))) + + (define (equal-files? file1 file2) + "Compares files, symlinks or directories of the same type." + (case (file-type file1) + ((directory) (equal-directories? file1 file2)) + ((symlink) (equal-symlinks? file1 file2)) + ((regular) (equal-regulars? file1 file2)) + (else + (display "The file type is unsupported by on-change service.\n") + #f))) + + (define (file-type file) + (stat:type (lstat file))) + + (define (something-changed? file1 file2) + (cond + ((and (not (file-exists? file1)) + (not (file-exists? file2))) #f) + ((or (not (file-exists? file1)) + (not (file-exists? file2))) #t) + + ((not (eq? (file-type file1) (file-type file2))) #t) + + (else + (not (equal-files? file1 file2))))) + + (define expressions-to-eval + (map + (lambda (x) + (let* ((file1 (string-append (getenv "GUIX_OLD_HOME") "/" (car x))) + (file2 (string-append (getenv "GUIX_NEW_HOME") "/" (car x))) + (_ (format #t "Comparing ~a and\n~10t~a..." file1 file2)) + (any-changes? (something-changed? file1 file2)) + (_ (format #t " done (~a)\n" + (if any-changes? "changed" "same")))) + (if any-changes? (cadr x) ""))) + '#$pattern-gexp-tuples)) + + (if #$eval-gexps? + (begin + (display "Evaling on-change gexps.\n\n") + (for-each primitive-eval expressions-to-eval) + (display "On-change gexps evaluation finished.\n\n")) + (display "\ +On-change gexps won't evaluated, disabled by service configuration.\n")))) + +(define home-run-on-change-service-type + (service-type (name 'home-run-on-change) + (extensions + (list (service-extension + home-activation-service-type + identity))) + (compose concatenate) + (extend compute-on-change-gexp) + (default-value #t) + (description "\ +G-expressions to run if the specified files have changed since the +last generation. The extension should be a list of lists where the +first element is the pattern for file or directory that expected to be +changed, and the second element is the G-expression to be evaluated."))) -- 2.32.0 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH v3 3/4] home-services: Add home-provenance-service-type 2021-07-19 8:04 ` [bug#49419] [PATCH v3 0/4] Essential home services Andrew Tropin 2021-07-05 15:37 ` [bug#49419] [PATCH v3 1/4] home-services: Add most essential " Andrew Tropin 2021-07-05 15:39 ` [bug#49419] [PATCH v3 2/4] home-services: Add home-run-on-change-service-type Andrew Tropin @ 2021-07-05 15:41 ` Andrew Tropin 2021-07-05 15:41 ` [bug#49419] [PATCH v3 4/4] home-services: Add fold-home-service-types function Andrew Tropin 2021-07-21 15:08 ` [bug#49419] [PATCH 0/4] Essential home services Ludovic Courtès 4 siblings, 0 replies; 38+ messages in thread From: Andrew Tropin @ 2021-07-05 15:41 UTC (permalink / raw) To: 49419 [-- Attachment #1: Type: text/plain, Size: 1784 bytes --] * gnu/home-services.scm (home-provenance-service-type, sexp->home-provenance, home-provenance): New variables. --- gnu/home-services.scm | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/gnu/home-services.scm b/gnu/home-services.scm index bcb6dd80df..8aa9adeaaf 100644 --- a/gnu/home-services.scm +++ b/gnu/home-services.scm @@ -38,7 +38,10 @@ home-files-service-type home-run-on-first-login-service-type home-activation-service-type - home-run-on-change-service-type) + home-run-on-change-service-type + home-provenance-service-type + + fold-home-service-types) #:re-export (service service-type @@ -424,3 +427,25 @@ G-expressions to run if the specified files have changed since the last generation. The extension should be a list of lists where the first element is the pattern for file or directory that expected to be changed, and the second element is the G-expression to be evaluated."))) + +\f +;;; +;;; Provenance tracking. +;;; + +(define home-provenance-service-type + (service-type + (name 'home-provenance) + (extensions + (list (service-extension + home-service-type + (service-extension-compute + (first (service-type-extensions provenance-service-type)))))) + (default-value #f) ;the HE config file + (description "\ +Store provenance information about the home environment in the home +environment itself: the channels used when building the home +environment, and its configuration file, when available."))) + +(define sexp->home-provenance sexp->system-provenance) +(define home-provenance system-provenance) -- 2.32.0 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH v3 4/4] home-services: Add fold-home-service-types function 2021-07-19 8:04 ` [bug#49419] [PATCH v3 0/4] Essential home services Andrew Tropin ` (2 preceding siblings ...) 2021-07-05 15:41 ` [bug#49419] [PATCH v3 3/4] home-services: Add home-provenance-service-type Andrew Tropin @ 2021-07-05 15:41 ` Andrew Tropin 2021-07-21 15:08 ` [bug#49419] [PATCH 0/4] Essential home services Ludovic Courtès 4 siblings, 0 replies; 38+ messages in thread From: Andrew Tropin @ 2021-07-05 15:41 UTC (permalink / raw) To: 49419 [-- Attachment #1: Type: text/plain, Size: 1482 bytes --] * gnu/home-services.scm (parent-directory, %guix-home-root-directory, %service-type-path, all-home-service-modules, fold-home-service-types): New variables. --- gnu/home-services.scm | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/gnu/home-services.scm b/gnu/home-services.scm index 8aa9adeaaf..9afb70f0a7 100644 --- a/gnu/home-services.scm +++ b/gnu/home-services.scm @@ -449,3 +449,29 @@ environment, and its configuration file, when available."))) (define sexp->home-provenance sexp->system-provenance) (define home-provenance system-provenance) + +\f +;;; +;;; Searching +;;; + +(define (parent-directory directory) + "Get the parent directory of DIRECTORY" + (string-join (drop-right (string-split directory #\/) 1) "/")) + +(define %guix-home-root-directory + ;; Absolute file name of the module hierarchy. + (parent-directory (dirname (search-path %load-path "gnu/home-services.scm")))) + +(define %service-type-path + ;; Search path for service types. + (make-parameter `((,%guix-home-root-directory . "gnu/home-services")))) + +(define (all-home-service-modules) + "Return the default set of home-service modules." + (cons (resolve-interface '(gnu home-services)) + (all-modules (%service-type-path) + #:warn warn-about-load-error))) + +(define* (fold-home-service-types proc seed) + (fold-service-types proc seed (all-home-service-modules))) -- 2.32.0 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH 0/4] Essential home services 2021-07-19 8:04 ` [bug#49419] [PATCH v3 0/4] Essential home services Andrew Tropin ` (3 preceding siblings ...) 2021-07-05 15:41 ` [bug#49419] [PATCH v3 4/4] home-services: Add fold-home-service-types function Andrew Tropin @ 2021-07-21 15:08 ` Ludovic Courtès 2021-07-28 5:35 ` Andrew Tropin 4 siblings, 1 reply; 38+ messages in thread From: Ludovic Courtès @ 2021-07-21 15:08 UTC (permalink / raw) To: Andrew Tropin; +Cc: 49419 Hi Andrew, Andrew Tropin <andrew@trop.in> skribis: > Diff with v2: Prevents unecessary calls to system* > > Please, when review finished, apply against guix-home-wip branch. > > Andrew Tropin (4): > home-services: Add most essential home services > home-services: Add home-run-on-change-service-type > home-services: Add home-provenance-service-type > home-services: Add fold-home-service-types function Thanks for sending this first patch series! How would you like to proceed? Sending patches that add essential services, and then (guix scripts home …) modules? I agree we should apply it all in ‘wip-guix-home’ for now. Some general comments: • Please remove tabs from Scheme files. • Please do not write documentation in commit logs. For example, patch #1 explains the different service types, but to me, that’d belong in a comment or (better yet) in a section of the manual. For commit logs, we use ChangeLog style: https://guix.gnu.org/manual/en/html_node/Submitting-Patches.html It’s OK if you don’t get the fine points right from the start, committers can tweak it for you. :-) • When there are tests or documentation, add them in the commit that adds the corresponding functionality. • Regarding module names: what about putting everything in the (gnu home …) name space. For services, I wonder if we could simply use (gnu services home), for the essential services, and other (gnu services …) module, but that assumes some code can be shared between System and Home. Thoughts? I’ll look at the actual patches later, but I invite others to chime in too. :-) Thanks! Ludo’. ^ permalink raw reply [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH 0/4] Essential home services 2021-07-21 15:08 ` [bug#49419] [PATCH 0/4] Essential home services Ludovic Courtès @ 2021-07-28 5:35 ` Andrew Tropin 0 siblings, 0 replies; 38+ messages in thread From: Andrew Tropin @ 2021-07-28 5:35 UTC (permalink / raw) To: Ludovic Courtès; +Cc: 49419 [-- Attachment #1.1: Type: text/plain, Size: 820 bytes --] Ludovic Courtès <ludo@gnu.org> writes: > Hi Andrew, > > Andrew Tropin <andrew@trop.in> skribis: > >> Diff with v2: Prevents unecessary calls to system* >> >> Please, when review finished, apply against guix-home-wip branch. >> >> Andrew Tropin (4): >> home-services: Add most essential home services >> home-services: Add home-run-on-change-service-type >> home-services: Add home-provenance-service-type >> home-services: Add fold-home-service-types function > > Thanks for sending this first patch series! > > How would you like to proceed? Sending patches that add essential > services, and then (guix scripts home …) modules? Yep. > I agree we should apply it all in ‘wip-guix-home’ for now. > > Some general comments: > > • Please remove tabs from Scheme files. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1.2: 0001-toberebased-gnu-home-services-Untabify-a-file.patch --] [-- Type: text/x-patch, Size: 7915 bytes --] From 26bfd8052d90650abc7e5ec6dbb7dd7165dfba3c Mon Sep 17 00:00:00 2001 From: Andrew Tropin <andrew@trop.in> Date: Wed, 28 Jul 2021 08:22:20 +0300 Subject: [PATCH] (toberebased) gnu: home-services: Untabify a file --- gnu/home-services.scm | 80 +++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/gnu/home-services.scm b/gnu/home-services.scm index 9afb70f0a7..94f0ccff7a 100644 --- a/gnu/home-services.scm +++ b/gnu/home-services.scm @@ -33,10 +33,10 @@ #:use-module (ice-9 match) #:export (home-service-type - home-profile-service-type - home-environment-variables-service-type - home-files-service-type - home-run-on-first-login-service-type + home-profile-service-type + home-environment-variables-service-type + home-files-service-type + home-run-on-first-login-service-type home-activation-service-type home-run-on-change-service-type home-provenance-service-type @@ -44,8 +44,8 @@ fold-home-service-types) #:re-export (service - service-type - service-extension)) + service-type + service-extension)) ;;; Comment: ;;; @@ -76,7 +76,7 @@ directory containing the given entries." (extensions '()) (compose identity) (extend home-derivation) - (default-value '()) + (default-value '()) (description "Build the home environment top-level directory, which in turn refers to everything the home environment needs: its @@ -130,12 +130,12 @@ exported." (fold (lambda (x acc) (when (equal? (car x) (car acc)) - (warning - (G_ "duplicate definition for `~a' environment variable ~%") (car x))) + (warning + (G_ "duplicate definition for `~a' environment variable ~%") (car x))) x) (cons "" "") (sort vars (lambda (a b) - (string<? (car a) (car b)))))) + (string<? (car a) (car b)))))) (warn-about-duplicate-defenitions) (with-monad @@ -145,7 +145,7 @@ exported." ;; TODO: It's necessary to source ~/.guix-profile too ;; on foreign distros ,(apply mixed-text-file "setup-environment" - "\ + "\ HOME_ENVIRONMENT=$HOME/.guix-home GUIX_PROFILE=\"$HOME_ENVIRONMENT/profile\" PROFILE_FILE=\"$HOME_ENVIRONMENT/profile/etc/profile\" @@ -174,25 +174,25 @@ esac " - (append-map - (match-lambda - ((key . #f) - '()) - ((key . #t) - (list "export " key "\n")) - ((key . value) + (append-map + (match-lambda + ((key . #f) + '()) + ((key . #t) + (list "export " key "\n")) + ((key . value) (list "export " key "=" value "\n"))) - vars))))))) + vars))))))) (define home-environment-variables-service-type (service-type (name 'home-environment-variables) (extensions (list (service-extension - home-service-type + home-service-type environment-variables->setup-environment-script))) (compose concatenate) (extend append) - (default-value '()) + (default-value '()) (description "Set the environment variables."))) (define (files->files-directory files) @@ -227,7 +227,7 @@ directory containing FILES." files-entry))) (compose concatenate) (extend append) - (default-value '()) + (default-value '()) (description "Configuration files for programs that will be put in @file{~/.guix-home/files}."))) @@ -235,32 +235,32 @@ will be put in @file{~/.guix-home/files}."))) (gexp->script "on-first-login" #~(let* ((xdg-runtime-dir (or (getenv "XDG_RUNTIME_DIR") - (format #f "/run/user/~a" (getuid)))) - (flag-file-path (string-append - xdg-runtime-dir "/on-first-login-executed")) - (touch (lambda (file-name) - (call-with-output-file file-name (const #t))))) + (format #f "/run/user/~a" (getuid)))) + (flag-file-path (string-append + xdg-runtime-dir "/on-first-login-executed")) + (touch (lambda (file-name) + (call-with-output-file file-name (const #t))))) ;; XDG_RUNTIME_DIR dissapears on logout, that means such trick ;; allows to launch on-first-login script on first login only ;; after complete logout/reboot. (when (not (file-exists? flag-file-path)) - (begin #$@gexps (touch flag-file-path)))))) + (begin #$@gexps (touch flag-file-path)))))) (define (on-first-login-script-entry m-on-first-login) "Return, as a monadic value, an entry for the on-first-login script in the home environment directory." (mlet %store-monad ((on-first-login m-on-first-login)) - (return `(("on-first-login" ,on-first-login))))) + (return `(("on-first-login" ,on-first-login))))) (define home-run-on-first-login-service-type (service-type (name 'home-run-on-first-login) (extensions (list (service-extension - home-service-type + home-service-type on-first-login-script-entry))) (compose identity) (extend compute-on-first-login-script) - (default-value #f) + (default-value #f) (description "Run gexps on first user login. Can be extended with one gexp."))) @@ -281,18 +281,18 @@ 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" (he-init-file new-home)))) - (result ((@ (ice-9 rdelim) read-delimited) "" port)) - (vars (map (lambda (x) + (result ((@ (ice-9 rdelim) read-delimited) "" port)) + (vars (map (lambda (x) (let ((si (string-index x #\=))) (cons (string-take x si) (string-drop x (1+ si))))) - ((@ (srfi srfi-1) remove) - string-null? + ((@ (srfi srfi-1) remove) + string-null? (string-split result #\newline))))) - (close-port port) - (map (lambda (x) (setenv (car x) (cdr x))) vars) + (close-port port) + (map (lambda (x) (setenv (car x) (cdr x))) vars) (setenv "GUIX_NEW_HOME" new-home) (setenv "GUIX_OLD_HOME" old-home) @@ -319,11 +319,11 @@ in the home environment directory." (service-type (name 'home-activation) (extensions (list (service-extension - home-service-type + home-service-type activation-script-entry))) (compose identity) (extend compute-activation-script) - (default-value #f) + (default-value #f) (description "Run gexps to activate the current generation of home environment and update the state of the home directory. @command{activate} script automatically called during -- 2.32.0 [-- Attachment #1.3: Type: text/plain, Size: 1997 bytes --] > • Please do not write documentation in commit logs. For example, > patch #1 explains the different service types, but to me, that’d > belong in a comment or (better yet) in a section of the manual. For > commit logs, we use ChangeLog style: > > https://guix.gnu.org/manual/en/html_node/Submitting-Patches.html > > It’s OK if you don’t get the fine points right from the start, > committers can tweak it for you. :-) True, I forgot to add ChangeLog style parts to first two patches. The rest of commit message originally was just an explanation for reviewers to provide a context, but yep it's already looks like a documentation) > > • When there are tests or documentation, add them in the commit that > adds the corresponding functionality. Wanted to add documentation with a separate patch series to make patch series to wip-guix-home be smaller and easier for review, but probably you are right, I should add related documentation in the same series. > • Regarding module names: what about putting everything in the (gnu > home …) name space. For services, I wonder if we could simply use > (gnu services home), for the essential services, and other (gnu > services …) module, but that assumes some code can be shared between > System and Home. Thoughts? There was a thread on rde-devel about moving home services to (gnu services ...), in the second half of the first response I provided some arguments against this change. https://lists.sr.ht/~abcdw/rde-devel/%3C87y2cqifpx.fsf%40yoctocell.xyz%3E However, I can miss some niceties, so I still open for discussion if you think that arguments from the thread isn't valid anymore or not valid at all. > I’ll look at the actual patches later, but I invite others to chime in > too. :-) Cool, I'll wait for the review of the code and will prepare a new version of patch series after that. Thank you for the comments! [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply related [flat|nested] 38+ messages in thread
[parent not found: <handler.49419.B.162549932625345.ack@debbugs.gnu.org>]
* [bug#49419] [PATCH v4 0/4] Essential home services [not found] ` <handler.49419.B.162549932625345.ack@debbugs.gnu.org> @ 2021-08-05 5:41 ` Andrew Tropin 2021-08-05 5:45 ` [bug#49419] [PATCH v4 1/4] home-services: Add most essential " Andrew Tropin ` (4 more replies) 0 siblings, 5 replies; 38+ messages in thread From: Andrew Tropin @ 2021-08-05 5:41 UTC (permalink / raw) To: 49419 [-- Attachment #1: Type: text/plain, Size: 688 bytes --] Seems there is no additional comments about implementation, so I just send cosmetical changes treating comments from previous reviews. Changes since v3: - Remove tabs. - Move Home Services explanation from commit message to comment. - Add missing ChangeLog-style commit body. Andrew Tropin (4): home-services: Add most essential home services home-services: Add home-run-on-change-service-type home-services: Add home-provenance-service-type home-services: Add fold-home-service-types function gnu/home-services.scm | 520 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 520 insertions(+) create mode 100644 gnu/home-services.scm -- 2.32.0 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH v4 1/4] home-services: Add most essential home services 2021-08-05 5:41 ` [bug#49419] [PATCH v4 " Andrew Tropin @ 2021-08-05 5:45 ` Andrew Tropin 2021-08-05 5:46 ` [bug#49419] [PATCH v4 2/4] home-services: Add home-run-on-change-service-type Andrew Tropin ` (3 subsequent siblings) 4 siblings, 0 replies; 38+ messages in thread From: Andrew Tropin @ 2021-08-05 5:45 UTC (permalink / raw) To: 49419 [-- Attachment #1: Type: text/plain, Size: 16654 bytes --] * gnu/home-services.scm (home-service-type, home-profile-service-type) (home-environment-variables-service-type, home-files-service-type) (home-run-on-first-login-service-type, home-activation-service-type): New variables. --- gnu/home-services.scm | 368 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 368 insertions(+) create mode 100644 gnu/home-services.scm diff --git a/gnu/home-services.scm b/gnu/home-services.scm new file mode 100644 index 0000000000..4a6458abec --- /dev/null +++ b/gnu/home-services.scm @@ -0,0 +1,368 @@ +;;; 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) + #:use-module (gnu services) + #:use-module (guix channels) + #:use-module (guix monads) + #:use-module (guix store) + #:use-module (guix gexp) + #:use-module (guix profiles) + #:use-module (guix sets) + #:use-module (guix ui) + #:use-module (guix discovery) + #:use-module (guix diagnostics) + + #:use-module (srfi srfi-1) + #:use-module (ice-9 match) + + #:export (home-service-type + home-profile-service-type + home-environment-variables-service-type + home-files-service-type + home-run-on-first-login-service-type + home-activation-service-type) + + #:re-export (service + service-type + service-extension)) + +;;; Comment: +;;; +;;; This module is similar to (gnu system services) module, but +;;; provides Home Services, which are supposed to be used for building +;;; home-environment. +;;; +;;; Home Services use the same extension as System Services. Consult +;;; (gnu system services) module or manual for more information. +;;; +;;; home-service-type is a root of home services DAG. +;;; +;;; home-profile-service-type is almost the same as profile-service-type, at least +;;; for now. +;;; +;;; home-environment-variables-service-type generates a @file{setup-environment} +;;; shell script, which is expected to be sourced by login shell or other program, +;;; which starts early and spawns all other processes. Home services for shells +;;; automatically add code for sourcing this file, if person do not use those home +;;; services they have to source this script manually in their's shell *profile +;;; file (details described in the manual). +;;; +;;; home-files-service-type is similar to etc-service-type, but doesn't extend +;;; home-activation, because deploy mechanism for config files is pluggable and +;;; can be different for different home environments: The default one is called +;;; symlink-manager (will be introudced in a separate patch series), which creates +;;; links for various dotfiles (like $XDG_CONFIG_HOME/$APP/...) to store, but is +;;; possible to implement alternative approaches like read-only home from Julien's +;;; guix-home-manager. +;;; +;;; home-run-on-first-login-service-type provides an @file{on-first-login} guile +;;; script, which runs provided gexps once, when user makes first login. It can +;;; be used to start user's Shepherd and maybe some other process. It relies on +;;; assumption that /run/user/$UID will be created on login by some login +;;; manager (elogind for example). +;;; +;;; home-activation-service-type provides an @file{activate} guile script, which +;;; do three main things: +;;; +;;; - Sets environment variables to the values declared in +;;; @file{setup-environment} shell script. It's necessary, because user can set +;;; for example XDG_CONFIG_HOME and it should be respected by activation gexp of +;;; symlink-manager. +;;; +;;; - Sets GUIX_NEW_HOME and possibly GUIX_OLD_HOME vars to paths in the store. +;;; Later those variables can be used by activation gexps, for example by +;;; symlink-manager or run-on-change services. +;;; +;;; - Run all activation gexps provided by other home services. +;;; +;;; Code: + + +(define (home-derivation entries mextensions) + "Return as a monadic value the derivation of the 'home' +directory containing the given entries." + (mlet %store-monad ((extensions (mapm/accumulate-builds identity + mextensions))) + (lower-object + (file-union "home" (append entries (concatenate extensions)))))) + +(define home-service-type + ;; This is the ultimate service type, the root of the home service + ;; DAG. The service of this type is extended by monadic name/item + ;; pairs. These items end up in the "home-environment directory" as + ;; returned by 'home-environment-derivation'. + (service-type (name 'home) + (extensions '()) + (compose identity) + (extend home-derivation) + (default-value '()) + (description + "Build the home environment top-level directory, +which in turn refers to everything the home environment needs: its +packages, configuration files, activation script, and so on."))) + +(define (packages->profile-entry packages) + "Return a system entry for the profile containing PACKAGES." + ;; XXX: 'mlet' is needed here for one reason: to get the proper + ;; '%current-target' and '%current-target-system' bindings when + ;; 'packages->manifest' is called, and thus when the 'package-inputs' + ;; etc. procedures are called on PACKAGES. That way, conditionals in those + ;; inputs see the "correct" value of these two parameters. See + ;; <https://issues.guix.gnu.org/44952>. + (mlet %store-monad ((_ (current-target-system))) + (return `(("profile" ,(profile + (content (packages->manifest + (map identity + ;;(options->transformation transformations) + (delete-duplicates packages eq?)))))))))) + +;; MAYBE: Add a list of transformations for packages. It's better to +;; place it in home-profile-service-type to affect all profile +;; packages and prevent conflicts, when other packages relies on +;; non-transformed version of package. +(define home-profile-service-type + (service-type (name 'home-profile) + (extensions + (list (service-extension home-service-type + packages->profile-entry))) + (compose concatenate) + (extend append) + (description + "This is the @dfn{home profile} and can be found in +@file{~/.guix-home/profile}. It contains packages and +configuration files that the user has declared in their +@code{home-environment} record."))) + +(define (environment-variables->setup-environment-script vars) + "Return a file that can be sourced by a POSIX compliant shell which +initializes the environment. The file will source the home +environment profile, set some default environment variables, and set +environment variables provided in @code{vars}. @code{vars} is a list +of pairs (@code{(key . value)}), @code{key} is a string and +@code{value} is a string or gexp. + +If value is @code{#f} variable will be omitted. +If value is @code{#t} variable will be just exported. +For any other, value variable will be set to the @code{value} and +exported." + (define (warn-about-duplicate-defenitions) + (fold + (lambda (x acc) + (when (equal? (car x) (car acc)) + (warning + (G_ "duplicate definition for `~a' environment variable ~%") (car x))) + x) + (cons "" "") + (sort vars (lambda (a b) + (string<? (car a) (car b)))))) + + (warn-about-duplicate-defenitions) + (with-monad + %store-monad + (return + `(("setup-environment" + ;; TODO: It's necessary to source ~/.guix-profile too + ;; on foreign distros + ,(apply mixed-text-file "setup-environment" + "\ +HOME_ENVIRONMENT=$HOME/.guix-home +GUIX_PROFILE=\"$HOME_ENVIRONMENT/profile\" +PROFILE_FILE=\"$HOME_ENVIRONMENT/profile/etc/profile\" +[ -f $PROFILE_FILE ] && . $PROFILE_FILE + +case $XDG_DATA_DIRS in + *$HOME_ENVIRONMENT/profile/share*) ;; + *) export XDG_DATA_DIRS=$HOME_ENVIRONMENT/profile/share:$XDG_DATA_DIRS ;; +esac +case $MANPATH in + *$HOME_ENVIRONMENT/profile/share/man*) ;; + *) export MANPATH=$HOME_ENVIRONMENT/profile/share/man:$MANPATH +esac +case $INFOPATH in + *$HOME_ENVIRONMENT/profile/share/info*) ;; + *) export INFOPATH=$HOME_ENVIRONMENT/profile/share/info:$INFOPATH ;; +esac +case $XDG_CONFIG_DIRS in + *$HOME_ENVIRONMENT/profile/etc/xdg*) ;; + *) export XDG_CONFIG_DIRS=$HOME_ENVIRONMENT/profile/etc/xdg:$XDG_CONFIG_DIRS ;; +esac +case $XCURSOR_PATH in + *$HOME_ENVIRONMENT/profile/share/icons*) ;; + *) export XCURSOR_PATH=$HOME_ENVIRONMENT/profile/share/icons:$XCURSOR_PATH ;; +esac + +" + + (append-map + (match-lambda + ((key . #f) + '()) + ((key . #t) + (list "export " key "\n")) + ((key . value) + (list "export " key "=" value "\n"))) + vars))))))) + +(define home-environment-variables-service-type + (service-type (name 'home-environment-variables) + (extensions + (list (service-extension + home-service-type + environment-variables->setup-environment-script))) + (compose concatenate) + (extend append) + (default-value '()) + (description "Set the environment variables."))) + +(define (files->files-directory files) + "Return a @code{files} directory that contains FILES." + (define (assert-no-duplicates files) + (let loop ((files files) + (seen (set))) + (match files + (() #t) + (((file _) rest ...) + (when (set-contains? seen file) + (raise (formatted-message (G_ "duplicate '~a' entry for files/") + file))) + (loop rest (set-insert file seen)))))) + + ;; Detect duplicates early instead of letting them through, eventually + ;; leading to a build failure of "files.drv". + (assert-no-duplicates files) + + (file-union "files" files)) + +(define (files-entry files) + "Return an entry for the @file{~/.guix-home/files} +directory containing FILES." + (with-monad %store-monad + (return `(("files" ,(files->files-directory files)))))) + +(define home-files-service-type + (service-type (name 'home-files) + (extensions + (list (service-extension home-service-type + files-entry))) + (compose concatenate) + (extend append) + (default-value '()) + (description "Configuration files for programs that +will be put in @file{~/.guix-home/files}."))) + +(define (compute-on-first-login-script _ gexps) + (gexp->script + "on-first-login" + #~(let* ((xdg-runtime-dir (or (getenv "XDG_RUNTIME_DIR") + (format #f "/run/user/~a" (getuid)))) + (flag-file-path (string-append + xdg-runtime-dir "/on-first-login-executed")) + (touch (lambda (file-name) + (call-with-output-file file-name (const #t))))) + ;; XDG_RUNTIME_DIR dissapears on logout, that means such trick + ;; allows to launch on-first-login script on first login only + ;; after complete logout/reboot. + (when (not (file-exists? flag-file-path)) + (begin #$@gexps (touch flag-file-path)))))) + +(define (on-first-login-script-entry m-on-first-login) + "Return, as a monadic value, an entry for the on-first-login script +in the home environment directory." + (mlet %store-monad ((on-first-login m-on-first-login)) + (return `(("on-first-login" ,on-first-login))))) + +(define home-run-on-first-login-service-type + (service-type (name 'home-run-on-first-login) + (extensions + (list (service-extension + home-service-type + on-first-login-script-entry))) + (compose identity) + (extend compute-on-first-login-script) + (default-value #f) + (description "Run gexps on first user login. Can be +extended with one gexp."))) + + +(define (compute-activation-script init-gexp gexps) + (gexp->script + "activate" + #~(let* ((he-init-file (lambda (he) (string-append he "/setup-environment"))) + (he-path (string-append (getenv "HOME") "/.guix-home")) + (new-home-env (getenv "GUIX_NEW_HOME")) + (new-home (or new-home-env + ;; Path of the activation file if called interactively + (dirname (car (command-line))))) + (old-home-env (getenv "GUIX_OLD_HOME")) + (old-home (or old-home-env + (if (file-exists? (he-init-file he-path)) + (readlink he-path) + #f)))) + (if (file-exists? (he-init-file new-home)) + (let* ((port ((@ (ice-9 popen) open-input-pipe) + (format #f "source ~a && env" + (he-init-file new-home)))) + (result ((@ (ice-9 rdelim) read-delimited) "" port)) + (vars (map (lambda (x) + (let ((si (string-index x #\=))) + (cons (string-take x si) + (string-drop x (1+ si))))) + ((@ (srfi srfi-1) remove) + string-null? + (string-split result #\newline))))) + (close-port port) + (map (lambda (x) (setenv (car x) (cdr x))) vars) + + (setenv "GUIX_NEW_HOME" new-home) + (setenv "GUIX_OLD_HOME" old-home) + + #$@gexps + + ;; Do not unset env variable if it was set outside. + (unless new-home-env (setenv "GUIX_NEW_HOME" #f)) + (unless old-home-env (setenv "GUIX_OLD_HOME" #f))) + (format #t "\ +Activation script was either called or loaded by file from this direcotry: +~a +It doesn't seem that home environment is somewhere around. +Make sure that you call ./activate by symlink from -home store item.\n" + new-home))))) + +(define (activation-script-entry m-activation) + "Return, as a monadic value, an entry for the activation script +in the home environment directory." + (mlet %store-monad ((activation m-activation)) + (return `(("activate" ,activation))))) + +(define home-activation-service-type + (service-type (name 'home-activation) + (extensions + (list (service-extension + home-service-type + activation-script-entry))) + (compose identity) + (extend compute-activation-script) + (default-value #f) + (description "Run gexps to activate the current +generation of home environment and update the state of the home +directory. @command{activate} script automatically called during +reconfiguration or generation switching. This service can be extended +with one gexp, but many times, and all gexps must be idempotent."))) + -- 2.32.0 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH v4 2/4] home-services: Add home-run-on-change-service-type 2021-08-05 5:41 ` [bug#49419] [PATCH v4 " Andrew Tropin 2021-08-05 5:45 ` [bug#49419] [PATCH v4 1/4] home-services: Add most essential " Andrew Tropin @ 2021-08-05 5:46 ` Andrew Tropin 2021-08-05 5:46 ` [bug#49419] [PATCH v4 3/4] home-services: Add home-provenance-service-type Andrew Tropin ` (2 subsequent siblings) 4 siblings, 0 replies; 38+ messages in thread From: Andrew Tropin @ 2021-08-05 5:46 UTC (permalink / raw) To: 49419 [-- Attachment #1: Type: text/plain, Size: 5207 bytes --] * gnu/home-services.scm (home-run-on-change-service-type): New variable. --- gnu/home-services.scm | 103 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 102 insertions(+), 1 deletion(-) diff --git a/gnu/home-services.scm b/gnu/home-services.scm index 4a6458abec..32b59f55df 100644 --- a/gnu/home-services.scm +++ b/gnu/home-services.scm @@ -37,7 +37,8 @@ home-environment-variables-service-type home-files-service-type home-run-on-first-login-service-type - home-activation-service-type) + home-activation-service-type + home-run-on-change-service-type) #:re-export (service service-type @@ -92,6 +93,9 @@ ;;; ;;; - Run all activation gexps provided by other home services. ;;; +;;; home-run-on-change-service-type allows to trigger actions during +;;; activation if file or directory specified by pattern is changed. +;;; ;;; Code: @@ -366,3 +370,100 @@ directory. @command{activate} script automatically called during reconfiguration or generation switching. This service can be extended with one gexp, but many times, and all gexps must be idempotent."))) +\f +;;; +;;; On-change. +;;; + +(define (compute-on-change-gexp eval-gexps? pattern-gexp-tuples) + #~(begin + (define (equal-regulars? file1 file2) + "Check if FILE1 and FILE2 are bit for bit identical." + (let* ((cmp-binary #$(file-append + (@ (gnu packages base) diffutils) "/bin/cmp")) + (stats1 (lstat file1)) + (stats2 (lstat file2))) + (cond + ((= (stat:ino stats1) (stat:ino stats2)) #t) + ((not (= (stat:size stats1) (stat:size stats2))) #f) + + (else (= (system* cmp-binary file1 file2) 0))))) + + (define (equal-symlinks? symlink1 symlink2) + "Check if SYMLINK1 and SYMLINK2 are pointing to the same target." + (string=? (readlink symlink1) (readlink symlink2))) + + (define (equal-directories? dir1 dir2) + "Check if DIR1 and DIR2 have the same content." + (define (ordinary-file file) + (not (or (string=? file ".") + (string=? file "..")))) + (let* ((files1 (scandir dir1 ordinary-file)) + (files2 (scandir dir2 ordinary-file))) + (if (equal? files1 files2) + (map (lambda (file) + (equal-files? + (string-append dir1 "/" file) + (string-append dir2 "/" file))) + files1) + #f))) + + (define (equal-files? file1 file2) + "Compares files, symlinks or directories of the same type." + (case (file-type file1) + ((directory) (equal-directories? file1 file2)) + ((symlink) (equal-symlinks? file1 file2)) + ((regular) (equal-regulars? file1 file2)) + (else + (display "The file type is unsupported by on-change service.\n") + #f))) + + (define (file-type file) + (stat:type (lstat file))) + + (define (something-changed? file1 file2) + (cond + ((and (not (file-exists? file1)) + (not (file-exists? file2))) #f) + ((or (not (file-exists? file1)) + (not (file-exists? file2))) #t) + + ((not (eq? (file-type file1) (file-type file2))) #t) + + (else + (not (equal-files? file1 file2))))) + + (define expressions-to-eval + (map + (lambda (x) + (let* ((file1 (string-append (getenv "GUIX_OLD_HOME") "/" (car x))) + (file2 (string-append (getenv "GUIX_NEW_HOME") "/" (car x))) + (_ (format #t "Comparing ~a and\n~10t~a..." file1 file2)) + (any-changes? (something-changed? file1 file2)) + (_ (format #t " done (~a)\n" + (if any-changes? "changed" "same")))) + (if any-changes? (cadr x) ""))) + '#$pattern-gexp-tuples)) + + (if #$eval-gexps? + (begin + (display "Evaling on-change gexps.\n\n") + (for-each primitive-eval expressions-to-eval) + (display "On-change gexps evaluation finished.\n\n")) + (display "\ +On-change gexps won't evaluated, disabled by service configuration.\n")))) + +(define home-run-on-change-service-type + (service-type (name 'home-run-on-change) + (extensions + (list (service-extension + home-activation-service-type + identity))) + (compose concatenate) + (extend compute-on-change-gexp) + (default-value #t) + (description "\ +G-expressions to run if the specified files have changed since the +last generation. The extension should be a list of lists where the +first element is the pattern for file or directory that expected to be +changed, and the second element is the G-expression to be evaluated."))) -- 2.32.0 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH v4 3/4] home-services: Add home-provenance-service-type 2021-08-05 5:41 ` [bug#49419] [PATCH v4 " Andrew Tropin 2021-08-05 5:45 ` [bug#49419] [PATCH v4 1/4] home-services: Add most essential " Andrew Tropin 2021-08-05 5:46 ` [bug#49419] [PATCH v4 2/4] home-services: Add home-run-on-change-service-type Andrew Tropin @ 2021-08-05 5:46 ` Andrew Tropin 2021-08-05 5:47 ` [bug#49419] [PATCH v4 4/4] home-services: Add fold-home-service-types function Andrew Tropin 2021-08-23 9:57 ` [bug#49419] [PATCH v4 0/4] Essential home services Andrew Tropin 4 siblings, 0 replies; 38+ messages in thread From: Andrew Tropin @ 2021-08-05 5:46 UTC (permalink / raw) To: 49419 [-- Attachment #1: Type: text/plain, Size: 1803 bytes --] * gnu/home-services.scm (home-provenance-service-type, sexp->home-provenance, home-provenance): New variables. --- gnu/home-services.scm | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/gnu/home-services.scm b/gnu/home-services.scm index 32b59f55df..d320d3a44d 100644 --- a/gnu/home-services.scm +++ b/gnu/home-services.scm @@ -38,7 +38,10 @@ home-files-service-type home-run-on-first-login-service-type home-activation-service-type - home-run-on-change-service-type) + home-run-on-change-service-type + home-provenance-service-type + + fold-home-service-types) #:re-export (service service-type @@ -467,3 +470,25 @@ G-expressions to run if the specified files have changed since the last generation. The extension should be a list of lists where the first element is the pattern for file or directory that expected to be changed, and the second element is the G-expression to be evaluated."))) + +\f +;;; +;;; Provenance tracking. +;;; + +(define home-provenance-service-type + (service-type + (name 'home-provenance) + (extensions + (list (service-extension + home-service-type + (service-extension-compute + (first (service-type-extensions provenance-service-type)))))) + (default-value #f) ;the HE config file + (description "\ +Store provenance information about the home environment in the home +environment itself: the channels used when building the home +environment, and its configuration file, when available."))) + +(define sexp->home-provenance sexp->system-provenance) +(define home-provenance system-provenance) -- 2.32.0 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH v4 4/4] home-services: Add fold-home-service-types function 2021-08-05 5:41 ` [bug#49419] [PATCH v4 " Andrew Tropin ` (2 preceding siblings ...) 2021-08-05 5:46 ` [bug#49419] [PATCH v4 3/4] home-services: Add home-provenance-service-type Andrew Tropin @ 2021-08-05 5:47 ` Andrew Tropin 2021-08-23 9:57 ` [bug#49419] [PATCH v4 0/4] Essential home services Andrew Tropin 4 siblings, 0 replies; 38+ messages in thread From: Andrew Tropin @ 2021-08-05 5:47 UTC (permalink / raw) To: 49419 [-- Attachment #1: Type: text/plain, Size: 1480 bytes --] * gnu/home-services.scm (parent-directory, %guix-home-root-directory, %service-type-path, all-home-service-modules, fold-home-service-types): New variables. --- gnu/home-services.scm | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/gnu/home-services.scm b/gnu/home-services.scm index d320d3a44d..16b9736d64 100644 --- a/gnu/home-services.scm +++ b/gnu/home-services.scm @@ -492,3 +492,29 @@ environment, and its configuration file, when available."))) (define sexp->home-provenance sexp->system-provenance) (define home-provenance system-provenance) + +\f +;;; +;;; Searching +;;; + +(define (parent-directory directory) + "Get the parent directory of DIRECTORY" + (string-join (drop-right (string-split directory #\/) 1) "/")) + +(define %guix-home-root-directory + ;; Absolute file name of the module hierarchy. + (parent-directory (dirname (search-path %load-path "gnu/home-services.scm")))) + +(define %service-type-path + ;; Search path for service types. + (make-parameter `((,%guix-home-root-directory . "gnu/home-services")))) + +(define (all-home-service-modules) + "Return the default set of home-service modules." + (cons (resolve-interface '(gnu home-services)) + (all-modules (%service-type-path) + #:warn warn-about-load-error))) + +(define* (fold-home-service-types proc seed) + (fold-service-types proc seed (all-home-service-modules))) -- 2.32.0 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH v4 0/4] Essential home services 2021-08-05 5:41 ` [bug#49419] [PATCH v4 " Andrew Tropin ` (3 preceding siblings ...) 2021-08-05 5:47 ` [bug#49419] [PATCH v4 4/4] home-services: Add fold-home-service-types function Andrew Tropin @ 2021-08-23 9:57 ` Andrew Tropin 2021-08-23 16:24 ` [bug#49419] [PATCH " Oleg Pykhalov 4 siblings, 1 reply; 38+ messages in thread From: Andrew Tropin @ 2021-08-23 9:57 UTC (permalink / raw) To: 49419; +Cc: Ludovic Courtès, Maxime Devos [-- Attachment #1: Type: text/plain, Size: 762 bytes --] On 2021-08-05 08:41, Andrew Tropin wrote: > Seems there is no additional comments about implementation, so I just > send cosmetical changes treating comments from previous reviews. > > Changes since v3: > - Remove tabs. > - Move Home Services explanation from commit message to comment. > - Add missing ChangeLog-style commit body. > > Andrew Tropin (4): > home-services: Add most essential home services > home-services: Add home-run-on-change-service-type > home-services: Add home-provenance-service-type > home-services: Add fold-home-service-types function > > gnu/home-services.scm | 520 ++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 520 insertions(+) > create mode 100644 gnu/home-services.scm Guys, review v4 patches, please. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH 0/4] Essential home services 2021-08-23 9:57 ` [bug#49419] [PATCH v4 0/4] Essential home services Andrew Tropin @ 2021-08-23 16:24 ` Oleg Pykhalov 2021-08-24 8:53 ` Andrew Tropin 0 siblings, 1 reply; 38+ messages in thread From: Oleg Pykhalov @ 2021-08-23 16:24 UTC (permalink / raw) To: Andrew Tropin; +Cc: Ludovic Courtès, Maxime Devos, 49419 [-- Attachment #1: Type: text/plain, Size: 499 bytes --] Hi Andrew, Andrew Tropin <andrew@trop.in> writes: […] > Guys, review v4 patches, please. These patch series looks good for me. As Ludovic suggested, we could move modules to another namespace for code sharing, but it is not a blocker from merging changes and we could do it later when we need to share the code. I think we should go forward and push to the master. WDYT? As I remember you have an access to push. Otherwise, please, ping me to push it.< Thanks, Oleg. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 861 bytes --] ^ permalink raw reply [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH 0/4] Essential home services 2021-08-23 16:24 ` [bug#49419] [PATCH " Oleg Pykhalov @ 2021-08-24 8:53 ` Andrew Tropin 2021-08-24 12:14 ` bug#49419: " Oleg Pykhalov 0 siblings, 1 reply; 38+ messages in thread From: Andrew Tropin @ 2021-08-24 8:53 UTC (permalink / raw) To: Oleg Pykhalov; +Cc: Ludovic Courtès, Maxime Devos, 49419 [-- Attachment #1: Type: text/plain, Size: 1277 bytes --] On 2021-08-23 19:24, Oleg Pykhalov wrote: > Hi Andrew, > Hi Oleg! > > These patch series looks good for me. > > As Ludovic suggested, we could move modules to another namespace for > code sharing, but it is not a blocker from merging changes and we could > do it later when we need to share the code. I think we should go > forward and push to the master. WDYT? Yep, let's postpone moving modules to another namespace until it will be needed. Later, when the necessity appears, we will decide how to better organize the code. We can push it to master, but I planned to keep it in wip-guix-home for a while to bring all related stuff like documentation and cli to the branch and merge it to the master after everything is complete. Also, merging only part of Guix Home to the master will arise conflicts for users of rde channel (which contains current implementation of Guix Home). However, it is solvable by removing already merged parts from rde repository, so, it's not a big deal and I'm fine with both merging options. > > As I remember you have an access to push. Nope, I don't have commit access yet) > Otherwise, please, ping me to push it.< If everything seems ok, merge the changes, please. I'll prepare the next patch series soon. > > Thanks, > Oleg. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply [flat|nested] 38+ messages in thread
* bug#49419: [PATCH 0/4] Essential home services 2021-08-24 8:53 ` Andrew Tropin @ 2021-08-24 12:14 ` Oleg Pykhalov 2021-08-26 7:01 ` [bug#49419] " Andrew Tropin 0 siblings, 1 reply; 38+ messages in thread From: Oleg Pykhalov @ 2021-08-24 12:14 UTC (permalink / raw) To: Andrew Tropin; +Cc: 49419-done [-- Attachment #1: Type: text/plain, Size: 1117 bytes --] Andrew Tropin <andrew@trop.in> writes: […] >> As Ludovic suggested, we could move modules to another namespace for >> code sharing, but it is not a blocker from merging changes and we could >> do it later when we need to share the code. I think we should go >> forward and push to the master. WDYT? > > Yep, let's postpone moving modules to another namespace until it will be > needed. Later, when the necessity appears, we will decide how to better > organize the code. > > We can push it to master, but I planned to keep it in wip-guix-home for > a while to bring all related stuff like documentation and cli to the > branch and merge it to the master after everything is complete. > > Also, merging only part of Guix Home to the master will arise conflicts > for users of rde channel (which contains current implementation of Guix > Home). However, it is solvable by removing already merged parts from > rde repository, so, it's not a big deal and I'm fine with both merging > options. OK, pushed to the wip-guix-home. https://git.savannah.gnu.org/cgit/guix.git/?h=wip-guix-home [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 861 bytes --] ^ permalink raw reply [flat|nested] 38+ messages in thread
* [bug#49419] [PATCH 0/4] Essential home services 2021-08-24 12:14 ` bug#49419: " Oleg Pykhalov @ 2021-08-26 7:01 ` Andrew Tropin 0 siblings, 0 replies; 38+ messages in thread From: Andrew Tropin @ 2021-08-26 7:01 UTC (permalink / raw) To: Oleg Pykhalov; +Cc: 49419-done [-- Attachment #1: Type: text/plain, Size: 1260 bytes --] On 2021-08-24 15:14, Oleg Pykhalov wrote: > Andrew Tropin <andrew@trop.in> writes: > > […] > >>> As Ludovic suggested, we could move modules to another namespace for >>> code sharing, but it is not a blocker from merging changes and we could >>> do it later when we need to share the code. I think we should go >>> forward and push to the master. WDYT? >> >> Yep, let's postpone moving modules to another namespace until it will be >> needed. Later, when the necessity appears, we will decide how to better >> organize the code. >> >> We can push it to master, but I planned to keep it in wip-guix-home for >> a while to bring all related stuff like documentation and cli to the >> branch and merge it to the master after everything is complete. >> >> Also, merging only part of Guix Home to the master will arise conflicts >> for users of rde channel (which contains current implementation of Guix >> Home). However, it is solvable by removing already merged parts from >> rde repository, so, it's not a big deal and I'm fine with both merging >> options. > > OK, pushed to the wip-guix-home. > > https://git.savannah.gnu.org/cgit/guix.git/?h=wip-guix-home Thank you very much!) Sent a next patch for Guix Home. #50208 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 853 bytes --] ^ permalink raw reply [flat|nested] 38+ messages in thread
end of thread, other threads:[~2021-08-26 7:03 UTC | newest] Thread overview: 38+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2021-07-05 15:35 [bug#49419] [PATCH 0/4] Essential home services Andrew Tropin 2021-07-05 15:37 ` [bug#49419] [PATCH 1/4] home-services: Add most essential " Andrew Tropin 2021-07-05 15:47 ` Maxime Devos 2021-07-05 16:19 ` Andrew Tropin 2021-07-05 19:19 ` Maxime Devos 2021-07-06 7:09 ` Andrew Tropin 2021-07-06 8:26 ` Maxime Devos 2021-07-06 7:23 ` Andrew Tropin 2021-07-05 15:39 ` [bug#49419] [PATCH 2/4] home-services: Add home-run-on-change-service-type Andrew Tropin 2021-07-05 15:41 ` [bug#49419] [PATCH 3/4] home-services: Add home-provenance-service-type Andrew Tropin 2021-07-05 15:41 ` [bug#49419] [PATCH 4/4] home-services: Add fold-home-service-types function Andrew Tropin 2021-07-13 16:17 ` [bug#49419] [PATCH v2 0/4] Essential home services Andrew Tropin 2021-07-05 15:37 ` [bug#49546] [PATCH v2 1/4] home-services: Add most essential " Andrew Tropin [not found] ` <handler.49546.B.16262002971832.ack@debbugs.gnu.org> 2021-07-13 18:24 ` [bug#49546] Acknowledgement ([PATCH v2 1/4] home-services: Add most essential home services) Andrew Tropin 2021-07-05 15:39 ` [bug#49547] [PATCH v2 2/4] home-services: Add home-run-on-change-service-type Andrew Tropin 2021-07-14 10:41 ` Maxime Devos 2021-07-15 8:46 ` Andrew Tropin 2021-07-18 16:17 ` Maxime Devos 2021-07-05 15:41 ` [bug#49548] [PATCH v2 3/4] home-services: Add home-provenance-service-type Andrew Tropin 2021-07-05 15:41 ` [bug#49549] [PATCH v2 4/4] home-services: Add fold-home-service-types function Andrew Tropin 2021-07-15 9:59 ` [bug#49568] Testing reply without debbugs address Andrew Tropin 2021-07-19 8:04 ` [bug#49419] [PATCH v3 0/4] Essential home services Andrew Tropin 2021-07-05 15:37 ` [bug#49419] [PATCH v3 1/4] home-services: Add most essential " Andrew Tropin 2021-07-05 15:39 ` [bug#49419] [PATCH v3 2/4] home-services: Add home-run-on-change-service-type Andrew Tropin 2021-07-05 15:41 ` [bug#49419] [PATCH v3 3/4] home-services: Add home-provenance-service-type Andrew Tropin 2021-07-05 15:41 ` [bug#49419] [PATCH v3 4/4] home-services: Add fold-home-service-types function Andrew Tropin 2021-07-21 15:08 ` [bug#49419] [PATCH 0/4] Essential home services Ludovic Courtès 2021-07-28 5:35 ` Andrew Tropin [not found] ` <handler.49419.B.162549932625345.ack@debbugs.gnu.org> 2021-08-05 5:41 ` [bug#49419] [PATCH v4 " Andrew Tropin 2021-08-05 5:45 ` [bug#49419] [PATCH v4 1/4] home-services: Add most essential " Andrew Tropin 2021-08-05 5:46 ` [bug#49419] [PATCH v4 2/4] home-services: Add home-run-on-change-service-type Andrew Tropin 2021-08-05 5:46 ` [bug#49419] [PATCH v4 3/4] home-services: Add home-provenance-service-type Andrew Tropin 2021-08-05 5:47 ` [bug#49419] [PATCH v4 4/4] home-services: Add fold-home-service-types function Andrew Tropin 2021-08-23 9:57 ` [bug#49419] [PATCH v4 0/4] Essential home services Andrew Tropin 2021-08-23 16:24 ` [bug#49419] [PATCH " Oleg Pykhalov 2021-08-24 8:53 ` Andrew Tropin 2021-08-24 12:14 ` bug#49419: " Oleg Pykhalov 2021-08-26 7:01 ` [bug#49419] " Andrew Tropin
Code repositories for project(s) associated with this public inbox https://git.savannah.gnu.org/cgit/guix.git This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).