M lib/default.nix => lib/default.nix +53 -1
@@ 1,6 1,58 @@
{ pkgs, lib, ... }:
rec {
+ mkWrapper = { basePackage, prependFlags ? [], appendFlags ? [], pathAdd ? [], environment ? {}, extraPackages ? [] }: pkgs.symlinkJoin ({
+ name = "wrapper-${basePackage.name}";
+ paths = [ basePackage ] ++ extraPackages;
+ nativeBuildInputs = [ pkgs.makeWrapper ];
+ postBuild = let
+
+ envToWrapperArg = name: config: let
+ optionStr = attr: lib.showOption ["env" name attr];
+ unsetArg =
+ if !config.force
+ then
+ (lib.warn ''
+ ${optionStr "value"} is null (indicating unsetting the variable), but ${optionStr "force"} is false. This option will have no effect
+ '' [])
+ else ["--unset" config.name];
+ setArg = let
+ arg =
+ if config.force
+ then "--set"
+ else "--set-default";
+ in [arg config.name config.value];
+ in
+ if config.value == null
+ then unsetArg
+ else setArg;
+
+ envArgs = lib.mapAttrsToList envToWrapperArg environment;
+ # Yes, the arguments are escaped later, yes, this is intended to "double escape",
+ # so that they are escaped for wrapProgram and for the final binary too.
+ prependFlagArgs = map (args: ["--add-flags" (lib.escapeShellArg args)]) prependFlags;
+ appendFlagArgs = map (args: ["--append-flags" (lib.escapeShellArg args)]) appendFlags;
+ pathArgs = map (p: ["--prefix" "PATH" ":" "${p}/bin"]) pathAdd;
+ allArgs = lib.flatten (envArgs ++ prependFlagArgs ++ appendFlagArgs ++ pathArgs);
+ in ''
+ for file in $out/bin/*; do
+ wrapProgram \
+ "$file" \
+ ${lib.escapeShellArgs allArgs}
+ done
+
+ ${
+ lib.concatMapStringsSep "\n"
+ (p:
+ if lib.hasAttr "man" p
+ then "${pkgs.xorg.lndir}/bin/lndir -silent ${p.man} $out"
+ else "#")
+ ([basePackage] ++ extraPackages)
+ }
+ '';
+ passthru = (basePackage.passhtru or {}) // {unwrapped = basePackage;};
+ });
+
escapeTmpFileContents = contents: builtins.replaceStrings ["\n"] ["\\n"] contents;
mkTmpFile = { type ? "f", target, mode ? "0700", user, group, contents }: "${type} \"${target}\" ${mode} ${user} ${group} - ${escapeTmpFileContents contents}";
mkRmTmpFile = { type ? "f", target }: "${if type == "d" then "R" else "r"} ${target}";
@@ 36,7 88,7 @@ rec {
};
});
- homeFileType = lib.types.attrsOf (lib.types.submodule ({ config, name, ... }: {
+ homeFileType = (lib.types.submodule ({ config, name, ... }: {
options = {
enable = lib.mkOption {
type = lib.types.bool;
M modules/default.nix => modules/default.nix +1 -0
@@ 5,6 5,7 @@
./tmpfiles.nix
./home.nix
./systemd.nix
+ ./desktop-items.nix
];
_module.args = {
A modules/desktop-items.nix => modules/desktop-items.nix +40 -0
@@ 0,0 1,40 @@
+{ pkgs, lib, config, ... }:
+
+let
+ mkStrOption = lib.mkOption { type = lib.types.str; };
+ mkStrNullOption = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; };
+
+ desktopItems = lib.mapAttrs (name: conf: (pkgs.makeDesktopItem {
+ inherit name;
+ inherit (conf) desktopName exec icon path;
+ }) + "/share/applications/${name}.desktop") config.desktopItems.items;
+in {
+ options = {
+ desktopItems = {
+ enable = lib.mkEnableOption "desktop items";
+
+ items = lib.mkOption {
+ type = lib.types.attrsOf (lib.types.submodule ({ config, ... }: {
+ options = {
+ desktopName = mkStrOption;
+ exec = mkStrOption;
+ icon = mkStrNullOption;
+ path = mkStrNullOption;
+ };
+ }));
+ default = [];
+ };
+ };
+ };
+
+ config = lib.mkIf config.desktopItems.enable {
+
+ home.file = lib.mapAttrs'
+ (name: conf:
+ lib.nameValuePair
+ ".local/share/applications/${name}.desktop"
+ { source = conf; }
+ )
+ desktopItems;
+ };
+}
M modules/home.nix => modules/home.nix +13 -1
@@ 30,10 30,15 @@ in {
};
file = lib.mkOption {
- type = tmpLib.homeFileType;
+ type = lib.types.attrsOf tmpLib.homeFileType;
default = {};
};
+ packages = lib.mkOption {
+ type = lib.types.listOf lib.types.package;
+ default = [];
+ };
+
homeFilesPackage = lib.mkOption {
type = lib.types.package;
};
@@ 44,6 49,13 @@ in {
tmpfiles.defaultUser = config.home.user;
tmpfiles.defaultGroup = config.home.group;
+ home.file = builtins.listToAttrs (builtins.map (pkg:
+ lib.nameValuePair (".local/bin/${pkg.meta.mainProgram}") {
+ source = (lib.getExe pkg);
+ executable = true;
+ })
+ config.home.packages);
+
tmpfiles.files = (lib.attrValues (lib.mapAttrs (name: conf: {
type = "L+";
mode = "-";
M modules/systemd.nix => modules/systemd.nix +50 -36
@@ 14,42 14,47 @@ let
timerToUnit
pathToUnit;
- cfg = config.systemd;
+ cfg = config.systemd.user;
+
+ wantedPaths = lib.unique (lib.flatten (lib.attrValues (lib.mapAttrs (name: conf: (builtins.map (wanted: "${wanted}.wants/${name}") (conf.wantedBy or []))) cfg.units)));
+ requiredPaths = lib.unique (lib.flatten (lib.attrValues (lib.mapAttrs (name: conf: (builtins.map (required: "${required}.requires/${name}") (conf.requiredBy or []))) cfg.units)));
in {
options = {
systemd = {
- units = lib.mkOption {
- default = {};
- type = systemdUtils.types.units;
- };
- services = lib.mkOption {
- default = {};
- type = systemdUtils.types.services;
- };
- slices = lib.mkOption {
- default = {};
- type = systemdUtils.types.slices;
- };
- paths = lib.mkOption {
- default = {};
- type = systemdUtils.types.paths;
- };
- sockets = lib.mkOption {
- default = {};
- type = systemdUtils.types.sockets;
- };
- targets = lib.mkOption {
- default = {};
- type = systemdUtils.types.targets;
- };
- timers = lib.mkOption {
- default = {};
- type = systemdUtils.types.timers;
- };
+ user = {
+ units = lib.mkOption {
+ default = {};
+ type = systemdUtils.types.units;
+ };
+ services = lib.mkOption {
+ default = {};
+ type = systemdUtils.types.services;
+ };
+ slices = lib.mkOption {
+ default = {};
+ type = systemdUtils.types.slices;
+ };
+ paths = lib.mkOption {
+ default = {};
+ type = systemdUtils.types.paths;
+ };
+ sockets = lib.mkOption {
+ default = {};
+ type = systemdUtils.types.sockets;
+ };
+ targets = lib.mkOption {
+ default = {};
+ type = systemdUtils.types.targets;
+ };
+ timers = lib.mkOption {
+ default = {};
+ type = systemdUtils.types.timers;
+ };
- unitsPackage = lib.mkOption {
- type = lib.types.package;
+ unitsPackage = lib.mkOption {
+ type = lib.types.package;
+ };
};
package = lib.mkOption {
@@ 60,10 65,11 @@ in {
};
};
+ a.wantedServices = lib.mkOption { type = lib.types.listOf lib.types.str; };
};
config = {
- systemd.units = with lib;
+ systemd.user.units = with lib;
mapAttrs' (n: v: nameValuePair "${n}.path" (pathToUnit n v)) cfg.paths
// mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit n v)) cfg.services
// mapAttrs' (n: v: nameValuePair "${n}.slice" (sliceToUnit n v)) cfg.slices
@@ 71,7 77,7 @@ in {
// mapAttrs' (n: v: nameValuePair "${n}.target" (targetToUnit n v)) cfg.targets
// mapAttrs' (n: v: nameValuePair "${n}.timer" (timerToUnit n v)) cfg.timers;
- systemd.unitsPackage = generateUnits {
+ systemd.user.unitsPackage = generateUnits {
type = "user";
inherit (cfg) units;
upstreamUnits = [];
@@ 85,8 91,16 @@ in {
# inherit (cfg) units;
# };
#
- home.file = lib.mapAttrs' (name: conf: (lib.nameValuePair ".config/systemd/user/${name}" {
- source = "${config.systemd.unitsPackage}/${name}";
- })) config.systemd.units;
+ home.file = lib.mkMerge [
+ (lib.mapAttrs' (name: conf: (lib.nameValuePair ".config/systemd/user/${name}" {
+ source = "${cfg.unitsPackage}/${name}";
+ })) cfg.units)
+
+ (lib.listToAttrs (builtins.map (path:
+ (lib.nameValuePair
+ ".config/systemd/user/${path}"
+ { source = "${cfg.unitsPackage}/${path}"; })
+ ) (wantedPaths ++ requiredPaths)))
+ ];
};
}