2017-12-21 17:16:19 +01:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
|
2014-04-02 18:21:00 +02:00
|
|
|
let
|
|
|
|
cfg = config.programs.dconf;
|
2023-06-14 10:22:17 +02:00
|
|
|
|
2023-08-15 11:58:02 +02:00
|
|
|
# Compile keyfiles to dconf DB
|
|
|
|
compileDconfDb = dir: pkgs.runCommand "dconf-db"
|
|
|
|
{
|
|
|
|
nativeBuildInputs = [ (lib.getBin pkgs.dconf) ];
|
|
|
|
} "dconf compile $out ${dir}";
|
|
|
|
|
|
|
|
# Check if dconf keyfiles are valid
|
|
|
|
checkDconfKeyfiles = dir: pkgs.runCommand "check-dconf-keyfiles"
|
|
|
|
{
|
|
|
|
nativeBuildInputs = [ (lib.getBin pkgs.dconf) ];
|
|
|
|
} ''
|
|
|
|
if [[ -f ${dir} ]]; then
|
|
|
|
echo "dconf keyfiles should be a directory but a file is provided: ${dir}"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
dconf compile db ${dir} || (
|
|
|
|
echo "The dconf keyfiles are invalid: ${dir}"
|
|
|
|
exit 1
|
|
|
|
)
|
|
|
|
cp -R ${dir} $out
|
|
|
|
'';
|
|
|
|
|
2023-06-14 10:27:19 +02:00
|
|
|
mkAllLocks = settings: lib.flatten (
|
|
|
|
lib.mapAttrsToList (k: v: lib.mapAttrsToList (k': _: "/${k}/${k'}") v) settings);
|
|
|
|
|
2023-08-15 11:58:02 +02:00
|
|
|
# Generate dconf DB from dconfDatabase and keyfiles
|
|
|
|
mkDconfDb = val: compileDconfDb (pkgs.symlinkJoin {
|
|
|
|
name = "nixos-generated-dconf-keyfiles";
|
|
|
|
paths = [
|
|
|
|
(pkgs.writeTextDir "nixos-generated-dconf-keyfiles" (lib.generators.toDconfINI val.settings))
|
2023-06-14 10:27:19 +02:00
|
|
|
(pkgs.writeTextDir "locks/nixos-generated-dconf-locks" (lib.concatStringsSep "\n"
|
|
|
|
(if val.lockAll then mkAllLocks val.settings else val.locks)
|
|
|
|
))
|
2023-08-15 11:58:02 +02:00
|
|
|
] ++ (map checkDconfKeyfiles val.keyfiles);
|
|
|
|
});
|
|
|
|
|
|
|
|
# Check if a dconf DB file is valid. The dconf cli doesn't return 1 when it can't
|
|
|
|
# open the database file so we have to check if the output is empty.
|
|
|
|
checkDconfDb = file: pkgs.runCommand "check-dconf-db"
|
|
|
|
{
|
|
|
|
nativeBuildInputs = [ (lib.getBin pkgs.dconf) ];
|
|
|
|
} ''
|
|
|
|
if [[ -d ${file} ]]; then
|
|
|
|
echo "dconf DB should be a file but a directory is provided: ${file}"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo "file-db:${file}" > profile
|
|
|
|
DCONF_PROFILE=$(pwd)/profile dconf dump / > output 2> error
|
|
|
|
if [[ ! -s output ]] && [[ -s error ]]; then
|
|
|
|
cat error
|
|
|
|
echo "The dconf DB file is invalid: ${file}"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
cp ${file} $out
|
|
|
|
'';
|
|
|
|
|
2023-06-14 10:22:17 +02:00
|
|
|
# Generate dconf profile
|
|
|
|
mkDconfProfile = name: value:
|
2023-08-15 11:58:02 +02:00
|
|
|
if lib.isDerivation value || lib.isPath value then
|
|
|
|
pkgs.runCommand "dconf-profile" { } ''
|
|
|
|
if [[ -d ${value} ]]; then
|
|
|
|
echo "Dconf profile should be a file but a directory is provided."
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
mkdir -p $out/etc/dconf/profile/
|
|
|
|
cp ${value} $out/etc/dconf/profile/${name}
|
|
|
|
''
|
|
|
|
else
|
|
|
|
pkgs.writeTextDir "etc/dconf/profile/${name}" (
|
|
|
|
lib.concatMapStrings (x: "${x}\n") ((
|
|
|
|
lib.optional value.enableUserDb "user-db:user"
|
|
|
|
) ++ (
|
|
|
|
map
|
|
|
|
(value:
|
|
|
|
let
|
|
|
|
db = if lib.isAttrs value && !lib.isDerivation value then mkDconfDb value else checkDconfDb value;
|
|
|
|
in
|
|
|
|
"file-db:${db}")
|
|
|
|
value.databases
|
|
|
|
))
|
|
|
|
);
|
|
|
|
|
|
|
|
dconfDatabase = with lib.types; submodule {
|
|
|
|
options = {
|
|
|
|
keyfiles = lib.mkOption {
|
|
|
|
type = listOf (oneOf [ path package ]);
|
|
|
|
default = [ ];
|
|
|
|
description = lib.mdDoc "A list of dconf keyfile directories.";
|
|
|
|
};
|
|
|
|
settings = lib.mkOption {
|
|
|
|
type = attrs;
|
|
|
|
default = { };
|
|
|
|
description = lib.mdDoc "An attrset used to generate dconf keyfile.";
|
|
|
|
example = literalExpression ''
|
|
|
|
with lib.gvariant;
|
|
|
|
{
|
|
|
|
"com/raggesilver/BlackBox" = {
|
|
|
|
scrollback-lines = mkUint32 10000;
|
|
|
|
theme-dark = "Tommorow Night";
|
|
|
|
};
|
|
|
|
}
|
|
|
|
'';
|
|
|
|
};
|
2023-06-14 10:27:19 +02:00
|
|
|
locks = lib.mkOption {
|
|
|
|
type = with lib.types; listOf str;
|
|
|
|
default = [ ];
|
|
|
|
description = lib.mdDoc ''
|
|
|
|
A list of dconf keys to be lockdown. This doesn't take effect if `lockAll`
|
|
|
|
is set.
|
|
|
|
'';
|
|
|
|
example = literalExpression ''
|
|
|
|
[ "/org/gnome/desktop/background/picture-uri" ]
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
lockAll = lib.mkOption {
|
|
|
|
type = lib.types.bool;
|
|
|
|
default = false;
|
|
|
|
description = lib.mdDoc "Lockdown all dconf keys in `settings`.";
|
|
|
|
};
|
2023-08-15 11:58:02 +02:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
dconfProfile = with lib.types; submodule {
|
|
|
|
options = {
|
|
|
|
enableUserDb = lib.mkOption {
|
|
|
|
type = bool;
|
|
|
|
default = true;
|
|
|
|
description = lib.mdDoc "Add `user-db:user` at the beginning of the profile.";
|
|
|
|
};
|
|
|
|
|
|
|
|
databases = lib.mkOption {
|
|
|
|
type = with lib.types; listOf (oneOf [
|
|
|
|
path
|
|
|
|
package
|
|
|
|
dconfDatabase
|
|
|
|
]);
|
|
|
|
default = [ ];
|
|
|
|
description = lib.mdDoc ''
|
|
|
|
List of data sources for the profile. An element can be an attrset,
|
|
|
|
or the path of an already compiled database. Each element is converted
|
|
|
|
to a file-db.
|
|
|
|
|
|
|
|
A key is searched from up to down and the first result takes the
|
|
|
|
priority. If a lock for a particular key is installed then the value from
|
|
|
|
the last database in the profile where the key is locked will be used.
|
|
|
|
This can be used to enforce mandatory settings.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2014-04-02 18:21:00 +02:00
|
|
|
in
|
|
|
|
{
|
|
|
|
options = {
|
|
|
|
programs.dconf = {
|
2023-06-14 10:22:17 +02:00
|
|
|
enable = lib.mkEnableOption (lib.mdDoc "dconf");
|
|
|
|
|
|
|
|
profiles = lib.mkOption {
|
|
|
|
type = with lib.types; attrsOf (oneOf [
|
|
|
|
path
|
|
|
|
package
|
2023-08-15 11:58:02 +02:00
|
|
|
dconfProfile
|
2023-06-14 10:22:17 +02:00
|
|
|
]);
|
2023-08-15 11:58:02 +02:00
|
|
|
default = { };
|
|
|
|
description = lib.mdDoc ''
|
|
|
|
Attrset of dconf profiles. By default the `user` profile is used which
|
|
|
|
ends up in `/etc/dconf/profile/user`.
|
|
|
|
'';
|
|
|
|
example = lib.literalExpression ''
|
|
|
|
{
|
|
|
|
# A "user" profile with a database
|
|
|
|
user.databases = [
|
|
|
|
{
|
|
|
|
settings = { };
|
|
|
|
}
|
|
|
|
];
|
|
|
|
# A "bar" profile from a package
|
|
|
|
bar = pkgs.bar-dconf-profile;
|
|
|
|
# A "foo" profile from a path
|
|
|
|
foo = ''${./foo}
|
|
|
|
};
|
|
|
|
'';
|
2014-04-02 18:21:00 +02:00
|
|
|
};
|
|
|
|
|
2023-06-14 10:22:17 +02:00
|
|
|
packages = lib.mkOption {
|
|
|
|
type = lib.types.listOf lib.types.package;
|
|
|
|
default = [ ];
|
2022-07-20 12:32:04 +02:00
|
|
|
description = lib.mdDoc "A list of packages which provide dconf profiles and databases in {file}`/etc/dconf`.";
|
2020-04-23 14:00:00 +02:00
|
|
|
};
|
2014-04-02 18:21:00 +02:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2023-06-14 10:22:17 +02:00
|
|
|
config = lib.mkIf (cfg.profiles != { } || cfg.enable) {
|
|
|
|
programs.dconf.packages = lib.mapAttrsToList mkDconfProfile cfg.profiles;
|
|
|
|
|
|
|
|
environment.etc.dconf = lib.mkIf (cfg.packages != [ ]) {
|
|
|
|
source = pkgs.symlinkJoin {
|
|
|
|
name = "dconf-system-config";
|
|
|
|
paths = map (x: "${x}/etc/dconf") cfg.packages;
|
|
|
|
nativeBuildInputs = [ (lib.getBin pkgs.dconf) ];
|
|
|
|
postBuild = ''
|
|
|
|
if test -d $out/db; then
|
|
|
|
dconf update $out/db
|
|
|
|
fi
|
|
|
|
'';
|
|
|
|
};
|
2020-04-23 14:00:00 +02:00
|
|
|
};
|
2017-12-21 17:16:19 +01:00
|
|
|
|
2019-12-01 00:11:47 +01:00
|
|
|
services.dbus.packages = [ pkgs.dconf ];
|
2018-09-04 21:19:31 +02:00
|
|
|
|
2021-05-17 01:32:18 +02:00
|
|
|
systemd.packages = [ pkgs.dconf ];
|
|
|
|
|
2019-08-19 03:54:00 +02:00
|
|
|
# For dconf executable
|
2019-12-01 00:11:47 +01:00
|
|
|
environment.systemPackages = [ pkgs.dconf ];
|
2019-08-19 03:54:00 +02:00
|
|
|
|
2023-06-14 10:22:17 +02:00
|
|
|
environment.sessionVariables = lib.mkIf cfg.enable {
|
|
|
|
# Needed for unwrapped applications
|
|
|
|
GIO_EXTRA_MODULES = [ "${pkgs.dconf.lib}/lib/gio/modules" ];
|
|
|
|
};
|
2014-04-02 18:21:00 +02:00
|
|
|
};
|
|
|
|
}
|