at 25.11-pre 7.3 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8let 9 cfg = config.programs.dconf; 10 11 # Compile keyfiles to dconf DB 12 compileDconfDb = 13 dir: 14 pkgs.runCommand "dconf-db" { 15 nativeBuildInputs = [ (lib.getBin pkgs.dconf) ]; 16 } "dconf compile $out ${dir}"; 17 18 # Check if dconf keyfiles are valid 19 checkDconfKeyfiles = 20 dir: 21 pkgs.runCommand "check-dconf-keyfiles" 22 { 23 nativeBuildInputs = [ (lib.getBin pkgs.dconf) ]; 24 } 25 '' 26 if [[ -f ${dir} ]]; then 27 echo "dconf keyfiles should be a directory but a file is provided: ${dir}" 28 exit 1 29 fi 30 31 dconf compile db ${dir} || ( 32 echo "The dconf keyfiles are invalid: ${dir}" 33 exit 1 34 ) 35 cp -R ${dir} $out 36 ''; 37 38 mkAllLocks = 39 settings: 40 lib.flatten (lib.mapAttrsToList (k: v: lib.mapAttrsToList (k': _: "/${k}/${k'}") v) settings); 41 42 # Generate dconf DB from dconfDatabase and keyfiles 43 mkDconfDb = 44 val: 45 compileDconfDb ( 46 pkgs.symlinkJoin { 47 name = "nixos-generated-dconf-keyfiles"; 48 paths = [ 49 (pkgs.writeTextDir "nixos-generated-dconf-keyfiles" (lib.generators.toDconfINI val.settings)) 50 (pkgs.writeTextDir "locks/nixos-generated-dconf-locks" ( 51 lib.concatStringsSep "\n" (if val.lockAll then mkAllLocks val.settings else val.locks) 52 )) 53 ] ++ (map checkDconfKeyfiles val.keyfiles); 54 } 55 ); 56 57 # Check if a dconf DB file is valid. The dconf cli doesn't return 1 when it can't 58 # open the database file so we have to check if the output is empty. 59 checkDconfDb = 60 file: 61 pkgs.runCommand "check-dconf-db" 62 { 63 nativeBuildInputs = [ (lib.getBin pkgs.dconf) ]; 64 } 65 '' 66 if [[ -d ${file} ]]; then 67 echo "dconf DB should be a file but a directory is provided: ${file}" 68 exit 1 69 fi 70 71 echo "file-db:${file}" > profile 72 DCONF_PROFILE=$(pwd)/profile dconf dump / > output 2> error 73 if [[ ! -s output ]] && [[ -s error ]]; then 74 cat error 75 echo "The dconf DB file is invalid: ${file}" 76 exit 1 77 fi 78 79 cp ${file} $out 80 ''; 81 82 # Generate dconf profile 83 mkDconfProfile = 84 name: value: 85 if lib.isDerivation value || lib.isPath value then 86 pkgs.runCommand "dconf-profile" { } '' 87 if [[ -d ${value} ]]; then 88 echo "Dconf profile should be a file but a directory is provided." 89 exit 1 90 fi 91 mkdir -p $out/etc/dconf/profile/ 92 cp ${value} $out/etc/dconf/profile/${name} 93 '' 94 else 95 pkgs.writeTextDir "etc/dconf/profile/${name}" ( 96 lib.concatMapStrings (x: "${x}\n") ( 97 (lib.optional value.enableUserDb "user-db:user") 98 ++ (map ( 99 value: 100 let 101 db = if lib.isAttrs value && !lib.isDerivation value then mkDconfDb value else checkDconfDb value; 102 in 103 "file-db:${db}" 104 ) value.databases) 105 ) 106 ); 107 108 dconfDatabase = 109 with lib.types; 110 submodule { 111 options = { 112 keyfiles = lib.mkOption { 113 type = listOf (oneOf [ 114 path 115 package 116 ]); 117 default = [ ]; 118 description = "A list of dconf keyfile directories."; 119 }; 120 settings = lib.mkOption { 121 type = attrs; 122 default = { }; 123 description = "An attrset used to generate dconf keyfile."; 124 example = literalExpression '' 125 with lib.gvariant; 126 { 127 "com/raggesilver/BlackBox" = { 128 scrollback-lines = mkUint32 10000; 129 theme-dark = "Tommorow Night"; 130 }; 131 } 132 ''; 133 }; 134 locks = lib.mkOption { 135 type = with lib.types; listOf str; 136 default = [ ]; 137 description = '' 138 A list of dconf keys to be lockdown. This doesn't take effect if `lockAll` 139 is set. 140 ''; 141 example = literalExpression '' 142 [ "/org/gnome/desktop/background/picture-uri" ] 143 ''; 144 }; 145 lockAll = lib.mkOption { 146 type = lib.types.bool; 147 default = false; 148 description = "Lockdown all dconf keys in `settings`."; 149 }; 150 }; 151 }; 152 153 dconfProfile = 154 with lib.types; 155 submodule { 156 options = { 157 enableUserDb = lib.mkOption { 158 type = bool; 159 default = true; 160 description = "Add `user-db:user` at the beginning of the profile."; 161 }; 162 163 databases = lib.mkOption { 164 type = 165 with lib.types; 166 listOf (oneOf [ 167 path 168 package 169 dconfDatabase 170 ]); 171 default = [ ]; 172 description = '' 173 List of data sources for the profile. An element can be an attrset, 174 or the path of an already compiled database. Each element is converted 175 to a file-db. 176 177 A key is searched from up to down and the first result takes the 178 priority. If a lock for a particular key is installed then the value from 179 the last database in the profile where the key is locked will be used. 180 This can be used to enforce mandatory settings. 181 ''; 182 }; 183 }; 184 }; 185 186in 187{ 188 options = { 189 programs.dconf = { 190 enable = lib.mkEnableOption "dconf"; 191 192 profiles = lib.mkOption { 193 type = 194 with lib.types; 195 attrsOf (oneOf [ 196 path 197 package 198 dconfProfile 199 ]); 200 default = { }; 201 description = '' 202 Attrset of dconf profiles. By default the `user` profile is used which 203 ends up in `/etc/dconf/profile/user`. 204 ''; 205 example = lib.literalExpression '' 206 { 207 # A "user" profile with a database 208 user.databases = [ 209 { 210 settings = { }; 211 } 212 ]; 213 # A "bar" profile from a package 214 bar = pkgs.bar-dconf-profile; 215 # A "foo" profile from a path 216 foo = ''${./foo} 217 }; 218 ''; 219 }; 220 221 packages = lib.mkOption { 222 type = lib.types.listOf lib.types.package; 223 default = [ ]; 224 description = "A list of packages which provide dconf profiles and databases in {file}`/etc/dconf`."; 225 }; 226 }; 227 }; 228 229 config = lib.mkIf (cfg.profiles != { } || cfg.enable) { 230 programs.dconf.packages = lib.mapAttrsToList mkDconfProfile cfg.profiles; 231 232 environment.etc.dconf = lib.mkIf (cfg.packages != [ ]) { 233 source = pkgs.symlinkJoin { 234 name = "dconf-system-config"; 235 paths = map (x: "${x}/etc/dconf") cfg.packages; 236 nativeBuildInputs = [ (lib.getBin pkgs.dconf) ]; 237 postBuild = '' 238 if test -d $out/db; then 239 dconf update $out/db 240 fi 241 ''; 242 }; 243 }; 244 245 services.dbus.packages = [ pkgs.dconf ]; 246 247 systemd.packages = [ pkgs.dconf ]; 248 249 # For dconf executable 250 environment.systemPackages = [ pkgs.dconf ]; 251 252 environment.sessionVariables = lib.mkIf cfg.enable { 253 # Needed for unwrapped applications 254 GIO_EXTRA_MODULES = [ "${pkgs.dconf.lib}/lib/gio/modules" ]; 255 }; 256 }; 257}