From 22e9b01bdaa8184aa08f03542798750bc587b457 Mon Sep 17 00:00:00 2001 From: Bruno Victal Date: Tue, 3 Jan 2023 14:07:49 +0000 Subject: services: git-daemon: Deprecate 'git-daemon-service' procedure. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * gnu/services/version-control.scm (git-daemon-service): Define with 'define-deprecated' * doc/guix.texi (Version Control Services): Replace with 'git-daemon-service-type' Signed-off-by: Ludovic Courtès --- gnu/services/version-control.scm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'gnu/services') diff --git a/gnu/services/version-control.scm b/gnu/services/version-control.scm index 86d40bdbe3..14ff0a59a6 100644 --- a/gnu/services/version-control.scm +++ b/gnu/services/version-control.scm @@ -29,6 +29,7 @@ #:use-module (gnu system shadow) #:use-module (gnu packages version-control) #:use-module (gnu packages admin) + #:use-module (guix deprecation) #:use-module (guix records) #:use-module (guix gexp) #:use-module (guix store) @@ -178,7 +179,8 @@ protocol.") (default-value (git-daemon-configuration)))) -(define* (git-daemon-service #:key (config (git-daemon-configuration))) +(define-deprecated (git-daemon-service #:key (config (git-daemon-configuration))) + git-daemon-service-type "Return a service that runs @command{git daemon}, a simple TCP server to expose repositories over the Git protocol for anonymous access. -- cgit v1.2.3 From 5f63811032dab5c04c397e043cc7290cb3d51ee0 Mon Sep 17 00:00:00 2001 From: Giacomo Leidi Date: Mon, 2 Jan 2023 18:05:24 +0100 Subject: services: unattended-upgrade: Add 'operating-system-expression' field. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * gnu/services/admin.scm () [operating-system-expression]: New field. (unattended-upgrade-mcron-jobs): Honor it. * doc/guix.texi (Unattended Upgrades): Document it. Co-authored-by: Ludovic Courtès --- doc/guix.texi | 14 +++++++++++++- gnu/services/admin.scm | 20 ++++++++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) (limited to 'gnu/services') diff --git a/doc/guix.texi b/doc/guix.texi index 11a4ca18fb..cd0f561f71 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -22,7 +22,7 @@ @set SUBSTITUTE-URLS https://@value{SUBSTITUTE-SERVER-1} https://@value{SUBSTITUTE-SERVER-2} @copying -Copyright @copyright{} 2012-2022 Ludovic Courtès@* +Copyright @copyright{} 2012-2023 Ludovic Courtès@* Copyright @copyright{} 2013, 2014, 2016 Andreas Enge@* Copyright @copyright{} 2013 Nikita Karetnikov@* Copyright @copyright{} 2014, 2015, 2016 Alex Kost@* @@ -110,6 +110,7 @@ Copyright @copyright{} 2022 Simon Streit@* Copyright @copyright{} 2022 (@* Copyright @copyright{} 2022 John Kehayias@* Copyright @copyright{} 2022 Ivan Vilata-i-Balaguer@* +Copyright @copyright{} 2023 Giacomo Leidi@* Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or @@ -21362,6 +21363,17 @@ Therefore, uses of @code{local-file} within @file{config.scm} will work as expected. @xref{G-Expressions}, for information about @code{local-file} and @code{file-append}. +@item @code{operating-system-expression} (default: @code{#f}) +This field specifies an expression that evaluates to the operating +system to use for the upgrade. If no value is provided the +@code{operating-system-file} field value is used. + +@lisp +(unattended-upgrade-configuration + (operating-system-expression + #~(@@ (guix system install) installation-os))) +@end lisp + @item @code{services-to-restart} (default: @code{'(mcron)}) This field specifies the Shepherd services to restart when the upgrade completes. diff --git a/gnu/services/admin.scm b/gnu/services/admin.scm index 252bedb0bd..1c10cfb1f6 100644 --- a/gnu/services/admin.scm +++ b/gnu/services/admin.scm @@ -1,7 +1,8 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2016 Jan Nieuwenhuizen -;;; Copyright © 2016-2022 Ludovic Courtès +;;; Copyright © 2016-2023 Ludovic Courtès ;;; Copyright © 2020 Brice Waegeneire +;;; Copyright © 2023 Giacomo Leidi ;;; ;;; This file is part of GNU Guix. ;;; @@ -58,6 +59,7 @@ unattended-upgrade-configuration unattended-upgrade-configuration? unattended-upgrade-configuration-operating-system-file + unattended-upgrade-configuration-operating-system-expression unattended-upgrade-configuration-channels unattended-upgrade-configuration-schedule unattended-upgrade-configuration-services-to-restart @@ -263,6 +265,8 @@ Old log files are removed or compressed according to the configuration.") unattended-upgrade-configuration? (operating-system-file unattended-upgrade-operating-system-file (default "/run/current-system/configuration.scm")) + (operating-system-expression unattended-upgrade-operating-system-expression + (default #f)) (schedule unattended-upgrade-configuration-schedule (default "30 01 * * 0")) (channels unattended-upgrade-configuration-channels @@ -296,6 +300,14 @@ Old log files are removed or compressed according to the configuration.") (define config-file (unattended-upgrade-operating-system-file config)) + (define expression + (unattended-upgrade-operating-system-expression config)) + + (define arguments + (if expression + #~(list "-e" (object->string '#$expression)) + #~(list #$config-file))) + (define code (with-imported-modules (source-module-closure '((guix build utils) (gnu services herd))) @@ -333,9 +345,9 @@ Old log files are removed or compressed according to the configuration.") (format #t "~a starting upgrade...~%" (timestamp)) (guard (c ((invoke-error? c) (report-invoke-error c))) - (invoke #$(file-append guix "/bin/guix") - "time-machine" "-C" #$channels - "--" "system" "reconfigure" #$config-file) + (apply invoke #$(file-append guix "/bin/guix") + "time-machine" "-C" #$channels + "--" "system" "reconfigure" #$arguments) ;; 'guix system delete-generations' fails when there's no ;; matching generation. Thus, catch 'invoke-error?'. -- cgit v1.2.3 From dc403ec7f15cdb94a43654a941b25894cff707c7 Mon Sep 17 00:00:00 2001 From: muradm Date: Tue, 10 Jan 2023 17:47:56 +0300 Subject: gnu: services: Fix fail2ban configuration serialization. This fixes a regression from 543d971ed2a1d9eb934af1f51930741d7cc4e7ef whereby match-lambda due to configuration field reordering. * gnu/services/security.scm: [serialize-fail2ban-ignore-cache-configuration]: Switch to match-record. [serialize-fail2ban-jail-filter-configuration]: Switch to match-record. [serialize-fail2ban-jail-action-configuration]: Switch to match-record. Signed-off-by: Maxim Cournoyer --- gnu/services/security.scm | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'gnu/services') diff --git a/gnu/services/security.scm b/gnu/services/security.scm index 50111455fb..8116072920 100644 --- a/gnu/services/security.scm +++ b/gnu/services/security.scm @@ -42,11 +42,11 @@ (max-count integer "Cache size.") (max-time integer "Cache time.")) -(define serialize-fail2ban-ignore-cache-configuration - (match-lambda - (($ _ key max-count max-time) - (format #f "key=\"~a\", max-count=~d, max-time=~d" - key max-count max-time)))) +(define (serialize-fail2ban-ignore-cache-configuration config) + (match-record config + (key max-count max-time) + (format #f "key=\"~a\", max-count=~d, max-time=~d" + key max-count max-time))) (define-maybe/no-serialization string) @@ -54,10 +54,10 @@ (name string "Filter to use.") (mode maybe-string "Mode for filter.")) -(define serialize-fail2ban-jail-filter-configuration - (match-lambda - (($ _ name mode) - (format #f "~a~@[[mode=~a]~]" name (maybe-value mode))))) +(define (serialize-fail2ban-jail-filter-configuration config) + (match-record config + (name mode) + (format #f "~a~@[[mode=~a]~]" name (maybe-value mode)))) (define (argument? a) (and (pair? a) @@ -86,17 +86,17 @@ (format #f "~a=~a" (car e) (any-value (cdr e)))))) (format #f "~a" (string-join (map key-value args) ",")))) -(define serialize-fail2ban-jail-action-configuration - (match-lambda - (($ _ name arguments) - (format - #f "~a~a" - name - (if (null? arguments) "" - (format - #f "[~a]" - (serialize-fail2ban-jail-action-configuration-arguments - arguments))))))) +(define (serialize-fail2ban-jail-action-configuration config) + (match-record config + (name arguments) + (format + #f "~a~a" + name + (if (null? arguments) "" + (format + #f "[~a]" + (serialize-fail2ban-jail-action-configuration-arguments + arguments)))))) (define fail2ban-backend->string (match-lambda -- cgit v1.2.3 From 202ac747e697a2373f0201be490e668695283eb4 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Fri, 13 Jan 2023 17:04:21 -0500 Subject: gnu: services: Add joycond-service. * gnu/services/games.scm (joycond-configuration): New configuration type. (joycond-shepherd-service): New procedure. (joycond-service-type): New variable. * doc/guix.texi (Game Services): Document it. --- doc/guix.texi | 19 +++++++++++++++++++ gnu/services/games.scm | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) (limited to 'gnu/services') diff --git a/doc/guix.texi b/doc/guix.texi index 751d0957d8..c07ec89b2f 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -36277,6 +36277,25 @@ like to serve. @node Game Services @subsection Game Services +@subsubheading Joycond service +@cindex joycond +The joycond service allows the pairing of Nintendo joycon game +controllers over Bluetooth. (@pxref{Desktop Services} for setting up +Bluetooth.) + +@deftp {Data Type} joycond-configuration +Data type representing the configuration of @command{joycond}. + +@table @asis +@item @code{package} (default: @code{joycond}) +The joycond package to use. +@end table +@end deftp + +@defvar joycond-service-type +Service type for the joycond service. +@end defvar + @subsubheading The Battle for Wesnoth Service @cindex wesnothd @uref{https://wesnoth.org, The Battle for Wesnoth} is a fantasy, turn diff --git a/gnu/services/games.scm b/gnu/services/games.scm index 6c2af44b49..e63c1c1299 100644 --- a/gnu/services/games.scm +++ b/gnu/services/games.scm @@ -19,6 +19,7 @@ (define-module (gnu services games) #:use-module (gnu services) + #:use-module (gnu services configuration) #:use-module (gnu services shepherd) #:use-module (gnu packages admin) #:use-module (gnu packages games) @@ -28,12 +29,45 @@ #:autoload (guix least-authority) (least-authority-wrapper) #:use-module (guix gexp) #:use-module (guix modules) + #:use-module (guix packages) #:use-module (guix records) #:use-module (ice-9 match) - #:export (wesnothd-configuration + #:export (joycond-configuration + joycond-configuration? + joycond-service-type + + wesnothd-configuration wesnothd-configuration? wesnothd-service-type)) +;;; +;;; Joycond +;;; + +(define-configuration/no-serialization joycond-configuration + (package (package joycond) "The joycond package to use")) + +(define (joycond-shepherd-service config) + (let ((joycond (joycond-configuration-package config))) + (list (shepherd-service + (documentation "Run joycond.") + (provision '(joycond)) + (requirement '(bluetooth)) + (start #~(make-forkexec-constructor + (list #$(file-append joycond "/bin/joycond")))) + (stop #~(make-kill-destructor)))))) + +(define joycond-service-type + (service-type + (name 'joycond) + (description + "Run @command{joycond} for pairing Nintendo joycons via Bluetooth.") + (extensions + (list (service-extension shepherd-root-service-type + joycond-shepherd-service))) + (default-value (joycond-configuration)))) + + ;;; ;;; The Battle for Wesnoth server ;;; -- cgit v1.2.3 From a5b914156eda876000ecab29ebe855080f8d8ff6 Mon Sep 17 00:00:00 2001 From: Jelle Licht Date: Tue, 13 Dec 2022 19:35:59 +0100 Subject: services: greetd: Add 'source-profile?' configuration field. * gnu/services/base.scm ()[source-profile?]: New field. (make-greetd-terminal-configuration-file): Serialize new field to configuration file. * doc/guix.texi (Base Services): Document it. --- doc/guix.texi | 4 ++++ gnu/services/base.scm | 3 +++ 2 files changed, 7 insertions(+) (limited to 'gnu/services') diff --git a/doc/guix.texi b/doc/guix.texi index c07ec89b2f..9bcaf8ff78 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -18908,6 +18908,10 @@ is recommended. @item @code{terminal-switch} (default: @code{#f}) Make this terminal active on start of @code{greetd}. +@item @code{source-profile?} (default: @code{#t}) +Whether to source @file{/etc/profile} and @file{~/.profile}, when they +exist. + @item @code{default-session-user} (default: @samp{"greeter"}) The user to use for running the greeter. diff --git a/gnu/services/base.scm b/gnu/services/base.scm index 08eea46dc6..9e799445d2 100644 --- a/gnu/services/base.scm +++ b/gnu/services/base.scm @@ -3050,6 +3050,7 @@ to handle." (default (default-log-file-name this-record))) (terminal-vt greetd-terminal-vt (default "7")) (terminal-switch greetd-terminal-switch (default #f)) + (source-profile? greetd-source-profile? (default #t)) (default-session-user greetd-default-session-user (default "greeter")) (default-session-command greetd-default-session-command (default (greetd-agreety-session)))) @@ -3063,12 +3064,14 @@ to handle." (define (make-greetd-terminal-configuration-file config) (let* ((config-file-name (greetd-config-file-name config)) + (source-profile? (greetd-source-profile? config)) (terminal-vt (greetd-terminal-vt config)) (terminal-switch (greetd-terminal-switch config)) (default-session-user (greetd-default-session-user config)) (default-session-command (greetd-default-session-command config))) (mixed-text-file config-file-name + "source_profile = " (if source-profile? "true" "false") "\n" "[terminal]\n" "vt = " terminal-vt "\n" "switch = " (if terminal-switch "true" "false") "\n" -- cgit v1.2.3 From daa471a7382cc49c1c8ecc0e57a42f1a91b28a6e Mon Sep 17 00:00:00 2001 From: Zhu Zihao Date: Mon, 16 Jan 2023 14:42:22 +0800 Subject: gnu: services: Export polkit-configuration. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Export for user customization. * gnu/services/dbus.scm (polkit-configuration): Export. (polkit-configuration?): Export. Signed-off-by: 宋文武 --- gnu/services/dbus.scm | 2 ++ 1 file changed, 2 insertions(+) (limited to 'gnu/services') diff --git a/gnu/services/dbus.scm b/gnu/services/dbus.scm index 52cb1e3a51..5efd6bdadf 100644 --- a/gnu/services/dbus.scm +++ b/gnu/services/dbus.scm @@ -40,6 +40,8 @@ dbus-service wrapped-dbus-service + polkit-configuration + polkit-configuration? polkit-service-type polkit-service)) -- cgit v1.2.3 From 0f20fc4dd99146c988907ca1cd2c58421b287596 Mon Sep 17 00:00:00 2001 From: Declan Tsien Date: Thu, 12 Jan 2023 18:37:51 +0800 Subject: services: connman: Add iwd backend support. * gnu/services/networking.scm (connman-configuration)[iwd?]: New field. (connman-shepherd-service): Add iwd? logic, remove wpa-supplicant requirement. * doc/guix.texi: Add information about connman-configuration iwd? option. Co-authored-by: Andrew Tropin Signed-off-by: Andrew Tropin --- doc/guix.texi | 3 +++ gnu/services/networking.scm | 14 ++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'gnu/services') diff --git a/doc/guix.texi b/doc/guix.texi index ac0f479e0f..27a0c62532 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -19770,6 +19770,9 @@ The connman package to use. @item @code{disable-vpn?} (default: @code{#f}) When true, disable connman's vpn plugin. + +@item @code{iwd?} (default: @code{#f}) +When true, ConnMan uses iwd to connect to wireless networks. @end table @end deftp diff --git a/gnu/services/networking.scm b/gnu/services/networking.scm index 702404bc6c..89ce16f6af 100644 --- a/gnu/services/networking.scm +++ b/gnu/services/networking.scm @@ -18,7 +18,8 @@ ;;; Copyright © 2021 Christine Lemmer-Webber ;;; Copyright © 2021 Maxime Devos ;;; Copyright © 2021 Guillaume Le Vaillant -;;; Copyright © 2022 Andrew Tropin +;;; Copyright © 2022, 2023 Andrew Tropin +;;; Copyright © 2023 Declan Tsien ;;; ;;; This file is part of GNU Guix. ;;; @@ -1265,6 +1266,8 @@ wireless networking.")))) (connman connman-configuration-connman (default connman)) (disable-vpn? connman-configuration-disable-vpn? + (default #f)) + (iwd? connman-configuration-iwd? (default #f))) (define (connman-activation config) @@ -1281,18 +1284,21 @@ wireless networking.")))) (and (connman-configuration? config) (let ((connman (connman-configuration-connman config)) - (disable-vpn? (connman-configuration-disable-vpn? config))) + (disable-vpn? (connman-configuration-disable-vpn? config)) + (iwd? (connman-configuration-iwd? config))) (list (shepherd-service (documentation "Run Connman") (provision '(networking)) (requirement - '(user-processes dbus-system loopback wpa-supplicant)) + (append '(user-processes dbus-system loopback) + (if iwd? '(iwd) '()))) (start #~(make-forkexec-constructor (list (string-append #$connman "/sbin/connmand") "--nodaemon" "--nodnsproxy" - #$@(if disable-vpn? '("--noplugin=vpn") '())) + #$@(if disable-vpn? '("--noplugin=vpn") '()) + #$@(if iwd? '("--wifi=iwd_agent") '())) ;; As connman(8) notes, when passing '-n', connman ;; "directs log output to the controlling terminal in -- cgit v1.2.3 From 6ffeef92e64f0f296dd795db906a480dbd3e97a4 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Sun, 22 Jan 2023 18:06:13 +0100 Subject: services: hpcguix-web: Provide default values. * gnu/services/web.scm ()[specs]: Default to #f. (hpcguix-web-shepherd-service): Do not pass '--config' when SPECS is #f. (hpcguix-web-service-type)[default-value]: New field. * doc/guix.texi (Web Services): Adjust accordingly. --- doc/guix.texi | 8 ++++---- gnu/services/web.scm | 15 +++++++++------ 2 files changed, 13 insertions(+), 10 deletions(-) (limited to 'gnu/services') diff --git a/doc/guix.texi b/doc/guix.texi index 507a0d3ee4..e4474943b9 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -30320,10 +30320,10 @@ The service type for @code{hpcguix-web}. Data type for the hpcguix-web service configuration. @table @asis -@item @code{specs} -A gexp (@pxref{G-Expressions}) specifying the hpcguix-web service -configuration as an @code{hpcguix-web-configuration} record. The main -fields of that record type are: +@item @code{specs} (default: @code{#f}) +Either @code{#f} or a gexp (@pxref{G-Expressions}) specifying the +hpcguix-web service configuration as an @code{hpcguix-web-configuration} +record. The main fields of that record type are: @table @asis @item @code{title-prefix} (default: @code{"hpcguix | "}) diff --git a/gnu/services/web.scm b/gnu/services/web.scm index 83aa97055f..d56e893527 100644 --- a/gnu/services/web.scm +++ b/gnu/services/web.scm @@ -1,6 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2015 David Thompson -;;; Copyright © 2015-2022 Ludovic Courtès +;;; Copyright © 2015-2023 Ludovic Courtès ;;; Copyright © 2016 Nikita ;;; Copyright © 2016, 2017, 2018 Julien Lepiller ;;; Copyright © 2017, 2018, 2019 Christopher Baines @@ -1155,8 +1155,7 @@ a webserver.") (package hpcguix-web-package (default hpcguix-web)) ;file-like - ;; Specs is gexp of hpcguix-web configuration file - (specs hpcguix-web-configuration-specs) + (specs hpcguix-web-configuration-specs (default #f)) ;#f | gexp (address hpcguix-web-configuration-address (default "127.0.0.1")) (port hpcguix-web-configuration-port (default 5000))) @@ -1217,8 +1216,11 @@ a webserver.") "-p" #$(number->string (hpcguix-web-configuration-port config)) - (string-append "--config=" - #$(scheme-file "hpcguix-web.scm" specs))) + #$@(if specs + #~((string-append "--config=" + #$(scheme-file + "hpcguix-web.scm" specs))) + #~())) #:user "hpcguix-web" #:group "hpcguix-web" #:environment-variables @@ -1239,7 +1241,8 @@ a webserver.") (service-extension rottlog-service-type (const %hpcguix-web-log-rotations)) (service-extension shepherd-root-service-type - (compose list hpcguix-web-shepherd-service)))))) + (compose list hpcguix-web-shepherd-service)))) + (default-value (hpcguix-web-configuration)))) ;;; -- cgit v1.2.3 From 9a5533c653522a4fbba61c3ea17ff6fa0f96af9f Mon Sep 17 00:00:00 2001 From: Christopher Baines Date: Fri, 3 Feb 2023 15:18:44 +0100 Subject: services: nar-herder: Add cached compression support. * gnu/services/guix.scm (): New record type. (nar-herder-configuration-cached-compressions, nar-herder-configuration-cached-compression-min-uses, nar-herder-configuration-cached-compression-workers, nar-herder-configuration-cached-compression-nar-source, nar-herder-cached-compression-configuration, nar-herder-cached-compression-configuration?, nar-herder-cached-compression-configuration-type, nar-herder-cached-compression-configuration-level, nar-herder-cached-compression-configuration-directory, nar-herder-cached-compression-configuration-directory-max-size): New procedures. * doc/guix.texi (Guix Services): Document this. --- doc/guix.texi | 36 ++++++++++++++++++++++ gnu/services/guix.scm | 85 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 118 insertions(+), 3 deletions(-) (limited to 'gnu/services') diff --git a/doc/guix.texi b/doc/guix.texi index 64873db00b..d69be8586e 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -36836,6 +36836,42 @@ advertised. Log level to use, specify a log level like @code{'INFO} to stop logging individual requests. +@item @code{cached-compressions} (default: @code{'()}) +Activate generating cached nars with different compression details from +the stored nars. This is a list of +nar-herder-cached-compression-configuration records. + +@item @code{min-uses} (default: @code{3}) +When cached-compressions are enabled, generate cached nars when at least +this number of requests are made for a nar. + +@item @code{workers} (default: @code{2}) +Number of cached nars to generate at a time. + +@item @code{nar-source} (default: @code{#f}) +Location to fetch nars from when computing cached compressions. By +default, the storage location will be used. + +@end table +@end deftp + +@deftp {Data Type} nar-herder-cached-compression-configuration +Data type representing the cached compression configuration. + +@table @asis +@item @code{type} +Type of compression to use, e.g. @code{'zstd}. + +@item @code{workers} (default: @code{#f}) +Level of the compression to use. + +@item @code{directory} (default: @code{#f}) +Location to store the cached nars. If unspecified, they will be stored +in /var/cache/nar-herder/nar/TYPE. + +@item @code{directory-max-size} (default: @code{#f}) +Maximum size in bytes of the directory. + @end table @end deftp diff --git a/gnu/services/guix.scm b/gnu/services/guix.scm index 65bf0b5a7f..2dfedc553e 100644 --- a/gnu/services/guix.scm +++ b/gnu/services/guix.scm @@ -126,7 +126,18 @@ nar-herder-configuration-storage nar-herder-configuration-storage-limit nar-herder-configuration-storage-nar-removal-criteria - nar-herder-configuration-log-level)) + nar-herder-configuration-log-level + nar-herder-configuration-cached-compressions + nar-herder-configuration-cached-compression-min-uses + nar-herder-configuration-cached-compression-workers + nar-herder-configuration-cached-compression-nar-source + + nar-herder-cached-compression-configuration + nar-herder-cached-compression-configuration? + nar-herder-cached-compression-configuration-type + nar-herder-cached-compression-configuration-level + nar-herder-cached-compression-configuration-directory + nar-herder-cached-compression-configuration-directory-max-size)) ;;;; Commentary: ;;; @@ -828,17 +839,67 @@ ca-certificates.crt file in the system profile." (negative-ttl nar-herder-configuration-negative-ttl (default #f)) (log-level nar-herder-configuration-log-level - (default 'DEBUG))) + (default 'DEBUG)) + (cached-compressions + nar-herder-configuration-cached-compressions + (default '())) + (cached-compression-min-uses + nar-herder-configuration-cached-compression-min-uses + (default 3)) + (cached-compression-workers + nar-herder-configuration-cached-compression-workers + (default 2)) + (cached-compression-nar-source + nar-herder-configuration-cached-compression-nar-source + (default #f))) +(define-record-type* + nar-herder-cached-compression-configuration + make-nar-herder-cached-compression-configuration + nar-herder-cached-compression-configuration? + (type nar-herder-cached-compression-configuration-type) + (level nar-herder-cached-compression-configuration-level + (default #f)) + (directory nar-herder-cached-compression-configuration-directory + (default #f)) + (directory-max-size + nar-herder-cached-compression-configuration-directory-max-size + (default #f))) (define (nar-herder-shepherd-services config) + (define (cached-compression-configuration->options cached-compression) + (match-record + cached-compression + + (type level directory directory-max-size) + + `(,(simple-format #f "--enable-cached-compression=~A~A" + type + (if level + (simple-format #f ":~A" level) + "")) + ,@(if directory + (list + (simple-format #f "--cached-compression-directory=~A=~A" + type + directory)) + '()) + ,@(if directory-max-size + (list + (simple-format #f "--cached-compression-directory-max-size=~A=~A" + type + directory-max-size)) + '())))) + (match-record config (package user group mirror database database-dump host port storage storage-limit storage-nar-removal-criteria - ttl negative-ttl log-level) + ttl negative-ttl log-level + cached-compressions cached-compression-min-uses + cached-compression-workers cached-compression-nar-source) (unless (or mirror storage) (error "nar-herder: mirror or storage must be set")) @@ -882,6 +943,24 @@ ca-certificates.crt file in the system profile." '()) #$@(if log-level (list (simple-format #f "--log-level=~A" log-level)) + '()) + #$@(append-map + cached-compression-configuration->options + cached-compressions) + #$@(if cached-compression-min-uses + (list (simple-format + #f "--cached-compression-min-uses=~A" + cached-compression-min-uses)) + '()) + #$@(if cached-compression-workers + (list (simple-format + #f "--cached-compression-workers=~A" + cached-compression-workers)) + '()) + #$@(if cached-compression-nar-source + (list (simple-format + #f "--cached-compression-nar-source=~A" + cached-compression-nar-source)) '())) #:user #$user #:group #$group -- cgit v1.2.3 From d7fd9ec209f72e9cfff04a48bf16e092f258d8ff Mon Sep 17 00:00:00 2001 From: Bruno Victal Date: Thu, 2 Feb 2023 20:07:36 +0000 Subject: services: mpd: Rewrite using 'define-configuration'. * gnu/services/audio.scm (mpd-configuration, mpd-output): Rewrite using define-configuration. (uglify-field-name, mpd-serialize-field, mpd-serialize-alist) (mpd-serialize-number, mpd-serialize-boolean, mpd-serialize-list-of-mpd-output) (mpd-serialize-configuration): New procedure. (list-of-mpd-output?): New predicate. (mpd-config->file, mpd-output->string): Remove procedure. Signed-off-by: Liliana Marie Prikler --- gnu/services/audio.scm | 222 +++++++++++++++++++++++++++++-------------------- 1 file changed, 133 insertions(+), 89 deletions(-) (limited to 'gnu/services') diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm index c60053f33c..b7cb0ebe38 100644 --- a/gnu/services/audio.scm +++ b/gnu/services/audio.scm @@ -2,6 +2,7 @@ ;;; Copyright © 2017 Peter Mikkelsen ;;; Copyright © 2019 Ricardo Wurmus ;;; Copyright © 2020 Ludovic Courtès +;;; Copyright © 2022 Bruno Victal ;;; ;;; This file is part of GNU Guix. ;;; @@ -21,13 +22,15 @@ (define-module (gnu services audio) #:use-module (guix gexp) #:use-module (gnu services) + #:use-module (gnu services configuration) #:use-module (gnu services shepherd) #:use-module (gnu system shadow) #:use-module (gnu packages admin) #:use-module (gnu packages mpd) #:use-module (guix records) #:use-module (ice-9 match) - #:use-module (ice-9 format) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) #:export (mpd-output mpd-output? mpd-configuration @@ -40,93 +43,134 @@ ;;; ;;; Code: -(define-record-type* - mpd-output make-mpd-output - mpd-output? - (type mpd-output-type - (default "pulse")) - (name mpd-output-name - (default "MPD")) - (enabled? mpd-output-enabled? - (default #t)) - (tags? mpd-output-tags? - (default #t)) - (always-on? mpd-output-always-on? - (default #f)) - (mixer-type mpd-output-mixer-type - ;; valid: hardware, software, null, none - (default #f)) - (extra-options mpd-output-extra-options - (default '()))) - -(define-record-type* - mpd-configuration make-mpd-configuration - mpd-configuration? - (user mpd-configuration-user - (default "mpd")) - (music-dir mpd-configuration-music-dir - (default "~/Music")) - (playlist-dir mpd-configuration-playlist-dir - (default "~/.mpd/playlists")) - (db-file mpd-configuration-db-file - (default "~/.mpd/tag_cache")) - (state-file mpd-configuration-state-file - (default "~/.mpd/state")) - (sticker-file mpd-configuration-sticker-file - (default "~/.mpd/sticker.sql")) - (port mpd-configuration-port - (default "6600")) - (address mpd-configuration-address - (default "any")) - (outputs mpd-configuration-outputs - (default (list (mpd-output))))) - -(define (mpd-output->string output) - "Convert the OUTPUT of type to a configuration file snippet." - (let ((extra (string-join - (map (match-lambda - ((key . value) - (format #f " ~a \"~a\"" - (string-map - (lambda (c) (if (char=? c #\-) #\_ c)) - (symbol->string key)) - value))) - (mpd-output-extra-options output)) - "\n"))) - (format #f "\ -audio_output { - type \"~a\" - name \"~a\" -~:[ enabled \"no\"~%~;~]\ -~:[ tags \"no\"~%~;~]\ -~:[~; always_on \"yes\"~%~]\ -~@[ mixer_type \"~a\"~%~]\ -~a~%}~%" - (mpd-output-type output) - (mpd-output-name output) - (mpd-output-enabled? output) - (mpd-output-tags? output) - (mpd-output-always-on? output) - (mpd-output-mixer-type output) - extra))) - -(define (mpd-config->file config) - (apply - mixed-text-file "mpd.conf" - "pid_file \"" (mpd-file-name config "pid") "\"\n" - (append (map mpd-output->string - (mpd-configuration-outputs config)) - (map (match-lambda - ((config-name config-val) - (string-append config-name " \"" (config-val config) "\"\n"))) - `(("user" ,mpd-configuration-user) - ("music_directory" ,mpd-configuration-music-dir) - ("playlist_directory" ,mpd-configuration-playlist-dir) - ("db_file" ,mpd-configuration-db-file) - ("state_file" ,mpd-configuration-state-file) - ("sticker_file" ,mpd-configuration-sticker-file) - ("port" ,mpd-configuration-port) - ("bind_to_address" ,mpd-configuration-address)))))) +(define (uglify-field-name field-name) + (let ((str (symbol->string field-name))) + (string-join (string-split (if (string-suffix? "?" str) + (string-drop-right str 1) + str) + #\-) "_"))) + +(define (mpd-serialize-field field-name value) + #~(format #f "~a ~s~%" #$(if (string? field-name) + field-name + (uglify-field-name field-name)) + #$(if (string? value) + value + (object->string value)))) + +(define (mpd-serialize-alist field-name value) + #~(string-append #$@(generic-serialize-alist list mpd-serialize-field + value))) + +(define mpd-serialize-string mpd-serialize-field) + +(define (mpd-serialize-boolean field-name value) + (mpd-serialize-field field-name (if value "yes" "no"))) + +(define (mpd-serialize-list-of-mpd-output field-name value) + #~(string-append "\naudio_output {\n" + #$@(map (cut serialize-configuration <> + mpd-output-fields) + value) + "}\n")) + +(define (mpd-serialize-configuration configuration) + (mixed-text-file + "mpd.conf" + (serialize-configuration configuration mpd-configuration-fields))) + +(define-configuration mpd-output + (name + (string "MPD") + "The name of the audio output.") + + (type + (string "pulse") + "The type of audio output.") + + (enabled? + (boolean #t) + "Specifies whether this audio output is enabled when MPD is started. By +default, all audio outputs are enabled. This is just the default +setting when there is no state file; with a state file, the previous +state is restored.") + + (tags? + (boolean #t) + "If set to @code{#f}, then MPD will not send tags to this output. This +is only useful for output plugins that can receive tags, for example the +@code{httpd} output plugin.") + + (always-on? + (boolean #f) + "If set to @code{#t}, then MPD attempts to keep this audio output always +open. This may be useful for streaming servers, when you don’t want to +disconnect all listeners even when playback is accidentally stopped.") + + (mixer-type + (string "none") + "This field accepts a symbol that specifies which mixer should be used +for this audio output: the @code{hardware} mixer, the @code{software} +mixer, the @code{null} mixer (allows setting the volume, but with no +effect; this can be used as a trick to implement an external mixer +External Mixer) or no mixer (@code{none}).") + + (extra-options + (alist '()) + "An association list of option symbols to string values to be appended to +the audio output configuration.") + + (prefix mpd-)) + +(define list-of-mpd-output? + (list-of mpd-output?)) + +(define-configuration mpd-configuration + (user + (string "mpd") + "The user to run mpd as.") + + (music-dir + (string "~/Music") + "The directory to scan for music files." + (lambda (_ x) + (mpd-serialize-field "music_directory" x))) + + (playlist-dir + (string "~/.mpd/playlists") + "The directory to store playlists." + (lambda (_ x) + (mpd-serialize-field "playlist_directory" x))) + + (db-file + (string "~/.mpd/tag_cache") + "The location of the music database.") + + (state-file + (string "~/.mpd/state") + "The location of the file that stores current MPD's state.") + + (sticker-file + (string "~/.mpd/sticker.sql") + "The location of the sticker database.") + + (port + (string "6600") + "The port to run mpd on.") + + (address + (string "any") + "The address that mpd will bind to. +To use a Unix domain socket, an absolute path can be specified here." + (lambda (_ x) + (mpd-serialize-field "bind_to_address" x))) + + (outputs + (list-of-mpd-output (list (mpd-output))) + "The audio outputs that MPD can use. +By default this is a single output using pulseaudio.") + + (prefix mpd-)) (define (mpd-file-name config file) "Return a path in /var/run/mpd/ that is writable @@ -143,7 +187,7 @@ audio_output { (start #~(make-forkexec-constructor (list #$(file-append mpd "/bin/mpd") "--no-daemon" - #$(mpd-config->file config)) + #$(mpd-serialize-configuration config)) #:environment-variables ;; Required to detect PulseAudio when run under a user account. (list (string-append -- cgit v1.2.3 From 5c5f0fc1135ff15f9c4adfc5f27eadd9a592b5d1 Mon Sep 17 00:00:00 2001 From: Bruno Victal Date: Thu, 2 Feb 2023 20:07:37 +0000 Subject: services: mpd: Refactor MPD service. Refactor mpd-service-type to support additional mpd.conf directives and move activation-service-extension into service constructor. * gnu/services/audio.scm (mpd-plugin, mpd-partition): New records. (mpd-serialize-boolean): Alias to and integrate logic into... (mpd-serialize-field): ... this. (mpd-serialize-list-of-string): New variable. (mpd-plugin?, mpd-partition?, list-of-string?, list-of-symbol?) (list-of-mpd-plugin?, list-of-mpd-partition?) (list-of-mpd-plugin-or-output?, port?): New variables. (mpd-file-name, mpd-service-activation): Remove variables. (mpd-configuration) [package, group, shepherd-requirement, log-file, log-level, music-directory] [playlist-directory, endpoints, database, partitions, neighbors, inputs] [archive-plugins, input-cache-size, decoders, resampler, filters] [playlist-plugins, extra-options]: New fields. [music-dir, playlist-dir, address]: Deprecate shorthand fields. [db-file, state-file, sticker-file, port, outputs]: Change admissible type. (mpd-shepherd-service) [actions]: New shepherd actions: 'reopen' and 'configuration'. [requirement]: Splice with 'shepherd-requirement' field. [start]: Use 'package' field. Remove #:log-file parameter. Move activation-service extension into constructor. (mpd-accounts): Honor user and group names from configuration. (mpd-log-rotation): New procedure. (mpd-service-type)[extensions]: Add rottlog-service-type extension. Remove activation-service-type extension. (mpd-output-name, mpd-output-type, mpd-output-enabled?, mpd-output-format) (mpd-output-tags?, mpd-output-always-on?, mpd-output-mixer-type) (mpd-output-replay-gain-handler, mpd-output-extra-options) (mpd-plugin-plugin, mpd-plugin-name, mpd-plugin-enabled?) (mpd-plugin-extra-options) (mpd-partition-name, mpd-partition-extra-options) (mpd-configuration-package, mpd-configuration-user) (mpd-configuration-group, mpd-configuration-shepherd-requirement) (mpd-configuration-log-file, mpd-configuration-log-level) (mpd-configuration-music-directory, mpd-configuration-music-dir) (mpd-configuration-playlist-directory, mpd-configuration-playlist-dir) (mpd-configuration-db-file, mpd-configuration-state-file) (mpd-configuration-sticker-file, mpd-configuration-default-port) (mpd-configuration-endpoints, mpd-configuration-address) (mpd-configuration-database, mpd-configuration-partitions) (mpd-configuration-neighbors, mpd-configuration-inputs) (mpd-configuration-archive-plugins, mpd-configuration-input-cache-size) (mpd-configuration-decoders, mpd-configuration-resampler) (mpd-configuration-filters, mpd-configuration-outputs) (mpd-configuration-playlist-plugins, mpd-configuration-extra-options): Export accessors. * doc/guix.texi (Audio Services)[Music Player Daemon]: Update documentation. Signed-off-by: Liliana Marie Prikler --- doc/guix.texi | 177 +++++++++++++++--- gnu/services/audio.scm | 493 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 543 insertions(+), 127 deletions(-) (limited to 'gnu/services') diff --git a/doc/guix.texi b/doc/guix.texi index d69be8586e..cd18959db0 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -109,6 +109,7 @@ Copyright @copyright{} 2022 Reily Siegel@* Copyright @copyright{} 2022 Simon Streit@* Copyright @copyright{} 2022 (@* Copyright @copyright{} 2022 John Kehayias@* +Copyright @copyright{} 2022 Bruno Victal@* Copyright @copyright{} 2022 Ivan Vilata-i-Balaguer@* Copyright @copyright{} 2023 Giacomo Leidi@* Copyright @copyright{} 2022 Antero Mejr@* @@ -33185,79 +33186,187 @@ The service type for @command{mpd} Data type representing the configuration of @command{mpd}. @table @asis -@item @code{user} (default: @code{"mpd"}) +@item @code{package} (default: @code{mpd}) (type: file-like) +The MPD package. + +@item @code{user} (default: @code{"mpd"}) (type: string) The user to run mpd as. -@item @code{music-dir} (default: @code{"~/Music"}) +@item @code{group} (default: @code{"mpd"}) (type: string) +The group to run mpd as. + +@item @code{shepherd-requirement} (default: @code{()}) (type: list-of-symbol) +This is a list of symbols naming Shepherd services that this service +will depend on. + +@item @code{log-file} (default: @code{"/var/log/mpd/log"}) (type: maybe-string) +The location of the log file. Set to @code{syslog} to use the local +syslog daemon or @code{%unset-value} to omit this directive from the +configuration file. + +@item @code{log-level} (type: maybe-string) +Supress any messages below this threshold. Available values: +@code{notice}, @code{info}, @code{verbose}, @code{warning} and +@code{error}. + +@item @code{music-directory} (type: maybe-string) The directory to scan for music files. -@item @code{playlist-dir} (default: @code{"~/.mpd/playlists"}) +@item @code{playlist-directory} (type: maybe-string) The directory to store playlists. -@item @code{db-file} (default: @code{"~/.mpd/tag_cache"}) +@item @code{db-file} (type: maybe-string) The location of the music database. -@item @code{state-file} (default: @code{"~/.mpd/state"}) +@item @code{state-file} (type: maybe-string) The location of the file that stores current MPD's state. -@item @code{sticker-file} (default: @code{"~/.mpd/sticker.sql"}) +@item @code{sticker-file} (type: maybe-string) The location of the sticker database. -@item @code{port} (default: @code{"6600"}) -The port to run mpd on. +@item @code{default-port} (default: @code{6600}) (type: maybe-integer) +The default port to run mpd on. + +@item @code{endpoints} (type: maybe-list-of-string) +The addresses that mpd will bind to. A port different from @var{default-port} +may be specified, e.g. @code{localhost:6602} and IPv6 addresses must be +enclosed in square brackets when a different port is used. +To use a Unix domain socket, an absolute path or a path starting with @code{~} +can be specified here. + +@item @code{database} (type: maybe-mpd-plugin) +MPD database plugin configuration. + +@item @code{partitions} (default: @code{()}) (type: list-of-mpd-partition) +List of MPD "partitions". -@item @code{address} (default: @code{"any"}) -The address that mpd will bind to. To use a Unix domain socket, -an absolute path can be specified here. +@item @code{neighbors} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD neighbor plugin configurations. -@item @code{outputs} (default: @code{"(list (mpd-output))"}) -The audio outputs that MPD can use. By default this is a single output using pulseaudio. +@item @code{inputs} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD input plugin configurations. + +@item @code{archive-plugins} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD archive plugin configurations. + +@item @code{input-cache-size} (type: maybe-string) +MPD input cache size. + +@item @code{decoders} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD decoder plugin configurations. + +@item @code{resampler} (type: maybe-mpd-plugin) +MPD resampler plugin configuration. + +@item @code{filters} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD filter plugin configurations. + +@item @code{outputs} (type: list-of-mpd-plugin-or-output) +The audio outputs that MPD can use. By default this is a single output +using pulseaudio. + +@item @code{playlist-plugins} (default: @code{()}) (type: list-of-mpd-plugin) +List of MPD playlist plugin configurations. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the configuration. + +@end table +@end deftp + +@deftp {Data Type} mpd-plugin +Data type representing a @command{mpd} plugin. + +@table @asis +@item @code{plugin} (type: maybe-string) +Plugin name. + +@item @code{name} (type: maybe-string) +Name. + +@item @code{enabled?} (type: maybe-boolean) +Whether the plugin is enabled/disabled. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the plugin configuration. See +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD plugin +reference} for available options. + +@end table +@end deftp + +@deftp {Data Type} mpd-partition +Data type representing a @command{mpd} partition. + +@table @asis +@item @code{name} (type: string) +Partition name. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the partition configuration. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions,Configuring +Partitions} for available options. @end table @end deftp @deftp {Data Type} mpd-output -Data type representing an @command{mpd} audio output. +Data type representing a @command{mpd} audio output. @table @asis -@item @code{name} (default: @code{"MPD"}) +@item @code{name} (default: @code{"MPD"}) (type: string) The name of the audio output. -@item @code{type} (default: @code{"pulse"}) +@item @code{type} (default: @code{"pulse"}) (type: string) The type of audio output. -@item @code{enabled?} (default: @code{#t}) +@item @code{enabled?} (default: @code{#t}) (type: boolean) Specifies whether this audio output is enabled when MPD is started. By default, all audio outputs are enabled. This is just the default setting when there is no state file; with a state file, the previous state is restored. -@item @code{tags?} (default: @code{#t}) +@item @code{format} (type: maybe-string) +Force a specific audio format on output. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Global +Audio Format} for a more detailed description. + +@item @code{tags?} (default: @code{#t}) (type: boolean) If set to @code{#f}, then MPD will not send tags to this output. This is only useful for output plugins that can receive tags, for example the @code{httpd} output plugin. -@item @code{always-on?} (default: @code{#f}) +@item @code{always-on?} (default: @code{#f}) (type: boolean) If set to @code{#t}, then MPD attempts to keep this audio output always -open. This may be useful for streaming servers, when you don’t want to +open. This may be useful for streaming servers, when you don?t want to disconnect all listeners even when playback is accidentally stopped. -@item @code{mixer-type} -This field accepts a symbol that specifies which mixer should be used +@item @code{mixer-type} (default: @code{"none"}) (type: string) +This field accepts a string that specifies which mixer should be used for this audio output: the @code{hardware} mixer, the @code{software} mixer, the @code{null} mixer (allows setting the volume, but with no effect; this can be used as a trick to implement an external mixer External Mixer) or no mixer (@code{none}). -@item @code{extra-options} (default: @code{'()}) -An association list of option symbols to string values to be appended to -the audio output configuration. +@item @code{replay-gain-handler} (type: maybe-string) +This field accepts a string that specifies how +@uref{https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay +Gain} is to be applied. @code{software} uses an internal software +volume control, @code{mixer} uses the configured (hardware) mixer +control and @code{none} disables replay gain on this audio output. + +@item @code{extra-options} (default: @code{()}) (type: alist) +An association list of option symbols/strings to string values to be +appended to the audio output configuration. @end table @end deftp -The following example shows a configuration of @code{mpd} that provides -an HTTP audio streaming output. +The following example shows a configuration of @command{mpd} that +configures some of its plugins and provides a HTTP audio streaming output. @lisp (service mpd-service-type @@ -33269,7 +33378,19 @@ an HTTP audio streaming output. (mixer-type 'null) (extra-options `((encoder . "vorbis") - (port . "8080")))))))) + (port . "8080")))))) + (decoders + (list (mpd-plugin + (plugin "mikmod") + (enabled? #f)) + (mpd-plugin + (plugin "openmpt") + (enabled? #t) + (extra-options `((repeat-count . -1) + (interpolation-filter . 1)))))) + (resampler (mpd-plugin + (plugin "libsamplerate") + (extra-options `((type . 0))))))) @end lisp diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm index b7cb0ebe38..2bb8f66c96 100644 --- a/gnu/services/audio.scm +++ b/gnu/services/audio.scm @@ -21,9 +21,13 @@ (define-module (gnu services audio) #:use-module (guix gexp) + #:use-module (guix deprecation) + #:use-module (guix diagnostics) + #:use-module (guix i18n) #:use-module (gnu services) #:use-module (gnu services configuration) #:use-module (gnu services shepherd) + #:use-module (gnu services admin) #:use-module (gnu system shadow) #:use-module (gnu packages admin) #:use-module (gnu packages mpd) @@ -31,10 +35,61 @@ #:use-module (ice-9 match) #:use-module (srfi srfi-1) #:use-module (srfi srfi-26) + #:use-module (srfi srfi-71) #:export (mpd-output mpd-output? + mpd-output-name + mpd-output-type + mpd-output-enabled? + mpd-output-format + mpd-output-tags? + mpd-output-always-on? + mpd-output-mixer-type + mpd-output-replay-gain-handler + mpd-output-extra-options + + mpd-plugin + mpd-plugin? + mpd-plugin-plugin + mpd-plugin-name + mpd-plugin-enabled? + mpd-plugin-extra-options + + mpd-partition + mpd-partition? + mpd-partition-name + mpd-partition-extra-options + mpd-configuration mpd-configuration? + mpd-configuration-package + mpd-configuration-user + mpd-configuration-group + mpd-configuration-shepherd-requirement + mpd-configuration-log-file + mpd-configuration-log-level + mpd-configuration-music-directory + mpd-configuration-music-dir + mpd-configuration-playlist-directory + mpd-configuration-playlist-dir + mpd-configuration-db-file + mpd-configuration-state-file + mpd-configuration-sticker-file + mpd-configuration-default-port + mpd-configuration-endpoints + mpd-configuration-address + mpd-configuration-database + mpd-configuration-partitions + mpd-configuration-neighbors + mpd-configuration-inputs + mpd-configuration-archive-plugins + mpd-configuration-input-cache-size + mpd-configuration-decoders + mpd-configuration-resampler + mpd-configuration-filters + mpd-configuration-outputs + mpd-configuration-playlist-plugins + mpd-configuration-extra-options mpd-service-type)) ;;; Commentary: @@ -50,34 +105,125 @@ str) #\-) "_"))) +(define list-of-string? + (list-of string?)) + +(define list-of-symbol? + (list-of symbol?)) + (define (mpd-serialize-field field-name value) - #~(format #f "~a ~s~%" #$(if (string? field-name) - field-name - (uglify-field-name field-name)) - #$(if (string? value) - value - (object->string value)))) + (let ((field (if (string? field-name) field-name + (uglify-field-name field-name))) + (value (cond + ((boolean? value) (if value "yes" "no")) + ((string? value) value) + (else (object->string value))))) + #~(format #f "~a ~s~%" #$field #$value))) (define (mpd-serialize-alist field-name value) #~(string-append #$@(generic-serialize-alist list mpd-serialize-field value))) (define mpd-serialize-string mpd-serialize-field) +(define mpd-serialize-boolean mpd-serialize-field) -(define (mpd-serialize-boolean field-name value) - (mpd-serialize-field field-name (if value "yes" "no"))) +(define (mpd-serialize-list-of-string field-name value) + #~(string-concatenate #$(map (cut mpd-serialize-string field-name <>) value))) -(define (mpd-serialize-list-of-mpd-output field-name value) - #~(string-append "\naudio_output {\n" - #$@(map (cut serialize-configuration <> - mpd-output-fields) - value) - "}\n")) +(define-maybe string (prefix mpd-)) +(define-maybe list-of-string (prefix mpd-)) +(define-maybe boolean (prefix mpd-)) -(define (mpd-serialize-configuration configuration) - (mixed-text-file - "mpd.conf" - (serialize-configuration configuration mpd-configuration-fields))) +;;; TODO: Procedures for deprecated fields, to be removed. + +(define mpd-deprecated-fields '((music-dir . music-directory) + (playlist-dir . playlist-directory) + (address . endpoints))) + +(define (port? value) (or (string? value) (integer? value))) + +(define (mpd-serialize-deprecated-field field-name value) + (if (maybe-value-set? value) + (begin + (warn-about-deprecation + field-name #f + #:replacement (assoc-ref mpd-deprecated-fields field-name)) + (match field-name + ('playlist-dir (mpd-serialize-string "playlist_directory" value)) + ('music-dir (mpd-serialize-string "music_directory" value)) + ('address (mpd-serialize-string "bind_to_address" value)))) + "")) + +(define (mpd-serialize-port field-name value) + (when (string? value) + (warning + (G_ "string value for '~a' is deprecated, use integer instead~%") + field-name)) + (mpd-serialize-field "port" value)) + +(define-maybe port (prefix mpd-)) + +;;; + +;; Generic MPD plugin record, lists only the most prevalent fields. +(define-configuration mpd-plugin + (plugin + maybe-string + "Plugin name.") + + (name + maybe-string + "Name.") + + (enabled? + maybe-boolean + "Whether the plugin is enabled/disabled.") + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values +to be appended to the plugin configuration. See +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD plugin reference} +for available options.") + + (prefix mpd-)) + +(define (mpd-serialize-mpd-plugin field-name value) + #~(format #f "~a {~%~a}~%" + '#$field-name + #$(serialize-configuration value mpd-plugin-fields))) + +(define (mpd-serialize-list-of-mpd-plugin field-name value) + #~(string-append #$@(map (cut mpd-serialize-mpd-plugin field-name <>) + value))) + +(define list-of-mpd-plugin? (list-of mpd-plugin?)) + +(define-maybe mpd-plugin (prefix mpd-)) + +(define-configuration mpd-partition + (name + string + "Partition name.") + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values +to be appended to the partition configuration. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions,Configuring Partitions} +for available options.") + + (prefix mpd-)) + +(define (mpd-serialize-mpd-partition field-name value) + #~(format #f "partition {~%~a}~%" + #$(serialize-configuration value mpd-partition-fields))) + +(define (mpd-serialize-list-of-mpd-partition field-name value) + #~(string-append #$@(map (cut mpd-serialize-mpd-partition #f <>) value))) + +(define list-of-mpd-partition? + (list-of mpd-partition?)) (define-configuration mpd-output (name @@ -95,6 +241,12 @@ default, all audio outputs are enabled. This is just the default setting when there is no state file; with a state file, the previous state is restored.") + (format + maybe-string + "Force a specific audio format on output. See +@uref{https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Global Audio Format} +for a more detailed description.") + (tags? (boolean #t) "If set to @code{#f}, then MPD will not send tags to this output. This @@ -109,125 +261,268 @@ disconnect all listeners even when playback is accidentally stopped.") (mixer-type (string "none") - "This field accepts a symbol that specifies which mixer should be used + "This field accepts a string that specifies which mixer should be used for this audio output: the @code{hardware} mixer, the @code{software} mixer, the @code{null} mixer (allows setting the volume, but with no effect; this can be used as a trick to implement an external mixer External Mixer) or no mixer (@code{none}).") + (replay-gain-handler + maybe-string + "This field accepts a string that specifies how +@uref{https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay Gain} +is to be applied. @code{software} uses an internal software volume control, +@code{mixer} uses the configured (hardware) mixer control and @code{none} +disables replay gain on this audio output.") + (extra-options (alist '()) - "An association list of option symbols to string values to be appended to -the audio output configuration.") + "An association list of option symbols/strings to string values +to be appended to the audio output configuration.") (prefix mpd-)) -(define list-of-mpd-output? - (list-of mpd-output?)) +(define (mpd-serialize-mpd-output field-name value) + #~(format #f "audio_output {~%~a}~%" + #$(serialize-configuration value mpd-output-fields))) + +(define (mpd-serialize-list-of-mpd-plugin-or-output field-name value) + (let ((plugins outputs (partition mpd-plugin? value))) + #~(string-append #$@(map (cut mpd-serialize-mpd-plugin "audio_output" <>) + plugins) + #$@(map (cut mpd-serialize-mpd-output #f <>) outputs)))) + +(define list-of-mpd-plugin-or-output? + (list-of (lambda (x) + (or (mpd-output? x) (mpd-plugin? x))))) (define-configuration mpd-configuration + (package + (file-like mpd) + "The MPD package." + empty-serializer) + (user (string "mpd") "The user to run mpd as.") - (music-dir - (string "~/Music") + (group + (string "mpd") + "The group to run mpd as.") + + (shepherd-requirement + (list-of-symbol '()) + "This is a list of symbols naming Shepherd services that this service +will depend on." + empty-serializer) + + (log-file + (maybe-string "/var/log/mpd/log") + "The location of the log file. Set to @code{syslog} to use the +local syslog daemon or @code{%unset-value} to omit this directive +from the configuration file.") + + (log-level + maybe-string + "Supress any messages below this threshold. +Available values: @code{notice}, @code{info}, @code{verbose}, +@code{warning} and @code{error}.") + + (music-directory + maybe-string + "The directory to scan for music files.") + + (music-dir ; TODO: deprecated, remove later + maybe-string "The directory to scan for music files." - (lambda (_ x) - (mpd-serialize-field "music_directory" x))) + mpd-serialize-deprecated-field) + + (playlist-directory + maybe-string + "The directory to store playlists.") - (playlist-dir - (string "~/.mpd/playlists") + (playlist-dir ; TODO: deprecated, remove later + maybe-string "The directory to store playlists." - (lambda (_ x) - (mpd-serialize-field "playlist_directory" x))) + mpd-serialize-deprecated-field) (db-file - (string "~/.mpd/tag_cache") + maybe-string "The location of the music database.") (state-file - (string "~/.mpd/state") + maybe-string "The location of the file that stores current MPD's state.") (sticker-file - (string "~/.mpd/sticker.sql") + maybe-string "The location of the sticker database.") - (port - (string "6600") - "The port to run mpd on.") - - (address - (string "any") + (default-port + (maybe-port 6600) + "The default port to run mpd on.") + + (endpoints + maybe-list-of-string + "The addresses that mpd will bind to. A port different from +@var{default-port} may be specified, e.g. @code{localhost:6602} and +IPv6 addresses must be enclosed in square brackets when a different +port is used. +To use a Unix domain socket, an absolute path or a path starting with @code{~} +can be specified here." + (lambda (_ endpoints) + (if (maybe-value-set? endpoints) + (mpd-serialize-list-of-string "bind_to_address" endpoints) + ""))) + + (address ; TODO: deprecated, remove later + maybe-string "The address that mpd will bind to. To use a Unix domain socket, an absolute path can be specified here." + mpd-serialize-deprecated-field) + + (database + maybe-mpd-plugin + "MPD database plugin configuration.") + + (partitions + (list-of-mpd-partition '()) + "List of MPD \"partitions\".") + + (neighbors + (list-of-mpd-plugin '()) + "List of MPD neighbor plugin configurations.") + + (inputs + (list-of-mpd-plugin '()) + "List of MPD input plugin configurations." (lambda (_ x) - (mpd-serialize-field "bind_to_address" x))) + (mpd-serialize-list-of-mpd-plugin "input" x))) + + (archive-plugins + (list-of-mpd-plugin '()) + "List of MPD archive plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "archive_plugin" x))) + + (input-cache-size + maybe-string + "MPD input cache size." + (lambda (_ x) + (if (maybe-value-set? x) + #~(string-append "\ninput_cache {\n" + #$(mpd-serialize-string "size" x) + "}\n") ""))) + + (decoders + (list-of-mpd-plugin '()) + "List of MPD decoder plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "decoder" x))) + + (resampler + maybe-mpd-plugin + "MPD resampler plugin configuration.") + + (filters + (list-of-mpd-plugin '()) + "List of MPD filter plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "filter" x))) (outputs - (list-of-mpd-output (list (mpd-output))) + (list-of-mpd-plugin-or-output (list (mpd-output))) "The audio outputs that MPD can use. By default this is a single output using pulseaudio.") + (playlist-plugins + (list-of-mpd-plugin '()) + "List of MPD playlist plugin configurations." + (lambda (_ x) + (mpd-serialize-list-of-mpd-plugin "playlist_plugin" x))) + + (extra-options + (alist '()) + "An association list of option symbols/strings to string values to be +appended to the configuration.") + (prefix mpd-)) -(define (mpd-file-name config file) - "Return a path in /var/run/mpd/ that is writable - by @code{user} from @code{config}." - (string-append "/var/run/mpd/" - (mpd-configuration-user config) - "/" file)) +(define (mpd-serialize-configuration configuration) + (mixed-text-file + "mpd.conf" + (serialize-configuration configuration mpd-configuration-fields))) + +(define (mpd-log-rotation config) + (match-record config (log-file) + (log-rotation + (files (list log-file)) + (post-rotate #~(begin + (use-modules (gnu services herd)) + (with-shepherd-action 'mpd ('reopen) #f)))))) (define (mpd-shepherd-service config) - (shepherd-service - (documentation "Run the MPD (Music Player Daemon)") - (requirement '(user-processes)) - (provision '(mpd)) - (start #~(make-forkexec-constructor - (list #$(file-append mpd "/bin/mpd") - "--no-daemon" - #$(mpd-serialize-configuration config)) - #:environment-variables - ;; Required to detect PulseAudio when run under a user account. - (list (string-append - "XDG_RUNTIME_DIR=/run/user/" - (number->string - (passwd:uid - (getpwnam #$(mpd-configuration-user config)))))) - #:log-file #$(mpd-file-name config "log"))) - (stop #~(make-kill-destructor)))) - -(define (mpd-service-activation config) - (with-imported-modules '((guix build utils)) - #~(begin - (use-modules (guix build utils)) - (define %user - (getpw #$(mpd-configuration-user config))) - - (let ((directory #$(mpd-file-name config ".mpd"))) - (mkdir-p directory) - (chown directory (passwd:uid %user) (passwd:gid %user)) - - ;; Make /var/run/mpd/USER user-owned as well. - (chown (dirname directory) - (passwd:uid %user) (passwd:gid %user)))))) - - -(define %mpd-accounts - ;; Default account and group for MPD. - (list (user-group (name "mpd") (system? #t)) - (user-account - (name "mpd") - (group "mpd") - (system? #t) - (comment "Music Player Daemon (MPD) user") - - ;; Note: /var/run/mpd hosts one sub-directory per user, of which - ;; /var/run/mpd/mpd corresponds to the "mpd" user. - (home-directory "/var/run/mpd/mpd") - - (shell (file-append shadow "/sbin/nologin"))))) + (match-record config (user package shepherd-requirement + log-file playlist-directory + db-file state-file sticker-file) + (let* ((config-file (mpd-serialize-configuration config))) + (shepherd-service + (documentation "Run the MPD (Music Player Daemon)") + (requirement `(user-processes loopback ,@shepherd-requirement)) + (provision '(mpd)) + (start #~(begin + (and=> #$(maybe-value log-file) + (compose mkdir-p dirname)) + + (let ((user (getpw #$user))) + (for-each + (lambda (x) + (when (and x (not (file-exists? x))) + (mkdir-p x) + (chown x (passwd:uid user) (passwd:gid user)))) + (list #$(maybe-value playlist-directory) + (and=> #$(maybe-value db-file) dirname) + (and=> #$(maybe-value state-file) dirname) + (and=> #$(maybe-value sticker-file) dirname)))) + + (make-forkexec-constructor + (list #$(file-append package "/bin/mpd") + "--no-daemon" + #$config-file) + #:environment-variables + ;; Required to detect PulseAudio when run under a user account. + (list (string-append + "XDG_RUNTIME_DIR=/run/user/" + (number->string (passwd:uid (getpwnam #$user)))))))) + (stop #~(make-kill-destructor)) + (actions + (list (shepherd-configuration-action config-file) + (shepherd-action + (name 'reopen) + (documentation "Re-open log files and flush caches.") + (procedure + #~(lambda (pid) + (if pid + (begin + (kill pid SIGHUP) + (format #t + "Issued SIGHUP to Service MPD (PID ~a)." + pid)) + (format #t "Service MPD is not running."))))))))))) + +(define (mpd-accounts config) + (match-record config (user group) + (list (user-group + (name group) + (system? #t)) + (user-account + (name user) + (group group) + (system? #t) + (comment "Music Player Daemon (MPD) user") + ;; MPD can use $HOME (or $XDG_CONFIG_HOME) to place its data + (home-directory "/var/lib/mpd") + (shell (file-append shadow "/sbin/nologin")))))) (define mpd-service-type (service-type @@ -237,7 +532,7 @@ By default this is a single output using pulseaudio.") (list (service-extension shepherd-root-service-type (compose list mpd-shepherd-service)) (service-extension account-service-type - (const %mpd-accounts)) - (service-extension activation-service-type - mpd-service-activation))) + mpd-accounts) + (service-extension rottlog-service-type + (compose list mpd-log-rotation)))) (default-value (mpd-configuration)))) -- cgit v1.2.3 From 637a9c3b264fe8eb76b6ed9f104b635d95632be6 Mon Sep 17 00:00:00 2001 From: Bruno Victal Date: Thu, 2 Feb 2023 20:07:38 +0000 Subject: services: mpd: Do not hardcode environment variables. Services should not expect for XDG_RUNTIME_DIR to be set. Inferring from the past comment, this seemed to resolve an issue when the service was launched with an _interactive_ user-account, which tends to have this variable set by the login-manager. This is not the case for system accounts and setting this variable results in PulseAudio (launched by the same system user) failing to start since it attempts to use a nonexistent directory. Ideally, this service should have a home-service counterpart but the old behavior can be emulated by setting the environment-variables field to: (environment-variables (list (string-append "XDG_RUNTIME_DIR=/run/user/" (number->string (passwd:uid (getpwnam "myuser")))))) * gnu/services/audio.scm (mpd-configuration)[environment-variables]: New field. (mpd-shepherd-service)[start]: Use new field. * doc/guix.texi (Audio Services)[Music Player Daemon]: Document it. Signed-off-by: Liliana Marie Prikler --- doc/guix.texi | 3 +++ gnu/services/audio.scm | 14 ++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'gnu/services') diff --git a/doc/guix.texi b/doc/guix.texi index cd18959db0..e7d56f2504 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -33199,6 +33199,9 @@ The group to run mpd as. This is a list of symbols naming Shepherd services that this service will depend on. +@item @code{environment-variables} (default: @code{()}) (type: list-of-string) +A list of strings specifying environment variables. + @item @code{log-file} (default: @code{"/var/log/mpd/log"}) (type: maybe-string) The location of the log file. Set to @code{syslog} to use the local syslog daemon or @code{%unset-value} to omit this directive from the diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm index 2bb8f66c96..3cbe21f23e 100644 --- a/gnu/services/audio.scm +++ b/gnu/services/audio.scm @@ -316,6 +316,11 @@ to be appended to the audio output configuration.") will depend on." empty-serializer) + (environment-variables + (list-of-string '()) + "A list of strings specifying environment variables." + empty-serializer) + (log-file (maybe-string "/var/log/mpd/log") "The location of the log file. Set to @code{syslog} to use the @@ -464,7 +469,8 @@ appended to the configuration.") (define (mpd-shepherd-service config) (match-record config (user package shepherd-requirement log-file playlist-directory - db-file state-file sticker-file) + db-file state-file sticker-file + environment-variables) (let* ((config-file (mpd-serialize-configuration config))) (shepherd-service (documentation "Run the MPD (Music Player Daemon)") @@ -489,11 +495,7 @@ appended to the configuration.") (list #$(file-append package "/bin/mpd") "--no-daemon" #$config-file) - #:environment-variables - ;; Required to detect PulseAudio when run under a user account. - (list (string-append - "XDG_RUNTIME_DIR=/run/user/" - (number->string (passwd:uid (getpwnam #$user)))))))) + #:environment-variables '#$environment-variables))) (stop #~(make-kill-destructor)) (actions (list (shepherd-configuration-action config-file) -- cgit v1.2.3 From 139c9a53cb19a97947aa6998eae953a4f32d3c3e Mon Sep 17 00:00:00 2001 From: Bruno Victal Date: Sat, 4 Feb 2023 20:28:16 +0000 Subject: services: Add mympd-service-type. * gnu/services/audio.scm (mympd-service-type): New variable. * gnu/tests/audio.scm (%test-mympd): New variable. * doc/guix.texi: Document it. Signed-off-by: Liliana Marie Prikler --- doc/guix.texi | 120 ++++++++++++++++++++++ gnu/services/audio.scm | 269 ++++++++++++++++++++++++++++++++++++++++++++++++- gnu/tests/audio.scm | 53 +++++++++- 3 files changed, 440 insertions(+), 2 deletions(-) (limited to 'gnu/services') diff --git a/doc/guix.texi b/doc/guix.texi index e7d56f2504..359c9b7a47 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -113,6 +113,7 @@ Copyright @copyright{} 2022 Bruno Victal@* Copyright @copyright{} 2022 Ivan Vilata-i-Balaguer@* Copyright @copyright{} 2023 Giacomo Leidi@* Copyright @copyright{} 2022 Antero Mejr@* +Copyright @copyright{} 2022 Bruno Victal@* Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or @@ -33396,6 +33397,125 @@ configures some of its plugins and provides a HTTP audio streaming output. (extra-options `((type . 0))))))) @end lisp +@subsubheading myMPD + +@cindex MPD, web interface +@cindex myMPD service + +@uref{https://jcorporation.github.io/myMPD/, myMPD} is a web server +frontend for MPD that provides a mobile friendly web client for MPD. + +The following example shows a myMPD instance listening on port 80, +with album cover caching disabled. + +@lisp +(service mympd-service-type + (mympd-configuration + (port 80) + (covercache-ttl 0))) +@end lisp + +@defvar mympd-service-type +The service type for @command{mympd}. +@end defvar + +@c %start of fragment +@deftp {Data Type} mympd-configuration +Available @code{mympd-configuration} fields are: + +@table @asis +@item @code{package} (default: @code{mympd}) (type: file-like) +The package object of the myMPD server. + +@item @code{shepherd-requirement} (default: @code{()}) (type: list-of-symbol) +This is a list of symbols naming Shepherd services that this service +will depend on. + +@item @code{user} (default: @code{"mympd"}) (type: string) +Owner of the @command{mympd} process. + +@item @code{group} (default: @code{"nogroup"}) (type: string) +Owner group of the @command{mympd} process. + +@item @code{work-directory} (default: @code{"/var/lib/mympd"}) (type: string) +Where myMPD will store its data. + +@item @code{cache-directory} (default: @code{"/var/cache/mympd"}) (type: string) +Where myMPD will store its cache. + +@item @code{acl} (type: maybe-mympd-ip-acl) +ACL to access the myMPD webserver. + +@item @code{covercache-ttl} (default: @code{31}) (type: maybe-integer) +How long to keep cached covers, @code{0} disables cover caching. + +@item @code{http?} (default: @code{#t}) (type: boolean) +HTTP support. + +@item @code{host} (default: @code{"[::]"}) (type: string) +Host name to listen on. + +@item @code{port} (default: @code{80}) (type: maybe-port) +HTTP port to listen on. + +@item @code{log-level} (default: @code{5}) (type: integer) +How much detail to include in logs, possible values: @code{0} to +@code{7}. + +@item @code{log-to} (default: @code{"/var/log/mympd/log"}) (type: string-or-symbol) +Where to send logs. By default, the service logs to +@file{/var/log/mympd.log}. The alternative is @code{'syslog}, which +sends output to the running syslog service under the @samp{daemon} +facility. + +@item @code{lualibs} (default: @code{"all"}) (type: maybe-string) +See +@uref{https://jcorporation.github.io/myMPD/scripting/#lua-standard-libraries}. + +@item @code{uri} (type: maybe-string) +Override URI to myMPD. See +@uref{https://github.com/jcorporation/myMPD/issues/950}. + +@item @code{script-acl} (default: @code{(mympd-ip-acl (allow '("127.0.0.1")))}) (type: maybe-mympd-ip-acl) +ACL to access the myMPD script backend. + +@item @code{ssl?} (default: @code{#f}) (type: boolean) +SSL/TLS support. + +@item @code{ssl-port} (default: @code{443}) (type: maybe-port) +Port to listen for HTTPS. + +@item @code{ssl-cert} (type: maybe-string) +Path to PEM encoded X.509 SSL/TLS certificate (public key). + +@item @code{ssl-key} (type: maybe-string) +Path to PEM encoded SSL/TLS private key. + +@item @code{pin-hash} (type: maybe-string) +SHA-256 hashed pin used by myMPD to control settings access by prompting +a pin from the user. + +@item @code{save-caches?} (type: maybe-boolean) +Whether to preserve caches between service restarts. + +@end table +@end deftp +@c %end of fragment + +@c %start of fragment +@deftp {Data Type} mympd-ip-acl +Available @code{mympd-ip-acl} fields are: + +@table @asis +@item @code{allow} (default: @code{()}) (type: list-of-string) +Allowed IP addresses. + +@item @code{deny} (default: @code{()}) (type: list-of-string) +Disallowed IP addresses. + +@end table +@end deftp +@c %end of fragment @node Virtualization Services @subsection Virtualization Services diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm index 3cbe21f23e..630110db2a 100644 --- a/gnu/services/audio.scm +++ b/gnu/services/audio.scm @@ -25,6 +25,7 @@ #:use-module (guix diagnostics) #:use-module (guix i18n) #:use-module (gnu services) + #:use-module (gnu services admin) #:use-module (gnu services configuration) #:use-module (gnu services shepherd) #:use-module (gnu services admin) @@ -32,6 +33,7 @@ #:use-module (gnu packages admin) #:use-module (gnu packages mpd) #:use-module (guix records) + #:use-module (ice-9 format) #:use-module (ice-9 match) #:use-module (srfi srfi-1) #:use-module (srfi srfi-26) @@ -90,7 +92,37 @@ mpd-configuration-outputs mpd-configuration-playlist-plugins mpd-configuration-extra-options - mpd-service-type)) + mpd-service-type + + mympd-service-type + mympd-configuration + mympd-configuration? + mympd-configuration-package + mympd-configuration-shepherd-requirement + mympd-configuration-user + mympd-configuration-group + mympd-configuration-work-directory + mympd-configuration-cache-directory + mympd-configuration-acl + mympd-configuration-covercache-ttl + mympd-configuration-http? + mympd-configuration-host + mympd-configuration-port + mympd-configuration-log-level + mympd-configuration-log-to + mympd-configuration-lualibs + mympd-configuration-uri + mympd-configuration-script-acl + mympd-configuration-ssl? + mympd-configuration-ssl-port + mympd-configuration-ssl-cert + mympd-configuration-ssl-key + mympd-configuration-pin-hash + mympd-configuration-save-caches? + mympd-ip-acl + mympd-ip-acl? + mympd-ip-acl-allow + mympd-ip-acl-deny)) ;;; Commentary: ;;; @@ -538,3 +570,238 @@ appended to the configuration.") (service-extension rottlog-service-type (compose list mpd-log-rotation)))) (default-value (mpd-configuration)))) + + +;;; +;;; myMPD +;;; + +(define (string-or-symbol? x) + (or (symbol? x) (string? x))) + +(define-configuration/no-serialization mympd-ip-acl + (allow + (list-of-string '()) + "Allowed IP addresses.") + + (deny + (list-of-string '()) + "Disallowed IP addresses.")) + +(define-maybe/no-serialization integer) +(define-maybe/no-serialization mympd-ip-acl) + +;; XXX: The serialization procedures are insufficient since we require +;; access to multiple fields at once. +;; Fields marked with empty-serializer are never serialized and are +;; used for command-line arguments or by the service definition. +(define-configuration/no-serialization mympd-configuration + (package + (file-like mympd) + "The package object of the myMPD server." + empty-serializer) + + (shepherd-requirement + (list-of-symbol '()) + "This is a list of symbols naming Shepherd services that this service +will depend on." + empty-serializer) + + (user + (string "mympd") + "Owner of the @command{mympd} process." + empty-serializer) + + (group + (string "nogroup") + "Owner group of the @command{mympd} process." + empty-serializer) + + (work-directory + (string "/var/lib/mympd") + "Where myMPD will store its data." + empty-serializer) + + (cache-directory + (string "/var/cache/mympd") + "Where myMPD will store its cache." + empty-serializer) + + (acl + maybe-mympd-ip-acl + "ACL to access the myMPD webserver.") + + (covercache-ttl + (maybe-integer 31) + "How long to keep cached covers, @code{0} disables cover caching.") + + (http? + (boolean #t) + "HTTP support.") + + (host + (string "[::]") + "Host name to listen on.") + + (port + (maybe-port 80) + "HTTP port to listen on.") + + (log-level + (integer 5) + "How much detail to include in logs, possible values: @code{0} to @code{7}.") + + (log-to + (string-or-symbol "/var/log/mympd/log") + "Where to send logs. By default, the service logs to +@file{/var/log/mympd.log}. The alternative is @code{'syslog}, which +sends output to the running syslog service under the @samp{daemon} facility." + empty-serializer) + + (lualibs + (maybe-string "all") + "See +@url{https://jcorporation.github.io/myMPD/scripting/#lua-standard-libraries}.") + + (uri + maybe-string + "Override URI to myMPD. +See @url{https://github.com/jcorporation/myMPD/issues/950}.") + + (script-acl + (maybe-mympd-ip-acl (mympd-ip-acl + (allow '("127.0.0.1")))) + "ACL to access the myMPD script backend.") + + (ssl? + (boolean #f) + "SSL/TLS support.") + + (ssl-port + (maybe-port 443) + "Port to listen for HTTPS.") + + (ssl-cert + maybe-string + "Path to PEM encoded X.509 SSL/TLS certificate (public key).") + + (ssl-key + maybe-string + "Path to PEM encoded SSL/TLS private key.") + + (pin-hash + maybe-string + "SHA-256 hashed pin used by myMPD to control settings access by +prompting a pin from the user.") + + (save-caches? + maybe-boolean + "Whether to preserve caches between service restarts.")) + +(define (mympd-serialize-configuration config) + (define serialize-value + (match-lambda + ((? boolean? val) (if val "true" "false")) + ((? integer? val) (number->string val)) + ((? mympd-ip-acl? val) (ip-acl-serialize-configuration val)) + ((? string? val) val))) + + (define (ip-acl-serialize-configuration config) + (define (serialize-list-of-string prefix lst) + (map (cut format #f "~a~a" prefix <>) lst)) + (string-join + (append + (serialize-list-of-string "+" (mympd-ip-acl-allow config)) + (serialize-list-of-string "-" (mympd-ip-acl-deny config))) ",")) + + ;; myMPD configuration fields are serialized as individual files under + ;; /config/. + (match-record config (work-directory acl + covercache-ttl http? host port + log-level lualibs uri script-acl + ssl? ssl-port ssl-cert ssl-key + pin-hash save-caches?) + (define (serialize-field filename value) + (when (maybe-value-set? value) + (list (format #f "~a/config/~a" work-directory filename) + (mixed-text-file filename (serialize-value value))))) + + (let ((filename-to-field `(("acl" . ,acl) + ("covercache_keep_days" . ,covercache-ttl) + ("http" . ,http?) + ("http_host" . ,host) + ("http_port" . ,port) + ("loglevel" . ,log-level) + ("lualibs" . ,lualibs) + ("mympd_uri" . ,uri) + ("scriptacl" . ,script-acl) + ("ssl" . ,ssl?) + ("ssl_port" . ,ssl-port) + ("ssl_cert" . ,ssl-cert) + ("ssl_key" . ,ssl-key) + ("pin_hash" . ,pin-hash) + ("save_caches" . ,save-caches?)))) + (filter list? + (generic-serialize-alist list serialize-field + filename-to-field))))) + +(define (mympd-shepherd-service config) + (match-record config (package shepherd-requirement + user work-directory + cache-directory log-level log-to) + (let ((log-level* (format #f "MYMPD_LOGLEVEL=~a" log-level))) + (shepherd-service + (documentation "Run the myMPD daemon.") + (requirement `(loopback user-processes ,@shepherd-requirement)) + (provision '(mympd)) + (start #~(begin + (let* ((pw (getpwnam #$user)) + (uid (passwd:uid pw)) + (gid (passwd:gid pw))) + (for-each (lambda (dir) + (mkdir-p dir) + (chown dir uid gid)) + (list #$work-directory #$cache-directory))) + + (make-forkexec-constructor + `(#$(file-append package "/bin/mympd") + "--user" #$user + #$@(if (eqv? log-to 'syslog) '("--syslog") '()) + "--workdir" #$work-directory + "--cachedir" #$cache-directory) + #:environment-variables (list #$log-level*) + #:log-file #$(if (string? log-to) log-to #f)))) + (stop #~(make-kill-destructor)))))) + +(define (mympd-accounts config) + (match-record config (user group) + (list (user-group (name group) + (system? #t)) + (user-account (name user) + (group group) + (system? #t) + (comment "myMPD user") + (home-directory "/var/empty") + (shell (file-append shadow "/sbin/nologin")))))) + +(define (mympd-log-rotation config) + (match-record config (log-to) + (if (string? log-to) + (list (log-rotation + (files (list log-to)))) + '()))) + +(define mympd-service-type + (service-type + (name 'mympd) + (extensions + (list (service-extension shepherd-root-service-type + (compose list mympd-shepherd-service)) + (service-extension account-service-type + mympd-accounts) + (service-extension special-files-service-type + mympd-serialize-configuration) + (service-extension rottlog-service-type + mympd-log-rotation))) + (description "Run myMPD, a frontend for MPD. (Music Player Daemon)") + (default-value (mympd-configuration)))) diff --git a/gnu/tests/audio.scm b/gnu/tests/audio.scm index 8aa6d1e818..acb91293e8 100644 --- a/gnu/tests/audio.scm +++ b/gnu/tests/audio.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2017 Peter Mikkelsen +;;; Copyright © 2022 Bruno Victal ;;; ;;; This file is part of GNU Guix. ;;; @@ -22,9 +23,11 @@ #:use-module (gnu system vm) #:use-module (gnu services) #:use-module (gnu services audio) + #:use-module (gnu services networking) #:use-module (gnu packages mpd) #:use-module (guix gexp) - #:export (%test-mpd)) + #:export (%test-mpd + %test-mympd)) (define %mpd-os (simple-operating-system @@ -76,3 +79,51 @@ (name "mpd") (description "Test that the mpd can run and be connected to.") (value (run-mpd-test)))) + +(define (run-mympd-test) + (define os (marionette-operating-system + (simple-operating-system (service dhcp-client-service-type) + (service mympd-service-type)) + #:imported-modules '((gnu services herd)))) + + (define vm + (virtual-machine + (operating-system os) + (port-forwardings '((8080 . 80))))) + + (define test + (with-imported-modules '((gnu build marionette)) + #~(begin + (use-modules (srfi srfi-64) + (srfi srfi-8) + (web client) + (web response) + (gnu build marionette)) + + (define marionette + (make-marionette (list #$vm))) + + (test-runner-current (system-test-runner #$output)) + (test-begin "mympd") + (test-assert "service is running" + (marionette-eval '(begin + (use-modules (gnu services herd)) + + (start-service 'mympd)) + marionette)) + + (test-assert "HTTP port ready" + (wait-for-tcp-port 80 marionette)) + + (test-equal "http-head" + 200 + (receive (x _) (http-head "http://localhost:8080") (response-code x))) + + (test-end)))) + (gexp->derivation "mympd-test" test)) + +(define %test-mympd + (system-test + (name "mympd") + (description "Connect to a running myMPD service.") + (value (run-mympd-test)))) -- cgit v1.2.3 From 4b9e1e84585270a40cec485046ce15387405d256 Mon Sep 17 00:00:00 2001 From: Bruno Victal Date: Sun, 5 Feb 2023 14:51:19 +0000 Subject: services: mpd: Fix serialization procedure for list-of-string. This is a followup to commit 5c5f0fc1135ff15f9c4adfc5f27eadd9a592b5d1 * gnu/services/audio.scm (mpd-serialize-list-of-string): Fix serialization procedure. Signed-off-by: Leo Famulari --- gnu/services/audio.scm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gnu/services') diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm index 630110db2a..d55b804ba9 100644 --- a/gnu/services/audio.scm +++ b/gnu/services/audio.scm @@ -160,7 +160,7 @@ (define mpd-serialize-boolean mpd-serialize-field) (define (mpd-serialize-list-of-string field-name value) - #~(string-concatenate #$(map (cut mpd-serialize-string field-name <>) value))) + #~(string-append #$@(map (cut mpd-serialize-string field-name <>) value))) (define-maybe string (prefix mpd-)) (define-maybe list-of-string (prefix mpd-)) -- cgit v1.2.3 From aef75942fc24fdb753978848b5471c5da21f23b7 Mon Sep 17 00:00:00 2001 From: Maxim Cournoyer Date: Tue, 7 Feb 2023 20:45:59 -0500 Subject: gnu: libjami: Move jamid daemon to a "bin" output. * gnu/packages/jami.scm (libjami) [outputs]: Add a "bin" output. [arguments]: Add a move-jamid phase. * gnu/services/telephony.scm (jami-configuration->command-line-arguments): Refer to the "bin" output of libjami. (jami-shepherd-services): Likewise. --- gnu/packages/jami.scm | 21 ++++++++++++++++++--- gnu/services/telephony.scm | 8 +++++--- 2 files changed, 23 insertions(+), 6 deletions(-) (limited to 'gnu/services') diff --git a/gnu/packages/jami.scm b/gnu/packages/jami.scm index b5b939c21c..64a4c53c9c 100644 --- a/gnu/packages/jami.scm +++ b/gnu/packages/jami.scm @@ -402,7 +402,7 @@ (name "libjami") (version %jami-version) (source %jami-sources) - (outputs '("out" "debug")) + (outputs '("out" "bin" "debug")) ;"bin' contains jamid (build-system gnu-build-system) (arguments (list @@ -425,7 +425,20 @@ (lambda _ (for-each delete-file (find-files (string-append #$output "/lib") - "\\.a$"))))))) + "\\.a$")))) + (add-after 'install 'move-jamid + ;; This nearly halves the size of the main output (from 1566.2 MiB + ;; to 833.6 MiB), due to not depending on dbus-c++ and its large + ;; dependencies. + (lambda* (#:key outputs #:allow-other-keys) + (let ((libexec (string-append #$output:bin "/libexec")) + (share (string-append #$output:bin "/share"))) + (mkdir-p libexec) + (rename-file (search-input-file outputs "libexec/jamid") + (string-append libexec "/jamid")) + (mkdir-p share) + (rename-file (search-input-directory outputs "share/dbus-1") + (string-append share "/dbus-1")))))))) (inputs (list alsa-lib asio @@ -461,7 +474,9 @@ Jami core functionality. Jami is a secure and distributed voice, video and chat communication platform that requires no centralized server and leaves the power of privacy in the hands of the user. It supports the SIP and IAX -protocols, as well as decentralized calling using P2P-DHT.") +protocols, as well as decentralized calling using P2P-DHT. The @samp{\"bin\"} +output contains the D-Bus daemon (@command{jamid}) as well as the Jami D-Bus +service definitions.") (home-page "https://jami.net/") (license license:gpl3+))) diff --git a/gnu/services/telephony.scm b/gnu/services/telephony.scm index b66c7a8563..23ccb8d403 100644 --- a/gnu/services/telephony.scm +++ b/gnu/services/telephony.scm @@ -267,7 +267,7 @@ consistent state.")) CONFIG, a object." (match-record config (libjami dbus enable-logging? debug? auto-answer?) - `(,(file-append libjami "/libexec/jamid") + `(,#~(string-append #$libjami:bin "/libexec/jamid") "--persistent" ;stay alive after client quits ,@(if enable-logging? '() ;logs go to syslog by default @@ -524,7 +524,8 @@ argument, either a registered username or the fingerprint of the account.") #:environment-variables ;; This is so that the cx.ring.Ring service D-Bus ;; definition is found by dbus-daemon. - (list (string-append "XDG_DATA_DIRS=" #$libjami "/share")))) + (list (string-append "XDG_DATA_DIRS=" + #$libjami:bin "/share")))) (stop #~(make-kill-destructor))) (shepherd-service @@ -595,7 +596,8 @@ argument, either a registered username or the fingerprint of the account.") ;; Start the daemon. (define daemon-pid ((make-forkexec-constructor/container - '#$(jami-configuration->command-line-arguments config) + (list #$@(jami-configuration->command-line-arguments + config)) #:mappings (list (file-system-mapping (source "/dev/log") ;for syslog -- cgit v1.2.3