-
-
Save piousdeer/b29c272eaeba398b864da6abf6cb5daa to your computer and use it in GitHub Desktop.
{ | |
home.file."test-file" = { | |
text = "Hello world"; | |
force = true; | |
mutable = true; | |
}; | |
} |
# This module extends home.file, xdg.configFile and xdg.dataFile with the `mutable` option. | |
{ config, lib, ... }: | |
let | |
fileOptionAttrPaths = | |
[ [ "home" "file" ] [ "xdg" "configFile" ] [ "xdg" "dataFile" ] ]; | |
in { | |
options = let | |
mergeAttrsList = builtins.foldl' (lib.mergeAttrs) { }; | |
fileAttrsType = lib.types.attrsOf (lib.types.submodule ({ config, ... }: { | |
options.mutable = lib.mkOption { | |
type = lib.types.bool; | |
default = false; | |
description = '' | |
Whether to copy the file without the read-only attribute instead of | |
symlinking. If you set this to `true`, you must also set `force` to | |
`true`. Mutable files are not removed when you remove them from your | |
configuration. | |
This option is useful for programs that don't have a very good | |
support for read-only configurations. | |
''; | |
}; | |
})); | |
in mergeAttrsList (map (attrPath: | |
lib.setAttrByPath attrPath (lib.mkOption { type = fileAttrsType; })) | |
fileOptionAttrPaths); | |
config = { | |
home.activation.mutableFileGeneration = let | |
allFiles = (builtins.concatLists (map | |
(attrPath: builtins.attrValues (lib.getAttrFromPath attrPath config)) | |
fileOptionAttrPaths)); | |
filterMutableFiles = builtins.filter (file: | |
(file.mutable or false) && lib.assertMsg file.force | |
"if you specify `mutable` to `true` on a file, you must also set `force` to `true`"); | |
mutableFiles = filterMutableFiles allFiles; | |
toCommand = (file: | |
let | |
source = lib.escapeShellArg file.source; | |
target = lib.escapeShellArg file.target; | |
in '' | |
$VERBOSE_ECHO "${source} -> ${target}" | |
$DRY_RUN_CMD cp --remove-destination --no-preserve=mode ${source} ${target} | |
''); | |
command = '' | |
echo "Copying mutable home files for $HOME" | |
'' + lib.concatLines (map toCommand mutableFiles); | |
in (lib.hm.dag.entryAfter [ "linkGeneration" ] command); | |
}; | |
} |
{ config, pkgs, lib, ... }: | |
let | |
# Path logic from: | |
# https://github.com/nix-community/home-manager/blob/3876cc613ac3983078964ffb5a0c01d00028139e/modules/programs/vscode.nix | |
cfg = config.programs.vscode; | |
vscodePname = cfg.package.pname; | |
configDir = { | |
"vscode" = "Code"; | |
"vscode-insiders" = "Code - Insiders"; | |
"vscodium" = "VSCodium"; | |
}.${vscodePname}; | |
userDir = if pkgs.stdenv.hostPlatform.isDarwin then | |
"Library/Application Support/${configDir}/User" | |
else | |
"${config.xdg.configHome}/${configDir}/User"; | |
configFilePath = "${userDir}/settings.json"; | |
tasksFilePath = "${userDir}/tasks.json"; | |
keybindingsFilePath = "${userDir}/keybindings.json"; | |
snippetDir = "${userDir}/snippets"; | |
pathsToMakeWritable = lib.flatten [ | |
(lib.optional (cfg.userTasks != { }) tasksFilePath) | |
(lib.optional (cfg.userSettings != { }) configFilePath) | |
(lib.optional (cfg.keybindings != [ ]) keybindingsFilePath) | |
(lib.optional (cfg.globalSnippets != { }) | |
"${snippetDir}/global.code-snippets") | |
(lib.mapAttrsToList (language: _: "${snippetDir}/${language}.json") | |
cfg.languageSnippets) | |
]; | |
in { | |
home.file = lib.genAttrs pathsToMakeWritable (_: { | |
force = true; | |
mutable = true; | |
}); | |
} |
Thank you for your response, very much appreciated.
Alternatively, you can use mkOutOfStoreSymlink to symlink the config to a writable file. Then, however:
This is what I was referring to as symlink.
- you can't use Nix to generate the config contents
That is a drawback, but I can live with it by using some other method to generate it (a script or something like that)
- you have to hardcode the writable file's location, which deduces from reproducibility
That is definitely the main problem, and what I have been doing up until now. I was wondering it I was just doing it wrong and nix provides a mechanism for referencing the paths it owns (like a subfolder within my nix dotfiles folder), but if an advanced user like you tell me that is a literal problem, I trust you.
The cherry on top of this would be to have a mechanism to detect conflicts, or even better, to re-incorporate the modified file into the nix repository
since updating to 25.05, a bunch of warnings are issued:
trace: Obsolete option programs.vscode.userTasks' is used. It was renamed to
programs.vscode.profiles.default.userTasks'.
trace: Obsolete option programs.vscode.userSettings' is used. It was renamed to
programs.vscode.profiles.default.userSettings'.
trace: Obsolete option programs.vscode.keybindings' is used. It was renamed to
programs.vscode.profiles.default.keybindings'.
trace: Obsolete option programs.vscode.globalSnippets' is used. It was renamed to
programs.vscode.profiles.default.globalSnippets'.
trace: Obsolete option programs.vscode.languageSnippets' is used. It was renamed to
programs.vscode.profiles.default.languageSnippets'.
Ive been using this module extension for awhile but it recently broke for me for some other reason, the home-manager-myuser
activation service was failing on system startup because this module wasnt able to find symlinks to make into mutable files even though the symlinks exist afterwards when i look for them. I suspected some sort of race condition so i moved the execution into a regular systemd.user
service. It works fine for now but it isnt as elegant as having the logic right inside home.activation
after linkGeneration. Im not sure why links are not available to me even when specifying hm.dag.entryAfter [ "linkGeneration" ]
, maybe some interaction with impermanence bindfs. Note that this is a problem that started happening to me about ~1month ago, so perhaps some recent home-manager code change can also be at fault.
@danielo515
The file will be modified
Yes. This will also happen after a reboot (at least if you're using home-manager as a NixOS module)
Normally, config files managed by home-manager are symlinks pointing to
/nix/store
. This makes them read-only.Not being read-only allows for quick iteration on the config before integrating your changes with home-manager. Additionally, some programs, like vscode, just don't work well with a read-only config: nix-community/home-manager#1800
Alternatively, you can use
mkOutOfStoreSymlink
to symlink the config to a writable file. Then, however: