fix: respect directory parameter in machines_dir

The machines_dir() function was hardcoding "machines" without considering
the directory parameter from buildClan/clan configuration. This caused
update-hardware-config and other commands to write files to the wrong
location when a custom directory was specified (e.g., directory = ./clan).

Solution:
1. Added relativeDirectory to inventoryClass in Nix, computed where both
   self and directory have consistent store paths during evaluation
2. Updated machines_dir() to use this pre-computed relative path from Nix
   via flake.select("clanInternals.inventoryClass.relativeDirectory")

Fixes: https://git.clan.lol/clan/clan-core/issues/2906
This commit is contained in:
Jörg Thalheim
2025-10-27 14:59:05 +01:00
parent 5b136ecaf0
commit b8d79c7fc2
3 changed files with 46 additions and 7 deletions

View File

@@ -222,6 +222,18 @@ in
inventoryClass = inventoryClass =
let let
flakeInputs = config.self.inputs; flakeInputs = config.self.inputs;
# Compute the relative directory path
selfStr = toString config.self;
dirStr = toString directory;
relativeDirectory =
if selfStr == dirStr then
""
else if lib.hasPrefix selfStr dirStr then
lib.removePrefix (selfStr + "/") dirStr
else
# This shouldn't happen in normal usage, but can occur when
# the flake is copied (e.g., in tests). Fall back to empty string.
"";
in in
{ {
_module.args = { _module.args = {
@@ -230,7 +242,12 @@ in
imports = [ imports = [
../inventoryClass/default.nix ../inventoryClass/default.nix
{ {
inherit inventory directory flakeInputs; inherit
inventory
directory
flakeInputs
relativeDirectory
;
exportsModule = config.exportsModule; exportsModule = config.exportsModule;
} }
( (

View File

@@ -81,6 +81,14 @@ in
directory = mkOption { directory = mkOption {
type = types.path; type = types.path;
}; };
relativeDirectory = mkOption {
type = types.str;
internal = true;
description = ''
The relative directory path from the flake root to the clan directory.
Empty string if directory equals the flake root.
'';
};
machines = mkOption { machines = mkOption {
type = types.attrsOf (submodule ({ type = types.attrsOf (submodule ({
options = { options = {

View File

@@ -156,14 +156,28 @@ def vm_state_dir(flake_url: str, vm_name: str) -> Path:
def machines_dir(flake: "Flake") -> Path: def machines_dir(flake: "Flake") -> Path:
# Determine the base path
if flake.is_local: if flake.is_local:
return flake.path / "machines" base_path = flake.path
else:
store_path = flake.store_path
if store_path is None:
msg = "Invalid flake object. Doesn't have a store path"
raise ClanError(msg)
base_path = Path(store_path)
store_path = flake.store_path # Get the clan directory configuration from Nix
if store_path is None: # This is computed in Nix where store paths are consistent
msg = "Invalid flake object. Doesn't have a store path" # Returns "" if no custom directory is set
raise ClanError(msg) # Fall back to "" if the option doesn't exist (backwards compatibility)
return Path(store_path) / "machines" try:
clan_dir = flake.select("clanInternals.inventoryClass.relativeDirectory")
except ClanError:
# Option doesn't exist in older clan-core versions
# Assume no custom directory
clan_dir = ""
return base_path / clan_dir / "machines"
def specific_machine_dir(machine: "MachineSpecProtocol") -> Path: def specific_machine_dir(machine: "MachineSpecProtocol") -> Path: