From 43035b85a572d8cde0bbda9ed8a72cee854bef87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Wed, 19 Mar 2025 16:31:36 +0100 Subject: [PATCH] always resolve symlinks for TemporaryDirectory On macOS mktemp returns a temporary directory in a symlink. Nix has a bug where it won't accept path:// located in a symlink. This avoid this issue by always resolving symlinks as returned by TemporaryDirectory. --- pkgs/clan-app/tests/temporary_dir.py | 7 +-- pkgs/clan-cli/clan_cli/facts/generate.py | 4 +- pkgs/clan-cli/clan_cli/facts/upload.py | 4 +- pkgs/clan-cli/clan_cli/flash/flash.py | 4 +- pkgs/clan-cli/clan_cli/machines/install.py | 7 +-- pkgs/clan-cli/clan_cli/machines/morph.py | 4 +- pkgs/clan-cli/clan_cli/vars/generate.py | 4 +- .../vars/secret_modules/password_store.py | 4 +- .../clan_cli/vars/secret_modules/sops.py | 4 +- pkgs/clan-cli/tests/fixtures_flakes.py | 7 +-- pkgs/clan-cli/tests/temporary_dir.py | 13 ++--- pkgs/clan-cli/tests/test_clan_uri.py | 48 +++++++++---------- 12 files changed, 55 insertions(+), 55 deletions(-) diff --git a/pkgs/clan-app/tests/temporary_dir.py b/pkgs/clan-app/tests/temporary_dir.py index aaa54ca27..65c524b1d 100644 --- a/pkgs/clan-app/tests/temporary_dir.py +++ b/pkgs/clan-app/tests/temporary_dir.py @@ -19,9 +19,10 @@ def temporary_home(monkeypatch: pytest.MonkeyPatch) -> Iterator[Path]: monkeypatch.chdir(str(path)) yield path else: - with tempfile.TemporaryDirectory(prefix="pytest-") as dirpath: + with tempfile.TemporaryDirectory(prefix="pytest-") as _dirpath: + dirpath = Path(_dirpath) monkeypatch.setenv("HOME", str(dirpath)) - monkeypatch.setenv("XDG_CONFIG_HOME", str(Path(dirpath) / ".config")) + monkeypatch.setenv("XDG_CONFIG_HOME", str(dirpath / ".config")) monkeypatch.chdir(str(dirpath)) log.debug("Temp HOME directory: %s", str(dirpath)) - yield Path(dirpath) + yield dirpath diff --git a/pkgs/clan-cli/clan_cli/facts/generate.py b/pkgs/clan-cli/clan_cli/facts/generate.py index c5da1e3a6..be046117c 100644 --- a/pkgs/clan-cli/clan_cli/facts/generate.py +++ b/pkgs/clan-cli/clan_cli/facts/generate.py @@ -202,8 +202,8 @@ def generate_facts( prompt: Callable[[str, str], str] = prompt_func, ) -> bool: was_regenerated = False - with TemporaryDirectory(prefix="facts-generate-") as tmp: - tmpdir = Path(tmp) + with TemporaryDirectory(prefix="facts-generate-") as _tmpdir: + tmpdir = Path(_tmpdir).resolve() for machine in machines: errors = 0 diff --git a/pkgs/clan-cli/clan_cli/facts/upload.py b/pkgs/clan-cli/clan_cli/facts/upload.py index aff152d53..054714d8e 100644 --- a/pkgs/clan-cli/clan_cli/facts/upload.py +++ b/pkgs/clan-cli/clan_cli/facts/upload.py @@ -19,8 +19,8 @@ def upload_secrets(machine: Machine) -> None: machine.info("Secrets already uploaded") return - with TemporaryDirectory(prefix="facts-upload-") as tempdir: - local_secret_dir = Path(tempdir) + with TemporaryDirectory(prefix="facts-upload-") as _tempdir: + local_secret_dir = Path(_tempdir).resolve() secret_facts_store.upload(local_secret_dir) remote_secret_dir = Path(machine.secrets_upload_directory) diff --git a/pkgs/clan-cli/clan_cli/flash/flash.py b/pkgs/clan-cli/clan_cli/flash/flash.py index 66d948c9a..217ecf98d 100644 --- a/pkgs/clan-cli/clan_cli/flash/flash.py +++ b/pkgs/clan-cli/clan_cli/flash/flash.py @@ -100,8 +100,8 @@ def flash_machine( secret_facts_store: SecretStoreBase = secret_facts_module.SecretStore( machine=machine ) - with TemporaryDirectory(prefix="disko-install-") as tmpdir_: - tmpdir = Path(tmpdir_) + with TemporaryDirectory(prefix="disko-install-") as _tmpdir: + tmpdir = Path(_tmpdir) upload_dir = machine.secrets_upload_directory if upload_dir.startswith("/"): diff --git a/pkgs/clan-cli/clan_cli/machines/install.py b/pkgs/clan-cli/clan_cli/machines/install.py index 04a5d30ff..3cbe07448 100644 --- a/pkgs/clan-cli/clan_cli/machines/install.py +++ b/pkgs/clan-cli/clan_cli/machines/install.py @@ -61,8 +61,9 @@ def install_machine(opts: InstallOptions) -> None: generate_facts([machine]) generate_vars([machine]) - with TemporaryDirectory(prefix="nixos-install-") as base_directory: - activation_secrets = Path(base_directory) / "activation_secrets" + with TemporaryDirectory(prefix="nixos-install-") as _base_directory: + base_directory = Path(_base_directory).resolve() + activation_secrets = base_directory / "activation_secrets" upload_dir = activation_secrets / machine.secrets_upload_directory.lstrip("/") upload_dir.mkdir(parents=True) machine.secret_facts_store.upload(upload_dir) @@ -70,7 +71,7 @@ def install_machine(opts: InstallOptions) -> None: upload_dir, phases=["activation", "users", "services"] ) - partitioning_secrets = Path(base_directory) / "partitioning_secrets" + partitioning_secrets = base_directory / "partitioning_secrets" partitioning_secrets.mkdir(parents=True) machine.secret_vars_store.populate_dir( partitioning_secrets, phases=["partitioning"] diff --git a/pkgs/clan-cli/clan_cli/machines/morph.py b/pkgs/clan-cli/clan_cli/machines/morph.py index 46981b9a3..b438516ae 100644 --- a/pkgs/clan-cli/clan_cli/machines/morph.py +++ b/pkgs/clan-cli/clan_cli/machines/morph.py @@ -56,8 +56,8 @@ def morph_machine( ).stdout.rstrip() archive_path = json.loads(archive_json)["path"] - with TemporaryDirectory(prefix="morph-") as temp_dir: - flakedir = Path(temp_dir) / "flake" + with TemporaryDirectory(prefix="morph-") as _temp_dir: + flakedir = Path(_temp_dir).resolve() / "flake" flakedir.mkdir(parents=True, exist_ok=True) run(["cp", "-r", archive_path + "/.", str(flakedir)]) diff --git a/pkgs/clan-cli/clan_cli/vars/generate.py b/pkgs/clan-cli/clan_cli/vars/generate.py index 170ab82ea..57ea6607d 100644 --- a/pkgs/clan-cli/clan_cli/vars/generate.py +++ b/pkgs/clan-cli/clan_cli/vars/generate.py @@ -181,8 +181,8 @@ def execute_generator( raise ClanError(msg) from e env = os.environ.copy() - with TemporaryDirectory(prefix="vars-") as tmp: - tmpdir = Path(tmp) + with TemporaryDirectory(prefix="vars-") as _tmpdir: + tmpdir = Path(_tmpdir).resolve() tmpdir_in = tmpdir / "in" tmpdir_prompts = tmpdir / "prompts" tmpdir_out = tmpdir / "out" diff --git a/pkgs/clan-cli/clan_cli/vars/secret_modules/password_store.py b/pkgs/clan-cli/clan_cli/vars/secret_modules/password_store.py index 57524d8c4..6d5069e47 100644 --- a/pkgs/clan-cli/clan_cli/vars/secret_modules/password_store.py +++ b/pkgs/clan-cli/clan_cli/vars/secret_modules/password_store.py @@ -231,8 +231,8 @@ class SecretStore(StoreBase): if not self.needs_upload(): log.info("Secrets already uploaded") return - with TemporaryDirectory(prefix="vars-upload-") as tempdir: - pass_dir = Path(tempdir) + with TemporaryDirectory(prefix="vars-upload-") as _tempdir: + pass_dir = Path(_tempdir).resolve() self.populate_dir(pass_dir, phases) upload_dir = Path( self.machine.deployment["password-store"]["secretLocation"] diff --git a/pkgs/clan-cli/clan_cli/vars/secret_modules/sops.py b/pkgs/clan-cli/clan_cli/vars/secret_modules/sops.py index 3ef05ce2b..bcdf147c7 100644 --- a/pkgs/clan-cli/clan_cli/vars/secret_modules/sops.py +++ b/pkgs/clan-cli/clan_cli/vars/secret_modules/sops.py @@ -224,8 +224,8 @@ class SecretStore(StoreBase): if "partitioning" in phases: msg = "Cannot upload partitioning secrets" raise NotImplementedError(msg) - with TemporaryDirectory(prefix="sops-upload-") as tempdir: - sops_upload_dir = Path(tempdir) + with TemporaryDirectory(prefix="sops-upload-") as _tempdir: + sops_upload_dir = Path(_tempdir).resolve() self.populate_dir(sops_upload_dir, phases) upload(self.machine.target_host, sops_upload_dir, Path("/var/lib/sops-nix")) diff --git a/pkgs/clan-cli/tests/fixtures_flakes.py b/pkgs/clan-cli/tests/fixtures_flakes.py index 17b32ec4a..eab0bb376 100644 --- a/pkgs/clan-cli/tests/fixtures_flakes.py +++ b/pkgs/clan-cli/tests/fixtures_flakes.py @@ -209,12 +209,13 @@ class ClanFlake: @pytest.fixture(scope="session") def minimal_flake_template() -> Iterator[ClanFlake]: with ( - tempfile.TemporaryDirectory(prefix="flake-") as home, + tempfile.TemporaryDirectory(prefix="flake-") as _home, pytest.MonkeyPatch.context() as mp, ): - mp.setenv("HOME", home) + home = Path(_home).resolve() + mp.setenv("HOME", str(home)) flake = ClanFlake( - temporary_home=Path(home), + temporary_home=home, flake_template=clan_templates(TemplateType.CLAN) / "minimal", ) flake.init_from_template() diff --git a/pkgs/clan-cli/tests/temporary_dir.py b/pkgs/clan-cli/tests/temporary_dir.py index 8713ac9f4..36ae5bc84 100644 --- a/pkgs/clan-cli/tests/temporary_dir.py +++ b/pkgs/clan-cli/tests/temporary_dir.py @@ -11,12 +11,13 @@ log = logging.getLogger(__name__) @pytest.fixture def temporary_home(monkeypatch: pytest.MonkeyPatch) -> Iterator[Path]: - with tempfile.TemporaryDirectory(prefix="pytest-home-") as dirpath: + with tempfile.TemporaryDirectory(prefix="pytest-home-") as _dirpath: + dirpath = Path(_dirpath).resolve() xdg_runtime_dir = os.getenv("XDG_RUNTIME_DIR") monkeypatch.setenv("HOME", str(dirpath)) - monkeypatch.setenv("XDG_CONFIG_HOME", str(Path(dirpath) / ".config")) + monkeypatch.setenv("XDG_CONFIG_HOME", str(dirpath / ".config")) - runtime_dir = Path(dirpath) / "xdg-runtime-dir" + runtime_dir = dirpath / "xdg-runtime-dir" runtime_dir.mkdir() runtime_dir.chmod(0o700) @@ -34,10 +35,10 @@ def temporary_home(monkeypatch: pytest.MonkeyPatch) -> Iterator[Path]: monkeypatch.setenv("XDG_RUNTIME_DIR", str(runtime_dir)) monkeypatch.chdir(str(dirpath)) - yield Path(dirpath) + yield dirpath @pytest.fixture def temp_dir() -> Iterator[Path]: - with tempfile.TemporaryDirectory(prefix="pytest-") as dirpath: - yield Path(dirpath) + with tempfile.TemporaryDirectory(prefix="pytest-") as _dirpath: + yield Path(_dirpath).resolve() diff --git a/pkgs/clan-cli/tests/test_clan_uri.py b/pkgs/clan-cli/tests/test_clan_uri.py index 703e763d6..d85b61680 100644 --- a/pkgs/clan-cli/tests/test_clan_uri.py +++ b/pkgs/clan-cli/tests/test_clan_uri.py @@ -1,5 +1,4 @@ from pathlib import Path -from tempfile import TemporaryDirectory import pytest from clan_cli.clan_uri import ClanURI @@ -36,14 +35,13 @@ def test_firefox_strip_uri() -> None: assert uri.get_url() == "git+https://git.clan.lol/clan/democlan.git" -def test_local_uri() -> None: - with TemporaryDirectory(prefix="clan_test") as tempdir: - flake_nix = Path(tempdir) / "flake.nix" - flake_nix.write_text("outputs = _: {}") +def test_local_uri(temp_dir: Path) -> None: + flake_nix = temp_dir / "flake.nix" + flake_nix.write_text("outputs = _: {}") - # Create a ClanURI object from a local URI - uri = ClanURI.from_str(f"clan://file://{tempdir}") - assert uri.flake.path == Path(tempdir) + # Create a ClanURI object from a local URI + uri = ClanURI.from_str(f"clan://file://{temp_dir}") + assert uri.flake.path == temp_dir def test_is_remote() -> None: @@ -79,25 +77,23 @@ def test_from_str_remote() -> None: assert uri.flake.identifier == "https://example.com" -def test_from_str_local() -> None: - with TemporaryDirectory(prefix="clan_test") as tempdir: - flake_nix = Path(tempdir) / "flake.nix" - flake_nix.write_text("outputs = _: {}") +def test_from_str_local(temp_dir: Path) -> None: + flake_nix = temp_dir / "flake.nix" + flake_nix.write_text("outputs = _: {}") - uri = ClanURI.from_str(url=tempdir, machine_name="myVM") - assert uri.get_url().endswith(tempdir) - assert uri.machine_name == "myVM" - assert uri.flake.is_local - assert str(uri.flake).endswith(tempdir) # type: ignore + uri = ClanURI.from_str(url=str(temp_dir), machine_name="myVM") + assert uri.get_url().endswith(str(temp_dir)) + assert uri.machine_name == "myVM" + assert uri.flake.is_local + assert str(uri.flake).endswith(str(temp_dir)) -def test_from_str_local_no_machine() -> None: - with TemporaryDirectory(prefix="clan_test") as tempdir: - flake_nix = Path(tempdir) / "flake.nix" - flake_nix.write_text("outputs = _: {}") +def test_from_str_local_no_machine(temp_dir: Path) -> None: + flake_nix = temp_dir / "flake.nix" + flake_nix.write_text("outputs = _: {}") - uri = ClanURI.from_str(tempdir) - assert uri.get_url().endswith(tempdir) - assert uri.machine_name == "defaultVM" - assert uri.flake.is_local - assert str(uri.flake).endswith(tempdir) # type: ignore + uri = ClanURI.from_str(str(temp_dir)) + assert uri.get_url().endswith(str(temp_dir)) + assert uri.machine_name == "defaultVM" + assert uri.flake.is_local + assert str(uri.flake).endswith(str(temp_dir))