2 files changed, 51 insertions(+) gnu/packages.scm | 1 + gnu/services/configuration.scm | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ modified gnu/packages.scm @@ -49,6 +49,7 @@ (define-module (gnu packages) #:export (search-patch search-patches search-auxiliary-file + %distro-root-directory %patch-path %auxiliary-files-path %package-module-path modified gnu/services/configuration.scm @@ -25,6 +25,9 @@ ;;; along with GNU Guix. If not, see . (define-module (gnu services configuration) + #:use-module (gnu packages) + #:use-module (guix discovery) + #:use-module (guix memoization) #:use-module (guix packages) #:use-module (guix records) #:use-module (guix gexp) @@ -34,6 +37,7 @@ (define-module (gnu services configuration) warning)) #:use-module ((guix modules) #:select (file-name->module-name)) #:use-module (guix i18n) + #:use-module ((guix ui) #:select (warn-about-load-error)) #:autoload (texinfo) (texi-fragment->stexi) #:autoload (texinfo serialize) (stexi->texi) #:use-module (ice-9 curried-definitions) @@ -588,3 +592,49 @@ (define (generic-serialize-alist combine serialize-field fields) @code{append} are usually good candidates for this." (apply combine (map (generic-serialize-alist-entry serialize-field) fields))) + + +;;; +;;; Configuration objects discovery. +;;; + +(define %default-service-module-path + ;; Default search path for service modules. + `((,%distro-root-directory . "gnu/services"))) + +(define (define-configuration? module symbol) + "Predicate to check if SYMBOL points to a `define-configuration'-generated +object in MODULE." + (let ((fields-variable-name (symbol-append symbol '-fields))) + (or (module-local-variable module fields-variable-name) ;private variable + (module-variable module fields-variable-name)))) ;public variable + +(define (interface->directory interface) + "Convert a module interface to a module directory." + (resolve-module (module-name interface))) + +(define* (fold-configurations proc init + #:optional + (modules + (map interface->directory + (all-modules %default-service-module-path + #:warn + warn-about-load-error))) + #:key (select? (const #t))) + "Call (PROC MODULE SYMBOL RESULT) for each service configuration defined via +`define-configuration' in the MODULES that matches SELECT?, using INIT as the +initial value of RESULT. SELECT? is called with two arguments, the module +object as well as the variable name (a symbol) of the configuration record +constructor, e.g. @code{'forgejo-configuration}." + ;; FIXME: Contrary to its name, `fold-module-public-variables*' (and + ;; fold-module-public-variables) fold all the variables of a module, + ;; including the private ones. The distinction between public/private is + ;; made by whether the MODULES provided are whole modules (resolve-module) + ;; or just their exported interface (resolve-interface). + (fold-module-public-variables* (lambda (module symbol _ result) + (if (and (define-configuration? module symbol) + (select? module symbol)) + (proc module symbol result) + result)) + init + modules)) [back]