From b8d79c7fc24ff918740f6b491c2f8fac78418c1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Mon, 27 Oct 2025 14:59:05 +0100 Subject: [PATCH] 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 --- modules/clan/module.nix | 19 +++++++++++++++++- modules/inventoryClass/default.nix | 8 ++++++++ pkgs/clan-cli/clan_lib/dirs/__init__.py | 26 +++++++++++++++++++------ 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/modules/clan/module.nix b/modules/clan/module.nix index fc0300b2e..cdd616b40 100644 --- a/modules/clan/module.nix +++ b/modules/clan/module.nix @@ -222,6 +222,18 @@ in inventoryClass = let 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 { _module.args = { @@ -230,7 +242,12 @@ in imports = [ ../inventoryClass/default.nix { - inherit inventory directory flakeInputs; + inherit + inventory + directory + flakeInputs + relativeDirectory + ; exportsModule = config.exportsModule; } ( diff --git a/modules/inventoryClass/default.nix b/modules/inventoryClass/default.nix index f767b9dc2..20893aaa6 100644 --- a/modules/inventoryClass/default.nix +++ b/modules/inventoryClass/default.nix @@ -81,6 +81,14 @@ in directory = mkOption { 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 { type = types.attrsOf (submodule ({ options = { diff --git a/pkgs/clan-cli/clan_lib/dirs/__init__.py b/pkgs/clan-cli/clan_lib/dirs/__init__.py index bb081f0ab..818779ba5 100644 --- a/pkgs/clan-cli/clan_lib/dirs/__init__.py +++ b/pkgs/clan-cli/clan_lib/dirs/__init__.py @@ -156,14 +156,28 @@ def vm_state_dir(flake_url: str, vm_name: str) -> Path: def machines_dir(flake: "Flake") -> Path: + # Determine the base path 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 - if store_path is None: - msg = "Invalid flake object. Doesn't have a store path" - raise ClanError(msg) - return Path(store_path) / "machines" + # Get the clan directory configuration from Nix + # This is computed in Nix where store paths are consistent + # Returns "" if no custom directory is set + # Fall back to "" if the option doesn't exist (backwards compatibility) + 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: