mirror of
https://github.com/nix-community/home-manager.git
synced 2025-12-21 08:21:12 +01:00
WIP home-manager: use putter for file management
This commit is contained in:
parent
09de9577d4
commit
02c8ce9f92
5 changed files with 342 additions and 150 deletions
226
flake.lock
generated
226
flake.lock
generated
|
|
@ -1,5 +1,105 @@
|
||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
|
"crane": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
|
"flake-utils": [
|
||||||
|
"putter",
|
||||||
|
"flake-utils"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"putter",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"rust-overlay": "rust-overlay"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1697588719,
|
||||||
|
"narHash": "sha256-n9ALgm3S+ygpzjesBkB9qutEtM4dtIkhn8WnstCPOew=",
|
||||||
|
"owner": "ipetkov",
|
||||||
|
"repo": "crane",
|
||||||
|
"rev": "da6b58e270d339a78a6e95728012ec2eea879612",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "ipetkov",
|
||||||
|
"ref": "v0.14.3",
|
||||||
|
"repo": "crane",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-compat": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1696267196,
|
||||||
|
"narHash": "sha256-AAQ/2sD+0D18bb8hKuEEVpHUYD1GmO2Uh/taFamn6XQ=",
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "4f910c9827911b1ec2bf26b5a062cd09f8d89f85",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-compat_2": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1673956053,
|
||||||
|
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1694529238,
|
||||||
|
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"gitignore": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"putter",
|
||||||
|
"pre-commit-hooks",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1660459072,
|
||||||
|
"narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "gitignore.nix",
|
||||||
|
"rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "gitignore.nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1765472234,
|
"lastModified": 1765472234,
|
||||||
|
|
@ -16,9 +116,133 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nixpkgs-stable": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1685801374,
|
||||||
|
"narHash": "sha256-otaSUoFEMM+LjBI1XL/xGB5ao6IwnZOXc47qhIgJe8U=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "c37ca420157f4abc31e26f436c1145f8951ff373",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-23.05",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1699094435,
|
||||||
|
"narHash": "sha256-YLZ5/KKZ1PyLrm2MO8UxRe4H3M0/oaYqNhSlq6FDeeA=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "9d5d25bbfe8c0297ebe85324addcb5020ed1a454",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pre-commit-hooks": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat_2",
|
||||||
|
"flake-utils": [
|
||||||
|
"putter",
|
||||||
|
"flake-utils"
|
||||||
|
],
|
||||||
|
"gitignore": "gitignore",
|
||||||
|
"nixpkgs": [
|
||||||
|
"putter",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"nixpkgs-stable": "nixpkgs-stable"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1698852633,
|
||||||
|
"narHash": "sha256-Hsc/cCHud8ZXLvmm8pxrXpuaPEeNaaUttaCvtdX/Wug=",
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "pre-commit-hooks.nix",
|
||||||
|
"rev": "dec10399e5b56aa95fcd530e0338be72ad6462a0",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "pre-commit-hooks.nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"putter": {
|
||||||
|
"inputs": {
|
||||||
|
"crane": "crane",
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs_2",
|
||||||
|
"pre-commit-hooks": "pre-commit-hooks"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1704013409,
|
||||||
|
"narHash": "sha256-v7CTHSKcD6vnIwXRPav+3XETf+uNJz3G+RUF/SHZ+vE=",
|
||||||
|
"ref": "refs/heads/master",
|
||||||
|
"rev": "4d773d3aa9feca3af4578dc62cc6f91ebb16b002",
|
||||||
|
"revCount": 33,
|
||||||
|
"type": "git",
|
||||||
|
"url": "file:///home/rycee/devel/putter"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "file:///home/rycee/devel/putter"
|
||||||
|
}
|
||||||
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": "nixpkgs"
|
"nixpkgs": "nixpkgs",
|
||||||
|
"putter": "putter"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rust-overlay": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": [
|
||||||
|
"putter",
|
||||||
|
"crane",
|
||||||
|
"flake-utils"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"putter",
|
||||||
|
"crane",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1696299134,
|
||||||
|
"narHash": "sha256-RS77cAa0N+Sfj5EmKbm5IdncNXaBCE1BSSQvUE8exvo=",
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"rev": "611ccdceed92b4d94ae75328148d84ee4a5b462d",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,13 @@
|
||||||
description = "Home Manager for Nix";
|
description = "Home Manager for Nix";
|
||||||
|
|
||||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
inputs.putter.url = "git+file:///home/rycee/devel/putter";
|
||||||
|
|
||||||
outputs =
|
outputs =
|
||||||
{
|
{
|
||||||
self,
|
self,
|
||||||
nixpkgs,
|
nixpkgs,
|
||||||
|
putter,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
pkgs,
|
pkgs,
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
|
putter,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
|
|
||||||
|
|
@ -30,6 +31,8 @@ let
|
||||||
name = sourceName;
|
name = sourceName;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
putterStatePath = "${config.xdg.stateHome}/home-manager/putter-state.json";
|
||||||
|
|
||||||
in
|
in
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -45,6 +48,14 @@ in
|
||||||
internal = true;
|
internal = true;
|
||||||
description = "Package to contain all home files";
|
description = "Package to contain all home files";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
home.internal = {
|
||||||
|
filePutterConfig = lib.mkOption {
|
||||||
|
type = lib.types.package;
|
||||||
|
internal = true;
|
||||||
|
description = "Putter configuration.";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
|
|
@ -91,156 +102,17 @@ in
|
||||||
|
|
||||||
# This verifies that the links we are about to create will not
|
# This verifies that the links we are about to create will not
|
||||||
# overwrite an existing file.
|
# overwrite an existing file.
|
||||||
home.activation.checkLinkTargets = lib.hm.dag.entryBefore [ "writeBoundary" ] (
|
home.activation.checkLinkTargets = lib.hm.dag.entryBefore [ "writeBoundary" ] ''
|
||||||
let
|
${lib.getExe putter} check -v \
|
||||||
# Paths that should be forcibly overwritten by Home Manager.
|
--state-file "${putterStatePath}" \
|
||||||
# Caveat emptor!
|
${config.home.internal.filePutterConfig}
|
||||||
forcedPaths = lib.concatMapStringsSep " " (p: ''"$HOME"/${lib.escapeShellArg p}'') (
|
'';
|
||||||
lib.mapAttrsToList (n: v: v.target) (lib.filterAttrs (n: v: v.force) cfg)
|
|
||||||
);
|
|
||||||
|
|
||||||
storeDir = lib.escapeShellArg builtins.storeDir;
|
home.activation.linkGeneration = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
||||||
|
${lib.getExe putter} apply $VERBOSE_ARG -v ''${DRY_RUN:+--dry-run} \
|
||||||
check = pkgs.replaceVars ./files/check-link-targets.sh {
|
--state-file "${putterStatePath}" \
|
||||||
inherit (config.lib.bash) initHomeManagerLib;
|
${config.home.internal.filePutterConfig}
|
||||||
inherit forcedPaths storeDir;
|
'';
|
||||||
};
|
|
||||||
in
|
|
||||||
''
|
|
||||||
function checkNewGenCollision() {
|
|
||||||
local newGenFiles
|
|
||||||
newGenFiles="$(readlink -e "$newGenPath/home-files")"
|
|
||||||
find "$newGenFiles" \( -type f -or -type l \) \
|
|
||||||
-exec bash ${check} "$newGenFiles" {} +
|
|
||||||
}
|
|
||||||
|
|
||||||
checkNewGenCollision || exit 1
|
|
||||||
''
|
|
||||||
);
|
|
||||||
|
|
||||||
# This activation script will
|
|
||||||
#
|
|
||||||
# 1. Remove files from the old generation that are not in the new
|
|
||||||
# generation.
|
|
||||||
#
|
|
||||||
# 2. Symlink files from the new generation into $HOME.
|
|
||||||
#
|
|
||||||
# This order is needed to ensure that we always know which links
|
|
||||||
# belong to which generation. Specifically, if we're moving from
|
|
||||||
# generation A to generation B having sets of home file links FA
|
|
||||||
# and FB, respectively then cleaning before linking produces state
|
|
||||||
# transitions similar to
|
|
||||||
#
|
|
||||||
# FA → FA ∩ FB → (FA ∩ FB) ∪ FB = FB
|
|
||||||
#
|
|
||||||
# and a failure during the intermediate state FA ∩ FB will not
|
|
||||||
# result in lost links because this set of links are in both the
|
|
||||||
# source and target generation.
|
|
||||||
home.activation.linkGeneration = lib.hm.dag.entryAfter [ "writeBoundary" ] (
|
|
||||||
let
|
|
||||||
link = pkgs.writeShellScript "link" ''
|
|
||||||
${config.lib.bash.initHomeManagerLib}
|
|
||||||
|
|
||||||
newGenFiles="$1"
|
|
||||||
shift
|
|
||||||
for sourcePath in "$@" ; do
|
|
||||||
relativePath="''${sourcePath#$newGenFiles/}"
|
|
||||||
targetPath="$HOME/$relativePath"
|
|
||||||
if [[ -e "$targetPath" && ! -L "$targetPath" ]] ; then
|
|
||||||
if [[ -n "$HOME_MANAGER_BACKUP_COMMAND" ]] ; then
|
|
||||||
verboseEcho "Running $HOME_MANAGER_BACKUP_COMMAND $targetPath."
|
|
||||||
run $HOME_MANAGER_BACKUP_COMMAND "$targetPath" || errorEcho "Running `$HOME_MANAGER_BACKUP_COMMAND` on '$targetPath' failed."
|
|
||||||
elif [[ -n "$HOME_MANAGER_BACKUP_EXT" ]] ; then
|
|
||||||
# The target exists, back it up
|
|
||||||
backup="$targetPath.$HOME_MANAGER_BACKUP_EXT"
|
|
||||||
if [[ -e "$backup" && -n "$HOME_MANAGER_BACKUP_OVERWRITE" ]]; then
|
|
||||||
run rm $VERBOSE_ARG "$backup"
|
|
||||||
fi
|
|
||||||
run mv $VERBOSE_ARG "$targetPath" "$backup" || errorEcho "Moving '$targetPath' failed!"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -e "$targetPath" && ! -L "$targetPath" ]] && cmp -s "$sourcePath" "$targetPath" ; then
|
|
||||||
# The target exists but is identical – don't do anything.
|
|
||||||
verboseEcho "Skipping '$targetPath' as it is identical to '$sourcePath'"
|
|
||||||
else
|
|
||||||
# Place that symlink, --force
|
|
||||||
# This can still fail if the target is a directory, in which case we bail out.
|
|
||||||
run mkdir -p $VERBOSE_ARG "$(dirname "$targetPath")"
|
|
||||||
run ln -Tsf $VERBOSE_ARG "$sourcePath" "$targetPath" || exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
'';
|
|
||||||
|
|
||||||
cleanup = pkgs.writeShellScript "cleanup" ''
|
|
||||||
${config.lib.bash.initHomeManagerLib}
|
|
||||||
|
|
||||||
# A symbolic link whose target path matches this pattern will be
|
|
||||||
# considered part of a Home Manager generation.
|
|
||||||
homeFilePattern="$(readlink -e ${lib.escapeShellArg builtins.storeDir})/*-home-manager-files/*"
|
|
||||||
|
|
||||||
newGenFiles="$1"
|
|
||||||
shift 1
|
|
||||||
for relativePath in "$@" ; do
|
|
||||||
targetPath="$HOME/$relativePath"
|
|
||||||
if [[ -e "$newGenFiles/$relativePath" ]] ; then
|
|
||||||
verboseEcho "Checking $targetPath: exists"
|
|
||||||
elif [[ ! "$(readlink "$targetPath")" == $homeFilePattern ]] ; then
|
|
||||||
warnEcho "Path '$targetPath' does not link into a Home Manager generation. Skipping delete."
|
|
||||||
else
|
|
||||||
verboseEcho "Checking $targetPath: gone (deleting)"
|
|
||||||
run rm $VERBOSE_ARG "$targetPath"
|
|
||||||
|
|
||||||
# Recursively delete empty parent directories.
|
|
||||||
targetDir="$(dirname "$relativePath")"
|
|
||||||
if [[ "$targetDir" != "." ]] ; then
|
|
||||||
pushd "$HOME" > /dev/null
|
|
||||||
|
|
||||||
# Call rmdir with a relative path excluding $HOME.
|
|
||||||
# Otherwise, it might try to delete $HOME and exit
|
|
||||||
# with a permission error.
|
|
||||||
run rmdir $VERBOSE_ARG \
|
|
||||||
-p --ignore-fail-on-non-empty \
|
|
||||||
"$targetDir"
|
|
||||||
|
|
||||||
popd > /dev/null
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
'';
|
|
||||||
in
|
|
||||||
''
|
|
||||||
function linkNewGen() {
|
|
||||||
_i "Creating home file links in %s" "$HOME"
|
|
||||||
|
|
||||||
local newGenFiles
|
|
||||||
newGenFiles="$(readlink -e "$newGenPath/home-files")"
|
|
||||||
find "$newGenFiles" \( -type f -or -type l \) \
|
|
||||||
-exec bash ${link} "$newGenFiles" {} +
|
|
||||||
}
|
|
||||||
|
|
||||||
function cleanOldGen() {
|
|
||||||
if [[ ! -v oldGenPath || ! -e "$oldGenPath/home-files" ]] ; then
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
_i "Cleaning up orphan links from %s" "$HOME"
|
|
||||||
|
|
||||||
local newGenFiles oldGenFiles
|
|
||||||
newGenFiles="$(readlink -e "$newGenPath/home-files")"
|
|
||||||
oldGenFiles="$(readlink -e "$oldGenPath/home-files")"
|
|
||||||
|
|
||||||
# Apply the cleanup script on each leaf in the old
|
|
||||||
# generation. The find command below will print the
|
|
||||||
# relative path of the entry.
|
|
||||||
find "$oldGenFiles" '(' -type f -or -type l ')' -printf '%P\0' \
|
|
||||||
| xargs -0 bash ${cleanup} "$newGenFiles"
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanOldGen
|
|
||||||
linkNewGen
|
|
||||||
''
|
|
||||||
);
|
|
||||||
|
|
||||||
home.activation.checkFilesChanged = lib.hm.dag.entryBefore [ "linkGeneration" ] (
|
home.activation.checkFilesChanged = lib.hm.dag.entryBefore [ "linkGeneration" ] (
|
||||||
let
|
let
|
||||||
|
|
@ -286,6 +158,18 @@ in
|
||||||
'') (lib.filter (v: v.onChange != "") (lib.attrValues cfg))
|
'') (lib.filter (v: v.onChange != "") (lib.attrValues cfg))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
home.internal.filePutterConfig =
|
||||||
|
let
|
||||||
|
putter = import ./lib/putter.nix { inherit lib; };
|
||||||
|
manifest = putter.mkPutterManifest {
|
||||||
|
inherit putterStatePath;
|
||||||
|
sourceBaseDirectory = config.home-files;
|
||||||
|
targetBaseDirectory = config.home.homeDirectory;
|
||||||
|
fileEntries = attrValues cfg;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
pkgs.writeText "hm-putter.json" manifest;
|
||||||
|
|
||||||
# Symlink directories and files that have the right execute bit.
|
# Symlink directories and files that have the right execute bit.
|
||||||
# Copy files that need their execute bit changed.
|
# Copy files that need their execute bit changed.
|
||||||
home-files =
|
home-files =
|
||||||
|
|
|
||||||
|
|
@ -906,6 +906,7 @@ in
|
||||||
--subst-var-by GENERATION_DIR $out
|
--subst-var-by GENERATION_DIR $out
|
||||||
|
|
||||||
ln -s ${config.home-files} $out/home-files
|
ln -s ${config.home-files} $out/home-files
|
||||||
|
ln -s ${config.home.internal.filePutterConfig} $out/putter.json
|
||||||
ln -s ${cfg.path} $out/home-path
|
ln -s ${cfg.path} $out/home-path
|
||||||
|
|
||||||
cp "$extraDependenciesPath" "$out/extra-dependencies"
|
cp "$extraDependenciesPath" "$out/extra-dependencies"
|
||||||
|
|
|
||||||
81
modules/lib/putter.nix
Normal file
81
modules/lib/putter.nix
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
# Contains some handy functions for generating Putter file manifests.
|
||||||
|
|
||||||
|
{ lib }:
|
||||||
|
|
||||||
|
let
|
||||||
|
|
||||||
|
inherit (lib)
|
||||||
|
concatMap
|
||||||
|
concatLists
|
||||||
|
mapAttrsToList
|
||||||
|
hasPrefix
|
||||||
|
filter
|
||||||
|
;
|
||||||
|
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# Converts a Home Manager style list of file specifications into a Putter
|
||||||
|
# configuration.
|
||||||
|
#
|
||||||
|
# Note, the interface of this function is not considered stable, it may change
|
||||||
|
# as the needs of Home Manager change.
|
||||||
|
mkPutterManifest =
|
||||||
|
{
|
||||||
|
putterStatePath,
|
||||||
|
sourceBaseDirectory,
|
||||||
|
targetBaseDirectory,
|
||||||
|
fileEntries,
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
# Convert a directory to a Putter configuration. Basically, this will
|
||||||
|
# create a file entry for each file in the directory. Any sub-directories
|
||||||
|
# will be handled recursively.
|
||||||
|
mkDirEntry =
|
||||||
|
f:
|
||||||
|
concatLists (
|
||||||
|
mapAttrsToList (
|
||||||
|
n: v:
|
||||||
|
let
|
||||||
|
f' = f // {
|
||||||
|
source = "${f.source}/${n}";
|
||||||
|
target = "${f.target}/${n}";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
mkEntriesForType f' v
|
||||||
|
) (builtins.readDir f.source)
|
||||||
|
);
|
||||||
|
|
||||||
|
mkEntriesForType =
|
||||||
|
f: t:
|
||||||
|
if t == "regular" || t == "symlink" then
|
||||||
|
mkFileEntry f
|
||||||
|
else if t == "directory" then
|
||||||
|
mkDirEntry f
|
||||||
|
else
|
||||||
|
throw "unexpected file type ${t}";
|
||||||
|
|
||||||
|
# Create a file entry for the given file.
|
||||||
|
mkFileEntry = f: [
|
||||||
|
{
|
||||||
|
collision.resolution = if f.force then "force" else "abort";
|
||||||
|
action.type = "symlink";
|
||||||
|
source = "${sourceBaseDirectory}/${f.target}";
|
||||||
|
target = (if hasPrefix "/" f.target then "" else "${targetBaseDirectory}/") + f.target;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
# Given a Home Manager file entry, produce a list of Putter entries. For
|
||||||
|
# recursive HM file entries, we recursively traverse the source directory
|
||||||
|
# and generate a Putter entry for each file we encounter.
|
||||||
|
mkEntries = f: if f.recursive then mkEntriesForType f "directory" else mkFileEntry f;
|
||||||
|
|
||||||
|
putterJson = {
|
||||||
|
version = "1";
|
||||||
|
state = putterStatePath;
|
||||||
|
files = concatMap mkEntries (filter (f: f.enable) fileEntries);
|
||||||
|
};
|
||||||
|
|
||||||
|
putterJsonText = builtins.toJSON putterJson;
|
||||||
|
in
|
||||||
|
putterJsonText;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue