diff --git a/modules/rosenthal/services/monitoring.scm b/modules/rosenthal/services/monitoring.scm index a66bc38..000c2a8 100644 --- a/modules/rosenthal/services/monitoring.scm +++ b/modules/rosenthal/services/monitoring.scm @@ -6,8 +6,8 @@ #:use-module (guix gexp) #:use-module (guix modules) #:use-module (guix records) + #:use-module (rosenthal utils file) #:use-module (rosenthal utils predicates) - #:use-module (rosenthal utils serializers ini) #:use-module (rosenthal utils serializers yaml) ;; Guix System #:use-module (gnu system shadow) @@ -99,7 +99,7 @@ (file-like grafana-bin) "") (config - ini-config + gexp "") (postgresql-password-file string @@ -158,13 +158,7 @@ (define grafana-shepherd (match-record-lambda (grafana config shepherd-provision shepherd-requirement auto-start?) - (let ((config-file - (computed-file "grafana.ini" - (with-extensions (list guile-ini guile-lib guile-smc) - #~(begin - (use-modules (srfi srfi-26) (ini)) - (call-with-output-file #$output - (cut scm->ini '#$config #:port <>))))))) + (let ((config-file (ini-file "grafana.ini" config))) (list (shepherd-service (provision shepherd-provision) (requirement `(loopback postgresql user-processes diff --git a/modules/rosenthal/services/web.scm b/modules/rosenthal/services/web.scm index 8434f08..2d4753d 100644 --- a/modules/rosenthal/services/web.scm +++ b/modules/rosenthal/services/web.scm @@ -6,8 +6,8 @@ #:use-module (guix gexp) #:use-module (guix modules) #:use-module (guix records) + #:use-module (rosenthal utils file) #:use-module (rosenthal utils predicates) - #:use-module (rosenthal utils serializers ini) #:use-module (rosenthal utils serializers yaml) ;; Guix System #:use-module (gnu system privilege) @@ -281,7 +281,7 @@ reload its configuration file.")) (list-of-file-likes (list git git-lfs)) "@code{git} and extension packages to install.") (config - ini-config + gexp "") (postgresql-password-file string @@ -331,13 +331,7 @@ reload its configuration file.")) (define forgejo-shepherd-service (match-record-lambda (forgejo config) - (let ((config-file - (computed-file "forgejo.ini" - (with-extensions (list guile-ini guile-lib guile-smc) - #~(begin - (use-modules (srfi srfi-26) (ini)) - (call-with-output-file #$output - (cut scm->ini '#$config #:port <>))))))) + (let ((config-file (ini-file "forgejo.ini" config))) (list (shepherd-service (documentation "Run Forgejo.") (provision '(forgejo)) diff --git a/modules/rosenthal/utils/file.scm b/modules/rosenthal/utils/file.scm index 6173525..4f66056 100644 --- a/modules/rosenthal/utils/file.scm +++ b/modules/rosenthal/utils/file.scm @@ -6,9 +6,13 @@ #:use-module (ice-9 textual-ports) ;; Utilities #:use-module (guix gexp) + ;; Guix packages + #:use-module (gnu packages guile-xyz) #:export (computed-substitution-with-inputs file-content - hidden-desktop-entry)) + hidden-desktop-entry + + ini-file)) ;; XXX: ‘substitute*’ doesn't fully support Unicode: ;; https://codeberg.org/guix/guix/src/commit/a88d6a45e422cede96d57d7a953439dc27c6a50c/guix/build/utils.scm#L964 @@ -45,3 +49,19 @@ (substitute* #$output (("^\\[Desktop Entry\\].*" all) (string-append all "NoDisplay=true\n"))))))) + + +;;; +;;; Serializers. +;;; + +;; https://github.com/artyom-poptsov/guile-ini +(define (ini-file name exp) + "Return file-like object NAME, serialized from G-expression EXP in INI +format." + (computed-file name + (with-extensions (list guile-ini guile-lib guile-smc) + #~(begin + (use-modules (srfi srfi-26) (ini)) + (call-with-output-file #$output + (cut scm->ini #$exp #:port <>)))))) diff --git a/modules/rosenthal/utils/serializers/ini.scm b/modules/rosenthal/utils/serializers/ini.scm deleted file mode 100644 index 0b843ca..0000000 --- a/modules/rosenthal/utils/serializers/ini.scm +++ /dev/null @@ -1,154 +0,0 @@ -;;; SPDX-License-Identifier: GPL-3.0-or-later -;;; Copyright © Copyright © 2022 Andrew Tropin - -(define-module (rosenthal utils serializers ini) - ;; Guile builtins - #:use-module (ice-9 format) - #:use-module (ice-9 match) - #:use-module (srfi srfi-1) - ;; Utilities - #:use-module (guix diagnostics) - #:use-module (guix gexp) - #:use-module (guix packages) - #:use-module (guix ui) - #:use-module (rosenthal utils serializers) - ;; Guix System - services - #:use-module (gnu services configuration) - #:export (ini-serialize - ini-print - ini-merge - ini-append - - serialize-ini-config - ini-config?)) - -(define ini-config? list?) - -(define sample-ini - `((global ((daemon) - (log . file))) - (http ((host . 127.0.0.1) - (port . 1234))))) - -(define (format-ini-section section) - (match section - ('global "") - (name (format #f "[~a]\n" (symbol->string name))))) - -(define* (ini-serialize - config - #:key - (equal-string " = ") - (format-ini-section format-ini-section)) - "For global properties use global section, the properties will be added to the -beginning of the list before any section, this behavior can be adjusted with -FORMAT-INI-SECTION argument. - -@lisp -`((global ((daemon) - (log . file))) - (http ((host . 127.0.0.1) - (port . 1234)))) -@end lisp - -would yeld - -@example -@end example -" - (define (serialize-ini-term term) - (match term - (#t "true") - (#f "false") - ((? symbol? e) (symbol->string e)) - ((? number? e) (number->string e)) - ((? string? e) (object->string e)) - ((lst ...) - (raise (formatted-message - (G_ "INI term should be a non-list value (string, \ -boolean, number, symbol, or gexp). Provided term is:\n ~a") lst))) - (e e))) - - (define (serialize-ini-properties properties) - (unless (alist? properties) - (raise (formatted-message - (G_ "INI properties should be an alist, \ -but provided value is:\n ~a") properties))) - (append-map - (match-lambda - ((? gexp? e) - (list e "\n")) - ((k) - (list (serialize-ini-term k) equal-string "\n")) - ((k . v) - (list (serialize-ini-term k) equal-string - (serialize-ini-term v) "\n"))) - properties)) - - (define (serialize-ini-section section) - (match section - ((name properties) - (append - (list (format-ini-section name)) - (serialize-ini-properties properties))) - (e - (raise (formatted-message - (G_ "INI section should be a list containing a section name as \ -the first element and alist of properties as the second, but provided value \ -is:\n~a") e))))) - - ;; TODO: serialize global section before all other sections. - (append-map - (lambda (expr) - (append - (match expr - ((? gexp? e) (list e)) - (e (serialize-ini-section e))) - (list "\n"))) - config)) - -(define (ini-merge ini1 ini2) - "Combine to INIs. Naive quadratic implementation, which can be rediculously -slow." - (define keys-to-merge - (fold - (match-lambda* - (((k v) acc) (if (assoc-ref ini2 k) (cons k acc) acc)) - (((? gexp? e) acc) acc)) - '() ini1)) - - (define enriched-ini1 - (fold-right - (match-lambda* - (((k v) acc) - (cons - (cons k (list (append v (car (or (assoc-ref ini2 k) '(())))))) - acc)) - (((? gexp? e) acc) (cons e acc))) - '() - ini1)) - - (define stripped-ini2 - (remove (match-lambda - ((k . v) (memq k keys-to-merge)) - (e #f)) - ini2)) - (append enriched-ini1 stripped-ini2)) - -(define (ini-append x acc) - (ini-merge acc x)) - -(define serialize-ini-config ini-serialize) -;; (display -;; (merge-ini -;; '((section1 ((k1 . v1))) -;; (section2 ((k4 . v4)))) -;; '((section1 ((k2 . v2) -;; (k3 . v3))) -;; (section3 ((k5 . v5)))))) - -;; (cdr '(a ((k . v) (k2 . v2)))) - -(define (ini-print ini) - "Prints generated INI, useful for debugging." - (display (apply string-append (ini-serialize ini))))