Subject: [PATCH v3 05/10] services: Add etc-bashrc-d-service-type.

From: Maxim Cournoyer <[email-masked]>
Date: Mon, 19 May 2025 09:29:03 +0900

* gnu/services.scm (files->bashrc-d-directory) New procedure.
(etc-bashrc-d-service-type): New service type.
* doc/guix.texi (Service Reference): Document it.
* gnu/tests/base.scm (test-basic-os): Test it.

Change-Id: Ibbb0f684de7aee296adedbce5b1192786d661af2
---
 doc/guix.texi      | 18 ++++++++++++++++++
 gnu/services.scm   | 14 ++++++++++++++
 gnu/tests/base.scm | 39 ++++++++++++++++++++++++++++++---------
 3 files changed, 62 insertions(+), 9 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index b236a358a1f..927e9243bfb 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -47645,6 +47645,24 @@ Service Reference
 @end example
 @end defvar
 
+@defvar etc-bashrc-d-service-type
+The type of the @file{/etc/bashrc.d} service.  This service is used to
+create files under @file{/etc/bashrc.d}.  It takes as value a list of
+file-like objects, as can be produced with @code{local-file},
+@code{plain-file}, etc.  Note that provided files whose file names do
+not end with @file{.sh} are @emph{not} added to @file{/etc/profile.d/}
+and are silently dropped.  Package objects can also be provided directly
+to have their @file{etc/bashrc.d/*.sh} prefixed files added.  An example
+usage may look like:
+
+@example
+(use-package-modules gnome)     ;for the `vte' package
+
+(service etc-bashrc-d-service-type
+         (list (file-append vte "/etc/profile.d/vte.sh")))
+@end example
+@end defvar
+
 @defvar privileged-program-service-type
 Type for the ``privileged-program service''.  This service collects lists of
 executable file names, passed as gexps, and adds them to the set of
diff --git a/gnu/services.scm b/gnu/services.scm
index 8584b16ac5c..7083c88c130 100644
--- a/gnu/services.scm
+++ b/gnu/services.scm
@@ -123,6 +123,7 @@ (define-module (gnu services)
             extra-special-file
             etc-service-type
             etc-profile-d-service-type
+            etc-bashrc-d-service-type
             etc-directory
             privileged-program-service-type
             setuid-program-service-type ; deprecated
@@ -988,6 +989,19 @@ (define etc-profile-d-service-type
 scripts having the @file{.sh} file extension, to be sourced when users
 log in.")))
 
+(define files->bashrc-d-directory
+  (make-files->etc-directory "bashrc.d"))
+
+(define etc-bashrc-d-service-type
+  (service-type
+   (inherit etc-profile-d-service-type)
+   (name 'etc-bashrc-d)
+   (extensions (list (service-extension etc-service-type
+                                        files->bashrc-d-directory)))
+   (description "A service for populating @file{/etc/bashrc.d/} with Bash
+scripts having the @file{.sh} file extension, to be sourced by interactive
+Bash shells.")))
+
 (define (privileged-program->activation-gexp programs)
   "Return an activation gexp for privileged-program from PROGRAMS."
   (let ((programs
diff --git a/gnu/tests/base.scm b/gnu/tests/base.scm
index 09fc91383df..0f31c152e0f 100644
--- a/gnu/tests/base.scm
+++ b/gnu/tests/base.scm
@@ -178,6 +178,19 @@ (define* (run-basic-test os command #:optional (name "basic")
 test \"$PROFILE_D_OK\" = yes")
                                     marionette)))
 
+          (test-assert "/etc/bashrc.d is sourced"
+            (zero? (marionette-eval
+                    '(system* "bash"
+                              ;; Ensure Bash runs interactively.
+                              "--init-file"
+                              #$(plain-file "test_bashrc_d.sh"
+                                            "\
+. /etc/bashrc
+set -e -x
+test -f /etc/bashrc.d/test_bashrc_d.sh
+test \"$BASHRC_D_OK\" = yes"))
+                    marionette)))
+
           (test-equal "special files"
             '#$special-files
             (marionette-eval
@@ -585,15 +598,23 @@ (define* (test-basic-os #:optional (kernel linux-libre))
                  (operating-system
                    (inherit %simple-os)
                    (kernel kernel)
-                   (services (cons (service
-                                    etc-profile-d-service-type
-                                    (list (plain-file
-                                           "test_profile_d.sh"
-                                           "export PROFILE_D_OK=yes\n")
-                                          (plain-file
-                                           "invalid-name"
-                                           "not a POSIX script -- ignore me")))
-                                   %base-services)))
+                   (services (cons* (service
+                                     etc-profile-d-service-type
+                                     (list (plain-file
+                                            "test_profile_d.sh"
+                                            "export PROFILE_D_OK=yes\n")
+                                           (plain-file
+                                            "invalid-name"
+                                            "not a POSIX script -- ignore me")))
+                                    (service
+                                     etc-bashrc-d-service-type
+                                     (list (plain-file
+                                            "test_bashrc_d.sh"
+                                            "export BASHRC_D_OK=yes\n")
+                                           (plain-file
+                                            "invalid-name"
+                                            "not a Bash script -- ignore me")))
+                                    %base-services)))
                  #:imported-modules '((gnu services herd)
                                       (guix combinators))))
            (vm  (virtual-machine os)))
-- 
2.49.0