173 lines
7.3 KiB
Nix
173 lines
7.3 KiB
Nix
{
|
|
pkgs,
|
|
lib ? pkgs.lib,
|
|
config,
|
|
...
|
|
}:
|
|
|
|
let
|
|
inherit (lib) mkOption types;
|
|
|
|
cfg = lib.filterAttrs (n: f: f.enable) config.home.initialFile;
|
|
home = config.home.homeDirectory;
|
|
in
|
|
{
|
|
options = {
|
|
home.initialFile = mkOption {
|
|
type = types.attrsOf (
|
|
types.submodule (
|
|
{ name, config, ... }:
|
|
{
|
|
options = {
|
|
enable = mkOption {
|
|
type = types.bool;
|
|
default = true;
|
|
};
|
|
target = mkOption {
|
|
type = types.str;
|
|
apply =
|
|
path:
|
|
let
|
|
absPath = if lib.hasPrefix "/" path then path else "${home}/${path}";
|
|
in
|
|
lib.removePrefix (home + "/") absPath;
|
|
description = "Path to target file relative to home directory";
|
|
default = "/homeless-shelter/home";
|
|
};
|
|
text = mkOption {
|
|
type = types.nullOr types.lines;
|
|
description = "Text of the file, otherwise copies .source file.";
|
|
default = null;
|
|
};
|
|
source = mkOption {
|
|
type = types.path;
|
|
description = "Path of file whose source to copy";
|
|
};
|
|
mode = mkOption {
|
|
type = types.nullOr types.str;
|
|
description = "File mode to apply to target file (sourced from .source / .text if not specified)";
|
|
default = null;
|
|
};
|
|
dir_mode = mkOption {
|
|
type = types.str;
|
|
description = "File mode to apply to directories";
|
|
default = "0755";
|
|
};
|
|
recursive = mkOption {
|
|
type = types.bool;
|
|
description = "Whether or not to recursively copy .source as a directory instead of as a file";
|
|
default = false;
|
|
};
|
|
force = mkOption {
|
|
type = types.bool;
|
|
description = "Whether to unconditionally replace the target file, even if it already exists.";
|
|
default = false;
|
|
};
|
|
};
|
|
config = {
|
|
target = lib.mkDefault name;
|
|
source = lib.mkIf (config.text != null) (
|
|
lib.mkDefault (
|
|
pkgs.writeTextFile {
|
|
inherit (config) text;
|
|
name = lib.hm.strings.storeFileName name;
|
|
}
|
|
)
|
|
);
|
|
};
|
|
}
|
|
)
|
|
);
|
|
description = "Attribute set of files to write into the user home (if they don't already exist).";
|
|
default = { };
|
|
};
|
|
};
|
|
|
|
config = {
|
|
assertions = [
|
|
(
|
|
let
|
|
dups = lib.attrNames (
|
|
lib.filterAttrs (n: v: v > 1) (
|
|
lib.foldAttrs (acc: v: acc + v) 0 (lib.mapAttrsToList (n: v: { ${v.target} = 1; }) cfg)
|
|
)
|
|
);
|
|
dupsStr = lib.concatStringsSep ", " dups;
|
|
in
|
|
{
|
|
assertion = dups == [ ];
|
|
message = ''
|
|
Conflicting managed target files: ${dupsStr}
|
|
|
|
This may happen, for example, if you have a configuration similar to
|
|
|
|
home.initialFile = {
|
|
conflict1 = { source = ./foo.nix; target = "baz"; };
|
|
conflict2 = { source = ./bar.nix; target = "baz"; };
|
|
}'';
|
|
}
|
|
)
|
|
];
|
|
|
|
home.activation.copyInitialFiles = lib.hm.dag.entryAfter [ "writeBoundary" ] (
|
|
let
|
|
homeArg = lib.escapeShellArg home;
|
|
in
|
|
''
|
|
function copyFile() {
|
|
local source="$1"
|
|
local targetRel="$2"
|
|
local mode="$3"
|
|
local dirMode="$4"
|
|
local recursive="$5"
|
|
local force="$6"
|
|
|
|
local target="${homeArg}/$targetRel"
|
|
|
|
if [[ -e "$target" && "$force" != "true" ]]; then
|
|
verboseEcho "Skipping existing $target"
|
|
return 0
|
|
fi
|
|
|
|
run mkdir -p "$(dirname "$target")"
|
|
|
|
if [[ -d "$source" ]]; then
|
|
if [[ "$recursive" != "true" ]]; then
|
|
errorEcho "Source '$source' is a directory but recursive=false"
|
|
return 1
|
|
fi
|
|
run rm -rf "$target"
|
|
run cp -r "$source" "$target"
|
|
else
|
|
if [[ -e "$target" && "$force" == "true" ]]; then
|
|
run rm -f "$target"
|
|
fi
|
|
run cp "$source" "$target"
|
|
fi
|
|
|
|
if [[ -n "$mode" ]]; then
|
|
if [[ -d "$target" && "$recursive" == "true" ]]; then
|
|
run chmod "$dirMode" "$target"
|
|
find "$target" -type f -exec chmod "$mode" {} +
|
|
else
|
|
run chmod "$mode" "$target"
|
|
fi
|
|
fi
|
|
}
|
|
''
|
|
+ lib.concatMapStrings (
|
|
v:
|
|
let
|
|
src = lib.escapeShellArg (toString v.source);
|
|
tgt = lib.escapeShellArg v.target;
|
|
mode = if v.mode == null then "''" else lib.escapeShellArg v.mode;
|
|
in
|
|
''
|
|
copyFile ${src} ${tgt} ${mode} ${lib.escapeShellArg v.dir_mode} ${lib.trivial.boolToString v.recursive} ${lib.trivial.boolToString v.force}
|
|
''
|
|
) (lib.attrValues cfg)
|
|
);
|
|
|
|
};
|
|
}
|