GNU bug report logs - #59866
[PATCH 0/2] services: mpd: Refactor MPD service.

Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.

Package: guix-patches; Reported by: mirai@HIDDEN; Keywords: patch; dated Tue, 6 Dec 2022 23:24:01 UTC; Maintainer for guix-patches is guix-patches@HIDDEN.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 2 Feb 2023 20:09:52 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Feb 02 15:09:52 2023
Received: from localhost ([127.0.0.1]:35887 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1pNfu3-0007cx-L2
	for submit <at> debbugs.gnu.org; Thu, 02 Feb 2023 15:09:51 -0500
Received: from smtpmciv6.myservices.hosting ([185.26.106.201]:47066)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mirai@HIDDEN>) id 1pNfu1-0007cp-E3
 for 59866 <at> debbugs.gnu.org; Thu, 02 Feb 2023 15:09:50 -0500
Received: from mail1.netim.hosting (unknown [185.26.106.172])
 by smtpmciv6.myservices.hosting (Postfix) with ESMTP id 7B85320DE9;
 Thu,  2 Feb 2023 21:09:48 +0100 (CET)
Received: from localhost (localhost [127.0.0.1])
 by mail1.netim.hosting (Postfix) with ESMTP id 2EFF680098;
 Thu,  2 Feb 2023 21:09:48 +0100 (CET)
X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting
Received: from mail1.netim.hosting ([127.0.0.1])
 by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id rtrGhNt4uFWV; Thu,  2 Feb 2023 21:09:47 +0100 (CET)
Received: from guix-nuc.home.arpa (bl9-118-236.dsl.telepac.pt [85.242.118.236])
 (Authenticated sender: lumen@HIDDEN)
 by mail1.netim.hosting (Postfix) with ESMTPSA id A5A7880097;
 Thu,  2 Feb 2023 21:09:47 +0100 (CET)
From: Bruno Victal <mirai@HIDDEN>
To: 59866 <at> debbugs.gnu.org
Subject: [PATCH v6 3/3] services: mpd: Do not hardcode environment variables.
Date: Thu,  2 Feb 2023 20:07:38 +0000
Message-Id: <6b51304098d50a01c207abddb3b02ba863034e56.1675367583.git.mirai@HIDDEN>
X-Mailer: git-send-email 2.38.1
In-Reply-To: <23b0f83d1fd58fce9262d0b281b34e9678e21471.1675367583.git.mirai@HIDDEN>
References: <23b0f83d1fd58fce9262d0b281b34e9678e21471.1675367583.git.mirai@HIDDEN>
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 59866
Cc: Bruno Victal <mirai@HIDDEN>, liliana.prikler@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

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.
---

Notable changes since v5:
  * NEW. Fixes PulseAudio issues resulting from hardcoded environment variables.

 doc/guix.texi          |  3 +++
 gnu/services/audio.scm | 14 ++++++++------
 2 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 8e220e0631..05c216bec4 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -33199,6 +33199,9 @@ Audio Services
 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 7168320635..96b27660e5 100644
--- a/gnu/services/audio.scm
+++ b/gnu/services/audio.scm
@@ -316,6 +316,11 @@ (define-configuration mpd-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
@@ -465,7 +470,8 @@ (define (mpd-log-rotation config)
 (define (mpd-shepherd-service config)
   (match-record config <mpd-configuration> (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)")
@@ -490,11 +496,7 @@ (define (mpd-shepherd-service config)
                    (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)
-- 
2.38.1





Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 2 Feb 2023 20:08:15 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Feb 02 15:08:15 2023
Received: from localhost ([127.0.0.1]:35883 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1pNfsT-0007ac-Sc
	for submit <at> debbugs.gnu.org; Thu, 02 Feb 2023 15:08:15 -0500
Received: from smtpm2.myservices.hosting ([185.26.105.233]:40388)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mirai@HIDDEN>) id 1pNfsQ-0007aR-Tq
 for 59866 <at> debbugs.gnu.org; Thu, 02 Feb 2023 15:08:12 -0500
Received: from mail1.netim.hosting (unknown [185.26.106.172])
 by smtpm2.myservices.hosting (Postfix) with ESMTP id EF1EE20E7C;
 Thu,  2 Feb 2023 21:08:09 +0100 (CET)
Received: from localhost (localhost [127.0.0.1])
 by mail1.netim.hosting (Postfix) with ESMTP id B061480096;
 Thu,  2 Feb 2023 21:08:09 +0100 (CET)
X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting
Received: from mail1.netim.hosting ([127.0.0.1])
 by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id L-GJINCNunHY; Thu,  2 Feb 2023 21:08:08 +0100 (CET)
Received: from guix-nuc.home.arpa (bl9-118-236.dsl.telepac.pt [85.242.118.236])
 (Authenticated sender: lumen@HIDDEN)
 by mail1.netim.hosting (Postfix) with ESMTPSA id 8E76380093;
 Thu,  2 Feb 2023 21:08:08 +0100 (CET)
From: Bruno Victal <mirai@HIDDEN>
To: 59866 <at> debbugs.gnu.org
Subject: [PATCH v6 2/3] services: mpd: Refactor MPD service.
Date: Thu,  2 Feb 2023 20:07:37 +0000
Message-Id: <fe3fc24ea98bf66c95d0c589064a5c2edd7218bd.1675367583.git.mirai@HIDDEN>
X-Mailer: git-send-email 2.38.1
In-Reply-To: <23b0f83d1fd58fce9262d0b281b34e9678e21471.1675367583.git.mirai@HIDDEN>
References: <23b0f83d1fd58fce9262d0b281b34e9678e21471.1675367583.git.mirai@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 59866
Cc: Bruno Victal <mirai@HIDDEN>, liliana.prikler@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

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 record.

(mpd-serialize-boolean, mpd-serialize-field): Integrate serializers
into a single procedure for alist interop.

(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 predicate.

(mpd-file-name, mpd-service-activation): Remove procedure.

(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 field.
[music-dir, playlist-dir, address]: Deprecate shorthand field.
[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 doc.
---


Notable changes since v5:
  * Export accessors.
  * Integrate activation-service-type extension into service constructor.
  * Honor existing directories and permissions, only create when absent.

 doc/guix.texi          | 177 ++++++++++++---
 gnu/services/audio.scm | 492 +++++++++++++++++++++++++++++++++--------
 2 files changed, 543 insertions(+), 126 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 64873db00b..8e220e0631 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -109,6 +109,7 @@
 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 @@ Audio Services
 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 @@ Audio Services
                      (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..7168320635 100644
--- a/gnu/services/audio.scm
+++ b/gnu/services/audio.scm
@@ -21,20 +21,75 @@
 
 (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)
   #:use-module (guix records)
   #:use-module (ice-9 match)
   #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-8)
   #:use-module (srfi srfi-26)
   #: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,13 +105,20 @@ (define (uglify-field-name field-name)
                                    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
@@ -64,20 +126,103 @@ (define (mpd-serialize-alist field-name 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-boolean mpd-serialize-field)
 
-(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-maybe string (prefix mpd-))
+(define-maybe list-of-string (prefix mpd-))
+(define-maybe boolean (prefix mpd-))
+
+;;; 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 +240,12 @@ (define-configuration mpd-output
 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 +260,270 @@ (define-configuration mpd-output
 
   (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)
+  (receive (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.")
+  (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 (_ x)
+     (if (maybe-value-set? x)
+         #~(string-append #$@(map
+                              (cut mpd-serialize-field "bind_to_address" <>)
+                              x)) "")))
 
-  (address
-   (string "any")
+  (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 <mpd-configuration> (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 <mpd-configuration> (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 <mpd-configuration> (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 +533,7 @@ (define mpd-service-type
     (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))))
-- 
2.38.1





Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 2 Feb 2023 20:07:49 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Feb 02 15:07:49 2023
Received: from localhost ([127.0.0.1]:35879 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1pNfs5-0007ZX-1Q
	for submit <at> debbugs.gnu.org; Thu, 02 Feb 2023 15:07:49 -0500
Received: from smtpmciv3.myservices.hosting ([185.26.107.239]:55878)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mirai@HIDDEN>) id 1pNfs3-0007ZN-FD
 for 59866 <at> debbugs.gnu.org; Thu, 02 Feb 2023 15:07:48 -0500
Received: from mail1.netim.hosting (unknown [185.26.106.172])
 by smtpmciv3.myservices.hosting (Postfix) with ESMTP id 549292079E;
 Thu,  2 Feb 2023 21:07:45 +0100 (CET)
Received: from localhost (localhost [127.0.0.1])
 by mail1.netim.hosting (Postfix) with ESMTP id 0E92E80096;
 Thu,  2 Feb 2023 21:07:45 +0100 (CET)
X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting
Received: from mail1.netim.hosting ([127.0.0.1])
 by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id s5UzeYsfdz2q; Thu,  2 Feb 2023 21:07:42 +0100 (CET)
Received: from guix-nuc.home.arpa (bl9-118-236.dsl.telepac.pt [85.242.118.236])
 (Authenticated sender: lumen@HIDDEN)
 by mail1.netim.hosting (Postfix) with ESMTPSA id D489980093;
 Thu,  2 Feb 2023 21:07:41 +0100 (CET)
From: Bruno Victal <mirai@HIDDEN>
To: 59866 <at> debbugs.gnu.org
Subject: [PATCH v6 1/3] services: mpd: Rewrite using 'define-configuration'.
Date: Thu,  2 Feb 2023 20:07:36 +0000
Message-Id: <23b0f83d1fd58fce9262d0b281b34e9678e21471.1675367583.git.mirai@HIDDEN>
X-Mailer: git-send-email 2.38.1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 59866
Cc: Bruno Victal <mirai@HIDDEN>, liliana.prikler@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

* 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.
---

Notable changes since v5:
  * Completely eliminate indented procedures from patchset.

 gnu/services/audio.scm | 222 ++++++++++++++++++++++++-----------------
 1 file changed, 133 insertions(+), 89 deletions(-)

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 <petermikkelsen10@HIDDEN>
 ;;; Copyright © 2019 Ricardo Wurmus <rekado@HIDDEN>
 ;;; Copyright © 2020 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2022 Bruno Victal <mirai@HIDDEN>
 ;;;
 ;;; 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 @@ (define-module (gnu services audio)
 ;;;
 ;;; Code:
 
-(define-record-type* <mpd-output>
-  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>
-  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 <mpd-output> 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 @@ (define (mpd-shepherd-service config)
    (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
-- 
2.38.1





Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 3 Jan 2023 19:38:27 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Jan 03 14:38:27 2023
Received: from localhost ([127.0.0.1]:46722 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1pCn7D-0007Rz-4y
	for submit <at> debbugs.gnu.org; Tue, 03 Jan 2023 14:38:27 -0500
Received: from mail-ej1-f65.google.com ([209.85.218.65]:41472)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <liliana.prikler@HIDDEN>) id 1pCn78-0007Ri-KW
 for 59866 <at> debbugs.gnu.org; Tue, 03 Jan 2023 14:38:25 -0500
Received: by mail-ej1-f65.google.com with SMTP id u19so76546734ejm.8
 for <59866 <at> debbugs.gnu.org>; Tue, 03 Jan 2023 11:38:22 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112;
 h=mime-version:user-agent:content-transfer-encoding:references
 :in-reply-to:date:to:from:subject:message-id:from:to:cc:subject:date
 :message-id:reply-to;
 bh=gBQ+iGtJZUysPIMAzTgsU8U5wao51urAM1Ht84CuD2E=;
 b=caSH6cNPftw60aRy7oT5dsS+7IMmiWkLHmTdCIVBPqIuVsr9U1WZDE3W1Wkkdo+mQX
 L8yvnfZd/IAJFwS+kNc171CpfIFHfW4GmBpmqzRmhr1IlMd7rBchKyrDiwz+WJ4265FK
 axkz7IZUlYJ9R7JB0xn5DNXd5fSyCSPcv89zK/OjG2aqXBlMSYZOPbYlSIGKmkPPJjCt
 Jjt3CshC+6kpZ8/A6zj6R7obDAjdMqP0jShaHiHKWR10ZNcrQ4fPdiYirkFMWElYe2E+
 MXfKqEK3lEwwO7GjY8LqyDCeJmTyd4rRumwIdTLy9hgyi2PpzCQVkpumRvpmbHHi2/bP
 2xyw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20210112;
 h=mime-version:user-agent:content-transfer-encoding:references
 :in-reply-to:date:to:from:subject:message-id:x-gm-message-state:from
 :to:cc:subject:date:message-id:reply-to;
 bh=gBQ+iGtJZUysPIMAzTgsU8U5wao51urAM1Ht84CuD2E=;
 b=1ruUh3XBX46RZEoT0c6H4gnMC7Lh0JUAAKqypqg3jTB/bezs8fpLNpjjO1CzoNN2cr
 tCZ6xX+iaFLTyxKYWAFwYNelqrFLB6LlJxFDzw56TL1vvl+Uf6pBSGqRwbdWngat+EVW
 HkK3zXfrrgxSCF/mLBWMmSjynGZhxcWawA7o3hy1c28qgKEJfAs1adaIv0kxQiqJtN68
 XhvTwajHfSpRWNTiXrQB67vT40iHybviT1iflBs4gM0uJc78HDz8h2wbzSeaNTxHQycW
 EInCNl8Upa1IdQqkSlEsH0SkR10Iv0KcIhq7Zm5aX16rnxo16PRNttaheUuLbsC1otDb
 9sDA==
X-Gm-Message-State: AFqh2kqASReE8Ms55su/YWEeFlymWEgCJjKrKVB56iymLgVHw9FMPfnV
 HsCTjvCgJw6ZgyYgp6FuCyw=
X-Google-Smtp-Source: AMrXdXsGwoagZeFFO15Ttg0/r29/7PglguQAjf+Zvip1kTVKn+ERnkQ07sFBlD3CHmNAoclpbhB73w==
X-Received: by 2002:a17:906:27d4:b0:7c1:337e:575b with SMTP id
 k20-20020a17090627d400b007c1337e575bmr38089450ejc.66.1672774696520; 
 Tue, 03 Jan 2023 11:38:16 -0800 (PST)
Received: from lumine.fritz.box (85-127-52-93.dsl.dynamic.surfer.at.
 [85.127.52.93]) by smtp.gmail.com with ESMTPSA id
 k13-20020a1709061c0d00b0082000f8d871sm14445252ejg.152.2023.01.03.11.38.15
 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
 Tue, 03 Jan 2023 11:38:16 -0800 (PST)
Message-ID: <8af12f33afa0ef406711e8ed144d49b3e67935c3.camel@HIDDEN>
Subject: Re: Pulseaudio woes
From: Liliana Marie Prikler <liliana.prikler@HIDDEN>
To: mirai <mirai@HIDDEN>, 59866 <59866 <at> debbugs.gnu.org>
Date: Tue, 03 Jan 2023 20:38:14 +0100
In-Reply-To: <b381d59b-2278-1a6b-5f93-7b008504d544@HIDDEN>
References: <b381d59b-2278-1a6b-5f93-7b008504d544@HIDDEN>
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: base64
User-Agent: Evolution 3.46.0 
MIME-Version: 1.0
X-Spam-Score: 1.3 (+)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 Content preview:  Am Dienstag, dem 03.01.2023 um 14:43 +0000 schrieb mirai:
 > I've found out that this service (even before this patch-set) > is biased
 towards being used as a home service rather than a system > servic [...] 
 Content analysis details:   (1.3 points, 10.0 required)
 pts rule name              description
 ---- ---------------------- --------------------------------------------------
 0.0 FREEMAIL_FROM          Sender email is commonly abused enduser mail
 provider (liliana.prikler[at]gmail.com)
 1.3 RCVD_IN_VALIDITY_RPBL  RBL: Relay in Validity RPBL,
 https://senderscore.org/blocklistlookup/
 [209.85.218.65 listed in bl.score.senderscore.com]
 0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
 -0.0 SPF_PASS               SPF: sender matches SPF record
 0.0 RCVD_IN_MSPIKE_H3      RBL: Good reputation (+3)
 [209.85.218.65 listed in wl.mailspike.net]
 0.0 RCVD_IN_MSPIKE_WL      Mailspike good senders
X-Debbugs-Envelope-To: 59866
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 0.3 (/)

QW0gRGllbnN0YWcsIGRlbSAwMy4wMS4yMDIzIHVtIDE0OjQzICswMDAwIHNjaHJpZWIgbWlyYWk6
Cj4gSSd2ZSBmb3VuZCBvdXQgdGhhdCB0aGlzIHNlcnZpY2UgKGV2ZW4gYmVmb3JlIHRoaXMgcGF0
Y2gtc2V0KQo+IGlzIGJpYXNlZCB0b3dhcmRzIGJlaW5nIHVzZWQgYXMgYSBob21lIHNlcnZpY2Ug
cmF0aGVyIHRoYW4gYSBzeXN0ZW0KPiBzZXJ2aWNlLgo+IAo+IFRoZSByZWFzb24gaXMgdGhhdCBp
dCBzZXRzIHRoZSBYREdfUlVOVElNRV9ESVIgZW52aXJvbm1lbnQgdmFyaWFibGUKPiB0aHJvdWdo
IHNoZXBoZXJkCj4gdG86Cj4gCj4gLS04PC0tLS0tLS0tLS0tLS0tLWN1dCBoZXJlLS0tLS0tLS0t
LS0tLS0tc3RhcnQtLS0tLS0tLS0tLS0tPjgtLS0KPiAobGlzdCAoc3RyaW5nLWFwcGVuZAo+IMKg
wqDCoMKgwqDCoMKgICJYREdfUlVOVElNRV9ESVI9L3J1bi91c2VyLyIKPiDCoMKgwqDCoMKgwqDC
oCAobnVtYmVyLT5zdHJpbmcgKHBhc3N3ZDp1aWQgKGdldHB3bmFtICMkdXNlcikpKSkpCj4gLS04
PC0tLS0tLS0tLS0tLS0tLWN1dCBoZXJlLS0tLS0tLS0tLS0tLS0tZW5kLS0tLS0tLS0tLS0tLS0t
PjgtLS0KPiAKPiBUaGlzIGRpcmVjdG9yeSBkb2VzIG5vdCBleGlzdCBpZiB0aGlzIGlzIGxhdW5j
aGVkIGFzIGEgc3lzdGVtLXdpZGUKPiBzZXJ2aWNlLgo+IEkgcHJlc3VtZSB0aGF0IHRoaXMgd2Vu
dCB1bm5vdGljZWQgYmVjYXVzZSBtb3N0IG9mIHRoZSB0aW1lcyB5b3UnZAo+IHdhbnQgdG8gdXNl
IHRoaXMgc2VydmljZSBzeXN0ZW0td2lkZSB5b3UgYWxzbyBjb25maWd1cmUgdGhpcyBlaXRoZXIK
PiBhcyBhIE1QRCAnc2F0ZWxsaXRlIGluc3RhbmNlJyBvciB0aGUgYXVkaW8tb3V0cHV0cyBhcmUg
YWx3YXlzCj4gbmV0d29yay1zdHJlYW1pbmcgb25lcy4KPiAKPiBUaGlzIGZhbGxzIGFwYXJ0IGlm
IHlvdSBjb25maWd1cmUgYSBzeXN0ZW0td2lkZSBtcGQtc2VydmljZSB3aXRoIGEKPiBwdWxzZWF1
ZGlvIG91dHB1dCBhcyBpdCB3aWxsIHRyeSB0byBhY2Nlc3MgWERHX1JVTlRJTUVfRElSIHdoaWNo
IGlzCj4gbm90IGNyZWF0ZWQgZm9yIHRoZSBzeXN0ZW0/ICN0ICdtcGQnIHVzZXIuCkFzIGZhciBh
cyBJJ20gYXdhcmUsIHlvdSBjYW4gaW5zdGFudGlhdGUgdGhlIE1QRCBzZXJ2aWNlIHN5c3RlbS13
aWRlCndoaWxlIGFsc28gcG9pbnRpbmcgaXQgdG8gYSBub24tc3lzdGVtIHVzZXIuICBBZG1pdHRl
ZGx5LCB0aGlzIGlzIGEKc29tZXdoYXQgZGVnZW5lcmF0ZSB1c2UgY2FzZSwgYnV0IHRoYXQncyBo
b3cgdGhpbmdzIHdlcmUgaGFuZGxlZCBiZWZvcmUKaG9tZSBzZXJ2aWNlcyB3ZXJlIGEgdGhpbmcs
IGFuZCB0aGVyZSBtaWdodCBzdGlsbCBiZSB2YWxpZCByZWFzb25zIHRvCnN1cHBvcnQgaXQuCgo+
IE5vdywgcHVsc2VhdWRpbyBpcyB1c3VhbGx5IGxhdW5jaGVkIGFzIGEgJ3Blci11c2VyJyBkYWVt
b24gYWx0aG91Z2gKPiBpdCBjYW4gYmUgdXNlZCBpbiBhIHN5c3RlbS1wdWxzZSBjb25maWd1cmF0
aW9uIHRob3VnaCB0aGlzIGlzCj4gc3Ryb25nbHkgZGlzY291cmFnZWQuCklmIGl0IGlzLCB0aGVu
IFhER19SVU5USU1FX0RJUiBkb2Vzbid0IG1hdHRlci4KCj4gVW5kZXIgbW9zdCBjb25kaXRpb25z
IChwdWxzZWF1ZGlvIGNvbmZpZyBtb3N0bHkgdW5jaGFuZ2VkKSwKPiBhIHN5c3RlbS13aWRlIG1w
ZC1zZXJ2aWNlLXR5cGUgaXMgYWxzbyBhYmxlIHRvIGxhdW5jaCBpdHMgb3duIHB1bHNlCj4gaW5z
dGFuY2UgYnV0IGR1ZSB0byB0aGUgaW5oZXJlbnQgYXNzdW1wdGlvbnMgcHJlc2VudCBpbiB0aGUg
b3JpZ2luYWwKPiBzZXJ2aWNlIHdlIGhhdmUgdGhhdDoKPiDCoCAtIFRoZSBYREdfUlVOVElNRV9E
SVIgZW52IHZhciBpcyBzZXQgd2hlbiBpdCBzaG91bGQgb25seSBiZSBzZXQgZm9yCj4gJ3N5c3Rl
bT8gI2YnIHVzZXJzLgo+IMKgIC0gUFVMU0VfQ0xJRU5UQ09ORklHIGFuZCBQVUxTRV9DT05GSUcg
YXJlIG5vdCBzZXQgYnkgc2hlcGhlcmQuCj4gwqDCoMKgwqDCoMKgwqDCoFRoZXNlIHVzdWFsbHkg
Y29ycmVzcG9uZCB0bzoKPiDCoMKgwqDCoMKgwqDCoMKgwqAgUFVMU0VfQ09ORklHID0vZXRjL3B1
bHNlL2NsaWVudC5jb25mCj4gwqDCoMKgwqDCoMKgwqDCoMKgIFBVTFNFX0NPTkZJRz0vZXRjL3B1
bHNlL2RhZW1vbi5jb25mCj4gwqDCoMKgwqDCoMKgwqAgQnV0IGlmIHlvdSB1c2UgbXBkLXNlcnZp
Y2UtdHlwZSBhcyBhIGhvbWUgc2VydmljZSwgeW91IGNvdWxkCj4gYWxzbyBoYXZlCj4gwqDCoMKg
wqDCoCB0aGVzZSBzZXQgdG8gYSB1c2VyLXNwZWNpZmljIHB1bHNlIGNvbmZpZywgd2hpY2ggd2ls
bCBiZQo+IG92ZXJyaWRkZW4gYnkgc2hlcGhlcmQKPiDCoMKgwqDCoMKgIGlmIHRoZXNlIGFyZSBz
ZXQgaW4gbXBkLXNlcnZpY2UtdHlwZS4KPiDCoMKgwqDCoMKgwqDCoCBCdXQgYWdhaW4sIGlmIHlv
dSBkb24ndCBzZXQgdGhlc2UgZW52IHZhcnMgYW5kIHVzZSBpdCBhcyBhCj4gc3lzdGVtd2lkZSBz
ZXJ2aWNlCj4gwqDCoMKgwqDCoCB3aXRoIGEgcHVsc2VhdWRpbyBvdXRwdXQgYW5kIHlvdSB3b3Jr
YXJvdW5kIHRoZSBYREdfUlVOVElNRV9ESVIKPiBieSB1bnNldHRpbmcgaXQsCj4gwqDCoMKgwqDC
oCB5b3VyIHB1bHNlIGRhZW1vbiB3b24ndCByZWFkIGl0cyBjb25maWcgYW5kIHRoZXJlIHdpbGwg
YmUgbm8KPiBvdXRwdXQuCuS9le+8nwoKPiBUaGlzIGlzIG5vdCBqdXN0IGEgdGhlb3JldGljYWwg
aXNzdWUsIGNvbnNpZGVyIHRoaXMgc25pcHBldDoKPiAKPiAtLTg8LS0tLS0tLS0tLS0tLS0tY3V0
IGhlcmUtLS0tLS0tLS0tLS0tLS1zdGFydC0tLS0tLS0tLS0tLS0+OC0tLQo+IDs7IFNldCBhIHN5
c3RlbXdpZGUgbXBkIHNlcnZpY2UgdGhhdCBzdHJlYW1zIHdpdGggcHVsc2VhdWRpbyBSVFAKPiBv
dXRwdXQuCj4gCj4gKHNlcnZpY2UgcHVsc2VhdWRpby1zZXJ2aWNlLXR5cGUgKHB1bHNlYXVkaW8t
Y29uZmlndXJhdGlvbgo+IMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC
oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgKGV4dHJhLXNjcmlwdC1maWxlcwo+IMKgwqDC
oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg
wqDCoMKgwqDCoMKgwqAgKGxpc3QKPiDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg
wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAocGxhaW4tZmls
ZQo+IMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC
oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAicnRwLnBhIgo+IMKgwqDCoMKgwqDCoMKg
wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC
oMKgwqDCoMKgwqDCoCAoc3RyaW5nLWpvaW4gKGxpc3QgImxvYWQtCj4gbW9kdWxlIG1vZHVsZS1u
dWxsLXNpbmsgc2lua19uYW1lPXJ0cCIKPiDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC
oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg
wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAibG9hZC0KPiBtb2R1bGUgbW9kdWxl
LXJ0cC1zZW5kIHNvdXJjZT1ydHAubW9uaXRvciIKPiDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC
oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg
wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAic2V0LQo+IGRlZmF1bHQt
c2luayBydHAiKSAiXG4iICdzdWZmaXgpKSkpKSkKPiAoc2VydmljZSBtcGQtc2VydmljZS10eXBl
Cj4gwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIChtcGQtY29uZmlndXJhdGlv
bgo+IMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIChvdXRwdXRzIChsaXN0
IChtcGQtb3V0cHV0IChuYW1lICJQdWxzZWF1ZGlvIG92ZXIKPiBSVFAiKQo+IMKgwqDCoMKgwqDC
oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg
wqDCoCAodHlwZSAicHVsc2UiKQo+IMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC
oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAoZXh0cmEtb3B0aW9ucyAnKChz
aW5rIC4KPiAicnRwIikpKSkpKSkKPiAtLTg8LS0tLS0tLS0tLS0tLS0tY3V0IGhlcmUtLS0tLS0t
LS0tLS0tLS1lbmQtLS0tLS0tLS0tLS0tLS0+OC0tLQo+IAo+IFRoZSBwcm9ibGVtIGhlcmUgaXMg
aG93IHRvIGNvbmRpdGlvbmFsbHkgc2VsZWN0IHdoaWNoIGVudmlyb25tZW50Cj4gdmFyaWFibGVz
IHNob3VsZCBiZSBzZXQgYmFzZWQgb24gd2hldGhlciB0aGlzIGlzIGJlaW5nIGxhdW5jaGVkIGFz
IGEKPiBzeXN0ZW0td2lkZSBvciBob21lLWluc3RhbmNlIHNlcnZpY2UuIEknbSBhbGwgZWFycyBm
b3IKPiBzdWdnZXN0aW9ucy4KSSBkb24ndCB0aGluayB5b3UgbmVlZCB0byB0aGluayBhYm91dCB0
aGUgaG9tZSBzZXJ2aWNlIHRvbyBoYXJkIGhlcmUuIApJZiB5b3UgY2FuJ3QgZ2V0IHRoZSB0d28g
dXNlIGNhc2VzIHRvIHdvcmsgdG9nZXRoZXIsIHlvdSBjYW4gZGVmaW5lIGEKaG9tZS1tcGQtc2Vy
dmljZS10eXBlIHdoaWNoIHRha2VzIGEgcmVndWxhciBtcGQtY29uZmlndXJhdGlvbiBvciBhCnBh
cnRpY3VsYXJseSBjcmFmdGVkIGhvbWUtbXBkLWNvbmZpZ3VyYXRpb24sIHdoaWNoZXZlciBtYWtl
cyBtb3JlCnNlbnNlLiAgTm90IHNheWluZyB0aGF0IHRoaXMgd291bGQgYmUgYSBnb29kIGRlc2ln
biBpZGVhLCBqdXN0IHRoYXQgdGhlCm9wdGlvbiBleGlzdHMuCgpJIGRvIHRoaW5rIHRyeWluZyB0
byBmaWd1cmUgb3V0IHdoYXQgeW91J3JlIGdvaW5nIHRvIGRvIHdpdGggeW91cgplbnZpcm9ubWVu
dCB2YXJpYWJsZXMgaXMgYSBtb3JlIHdvcnRod2hpbGUgZXhlcmNpc2UgYXQgdGhlIG1vbWVudC4K
Cj4gUmVnYXJkaW5nIHRoZSBjdXJyZW50IHBhdGNoLXNldCwgSSdtIHRoaW5raW5nIHRoYXQgc29t
ZSBvZiB0aGUgbm9uLQo+IHB1YmxpYyBwcm9jZWR1cmVzIGNvdWxkIGJlIGRlZmluZWQgd2l0aCAn
ZGVmaW5lLWRlcHJlY2F0ZWQnIGluc3RlYWQKPiB3aGljaCBzaG91bGQgKD8pIGJlIGNsZWFuZXIg
dGhhbiB0aGUgY3VycmVudAo+IGNvbW1lbnRzIHRoYXQgYXJlIGRlbWFyY2F0aW5nIGRlcHJlY2F0
ZWQgY29kZS4KSWYgdGhleSBhcmVuJ3QgcHVibGljLCB3aGF0IGlzIHRoZSBwb2ludCBvZiBkZWZp
bmUtZGVwcmVjYXRlZD8gIFlvdQp3aWxsIG9ubHkgdHJpcCBvdmVyIHlvdXIgb3duIHVzZXMuCgpD
aGVlcnMK





Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 3 Jan 2023 14:43:40 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Jan 03 09:43:39 2023
Received: from localhost ([127.0.0.1]:45032 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1pCiVr-0007Vc-S5
	for submit <at> debbugs.gnu.org; Tue, 03 Jan 2023 09:43:39 -0500
Received: from smtpmciv5.myservices.hosting ([185.26.107.241]:38368)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mirai@HIDDEN>) id 1pCiVl-0007VP-Jd
 for 59866 <at> debbugs.gnu.org; Tue, 03 Jan 2023 09:43:33 -0500
Received: from mail1.netim.hosting (unknown [185.26.106.172])
 by smtpmciv5.myservices.hosting (Postfix) with ESMTP id ADFC620BE5;
 Tue,  3 Jan 2023 15:43:24 +0100 (CET)
Received: from localhost (localhost [127.0.0.1])
 by mail1.netim.hosting (Postfix) with ESMTP id 357CF80096;
 Tue,  3 Jan 2023 15:43:24 +0100 (CET)
X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting
Received: from mail1.netim.hosting ([127.0.0.1])
 by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id rmK9p6p4dvEO; Tue,  3 Jan 2023 15:43:23 +0100 (CET)
Received: from [192.168.1.239] (unknown [10.192.1.83])
 (Authenticated sender: lumen@HIDDEN)
 by mail1.netim.hosting (Postfix) with ESMTPSA id 7463280093;
 Tue,  3 Jan 2023 15:43:23 +0100 (CET)
Message-ID: <b381d59b-2278-1a6b-5f93-7b008504d544@HIDDEN>
Date: Tue, 3 Jan 2023 14:43:23 +0000
MIME-Version: 1.0
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
 Thunderbird/102.6.0
Content-Language: en-US
To: 59866 <59866 <at> debbugs.gnu.org>
From: mirai <mirai@HIDDEN>
Subject: Pulseaudio woes
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 59866
Cc: Liliana Marie Prikler <liliana.prikler@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

I've found out that this service (even before this patch-set)
is biased towards being used as a home service rather than a system service.

The reason is that it sets the XDG_RUNTIME_DIR environment variable through shepherd
to:

--8<---------------cut here---------------start------------->8---
(list (string-append
        "XDG_RUNTIME_DIR=/run/user/"
        (number->string (passwd:uid (getpwnam #$user)))))
--8<---------------cut here---------------end--------------->8---

This directory does not exist if this is launched as a system-wide service.
I presume that this went unnoticed because most of the times you'd want to
use this service system-wide you also configure this either as a MPD
'satellite instance' or the audio-outputs are always network-streaming ones.

This falls apart if you configure a system-wide mpd-service with a pulseaudio
output as it will try to access XDG_RUNTIME_DIR which is not created for the
system? #t 'mpd' user.

Now, pulseaudio is usually launched as a 'per-user' daemon although it can
be used in a system-pulse configuration though this is strongly discouraged.
Under most conditions (pulseaudio config mostly unchanged),
a system-wide mpd-service-type is also able to launch its own pulse instance
but due to the inherent assumptions present in the original service we have that:
  - The XDG_RUNTIME_DIR env var is set when it should only be set for 'system? #f' users.
  - PULSE_CLIENTCONFIG and PULSE_CONFIG are not set by shepherd.
	These usually correspond to:
	  PULSE_CONFIG =/etc/pulse/client.conf
	  PULSE_CONFIG=/etc/pulse/daemon.conf
        But if you use mpd-service-type as a home service, you could also have
      these set to a user-specific pulse config, which will be overridden by shepherd
      if these are set in mpd-service-type.
        But again, if you don't set these env vars and use it as a systemwide service
      with a pulseaudio output and you workaround the XDG_RUNTIME_DIR by unsetting it,
      your pulse daemon won't read its config and there will be no output.

This is not just a theoretical issue, consider this snippet:

--8<---------------cut here---------------start------------->8---
;; Set a systemwide mpd service that streams with pulseaudio RTP output.

(service pulseaudio-service-type (pulseaudio-configuration
                                    (extra-script-files
                                       (list
                                         (plain-file
                                           "rtp.pa"
                                           (string-join (list "load-module module-null-sink sink_name=rtp"
                                                              "load-module module-rtp-send source=rtp.monitor"
                                                              "set-default-sink rtp") "\n" 'suffix))))))
(service mpd-service-type
                   (mpd-configuration
                    (outputs (list (mpd-output (name "Pulseaudio over RTP")
                                     (type "pulse")
                                     (extra-options '((sink . "rtp")))))))
--8<---------------cut here---------------end--------------->8---

The problem here is how to conditionally select which environment variables should be set based
on whether this is being launched as a system-wide or home-instance service. I'm all ears for
suggestions.


Regarding the current patch-set, I'm thinking that some of the non-public procedures could
be defined with 'define-deprecated' instead which should (?) be cleaner than the current
comments that are demarcating deprecated code.

Regards,
Bruno





Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.
Changed bug title to '[PATCH 0/2] services: mpd: Refactor MPD service.' from '[WIP] [PATCH 0/2] services: mpd: Refactor MPD service' Request was from mirai <mirai@HIDDEN> to control <at> debbugs.gnu.org. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 24 Dec 2022 19:17:34 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Dec 24 14:17:34 2022
Received: from localhost ([127.0.0.1]:47165 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p9A1V-0008Br-W6
	for submit <at> debbugs.gnu.org; Sat, 24 Dec 2022 14:17:34 -0500
Received: from smtpm5.myservices.hosting ([185.26.105.236]:55032)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mirai@HIDDEN>) id 1p9A1T-0008Bg-RB
 for 59866 <at> debbugs.gnu.org; Sat, 24 Dec 2022 14:17:32 -0500
Received: from mail1.netim.hosting (unknown [185.26.106.172])
 by smtpm5.myservices.hosting (Postfix) with ESMTP id 91F0F201BD;
 Sat, 24 Dec 2022 20:17:30 +0100 (CET)
Received: from localhost (localhost [127.0.0.1])
 by mail1.netim.hosting (Postfix) with ESMTP id 4E2B18009A;
 Sat, 24 Dec 2022 20:17:30 +0100 (CET)
X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting
Received: from mail1.netim.hosting ([127.0.0.1])
 by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id SW7pDfSv6QS9; Sat, 24 Dec 2022 20:17:30 +0100 (CET)
Received: from [192.168.1.239] (unknown [10.192.1.83])
 (Authenticated sender: lumen@HIDDEN)
 by mail1.netim.hosting (Postfix) with ESMTPSA id D449480099;
 Sat, 24 Dec 2022 20:17:29 +0100 (CET)
Message-ID: <9d585ea3-2cab-6aee-16ee-672e4cf1cf81@HIDDEN>
Date: Sat, 24 Dec 2022 19:17:29 +0000
MIME-Version: 1.0
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
 Thunderbird/102.6.0
Subject: Re: [PATCH v5.1] services: mpd: Refactor MPD service.
Content-Language: en-US
To: Liliana Marie Prikler <liliana.prikler@HIDDEN>, 59866 <at> debbugs.gnu.org
References: <099d959851cb9ce9bf4afdedd01825b7ccf78a73.1671891059.git.mirai@HIDDEN>
 <4a93981e06259ffac47ecc6f988c37d1910593ee.camel@HIDDEN>
From: mirai <mirai@HIDDEN>
In-Reply-To: <4a93981e06259ffac47ecc6f988c37d1910593ee.camel@HIDDEN>
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -1.1 (-)
X-Debbugs-Envelope-To: 59866
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -2.1 (--)

On 2022-12-24 17:20, Liliana Marie Prikler wrote:
>> -(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")
>> +        ;; TODO: remove me, migrates from the old location at
>> /var/run/mpd
>> +        ;;       to the new one at /var/lib/mpd.
>> +        (let* ((user (getpw #$user))
>> +               (deprecated-directory (string-append "/var/run/mpd/"
>> +                                                    #$user "/.mpd"))
>> +               (new-directory (string-append (passwd:dir user)
>> +                                             "/.config/mpd")))
>> +          (when (and (file-exists? deprecated-directory)
>> +                     (not (file-exists? new-directory)))
>> +            (rename-file deprecated-directory new-directory)
>> +            (chown new-directory (passwd:uid user) (passwd:gid
>> user))))
>> +        (mkdir-p (dirname #$log-file)))))
> I'm not sure whether we should migrate the logs here.  I do think the
> logs should be stored in /var/log rather than /var/run, but other than
> that I'm not even sure there's much value in changing the /var/run/mpd
> structure.  What's your use case for doing so?

I agree with you that they belong to /var/log, though I prefer leaving this to
MPDs default behavior when the directives are not explicitly set.
IIRC MPD will store them under $XDG_CONFIG_HOME/log if the "log_file" directive
is absent.

They were previously stored under /var/run because it was set by default to store
under ~/.mpd and the user account had its $HOME set as "/var/run/mpd/mpd".
(Looking closer to the old behavior, this also meant that the user field was actually
ignored as the user-group/user-account was hardcoded).
Since /var/run/mpd(/mpd) is the $HOME directory in the old style configuration, it
also contains other files of interest, as most of the fields default values are
directives relative to $HOME.

Personally I've no use to this migration part and I'd prefer an outright breaking
change to the new style, most of the MPD generated files can be regenerated without much hardship
and this is introducing complexity and soon™ to be obsolete code.

Cheers




Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 24 Dec 2022 18:55:20 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Dec 24 13:55:20 2022
Received: from localhost ([127.0.0.1]:47156 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p99fz-0007Se-1B
	for submit <at> debbugs.gnu.org; Sat, 24 Dec 2022 13:55:20 -0500
Received: from smtpm3.myservices.hosting ([185.26.105.234]:49794)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mirai@HIDDEN>) id 1p99fv-0007SJ-Ci
 for 59866 <at> debbugs.gnu.org; Sat, 24 Dec 2022 13:55:17 -0500
Received: from mail1.netim.hosting (unknown [185.26.106.172])
 by smtpm3.myservices.hosting (Postfix) with ESMTP id 8B9A420DB1
 for <59866 <at> debbugs.gnu.org>; Sat, 24 Dec 2022 19:55:11 +0100 (CET)
Received: from localhost (localhost [127.0.0.1])
 by mail1.netim.hosting (Postfix) with ESMTP id 1DAE380098;
 Sat, 24 Dec 2022 19:55:11 +0100 (CET)
X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting
Received: from mail1.netim.hosting ([127.0.0.1])
 by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id yFBDdU6qcc39; Sat, 24 Dec 2022 19:55:10 +0100 (CET)
Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156])
 (Authenticated sender: lumen@HIDDEN)
 by mail1.netim.hosting (Postfix) with ESMTPSA id 4D9DA80097;
 Sat, 24 Dec 2022 19:55:09 +0100 (CET)
From: mirai@HIDDEN
To: 59866 <at> debbugs.gnu.org
Subject: [PATCH v5.2] services: mpd: Refactor MPD service.
Date: Sat, 24 Dec 2022 18:53:00 +0000
Message-Id: <adb84c94a7eae70b53b384bfe5f251a238324a62.1671907977.git.mirai@HIDDEN>
X-Mailer: git-send-email 2.38.1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 59866
Cc: Bruno Victal <mirai@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

From: Bruno Victal <mirai@HIDDEN>

Refactor mpd-service-type to support additional mpd.conf
directives.

* gnu/services/audio.scm
(mpd-plugin, mpd-partition): New record.

(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 predicate.

(mpd-serialize-field): Handle multiple types.

(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 field.
[music-dir, playlist-dir, address]: Deprecate shorthand field.
[db-file, state-file, sticker-file, port, outputs]: Change admissible type.

(mpd-log-rotation): New procedure.

(mpd-shepherd-service)
[actions]: New shepherd actions: 'reopen' and 'configuration'.
[requirement]: Splice with 'shepherd-requirement' field.
[start]: Use 'package' field. Remove #:log-file parameter.

(mpd-service-activation): Create logging directory. Handle migration
from old-style configuration.

(mpd-accounts): Do not hardcode user and group names.

(mpd-service-type): Extend rottlog-service-type for log-rotation.
Update activation-service-type extension to reflect mpd-accounts
procedure change.

* doc/guix.texi (Audio Services)[Music Player Daemon]: Update doc.
---

 Changes since v5.1:
 * Rewrite commit message.
 * Create group and user, by default mpd:mpd.
 * Reword endpoints doc.

 doc/guix.texi          | 177 +++++++++++++---
 gnu/services/audio.scm | 467 +++++++++++++++++++++++++++++++----------
 2 files changed, 510 insertions(+), 134 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index e25692fd27..870efdbe2d 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@*
 
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -33014,79 +33015,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
@@ -33098,7 +33207,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 1a1026f342..6caacf8c68 100644
--- a/gnu/services/audio.scm
+++ b/gnu/services/audio.scm
@@ -21,19 +21,27 @@
 
 (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)
   #:use-module (guix records)
   #:use-module (ice-9 match)
-  #:use-module (ice-9 format)
   #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-8)
   #:use-module (srfi srfi-26)
   #:export (mpd-output
             mpd-output?
+            mpd-plugin
+            mpd-plugin?
+            mpd-partition
+            mpd-partition?
             mpd-configuration
             mpd-configuration?
             mpd-service-type))
@@ -52,180 +60,425 @@ (define (uglify-field-name field-name)
                                #\-)
                  "_")))
 
-(define (free-form-args? val)
-  (match val
-    (() #t)
-    ((((? symbol?) . (? string?)) . val) (free-form-args? val))
-    (_ #f)))
+(define list-of-string?
+  (list-of string?))
 
-(define* (mpd-serialize-field field-name value #:optional (indent-level 0))
-  #~(begin
-      (use-modules ((ice-9 format)))
-      (format #f "~v/~a \"~a\"~%" #$indent-level #$(if (string? field-name)
-                                                       field-name
-                                                       (uglify-field-name field-name)) #$value)))
+(define list-of-symbol?
+  (list-of symbol?))
 
-(define* (mpd-serialize-free-form-args field-name value #:optional (indent-level 0))
-  (generic-serialize-alist string-append (cut mpd-serialize-field <> <> indent-level) value))
+(define (mpd-serialize-field field-name value)
+  (let ((field (if (string? field-name) field-name
+                   (uglify-field-name field-name)))
+        (value (if (boolean? value) (if value "yes" "no") value)))
+    #~(format #f "~a \"~a\"~%" #$field #$value)))
 
 (define mpd-serialize-number mpd-serialize-field)
 
 (define mpd-serialize-string mpd-serialize-field)
 
-(define* (mpd-serialize-boolean field-name value #:optional (indent-level 0))
-  (mpd-serialize-field field-name (if value "yes" "no") indent-level))
+(define mpd-serialize-boolean mpd-serialize-field)
 
-(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-alist field-name value)
+  #~(string-append #$@(generic-serialize-alist list
+                                               mpd-serialize-field
+                                               value)))
 
-(define (mpd-serialize-configuration configuration)
-  (mixed-text-file
-   "mpd.conf"
-   (serialize-configuration configuration mpd-configuration-fields)))
+(define-maybe string (prefix mpd-))
+(define-maybe list-of-string (prefix mpd-))
+(define-maybe boolean (prefix mpd-))
+
+;;; 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 mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> 1))
-(define mpd-subsystem-serialize-string (cut mpd-serialize-string <> <> 1))
-(define mpd-subsystem-serialize-number (cut mpd-serialize-number <> <> 1))
-(define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean <> <> 1))
-(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize-free-form-args <> <> 1))
+(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
    (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.")
+
+  (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
 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
+   "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
-   (free-form-args '())
-   "An association list of option symbols to string values to be appended to
-the audio output configuration.")
-  (prefix mpd-subsystem-))
+   (alist '())
+   "An association list of option symbols/strings to string values
+to be appended to the audio output configuration.")
 
-(define list-of-mpd-output?
-  (list-of mpd-output?))
+  (prefix mpd-))
+
+(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)
+  (receive (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)))
-  (playlist-dir
-   (string "~/.mpd/playlists")
+   mpd-serialize-deprecated-field)
+
+  (playlist-directory
+   maybe-string
+   "The directory to store 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) ; TODO: switch to integer
+   "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 (_ x)
+     (if (maybe-value-set? x)
+         #~(string-append #$@(map
+                              (cut mpd-serialize-field "bind_to_address" <>)
+                              x)) "")))
+
+  (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-list-of-mpd-plugin "input" x)))
+
+  (archive-plugins
+   (list-of-mpd-plugin '())
+   "List of MPD archive plugin configurations."
    (lambda (_ x)
-     (mpd-serialize-field "bind_to_address" 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 <mpd-configuration> (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))))
+  (match-record config <mpd-configuration> (user package shepherd-requirement)
+    (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 #~(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-service-activation config)
-  (with-imported-modules '((guix build utils))
+  (match-record config <mpd-configuration> (user log-file)
     #~(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")
+        ;; TODO: remove me, migrates from the old location at /var/run/mpd
+        ;;       to the new one at /var/lib/mpd.
+        (let* ((user (getpw #$user))
+               (deprecated-directory (string-append "/var/run/mpd/"
+                                                    #$user "/.mpd"))
+               (new-directory (string-append (passwd:dir user)
+                                             "/.config/mpd")))
+          (when (and (file-exists? deprecated-directory)
+                     (not (file-exists? new-directory)))
+            (rename-file deprecated-directory new-directory)
+            (chown new-directory (passwd:uid user) (passwd:gid user))))
+        (mkdir-p (dirname #$log-file)))))
 
-         (shell (file-append shadow "/sbin/nologin")))))
+(define (mpd-accounts config)
+  (match-record config <mpd-configuration> (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
@@ -235,7 +488,9 @@ (define mpd-service-type
     (list (service-extension shepherd-root-service-type
                              (compose list mpd-shepherd-service))
           (service-extension account-service-type
-                             (const %mpd-accounts))
+                             mpd-accounts)
           (service-extension activation-service-type
-                             mpd-service-activation)))
+                             mpd-service-activation)
+          (service-extension rottlog-service-type
+                             (compose list mpd-log-rotation))))
    (default-value (mpd-configuration))))

base-commit: aae8371f72805cc35e31817e4120468eee4a4a80
prerequisite-patch-id: e47455c06e8e73edcc3f36ccd7b6b289cdfa1e16
-- 
2.38.1





Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 24 Dec 2022 17:21:08 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Dec 24 12:21:08 2022
Received: from localhost ([127.0.0.1]:47060 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p98Co-0002A1-4Y
	for submit <at> debbugs.gnu.org; Sat, 24 Dec 2022 12:21:08 -0500
Received: from mail-wm1-f66.google.com ([209.85.128.66]:36855)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <liliana.prikler@HIDDEN>) id 1p98Cl-000293-1E
 for 59866 <at> debbugs.gnu.org; Sat, 24 Dec 2022 12:21:05 -0500
Received: by mail-wm1-f66.google.com with SMTP id
 c65-20020a1c3544000000b003cfffd00fc0so8196499wma.1
 for <59866 <at> debbugs.gnu.org>; Sat, 24 Dec 2022 09:21:02 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112;
 h=mime-version:user-agent:content-transfer-encoding:references
 :in-reply-to:date:to:from:subject:message-id:from:to:cc:subject:date
 :message-id:reply-to;
 bh=ciboyAGhoWIxNKcuoCKq/EpiuvbsahqbNAca0qttacI=;
 b=jm6axPxaDrG7hhrzcLIx2G5OsN5pLyV0RJVISaZ4H91nYU1DnaOlHHV7Q52HyGQQZu
 yCkWgflbmzs2JqwqPwVyJhF0A1Ahwn0zYtKTkQWH85es8REc0nG0TxPIQL5qvxlt6JgR
 BXs0hOhW6wg+RL6SPBoYdMEVXfFHwxSuQpeKmwuhyAiZ/+Wr8HwUZDz7RkYMNwc3NR50
 RCSV4/bUZ1xzW9pVlklMGXToC6kMN4IAhnks+IUpkJR3zVEcYM/CaUnilaJyPaupWl7/
 ui0nWu/IgJPE9sTMSEKvtEvvCdySmjxx9kLyKPKK0kasOrt3jF8Ou0GQBxwxmc34tNxN
 YdbQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20210112;
 h=mime-version:user-agent:content-transfer-encoding:references
 :in-reply-to:date:to:from:subject:message-id:x-gm-message-state:from
 :to:cc:subject:date:message-id:reply-to;
 bh=ciboyAGhoWIxNKcuoCKq/EpiuvbsahqbNAca0qttacI=;
 b=ns8+PRxAO7Dg4iB9UtdC9O+KbAw8T+784Ikt78Bgehj5Voykq2xJu0YUJeyd6nmbSL
 1Qs13phigNXVbH5IFW5W94Ewiyxa78QeEzNvAJX3sMTq2Vn3ITGaX0lUq1oHFQfZLvEs
 443iJ7+hfIWmZep5ZAhbzrGxeK47WcYYyvPVsvQ4qE8m9BPe096FJybsNQhF2P3Kgg7P
 0SDtSK3cNS8FczRQfCdrJsMJOwTnTrfu6+rq+ZaKQAws4u+fm+HpCq6nxdKdQu6hL9ag
 rVJ5ehDBR4HHaMVsFJJFvuStDhmrfYSGkXah5uaMoRiGqJNA0WrNmuCb7OyVOY7RamIn
 xYFQ==
X-Gm-Message-State: AFqh2krnzAeglcCw0ZEFSExZbGH30VjSCR6WVGFIkMPP3DavwMPH0tL9
 qzAXfGiYEE0l/qaOlH2yqVQ=
X-Google-Smtp-Source: AMrXdXt8/8GXl8d4to1GUILweXsVwfyM+P5ja6VY+Py8AhRn4lNwTrjfGa+v019T2qjMg2s4KijQmg==
X-Received: by 2002:a05:600c:601e:b0:3c6:e61e:ae71 with SMTP id
 az30-20020a05600c601e00b003c6e61eae71mr11584043wmb.1.1671902456530; 
 Sat, 24 Dec 2022 09:20:56 -0800 (PST)
Received: from lumine.fritz.box (85-127-52-93.dsl.dynamic.surfer.at.
 [85.127.52.93]) by smtp.gmail.com with ESMTPSA id
 i2-20020a05600c354200b003d35acb0fd7sm14347049wmq.34.2022.12.24.09.20.55
 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
 Sat, 24 Dec 2022 09:20:56 -0800 (PST)
Message-ID: <4a93981e06259ffac47ecc6f988c37d1910593ee.camel@HIDDEN>
Subject: Re: [PATCH v5.1] services: mpd: Refactor MPD service.
From: Liliana Marie Prikler <liliana.prikler@HIDDEN>
To: mirai@HIDDEN, 59866 <at> debbugs.gnu.org
Date: Sat, 24 Dec 2022 18:20:54 +0100
In-Reply-To: <099d959851cb9ce9bf4afdedd01825b7ccf78a73.1671891059.git.mirai@HIDDEN>
References: <099d959851cb9ce9bf4afdedd01825b7ccf78a73.1671891059.git.mirai@HIDDEN>
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
User-Agent: Evolution 3.46.0 
MIME-Version: 1.0
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 59866
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Am Samstag, dem 24.12.2022 um 14:11 +0000 schrieb mirai@HIDDEN:
> From: Bruno Victal <mirai@HIDDEN>
>=20
> Introduces 'mpd-plugin' and 'mpd-partition' records.
> Expands 'mpd-output' and 'mpd-configuration' records.
> Deprecates redundant abbreviated fields in 'mpd-configuration' and
> avoids
> serializing unused fields that may introduce undesired behavior.
> Replace free-form-args serialization by making 'mpd-serialize-field'
> handle
> multiple types and using it with 'generic-serialize-alist'.
> Reduce code weight by removing cosmetic indented serialization
> procedures.
> Offload logging from shepherd to MPD.
> Implement log-rotation via rottlog.
> Implement Shepherd actions: 'reopen' and 'configuration'.
The things you wrote here read a like a less structured ChangeLog.  The
section between header and ChangeLog should instead be used to give
some wider context if needed, imo.

> * gnu/services/audio.scm
> (mpd-plugin, mpd-partition): New record.
>=20
> (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 predicate.
>=20
> (mpd-serialize-field): Handle multiple types.
>=20
> (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 field.
> [music-dir, playlist-dir, address]: Deprecate shorthand field.
> [db-file, state-file, sticker-file, port, outputs]: Change admissible
> type.
>=20
> (mpd-log-rotation): New procedure.
>=20
> (mpd-shepherd-service)
> [actions]: New shepherd actions: 'reopen' and 'configuration'.
> [requirement]: Splice with 'shepherd-requirement' field.
> [start]: Use 'package' field. Remove #:log-file parameter.
>=20
> (mpd-service-activation): Create logging directory. Handle migration
> from old-style configuration.
>=20
> (mpd-accounts): Do not hardcode username, change primary group to
> "nogroup".
While I welcome the extensibility here, I think the default should
still be mpd:mpd.  I think you should make it so that you can pass a
user-account and user-group to the mpd service so that they can be
reused (with a sanitizer that creates a user/group from string).

> (mpd-service-type): Extend rottlog-service-type for log-rotation.
> Update activation-service-type extension to reflect mpd-accounts
> procedure change.
>=20
> * doc/guix.texi (Audio Services)[Music Player Daemon]: Update doc.
> ---
>=20
> =C2=A0Changes since v5:
> =C2=A0* Serialize default_port field-name as "port".
>=20
> =C2=A0doc/guix.texi=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
 | 177 +++++++++++++---
> =C2=A0gnu/services/audio.scm | 463 +++++++++++++++++++++++++++++++-------=
-
> --
> =C2=A02 files changed, 506 insertions(+), 134 deletions(-)
>=20
> diff --git a/doc/guix.texi b/doc/guix.texi
> index e25692fd27..5663d1913a 100644
> --- a/doc/guix.texi
> +++ b/doc/guix.texi
> @@ -109,6 +109,7 @@ Copyright @copyright{} 2022 Reily Siegel@*
> =C2=A0Copyright @copyright{} 2022 Simon Streit@*
> =C2=A0Copyright @copyright{} 2022 (@*
> =C2=A0Copyright @copyright{} 2022 John Kehayias@*
> +Copyright @copyright{} 2022 Bruno Victal@*
> =C2=A0
> =C2=A0Permission is granted to copy, distribute and/or modify this
> document
> =C2=A0under the terms of the GNU Free Documentation License, Version 1.3
> or
> @@ -33014,79 +33015,187 @@ The service type for @command{mpd}
> =C2=A0Data type representing the configuration of @command{mpd}.
> =C2=A0
> =C2=A0@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)
> =C2=A0The user to run mpd as.
> =C2=A0
> -@item @code{music-dir} (default: @code{"~/Music"})
> +@item @code{group} (type: maybe-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.=C2=A0 Set to @code{syslog} to use the loca=
l
> +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.=C2=A0 Available values:
> +@code{notice}, @code{info}, @code{verbose}, @code{warning} and
> +@code{error}.
> +
> +@item @code{music-directory} (type: maybe-string)
> =C2=A0The directory to scan for music files.
> =C2=A0
> -@item @code{playlist-dir} (default: @code{"~/.mpd/playlists"})
> +@item @code{playlist-directory} (type: maybe-string)
> =C2=A0The directory to store playlists.
> =C2=A0
> -@item @code{db-file} (default: @code{"~/.mpd/tag_cache"})
> +@item @code{db-file} (type: maybe-string)
> =C2=A0The location of the music database.
> =C2=A0
> -@item @code{state-file} (default: @code{"~/.mpd/state"})
> +@item @code{state-file} (type: maybe-string)
> =C2=A0The location of the file that stores current MPD's state.
> =C2=A0
> -@item @code{sticker-file} (default: @code{"~/.mpd/sticker.sql"})
> +@item @code{sticker-file} (type: maybe-string)
> =C2=A0The location of the sticker database.
> =C2=A0
> -@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.=C2=A0 A different port may be
> +specified, e.g. @code{localhost:6602}.=C2=A0 IPv6 addresses must be
> +enclosed in square brackets if a different port is used.
> +To use a Unix domain socket, an absolute path or a path starting
> with @code{~}
> +can be specified here.
LGTM, but "A different port" should probably be "A port different from
@var{default-port}.

> +@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".
> =C2=A0
> -@item @code{address} (default: @code{"any"})
> -The address that mpd will bind to.=C2=A0 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.
> =C2=A0
> -@item @code{outputs} (default: @code{"(list (mpd-output))"})
> -The audio outputs that MPD can use.=C2=A0 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.=C2=A0 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.=C2=A0 See
> +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD=C2=A0plugin
> +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.=C2=A0 See
> +@uref{
> https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions
> ,Configuring
> +Partitions} for available options.
> =C2=A0
> =C2=A0@end table
> =C2=A0@end deftp
> =C2=A0
> =C2=A0@deftp {Data Type} mpd-output
> -Data type representing an @command{mpd} audio output.
> +Data type representing a @command{mpd} audio output.
> =C2=A0
> =C2=A0@table @asis
> -@item @code{name} (default: @code{"MPD"})
> +@item @code{name} (default: @code{"MPD"}) (type: string)
> =C2=A0The name of the audio output.
> =C2=A0
> -@item @code{type} (default: @code{"pulse"})
> +@item @code{type} (default: @code{"pulse"}) (type: string)
> =C2=A0The type of audio output.
> =C2=A0
> -@item @code{enabled?} (default: @code{#t})
> +@item @code{enabled?} (default: @code{#t}) (type: boolean)
> =C2=A0Specifies whether this audio output is enabled when MPD is started.=
=C2=A0
> By
> =C2=A0default, all audio outputs are enabled.=C2=A0 This is just the defa=
ult
> =C2=A0setting when there is no state file; with a state file, the previou=
s
> =C2=A0state is restored.
> =C2=A0
> -@item @code{tags?} (default: @code{#t})
> +@item @code{format} (type: maybe-string)
> +Force a specific audio format on output.=C2=A0 See
> +@uref{
> https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Gl
> obal
> +Audio Format} for a more detailed description.
> +
> +@item @code{tags?} (default: @code{#t}) (type: boolean)
> =C2=A0If set to @code{#f}, then MPD will not send tags to this output.=C2=
=A0
> This
> =C2=A0is only useful for output plugins that can receive tags, for exampl=
e
> the
> =C2=A0@code{httpd} output plugin.
> =C2=A0
> -@item @code{always-on?} (default: @code{#f})
> +@item @code{always-on?} (default: @code{#f}) (type: boolean)
> =C2=A0If set to @code{#t}, then MPD attempts to keep this audio output
> always
> -open.=C2=A0 This may be useful for streaming servers, when you don=E2=80=
=99t want
> to
> +open.=C2=A0 This may be useful for streaming servers, when you don?t wan=
t
> to
> =C2=A0disconnect all listeners even when playback is accidentally stopped=
.
> =C2=A0
> -@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
> =C2=A0for this audio output: the @code{hardware} mixer, the
> @code{software}
> =C2=A0mixer, the @code{null} mixer (allows setting the volume, but with n=
o
> =C2=A0effect; this can be used as a trick to implement an external mixer
> =C2=A0External Mixer) or no mixer (@code{none}).
> =C2=A0
> -@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.=C2=A0 @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.
> =C2=A0
> =C2=A0@end table
> =C2=A0@end deftp
> =C2=A0
> -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.
> =C2=A0
> =C2=A0@lisp
> =C2=A0(service mpd-service-type
> @@ -33098,7 +33207,19 @@ an HTTP audio streaming output.
> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (mixer-type 'null)
> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (extra-options
> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 `((encoder . "=
vorbis")
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (port=C2=
=A0=C2=A0=C2=A0 . "8080"))))))))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (port=C2=
=A0=C2=A0=C2=A0 . "8080"))))))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (decoders
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
 (list (mpd-plugin
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (plugin "mikmod")
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (enabled? #f))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-plugin
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (plugin "openmpt")
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (enabled? #t)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (extra-options `((repeat-c=
ount . -1)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
 (interpolation-filter .
> 1))))))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (resampler =
(mpd-plugin
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (plugin =
"libsamplerate")
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (extra-o=
ptions `((type . 0)))))))
> =C2=A0@end lisp
> =C2=A0
> =C2=A0
> diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm
> index 1a1026f342..e456205e99 100644
> --- a/gnu/services/audio.scm
> +++ b/gnu/services/audio.scm
> @@ -21,19 +21,27 @@
> =C2=A0
> =C2=A0(define-module (gnu services audio)
> =C2=A0=C2=A0 #:use-module (guix gexp)
> +=C2=A0 #:use-module (guix deprecation)
> +=C2=A0 #:use-module (guix diagnostics)
> +=C2=A0 #:use-module (guix i18n)
> =C2=A0=C2=A0 #:use-module (gnu services)
> =C2=A0=C2=A0 #:use-module (gnu services configuration)
> =C2=A0=C2=A0 #:use-module (gnu services shepherd)
> +=C2=A0 #:use-module (gnu services admin)
> =C2=A0=C2=A0 #:use-module (gnu system shadow)
> =C2=A0=C2=A0 #:use-module (gnu packages admin)
> =C2=A0=C2=A0 #:use-module (gnu packages mpd)
> =C2=A0=C2=A0 #:use-module (guix records)
> =C2=A0=C2=A0 #:use-module (ice-9 match)
> -=C2=A0 #:use-module (ice-9 format)
> =C2=A0=C2=A0 #:use-module (srfi srfi-1)
> +=C2=A0 #:use-module (srfi srfi-8)
> =C2=A0=C2=A0 #:use-module (srfi srfi-26)
> =C2=A0=C2=A0 #:export (mpd-output
> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =
mpd-output?
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 mpd-p=
lugin
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 mpd-p=
lugin?
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 mpd-p=
artition
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 mpd-p=
artition?
> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =
mpd-configuration
> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =
mpd-configuration?
> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =
mpd-service-type))
> @@ -52,180 +60,421 @@ (define (uglify-field-name field-name)
> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #\-)
> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "_")))
> =C2=A0
> -(define (free-form-args? val)
> -=C2=A0 (match val
> -=C2=A0=C2=A0=C2=A0 (() #t)
> -=C2=A0=C2=A0=C2=A0 ((((? symbol?) . (? string?)) . val) (free-form-args?=
 val))
> -=C2=A0=C2=A0=C2=A0 (_ #f)))
> +(define list-of-string?
> +=C2=A0 (list-of string?))
> =C2=A0
> -(define* (mpd-serialize-field field-name value #:optional (indent-
> level 0))
> -=C2=A0 #~(begin
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (use-modules ((ice-9 format)))
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (format #f "~v/~a \"~a\"~%" #$indent-leve=
l #$(if (string?
> field-name)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0 field-name
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0 (uglify-
> field-name field-name)) #$value)))
> +(define list-of-symbol?
> +=C2=A0 (list-of symbol?))
> =C2=A0
> -(define* (mpd-serialize-free-form-args field-name value #:optional
> (indent-level 0))
> -=C2=A0 (generic-serialize-alist string-append (cut mpd-serialize-field <=
>
> <> indent-level) value))
> +(define (mpd-serialize-field field-name value)
> +=C2=A0 (let ((field (if (string? field-name) field-name
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (uglify-field-name field-name)))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (value (if (boolean? value) (=
if value "yes" "no") value)))
> +=C2=A0=C2=A0=C2=A0 #~(format #f "~a \"~a\"~%" #$field #$value)))
> =C2=A0
> =C2=A0(define mpd-serialize-number mpd-serialize-field)
> =C2=A0
> =C2=A0(define mpd-serialize-string mpd-serialize-field)
> =C2=A0
> -(define* (mpd-serialize-boolean field-name value #:optional (indent-
> level 0))
> -=C2=A0 (mpd-serialize-field field-name (if value "yes" "no") indent-
> level))
> +(define mpd-serialize-boolean mpd-serialize-field)
> =C2=A0
> -(define (mpd-serialize-list-of-mpd-output field-name value)
> -=C2=A0 #~(string-append "\naudio_output {\n"
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #$@(map (cut serialize-configuration <=
>
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 mpd-output-fields)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0 value)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "}\n"))
> +(define (mpd-serialize-alist field-name value)
> +=C2=A0 #~(string-append #$@(generic-serialize-alist list
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 mpd-serialize-field
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 value)))
> =C2=A0
> -(define (mpd-serialize-configuration configuration)
> -=C2=A0 (mixed-text-file
> -=C2=A0=C2=A0 "mpd.conf"
> -=C2=A0=C2=A0 (serialize-configuration configuration mpd-configuration-
> fields)))
> +(define-maybe string (prefix mpd-))
> +(define-maybe list-of-string (prefix mpd-))
> +(define-maybe boolean (prefix mpd-))
> +
> +;;; TODO: Procedures for deprecated fields, to be removed.
> +
> +(define mpd-deprecated-fields '((music-dir . music-directory)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (playlist-dir . playlist-directory)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (address . endpoints)))
> +
> +(define (port? value) (or (string? value) (integer? value)))
> +
> +(define (mpd-serialize-deprecated-field field-name value)
> +=C2=A0 (if (maybe-value-set? value)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (begin
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (warn-about-deprecation
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 field-name #f
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #:replacement (assoc-re=
f mpd-deprecated-fields field-name))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (match field-name
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ('playlist-dir (m=
pd-serialize-string "playlist_directory"
> value))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ('music-dir (mpd-=
serialize-string "music_directory"
> value))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ('address (mpd-se=
rialize-string "bind_to_address"
> value))))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ""))
> +
> +(define (mpd-serialize-port field-name value)
> +=C2=A0 (when (string? value)
> +=C2=A0=C2=A0=C2=A0 (warning
> +=C2=A0=C2=A0=C2=A0=C2=A0 (G_ "string value for '~a' is deprecated, use i=
nteger
> instead~%")
> +=C2=A0=C2=A0=C2=A0=C2=A0 field-name))
> +=C2=A0 (mpd-serialize-field "port" value))
> +
> +(define-maybe port (prefix mpd-))
> +
> +;;;
> +
> +;; Generic MPD plugin record, lists only the most prevalent fields.
> +(define-configuration mpd-plugin
> +=C2=A0 (plugin
> +=C2=A0=C2=A0 maybe-string
> +=C2=A0=C2=A0 "Plugin name.")
> +
> +=C2=A0 (name
> +=C2=A0=C2=A0 maybe-string
> +=C2=A0=C2=A0 "Name.")
> +
> +=C2=A0 (enabled?
> +=C2=A0=C2=A0 maybe-boolean
> +=C2=A0=C2=A0 "Whether the plugin is enabled/disabled.")
> +
> +=C2=A0 (extra-options
> +=C2=A0=C2=A0 (alist '())
> +=C2=A0=C2=A0 "An association list of option symbols/strings to string va=
lues
> +to be appended to the plugin configuration. See
> +@uref{https://mpd.readthedocs.io/en/latest/plugins.html,MPD=C2=A0plugin
> reference}
> +for available options.")
> +
> +=C2=A0 (prefix mpd-))
> +
> +(define (mpd-serialize-mpd-plugin field-name value)
> +=C2=A0 #~(format #f "~a {~%~a}~%"
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 '#$fi=
eld-name
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #$(se=
rialize-configuration value mpd-plugin-fields)))
> +
> +(define (mpd-serialize-list-of-mpd-plugin field-name value)
> +=C2=A0 #~(string-append #$@(map (cut mpd-serialize-mpd-plugin field-name
> <>)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0 value)))
> =C2=A0
> -(define mpd-subsystem-serialize-field (cut mpd-serialize-field <> <>
> 1))
> -(define mpd-subsystem-serialize-string (cut mpd-serialize-string <>
> <> 1))
> -(define mpd-subsystem-serialize-number (cut mpd-serialize-number <>
> <> 1))
> -(define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean
> <> <> 1))
> -(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize-
> free-form-args <> <> 1))
> +(define list-of-mpd-plugin? (list-of mpd-plugin?))
> +
> +(define-maybe mpd-plugin (prefix mpd-))
> +
> +(define-configuration mpd-partition
> +=C2=A0 (name
> +=C2=A0=C2=A0 string
> +=C2=A0=C2=A0 "Partition name.")
> +
> +=C2=A0 (extra-options
> +=C2=A0=C2=A0 (alist '())
> +=C2=A0=C2=A0 "An association list of option symbols/strings to string va=
lues
> +to be appended to the partition configuration. See
> +@uref{
> https://mpd.readthedocs.io/en/latest/user.html#configuring-partitions
> ,Configuring=C2=A0Partitions}
> +for available options.")
> +
> +=C2=A0 (prefix mpd-))
> +
> +(define (mpd-serialize-mpd-partition field-name value)
> +=C2=A0 #~(format #f "partition {~%~a}~%"
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #$(se=
rialize-configuration value mpd-partition-fields)))
> +
> +(define (mpd-serialize-list-of-mpd-partition field-name value)
> +=C2=A0 #~(string-append #$@(map (cut mpd-serialize-mpd-partition #f <>)
> value)))
> +
> +(define list-of-mpd-partition?
> +=C2=A0 (list-of mpd-partition?))
> =C2=A0
> =C2=A0(define-configuration mpd-output
> =C2=A0=C2=A0 (name
> =C2=A0=C2=A0=C2=A0 (string "MPD")
> =C2=A0=C2=A0=C2=A0 "The name of the audio output.")
> +
> =C2=A0=C2=A0 (type
> =C2=A0=C2=A0=C2=A0 (string "pulse")
> =C2=A0=C2=A0=C2=A0 "The type of audio output.")
> +
> =C2=A0=C2=A0 (enabled?
> =C2=A0=C2=A0=C2=A0 (boolean #t)
> =C2=A0=C2=A0=C2=A0 "Specifies whether this audio output is enabled when M=
PD is
> started. By
> =C2=A0default, all audio outputs are enabled. This is just the default
> =C2=A0setting when there is no state file; with a state file, the previou=
s
> =C2=A0state is restored.")
> +
> +=C2=A0 (format
> +=C2=A0=C2=A0 maybe-string
> +=C2=A0=C2=A0 "Force a specific audio format on output. See
> +@uref{
> https://mpd.readthedocs.io/en/latest/user.html#audio-output-format,Gl
> obal=C2=A0Audio Format}
> +for a more detailed description.")
> +=C2=A0=C2=A0=20
> =C2=A0=C2=A0 (tags?
> =C2=A0=C2=A0=C2=A0 (boolean #t)
> =C2=A0=C2=A0=C2=A0 "If set to @code{#f}, then MPD will not send tags to t=
his output.
> This
> =C2=A0is only useful for output plugins that can receive tags, for exampl=
e
> the
> =C2=A0@code{httpd} output plugin.")
> +
> =C2=A0=C2=A0 (always-on?
> =C2=A0=C2=A0=C2=A0 (boolean #f)
> =C2=A0=C2=A0=C2=A0 "If set to @code{#t}, then MPD attempts to keep this a=
udio output
> always
> =C2=A0open. This may be useful for streaming servers, when you don=E2=80=
=99t want
> to
> =C2=A0disconnect all listeners even when playback is accidentally
> stopped.")
> +
> =C2=A0=C2=A0 (mixer-type
> =C2=A0=C2=A0=C2=A0 (string "none")
> -=C2=A0=C2=A0 "This field accepts a symbol that specifies which mixer sho=
uld be
> used
> +=C2=A0=C2=A0 "This field accepts a string that specifies which mixer sho=
uld be
> used
> =C2=A0for this audio output: the @code{hardware} mixer, the
> @code{software}
> =C2=A0mixer, the @code{null} mixer (allows setting the volume, but with n=
o
> =C2=A0effect; this can be used as a trick to implement an external mixer
> =C2=A0External Mixer) or no mixer (@code{none}).")
> +
> +=C2=A0 (replay-gain-handler
> +=C2=A0=C2=A0 maybe-string
> +=C2=A0=C2=A0 "This field accepts a string that specifies how
> +@uref{
> https://mpd.readthedocs.io/en/latest/user.html#replay-gain,Replay=C2=A0Ga=
i
> n}
> +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.")
> +
> =C2=A0=C2=A0 (extra-options
> -=C2=A0=C2=A0 (free-form-args '())
> -=C2=A0=C2=A0 "An association list of option symbols to string values to =
be
> appended to
> -the audio output configuration.")
> -=C2=A0 (prefix mpd-subsystem-))
> +=C2=A0=C2=A0 (alist '())
> +=C2=A0=C2=A0 "An association list of option symbols/strings to string va=
lues
> +to be appended to the audio output configuration.")
> =C2=A0
> -(define list-of-mpd-output?
> -=C2=A0 (list-of mpd-output?))
> +=C2=A0 (prefix mpd-))
> +
> +(define (mpd-serialize-mpd-output field-name value)
> +=C2=A0 #~(format #f "audio_output {~%~a}~%"
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #$(se=
rialize-configuration value mpd-output-fields)))
> +
> +(define (mpd-serialize-list-of-mpd-plugin-or-output field-name
> value)
> +=C2=A0 (receive (plugins outputs)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (partition mpd-plugin? value)
> +=C2=A0=C2=A0=C2=A0 #~(string-append #$@(map (cut mpd-serialize-mpd-plugi=
n
> "audio_output" <>)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 plugins)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #$@(map (cut mpd-serialize=
-mpd-output #f <>)
> outputs))))
> +
> +(define list-of-mpd-plugin-or-output?
> +=C2=A0 (list-of (lambda (x)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
 (or (mpd-output? x) (mpd-plugin? x)))))
> =C2=A0
> =C2=A0(define-configuration mpd-configuration
> +=C2=A0 (package
> +=C2=A0=C2=A0 (file-like mpd)
> +=C2=A0=C2=A0 "The MPD package."
> +=C2=A0=C2=A0 empty-serializer)
> +
> =C2=A0=C2=A0 (user
> =C2=A0=C2=A0=C2=A0 (string "mpd")
> =C2=A0=C2=A0=C2=A0 "The user to run mpd as.")
> -=C2=A0 (music-dir
> -=C2=A0=C2=A0 (string "~/Music")
> +
> +=C2=A0 (group
> +=C2=A0=C2=A0 maybe-string
> +=C2=A0=C2=A0 "The group to run mpd as.")
> +
> +=C2=A0 (shepherd-requirement
> +=C2=A0=C2=A0 (list-of-symbol '())
> +=C2=A0=C2=A0 "This is a list of symbols naming Shepherd services that th=
is
> service
> +will depend on."
> +=C2=A0=C2=A0 empty-serializer)
> +
> +=C2=A0 (log-file
> +=C2=A0=C2=A0 (maybe-string "/var/log/mpd/log")
> +=C2=A0=C2=A0 "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.")
> +
> +=C2=A0 (log-level
> +=C2=A0=C2=A0 maybe-string
> +=C2=A0=C2=A0 "Supress any messages below this threshold.
> +Available values: @code{notice}, @code{info}, @code{verbose},
> +@code{warning} and @code{error}.")
> +
> +=C2=A0 (music-directory
> +=C2=A0=C2=A0 maybe-string
> +=C2=A0=C2=A0 "The directory to scan for music files.")
> +
> +=C2=A0 (music-dir ; TODO: deprecated, remove later
> +=C2=A0=C2=A0 maybe-string
> =C2=A0=C2=A0=C2=A0 "The directory to scan for music files."
> -=C2=A0=C2=A0 (lambda (_ x)
> -=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-field "music_directory" x)))
> -=C2=A0 (playlist-dir
> -=C2=A0=C2=A0 (string "~/.mpd/playlists")
> +=C2=A0=C2=A0 mpd-serialize-deprecated-field)
> +
> +=C2=A0 (playlist-directory
> +=C2=A0=C2=A0 maybe-string
> +=C2=A0=C2=A0 "The directory to store playlists.")
> +
> +=C2=A0 (playlist-dir ; TODO: deprecated, remove later
> +=C2=A0=C2=A0 maybe-string
> =C2=A0=C2=A0=C2=A0 "The directory to store playlists."
> -=C2=A0=C2=A0 (lambda (_ x)
> -=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-field "playlist_directory" x)))
> +=C2=A0=C2=A0 mpd-serialize-deprecated-field)
> +
> =C2=A0=C2=A0 (db-file
> -=C2=A0=C2=A0 (string "~/.mpd/tag_cache")
> +=C2=A0=C2=A0 maybe-string
> =C2=A0=C2=A0=C2=A0 "The location of the music database.")
> +
> =C2=A0=C2=A0 (state-file
> -=C2=A0=C2=A0 (string "~/.mpd/state")
> +=C2=A0=C2=A0 maybe-string
> =C2=A0=C2=A0=C2=A0 "The location of the file that stores current MPD's st=
ate.")
> +
> =C2=A0=C2=A0 (sticker-file
> -=C2=A0=C2=A0 (string "~/.mpd/sticker.sql")
> +=C2=A0=C2=A0 maybe-string
> =C2=A0=C2=A0=C2=A0 "The location of the sticker database.")
> -=C2=A0 (port
> -=C2=A0=C2=A0 (string "6600")
> -=C2=A0=C2=A0 "The port to run mpd on.")
> -=C2=A0 (address
> -=C2=A0=C2=A0 (string "any")
> +
> +=C2=A0 (default-port
> +=C2=A0=C2=A0 (maybe-port 6600) ; TODO: switch to integer
> +=C2=A0=C2=A0 "The default port to run mpd on.")
> +
> +=C2=A0 (endpoints
> +=C2=A0=C2=A0 maybe-list-of-string
> +=C2=A0=C2=A0 "The addresses that mpd will bind to. A different port may =
be
> +specified, e.g. @code{localhost:6602}. IPv6 addresses must be
> +enclosed in square brackets if a different port is used.
> +To use a Unix domain socket, an absolute path or a path starting
> with @code{~}
> +can be specified here."
> +=C2=A0=C2=A0 (lambda (_ x)
> +=C2=A0=C2=A0=C2=A0=C2=A0 (if (maybe-value-set? x)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #~(string-append #$@(ma=
p
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0 (cut mpd-serialize-field
> "bind_to_address" <>)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0 x)) "")))
> +
> +=C2=A0 (address ; TODO: deprecated, remove later
> +=C2=A0=C2=A0 maybe-string
> =C2=A0=C2=A0=C2=A0 "The address that mpd will bind to.
> =C2=A0To use a Unix domain socket, an absolute path can be specified
> here."
> +=C2=A0=C2=A0 mpd-serialize-deprecated-field)
> +
> +=C2=A0 (database
> +=C2=A0=C2=A0 maybe-mpd-plugin
> +=C2=A0=C2=A0 "MPD database plugin configuration.")
> +
> +=C2=A0 (partitions
> +=C2=A0=C2=A0 (list-of-mpd-partition '())
> +=C2=A0=C2=A0 "List of MPD \"partitions\".")
> +=C2=A0=20
> +=C2=A0 (neighbors
> +=C2=A0=C2=A0 (list-of-mpd-plugin '())
> +=C2=A0=C2=A0 "List of MPD neighbor plugin configurations.")
> +
> +=C2=A0 (inputs
> +=C2=A0=C2=A0 (list-of-mpd-plugin '())
> +=C2=A0=C2=A0 "List of MPD input plugin configurations."
> +=C2=A0=C2=A0 (lambda (_ x)
> +=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-list-of-mpd-plugin "input" x)))
> +
> +=C2=A0 (archive-plugins
> +=C2=A0=C2=A0 (list-of-mpd-plugin '())
> +=C2=A0=C2=A0 "List of MPD archive plugin configurations."
> =C2=A0=C2=A0=C2=A0 (lambda (_ x)
> -=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-field "bind_to_address" x)))
> +=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-list-of-mpd-plugin "archive_plug=
in" x)))
> +
> +=C2=A0 (input-cache-size
> +=C2=A0=C2=A0 maybe-string
> +=C2=A0=C2=A0 "MPD input cache size."
> +=C2=A0=C2=A0 (lambda (_ x)
> +=C2=A0=C2=A0=C2=A0=C2=A0 (if (maybe-value-set? x)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #~(string-append "\ninp=
ut_cache {\n"
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0 #$(mpd-serialize-string "size" x)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0 "}\n") "")))
> +
> +=C2=A0 (decoders
> +=C2=A0=C2=A0 (list-of-mpd-plugin '())
> +=C2=A0=C2=A0 "List of MPD decoder plugin configurations."
> +=C2=A0=C2=A0 (lambda (_ x)
> +=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-list-of-mpd-plugin "decoder" x))=
)
> +
> +=C2=A0 (resampler
> +=C2=A0=C2=A0 maybe-mpd-plugin
> +=C2=A0=C2=A0 "MPD resampler plugin configuration.")
> +
> +=C2=A0 (filters
> +=C2=A0=C2=A0 (list-of-mpd-plugin '())
> +=C2=A0=C2=A0 "List of MPD filter plugin configurations."
> +=C2=A0=C2=A0 (lambda (_ x)
> +=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-list-of-mpd-plugin "filter" x)))
> +
> =C2=A0=C2=A0 (outputs
> -=C2=A0=C2=A0 (list-of-mpd-output (list (mpd-output)))
> +=C2=A0=C2=A0 (list-of-mpd-plugin-or-output (list (mpd-output)))
> =C2=A0=C2=A0=C2=A0 "The audio outputs that MPD can use.
> =C2=A0By default this is a single output using pulseaudio.")
> +
> +=C2=A0 (playlist-plugins
> +=C2=A0=C2=A0 (list-of-mpd-plugin '())
> +=C2=A0=C2=A0 "List of MPD playlist plugin configurations."
> +=C2=A0=C2=A0 (lambda (_ x)
> +=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-serialize-list-of-mpd-plugin "playlist_plu=
gin" x)))
> +
> +=C2=A0 (extra-options
> +=C2=A0=C2=A0 (alist '())
> +=C2=A0=C2=A0 "An association list of option symbols/strings to string va=
lues
> to be
> +appended to the configuration.")
> +
> =C2=A0=C2=A0 (prefix mpd-))
> =C2=A0
> -(define (mpd-file-name config file)
> -=C2=A0 "Return a path in /var/run/mpd/ that is writable
> -=C2=A0=C2=A0 by @code{user} from @code{config}."
> -=C2=A0 (string-append "/var/run/mpd/"
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0 (mpd-configuration-user config)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0 "/" file))
> +(define (mpd-serialize-configuration configuration)
> +=C2=A0 (mixed-text-file
> +=C2=A0=C2=A0 "mpd.conf"
> +=C2=A0=C2=A0 (serialize-configuration configuration mpd-configuration-
> fields)))
> +
> +(define (mpd-log-rotation config)
> +=C2=A0 (match-record config <mpd-configuration> (log-file)
> +=C2=A0=C2=A0=C2=A0 (log-rotation
> +=C2=A0=C2=A0=C2=A0=C2=A0 (files (list log-file))
> +=C2=A0=C2=A0=C2=A0=C2=A0 (post-rotate #~(begin
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (use-modules (gnu se=
rvices herd))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (with-shepherd-actio=
n 'mpd ('reopen) #f))))))
> =C2=A0
> =C2=A0(define (mpd-shepherd-service config)
> -=C2=A0 (shepherd-service
> -=C2=A0=C2=A0 (documentation "Run the MPD (Music Player Daemon)")
> -=C2=A0=C2=A0 (requirement '(user-processes))
> -=C2=A0=C2=A0 (provision '(mpd))
> -=C2=A0=C2=A0 (start #~(make-forkexec-constructor
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
 (list #$(file-append mpd "/bin/mpd")
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "--no-daemon"
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #$(mpd-serialize-configuration config)=
)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
 #:environment-variables
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
 ;; Required to detect PulseAudio when run under a user
> account.
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
 (list (string-append
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "XDG_RUNTIME_DIR=3D/run/user/"
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (number->string
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (passwd:uid
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (getpwnam #$(mpd-con=
figuration-user
> config))))))
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
 #:log-file #$(mpd-file-name config "log")))
> -=C2=A0=C2=A0 (stop=C2=A0 #~(make-kill-destructor))))
> +=C2=A0 (match-record config <mpd-configuration> (user package shepherd-
> requirement)
> +=C2=A0=C2=A0=C2=A0 (let* ((config-file (mpd-serialize-configuration conf=
ig)))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (shepherd-service
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (documentation "Run the MPD (Music =
Player Daemon)")
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (requirement `(user-processes loopb=
ack ,@shepherd-
> requirement))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (provision '(mpd))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (start #~(make-forkexec-constructor
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0 (list #$(file-append package "/bin/mpd")
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "--no-daemon"
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 #$config-file)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0 #:environment-variables
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0 ;; Required to detect PulseAudio when run under a
> user account.
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0 (list (string-append
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "XDG_RUN=
TIME_DIR=3D/run/user/"
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (number-=
>string (passwd:uid (getpwnam
> #$user)))))))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (stop=C2=A0 #~(make-kill-destructor=
))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (actions
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (list (shepherd-configuration=
-action config-file)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0 (shepherd-action
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0 (name 'reopen)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0 (documentation "Re-open log files and flush caches.")
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0 (procedure
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0 #~(lambda (pid)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (if pid
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (begin
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0 (kill pid SIGHUP)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0 (format #t
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "Issued SIGHUP to Servi=
ce MPD (PID
> ~a)."
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 pid))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (format =
#t "Service MPD is not
> running.")))))))))))
> =C2=A0
> =C2=A0(define (mpd-service-activation config)
> -=C2=A0 (with-imported-modules '((guix build utils))
> +=C2=A0 (match-record config <mpd-configuration> (user log-file)
> =C2=A0=C2=A0=C2=A0=C2=A0 #~(begin
> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (use-modules (guix build=
 utils))
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (define %user
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (getpw #$(mpd-con=
figuration-user config)))
> -
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (let ((directory #$(mpd-file-=
name config ".mpd")))
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (mkdir-p director=
y)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (chown directory =
(passwd:uid %user) (passwd:gid %user))
> -
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ;; Make /var/run/=
mpd/USER user-owned as well.
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (chown (dirname d=
irectory)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0 (passwd:uid %user) (passwd:gid %user))))))
> -
> -
> -(define %mpd-accounts
> -=C2=A0 ;; Default account and group for MPD.
> -=C2=A0 (list (user-group (name "mpd") (system? #t))
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (user-account
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (name "mpd")
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (group "mpd")
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (system? #t)
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (comment "Music Player =
Daemon (MPD) user")
> =C2=A0
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ;; Note: /var/run/mpd h=
osts one sub-directory per user, of
> which
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ;; /var/run/mpd/mpd cor=
responds to the "mpd" user.
> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (home-directory "/var/r=
un/mpd/mpd")
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ;; TODO: remove me, migrates =
from the old location at
> /var/run/mpd
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ;;=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0 to the new one at /var/lib/mpd.
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (let* ((user (getpw #$user))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0 (deprecated-directory (string-append "/var/run/mpd/"
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0 #$user "/.mpd"))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0 (new-directory (string-append (passwd:dir user)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "/.config/mpd")))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (when (and (file-=
exists? deprecated-directory)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (not (file-exists? new-dir=
ectory)))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (rena=
me-file deprecated-directory new-directory)
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (chow=
n new-directory (passwd:uid user) (passwd:gid
> user))))
> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (mkdir-p (dirname #$log-file)=
))))
I'm not sure whether we should migrate the logs here.  I do think the
logs should be stored in /var/log rather than /var/run, but other than
that I'm not even sure there's much value in changing the /var/run/mpd
structure.  What's your use case for doing so?


Cheers




Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 24 Dec 2022 14:24:26 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Dec 24 09:24:26 2022
Received: from localhost ([127.0.0.1]:43233 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p95Ro-0004TP-PX
	for submit <at> debbugs.gnu.org; Sat, 24 Dec 2022 09:24:26 -0500
Received: from smtpm1.myservices.hosting ([185.26.105.232]:44804)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mirai@HIDDEN>) id 1p95Rm-0004TD-3e
 for 59866 <at> debbugs.gnu.org; Sat, 24 Dec 2022 09:24:24 -0500
Received: from mail1.netim.hosting (unknown [185.26.106.172])
 by smtpm1.myservices.hosting (Postfix) with ESMTP id 5F3A420334
 for <59866 <at> debbugs.gnu.org>; Sat, 24 Dec 2022 15:24:19 +0100 (CET)
Received: from localhost (localhost [127.0.0.1])
 by mail1.netim.hosting (Postfix) with ESMTP id B95FA80096;
 Sat, 24 Dec 2022 15:24:18 +0100 (CET)
X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting
Received: from mail1.netim.hosting ([127.0.0.1])
 by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id xnv4DjSWzaTg; Sat, 24 Dec 2022 15:24:06 +0100 (CET)
Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156])
 (Authenticated sender: lumen@HIDDEN)
 by mail1.netim.hosting (Postfix) with ESMTPSA id 21EDB80093;
 Sat, 24 Dec 2022 15:24:06 +0100 (CET)
From: mirai@HIDDEN
To: 59866 <at> debbugs.gnu.org
Subject: [PATCH v5.1] services: mpd: Refactor MPD service.
Date: Sat, 24 Dec 2022 14:11:01 +0000
Message-Id: <099d959851cb9ce9bf4afdedd01825b7ccf78a73.1671891059.git.mirai@HIDDEN>
X-Mailer: git-send-email 2.38.1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 59866
Cc: Bruno Victal <mirai@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

From: Bruno Victal <mirai@HIDDEN>

Introduces 'mpd-plugin' and 'mpd-partition' records.
Expands 'mpd-output' and 'mpd-configuration' records.
Deprecates redundant abbreviated fields in 'mpd-configuration' and avoids
serializing unused fields that may introduce undesired behavior.
Replace free-form-args serialization by making 'mpd-serialize-field' handle
multiple types and using it with 'generic-serialize-alist'.
Reduce code weight by removing cosmetic indented serialization procedures.
Offload logging from shepherd to MPD.
Implement log-rotation via rottlog.
Implement Shepherd actions: 'reopen' and 'configuration'.

* gnu/services/audio.scm
(mpd-plugin, mpd-partition): New record.

(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 predicate.

(mpd-serialize-field): Handle multiple types.

(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 field.
[music-dir, playlist-dir, address]: Deprecate shorthand field.
[db-file, state-file, sticker-file, port, outputs]: Change admissible type.

(mpd-log-rotation): New procedure.

(mpd-shepherd-service)
[actions]: New shepherd actions: 'reopen' and 'configuration'.
[requirement]: Splice with 'shepherd-requirement' field.
[start]: Use 'package' field. Remove #:log-file parameter.

(mpd-service-activation): Create logging directory. Handle migration
from old-style configuration.

(mpd-accounts): Do not hardcode username, change primary group to
"nogroup".

(mpd-service-type): Extend rottlog-service-type for log-rotation.
Update activation-service-type extension to reflect mpd-accounts
procedure change.

* doc/guix.texi (Audio Services)[Music Player Daemon]: Update doc.
---

 Changes since v5:
 * Serialize default_port field-name as "port".

 doc/guix.texi          | 177 +++++++++++++---
 gnu/services/audio.scm | 463 +++++++++++++++++++++++++++++++----------
 2 files changed, 506 insertions(+), 134 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index e25692fd27..5663d1913a 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@*
 
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -33014,79 +33015,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} (type: maybe-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 different port may be
+specified, e.g. @code{localhost:6602}.  IPv6 addresses must be
+enclosed in square brackets if 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
@@ -33098,7 +33207,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 1a1026f342..e456205e99 100644
--- a/gnu/services/audio.scm
+++ b/gnu/services/audio.scm
@@ -21,19 +21,27 @@
 
 (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)
   #:use-module (guix records)
   #:use-module (ice-9 match)
-  #:use-module (ice-9 format)
   #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-8)
   #:use-module (srfi srfi-26)
   #:export (mpd-output
             mpd-output?
+            mpd-plugin
+            mpd-plugin?
+            mpd-partition
+            mpd-partition?
             mpd-configuration
             mpd-configuration?
             mpd-service-type))
@@ -52,180 +60,421 @@ (define (uglify-field-name field-name)
                                #\-)
                  "_")))
 
-(define (free-form-args? val)
-  (match val
-    (() #t)
-    ((((? symbol?) . (? string?)) . val) (free-form-args? val))
-    (_ #f)))
+(define list-of-string?
+  (list-of string?))
 
-(define* (mpd-serialize-field field-name value #:optional (indent-level 0))
-  #~(begin
-      (use-modules ((ice-9 format)))
-      (format #f "~v/~a \"~a\"~%" #$indent-level #$(if (string? field-name)
-                                                       field-name
-                                                       (uglify-field-name field-name)) #$value)))
+(define list-of-symbol?
+  (list-of symbol?))
 
-(define* (mpd-serialize-free-form-args field-name value #:optional (indent-level 0))
-  (generic-serialize-alist string-append (cut mpd-serialize-field <> <> indent-level) value))
+(define (mpd-serialize-field field-name value)
+  (let ((field (if (string? field-name) field-name
+                   (uglify-field-name field-name)))
+        (value (if (boolean? value) (if value "yes" "no") value)))
+    #~(format #f "~a \"~a\"~%" #$field #$value)))
 
 (define mpd-serialize-number mpd-serialize-field)
 
 (define mpd-serialize-string mpd-serialize-field)
 
-(define* (mpd-serialize-boolean field-name value #:optional (indent-level 0))
-  (mpd-serialize-field field-name (if value "yes" "no") indent-level))
+(define mpd-serialize-boolean mpd-serialize-field)
 
-(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-alist field-name value)
+  #~(string-append #$@(generic-serialize-alist list
+                                               mpd-serialize-field
+                                               value)))
 
-(define (mpd-serialize-configuration configuration)
-  (mixed-text-file
-   "mpd.conf"
-   (serialize-configuration configuration mpd-configuration-fields)))
+(define-maybe string (prefix mpd-))
+(define-maybe list-of-string (prefix mpd-))
+(define-maybe boolean (prefix mpd-))
+
+;;; 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 mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> 1))
-(define mpd-subsystem-serialize-string (cut mpd-serialize-string <> <> 1))
-(define mpd-subsystem-serialize-number (cut mpd-serialize-number <> <> 1))
-(define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean <> <> 1))
-(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize-free-form-args <> <> 1))
+(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
    (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.")
+
+  (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
 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
+   "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
-   (free-form-args '())
-   "An association list of option symbols to string values to be appended to
-the audio output configuration.")
-  (prefix mpd-subsystem-))
+   (alist '())
+   "An association list of option symbols/strings to string values
+to be appended to the audio output configuration.")
 
-(define list-of-mpd-output?
-  (list-of mpd-output?))
+  (prefix mpd-))
+
+(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)
+  (receive (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
+   maybe-string
+   "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)))
-  (playlist-dir
-   (string "~/.mpd/playlists")
+   mpd-serialize-deprecated-field)
+
+  (playlist-directory
+   maybe-string
+   "The directory to store 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) ; TODO: switch to integer
+   "The default port to run mpd on.")
+
+  (endpoints
+   maybe-list-of-string
+   "The addresses that mpd will bind to. A different port may be
+specified, e.g. @code{localhost:6602}. IPv6 addresses must be
+enclosed in square brackets if 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 (_ x)
+     (if (maybe-value-set? x)
+         #~(string-append #$@(map
+                              (cut mpd-serialize-field "bind_to_address" <>)
+                              x)) "")))
+
+  (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-list-of-mpd-plugin "input" x)))
+
+  (archive-plugins
+   (list-of-mpd-plugin '())
+   "List of MPD archive plugin configurations."
    (lambda (_ x)
-     (mpd-serialize-field "bind_to_address" 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 <mpd-configuration> (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))))
+  (match-record config <mpd-configuration> (user package shepherd-requirement)
+    (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 #~(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-service-activation config)
-  (with-imported-modules '((guix build utils))
+  (match-record config <mpd-configuration> (user log-file)
     #~(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")
+        ;; TODO: remove me, migrates from the old location at /var/run/mpd
+        ;;       to the new one at /var/lib/mpd.
+        (let* ((user (getpw #$user))
+               (deprecated-directory (string-append "/var/run/mpd/"
+                                                    #$user "/.mpd"))
+               (new-directory (string-append (passwd:dir user)
+                                             "/.config/mpd")))
+          (when (and (file-exists? deprecated-directory)
+                     (not (file-exists? new-directory)))
+            (rename-file deprecated-directory new-directory)
+            (chown new-directory (passwd:uid user) (passwd:gid user))))
+        (mkdir-p (dirname #$log-file)))))
 
-         (shell (file-append shadow "/sbin/nologin")))))
+(define (mpd-accounts config)
+  (match-record config <mpd-configuration> (user)
+    (list (user-account
+           (name user)
+           (group "nogroup")
+           (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
@@ -235,7 +484,9 @@ (define mpd-service-type
     (list (service-extension shepherd-root-service-type
                              (compose list mpd-shepherd-service))
           (service-extension account-service-type
-                             (const %mpd-accounts))
+                             mpd-accounts)
           (service-extension activation-service-type
-                             mpd-service-activation)))
+                             mpd-service-activation)
+          (service-extension rottlog-service-type
+                             (compose list mpd-log-rotation))))
    (default-value (mpd-configuration))))

base-commit: aae8371f72805cc35e31817e4120468eee4a4a80
prerequisite-patch-id: e47455c06e8e73edcc3f36ccd7b6b289cdfa1e16
-- 
2.38.1





Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 24 Dec 2022 13:59:14 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Dec 24 08:59:13 2022
Received: from localhost ([127.0.0.1]:43128 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p953Q-0001ld-76
	for submit <at> debbugs.gnu.org; Sat, 24 Dec 2022 08:59:13 -0500
Received: from smtpm5.myservices.hosting ([185.26.105.236]:53366)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mirai@HIDDEN>) id 1p953N-0001lU-4S
 for 59866 <at> debbugs.gnu.org; Sat, 24 Dec 2022 08:59:10 -0500
Received: from mail1.netim.hosting (unknown [185.26.106.172])
 by smtpm5.myservices.hosting (Postfix) with ESMTP id A886820C62
 for <59866 <at> debbugs.gnu.org>; Sat, 24 Dec 2022 14:59:08 +0100 (CET)
Received: from localhost (localhost [127.0.0.1])
 by mail1.netim.hosting (Postfix) with ESMTP id 4AC508009E;
 Sat, 24 Dec 2022 14:59:08 +0100 (CET)
X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting
Received: from mail1.netim.hosting ([127.0.0.1])
 by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id EOAl1alI_5_a; Sat, 24 Dec 2022 14:59:07 +0100 (CET)
Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156])
 (Authenticated sender: lumen@HIDDEN)
 by mail1.netim.hosting (Postfix) with ESMTPSA id 250178009D;
 Sat, 24 Dec 2022 14:59:07 +0100 (CET)
From: mirai@HIDDEN
To: 59866 <at> debbugs.gnu.org
Subject: [PATCH v5 2/2] services: mpd: Refactor MPD service.
Date: Sat, 24 Dec 2022 13:51:33 +0000
Message-Id: <fb7508dea3fb39f4d5fa572e37f18b8e1b3e442b.1671889887.git.mirai@HIDDEN>
X-Mailer: git-send-email 2.38.1
In-Reply-To: <8448291fc734b10d0dc9ce50d6a5131d477b537f.1671889887.git.mirai@HIDDEN>
References: <8448291fc734b10d0dc9ce50d6a5131d477b537f.1671889887.git.mirai@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 59866
Cc: Bruno Victal <mirai@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

From: Bruno Victal <mirai@HIDDEN>

Introduces 'mpd-plugin' and 'mpd-partition' records.
Expands 'mpd-output' and 'mpd-configuration' records.
Deprecates redundant abbreviated fields in 'mpd-configuration' and avoids
serializing unused fields that may introduce undesired behavior.
Replace free-form-args serialization by making 'mpd-serialize-field' handle
multiple types and using it with 'generic-serialize-alist'.
Reduce code weight by removing cosmetic indented serialization procedures.
Offload logging from shepherd to MPD.
Implement log-rotation via rottlog.
Implement Shepherd actions: 'reopen' and 'configuration'.

* gnu/services/audio.scm
(mpd-plugin, mpd-partition): New record.

(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 predicate.

(mpd-serialize-field): Handle multiple types.

(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 field.
[music-dir, playlist-dir, address]: Deprecate shorthand field.
[db-file, state-file, sticker-file, port, outputs]: Change admissible type.

(mpd-log-rotation): New procedure.

(mpd-shepherd-service)
[actions]: New shepherd actions: 'reopen' and 'configuration'.
[requirement]: Splice with 'shepherd-requirement' field.
[start]: Use 'package' field. Remove #:log-file parameter.

(mpd-service-activation): Create logging directory. Handle migration
from old-style configuration.

(mpd-accounts): Do not hardcode username, change primary group to
"nogroup".

(mpd-service-type): Extend rottlog-service-type for log-rotation.
Update activation-service-type extension to reflect mpd-accounts
procedure change.

* doc/guix.texi (Audio Services)[Music Player Daemon]: Update doc.
---

 Changes since v4:
 * Retitled commit message and added ChangeLog formatted entries.
 * Split long lines into shorter ones.
 * Fix leftover mentions of "addresses".
 * Document that endpoint addresses may contain ports in them.

 doc/guix.texi          | 177 +++++++++++++---
 gnu/services/audio.scm | 463 +++++++++++++++++++++++++++++++----------
 2 files changed, 506 insertions(+), 134 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index e25692fd27..5663d1913a 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@*
 
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -33014,79 +33015,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} (type: maybe-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 different port may be
+specified, e.g. @code{localhost:6602}.  IPv6 addresses must be
+enclosed in square brackets if 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
@@ -33098,7 +33207,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 1a1026f342..54b00157b0 100644
--- a/gnu/services/audio.scm
+++ b/gnu/services/audio.scm
@@ -21,19 +21,27 @@
 
 (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)
   #:use-module (guix records)
   #:use-module (ice-9 match)
-  #:use-module (ice-9 format)
   #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-8)
   #:use-module (srfi srfi-26)
   #:export (mpd-output
             mpd-output?
+            mpd-plugin
+            mpd-plugin?
+            mpd-partition
+            mpd-partition?
             mpd-configuration
             mpd-configuration?
             mpd-service-type))
@@ -52,180 +60,421 @@ (define (uglify-field-name field-name)
                                #\-)
                  "_")))
 
-(define (free-form-args? val)
-  (match val
-    (() #t)
-    ((((? symbol?) . (? string?)) . val) (free-form-args? val))
-    (_ #f)))
+(define list-of-string?
+  (list-of string?))
 
-(define* (mpd-serialize-field field-name value #:optional (indent-level 0))
-  #~(begin
-      (use-modules ((ice-9 format)))
-      (format #f "~v/~a \"~a\"~%" #$indent-level #$(if (string? field-name)
-                                                       field-name
-                                                       (uglify-field-name field-name)) #$value)))
+(define list-of-symbol?
+  (list-of symbol?))
 
-(define* (mpd-serialize-free-form-args field-name value #:optional (indent-level 0))
-  (generic-serialize-alist string-append (cut mpd-serialize-field <> <> indent-level) value))
+(define (mpd-serialize-field field-name value)
+  (let ((field (if (string? field-name) field-name
+                   (uglify-field-name field-name)))
+        (value (if (boolean? value) (if value "yes" "no") value)))
+    #~(format #f "~a \"~a\"~%" #$field #$value)))
 
 (define mpd-serialize-number mpd-serialize-field)
 
 (define mpd-serialize-string mpd-serialize-field)
 
-(define* (mpd-serialize-boolean field-name value #:optional (indent-level 0))
-  (mpd-serialize-field field-name (if value "yes" "no") indent-level))
+(define mpd-serialize-boolean mpd-serialize-field)
 
-(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-alist field-name value)
+  #~(string-append #$@(generic-serialize-alist list
+                                               mpd-serialize-field
+                                               value)))
 
-(define (mpd-serialize-configuration configuration)
-  (mixed-text-file
-   "mpd.conf"
-   (serialize-configuration configuration mpd-configuration-fields)))
+(define-maybe string (prefix mpd-))
+(define-maybe list-of-string (prefix mpd-))
+(define-maybe boolean (prefix mpd-))
+
+;;; 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 field-name 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 mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> 1))
-(define mpd-subsystem-serialize-string (cut mpd-serialize-string <> <> 1))
-(define mpd-subsystem-serialize-number (cut mpd-serialize-number <> <> 1))
-(define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean <> <> 1))
-(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize-free-form-args <> <> 1))
+(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
    (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.")
+
+  (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
 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
+   "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
-   (free-form-args '())
-   "An association list of option symbols to string values to be appended to
-the audio output configuration.")
-  (prefix mpd-subsystem-))
+   (alist '())
+   "An association list of option symbols/strings to string values
+to be appended to the audio output configuration.")
 
-(define list-of-mpd-output?
-  (list-of mpd-output?))
+  (prefix mpd-))
+
+(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)
+  (receive (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
+   maybe-string
+   "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)))
-  (playlist-dir
-   (string "~/.mpd/playlists")
+   mpd-serialize-deprecated-field)
+
+  (playlist-directory
+   maybe-string
+   "The directory to store 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) ; TODO: switch to integer
+   "The default port to run mpd on.")
+
+  (endpoints
+   maybe-list-of-string
+   "The addresses that mpd will bind to. A different port may be
+specified, e.g. @code{localhost:6602}. IPv6 addresses must be
+enclosed in square brackets if 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 (_ x)
+     (if (maybe-value-set? x)
+         #~(string-append #$@(map
+                              (cut mpd-serialize-field "bind_to_address" <>)
+                              x)) "")))
+
+  (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-list-of-mpd-plugin "input" x)))
+
+  (archive-plugins
+   (list-of-mpd-plugin '())
+   "List of MPD archive plugin configurations."
    (lambda (_ x)
-     (mpd-serialize-field "bind_to_address" 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 <mpd-configuration> (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))))
+  (match-record config <mpd-configuration> (user package shepherd-requirement)
+    (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 #~(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-service-activation config)
-  (with-imported-modules '((guix build utils))
+  (match-record config <mpd-configuration> (user log-file)
     #~(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")
+        ;; TODO: remove me, migrates from the old location at /var/run/mpd
+        ;;       to the new one at /var/lib/mpd.
+        (let* ((user (getpw #$user))
+               (deprecated-directory (string-append "/var/run/mpd/"
+                                                    #$user "/.mpd"))
+               (new-directory (string-append (passwd:dir user)
+                                             "/.config/mpd")))
+          (when (and (file-exists? deprecated-directory)
+                     (not (file-exists? new-directory)))
+            (rename-file deprecated-directory new-directory)
+            (chown new-directory (passwd:uid user) (passwd:gid user))))
+        (mkdir-p (dirname #$log-file)))))
 
-         (shell (file-append shadow "/sbin/nologin")))))
+(define (mpd-accounts config)
+  (match-record config <mpd-configuration> (user)
+    (list (user-account
+           (name user)
+           (group "nogroup")
+           (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
@@ -235,7 +484,9 @@ (define mpd-service-type
     (list (service-extension shepherd-root-service-type
                              (compose list mpd-shepherd-service))
           (service-extension account-service-type
-                             (const %mpd-accounts))
+                             mpd-accounts)
           (service-extension activation-service-type
-                             mpd-service-activation)))
+                             mpd-service-activation)
+          (service-extension rottlog-service-type
+                             (compose list mpd-log-rotation))))
    (default-value (mpd-configuration))))
-- 
2.38.1





Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 24 Dec 2022 13:55:19 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Dec 24 08:55:18 2022
Received: from localhost ([127.0.0.1]:43110 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p94ze-0001hz-2T
	for submit <at> debbugs.gnu.org; Sat, 24 Dec 2022 08:55:18 -0500
Received: from smtpm5.myservices.hosting ([185.26.105.236]:52658)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mirai@HIDDEN>) id 1p94zc-0001hq-Dr
 for 59866 <at> debbugs.gnu.org; Sat, 24 Dec 2022 08:55:17 -0500
Received: from mail1.netim.hosting (unknown [185.26.106.172])
 by smtpm5.myservices.hosting (Postfix) with ESMTP id 27ACB20C62
 for <59866 <at> debbugs.gnu.org>; Sat, 24 Dec 2022 14:55:14 +0100 (CET)
Received: from localhost (localhost [127.0.0.1])
 by mail1.netim.hosting (Postfix) with ESMTP id 4BCA08009F;
 Sat, 24 Dec 2022 14:55:14 +0100 (CET)
X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting
Received: from mail1.netim.hosting ([127.0.0.1])
 by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id PsQ3Rg-zBAAs; Sat, 24 Dec 2022 14:55:13 +0100 (CET)
Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156])
 (Authenticated sender: lumen@HIDDEN)
 by mail1.netim.hosting (Postfix) with ESMTPSA id B2A448009D;
 Sat, 24 Dec 2022 14:55:12 +0100 (CET)
From: mirai@HIDDEN
To: 59866 <at> debbugs.gnu.org
Subject: [PATCH v5 1/2] services: mpd: rewrite using 'define-configuration'.
Date: Sat, 24 Dec 2022 13:51:31 +0000
Message-Id: <8448291fc734b10d0dc9ce50d6a5131d477b537f.1671889887.git.mirai@HIDDEN>
X-Mailer: git-send-email 2.38.1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 59866
Cc: Bruno Victal <mirai@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

From: Bruno Victal <mirai@HIDDEN>

* gnu/services/audio.scm
(mpd-configuration, mpd-output): Rewrite using define-configuration.
(uglify-field-name): New procedure.
(free-form-args?, list-of-mpd-output?): New predicate.
---

 Changes since v4:
 * Copyright line moved to patch 1/2.
 * Retitled commit message and added ChangeLog formatted entries.

 gnu/services/audio.scm | 218 ++++++++++++++++++++++++-----------------
 1 file changed, 130 insertions(+), 88 deletions(-)

diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm
index c60053f33c..1a1026f342 100644
--- a/gnu/services/audio.scm
+++ b/gnu/services/audio.scm
@@ -2,6 +2,7 @@
 ;;; Copyright © 2017 Peter Mikkelsen <petermikkelsen10@HIDDEN>
 ;;; Copyright © 2019 Ricardo Wurmus <rekado@HIDDEN>
 ;;; Copyright © 2020 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2022 Bruno Victal <mirai@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -21,6 +22,7 @@
 (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)
@@ -28,6 +30,8 @@ (define-module (gnu services audio)
   #: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 +44,131 @@ (define-module (gnu services audio)
 ;;;
 ;;; Code:
 
-(define-record-type* <mpd-output>
-  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>
-  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 <mpd-output> 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 (free-form-args? val)
+  (match val
+    (() #t)
+    ((((? symbol?) . (? string?)) . val) (free-form-args? val))
+    (_ #f)))
+
+(define* (mpd-serialize-field field-name value #:optional (indent-level 0))
+  #~(begin
+      (use-modules ((ice-9 format)))
+      (format #f "~v/~a \"~a\"~%" #$indent-level #$(if (string? field-name)
+                                                       field-name
+                                                       (uglify-field-name field-name)) #$value)))
+
+(define* (mpd-serialize-free-form-args field-name value #:optional (indent-level 0))
+  (generic-serialize-alist string-append (cut mpd-serialize-field <> <> indent-level) value))
+
+(define mpd-serialize-number mpd-serialize-field)
+
+(define mpd-serialize-string mpd-serialize-field)
+
+(define* (mpd-serialize-boolean field-name value #:optional (indent-level 0))
+  (mpd-serialize-field field-name (if value "yes" "no") indent-level))
+
+(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 mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> 1))
+(define mpd-subsystem-serialize-string (cut mpd-serialize-string <> <> 1))
+(define mpd-subsystem-serialize-number (cut mpd-serialize-number <> <> 1))
+(define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean <> <> 1))
+(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize-free-form-args <> <> 1))
+
+(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
+   (free-form-args '())
+   "An association list of option symbols to string values to be appended to
+the audio output configuration.")
+  (prefix mpd-subsystem-))
+
+(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 +185,7 @@ (define (mpd-shepherd-service config)
    (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

base-commit: aae8371f72805cc35e31817e4120468eee4a4a80
-- 
2.38.1





Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 21 Dec 2022 14:25:14 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Dec 21 09:25:14 2022
Received: from localhost ([127.0.0.1]:52183 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p801v-0006dW-Tl
	for submit <at> debbugs.gnu.org; Wed, 21 Dec 2022 09:25:14 -0500
Received: from smtpm4.myservices.hosting ([185.26.105.235]:60734)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mirai@HIDDEN>) id 1p801r-0006dO-Kq
 for 59866 <at> debbugs.gnu.org; Wed, 21 Dec 2022 09:25:10 -0500
Received: from mail1.netim.hosting (unknown [185.26.106.172])
 by smtpm4.myservices.hosting (Postfix) with ESMTP id 5CA0520BEC
 for <59866 <at> debbugs.gnu.org>; Wed, 21 Dec 2022 15:25:06 +0100 (CET)
Received: from localhost (localhost [127.0.0.1])
 by mail1.netim.hosting (Postfix) with ESMTP id D346680098;
 Wed, 21 Dec 2022 15:16:01 +0100 (CET)
X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting
Received: from mail1.netim.hosting ([127.0.0.1])
 by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id qwO8616BuW0h; Wed, 21 Dec 2022 15:15:58 +0100 (CET)
Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156])
 (Authenticated sender: lumen@HIDDEN)
 by mail1.netim.hosting (Postfix) with ESMTPSA id 3478580096;
 Wed, 21 Dec 2022 15:15:58 +0100 (CET)
From: mirai@HIDDEN
To: 59866 <at> debbugs.gnu.org
Subject: [PATCH v4 2/2] services: mpd: Refactor MPD service.
Date: Wed, 21 Dec 2022 14:15:13 +0000
Message-Id: <22745f1abf008ad389638c984e51b12630a18307.1671632111.git.mirai@HIDDEN>
X-Mailer: git-send-email 2.38.1
In-Reply-To: <248f6adc7d434e3d8df791311744a38e0d965744.1671632111.git.mirai@HIDDEN>
References: <248f6adc7d434e3d8df791311744a38e0d965744.1671632111.git.mirai@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 59866
Cc: Bruno Victal <mirai@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

From: Bruno Victal <mirai@HIDDEN>

Introduces 'mpd-plugin' and 'mpd-partition' records.
Expands 'mpd-output' and 'mpd-configuration' records.
Deprecates redundant abbreviated fields in 'mpd-configuration' and
avoids serializing unused fields that may introduce undesired behavior.
Implement log-rotation via rottlog.
Implements Shepherd actions: 'reopen' and 'configuration'.
---
 doc/guix.texi          | 172 +++++++++++++---
 gnu/services/audio.scm | 434 +++++++++++++++++++++++++++++++----------
 2 files changed, 476 insertions(+), 130 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index fd03da8c97..3daec7dfaa 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@*
 
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -33012,79 +33013,184 @@ 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} (type: maybe-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"})
+@item @code{port} (default: @code{6600}) (type: maybe-integer)
 The port to run mpd on.
 
-@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{endpoints} (type: maybe-list-of-string)
+The addresses that mpd will bind to.  To use a Unix domain socket, an
+absolute path 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{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
@@ -33096,7 +33202,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 2351db8a4a..2b0447fd09 100644
--- a/gnu/services/audio.scm
+++ b/gnu/services/audio.scm
@@ -2,6 +2,7 @@
 ;;; Copyright © 2017 Peter Mikkelsen <petermikkelsen10@HIDDEN>
 ;;; Copyright © 2019 Ricardo Wurmus <rekado@HIDDEN>
 ;;; Copyright © 2020 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2022 Bruno Victal <mirai@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -20,19 +21,27 @@
 
 (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)
   #:use-module (guix records)
   #:use-module (ice-9 match)
-  #:use-module (ice-9 format)
   #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-8)
   #:use-module (srfi srfi-26)
   #:export (mpd-output
             mpd-output?
+            mpd-plugin
+            mpd-plugin?
+            mpd-partition
+            mpd-partition?
             mpd-configuration
             mpd-configuration?
             mpd-service-type))
@@ -51,180 +60,397 @@ (define (uglify-field-name field-name)
                                #\-)
                  "_")))
 
-(define (free-form-args? val)
-  (match val
-    (() #t)
-    ((((? symbol?) . (? string?)) . val) (free-form-args? val))
-    (_ #f)))
+(define list-of-string?
+  (list-of string?))
 
-(define* (mpd-serialize-field field-name value #:optional (indent-level 0))
-  #~(begin
-      (use-modules ((ice-9 format)))
-      (format #f "~v/~a \"~a\"~%" #$indent-level #$(if (string? field-name)
-                                                       field-name
-                                                       (uglify-field-name field-name)) #$value)))
+(define list-of-symbol?
+  (list-of symbol?))
 
-(define* (mpd-serialize-free-form-args field-name value #:optional (indent-level 0))
-  (generic-serialize-alist string-append (cut mpd-serialize-field <> <> indent-level) value))
+(define (mpd-serialize-field field-name value)
+  (let ((field (if (string? field-name) field-name
+                   (uglify-field-name field-name)))
+        (value (if (boolean? value) (if value "yes" "no") value)))
+    #~(format #f "~a \"~a\"~%" #$field #$value)))
 
 (define mpd-serialize-number mpd-serialize-field)
 
 (define mpd-serialize-string mpd-serialize-field)
 
-(define* (mpd-serialize-boolean field-name value #:optional (indent-level 0))
-  (mpd-serialize-field field-name (if value "yes" "no") indent-level))
+(define mpd-serialize-boolean mpd-serialize-field)
 
-(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-alist field-name value)
+  #~(string-append #$@(generic-serialize-alist list mpd-serialize-field value)))
 
-(define (mpd-serialize-configuration configuration)
-  (mixed-text-file
-   "mpd.conf"
-   (serialize-configuration configuration mpd-configuration-fields)))
+(define-maybe string (prefix mpd-))
+(define-maybe list-of-string (prefix mpd-))
+(define-maybe boolean (prefix mpd-))
+
+;;; TODO: Procedures for deprecated fields, to be removed.
+
+(define mpd-deprecated-fields '((music-dir . music-directory)
+                                (playlist-dir . playlist-directory)
+                                (address . addresses)))
+
+(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 field-name 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 mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> 1))
-(define mpd-subsystem-serialize-string (cut mpd-serialize-string <> <> 1))
-(define mpd-subsystem-serialize-number (cut mpd-serialize-number <> <> 1))
-(define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean <> <> 1))
-(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize-free-form-args <> <> 1))
+(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
    (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.")
+
+  (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
 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
+   "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
-   (free-form-args '())
-   "An association list of option symbols to string values to be appended to
+   (alist '())
+   "An association list of option symbols/strings to string values to be appended to
 the audio output configuration.")
-  (prefix mpd-subsystem-))
 
-(define list-of-mpd-output?
-  (list-of mpd-output?))
+  (prefix mpd-))
+
+(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)
+  (receive (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
+   maybe-string
+   "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)))
-  (playlist-dir
-   (string "~/.mpd/playlists")
+   mpd-serialize-deprecated-field)
+
+  (playlist-directory
+   maybe-string
+   "The directory to store 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")
+   (maybe-port 6600) ; TODO: switch to integer
    "The port to run mpd on.")
-  (address
-   (string "any")
+
+  (endpoints
+   maybe-list-of-string
+   "The addresses that mpd will bind to.
+To use a Unix domain socket, an absolute path can be specified here."
+   (lambda (_ x)
+     (if (maybe-value-set? x)
+         #~(string-append #$@(map
+                              (cut mpd-serialize-field "bind_to_address" <>)
+                              x)) "")))
+
+  (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-list-of-mpd-plugin "input" x)))
+
+  (archive-plugins
+   (list-of-mpd-plugin '())
+   "List of MPD archive plugin configurations."
    (lambda (_ x)
-     (mpd-serialize-field "bind_to_address" 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 <mpd-configuration> (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))))
+  (match-record config <mpd-configuration> (user package shepherd-requirement)
+    (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 #~(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-service-activation config)
-  (with-imported-modules '((guix build utils))
+  (match-record config <mpd-configuration> (user log-file)
     #~(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")
+        (let* ((user (getpw #$user))
+               (deprecated-directory (string-append "/var/run/mpd/" #$user "/.mpd"))
+               (new-directory (string-append (passwd:dir user) "/.config/mpd")))
+          ;; TODO: remove me, migrates from the old location at /var/run/mpd to the new one at /var/lib/mpd.
+          (when (and (file-exists? deprecated-directory) (not (file-exists? new-directory)))
+            (rename-file deprecated-directory new-directory)
+            (chown new-directory (passwd:uid user) (passwd:gid user)))
+          (mkdir-p (dirname #$log-file))))))
 
-         (shell (file-append shadow "/sbin/nologin")))))
+(define (mpd-accounts config)
+  (match-record config <mpd-configuration> (user)
+    (list (user-account
+           (name user)
+           (group "nogroup")
+           (system? #t)
+           (comment "Music Player Daemon (MPD) user")
+           (home-directory "/var/lib/mpd")  ; MPD can use $HOME (or $XDG_CONFIG_HOME) to place its data
+           (shell (file-append shadow "/sbin/nologin"))))))
 
 (define mpd-service-type
   (service-type
@@ -234,7 +460,9 @@ (define mpd-service-type
     (list (service-extension shepherd-root-service-type
                              (compose list mpd-shepherd-service))
           (service-extension account-service-type
-                             (const %mpd-accounts))
+                             mpd-accounts)
           (service-extension activation-service-type
-                             mpd-service-activation)))
+                             mpd-service-activation)
+          (service-extension rottlog-service-type
+                             (compose list mpd-log-rotation))))
    (default-value (mpd-configuration))))
-- 
2.38.1





Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 21 Dec 2022 14:15:51 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Dec 21 09:15:51 2022
Received: from localhost ([127.0.0.1]:52142 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p7zss-0006YO-Gf
	for submit <at> debbugs.gnu.org; Wed, 21 Dec 2022 09:15:51 -0500
Received: from smtpm2.myservices.hosting ([185.26.105.233]:55018)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mirai@HIDDEN>) id 1p7zsp-0006YI-OX
 for 59866 <at> debbugs.gnu.org; Wed, 21 Dec 2022 09:15:48 -0500
Received: from mail1.netim.hosting (unknown [185.26.106.172])
 by smtpm2.myservices.hosting (Postfix) with ESMTP id A7D8520DF1
 for <59866 <at> debbugs.gnu.org>; Wed, 21 Dec 2022 15:15:46 +0100 (CET)
Received: from localhost (localhost [127.0.0.1])
 by mail1.netim.hosting (Postfix) with ESMTP id 4CC558009A;
 Wed, 21 Dec 2022 15:15:46 +0100 (CET)
X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting
Received: from mail1.netim.hosting ([127.0.0.1])
 by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id 3VLzJ0EnXfa2; Wed, 21 Dec 2022 15:15:45 +0100 (CET)
Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156])
 (Authenticated sender: lumen@HIDDEN)
 by mail1.netim.hosting (Postfix) with ESMTPSA id F3F3380099;
 Wed, 21 Dec 2022 15:15:42 +0100 (CET)
From: mirai@HIDDEN
To: 59866 <at> debbugs.gnu.org
Subject: [PATCH v4 1/2] services: mpd: use 'define-configuration'.
Date: Wed, 21 Dec 2022 14:15:12 +0000
Message-Id: <248f6adc7d434e3d8df791311744a38e0d965744.1671632111.git.mirai@HIDDEN>
X-Mailer: git-send-email 2.38.1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 59866
Cc: Bruno Victal <mirai@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

From: Bruno Victal <mirai@HIDDEN>

---
 gnu/services/audio.scm | 217 ++++++++++++++++++++++++-----------------
 1 file changed, 129 insertions(+), 88 deletions(-)

diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm
index c60053f33c..2351db8a4a 100644
--- a/gnu/services/audio.scm
+++ b/gnu/services/audio.scm
@@ -21,6 +21,7 @@
 (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)
@@ -28,6 +29,8 @@ (define-module (gnu services audio)
   #: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,131 @@ (define-module (gnu services audio)
 ;;;
 ;;; Code:
 
-(define-record-type* <mpd-output>
-  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>
-  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 <mpd-output> 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 (free-form-args? val)
+  (match val
+    (() #t)
+    ((((? symbol?) . (? string?)) . val) (free-form-args? val))
+    (_ #f)))
+
+(define* (mpd-serialize-field field-name value #:optional (indent-level 0))
+  #~(begin
+      (use-modules ((ice-9 format)))
+      (format #f "~v/~a \"~a\"~%" #$indent-level #$(if (string? field-name)
+                                                       field-name
+                                                       (uglify-field-name field-name)) #$value)))
+
+(define* (mpd-serialize-free-form-args field-name value #:optional (indent-level 0))
+  (generic-serialize-alist string-append (cut mpd-serialize-field <> <> indent-level) value))
+
+(define mpd-serialize-number mpd-serialize-field)
+
+(define mpd-serialize-string mpd-serialize-field)
+
+(define* (mpd-serialize-boolean field-name value #:optional (indent-level 0))
+  (mpd-serialize-field field-name (if value "yes" "no") indent-level))
+
+(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 mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> 1))
+(define mpd-subsystem-serialize-string (cut mpd-serialize-string <> <> 1))
+(define mpd-subsystem-serialize-number (cut mpd-serialize-number <> <> 1))
+(define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean <> <> 1))
+(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize-free-form-args <> <> 1))
+
+(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
+   (free-form-args '())
+   "An association list of option symbols to string values to be appended to
+the audio output configuration.")
+  (prefix mpd-subsystem-))
+
+(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 +184,7 @@ (define (mpd-shepherd-service config)
    (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

base-commit: 7833acab0da02335941974608510c02e2d1d8069
-- 
2.38.1





Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 16 Dec 2022 14:25:12 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Dec 16 09:25:12 2022
Received: from localhost ([127.0.0.1]:49644 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p6BeA-0006Cu-K4
	for submit <at> debbugs.gnu.org; Fri, 16 Dec 2022 09:25:12 -0500
Received: from smtpm2.myservices.hosting ([185.26.105.233]:36820)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mirai@HIDDEN>) id 1p6Be5-0006Cm-Md
 for 59866 <at> debbugs.gnu.org; Fri, 16 Dec 2022 09:25:09 -0500
Received: from mail1.netim.hosting (unknown [185.26.106.172])
 by smtpm2.myservices.hosting (Postfix) with ESMTP id 320A320D8E
 for <59866 <at> debbugs.gnu.org>; Fri, 16 Dec 2022 15:25:03 +0100 (CET)
Received: from localhost (localhost [127.0.0.1])
 by mail1.netim.hosting (Postfix) with ESMTP id D699A8009B;
 Fri, 16 Dec 2022 15:25:03 +0100 (CET)
X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting
Received: from mail1.netim.hosting ([127.0.0.1])
 by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id huDVcoAZ3AiS; Fri, 16 Dec 2022 15:25:01 +0100 (CET)
Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156])
 (Authenticated sender: lumen@HIDDEN)
 by mail1.netim.hosting (Postfix) with ESMTPSA id 808CF8009A;
 Fri, 16 Dec 2022 15:25:00 +0100 (CET)
From: mirai@HIDDEN
To: 59866 <at> debbugs.gnu.org
Subject: [PATCH v3] services: mpd: Refactor MPD service.
Date: Fri, 16 Dec 2022 14:15:16 +0000
Message-Id: <bd2216b94eb04866095ba43d1807463153215ee2.1671200114.git.mirai@HIDDEN>
X-Mailer: git-send-email 2.38.1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 59866
Cc: Bruno Victal <mirai@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

From: Bruno Victal <mirai@HIDDEN>

Introduces 'mpd-plugin' and 'mpd-partition' records.
Expands 'mpd-output' and 'mpd-configuration' records.
Deprecates redundant abbreviated fields in 'mpd-configuration' and
avoids serializing unused fields that may introduce undesired behavior.
Implement log-rotation via rottlog.
Implements Shepherd actions: 'reopen' and 'configuration'.
---

Changes from v2 to v3:
* Removed "pretty-formatting" code to reduce overall code "weight".
* Renamed shepherd action 'reload' to 'reopen' as reloading would suggest
that it re-reads the config file.
* Renamed 'addresses' field to 'endpoints'.
* Allow mpd-plugin records to be used in 'outputs' field.
Technically an audio output is a mpd-plugin but since there
are numerous common audio output specific options it's worthwhile
having a mpd-output record-type for it.
* mpd-plugin serialization was simplified and the "subsystem block name"
was integrated directly into mpd-configuration record-type to better
track which field corresponds to which subsystem rather than keep an
external dictionary that maps the fields to the subsystem names.

 doc/guix.texi          | 172 +++++++++++++---
 gnu/services/audio.scm | 434 +++++++++++++++++++++++++++++++----------
 2 files changed, 476 insertions(+), 130 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 5cb5ae1dfe..3f186aefa9 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@*
 
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -33007,79 +33008,184 @@ 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} (type: maybe-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"})
+@item @code{port} (default: @code{6600}) (type: maybe-integer)
 The port to run mpd on.
 
-@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{endpoints} (type: maybe-list-of-string)
+The addresses that mpd will bind to.  To use a Unix domain socket, an
+absolute path 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{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
@@ -33091,7 +33197,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 2351db8a4a..aeb081380a 100644
--- a/gnu/services/audio.scm
+++ b/gnu/services/audio.scm
@@ -2,6 +2,7 @@
 ;;; Copyright © 2017 Peter Mikkelsen <petermikkelsen10@HIDDEN>
 ;;; Copyright © 2019 Ricardo Wurmus <rekado@HIDDEN>
 ;;; Copyright © 2020 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2022 Bruno Victal <mirai@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -20,19 +21,27 @@
 
 (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)
   #:use-module (guix records)
   #:use-module (ice-9 match)
-  #:use-module (ice-9 format)
   #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-8)
   #:use-module (srfi srfi-26)
   #:export (mpd-output
             mpd-output?
+            mpd-plugin
+            mpd-plugin?
+            mpd-partition
+            mpd-partition?
             mpd-configuration
             mpd-configuration?
             mpd-service-type))
@@ -51,180 +60,397 @@ (define (uglify-field-name field-name)
                                #\-)
                  "_")))
 
-(define (free-form-args? val)
-  (match val
-    (() #t)
-    ((((? symbol?) . (? string?)) . val) (free-form-args? val))
-    (_ #f)))
+(define list-of-string?
+  (list-of string?))
 
-(define* (mpd-serialize-field field-name value #:optional (indent-level 0))
-  #~(begin
-      (use-modules ((ice-9 format)))
-      (format #f "~v/~a \"~a\"~%" #$indent-level #$(if (string? field-name)
-                                                       field-name
-                                                       (uglify-field-name field-name)) #$value)))
+(define list-of-symbol?
+  (list-of symbol?))
 
-(define* (mpd-serialize-free-form-args field-name value #:optional (indent-level 0))
-  (generic-serialize-alist string-append (cut mpd-serialize-field <> <> indent-level) value))
+(define (mpd-serialize-field field-name value)
+  (let ((field (if (string? field-name) field-name
+                   (uglify-field-name field-name)))
+        (value (if (boolean? value) (if value "yes" "no") value)))
+    #~(format #f "~a \"~a\"~%" #$field #$value)))
 
 (define mpd-serialize-number mpd-serialize-field)
 
 (define mpd-serialize-string mpd-serialize-field)
 
-(define* (mpd-serialize-boolean field-name value #:optional (indent-level 0))
-  (mpd-serialize-field field-name (if value "yes" "no") indent-level))
+(define mpd-serialize-boolean mpd-serialize-field)
 
-(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-alist field-name value)
+  #~(string-append #$@(generic-serialize-alist list mpd-serialize-field value)))
 
-(define (mpd-serialize-configuration configuration)
-  (mixed-text-file
-   "mpd.conf"
-   (serialize-configuration configuration mpd-configuration-fields)))
+(define-maybe string (prefix mpd-))
+(define-maybe list-of-string (prefix mpd-))
+(define-maybe boolean (prefix mpd-))
+
+;;; TODO: Procedures for deprecated fields, to be removed.
+
+(define mpd-deprecated-fields '((music-dir . music-directory)
+                                (playlist-dir . playlist-directory)
+                                (address . addresses)))
+
+(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 field-name 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 mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> 1))
-(define mpd-subsystem-serialize-string (cut mpd-serialize-string <> <> 1))
-(define mpd-subsystem-serialize-number (cut mpd-serialize-number <> <> 1))
-(define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean <> <> 1))
-(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize-free-form-args <> <> 1))
+(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
    (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.")
+
+  (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
 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
+   "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
-   (free-form-args '())
-   "An association list of option symbols to string values to be appended to
+   (alist '())
+   "An association list of option symbols/strings to string values to be appended to
 the audio output configuration.")
-  (prefix mpd-subsystem-))
 
-(define list-of-mpd-output?
-  (list-of mpd-output?))
+  (prefix mpd-))
+
+(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)
+  (receive (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
+   maybe-string
+   "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)))
-  (playlist-dir
-   (string "~/.mpd/playlists")
+   mpd-serialize-deprecated-field)
+
+  (playlist-directory
+   maybe-string
+   "The directory to store 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")
+   (maybe-port 6600) ; TODO: switch to integer
    "The port to run mpd on.")
-  (address
-   (string "any")
+
+  (endpoints
+   maybe-list-of-string
+   "The addresses that mpd will bind to.
+To use a Unix domain socket, an absolute path can be specified here."
+   (lambda (_ x)
+     (if (maybe-value-set? x)
+         #~(string-append #$@(map
+                              (cut mpd-serialize-field "bind_to_address" <>)
+                              x)) "")))
+
+  (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-list-of-mpd-plugin "input" x)))
+
+  (archive-plugins
+   (list-of-mpd-plugin '())
+   "List of MPD archive plugin configurations."
    (lambda (_ x)
-     (mpd-serialize-field "bind_to_address" 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 <mpd-configuration> (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))))
+  (match-record config <mpd-configuration> (user package shepherd-requirement)
+    (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 #~(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-service-activation config)
-  (with-imported-modules '((guix build utils))
+  (match-record config <mpd-configuration> (user log-file)
     #~(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")
+        (let* ((user (getpw #$user))
+               (deprecated-directory (string-append "/var/run/mpd/" #$user "/.mpd"))
+               (new-directory (string-append (passwd:dir user) "/.config/mpd")))
+          ;; TODO: remove me, migrates from the old location at /var/run/mpd to the new one at /var/lib/mpd.
+          (when (and (file-exists? deprecated-directory) (not (file-exists? new-directory)))
+            (rename-file deprecated-directory new-directory)
+            (chown new-directory (passwd:uid user) (passwd:gid user)))
+          (mkdir-p (dirname #$log-file))))))
 
-         (shell (file-append shadow "/sbin/nologin")))))
+(define (mpd-accounts config)
+  (match-record config <mpd-configuration> (user)
+    (list (user-account
+           (name user)
+           (group "nogroup")
+           (system? #t)
+           (comment "Music Player Daemon (MPD) user")
+           (home-directory "/var/lib/mpd")  ; MPD can use $HOME (or $XDG_CONFIG_HOME) to place its data
+           (shell (file-append shadow "/sbin/nologin"))))))
 
 (define mpd-service-type
   (service-type
@@ -234,7 +460,9 @@ (define mpd-service-type
     (list (service-extension shepherd-root-service-type
                              (compose list mpd-shepherd-service))
           (service-extension account-service-type
-                             (const %mpd-accounts))
+                             mpd-accounts)
           (service-extension activation-service-type
-                             mpd-service-activation)))
+                             mpd-service-activation)
+          (service-extension rottlog-service-type
+                             (compose list mpd-log-rotation))))
    (default-value (mpd-configuration))))

base-commit: 7ce9b7e7062eee406e269bc40a20247973732be2
prerequisite-patch-id: 3b756bb4d930897ce79b1e51cc25478cb73fd9d8
-- 
2.38.1





Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 11 Dec 2022 12:05:47 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sun Dec 11 07:05:47 2022
Received: from localhost ([127.0.0.1]:46358 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p4L5X-0001GD-An
	for submit <at> debbugs.gnu.org; Sun, 11 Dec 2022 07:05:47 -0500
Received: from smtpm3.myservices.hosting ([185.26.105.234]:57936)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mirai@HIDDEN>)
 id 1p4L5V-0001G1-9v; Sun, 11 Dec 2022 07:05:45 -0500
Received: from mail1.netim.hosting (unknown [185.26.106.172])
 by smtpm3.myservices.hosting (Postfix) with ESMTP id 5FEC420CD0;
 Sun, 11 Dec 2022 13:05:40 +0100 (CET)
Received: from localhost (localhost [127.0.0.1])
 by mail1.netim.hosting (Postfix) with ESMTP id 1BAA480097;
 Sun, 11 Dec 2022 13:05:40 +0100 (CET)
X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting
Received: from mail1.netim.hosting ([127.0.0.1])
 by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id 7i8Dm-61ekDB; Sun, 11 Dec 2022 13:05:39 +0100 (CET)
Received: from [192.168.1.239] (unknown [10.192.1.83])
 (Authenticated sender: lumen@HIDDEN)
 by mail1.netim.hosting (Postfix) with ESMTPSA id A48E680093;
 Sun, 11 Dec 2022 13:05:39 +0100 (CET)
Message-ID: <cddf3b32-97e1-026f-d94b-1c35780db3a1@HIDDEN>
Date: Sun, 11 Dec 2022 12:05:38 +0000
MIME-Version: 1.0
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
 Thunderbird/102.5.1
Subject: Re: [PATCH 0/2] services: mpd: Refactor MPD service
Content-Language: en-US
To: Liliana Marie Prikler <liliana.prikler@HIDDEN>, 59866 <at> debbugs.gnu.org
References: <cover.1670368385.git.mirai@HIDDEN>
 <6e66967984d1bc22d8abf5dd4b07c1a20b4b06ee.camel@HIDDEN>
 <71f31a0d-cc58-a0e6-4aa4-b5c46513c835@HIDDEN>
 <c2c097ea2491638d0553e2a3bea65e571e5e595a.camel@HIDDEN>
 <d5439211-66b2-0938-2de4-1847b22ce0e2@HIDDEN>
 <4e6249e0970fcd02ac4666ce1fd40203b4b09003.camel@HIDDEN>
From: mirai <mirai@HIDDEN>
In-Reply-To: <4e6249e0970fcd02ac4666ce1fd40203b4b09003.camel@HIDDEN>
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 59866
Cc: 54986 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

On 2022-12-09 19:22, Liliana Marie Prikler wrote:
> Something like that, but I don't think the vocabulary matches 1:1.  In
> my opinion, an address is an endpoint – not a shepherd endpoint, but an
> endpoint still – while a shepherd endpoint is not an address.  Thus, I
> propose changing the vocabulary now to not break backwards
> compatibility later.
You prefer the 'addresses' field to be renamed to 'endpoints', is that correct?

IIUC, the change from the previous records to
> define-configuration is already an API change, so it'd be good to have
> both in the same series.
The first patch in the series changes from define-record-type* to define-configuration
but it does not add anything, I don't think there are actually any (exported)
API changes visible to the user.

Only the second patch starts to introduce visible API changes.

Cheers





Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 9 Dec 2022 19:22:16 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Dec 09 14:22:16 2022
Received: from localhost ([127.0.0.1]:37956 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p3iwq-0002AX-Dw
	for submit <at> debbugs.gnu.org; Fri, 09 Dec 2022 14:22:16 -0500
Received: from mail-ed1-f66.google.com ([209.85.208.66]:43878)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <liliana.prikler@HIDDEN>)
 id 1p3iwo-0002AO-Lm; Fri, 09 Dec 2022 14:22:15 -0500
Received: by mail-ed1-f66.google.com with SMTP id r26so4406588edc.10;
 Fri, 09 Dec 2022 11:22:14 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112;
 h=mime-version:user-agent:content-transfer-encoding:references
 :in-reply-to:date:cc:to:from:subject:message-id:from:to:cc:subject
 :date:message-id:reply-to;
 bh=UYDUuFv+QX94mxBglSp5PdFi+xLnIehulY1Kn2d4rPk=;
 b=KppNnK2Rwihk1crComLMhSa8UPjEjnxOrvoFpi9/o6czta1sVPgUzpeos/35nSDCli
 pHmpQxgC3fd/QWJxESu2bTxM2rPy6eBrP5e9IsjCkB+GYlw6bVeBdVEOCMD2B8WaF18/
 jB9cjqwR4o3gNlfe9AH7uHDSqvH+QvBr6scud+GRCkt3+M8inETA2HIJbt/v3OnS/AET
 nQ7rTO4jWaha3P4ClWdk77xoPEeiwYJbxLAGtGpaaQAIrYgJ62kiFPYNHyYhkCM/tPIo
 0e+WrAwC55phwpk0IVJeB8tOHg5wDUu1wPx1pIENEbg4PkP/WJCtnstPFkG4JI6M2q5q
 wunw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20210112;
 h=mime-version:user-agent:content-transfer-encoding:references
 :in-reply-to:date:cc:to:from:subject:message-id:x-gm-message-state
 :from:to:cc:subject:date:message-id:reply-to;
 bh=UYDUuFv+QX94mxBglSp5PdFi+xLnIehulY1Kn2d4rPk=;
 b=j168HP51cwZcv5/eUpyBea305ud492017v4GSqRRy/w52QcHKlkf5IsuB0HtB9QNBg
 cWcyT0ii4eHU3o+Rl5R4Ffg6b56I0S+cRcsodJu08AEGiloWE7X2zE7LtgACpxhRJtHB
 puVyjUh8zF/PyUCgrWCcx3Q2smyzxRxsoQmXQJVQU3eLW+Cv8xM13IXwEZpI6IJzNvt7
 OsFGaIfsY1S9m0qjz13B/HUzTQ4RDfiqTcgM6pEvJRcDjBC/NH3RhjTcORxLNif18rpD
 E9dD26QDvSD8k4eBXofFRM81x1qPGkTZOyl7wL5H1yRqZjQAirhMVdPscz000jPeFNzQ
 vjEQ==
X-Gm-Message-State: ANoB5pk8jEFIDGwmewfrj/1vNjLkulrFmz2T9ugeJzA8YoaPV9aqtVnH
 1Cspbbns33f2lkn9cbgW/oofCbE+hrs=
X-Google-Smtp-Source: AA0mqf6QXuoUzjKeH5AwW76lueHl196u1Gr0R1HUOqdnAauMuHb10TlDjd+gON94I5xhAyStTRZ0cw==
X-Received: by 2002:a05:6402:1047:b0:45c:835b:ac4d with SMTP id
 e7-20020a056402104700b0045c835bac4dmr5736202edu.8.1670613728618; 
 Fri, 09 Dec 2022 11:22:08 -0800 (PST)
Received: from lumine.fritz.box (85-127-52-93.dsl.dynamic.surfer.at.
 [85.127.52.93]) by smtp.gmail.com with ESMTPSA id
 m6-20020a056402050600b0046c5baa1f58sm952676edv.97.2022.12.09.11.22.07
 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
 Fri, 09 Dec 2022 11:22:08 -0800 (PST)
Message-ID: <4e6249e0970fcd02ac4666ce1fd40203b4b09003.camel@HIDDEN>
Subject: Re: [PATCH 0/2] services: mpd: Refactor MPD service
From: Liliana Marie Prikler <liliana.prikler@HIDDEN>
To: mirai <mirai@HIDDEN>, 59866 <at> debbugs.gnu.org
Date: Fri, 09 Dec 2022 20:22:06 +0100
In-Reply-To: <d5439211-66b2-0938-2de4-1847b22ce0e2@HIDDEN>
References: <cover.1670368385.git.mirai@HIDDEN>
 <6e66967984d1bc22d8abf5dd4b07c1a20b4b06ee.camel@HIDDEN>
 <71f31a0d-cc58-a0e6-4aa4-b5c46513c835@HIDDEN>
 <c2c097ea2491638d0553e2a3bea65e571e5e595a.camel@HIDDEN>
 <d5439211-66b2-0938-2de4-1847b22ce0e2@HIDDEN>
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
User-Agent: Evolution 3.46.0 
MIME-Version: 1.0
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 59866
Cc: 54986 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Am Freitag, dem 09.12.2022 um 13:44 +0000 schrieb mirai:
> On 2022-12-08 13:35, Liliana Marie Prikler wrote:
> > This doesn't work for #54986, which makes it so that in-file
> > addresses are ignored in favour of handing over the sockets
> > directly through shepherd.=C2=A0 Looking at [4], it appears the meaning
> > of "port" is closer to that of a default port, as addresses can
> > have ports in them.=C2=A0
> > But I would still prefer addresses to be "endpoints", which if they
> > happen to be a list of strings are taken as MPD addresses and if
> > they happen to be shepherd endpoints are passed on to the shepherd
> > service.
>=20
> Are you proposing for the 'addresses' field to be a
> "maybe-list-of-string-or-shepherd-endpoint"? (more of a xor as they
> can't be used simultaneously)
> Example:
>=20
> --8<---------------cut here---------------start------------->8---
> ;; should fire a error message during guix system reconfigure
> (mpd-configuration
> =C2=A0 (addresses `("[::]:6645"=C2=A0=20
> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0 ,(shepherd-endpoint
> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (address "/var/run/mpd-shepherd-socket")))))
> --8<---------------cut here---------------end--------------->8---
>=20
> I don't think it breaks backward compatibility to introduce this
> after #59866 is merged.
> The type of field 'addresses' could be changed transparently to
> something like:
>=20
> --8<---------------cut here---------------start------------->8---
> (define list-of-addresses (list-of (lambda (x) (or (string? x)
> (shepherd-endpoint? x)))))
> --8<---------------cut here---------------end--------------->8---
Something like that, but I don't think the vocabulary matches 1:1.  In
my opinion, an address is an endpoint =E2=80=93 not a shepherd endpoint, bu=
t an
endpoint still =E2=80=93 while a shepherd endpoint is not an address.  Thus=
, I
propose changing the vocabulary now to not break backwards
compatibility later.  IIUC, the change from the previous records to
define-configuration is already an API change, so it'd be good to have
both in the same series.

Cheers




Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.
Changed bug title to '[WIP] [PATCH 0/2] services: mpd: Refactor MPD service' from '[PATCH 0/2] services: mpd: Refactor MPD service' Request was from mirai <mirai@HIDDEN> to control <at> debbugs.gnu.org. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 9 Dec 2022 13:45:06 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Dec 09 08:45:05 2022
Received: from localhost ([127.0.0.1]:36197 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p3dgX-00024L-KZ
	for submit <at> debbugs.gnu.org; Fri, 09 Dec 2022 08:45:05 -0500
Received: from smtpmciv5.myservices.hosting ([185.26.107.241]:50898)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mirai@HIDDEN>)
 id 1p3dgV-00023u-DU; Fri, 09 Dec 2022 08:45:03 -0500
Received: from mail1.netim.hosting (unknown [185.26.106.172])
 by smtpmciv5.myservices.hosting (Postfix) with ESMTP id E947520BE5;
 Fri,  9 Dec 2022 14:45:00 +0100 (CET)
Received: from localhost (localhost [127.0.0.1])
 by mail1.netim.hosting (Postfix) with ESMTP id 865A080098;
 Fri,  9 Dec 2022 14:45:00 +0100 (CET)
X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting
Received: from mail1.netim.hosting ([127.0.0.1])
 by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id qmuGHNF6oe9n; Fri,  9 Dec 2022 14:45:00 +0100 (CET)
Received: from [192.168.1.239] (unknown [10.192.1.83])
 (Authenticated sender: lumen@HIDDEN)
 by mail1.netim.hosting (Postfix) with ESMTPSA id DD71480093;
 Fri,  9 Dec 2022 14:44:59 +0100 (CET)
Message-ID: <d5439211-66b2-0938-2de4-1847b22ce0e2@HIDDEN>
Date: Fri, 9 Dec 2022 13:44:58 +0000
MIME-Version: 1.0
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
 Thunderbird/102.5.1
Subject: Re: [PATCH 0/2] services: mpd: Refactor MPD service
Content-Language: en-US
To: Liliana Marie Prikler <liliana.prikler@HIDDEN>, 59866 <at> debbugs.gnu.org
References: <cover.1670368385.git.mirai@HIDDEN>
 <6e66967984d1bc22d8abf5dd4b07c1a20b4b06ee.camel@HIDDEN>
 <71f31a0d-cc58-a0e6-4aa4-b5c46513c835@HIDDEN>
 <c2c097ea2491638d0553e2a3bea65e571e5e595a.camel@HIDDEN>
From: mirai <mirai@HIDDEN>
In-Reply-To: <c2c097ea2491638d0553e2a3bea65e571e5e595a.camel@HIDDEN>
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 59866
Cc: 54986 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

On 2022-12-08 13:35, Liliana Marie Prikler wrote:
> This doesn't work for #54986, which makes it so that in-file addresses
> are ignored in favour of handing over the sockets directly through
> shepherd.  Looking at [4], it appears the meaning of "port" is closer
> to that of a default port, as addresses can have ports in them.  But I
> would still prefer addresses to be "endpoints", which if they happen to
> be a list of strings are taken as MPD addresses and if they happen to
> be shepherd endpoints are passed on to the shepherd service.

Are you proposing for the 'addresses' field to be a
"maybe-list-of-string-or-shepherd-endpoint"? (more of a xor as they can't
be used simultaneously)
Example:

--8<---------------cut here---------------start------------->8---
;; should fire a error message during guix system reconfigure
(mpd-configuration
  (addresses `("[::]:6645"  
               ,(shepherd-endpoint
                  (address "/var/run/mpd-shepherd-socket")))))
--8<---------------cut here---------------end--------------->8---

I don't think it breaks backward compatibility to introduce this
after #59866 is merged.
The type of field 'addresses' could be changed transparently to something like:

--8<---------------cut here---------------start------------->8---
(define list-of-addresses (list-of (lambda (x) (or (string? x) (shepherd-endpoint? x)))))
--8<---------------cut here---------------end--------------->8---




Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 8 Dec 2022 13:36:06 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Dec 08 08:36:06 2022
Received: from localhost ([127.0.0.1]:56811 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p3H4I-00033K-7p
	for submit <at> debbugs.gnu.org; Thu, 08 Dec 2022 08:36:06 -0500
Received: from mail-ej1-f66.google.com ([209.85.218.66]:40764)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <liliana.prikler@HIDDEN>)
 id 1p3H4G-00032r-32; Thu, 08 Dec 2022 08:36:04 -0500
Received: by mail-ej1-f66.google.com with SMTP id b2so3910445eja.7;
 Thu, 08 Dec 2022 05:36:04 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112;
 h=mime-version:user-agent:content-transfer-encoding:references
 :in-reply-to:date:cc:to:from:subject:message-id:from:to:cc:subject
 :date:message-id:reply-to;
 bh=NLSGOOf2eRBAwiYW6X8+LYnqDTQCwpP7U+hL/+ZUHVQ=;
 b=nigV6vxdvqjvSTOBVGJyMbgXrlmDMcah6CMYU/lv5MW5wZT+kBSuknsHSss1CdDjUY
 6wRpQtaQI5omo1xhgw+PKP1ob4YB4ZTGDInr8WeZSdG3Sii2Ah5VpzXwFCMkwmAmf1eN
 wRpFNNDLkR2jJ88h6EDYxYEM4wF3ouMvrVW70uZcAEsVdtfkgGLA3jnb3BLuNy8ATVWr
 tdamTH7ktq2IB1x82EsiLpWkEFerMn+tz0d1Vlsnz5aYHp7d35h+xI2AH5radpNkbYYi
 B3OlfNb4nhb9OhgbTSKFi+W4ssNJuCh1TqfOjI9l5CUUDffwiE4PrpQJMoism9pG/wG9
 mHug==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20210112;
 h=mime-version:user-agent:content-transfer-encoding:references
 :in-reply-to:date:cc:to:from:subject:message-id:x-gm-message-state
 :from:to:cc:subject:date:message-id:reply-to;
 bh=NLSGOOf2eRBAwiYW6X8+LYnqDTQCwpP7U+hL/+ZUHVQ=;
 b=eWuofNeZrctnoL2UbNalrbcOaQ3WKlwJwIY8Ne6bh32NymI6g0h2Hd6jnLoJsChZIh
 eLOPCADI+aggBnVFyzP/so3Mx8JStyqkKK8cs0t4fvQVxiap+DIAc+czT3ai3iHNgiTE
 irUqN7KS3tCCJm4XZ6+Jkru2rRI//qeEMa8xGR4UxDq0rjPCcDaNWyxukO35wPtKZT27
 KDlSAB8QeJ59NAFPBUnh7SELHFRKCN2/86DrRyXEAVCazAIphJylpfCYGUy/i2tHvBFP
 XH5bGpnTIjU2mKRKc3REXK8cFZ2e0TL+lwaJOhdJqV35VqFeGtg8wcjx68UrsUsgD0bs
 Sqag==
X-Gm-Message-State: ANoB5pkQ2329GieiWpoRajUiVj0L2JUQEqOBszVd7KluM5r9VrzGSebw
 8xwox0JAldLPqifJnBjHrZI=
X-Google-Smtp-Source: AA0mqf5Ln50FtyONi6KSjrGOB+MJbHvtPfzUlpfihVKWxpPlvU/LquS4omNId7i5rnq+03w5Lt3aQQ==
X-Received: by 2002:aa7:cd02:0:b0:46c:9536:8598 with SMTP id
 b2-20020aa7cd02000000b0046c95368598mr15835083edw.123.1670506557965; 
 Thu, 08 Dec 2022 05:35:57 -0800 (PST)
Received: from lumine.fritz.box (85-127-52-93.dsl.dynamic.surfer.at.
 [85.127.52.93]) by smtp.gmail.com with ESMTPSA id
 i26-20020aa7dd1a000000b0045c47b2a800sm3358568edv.67.2022.12.08.05.35.56
 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
 Thu, 08 Dec 2022 05:35:57 -0800 (PST)
Message-ID: <c2c097ea2491638d0553e2a3bea65e571e5e595a.camel@HIDDEN>
Subject: Re: [PATCH 0/2] services: mpd: Refactor MPD service
From: Liliana Marie Prikler <liliana.prikler@HIDDEN>
To: mirai <mirai@HIDDEN>, 59866 <at> debbugs.gnu.org
Date: Thu, 08 Dec 2022 14:35:55 +0100
In-Reply-To: <71f31a0d-cc58-a0e6-4aa4-b5c46513c835@HIDDEN>
References: <cover.1670368385.git.mirai@HIDDEN>
 <6e66967984d1bc22d8abf5dd4b07c1a20b4b06ee.camel@HIDDEN>
 <71f31a0d-cc58-a0e6-4aa4-b5c46513c835@HIDDEN>
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
User-Agent: Evolution 3.46.0 
MIME-Version: 1.0
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 59866
Cc: 54986 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Am Donnerstag, dem 08.12.2022 um 13:11 +0000 schrieb mirai:
> On 2022-12-07 18:27, Liliana Marie Prikler wrote:
> > Note that there is [1], which attempts to make it so that shepherd
> > endpoints can be specified in lieu of MPD endpoints.=C2=A0 You don't
> > need to implement this logic =E2=80=93 you are free to do so if you wan=
t to
> > =E2=80=93 but could you make it so that there is an explicit endpoint
> > abstraction that would allow for extension later on?
> >=20
> > Cheers
> >=20
> > [1] https://issues.guix.gnu.org/54986
>=20
> Hi,
>=20
> After reading issue #54986, regarding mpd escaping shepherd
> management, my guess is that there could be two issues at play here:
>=20
> * mpd.conf was serialized with pid_file [1]. The safest is
> to actually not serialize any unused directives and let MPD decide
> based on what's actually present. pid_file should only be set if
> MPD is to be launched as a "daemon process". [2]
>=20
> * But the service definition for MPD is launched with '--no-daemon'
> option as seen in [3], which could be triggering a bug in MPD. It's
> probably worth testing the combinations of having pid_file set and
> invoking --no-daemon.
Nice catch, but completely unrelated to the issue.  In neither case do
we ever spawn MPD as a regular daemon, yet only in the systemd case
does shepherd have a problem with it.  That statement was concerning
shepherd's (mis)management of sockets, not MPD.

> > but could you make it so that there is an explicit endpoint
> > abstraction that would allow for extension later on?
>=20
> If I'm understanding correctly what [1] is about, I think this can be
> implemented through the 'extend' interface. See how certbot adds a
> nginx-server-configuration to a nginx-service-type through the
> 'extend' interface. For MPD, this would amount to appending the
> 'adresses' field with "adequately formatted" values.
This doesn't work for #54986, which makes it so that in-file addresses
are ignored in favour of handing over the sockets directly through
shepherd.  Looking at [4], it appears the meaning of "port" is closer
to that of a default port, as addresses can have ports in them.  But I
would still prefer addresses to be "endpoints", which if they happen to
be a list of strings are taken as MPD addresses and if they happen to
be shepherd endpoints are passed on to the shepherd service.

WDYT?

[4] https://mpd.readthedocs.io/en/stable/user.html#client-connections




Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 8 Dec 2022 13:11:37 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Dec 08 08:11:37 2022
Received: from localhost ([127.0.0.1]:56704 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p3Ggb-0002o5-B5
	for submit <at> debbugs.gnu.org; Thu, 08 Dec 2022 08:11:37 -0500
Received: from smtpmciv4.myservices.hosting ([185.26.107.240]:48080)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mirai@HIDDEN>)
 id 1p3GgZ-0002nu-9L; Thu, 08 Dec 2022 08:11:35 -0500
Received: from mail1.netim.hosting (unknown [185.26.106.172])
 by smtpmciv4.myservices.hosting (Postfix) with ESMTP id A58AF20775;
 Thu,  8 Dec 2022 14:11:33 +0100 (CET)
Received: from localhost (localhost [127.0.0.1])
 by mail1.netim.hosting (Postfix) with ESMTP id 65C0E80096;
 Thu,  8 Dec 2022 14:11:33 +0100 (CET)
X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting
Received: from mail1.netim.hosting ([127.0.0.1])
 by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id Qm4M4if-MSeb; Thu,  8 Dec 2022 14:11:29 +0100 (CET)
Received: from [192.168.1.239] (unknown [10.192.1.83])
 (Authenticated sender: lumen@HIDDEN)
 by mail1.netim.hosting (Postfix) with ESMTPSA id 9CFC980093;
 Thu,  8 Dec 2022 14:11:29 +0100 (CET)
Message-ID: <71f31a0d-cc58-a0e6-4aa4-b5c46513c835@HIDDEN>
Date: Thu, 8 Dec 2022 13:11:29 +0000
MIME-Version: 1.0
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
 Thunderbird/102.5.1
From: mirai <mirai@HIDDEN>
Subject: Re: [PATCH 0/2] services: mpd: Refactor MPD service
To: Liliana Marie Prikler <liliana.prikler@HIDDEN>, 59866 <at> debbugs.gnu.org
References: <cover.1670368385.git.mirai@HIDDEN>
 <6e66967984d1bc22d8abf5dd4b07c1a20b4b06ee.camel@HIDDEN>
Content-Language: en-US
In-Reply-To: <6e66967984d1bc22d8abf5dd4b07c1a20b4b06ee.camel@HIDDEN>
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 59866
Cc: 54986 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

On 2022-12-07 18:27, Liliana Marie Prikler wrote:
> Note that there is [1], which attempts to make it so that shepherd
> endpoints can be specified in lieu of MPD endpoints.  You don't need to
> implement this logic – you are free to do so if you want to – but could
> you make it so that there is an explicit endpoint abstraction that
> would allow for extension later on?
> 
> Cheers
> 
> [1] https://issues.guix.gnu.org/54986

Hi,

After reading issue #54986, regarding mpd escaping shepherd management,
my guess is that there could be two issues at play here:

* mpd.conf was serialized with pid_file [1]. The safest is
to actually not serialize any unused directives and let MPD decide
based on what's actually present. pid_file should only be set if
MPD is to be launched as a "daemon process". [2]

* But the service definition for MPD is launched with '--no-daemon' option
as seen in [3], which could be triggering a bug in MPD. It's probably worth
testing the combinations of having pid_file set and invoking --no-daemon.


> but could
> you make it so that there is an explicit endpoint abstraction that
> would allow for extension later on?

If I'm understanding correctly what [1] is about, I think this can be
implemented through the 'extend' interface. See how
certbot adds a nginx-server-configuration to a nginx-service-type
through the 'extend' interface. For MPD, this would amount to
appending the 'adresses' field with "adequately formatted" values.


[1]: https://git.savannah.gnu.org/cgit/guix.git/tree/gnu/services/audio.scm?id=1b6172d5f6ca22f0fa02cd1335b1b90e9501b731#n116
[2]: https://mpd.readthedocs.io/en/latest/user.html#starting-and-stopping-mpd
[3]: https://git.savannah.gnu.org/cgit/guix.git/tree/gnu/services/audio.scm?id=1b6172d5f6ca22f0fa02cd1335b1b90e9501b731#n145




Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 8 Dec 2022 01:01:47 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Dec 07 20:01:47 2022
Received: from localhost ([127.0.0.1]:53276 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p35IH-0007h2-Kr
	for submit <at> debbugs.gnu.org; Wed, 07 Dec 2022 20:01:47 -0500
Received: from smtpm5.myservices.hosting ([185.26.105.236]:48210)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mirai@HIDDEN>) id 1p35ID-0007gw-Pj
 for 59866 <at> debbugs.gnu.org; Wed, 07 Dec 2022 20:01:44 -0500
Received: from mail1.netim.hosting (unknown [185.26.106.172])
 by smtpm5.myservices.hosting (Postfix) with ESMTP id A372E20CFC
 for <59866 <at> debbugs.gnu.org>; Thu,  8 Dec 2022 02:01:39 +0100 (CET)
Received: from localhost (localhost [127.0.0.1])
 by mail1.netim.hosting (Postfix) with ESMTP id 3312F80096;
 Thu,  8 Dec 2022 02:01:39 +0100 (CET)
X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting
Received: from mail1.netim.hosting ([127.0.0.1])
 by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id Z6Nc9jOAjO2M; Thu,  8 Dec 2022 02:01:38 +0100 (CET)
Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156])
 (Authenticated sender: lumen@HIDDEN)
 by mail1.netim.hosting (Postfix) with ESMTPSA id D320A80093;
 Thu,  8 Dec 2022 02:01:37 +0100 (CET)
From: mirai@HIDDEN
To: 59866 <at> debbugs.gnu.org
Subject: [PATCH v2] services: mpd: Refactor MPD service.
Date: Thu,  8 Dec 2022 00:59:57 +0000
Message-Id: <358a67f1493b55505ec5907750722fd43656e4d4.1670461192.git.mirai@HIDDEN>
X-Mailer: git-send-email 2.38.1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 59866
Cc: Bruno Victal <mirai@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

From: Bruno Victal <mirai@HIDDEN>

Introduces 'mpd-plugin' and 'mpd-partition' records.
Expands 'mpd-output' and 'mpd-configuration' records.
Deprecates redundant abbreviated fields in 'mpd-configuration' and
avoids serializing unused fields that may introduce undesired behavior.
Implement log-rotation via rottlog.
Implements Shepherd actions: 'reload' and 'configuration'.
---

Slight oversight, mpd-plugin and mpd-partition record types weren't
being exported.

 doc/guix.texi          | 172 ++++++++++++++---
 gnu/services/audio.scm | 426 ++++++++++++++++++++++++++++++++---------
 2 files changed, 476 insertions(+), 122 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 50487a5172..5a009df240 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@*
 
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -32823,79 +32824,184 @@ 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} (type: maybe-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"})
+@item @code{port} (default: @code{6600}) (type: maybe-integer)
 The port to run mpd on.
 
-@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{addresses} (type: maybe-list-of-string)
+The addresses that mpd will bind to.  To use a Unix domain socket, an
+absolute path 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{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-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
@@ -32907,7 +33013,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 2351db8a4a..07baf8554c 100644
--- a/gnu/services/audio.scm
+++ b/gnu/services/audio.scm
@@ -2,6 +2,7 @@
 ;;; Copyright © 2017 Peter Mikkelsen <petermikkelsen10@HIDDEN>
 ;;; Copyright © 2019 Ricardo Wurmus <rekado@HIDDEN>
 ;;; Copyright © 2020 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2022 Bruno Victal <mirai@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -20,19 +21,26 @@
 
 (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)
   #: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-plugin
+            mpd-plugin?
+            mpd-partition
+            mpd-partition?
             mpd-configuration
             mpd-configuration?
             mpd-service-type))
@@ -51,180 +59,406 @@ (define (uglify-field-name field-name)
                                #\-)
                  "_")))
 
-(define (free-form-args? val)
-  (match val
-    (() #t)
-    ((((? symbol?) . (? string?)) . val) (free-form-args? val))
-    (_ #f)))
+(define list-of-string?
+  (list-of string?))
 
-(define* (mpd-serialize-field field-name value #:optional (indent-level 0))
-  #~(begin
-      (use-modules ((ice-9 format)))
-      (format #f "~v/~a \"~a\"~%" #$indent-level #$(if (string? field-name)
-                                                       field-name
-                                                       (uglify-field-name field-name)) #$value)))
+(define list-of-symbol?
+  (list-of symbol?))
 
-(define* (mpd-serialize-free-form-args field-name value #:optional (indent-level 0))
-  (generic-serialize-alist string-append (cut mpd-serialize-field <> <> indent-level) value))
+(define* (mpd-serialize-field field-name value #:optional (indent-level 0))
+  (let ((field (if (string? field-name) field-name
+                   (uglify-field-name field-name)))
+        (value (if (boolean? value) (if value "yes" "no") value)))
+    #~(begin
+        (use-modules (ice-9 format))
+        (format #f "~v/~a \"~a\"~%" #$indent-level #$field #$value))))
 
 (define mpd-serialize-number mpd-serialize-field)
 
 (define mpd-serialize-string mpd-serialize-field)
 
-(define* (mpd-serialize-boolean field-name value #:optional (indent-level 0))
-  (mpd-serialize-field field-name (if value "yes" "no") indent-level))
+(define mpd-serialize-boolean mpd-serialize-field)
 
-(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-alist field-name value #:optional (indent-level 0))
+  #~(string-append #$@(generic-serialize-alist list (cut mpd-serialize-field <> <> indent-level) value)))
 
-(define (mpd-serialize-configuration configuration)
-  (mixed-text-file
-   "mpd.conf"
-   (serialize-configuration configuration mpd-configuration-fields)))
+(define-maybe string (prefix mpd-))
+(define-maybe list-of-string (prefix mpd-))
 
 (define mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> 1))
 (define mpd-subsystem-serialize-string (cut mpd-serialize-string <> <> 1))
 (define mpd-subsystem-serialize-number (cut mpd-serialize-number <> <> 1))
 (define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean <> <> 1))
-(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize-free-form-args <> <> 1))
+(define mpd-subsystem-serialize-alist (cut mpd-serialize-alist <> <> 1))
+
+(define-maybe string (prefix mpd-subsystem-))
+(define-maybe boolean (prefix mpd-subsystem-))
+
+;;; TODO: Procedures for deprecated fields, to be removed.
+
+(define mpd-deprecated-fields '((music-dir . music-directory)
+                                (playlist-dir . playlist-directory)
+                                (address . addresses)))
+
+(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 field-name 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-subsystem-))
+
+;; Translate <mpd-configuration> field name into block name for mpd.conf"
+(define mpd-subsystem-name
+  (match-lambda
+    ('archive-plugins "archive_plugin")
+    ('playlist-plugins "playlist_plugin")
+    ('inputs "input")
+    ('decoders "decoder")
+    ('filters "filter")
+    (x (symbol->string x))))
+
+(define (mpd-serialize-mpd-plugin field-name value)
+  #~(string-append "\n" #$(mpd-subsystem-name field-name) " {\n"
+                   #$(serialize-configuration value mpd-plugin-fields)
+                   "}\n"))
+
+(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-subsystem-))
+
+(define (mpd-serialize-mpd-partition field-name value)
+  #~(string-append "\npartition {\n"
+                   #$(serialize-configuration value mpd-partition-fields)
+                   "}\n"))
+
+(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
    (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.")
+
+  (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
 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
+   "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
-   (free-form-args '())
-   "An association list of option symbols to string values to be appended to
+   (alist '())
+   "An association list of option symbols/strings to string values to be appended to
 the audio output configuration.")
+
   (prefix mpd-subsystem-))
 
+(define (mpd-serialize-mpd-output field-name value)
+  #~(string-append "\naudio_output {\n"
+                   #$(serialize-configuration value mpd-output-fields)
+                   "}\n"))
+
+(define (mpd-serialize-list-of-mpd-output field-name value)
+  #~(string-append #$@(map (cut mpd-serialize-mpd-output #f <>) value)))
+
 (define list-of-mpd-output?
   (list-of mpd-output?))
 
 (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
+   maybe-string
+   "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)))
-  (playlist-dir
-   (string "~/.mpd/playlists")
+   mpd-serialize-deprecated-field)
+
+  (playlist-directory
+   maybe-string
+   "The directory to store 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")
+   (maybe-port 6600) ; TODO: switch to integer
    "The port to run mpd on.")
-  (address
-   (string "any")
+
+  (addresses
+   maybe-list-of-string
+   "The addresses that mpd will bind to.
+To use a Unix domain socket, an absolute path can be specified here."
+   (lambda (_ x)
+     (if (maybe-value-set? x)
+         #~(string-append #$@(map
+                              (cut mpd-serialize-field "bind_to_address" <>)
+                              x)) "")))
+
+  (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.")
+
+  (archive-plugins
+   (list-of-mpd-plugin '())
+   "List of MPD archive plugin configurations.")
+
+  (input-cache-size
+   maybe-string
+   "MPD input cache size."
    (lambda (_ x)
-     (mpd-serialize-field "bind_to_address" x)))
+     (if (maybe-value-set? x)
+         #~(string-append "\ninput_cache {\n"
+                          #$(mpd-subsystem-serialize-string "size" x)
+                          "}\n") "")))
+
+  (decoders
+   (list-of-mpd-plugin '())
+   "List of MPD decoder plugin configurations.")
+
+  (resampler
+   maybe-mpd-plugin
+   "MPD resampler plugin configuration.")
+
+  (filters
+   (list-of-mpd-plugin '())
+   "List of MPD filter plugin configurations.")
+
   (outputs
    (list-of-mpd-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.")
+
+  (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 <mpd-configuration> (log-file)
+    (log-rotation
+     (files (list log-file))
+     (post-rotate #~(begin
+                      (use-modules (gnu services herd))
+                      (with-shepherd-action 'mpd ('reload) #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))))
+  (match-record config <mpd-configuration> (user package shepherd-requirement)
+    (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 #~(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 'reload)
+               (documentation "Reopen 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-service-activation config)
-  (with-imported-modules '((guix build utils))
+  (match-record config <mpd-configuration> (user log-file)
     #~(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")
+        (let* ((user (getpw #$user))
+               (deprecated-directory (string-append "/var/run/mpd/" #$user "/.mpd"))
+               (new-directory (string-append (passwd:dir user) "/.config/mpd")))
+          ;; TODO: remove me, migrates from the old location at /var/run/mpd to the new one at /var/lib/mpd.
+          (when (and (file-exists? deprecated-directory) (not (file-exists? new-directory)))
+            (rename-file deprecated-directory new-directory)
+            (chown new-directory (passwd:uid user) (passwd:gid user)))
+          (mkdir-p (dirname #$log-file))))))
 
-         (shell (file-append shadow "/sbin/nologin")))))
+(define (mpd-accounts config)
+  (match-record config <mpd-configuration> (user)
+    (list (user-account
+           (name user)
+           (group "nogroup")
+           (system? #t)
+           (comment "Music Player Daemon (MPD) user")
+           (home-directory "/var/lib/mpd")  ; MPD can use $HOME (or $XDG_CONFIG_HOME) to place its data
+           (shell (file-append shadow "/sbin/nologin"))))))
 
 (define mpd-service-type
   (service-type
@@ -234,7 +468,9 @@ (define mpd-service-type
     (list (service-extension shepherd-root-service-type
                              (compose list mpd-shepherd-service))
           (service-extension account-service-type
-                             (const %mpd-accounts))
+                             mpd-accounts)
           (service-extension activation-service-type
-                             mpd-service-activation)))
+                             mpd-service-activation)
+          (service-extension rottlog-service-type
+                             (compose list mpd-log-rotation))))
    (default-value (mpd-configuration))))

base-commit: 81191e3410cc00c6438f532599dd0b96d521982f
prerequisite-patch-id: 3b756bb4d930897ce79b1e51cc25478cb73fd9d8
-- 
2.38.1





Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 7 Dec 2022 18:28:06 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Dec 07 13:28:06 2022
Received: from localhost ([127.0.0.1]:51530 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p2z9K-00086e-Eo
	for submit <at> debbugs.gnu.org; Wed, 07 Dec 2022 13:28:06 -0500
Received: from mail-ej1-f67.google.com ([209.85.218.67]:36631)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <liliana.prikler@HIDDEN>) id 1p2z9H-00086G-AO
 for 59866 <at> debbugs.gnu.org; Wed, 07 Dec 2022 13:28:05 -0500
Received: by mail-ej1-f67.google.com with SMTP id qk9so16058459ejc.3
 for <59866 <at> debbugs.gnu.org>; Wed, 07 Dec 2022 10:28:03 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112;
 h=mime-version:user-agent:content-transfer-encoding:references
 :in-reply-to:date:to:from:subject:message-id:from:to:cc:subject:date
 :message-id:reply-to;
 bh=MiTkz2PzmcVWDGiO+0q5zfX3Gt8gcRLJczq/PGlFZjw=;
 b=YYnJH90wn3wQ+VSKw8rdBFWjoItxC1MI60c+cMJioypE1Lh/66DIYTeY4JY+n6/tBI
 v30SS6JirGyClf0aJHAtrMNj9k2L0u9yldn+mQJEDGr2dScCtJUpDP3RstTX7gdOVAJD
 bdMkq5i0BSTX+h3JjXOUCCtWO6mU8dIQpcs/EoOoSE1vn2wyFxYmWpOnG6uTwVyO5wCI
 rXaUyHLfeRnC0fGKnNafql++s5orfk69Ax+Cga/wQxv2zYCGp5Foyko7wQNQIp9oyoA+
 UkA8bLs5GXoWR/PJruOnb5jjy64gbV0eaQvm/R27no81OUHTtH8VWZpr4QLcJGOciery
 xKmA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20210112;
 h=mime-version:user-agent:content-transfer-encoding:references
 :in-reply-to:date:to:from:subject:message-id:x-gm-message-state:from
 :to:cc:subject:date:message-id:reply-to;
 bh=MiTkz2PzmcVWDGiO+0q5zfX3Gt8gcRLJczq/PGlFZjw=;
 b=eVt5ov7PzwBkN1ktnjDFLQDztiX7U2ITqYWizH5BYbj3DF1TVjMCOY4DVbog5hWjIg
 F7T2V14+iZr/gOMd5Sr7wqnKJ8LZhyB/vbnZhrKwbRgKQfPW64H7WH95LrfZLUQzlyWt
 alHVNVyqNu2pM5WvLU8p4Mfy9ffS2Jj2c/r1E6C0czJZOf16oJEhTSd6v/w8+4j3z/Kl
 D7gQuLJCLJ+X+YLQMEcMN+TEqNel8Dtp8BhxVZmuoBGez1BmY2xNgaKz0uR2fsWXWTFX
 EtV2nHcPOaC9l2Gr9QqMZNV1wr2hNEV9ukjbRGc+owejlcvPbPrOtVaNiEzSS1ug7OLX
 Re0A==
X-Gm-Message-State: ANoB5png6u2BSS0w2trq2pHQKFu96RqkZaRYFeUJH4U2KwpRO8JzXNvi
 UDxomToCf/qpxE7tAXE3KQM=
X-Google-Smtp-Source: AA0mqf6zs7dmneuV5rmwhvwasLsmPRa91F8xlDAQ0jHnJv3OOSDQubCVr+yHhsU97YPbBuQ1NxDvVg==
X-Received: by 2002:a17:906:60c4:b0:7a2:36c7:31ea with SMTP id
 f4-20020a17090660c400b007a236c731eamr62592596ejk.210.1670437677313; 
 Wed, 07 Dec 2022 10:27:57 -0800 (PST)
Received: from lumine.fritz.box (85-127-52-93.dsl.dynamic.surfer.at.
 [85.127.52.93]) by smtp.gmail.com with ESMTPSA id
 x16-20020a170906135000b007b2a58e31dasm4522552ejb.145.2022.12.07.10.27.56
 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
 Wed, 07 Dec 2022 10:27:56 -0800 (PST)
Message-ID: <6e66967984d1bc22d8abf5dd4b07c1a20b4b06ee.camel@HIDDEN>
Subject: Re: [PATCH 0/2] services: mpd: Refactor MPD service
From: Liliana Marie Prikler <liliana.prikler@HIDDEN>
To: mirai@HIDDEN, 59866 <at> debbugs.gnu.org
Date: Wed, 07 Dec 2022 19:27:55 +0100
In-Reply-To: <cover.1670368385.git.mirai@HIDDEN>
References: <cover.1670368385.git.mirai@HIDDEN>
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
User-Agent: Evolution 3.46.0 
MIME-Version: 1.0
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 59866
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Am Dienstag, dem 06.12.2022 um 23:22 +0000 schrieb mirai@HIDDEN:
> Modernizes and expands 'mpd-service-type'.
> Performs "pretty-formatting" to the generated configuration file
> at the cost of a few extra procedures.
> It also deprecates some of the fields (abbreviated forms).
>=20
> Bruno Victal (2):
> =C2=A0 services: mpd: use 'define-configuration'.
> =C2=A0 services: mpd: Refactor MPD service.
Note that there is [1], which attempts to make it so that shepherd
endpoints can be specified in lieu of MPD endpoints.  You don't need to
implement this logic =E2=80=93 you are free to do so if you want to =E2=80=
=93 but could
you make it so that there is an explicit endpoint abstraction that
would allow for extension later on?

Cheers

[1] https://issues.guix.gnu.org/54986




Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 7 Dec 2022 13:43:39 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Dec 07 08:43:39 2022
Received: from localhost ([127.0.0.1]:50439 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p2ui3-0000z3-AU
	for submit <at> debbugs.gnu.org; Wed, 07 Dec 2022 08:43:39 -0500
Received: from knopi.disroot.org ([178.21.23.139]:36064)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <paren@HIDDEN>) id 1p2ui1-0000yx-QS
 for 59866 <at> debbugs.gnu.org; Wed, 07 Dec 2022 08:43:38 -0500
Received: from localhost (localhost [127.0.0.1])
 by disroot.org (Postfix) with ESMTP id 7736D415D7;
 Wed,  7 Dec 2022 14:43:36 +0100 (CET)
X-Virus-Scanned: SPAM Filter at disroot.org
Received: from knopi.disroot.org ([127.0.0.1])
 by localhost (disroot.org [127.0.0.1]) (amavisd-new, port 10024)
 with ESMTP id A5bp9Yf9XSa7; Wed,  7 Dec 2022 14:43:35 +0100 (CET)
Content-Type: multipart/signed;
 boundary=e32b301ad1ff9e6a45a2856c1864b91f421bbf54e3cf71a4577fd67a5325;
 micalg=pgp-sha512; protocol="application/pgp-signature"
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=disroot.org; s=mail;
 t=1670420615; bh=Ssz1h51TTFIxyStFf76GwZFlrKD0R/Xa5xPY17TkN4M=;
 h=Date:Subject:From:To:References:In-Reply-To;
 b=HsF13kvuQggeU85cF0vawyU7xwMv4O8DB51XRitUH6Czm1uyjGn8IHw/8iJIQhaKZ
 xzjX6iIEQmaJecdTM4Ai96doNsQwig5wBvrGuxdNmiCFczRvPgCC3WI2SBipdKUf5L
 Wic6zfbCr9f34MnNfH4YLvjrHLml8TkS/R454X2bgYrXYgklykeqbyBfOCrqr6L7+K
 b3uxw4tasp1s/L3eKRmWRhBi86PGYLQYqNElTbW875siQZYK+dsDlzSdk2bhuSsjCR
 VFdZ312oN5Vgu9XEfDsdbqqKGSSx6Th4FxEY/5g3mMe1i55d0bN09nE0qw3KDprW3e
 9KpPU3PXDkwSg==
Date: Wed, 07 Dec 2022 13:43:31 +0000
Message-Id: <COVMOR39ORBF.1UPCUSAICLT6L@guix-framework>
Subject: Re: [bug#59866] [PATCH 0/2] services: mpd: Refactor MPD service
From: "(" <paren@HIDDEN>
To: "mirai" <mirai@HIDDEN>, <59866 <at> debbugs.gnu.org>
References: <cover.1670368385.git.mirai@HIDDEN>
 <COVGN7KIK265.2AP7SD2GJ0Y4H@guix-framework>
 <f0eabd03-9523-efca-0399-b7cb3e852ed1@HIDDEN>
In-Reply-To: <f0eabd03-9523-efca-0399-b7cb3e852ed1@HIDDEN>
X-Spam-Score: 0.1 (/)
X-Debbugs-Envelope-To: 59866
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -0.9 (/)

--e32b301ad1ff9e6a45a2856c1864b91f421bbf54e3cf71a4577fd67a5325
Mime-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=UTF-8

Heya,

On Wed Dec 7, 2022 at 1:42 PM GMT, mirai wrote:
> It already does! The second commit introduces the bulk of the changes :)

Oops :) Reviewing now...

    -- (

--e32b301ad1ff9e6a45a2856c1864b91f421bbf54e3cf71a4577fd67a5325
Content-Type: application/pgp-signature; name="signature.asc"

-----BEGIN PGP SIGNATURE-----

iQGzBAABCgAdFiEE6Vh10NblKE5doNlW7ImHg/nqI20FAmOQmIQACgkQ7ImHg/nq
I23rXQv+JkbnxdWrWh17sL1WfjnKBfw1dbwDR5EOcwt3gyH95DYX0L8EtxWv1kwH
fnV+ZYIu1W1/gqrrkNWAWcXqIFliZjL7wmPIqxE4QdJ0eB9/QVLvp6Cx6nLsuYAK
TDVZUBLbKHgKIQlKR9dIyPILEgKxHW7E1x0lnaOda86KeiPerUyG3BEx/KbIqm92
Txk9agDrNVc3+vS+cyhgtnf0LvIw4CgMg19UjhZwOGm/n+/iPjtTysmwEbU3ZobP
Mv3LQR97LqOlc0UBjWy4wmKRSXigI8mR53D1nz0A8pcSElTIFCD/2nfcl3dRg7GH
fDbPpUHW3qGwHiLKX7supcu8ge/LMcNJpdHbtxUFrroegI6ODGHyuKfo5wodc7mn
wRuvTVWsXpunRl9V9/NyZO40ao43a54VYOXeKTSBXunGlqIh4uRhPjSTD+EWT4hv
7FBLcU8OXDj2j9mAAHzUEnWZMJgsDhcjcpixxRSb2Hvorpi5/nmXuAR6XM8dZ8+Y
YcDJ81Qn
=3VPs
-----END PGP SIGNATURE-----

--e32b301ad1ff9e6a45a2856c1864b91f421bbf54e3cf71a4577fd67a5325--




Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 7 Dec 2022 13:43:02 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Dec 07 08:43:02 2022
Received: from localhost ([127.0.0.1]:50436 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p2uhS-0000yb-1d
	for submit <at> debbugs.gnu.org; Wed, 07 Dec 2022 08:43:02 -0500
Received: from smtpm5.myservices.hosting ([185.26.105.236]:34812)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mirai@HIDDEN>) id 1p2uhQ-0000yP-SC
 for 59866 <at> debbugs.gnu.org; Wed, 07 Dec 2022 08:43:01 -0500
Received: from mail1.netim.hosting (unknown [185.26.106.172])
 by smtpm5.myservices.hosting (Postfix) with ESMTP id 9A4EA20C90;
 Wed,  7 Dec 2022 14:42:57 +0100 (CET)
Received: from localhost (localhost [127.0.0.1])
 by mail1.netim.hosting (Postfix) with ESMTP id 34ED380099;
 Wed,  7 Dec 2022 14:42:57 +0100 (CET)
X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting
Received: from mail1.netim.hosting ([127.0.0.1])
 by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id EgFTmrhw9hV7; Wed,  7 Dec 2022 14:42:56 +0100 (CET)
Received: from [192.168.1.239] (unknown [10.192.1.83])
 (Authenticated sender: lumen@HIDDEN)
 by mail1.netim.hosting (Postfix) with ESMTPSA id 0BABF8009B;
 Wed,  7 Dec 2022 14:42:53 +0100 (CET)
Message-ID: <f0eabd03-9523-efca-0399-b7cb3e852ed1@HIDDEN>
Date: Wed, 7 Dec 2022 13:42:53 +0000
MIME-Version: 1.0
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
 Thunderbird/102.5.1
Subject: Re: [bug#59866] [PATCH 0/2] services: mpd: Refactor MPD service
Content-Language: en-US
To: "(" <paren@HIDDEN>, 59866 <at> debbugs.gnu.org
References: <cover.1670368385.git.mirai@HIDDEN>
 <COVGN7KIK265.2AP7SD2GJ0Y4H@guix-framework>
From: mirai <mirai@HIDDEN>
In-Reply-To: <COVGN7KIK265.2AP7SD2GJ0Y4H@guix-framework>
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 59866
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

It already does! The second commit introduces the bulk of the changes :)

On 2022-12-07 08:59, ( wrote:
> On Tue Dec 6, 2022 at 11:22 PM GMT,  wrote:
>> Modernizes and expands 'mpd-service-type'.
>> Performs "pretty-formatting" to the generated configuration file
>> at the cost of a few extra procedures.
>> It also deprecates some of the fields (abbreviated forms).
>>
>> Bruno Victal (2):
>>   services: mpd: use 'define-configuration'.
>>   services: mpd: Refactor MPD service.
>>
>>  doc/guix.texi          | 172 +++++++++++--
>>  gnu/services/audio.scm | 549 ++++++++++++++++++++++++++++++-----------
>>  2 files changed, 556 insertions(+), 165 deletions(-)
>>
>>
>> base-commit: b94724e8b2102be0fe9d19e9dfe44d6f7101bd4b
>> -- 
>> 2.38.1
> 
> Could you also add support for ``herd configuration'' (added in #59197)?
>     -- (




Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 7 Dec 2022 08:59:35 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Dec 07 03:59:35 2022
Received: from localhost ([127.0.0.1]:48600 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p2qH8-00016K-VL
	for submit <at> debbugs.gnu.org; Wed, 07 Dec 2022 03:59:35 -0500
Received: from knopi.disroot.org ([178.21.23.139]:36624)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <paren@HIDDEN>) id 1p2qH6-00016D-5J
 for 59866 <at> debbugs.gnu.org; Wed, 07 Dec 2022 03:59:34 -0500
Received: from localhost (localhost [127.0.0.1])
 by disroot.org (Postfix) with ESMTP id 55C1641538;
 Wed,  7 Dec 2022 09:59:30 +0100 (CET)
X-Virus-Scanned: SPAM Filter at disroot.org
Received: from knopi.disroot.org ([127.0.0.1])
 by localhost (disroot.org [127.0.0.1]) (amavisd-new, port 10024)
 with ESMTP id 9ckLy6OFx9ap; Wed,  7 Dec 2022 09:59:29 +0100 (CET)
Content-Type: multipart/signed;
 boundary=ebfb761bd772cd1ac06eff68deb9d259b32f60dd8881b365ba10025ca77e;
 micalg=pgp-sha512; protocol="application/pgp-signature"
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=disroot.org; s=mail;
 t=1670403569; bh=7n0BmylC3oc8H39zfidTICQ/FQ07oTFmw65oEaZQ/ak=;
 h=Date:Subject:From:To:References:In-Reply-To;
 b=Uosy3vJ+YOcbmlGpGE5CYf+CwNuJh7VY1ZJEuI12g96TfM5fAWsLLAyGsKvILIuAf
 AYqW4HlaMl3Xg2HQ2xuzvN0QJaOQIejEYXfAVUQJ3szgb+4PmjO7w/FrIHgmyvkOSC
 el2zVJiCxz07D1i+Vs6EvNzVw2pTs4f/mc4tsdrWqCUdjEbAJqjsutnlHMUqRTGHjz
 sDwNGbM0bX25Pa3UgCGbWyd5wFTf7fCYEL1Pj4TNgMDAXyiX4qaChPQHNwUrsioJUP
 VjY10KkZTwreZCbRCfte1yv0uqyDFVMwEAKVtChOGiLVKhnEuhKlWFy8YCeZs+iU3e
 fwkiTDWGx1tSg==
Date: Wed, 07 Dec 2022 08:59:23 +0000
Message-Id: <COVGN7KIK265.2AP7SD2GJ0Y4H@guix-framework>
Subject: Re: [bug#59866] [PATCH 0/2] services: mpd: Refactor MPD service
From: "(" <paren@HIDDEN>
To: <mirai@HIDDEN>, <59866 <at> debbugs.gnu.org>
References: <cover.1670368385.git.mirai@HIDDEN>
In-Reply-To: <cover.1670368385.git.mirai@HIDDEN>
X-Spam-Score: 0.1 (/)
X-Debbugs-Envelope-To: 59866
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -0.9 (/)

--ebfb761bd772cd1ac06eff68deb9d259b32f60dd8881b365ba10025ca77e
Mime-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=UTF-8

On Tue Dec 6, 2022 at 11:22 PM GMT,  wrote:
> Modernizes and expands 'mpd-service-type'.
> Performs "pretty-formatting" to the generated configuration file
> at the cost of a few extra procedures.
> It also deprecates some of the fields (abbreviated forms).
>
> Bruno Victal (2):
>   services: mpd: use 'define-configuration'.
>   services: mpd: Refactor MPD service.
>
>  doc/guix.texi          | 172 +++++++++++--
>  gnu/services/audio.scm | 549 ++++++++++++++++++++++++++++++-----------
>  2 files changed, 556 insertions(+), 165 deletions(-)
>
>
> base-commit: b94724e8b2102be0fe9d19e9dfe44d6f7101bd4b
> --=20
> 2.38.1

Could you also add support for ``herd configuration'' (added in #59197)?
    -- (

--ebfb761bd772cd1ac06eff68deb9d259b32f60dd8881b365ba10025ca77e
Content-Type: application/pgp-signature; name="signature.asc"

-----BEGIN PGP SIGNATURE-----

iQGzBAABCgAdFiEE6Vh10NblKE5doNlW7ImHg/nqI20FAmOQVewACgkQ7ImHg/nq
I23FbQv/e6N7SbmFcjqJ7eAs3eNcwtP3FfMLxIqkFAKqi3IVJwQpyHY+J+OmQA4q
TEE1FBmM+nPJ1J/XG/ahHh2ACOULT9YZPaEwsndZQEPyoUr/cbdFQ9k0J0GNG62+
hcwEmlGpHRCAR4T1gjFj7hqvlI6Gt/S/kjG8Mygnj7Q82qv4V4LJcjbRf4Q8F4Q5
15EYjvPQRfFdgT0rm9QYQU1YX/qOCX4aIiZGPkETV3i9J6bPSghtjcXQgbX4WzzS
6T0HEIIOOeJPNf4lJ+DH+N5m3iLxKe+PTZJ2owpihymyE5YeUhGRoGk664MzNSmG
wuXaFMQdSJFQ8zDqywkTGMy834OA7ZXxNvScVtYBVJmuCh1Vj6k2KRJbsdpoDYws
w3dQW1NF29ijChDsu7lO9RViMIf6gatb/xz/UitrR0EFe9i0UFAGM9hMgwG5s1yE
yCFnogLZkxCStbEi599Jx2kwe8wnphqn3yZvm5L1jqmrOZgpwmLAASBbC68hZFug
8j/MIRxB
=2UDc
-----END PGP SIGNATURE-----

--ebfb761bd772cd1ac06eff68deb9d259b32f60dd8881b365ba10025ca77e--




Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 6 Dec 2022 23:25:42 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Dec 06 18:25:42 2022
Received: from localhost ([127.0.0.1]:45759 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p2hJk-0000qK-QQ
	for submit <at> debbugs.gnu.org; Tue, 06 Dec 2022 18:25:42 -0500
Received: from smtpm5.myservices.hosting ([185.26.105.236]:44784)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mirai@HIDDEN>) id 1p2hJh-0000qE-Bi
 for 59866 <at> debbugs.gnu.org; Tue, 06 Dec 2022 18:25:39 -0500
Received: from mail1.netim.hosting (unknown [185.26.106.172])
 by smtpm5.myservices.hosting (Postfix) with ESMTP id B4BD720CFC
 for <59866 <at> debbugs.gnu.org>; Wed,  7 Dec 2022 00:25:36 +0100 (CET)
Received: from localhost (localhost [127.0.0.1])
 by mail1.netim.hosting (Postfix) with ESMTP id 6064280096;
 Wed,  7 Dec 2022 00:25:36 +0100 (CET)
X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting
Received: from mail1.netim.hosting ([127.0.0.1])
 by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id 8Yz3X4RiMOQf; Wed,  7 Dec 2022 00:25:35 +0100 (CET)
Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156])
 (Authenticated sender: lumen@HIDDEN)
 by mail1.netim.hosting (Postfix) with ESMTPSA id A621980093;
 Wed,  7 Dec 2022 00:25:34 +0100 (CET)
From: mirai@HIDDEN
To: 59866 <at> debbugs.gnu.org
Subject: [PATCH 2/2] services: mpd: Refactor MPD service.
Date: Tue,  6 Dec 2022 23:25:17 +0000
Message-Id: <fd87503ea39dc6ad730e5dbf7156887924a64624.1670368385.git.mirai@HIDDEN>
X-Mailer: git-send-email 2.38.1
In-Reply-To: <cover.1670368385.git.mirai@HIDDEN>
References: <cover.1670368385.git.mirai@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 59866
Cc: Bruno Victal <mirai@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

From: Bruno Victal <mirai@HIDDEN>

Introduces 'mpd-plugin' and 'mpd-partition' records.
Expands 'mpd-output' and 'mpd-configuration' records.
Deprecates redundant abbreviated fields in 'mpd-configuration' and
avoids serializing unused fields that may introduce undesired behavior.
Implement log-rotation via rottlog.
Implements Shepherd actions: 'reload' and 'configuration'.
---
 doc/guix.texi          | 172 ++++++++++++++---
 gnu/services/audio.scm | 422 +++++++++++++++++++++++++++++++----------
 2 files changed, 472 insertions(+), 122 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index a79b777826..0408cab1cb 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@*
 
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -32823,79 +32824,184 @@ 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} (type: maybe-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"})
+@item @code{port} (default: @code{6600}) (type: maybe-integer)
 The port to run mpd on.
 
-@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{addresses} (type: maybe-list-of-string)
+The addresses that mpd will bind to.  To use a Unix domain socket, an
+absolute path 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{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-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
@@ -32907,7 +33013,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 2351db8a4a..b0587e0d3c 100644
--- a/gnu/services/audio.scm
+++ b/gnu/services/audio.scm
@@ -2,6 +2,7 @@
 ;;; Copyright © 2017 Peter Mikkelsen <petermikkelsen10@HIDDEN>
 ;;; Copyright © 2019 Ricardo Wurmus <rekado@HIDDEN>
 ;;; Copyright © 2020 Ludovic Courtès <ludo@HIDDEN>
+;;; Copyright © 2022 Bruno Victal <mirai@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -20,15 +21,18 @@
 
 (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)
   #: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
@@ -51,180 +55,406 @@ (define (uglify-field-name field-name)
                                #\-)
                  "_")))
 
-(define (free-form-args? val)
-  (match val
-    (() #t)
-    ((((? symbol?) . (? string?)) . val) (free-form-args? val))
-    (_ #f)))
+(define list-of-string?
+  (list-of string?))
 
-(define* (mpd-serialize-field field-name value #:optional (indent-level 0))
-  #~(begin
-      (use-modules ((ice-9 format)))
-      (format #f "~v/~a \"~a\"~%" #$indent-level #$(if (string? field-name)
-                                                       field-name
-                                                       (uglify-field-name field-name)) #$value)))
+(define list-of-symbol?
+  (list-of symbol?))
 
-(define* (mpd-serialize-free-form-args field-name value #:optional (indent-level 0))
-  (generic-serialize-alist string-append (cut mpd-serialize-field <> <> indent-level) value))
+(define* (mpd-serialize-field field-name value #:optional (indent-level 0))
+  (let ((field (if (string? field-name) field-name
+                   (uglify-field-name field-name)))
+        (value (if (boolean? value) (if value "yes" "no") value)))
+    #~(begin
+        (use-modules (ice-9 format))
+        (format #f "~v/~a \"~a\"~%" #$indent-level #$field #$value))))
 
 (define mpd-serialize-number mpd-serialize-field)
 
 (define mpd-serialize-string mpd-serialize-field)
 
-(define* (mpd-serialize-boolean field-name value #:optional (indent-level 0))
-  (mpd-serialize-field field-name (if value "yes" "no") indent-level))
+(define mpd-serialize-boolean mpd-serialize-field)
 
-(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-alist field-name value #:optional (indent-level 0))
+  #~(string-append #$@(generic-serialize-alist list (cut mpd-serialize-field <> <> indent-level) value)))
 
-(define (mpd-serialize-configuration configuration)
-  (mixed-text-file
-   "mpd.conf"
-   (serialize-configuration configuration mpd-configuration-fields)))
+(define-maybe string (prefix mpd-))
+(define-maybe list-of-string (prefix mpd-))
 
 (define mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> 1))
 (define mpd-subsystem-serialize-string (cut mpd-serialize-string <> <> 1))
 (define mpd-subsystem-serialize-number (cut mpd-serialize-number <> <> 1))
 (define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean <> <> 1))
-(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize-free-form-args <> <> 1))
+(define mpd-subsystem-serialize-alist (cut mpd-serialize-alist <> <> 1))
+
+(define-maybe string (prefix mpd-subsystem-))
+(define-maybe boolean (prefix mpd-subsystem-))
+
+;;; TODO: Procedures for deprecated fields, to be removed.
+
+(define mpd-deprecated-fields '((music-dir . music-directory)
+                                (playlist-dir . playlist-directory)
+                                (address . addresses)))
+
+(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 field-name 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-subsystem-))
+
+;; Translate <mpd-configuration> field name into block name for mpd.conf"
+(define mpd-subsystem-name
+  (match-lambda
+    ('archive-plugins "archive_plugin")
+    ('playlist-plugins "playlist_plugin")
+    ('inputs "input")
+    ('decoders "decoder")
+    ('filters "filter")
+    (x (symbol->string x))))
+
+(define (mpd-serialize-mpd-plugin field-name value)
+  #~(string-append "\n" #$(mpd-subsystem-name field-name) " {\n"
+                   #$(serialize-configuration value mpd-plugin-fields)
+                   "}\n"))
+
+(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-subsystem-))
+
+(define (mpd-serialize-mpd-partition field-name value)
+  #~(string-append "\npartition {\n"
+                   #$(serialize-configuration value mpd-partition-fields)
+                   "}\n"))
+
+(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
    (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.")
+
+  (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
 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
+   "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
-   (free-form-args '())
-   "An association list of option symbols to string values to be appended to
+   (alist '())
+   "An association list of option symbols/strings to string values to be appended to
 the audio output configuration.")
+
   (prefix mpd-subsystem-))
 
+(define (mpd-serialize-mpd-output field-name value)
+  #~(string-append "\naudio_output {\n"
+                   #$(serialize-configuration value mpd-output-fields)
+                   "}\n"))
+
+(define (mpd-serialize-list-of-mpd-output field-name value)
+  #~(string-append #$@(map (cut mpd-serialize-mpd-output #f <>) value)))
+
 (define list-of-mpd-output?
   (list-of mpd-output?))
 
 (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
+   maybe-string
+   "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)))
-  (playlist-dir
-   (string "~/.mpd/playlists")
+   mpd-serialize-deprecated-field)
+
+  (playlist-directory
+   maybe-string
+   "The directory to store 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")
+   (maybe-port 6600) ; TODO: switch to integer
    "The port to run mpd on.")
-  (address
-   (string "any")
+
+  (addresses
+   maybe-list-of-string
+   "The addresses that mpd will bind to.
+To use a Unix domain socket, an absolute path can be specified here."
+   (lambda (_ x)
+     (if (maybe-value-set? x)
+         #~(string-append #$@(map
+                              (cut mpd-serialize-field "bind_to_address" <>)
+                              x)) "")))
+
+  (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.")
+
+  (archive-plugins
+   (list-of-mpd-plugin '())
+   "List of MPD archive plugin configurations.")
+
+  (input-cache-size
+   maybe-string
+   "MPD input cache size."
    (lambda (_ x)
-     (mpd-serialize-field "bind_to_address" x)))
+     (if (maybe-value-set? x)
+         #~(string-append "\ninput_cache {\n"
+                          #$(mpd-subsystem-serialize-string "size" x)
+                          "}\n") "")))
+
+  (decoders
+   (list-of-mpd-plugin '())
+   "List of MPD decoder plugin configurations.")
+
+  (resampler
+   maybe-mpd-plugin
+   "MPD resampler plugin configuration.")
+
+  (filters
+   (list-of-mpd-plugin '())
+   "List of MPD filter plugin configurations.")
+
   (outputs
    (list-of-mpd-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.")
+
+  (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 <mpd-configuration> (log-file)
+    (log-rotation
+     (files (list log-file))
+     (post-rotate #~(begin
+                      (use-modules (gnu services herd))
+                      (with-shepherd-action 'mpd ('reload) #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))))
+  (match-record config <mpd-configuration> (user package shepherd-requirement)
+    (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 #~(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 'reload)
+               (documentation "Reopen 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-service-activation config)
-  (with-imported-modules '((guix build utils))
+  (match-record config <mpd-configuration> (user log-file)
     #~(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")
+        (let* ((user (getpw #$user))
+               (deprecated-directory (string-append "/var/run/mpd/" #$user "/.mpd"))
+               (new-directory (string-append (passwd:dir user) "/.config/mpd")))
+          ;; TODO: remove me, migrates from the old location at /var/run/mpd to the new one at /var/lib/mpd.
+          (when (and (file-exists? deprecated-directory) (not (file-exists? new-directory)))
+            (rename-file deprecated-directory new-directory)
+            (chown new-directory (passwd:uid user) (passwd:gid user)))
+          (mkdir-p (dirname #$log-file))))))
 
-         (shell (file-append shadow "/sbin/nologin")))))
+(define (mpd-accounts config)
+  (match-record config <mpd-configuration> (user)
+    (list (user-account
+           (name user)
+           (group "nogroup")
+           (system? #t)
+           (comment "Music Player Daemon (MPD) user")
+           (home-directory "/var/lib/mpd")  ; MPD can use $HOME (or $XDG_CONFIG_HOME) to place its data
+           (shell (file-append shadow "/sbin/nologin"))))))
 
 (define mpd-service-type
   (service-type
@@ -234,7 +464,9 @@ (define mpd-service-type
     (list (service-extension shepherd-root-service-type
                              (compose list mpd-shepherd-service))
           (service-extension account-service-type
-                             (const %mpd-accounts))
+                             mpd-accounts)
           (service-extension activation-service-type
-                             mpd-service-activation)))
+                             mpd-service-activation)
+          (service-extension rottlog-service-type
+                             (compose list mpd-log-rotation))))
    (default-value (mpd-configuration))))
-- 
2.38.1





Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at 59866 <at> debbugs.gnu.org:


Received: (at 59866) by debbugs.gnu.org; 6 Dec 2022 23:25:35 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Dec 06 18:25:35 2022
Received: from localhost ([127.0.0.1]:45755 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p2hJf-0000q7-5U
	for submit <at> debbugs.gnu.org; Tue, 06 Dec 2022 18:25:35 -0500
Received: from smtpm4.myservices.hosting ([185.26.105.235]:59584)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mirai@HIDDEN>) id 1p2hJd-0000q1-HR
 for 59866 <at> debbugs.gnu.org; Tue, 06 Dec 2022 18:25:34 -0500
Received: from mail1.netim.hosting (unknown [185.26.106.172])
 by smtpm4.myservices.hosting (Postfix) with ESMTP id ACB4220555
 for <59866 <at> debbugs.gnu.org>; Wed,  7 Dec 2022 00:25:32 +0100 (CET)
Received: from localhost (localhost [127.0.0.1])
 by mail1.netim.hosting (Postfix) with ESMTP id 60E0380097;
 Wed,  7 Dec 2022 00:25:32 +0100 (CET)
X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting
Received: from mail1.netim.hosting ([127.0.0.1])
 by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id 7IKKuLBZjI1B; Wed,  7 Dec 2022 00:25:31 +0100 (CET)
Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156])
 (Authenticated sender: lumen@HIDDEN)
 by mail1.netim.hosting (Postfix) with ESMTPSA id 9C2DA80096;
 Wed,  7 Dec 2022 00:25:31 +0100 (CET)
From: mirai@HIDDEN
To: 59866 <at> debbugs.gnu.org
Subject: [PATCH 1/2] services: mpd: use 'define-configuration'.
Date: Tue,  6 Dec 2022 23:25:16 +0000
Message-Id: <bd3ba0e684224d42c4a56b427ec3022a8c50fe38.1670368385.git.mirai@HIDDEN>
X-Mailer: git-send-email 2.38.1
In-Reply-To: <cover.1670368385.git.mirai@HIDDEN>
References: <cover.1670368385.git.mirai@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 59866
Cc: Bruno Victal <mirai@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

From: Bruno Victal <mirai@HIDDEN>

---
 gnu/services/audio.scm | 217 ++++++++++++++++++++++++-----------------
 1 file changed, 129 insertions(+), 88 deletions(-)

diff --git a/gnu/services/audio.scm b/gnu/services/audio.scm
index c60053f33c..2351db8a4a 100644
--- a/gnu/services/audio.scm
+++ b/gnu/services/audio.scm
@@ -21,6 +21,7 @@
 (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)
@@ -28,6 +29,8 @@ (define-module (gnu services audio)
   #: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,131 @@ (define-module (gnu services audio)
 ;;;
 ;;; Code:
 
-(define-record-type* <mpd-output>
-  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>
-  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 <mpd-output> 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 (free-form-args? val)
+  (match val
+    (() #t)
+    ((((? symbol?) . (? string?)) . val) (free-form-args? val))
+    (_ #f)))
+
+(define* (mpd-serialize-field field-name value #:optional (indent-level 0))
+  #~(begin
+      (use-modules ((ice-9 format)))
+      (format #f "~v/~a \"~a\"~%" #$indent-level #$(if (string? field-name)
+                                                       field-name
+                                                       (uglify-field-name field-name)) #$value)))
+
+(define* (mpd-serialize-free-form-args field-name value #:optional (indent-level 0))
+  (generic-serialize-alist string-append (cut mpd-serialize-field <> <> indent-level) value))
+
+(define mpd-serialize-number mpd-serialize-field)
+
+(define mpd-serialize-string mpd-serialize-field)
+
+(define* (mpd-serialize-boolean field-name value #:optional (indent-level 0))
+  (mpd-serialize-field field-name (if value "yes" "no") indent-level))
+
+(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 mpd-subsystem-serialize-field (cut mpd-serialize-field <> <> 1))
+(define mpd-subsystem-serialize-string (cut mpd-serialize-string <> <> 1))
+(define mpd-subsystem-serialize-number (cut mpd-serialize-number <> <> 1))
+(define mpd-subsystem-serialize-boolean (cut mpd-serialize-boolean <> <> 1))
+(define mpd-subsystem-serialize-free-form-args (cut mpd-serialize-free-form-args <> <> 1))
+
+(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
+   (free-form-args '())
+   "An association list of option symbols to string values to be appended to
+the audio output configuration.")
+  (prefix mpd-subsystem-))
+
+(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 +184,7 @@ (define (mpd-shepherd-service config)
    (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
-- 
2.38.1





Information forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.

Message received at submit <at> debbugs.gnu.org:


Received: (at submit) by debbugs.gnu.org; 6 Dec 2022 23:23:24 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Dec 06 18:23:23 2022
Received: from localhost ([127.0.0.1]:45740 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1p2hHX-0000of-NB
	for submit <at> debbugs.gnu.org; Tue, 06 Dec 2022 18:23:23 -0500
Received: from lists.gnu.org ([209.51.188.17]:58510)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mirai@HIDDEN>) id 1p2hHV-0000oZ-9e
 for submit <at> debbugs.gnu.org; Tue, 06 Dec 2022 18:23:22 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <mirai@HIDDEN>) id 1p2hHV-000742-22
 for guix-patches@HIDDEN; Tue, 06 Dec 2022 18:23:21 -0500
Received: from smtpm2.myservices.hosting ([185.26.105.233])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <mirai@HIDDEN>) id 1p2hHT-00043l-2n
 for guix-patches@HIDDEN; Tue, 06 Dec 2022 18:23:20 -0500
Received: from mail1.netim.hosting (unknown [185.26.106.172])
 by smtpm2.myservices.hosting (Postfix) with ESMTP id 771A920D63
 for <guix-patches@HIDDEN>; Wed,  7 Dec 2022 00:23:15 +0100 (CET)
Received: from localhost (localhost [127.0.0.1])
 by mail1.netim.hosting (Postfix) with ESMTP id 213F480097;
 Wed,  7 Dec 2022 00:23:15 +0100 (CET)
X-Virus-Scanned: Debian amavisd-new at mail1.netim.hosting
Received: from mail1.netim.hosting ([127.0.0.1])
 by localhost (mail1-1.netim.hosting [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id gnzJf-MHdcfJ; Wed,  7 Dec 2022 00:23:14 +0100 (CET)
Received: from guix-nuc.home.arpa (bl12-93-156.dsl.telepac.pt [85.245.93.156])
 (Authenticated sender: lumen@HIDDEN)
 by mail1.netim.hosting (Postfix) with ESMTPSA id B91CE80093;
 Wed,  7 Dec 2022 00:23:13 +0100 (CET)
From: mirai@HIDDEN
To: guix-patches@HIDDEN
Subject: [PATCH 0/2] services: mpd: Refactor MPD service
Date: Tue,  6 Dec 2022 23:22:16 +0000
Message-Id: <cover.1670368385.git.mirai@HIDDEN>
X-Mailer: git-send-email 2.38.1
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
Received-SPF: pass client-ip=185.26.105.233; envelope-from=mirai@HIDDEN;
 helo=smtpm2.myservices.hosting
X-Spam_score_int: -18
X-Spam_score: -1.9
X-Spam_bar: -
X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_NONE=0.001,
 SPF_PASS=-0.001 autolearn=ham autolearn_force=no
X-Spam_action: no action
X-Spam-Score: -1.3 (-)
X-Debbugs-Envelope-To: submit
Cc: mirai@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -2.3 (--)

Modernizes and expands 'mpd-service-type'.
Performs "pretty-formatting" to the generated configuration file
at the cost of a few extra procedures.
It also deprecates some of the fields (abbreviated forms).

Bruno Victal (2):
  services: mpd: use 'define-configuration'.
  services: mpd: Refactor MPD service.

 doc/guix.texi          | 172 +++++++++++--
 gnu/services/audio.scm | 549 ++++++++++++++++++++++++++++++-----------
 2 files changed, 556 insertions(+), 165 deletions(-)


base-commit: b94724e8b2102be0fe9d19e9dfe44d6f7101bd4b
-- 
2.38.1





Acknowledgement sent to mirai@HIDDEN:
New bug report received and forwarded. Copy sent to guix-patches@HIDDEN. Full text available.
Report forwarded to guix-patches@HIDDEN:
bug#59866; Package guix-patches. Full text available.
Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.
Last modified: Thu, 2 Feb 2023 20:15:01 UTC

GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997 nCipher Corporation Ltd, 1994-97 Ian Jackson.