clan-cli flake caching: fix selectors not merging

This commit is contained in:
lassulus
2025-02-15 06:52:19 +01:00
committed by clan-bot
parent 2a3bc7b31b
commit d5e391ecc8
2 changed files with 62 additions and 18 deletions

View File

@@ -5,7 +5,7 @@ import re
from dataclasses import dataclass
from hashlib import sha1
from pathlib import Path
from typing import Any
from typing import Any, cast
from clan_cli.cmd import run
from clan_cli.dirs import user_cache_dir
@@ -68,16 +68,22 @@ class FlakeCacheEntry:
is_out_path: bool = False,
) -> None:
self.value: str | float | int | dict[str | int, FlakeCacheEntry]
self.selector: Selector
self.selector: set[int] | set[str] | AllSelector
selector: Selector = AllSelector()
if selectors == []:
self.selector = AllSelector()
elif isinstance(selectors[0], set):
self.selector = selectors[0]
selector = selectors[0]
elif isinstance(selectors[0], int):
self.selector = {int(selectors[0])}
selector = int(selectors[0])
elif isinstance(selectors[0], str):
self.selector = selectors[0]
self.value = {self.selector: FlakeCacheEntry(value, selectors[1:])}
return
else:
self.selector = selectors[0]
self.selector = {(selectors[0])}
selector = selectors[0]
elif isinstance(selectors[0], AllSelector):
self.selector = AllSelector()
if is_out_path:
if selectors != []:
@@ -88,6 +94,9 @@ class FlakeCacheEntry:
raise ValueError(msg)
self.value = value
elif isinstance(selector, str):
self.value = {selector: FlakeCacheEntry(value, selectors[1:])}
elif isinstance(value, dict):
if isinstance(self.selector, set):
if not all(isinstance(v, str) for v in self.selector):
@@ -103,18 +112,17 @@ class FlakeCacheEntry:
self.value[key] = FlakeCacheEntry(value_, selectors[1:])
elif isinstance(value, list):
if isinstance(self.selector, int):
if isinstance(selector, int):
if len(value) != 1:
msg = "Cannot index list with int selector when value is not singleton"
raise ValueError(msg)
self.value = {}
self.value[int(self.selector)] = FlakeCacheEntry(
value[0], selectors[1:]
)
if isinstance(self.selector, set):
if all(isinstance(v, int) for v in self.selector):
self.value = {
int(selector): FlakeCacheEntry(value[0], selectors[1:]),
}
if isinstance(selector, set):
if all(isinstance(v, int) for v in selector):
self.value = {}
for i, v in enumerate(self.selector):
for i, v in enumerate([selector]):
assert isinstance(v, int)
self.value[int(v)] = FlakeCacheEntry(value[i], selectors[1:])
else:
@@ -126,11 +134,12 @@ class FlakeCacheEntry:
if isinstance(v, dict | list | str | float | int):
self.value[i] = FlakeCacheEntry(v, selectors[1:])
else:
msg = f"expected integer selector or all for type list, but got {type(selectors[0])}"
msg = f"expected integer selector or all for type list, but got {type(selector)}"
raise TypeError(msg)
elif isinstance(value, str) and value.startswith("/nix/store/"):
self.value = {}
self.selector = self.selector = {"outPath"}
self.value["outPath"] = FlakeCacheEntry(
value, selectors[1:], is_out_path=True
)
@@ -160,7 +169,34 @@ class FlakeCacheEntry:
if isinstance(selector, AllSelector):
self.selector = AllSelector()
elif isinstance(self.selector, set) and isinstance(selector, set):
self.selector.union(selector)
if all(isinstance(v, str) for v in self.selector) and all(
isinstance(v, str) for v in selector
):
selector = cast(set[str], selector)
self.selector = cast(set[str], self.selector)
self.selector = self.selector.union(selector)
elif all(isinstance(v, int) for v in self.selector) and all(
isinstance(v, int) for v in selector
):
selector = cast(set[int], selector)
self.selector = cast(set[int], self.selector)
self.selector = self.selector.union(selector)
else:
msg = "Cannot union set of different types"
raise ValueError(msg)
elif isinstance(self.selector, set) and isinstance(selector, int):
if all(isinstance(v, int) for v in self.selector):
self.selector = cast(set[int], self.selector)
self.selector.add(selector)
elif isinstance(self.selector, set) and isinstance(selector, str):
if all(isinstance(v, str) for v in self.selector):
self.selector = cast(set[str], self.selector)
self.selector.add(selector)
else:
msg = f"Cannot insert {selector} into {self.selector}"
raise TypeError(msg)
if isinstance(self.value, dict) and isinstance(value, dict):
for key, value_ in value.items():
@@ -191,6 +227,11 @@ class FlakeCacheEntry:
self.value[selector].insert(value[0], selectors[1:])
else:
self.value[selector] = FlakeCacheEntry(value[0], selectors[1:])
elif isinstance(value, str) and value.startswith("/nix/store/"):
self.value = {}
self.value["outPath"] = FlakeCacheEntry(
value, selectors[1:], is_out_path=True
)
elif isinstance(value, (str | float | int)):
if self.value:

View File

@@ -53,5 +53,8 @@ def test_cache_persistance(flake: ClanFlake) -> None:
"nixosConfigurations.*.config.networking.hostName"
)
flake1.select("nixosConfigurations.*.config.networking.hostName")
flake1.select("nixosConfigurations.*.config.networking.{hostName,hostId}")
flake2.prefetch()
assert flake2._cache.is_cached("nixosConfigurations.*.config.networking.hostName") # noqa: SLF001
assert flake2._cache.is_cached( # noqa: SLF001
"nixosConfigurations.*.config.networking.{hostName,hostId}"
)