From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp12.migadu.com ([2001:41d0:2:bcc0::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms9.migadu.com with LMTPS id 8KPVBEUTl2ToJQEASxT56A (envelope-from ) for ; Sat, 24 Jun 2023 18:01:09 +0200 Received: from aspmx1.migadu.com ([2001:41d0:2:bcc0::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp12.migadu.com with LMTPS id sCXQBEUTl2R9sgAAauVa8A (envelope-from ) for ; Sat, 24 Jun 2023 18:01:09 +0200 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id A7CB9DB19 for ; Sat, 24 Jun 2023 18:01:08 +0200 (CEST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qD5gK-0002su-Ob; Sat, 24 Jun 2023 12:00:12 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qD5gB-0002s7-4e for guix-patches@gnu.org; Sat, 24 Jun 2023 12:00:03 -0400 Received: from debbugs.gnu.org ([209.51.188.43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1qD5gA-0007s9-Pf for guix-patches@gnu.org; Sat, 24 Jun 2023 12:00:02 -0400 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1qD5gA-0000vT-Kg for guix-patches@gnu.org; Sat, 24 Jun 2023 12:00:02 -0400 X-Loop: help-debbugs@gnu.org Subject: [bug#64269] [PATCH-v4] home: Add home-dotfiles-service. Resent-From: Giacomo Leidi Original-Sender: "Debbugs-submit" Resent-CC: , guix-patches@gnu.org Resent-Date: Sat, 24 Jun 2023 16:00:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 64269 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 64269@debbugs.gnu.org Cc: Giacomo Leidi , ( , Andrew Tropin , Ludovic =?UTF-8?Q?Court=C3=A8s?= X-Debbugs-Original-To: guix-patches@gnu.org X-Debbugs-Original-Xcc: ( , Andrew Tropin , Ludovic =?UTF-8?Q?Court=C3=A8s?= Received: via spool by submit@debbugs.gnu.org id=B.16876223903505 (code B ref -1); Sat, 24 Jun 2023 16:00:02 +0000 Received: (at submit) by debbugs.gnu.org; 24 Jun 2023 15:59:50 +0000 Received: from localhost ([127.0.0.1]:41364 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qD5fx-0000uS-M1 for submit@debbugs.gnu.org; Sat, 24 Jun 2023 11:59:50 -0400 Received: from lists.gnu.org ([209.51.188.17]:41446) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qD5ft-0000uH-7E for submit@debbugs.gnu.org; Sat, 24 Jun 2023 11:59:47 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qD5fs-0002qT-Rt for guix-patches@gnu.org; Sat, 24 Jun 2023 11:59:44 -0400 Received: from confino.investici.org ([93.190.126.19]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qD5fq-0007n5-Da for guix-patches@gnu.org; Sat, 24 Jun 2023 11:59:44 -0400 Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4QpJhV3V8sz11DR; Sat, 24 Jun 2023 15:59:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1687622378; bh=kEVWmWMDI6ROyL0EwR2aQ1ZbhbGAm4v7SHOrgZ+Tl60=; h=From:To:Cc:Subject:Date:From; b=fkluANDIeRM3uPmlGACWyzdGKS29kwL2f8K7JbxNnKA2pnKlLHCBfVC2a5uIAKHVO COqwOCDDmhWtzlbTApT+sQuSfY+dMnNWEQkKG6RT4tk4tWip89WenguV/3Rjth8qHn qonW06RtiIcjv037a6ykiYpL6NMXzisxvTjx25OQ= Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4QpJhV2vbZz11DM; Sat, 24 Jun 2023 15:59:38 +0000 (UTC) Date: Sat, 24 Jun 2023 17:59:03 +0200 Message-Id: X-Mailer: git-send-email 2.40.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Received-SPF: pass client-ip=93.190.126.19; envelope-from=goodoldpaul@autistici.org; helo=confino.investici.org X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Giacomo Leidi X-ACL-Warn: , Giacomo Leidi via Guix-patches From: Giacomo Leidi via Guix-patches via Errors-To: guix-patches-bounces+larch=yhetil.org@gnu.org Sender: guix-patches-bounces+larch=yhetil.org@gnu.org X-Migadu-Country: US X-Migadu-Flow: FLOW_IN ARC-Seal: i=1; s=key1; d=yhetil.org; t=1687622468; a=rsa-sha256; cv=none; b=ghlt/7IeLmLEiv/dLBtmw/JMAiz6Ah7JfRmrvFnFE4f1Ycb2T7aXS/4siZotDPDSPamkM6 YtJlrvanyh3g5airu2MGoPIgUcDDxFrhHbAslm8jDSIlT2jjo5Bp6weegW802JQ8pU46/T DHC3SMeak90dpB6jjn0Nd2UVlaMvccF+LJ1GJYW3Y4wa4GBqv4iRZUg1uetOP+GvoteF9d /lKwdNFRAuqxsX2u54sGDZgvS4AcnhZqFYTthuLGw2yXxwSfj3Grs0LOOk0g3z15cV8vGu uelHgKl0UDI8uUIKnrQ+W4/Rkpa3BbzD8oq65zzLhhH5jlfIlo5TkN7jg/gHmA== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=autistici.org header.s=stigmate header.b=fkluANDI; dmarc=pass (policy=none) header.from=gnu.org; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org" ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1687622468; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding:resent-cc: resent-from:resent-sender:resent-message-id:list-id:list-help: list-unsubscribe:list-subscribe:list-post:dkim-signature; bh=kEVWmWMDI6ROyL0EwR2aQ1ZbhbGAm4v7SHOrgZ+Tl60=; b=OGRiWjrm96Mi83AxG5FehRLU6f23PaFFJ6/Vsv4WwypOZGMjBTYyeXxl2MiqZOWT1UcGSc hJtab8J/RgQqt9xcFr3O2ntKY9AcdcD2yUgkPU3YBZcJ9Wxg4dG2CCXlGQuZi18Wa+wkLF +cGbvH82FY3m4NPt7MmLObzQBUSWryxhYpoZmSM0gdolNKXf6AN6SDIpD/DtVjiqeEOD0K 5vVATZTrhHu1Y+gN72NJpWOdecPWqMedy8XHnNDpxih8UZqOVLCkQjCDPkwSWPc9hE8gfe 95kX0RBXf2vZP/36oEbTNqsVCG04848WbLXsgOh9ezt2jhviIKLywWOYcs6A1A== Authentication-Results: aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=autistici.org header.s=stigmate header.b=fkluANDI; dmarc=pass (policy=none) header.from=gnu.org; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org" X-Migadu-Scanner: scn0.migadu.com X-Migadu-Spam-Score: -3.25 X-Spam-Score: -3.25 X-Migadu-Queue-Id: A7CB9DB19 X-TUID: K6/hNbiZfjka * gnu/home/services.scm (dotfiles-for-app): New variable; (home-dotfiles-configuration): new variable; (home-dotfiles-service-type): new variable. * doc/guix.texi: Document it. --- doc/guix.texi | 108 ++++++++++++++++++++++++++++++++++++++++++ gnu/home/services.scm | 78 ++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+) diff --git a/doc/guix.texi b/doc/guix.texi index c961f706ec..cb3b0d05b0 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -42659,6 +42659,114 @@ Essential Home Services read-only home. Feel free to experiment and share your results. @end defvar +It is often the case that Guix Home users already have a setup for versioning +their user configuration files (also known as @emph{dotfiles}) in a single +directory, and some way of automatically deploy changes to their user home. + +The @code{home-dotfiles-service-type} is designed to ease the way into using +Guix Home for this kind of users, allowing them to point the service to their +dotfiles directory, which must follow the layout suggested by +@uref{https://www.gnu.org/software/stow/, GNU Stow}, +and have their dotfiles automatically deployed to their user home, without +migrating them to Guix native configurations. + +The dotfiles directory layout is expected to be structured as follows. Please +keep in mind that it is advisable to keep your dotfiles directories under +version control, for example in the same repository where you'd track your +Guix Home configuration. + +@example +~$ tree -a .dotfiles/ +.dotfiles/ +├── git +│ └── .gitconfig +├── gpg +│ └── .gnupg +│ ├── gpg-agent.conf +│ └── gpg.conf +├── guile +│ └── .guile +├── guix +│ └── .config +│ └── guix +│ └── channels.scm +├── nix +│ ├── .config +│ │ └── nixpkgs +│ │ └── config.nix +│ └── .nix-channels +├── tmux +│ └── .tmux.conf +└── vim + └── .vimrc + +13 directories, 10 files +@end example + +For an informal specification please refer to the Stow manual +(@pxref{Top,,, stow, Introduction}). A suitable configuration would then +be: + +@lisp +(use-modules (guix utils)) + +(home-environment + + [...] + + (services + (service home-dotfiles-service-type + (home-dotfiles-configuration + (directories + (list (string-append (current-source-directory) + "/.dotfiles"))))))) +@end lisp + +The expected home directory state would be: + +@example +. +├── .config +│ ├── guix +│ │ └── channels.scm +│ └── nixpkgs +│ └── config.nix +├── .gitconfig +├── .gnupg +│ ├── gpg-agent.conf +│ └── gpg.conf +├── .guile +├── .nix-channels +├── .tmux.conf +└── .vimrc +@end example + +@defvar home-dotfiles-service-type +Return a service which is very similiar to @code{home-files-service-type} +(and actually extends it), but designed to ease the way into using Guix +Home for users that already track their dotfiles under some kind of version +control. This service allows users to point Guix Home to their dotfiles +directory and have their file automatically deployed to their home directory +just like Stow would, without migrating all of their dotfiles to Guix native +configurations. +@end defvar + +@deftp {Data Type} home-dotfiles-configuration +Available @code{home-dotfiles-configuration} fields are: + +@table @asis +@item @code{directories} (type: list-of-strings) +The list of dotfiles directories where @code{home-dotfiles-service-type} will +look for application dotfiles. + +@item @code{exclude} (default: @code{'(".*~" ".*\\.swp" "\\.gitignore")}) +The list of file patterns @code{home-dotfiles-service-type} will exclude while +visiting @code{directories}. + +@end table + +@end deftp + @defvar home-xdg-configuration-files-service-type The service is very similar to @code{home-files-service-type} (and actually extends it), but used for defining files, which will go to diff --git a/gnu/home/services.scm b/gnu/home/services.scm index b17a34d19d..2fe6508a9a 100644 --- a/gnu/home/services.scm +++ b/gnu/home/services.scm @@ -2,6 +2,7 @@ ;;; Copyright © 2021-2023 Andrew Tropin ;;; Copyright © 2021 Xinglu Chen ;;; Copyright © 2022-2023 Ludovic Courtès +;;; Copyright © 2023 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -22,6 +23,7 @@ (define-module (gnu home services) #:use-module (gnu services) #:use-module ((gnu packages package-management) #:select (guix)) #:use-module ((gnu packages base) #:select (coreutils)) + #:use-module (guix build utils) #:use-module (guix channels) #:use-module (guix monads) #:use-module (guix store) @@ -33,15 +35,24 @@ (define-module (gnu home services) #:use-module (guix diagnostics) #:use-module (guix i18n) #:use-module (guix modules) + #:use-module (guix records) #:use-module (srfi srfi-1) #:use-module (srfi srfi-9) + #:use-module (ice-9 ftw) #:use-module (ice-9 match) + #:use-module (ice-9 regex) + #:use-module (ice-9 string-fun) #:use-module (ice-9 vlist) #:export (home-service-type home-profile-service-type home-environment-variables-service-type home-files-service-type + home-dotfiles-service-type + home-dotfiles-configuration + home-dotfiles-configuration? + home-dotfiles-configuration-directories + home-dotfiles-configuration-excluded home-xdg-configuration-files-service-type home-xdg-data-files-service-type home-run-on-first-login-service-type @@ -341,6 +352,73 @@ (define home-files-service-type (description "Files that will be put in @file{~/.guix-home/files}, and further processed during activation."))) +(define %home-dotfiles-excluded + '(".*~" + ".*\\.swp" + "\\.gitignore")) + +(define-record-type* + home-dotfiles-configuration make-home-dotfiles-configuration + home-dotfiles-configuration? + (directories home-dotfiles-configuration-directories ;list of strings + (default '())) + (excluded home-dotfiles-configuration-excluded ;list of strings + (default %home-dotfiles-excluded))) + +(define* (import-dotfiles directory excluded) + "Return a list of objects compatible with @code{home-files-service-type}'s +value. Each object is a pair where the first element is the relative path +of a file and the second is a gexp representing the file content. Objects are +generated by recursively visiting DIRECTORY and mapping its contents to the +user's home directory, excluding files that match any of the patterns in EXCLUDED." + (define filtered + (find-files directory + (lambda (file stat) + (not (string-match + (string-append + "^.*(" (string-join excluded "|") ")$") file))))) + (define (strip file) + (string-drop file (+ 1 (string-length directory)))) + (define (format file) + (string-append "home-dotfiles-" + (string-replace-substring file "/" "-"))) + + (map (lambda (file) + (let* ((stripped (strip file))) + (list stripped + (local-file file (format stripped))))) + filtered)) + +(define (home-dotfiles-configuration->files config) + "Return a list of objects compatible with @code{home-files-service-type}'s +value, generated following GNU Stow's algorithm for each of the +directories in CONFIG, excluding files that match any of the patterns configured." + (define (directory-contents directories) + (append-map + (lambda (directory) + (map + (lambda (content) + (with-directory-excursion directory + (canonicalize-path content))) + (scandir directory + (lambda (name) + (not (member name '("." ".."))))))) + directories)) + (append-map + (lambda (app) + (import-dotfiles app (home-dotfiles-configuration-excluded config))) + (directory-contents + (home-dotfiles-configuration-directories config)))) + +(define-public home-dotfiles-service-type + (service-type (name 'home-dotfiles) + (extensions + (list (service-extension home-files-service-type + home-dotfiles-configuration->files))) + (default-value (home-dotfiles-configuration)) + (description "Files that will be put in the user's home directory +following GNU Stow's algorithm, and further processed during activation."))) + (define xdg-configuration-files-directory ".config") (define (xdg-configuration-files files) base-commit: d6dc82e8cdb2d6114a12b06d449ce7f1150c7f70 -- 2.40.1