forked from clan/clan-core
simplify clan uri further
This commit is contained in:
parent
e637394370
commit
cc583dd79e
@ -12,7 +12,9 @@ class FlakeId:
|
|||||||
_value: str | Path
|
_value: str | Path
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return f"{self._value}" # The __str__ method returns a custom string representation
|
return str(
|
||||||
|
self._value
|
||||||
|
) # The __str__ method returns a custom string representation
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def path(self) -> Path:
|
def path(self) -> Path:
|
||||||
@ -34,26 +36,13 @@ class FlakeId:
|
|||||||
return isinstance(self._value, str)
|
return isinstance(self._value, str)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MachineData:
|
|
||||||
flake_id: FlakeId
|
|
||||||
name: str = "defaultVM"
|
|
||||||
|
|
||||||
def get_id(self) -> str:
|
|
||||||
return f"{self.flake_id}#{self.name}"
|
|
||||||
|
|
||||||
|
|
||||||
# Define the ClanURI class
|
# Define the ClanURI class
|
||||||
class ClanURI:
|
class ClanURI:
|
||||||
_orig_uri: str
|
|
||||||
_components: urllib.parse.ParseResult
|
|
||||||
flake_id: FlakeId
|
flake_id: FlakeId
|
||||||
_machines: list[MachineData]
|
machine_name: str
|
||||||
|
|
||||||
# Initialize the class with a clan:// URI
|
# Initialize the class with a clan:// URI
|
||||||
def __init__(self, uri: str) -> None:
|
def __init__(self, uri: str) -> None:
|
||||||
self._machines = []
|
|
||||||
|
|
||||||
# users might copy whitespace along with the uri
|
# users might copy whitespace along with the uri
|
||||||
uri = uri.strip()
|
uri = uri.strip()
|
||||||
self._orig_uri = uri
|
self._orig_uri = uri
|
||||||
@ -67,21 +56,16 @@ class ClanURI:
|
|||||||
|
|
||||||
# Parse the URI into components
|
# Parse the URI into components
|
||||||
# url://netloc/path;parameters?query#fragment
|
# url://netloc/path;parameters?query#fragment
|
||||||
self._components = urllib.parse.urlparse(nested_uri)
|
components: urllib.parse.ParseResult = urllib.parse.urlparse(nested_uri)
|
||||||
|
|
||||||
# Replace the query string in the components with the new query string
|
# Replace the query string in the components with the new query string
|
||||||
clean_comps = self._components._replace(
|
clean_comps = components._replace(query=components.query, fragment="")
|
||||||
query=self._components.query, fragment=""
|
|
||||||
)
|
|
||||||
|
|
||||||
# Parse the URL into a ClanUrl object
|
# Parse the URL into a ClanUrl object
|
||||||
self.flake_id = self._parse_url(clean_comps)
|
self.flake_id = self._parse_url(clean_comps)
|
||||||
|
self.machine_name = "defaultVM"
|
||||||
if self._components.fragment == "":
|
if components.fragment:
|
||||||
self._machines.append(MachineData(flake_id=self.flake_id))
|
self.machine_name = components.fragment
|
||||||
return
|
|
||||||
|
|
||||||
self._machines.append(self._parse_machine_query(self._components.fragment))
|
|
||||||
|
|
||||||
def _parse_url(self, comps: urllib.parse.ParseResult) -> FlakeId:
|
def _parse_url(self, comps: urllib.parse.ParseResult) -> FlakeId:
|
||||||
comb = (
|
comb = (
|
||||||
@ -100,20 +84,6 @@ class ClanURI:
|
|||||||
|
|
||||||
return flake_id
|
return flake_id
|
||||||
|
|
||||||
def _parse_machine_query(self, machine_frag: str) -> MachineData:
|
|
||||||
comp = urllib.parse.urlparse(machine_frag)
|
|
||||||
machine_name = comp.path
|
|
||||||
|
|
||||||
machine = MachineData(flake_id=self.flake_id, name=machine_name)
|
|
||||||
return machine
|
|
||||||
|
|
||||||
@property
|
|
||||||
def machine(self) -> MachineData:
|
|
||||||
return self._machines[0]
|
|
||||||
|
|
||||||
def get_orig_uri(self) -> str:
|
|
||||||
return self._orig_uri
|
|
||||||
|
|
||||||
def get_url(self) -> str:
|
def get_url(self) -> str:
|
||||||
return str(self.flake_id)
|
return str(self.flake_id)
|
||||||
|
|
||||||
@ -134,8 +104,5 @@ class ClanURI:
|
|||||||
|
|
||||||
return cls(clan_uri)
|
return cls(clan_uri)
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return self.get_orig_uri()
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"ClanURI({self})"
|
return f"ClanURI({self})"
|
||||||
|
@ -82,7 +82,7 @@ def add_all_to_history(uri: ClanURI) -> list[HistoryEntry]:
|
|||||||
def add_history(uri: ClanURI) -> HistoryEntry:
|
def add_history(uri: ClanURI) -> HistoryEntry:
|
||||||
user_history_file().parent.mkdir(parents=True, exist_ok=True)
|
user_history_file().parent.mkdir(parents=True, exist_ok=True)
|
||||||
history = list_history()
|
history = list_history()
|
||||||
new_entry = _add_maschine_to_history_list(uri.get_url(), uri.machine.name, history)
|
new_entry = _add_maschine_to_history_list(uri.get_url(), uri.machine_name, history)
|
||||||
write_history_file(history)
|
write_history_file(history)
|
||||||
return new_entry
|
return new_entry
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ def update_history() -> list[HistoryEntry]:
|
|||||||
url=str(entry.flake.flake_url),
|
url=str(entry.flake.flake_url),
|
||||||
machine_name=entry.flake.flake_attr,
|
machine_name=entry.flake.flake_attr,
|
||||||
)
|
)
|
||||||
flake = inspect_flake(uri.get_url(), uri.machine.name)
|
flake = inspect_flake(uri.get_url(), uri.machine_name)
|
||||||
flake.flake_url = str(flake.flake_url)
|
flake.flake_url = str(flake.flake_url)
|
||||||
entry = HistoryEntry(
|
entry = HistoryEntry(
|
||||||
flake=flake, last_used=datetime.datetime.now().isoformat()
|
flake=flake, last_used=datetime.datetime.now().isoformat()
|
||||||
|
@ -4,7 +4,7 @@ from pathlib import Path
|
|||||||
from tempfile import NamedTemporaryFile
|
from tempfile import NamedTemporaryFile
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from clan_cli.clan_uri import ClanURI, MachineData
|
from clan_cli.clan_uri import ClanURI, FlakeId
|
||||||
|
|
||||||
from ..cmd import run_no_stdout
|
from ..cmd import run_no_stdout
|
||||||
from ..errors import ClanError
|
from ..errors import ClanError
|
||||||
@ -16,8 +16,7 @@ log = logging.getLogger(__name__)
|
|||||||
|
|
||||||
class Machine:
|
class Machine:
|
||||||
name: str
|
name: str
|
||||||
flake: str | Path
|
flake: FlakeId
|
||||||
data: MachineData
|
|
||||||
nix_options: list[str]
|
nix_options: list[str]
|
||||||
eval_cache: dict[str, str]
|
eval_cache: dict[str, str]
|
||||||
build_cache: dict[str, Path]
|
build_cache: dict[str, Path]
|
||||||
@ -30,7 +29,6 @@ class Machine:
|
|||||||
flake: Path | str,
|
flake: Path | str,
|
||||||
deployment_info: dict | None = None,
|
deployment_info: dict | None = None,
|
||||||
nix_options: list[str] = [],
|
nix_options: list[str] = [],
|
||||||
machine: MachineData | None = None,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Creates a Machine
|
Creates a Machine
|
||||||
@ -38,14 +36,9 @@ class Machine:
|
|||||||
@clan_dir: the directory of the clan, optional, if not set it will be determined from the current working directory
|
@clan_dir: the directory of the clan, optional, if not set it will be determined from the current working directory
|
||||||
@machine_json: can be optionally used to skip evaluation of the machine, location of the json file with machine data
|
@machine_json: can be optionally used to skip evaluation of the machine, location of the json file with machine data
|
||||||
"""
|
"""
|
||||||
if machine is None:
|
|
||||||
uri = ClanURI.from_str(str(flake), name)
|
uri = ClanURI.from_str(str(flake), name)
|
||||||
machine = uri.machine
|
self.flake_id = uri.flake_id
|
||||||
self.flake: str | Path = machine.flake_id._value
|
self.name: str = uri.machine_name
|
||||||
self.name: str = machine.name
|
|
||||||
self.data: MachineData = machine
|
|
||||||
else:
|
|
||||||
self.data: MachineData = machine
|
|
||||||
|
|
||||||
self.eval_cache: dict[str, str] = {}
|
self.eval_cache: dict[str, str] = {}
|
||||||
self.build_cache: dict[str, Path] = {}
|
self.build_cache: dict[str, Path] = {}
|
||||||
@ -60,7 +53,7 @@ class Machine:
|
|||||||
self.eval_cache.clear()
|
self.eval_cache.clear()
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return f"Machine(name={self.data.name}, flake={self.data.flake_id})"
|
return f"Machine(name={self.name}, flake={self.flake_id})"
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return str(self)
|
return str(self)
|
||||||
@ -81,7 +74,7 @@ class Machine:
|
|||||||
"deploymentAddress"
|
"deploymentAddress"
|
||||||
)
|
)
|
||||||
if val is None:
|
if val is None:
|
||||||
msg = f"the 'clan.networking.targetHost' nixos option is not set for machine '{self.data.name}'"
|
msg = f"the 'clan.networking.targetHost' nixos option is not set for machine '{self.name}'"
|
||||||
raise ClanError(msg)
|
raise ClanError(msg)
|
||||||
return val
|
return val
|
||||||
|
|
||||||
@ -112,12 +105,12 @@ class Machine:
|
|||||||
if self._flake_path:
|
if self._flake_path:
|
||||||
return self._flake_path
|
return self._flake_path
|
||||||
|
|
||||||
if self.data.flake_id.is_local():
|
if self.flake_id.is_local():
|
||||||
self._flake_path = self.data.flake_id.path
|
self._flake_path = self.flake_id.path
|
||||||
elif self.data.flake_id.is_remote():
|
elif self.flake_id.is_remote():
|
||||||
self._flake_path = Path(nix_metadata(self.data.flake_id.url)["path"])
|
self._flake_path = Path(nix_metadata(self.flake_id.url)["path"])
|
||||||
else:
|
else:
|
||||||
raise ClanError(f"Unsupported flake url: {self.data.flake_id}")
|
raise ClanError(f"Unsupported flake url: {self.flake_id}")
|
||||||
|
|
||||||
assert self._flake_path is not None
|
assert self._flake_path is not None
|
||||||
return self._flake_path
|
return self._flake_path
|
||||||
@ -125,7 +118,7 @@ class Machine:
|
|||||||
@property
|
@property
|
||||||
def target_host(self) -> Host:
|
def target_host(self) -> Host:
|
||||||
return parse_deployment_address(
|
return parse_deployment_address(
|
||||||
self.data.name, self.target_host_address, meta={"machine": self}
|
self.name, self.target_host_address, meta={"machine": self}
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -139,7 +132,7 @@ class Machine:
|
|||||||
return self.target_host
|
return self.target_host
|
||||||
# enable ssh agent forwarding to allow the build host to access the target host
|
# enable ssh agent forwarding to allow the build host to access the target host
|
||||||
return parse_deployment_address(
|
return parse_deployment_address(
|
||||||
self.data.name,
|
self.name,
|
||||||
build_host,
|
build_host,
|
||||||
forward_agent=True,
|
forward_agent=True,
|
||||||
meta={"machine": self, "target_host": self.target_host},
|
meta={"machine": self, "target_host": self.target_host},
|
||||||
@ -198,7 +191,7 @@ class Machine:
|
|||||||
args += [
|
args += [
|
||||||
"--expr",
|
"--expr",
|
||||||
f"""
|
f"""
|
||||||
((builtins.getFlake "{url}").clanInternals.machinesFunc."{system}"."{self.data.name}" {{
|
((builtins.getFlake "{url}").clanInternals.machinesFunc."{system}"."{self.name}" {{
|
||||||
extraConfig = builtins.fromJSON (builtins.readFile (builtins.fetchTree {{
|
extraConfig = builtins.fromJSON (builtins.readFile (builtins.fetchTree {{
|
||||||
type = "file";
|
type = "file";
|
||||||
url = if (builtins.compareVersions builtins.nixVersion "2.19") == -1 then "{file_info["path"]}" else "file:{file_info["path"]}";
|
url = if (builtins.compareVersions builtins.nixVersion "2.19") == -1 then "{file_info["path"]}" else "file:{file_info["path"]}";
|
||||||
@ -213,9 +206,7 @@ class Machine:
|
|||||||
else:
|
else:
|
||||||
flake = f"path:{self.flake_dir}"
|
flake = f"path:{self.flake_dir}"
|
||||||
|
|
||||||
args += [
|
args += [f'{flake}#clanInternals.machines."{system}".{self.name}.{attr}']
|
||||||
f'{flake}#clanInternals.machines."{system}".{self.data.name}.{attr}'
|
|
||||||
]
|
|
||||||
args += nix_options + self.nix_options
|
args += nix_options + self.nix_options
|
||||||
|
|
||||||
if method == "eval":
|
if method == "eval":
|
||||||
|
@ -46,25 +46,21 @@ def test_remote_with_clanparams() -> None:
|
|||||||
# Create a ClanURI object from a remote URI with parameters
|
# Create a ClanURI object from a remote URI with parameters
|
||||||
uri = ClanURI("clan://https://example.com")
|
uri = ClanURI("clan://https://example.com")
|
||||||
|
|
||||||
assert uri.machine.name == "defaultVM"
|
assert uri.machine_name == "defaultVM"
|
||||||
assert uri.flake_id.url == "https://example.com"
|
assert uri.flake_id.url == "https://example.com"
|
||||||
|
|
||||||
|
|
||||||
def test_from_str_remote() -> None:
|
def test_from_str_remote() -> None:
|
||||||
uri = ClanURI.from_str(url="https://example.com", machine_name="myVM")
|
uri = ClanURI.from_str(url="https://example.com", machine_name="myVM")
|
||||||
assert uri.get_url() == "https://example.com"
|
assert uri.get_url() == "https://example.com"
|
||||||
assert uri.get_orig_uri() == "clan://https://example.com#myVM"
|
assert uri.machine_name == "myVM"
|
||||||
assert uri.machine.name == "myVM"
|
|
||||||
assert len(uri._machines) == 1
|
|
||||||
assert uri.flake_id.url == "https://example.com"
|
assert uri.flake_id.url == "https://example.com"
|
||||||
|
|
||||||
|
|
||||||
def test_from_str_local() -> None:
|
def test_from_str_local() -> None:
|
||||||
uri = ClanURI.from_str(url="~/Projects/democlan", machine_name="myVM")
|
uri = ClanURI.from_str(url="~/Projects/democlan", machine_name="myVM")
|
||||||
assert uri.get_url().endswith("/Projects/democlan")
|
assert uri.get_url().endswith("/Projects/democlan")
|
||||||
assert uri.get_orig_uri() == "clan://~/Projects/democlan#myVM"
|
assert uri.machine_name == "myVM"
|
||||||
assert uri.machine.name == "myVM"
|
|
||||||
assert len(uri._machines) == 1
|
|
||||||
assert uri.flake_id.is_local()
|
assert uri.flake_id.is_local()
|
||||||
assert str(uri.flake_id).endswith("/Projects/democlan") # type: ignore
|
assert str(uri.flake_id).endswith("/Projects/democlan") # type: ignore
|
||||||
|
|
||||||
@ -72,9 +68,7 @@ def test_from_str_local() -> None:
|
|||||||
def test_from_str_local_no_machine() -> None:
|
def test_from_str_local_no_machine() -> None:
|
||||||
uri = ClanURI.from_str("~/Projects/democlan")
|
uri = ClanURI.from_str("~/Projects/democlan")
|
||||||
assert uri.get_url().endswith("/Projects/democlan")
|
assert uri.get_url().endswith("/Projects/democlan")
|
||||||
assert uri.get_orig_uri() == "clan://~/Projects/democlan"
|
assert uri.machine_name == "defaultVM"
|
||||||
assert uri.machine.name == "defaultVM"
|
|
||||||
assert len(uri._machines) == 1
|
|
||||||
assert uri.flake_id.is_local()
|
assert uri.flake_id.is_local()
|
||||||
assert str(uri.flake_id).endswith("/Projects/democlan") # type: ignore
|
assert str(uri.flake_id).endswith("/Projects/democlan") # type: ignore
|
||||||
|
|
||||||
@ -82,8 +76,6 @@ def test_from_str_local_no_machine() -> None:
|
|||||||
def test_from_str_local_no_machine2() -> None:
|
def test_from_str_local_no_machine2() -> None:
|
||||||
uri = ClanURI.from_str("~/Projects/democlan#syncthing-peer1")
|
uri = ClanURI.from_str("~/Projects/democlan#syncthing-peer1")
|
||||||
assert uri.get_url().endswith("/Projects/democlan")
|
assert uri.get_url().endswith("/Projects/democlan")
|
||||||
assert uri.get_orig_uri() == "clan://~/Projects/democlan#syncthing-peer1"
|
assert uri.machine_name == "syncthing-peer1"
|
||||||
assert uri.machine.name == "syncthing-peer1"
|
|
||||||
assert len(uri._machines) == 1
|
|
||||||
assert uri.flake_id.is_local()
|
assert uri.flake_id.is_local()
|
||||||
assert str(uri.flake_id).endswith("/Projects/democlan") # type: ignore
|
assert str(uri.flake_id).endswith("/Projects/democlan") # type: ignore
|
||||||
|
Loading…
Reference in New Issue
Block a user