From patchwork Sun Jan 28 15:37:16 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: paul X-Patchwork-Id: 59536 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id 72A2127BBEA; Sun, 28 Jan 2024 15:38:14 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-3.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL, SPF_HELO_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id D481D27BBE2 for ; Sun, 28 Jan 2024 15:38:12 +0000 (GMT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rU7EN-0000El-R1; Sun, 28 Jan 2024 10:37:59 -0500 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 1rU7EJ-0000Cv-Tn for guix-patches@gnu.org; Sun, 28 Jan 2024 10:37:56 -0500 Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rU7EJ-0002L8-JP for guix-patches@gnu.org; Sun, 28 Jan 2024 10:37:55 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1rU7ER-0008WA-0S for guix-patches@gnu.org; Sun, 28 Jan 2024 10:38:03 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#60521] [PATCH v7] home: Add home-dotfiles-service. References: <0a8d7bce31856292baa06a08260494c0@autistici.org> In-Reply-To: <0a8d7bce31856292baa06a08260494c0@autistici.org> Resent-From: Giacomo Leidi Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sun, 28 Jan 2024 15:38:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 60521 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: moreinfo patch To: 60521@debbugs.gnu.org Cc: Giacomo Leidi , Ludovic =?utf-8?q?Court=C3=A8?= =?utf-8?q?s?= Received: via spool by 60521-submit@debbugs.gnu.org id=B60521.170645628232734 (code B ref 60521); Sun, 28 Jan 2024 15:38:02 +0000 Received: (at 60521) by debbugs.gnu.org; 28 Jan 2024 15:38:02 +0000 Received: from localhost ([127.0.0.1]:58200 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rU7EP-0008Vn-8C for submit@debbugs.gnu.org; Sun, 28 Jan 2024 10:38:02 -0500 Received: from confino.investici.org ([93.190.126.19]:23815) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rU7EM-0008Ve-U6 for 60521@debbugs.gnu.org; Sun, 28 Jan 2024 10:38:00 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org; s=stigmate; t=1706456270; bh=FcEDQey+E3FAcp4H5tQF4JT4WyMR/8JM0AvYIrDcnv0=; h=From:To:Cc:Subject:Date:From; b=Phrtxtcc1qEG8TvNDhIVHxiEpknijwk9ZI3PBkXCu00P7X6cmUlWsHKqr4TpPsuhp Fx9pJIfV4Ce8h4d/eGaERTkAPX+vYoZyvfbDdUhVIN/ATc6eZ9Taf4It7VZNzlTwCR ZWNAPqcFWlPjzblUyGtl/uuDWiu9y2tOZuZbupaM= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4TNFtk2mrcz10wK; Sun, 28 Jan 2024 15:37:50 +0000 (UTC) Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19]) (Authenticated sender: goodoldpaul@autistici.org) by localhost (Postfix) with ESMTPSA id 4TNFtk1k2tz10wB; Sun, 28 Jan 2024 15:37:50 +0000 (UTC) Date: Sun, 28 Jan 2024 16:37:16 +0100 Message-ID: <20240128153716.20514-1-goodoldpaul@autistici.org> X-Mailer: git-send-email 2.41.0 MIME-Version: 1.0 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 X-Patchwork-Original-From: Giacomo Leidi via Guix-patches via From: paul Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org X-getmail-retrieved-from-mailbox: Patches * gnu/home/services.scm: New file; (dotfiles-for-app): new variable; (home-dotfiles-configuration): new variable; (home-dotfiles-service-type): new variable. * gnu/local.mk (GNU_SYSTEM_MODULES): Add it. * po/guix/POTFILES.in: Add it. * doc/guix.texi: Document it. Change-Id: I6769169cfacefc3842faa5b31bee081c56c28743 Co-authored-by: Ludovic Courtès --- doc/guix.texi | 108 +++++++++++++++++++++++++++++ gnu/home/services/dotfiles.scm | 120 +++++++++++++++++++++++++++++++++ gnu/local.mk | 1 + po/guix/POTFILES.in | 1 + 4 files changed, 230 insertions(+) create mode 100644 gnu/home/services/dotfiles.scm base-commit: 8ae8b9804fa4aef23d4028563559bf7bec52fec2 diff --git a/doc/guix.texi b/doc/guix.texi index db0c751ded..c723631abe 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -44204,6 +44204,114 @@ to use alternative services to implement more advanced use cases like 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} from @code{(gnu home services dotfiles)} +is designed to ease the way into using Guix Home for this kind of users, +allowing them to point the service to their dotfiles directory, which must +follow the layout suggested by +@uref{https://www.gnu.org/software/stow/, GNU Stow}, +and have their dotfiles automatically deployed to their user home, without +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 +(home-environment + ;; @dots{} + (services + (service home-dotfiles-service-type + (home-dotfiles-configuration + (directories (list "./dotfiles")))))) +@end lisp + +The expected home directory state would then 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 files 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{source-directory} (default: @code{(current-source-directory)}) +The path where dotfile directories are resolved. By default dotfile directories +are resolved relative the source location where +@code{home-dotfiles-configuration} appears. + +@item @code{directories} (type: list-of-strings) +The list of dotfiles directories where @code{home-dotfiles-service-type} will +look for application dotfiles. + +@item @code{exclude} (default: @code{'(".*~" ".*\\.swp" "\\.git" "\\.gitignore")}) +The list of file patterns @code{home-dotfiles-service-type} will exclude while +visiting each one of the @code{directories}. + +@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/dotfiles.scm b/gnu/home/services/dotfiles.scm new file mode 100644 index 0000000000..7226b6bcff --- /dev/null +++ b/gnu/home/services/dotfiles.scm @@ -0,0 +1,120 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2024 Ludovic Courtès +;;; Copyright © 2024 Giacomo Leidi +;;; +;;; 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 . + +(define-module (gnu home services dotfiles) + #:use-module (gnu home services) + #:use-module (gnu services) + #:autoload (guix build utils) (find-files) + #:use-module (guix gexp) + #:use-module (guix records) + #:use-module ((guix utils) #:select (current-source-directory)) + #:use-module (srfi srfi-1) + #:use-module (ice-9 ftw) + #:use-module (ice-9 regex) + #:export (home-dotfiles-service-type + home-dotfiles-configuration + home-dotfiles-configuration? + home-dotfiles-configuration-source-directory + home-dotfiles-configuration-directories + home-dotfiles-configuration-excluded)) + +(define %home-dotfiles-excluded + '(".*~" + ".*\\.swp" + "\\.git" + "\\.gitignore")) + +(define-record-type* + home-dotfiles-configuration make-home-dotfiles-configuration + home-dotfiles-configuration? + (source-directory home-dotfiles-configuration-source-directory + (default (current-source-directory)) + (innate)) + (directories home-dotfiles-configuration-directories ;list of strings + (default '())) + (excluded home-dotfiles-configuration-excluded ;list of strings + (default %home-dotfiles-excluded))) + +(define (import-dotfiles directory files) + "Return a list of objects compatible with @code{home-files-service-type}'s +value. Each object is a pair where the first element is the relative path +of a file and the second is a gexp representing the file content. Objects are +generated by recursively visiting DIRECTORY and mapping its contents to the +user's home directory, excluding files that match any of the patterns in EXCLUDED." + (define (strip file) + (string-join + (cdr + (string-split (string-drop file (+ 1 (string-length directory))) + #\/)) + "/")) + (define (format file) + ;; Remove from FILE characters that cannot be used in the store. + (string-append + "home-dotfiles-" + (string-map (lambda (chr) + (if (and (char-set-contains? char-set:ascii chr) + (char-set-contains? char-set:graphic chr) + (not (memv chr '(#\. #\/ #\space)))) + chr + #\-)) + file))) + + (map (lambda (file) + (let ((stripped (strip file))) + (list stripped + (local-file file (format stripped) + #:recursive? #t)))) + files)) + +(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 excluded + (home-dotfiles-configuration-excluded config)) + (define exclusion-rx + (make-regexp (string-append "^.*(" (string-join excluded "|") ")$"))) + + (define (directory-contents directory) + (find-files directory + (lambda (file stat) + (not (regexp-exec exclusion-rx + (basename file)))))) + + (define (resolve directory) + ;; Resolve DIRECTORY relative to the 'source-directory' field of CONFIG. + (if (string-prefix? "/" directory) + directory + (in-vicinity (home-dotfiles-configuration-source-directory config) + directory))) + + (append-map (lambda (directory) + (let* ((directory (resolve directory)) + (contents (directory-contents directory))) + (import-dotfiles 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."))) diff --git a/gnu/local.mk b/gnu/local.mk index ab63bd5881..f11c65277e 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -96,6 +96,7 @@ GNU_SYSTEM_MODULES = \ %D%/home/services.scm \ %D%/home/services/desktop.scm \ %D%/home/services/dict.scm \ + %D%/home/services/dotfiles.scm \ %D%/home/services/symlink-manager.scm \ %D%/home/services/fontutils.scm \ %D%/home/services/gnupg.scm \ diff --git a/po/guix/POTFILES.in b/po/guix/POTFILES.in index 154ad4e530..d13e19619d 100644 --- a/po/guix/POTFILES.in +++ b/po/guix/POTFILES.in @@ -14,6 +14,7 @@ gnu/services/samba.scm gnu/services/version-control.scm gnu/home/services.scm gnu/home/services/desktop.scm +gnu/home/services/dotfiles.scm gnu/home/services/fontutils.scm gnu/home/services/gnupg.scm gnu/home/services/guix.scm