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