Merge pull request 'Added clan flakes inspect command. Improved ClanURI. Added democlan as dependency in flake.nix' (#635) from Qubasa-main into main

This commit is contained in:
clan-bot
2023-12-08 23:25:37 +00:00
11 changed files with 155 additions and 32 deletions

View File

@@ -88,7 +88,13 @@ class ClanURI:
raise ClanError(f"Unsupported uri components: {comb}")
def get_internal(self) -> str:
return self._nested_uri
match self.scheme:
case ClanScheme.FILE.value(path):
return str(path) # type: ignore
case ClanScheme.HTTP.value(url):
return url # type: ignore
case _:
raise ClanError(f"Unsupported uri components: {self.scheme}")
@classmethod
def from_path(cls, path: Path, params: ClanParameters) -> Self: # noqa

View File

@@ -3,6 +3,7 @@ import argparse
from clan_cli.flakes.add import register_add_parser
from clan_cli.flakes.history import register_list_parser
from clan_cli.flakes.inspect import register_inspect_parser
from .create import register_create_parser
@@ -21,3 +22,5 @@ def register_parser(parser: argparse.ArgumentParser) -> None:
register_add_parser(add_parser)
list_parser = subparser.add_parser("list", help="List recently used flakes")
register_list_parser(list_parser)
inspect_parser = subparser.add_parser("inspect", help="Inspect a clan flake")
register_inspect_parser(inspect_parser)

View File

@@ -0,0 +1,83 @@
import argparse
import shlex
import subprocess
from dataclasses import dataclass
from pathlib import Path
from ..errors import ClanError
from ..nix import nix_config, nix_eval, nix_metadata
@dataclass
class FlakeConfig:
flake_url: str | Path
flake_attr: str
icon: str | None
description: str | None
last_updated: str
revision: str | None
def inspect_flake(flake_url: str | Path, flake_attr: str) -> FlakeConfig:
config = nix_config()
system = config["system"]
cmd = nix_eval(
[
f'{flake_url}#clanInternals.machines."{system}"."{flake_attr}".config.clanCore.clanIcon'
]
)
proc = subprocess.run(cmd, check=True, text=True, stdout=subprocess.PIPE)
assert proc.stdout is not None
if proc.returncode != 0:
raise ClanError(
f"""
command: {shlex.join(cmd)}
exit code: {proc.returncode}
stdout:
{proc.stdout}
"""
)
res = proc.stdout.strip()
if res == "null":
icon_path = None
else:
icon_path = res
meta = nix_metadata(flake_url)
return FlakeConfig(
flake_url=flake_url,
flake_attr=flake_attr,
icon=icon_path,
description=meta.get("description"),
last_updated=meta["lastModified"],
revision=meta.get("revision"),
)
@dataclass
class InspectOptions:
machine: str
flake: Path
def inspect_command(args: argparse.Namespace) -> None:
inspect_options = InspectOptions(
machine=args.machine,
flake=args.flake or Path.cwd(),
)
res = inspect_flake(
flake_url=inspect_options.flake, flake_attr=inspect_options.machine
)
print("Icon:", res.icon)
print("Description:", res.description)
print("Last updated:", res.last_updated)
print("Revision:", res.revision)
def register_inspect_parser(parser: argparse.ArgumentParser) -> None:
parser.add_argument("--machine", type=str, default="defaultVM")
parser.set_defaults(func=inspect_command)

View File

@@ -10,7 +10,6 @@ from .dirs import nixpkgs_flake, nixpkgs_source
from .errors import ClanError
@deal.raises(ClanError)
def nix_command(flags: list[str]) -> list[str]:
return ["nix", "--extra-experimental-features", "nix-command flakes", *flags]
@@ -28,7 +27,6 @@ def nix_flake_show(flake_url: str | Path) -> list[str]:
)
@deal.raises(ClanError)
def nix_build(
flags: list[str],
) -> list[str]:
@@ -45,7 +43,6 @@ def nix_build(
)
@deal.raises(ClanError)
def nix_config() -> dict[str, Any]:
cmd = nix_command(["show-config", "--json"])
proc = subprocess.run(cmd, check=True, text=True, stdout=subprocess.PIPE)
@@ -56,7 +53,6 @@ def nix_config() -> dict[str, Any]:
return config
@deal.raises(ClanError)
def nix_eval(flags: list[str]) -> list[str]:
default_flags = nix_command(
[
@@ -82,9 +78,8 @@ def nix_eval(flags: list[str]) -> list[str]:
return default_flags + flags
@deal.raises(ClanError)
def nix_metadata(flake: str) -> dict[str, Any]:
cmd = nix_command(["flake", "metadata", "--json", flake])
def nix_metadata(flake_url: str | Path) -> dict[str, Any]:
cmd = nix_command(["flake", "metadata", "--json", f"{flake_url}"])
proc = subprocess.run(cmd, check=True, text=True, stdout=subprocess.PIPE)
data = json.loads(proc.stdout)
return data

View File

@@ -30,6 +30,7 @@ def inspect_vm(flake_url: str | Path, flake_attr: str) -> VmConfig:
f'{flake_url}#clanInternals.machines."{system}"."{flake_attr}".config.system.clan.vm.config'
]
)
proc = subprocess.run(cmd, check=True, text=True, stdout=subprocess.PIPE)
assert proc.stdout is not None
if proc.returncode != 0:
@@ -65,5 +66,5 @@ def inspect_command(args: argparse.Namespace) -> None:
def register_inspect_parser(parser: argparse.ArgumentParser) -> None:
parser.add_argument("machine", type=str)
parser.add_argument("machine", type=str, default="defaultVM")
parser.set_defaults(func=inspect_command)

View File

@@ -37,7 +37,6 @@
, clan-core-path
, writeShellScriptBin
, nodePackages
, schemathesis ? null
}:
let
@@ -155,6 +154,7 @@ python3.pkgs.buildPythonApplication {
${checkPython}/bin/python -m pytest -m "not impure and with_core" -s ./tests
touch $out
'';
clan-pytest = runCommand "clan-pytest" { } ''
echo ${clan-pytest-without-core}
echo ${clan-pytest-with-core}

View File

@@ -31,14 +31,15 @@
{
devShells.clan-cli = pkgs.callPackage ./shell.nix {
inherit (self'.packages) clan-cli ui-assets nix-unit;
# inherit (inputs) democlan;
};
packages = {
clan-cli = pkgs.python3.pkgs.callPackage ./default.nix {
inherit (self'.packages) ui-assets;
inherit (inputs) nixpkgs;
# inherit (inputs) democlan;
inherit (inputs.nixpkgs-for-deal.legacyPackages.${system}.python3Packages) deal;
inherit (inputs.nixpkgs-for-deal.legacyPackages.${system}.python3Packages) schemathesis;
#inherit (inputs.nixpkgs-for-deal.legacyPackages.${system}.python3Packages) schemathesis;
clan-core-path = clanCoreWithVendoredDeps;
};
default = self'.packages.clan-cli;

View File

@@ -118,6 +118,24 @@ def test_flake_with_core(
)
@pytest.fixture
def test_local_democlan(
monkeypatch: pytest.MonkeyPatch, temporary_home: Path
) -> Iterator[FlakeForTest]:
democlan = os.getenv(key="DEMOCLAN_ROOT")
if democlan is None:
raise Exception(
"DEMOCLAN_ROOT not set. This test requires the democlan flake to be present"
)
democlan_p = Path(democlan).resolve()
if not democlan_p.is_dir():
raise Exception(
f"DEMOCLAN_ROOT ({democlan_p}) is not a directory. This test requires the democlan directory to be present"
)
yield FlakeForTest(democlan_p)
@pytest.fixture
def test_democlan_url(
monkeypatch: pytest.MonkeyPatch, temporary_home: Path

View File

@@ -6,6 +6,21 @@ from clan_cli.clan_uri import ClanParameters, ClanScheme, ClanURI
from clan_cli.errors import ClanError
def test_get_internal() -> None:
# Create a ClanURI object from a remote URI with parameters
uri = ClanURI("clan://https://example.com?flake_attr=myVM&password=1234")
assert uri.get_internal() == "https://example.com?password=1234"
uri = ClanURI("clan://~/Downloads")
assert uri.get_internal() == "~/Downloads"
uri = ClanURI("clan:///home/user/Downloads")
assert uri.get_internal() == "/home/user/Downloads"
uri = ClanURI("clan://file:///home/user/Downloads")
assert uri.get_internal() == "/home/user/Downloads"
def test_local_uri() -> None:
# Create a ClanURI object from a local URI
uri = ClanURI("clan://file:///home/user/Downloads")

View File

@@ -1,6 +1,7 @@
import json
from typing import TYPE_CHECKING
import pytest
from cli import Cli
from fixtures_flakes import FlakeForTest
from pytest import CaptureFixture
@@ -46,3 +47,23 @@ def test_flakes_list(
cli.run(["flakes", "add", str(test_flake.path)])
cli.run(cmd)
assert str(test_flake.path) in capsys.readouterr().out
@pytest.mark.impure
def test_flakes_inspect(
test_flake_with_core: FlakeForTest, capsys: pytest.CaptureFixture
) -> None:
cli = Cli()
cli.run(
[
"--flake",
str(test_flake_with_core.path),
"flakes",
"inspect",
"--machine",
"vm1",
]
)
out = capsys.readouterr() # empty the buffer
assert "Icon" in out.out

View File

@@ -3,26 +3,6 @@ import deal
from clan_cli import nix
@deal.cases(nix.nix_command)
def test_nix_command(case: deal.TestCase) -> None:
case()
@deal.cases(nix.nix_build)
def test_nix_build(case: deal.TestCase) -> None:
case()
@deal.cases(nix.nix_config)
def test_nix_config(case: deal.TestCase) -> None:
case()
@deal.cases(nix.nix_eval)
def test_nix_eval(case: deal.TestCase) -> None:
case()
@deal.cases(nix.nix_shell)
def test_nix_shell(case: deal.TestCase) -> None:
case()