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:
@@ -88,7 +88,13 @@ class ClanURI:
|
|||||||
raise ClanError(f"Unsupported uri components: {comb}")
|
raise ClanError(f"Unsupported uri components: {comb}")
|
||||||
|
|
||||||
def get_internal(self) -> str:
|
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
|
@classmethod
|
||||||
def from_path(cls, path: Path, params: ClanParameters) -> Self: # noqa
|
def from_path(cls, path: Path, params: ClanParameters) -> Self: # noqa
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import argparse
|
|||||||
|
|
||||||
from clan_cli.flakes.add import register_add_parser
|
from clan_cli.flakes.add import register_add_parser
|
||||||
from clan_cli.flakes.history import register_list_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
|
from .create import register_create_parser
|
||||||
|
|
||||||
@@ -21,3 +22,5 @@ def register_parser(parser: argparse.ArgumentParser) -> None:
|
|||||||
register_add_parser(add_parser)
|
register_add_parser(add_parser)
|
||||||
list_parser = subparser.add_parser("list", help="List recently used flakes")
|
list_parser = subparser.add_parser("list", help="List recently used flakes")
|
||||||
register_list_parser(list_parser)
|
register_list_parser(list_parser)
|
||||||
|
inspect_parser = subparser.add_parser("inspect", help="Inspect a clan flake")
|
||||||
|
register_inspect_parser(inspect_parser)
|
||||||
|
|||||||
83
pkgs/clan-cli/clan_cli/flakes/inspect.py
Normal file
83
pkgs/clan-cli/clan_cli/flakes/inspect.py
Normal 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)
|
||||||
@@ -10,7 +10,6 @@ from .dirs import nixpkgs_flake, nixpkgs_source
|
|||||||
from .errors import ClanError
|
from .errors import ClanError
|
||||||
|
|
||||||
|
|
||||||
@deal.raises(ClanError)
|
|
||||||
def nix_command(flags: list[str]) -> list[str]:
|
def nix_command(flags: list[str]) -> list[str]:
|
||||||
return ["nix", "--extra-experimental-features", "nix-command flakes", *flags]
|
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(
|
def nix_build(
|
||||||
flags: list[str],
|
flags: list[str],
|
||||||
) -> list[str]:
|
) -> list[str]:
|
||||||
@@ -45,7 +43,6 @@ def nix_build(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@deal.raises(ClanError)
|
|
||||||
def nix_config() -> dict[str, Any]:
|
def nix_config() -> dict[str, Any]:
|
||||||
cmd = nix_command(["show-config", "--json"])
|
cmd = nix_command(["show-config", "--json"])
|
||||||
proc = subprocess.run(cmd, check=True, text=True, stdout=subprocess.PIPE)
|
proc = subprocess.run(cmd, check=True, text=True, stdout=subprocess.PIPE)
|
||||||
@@ -56,7 +53,6 @@ def nix_config() -> dict[str, Any]:
|
|||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
@deal.raises(ClanError)
|
|
||||||
def nix_eval(flags: list[str]) -> list[str]:
|
def nix_eval(flags: list[str]) -> list[str]:
|
||||||
default_flags = nix_command(
|
default_flags = nix_command(
|
||||||
[
|
[
|
||||||
@@ -82,9 +78,8 @@ def nix_eval(flags: list[str]) -> list[str]:
|
|||||||
return default_flags + flags
|
return default_flags + flags
|
||||||
|
|
||||||
|
|
||||||
@deal.raises(ClanError)
|
def nix_metadata(flake_url: str | Path) -> dict[str, Any]:
|
||||||
def nix_metadata(flake: str) -> dict[str, Any]:
|
cmd = nix_command(["flake", "metadata", "--json", f"{flake_url}"])
|
||||||
cmd = nix_command(["flake", "metadata", "--json", flake])
|
|
||||||
proc = subprocess.run(cmd, check=True, text=True, stdout=subprocess.PIPE)
|
proc = subprocess.run(cmd, check=True, text=True, stdout=subprocess.PIPE)
|
||||||
data = json.loads(proc.stdout)
|
data = json.loads(proc.stdout)
|
||||||
return data
|
return data
|
||||||
|
|||||||
@@ -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'
|
f'{flake_url}#clanInternals.machines."{system}"."{flake_attr}".config.system.clan.vm.config'
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
proc = subprocess.run(cmd, check=True, text=True, stdout=subprocess.PIPE)
|
proc = subprocess.run(cmd, check=True, text=True, stdout=subprocess.PIPE)
|
||||||
assert proc.stdout is not None
|
assert proc.stdout is not None
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
@@ -65,5 +66,5 @@ def inspect_command(args: argparse.Namespace) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def register_inspect_parser(parser: argparse.ArgumentParser) -> 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)
|
parser.set_defaults(func=inspect_command)
|
||||||
|
|||||||
@@ -37,7 +37,6 @@
|
|||||||
, clan-core-path
|
, clan-core-path
|
||||||
, writeShellScriptBin
|
, writeShellScriptBin
|
||||||
, nodePackages
|
, nodePackages
|
||||||
, schemathesis ? null
|
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
|
|
||||||
@@ -155,6 +154,7 @@ python3.pkgs.buildPythonApplication {
|
|||||||
${checkPython}/bin/python -m pytest -m "not impure and with_core" -s ./tests
|
${checkPython}/bin/python -m pytest -m "not impure and with_core" -s ./tests
|
||||||
touch $out
|
touch $out
|
||||||
'';
|
'';
|
||||||
|
|
||||||
clan-pytest = runCommand "clan-pytest" { } ''
|
clan-pytest = runCommand "clan-pytest" { } ''
|
||||||
echo ${clan-pytest-without-core}
|
echo ${clan-pytest-without-core}
|
||||||
echo ${clan-pytest-with-core}
|
echo ${clan-pytest-with-core}
|
||||||
|
|||||||
@@ -31,14 +31,15 @@
|
|||||||
{
|
{
|
||||||
devShells.clan-cli = pkgs.callPackage ./shell.nix {
|
devShells.clan-cli = pkgs.callPackage ./shell.nix {
|
||||||
inherit (self'.packages) clan-cli ui-assets nix-unit;
|
inherit (self'.packages) clan-cli ui-assets nix-unit;
|
||||||
|
# inherit (inputs) democlan;
|
||||||
};
|
};
|
||||||
packages = {
|
packages = {
|
||||||
clan-cli = pkgs.python3.pkgs.callPackage ./default.nix {
|
clan-cli = pkgs.python3.pkgs.callPackage ./default.nix {
|
||||||
inherit (self'.packages) ui-assets;
|
inherit (self'.packages) ui-assets;
|
||||||
inherit (inputs) nixpkgs;
|
inherit (inputs) nixpkgs;
|
||||||
|
# inherit (inputs) democlan;
|
||||||
inherit (inputs.nixpkgs-for-deal.legacyPackages.${system}.python3Packages) deal;
|
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;
|
clan-core-path = clanCoreWithVendoredDeps;
|
||||||
};
|
};
|
||||||
default = self'.packages.clan-cli;
|
default = self'.packages.clan-cli;
|
||||||
|
|||||||
@@ -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
|
@pytest.fixture
|
||||||
def test_democlan_url(
|
def test_democlan_url(
|
||||||
monkeypatch: pytest.MonkeyPatch, temporary_home: Path
|
monkeypatch: pytest.MonkeyPatch, temporary_home: Path
|
||||||
|
|||||||
@@ -6,6 +6,21 @@ from clan_cli.clan_uri import ClanParameters, ClanScheme, ClanURI
|
|||||||
from clan_cli.errors import ClanError
|
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:
|
def test_local_uri() -> None:
|
||||||
# Create a ClanURI object from a local URI
|
# Create a ClanURI object from a local URI
|
||||||
uri = ClanURI("clan://file:///home/user/Downloads")
|
uri = ClanURI("clan://file:///home/user/Downloads")
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import json
|
import json
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import pytest
|
||||||
from cli import Cli
|
from cli import Cli
|
||||||
from fixtures_flakes import FlakeForTest
|
from fixtures_flakes import FlakeForTest
|
||||||
from pytest import CaptureFixture
|
from pytest import CaptureFixture
|
||||||
@@ -46,3 +47,23 @@ def test_flakes_list(
|
|||||||
cli.run(["flakes", "add", str(test_flake.path)])
|
cli.run(["flakes", "add", str(test_flake.path)])
|
||||||
cli.run(cmd)
|
cli.run(cmd)
|
||||||
assert str(test_flake.path) in capsys.readouterr().out
|
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
|
||||||
|
|||||||
@@ -3,26 +3,6 @@ import deal
|
|||||||
from clan_cli import nix
|
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)
|
@deal.cases(nix.nix_shell)
|
||||||
def test_nix_shell(case: deal.TestCase) -> None:
|
def test_nix_shell(case: deal.TestCase) -> None:
|
||||||
case()
|
case()
|
||||||
|
|||||||
Reference in New Issue
Block a user