diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 2d2afce8c..25429a974 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -125,7 +125,6 @@ nav: - reference/cli/facts.md - reference/cli/flakes.md - reference/cli/flash.md - - reference/cli/history.md - reference/cli/machines.md - reference/cli/select.md - reference/cli/secrets.md diff --git a/pkgs/clan-cli/clan_cli/__init__.py b/pkgs/clan-cli/clan_cli/__init__.py index 98e85191a..cedf7e430 100644 --- a/pkgs/clan-cli/clan_cli/__init__.py +++ b/pkgs/clan-cli/clan_cli/__init__.py @@ -16,7 +16,6 @@ __all__ = ["admin", "directory", "disk", "iwd", "mdns_discovery", "modules", "up from . import ( backups, clan, - history, secrets, select, state, @@ -372,12 +371,6 @@ For more detailed information, visit: {help_hyperlink("deploy", "https://docs.cl ) vms.register_parser(parser_vms) - parser_history = subparsers.add_parser( - "history", - description="manage history", - ) - history.register_parser(parser_history) - parser_select = subparsers.add_parser( "select", aliases=["se"], diff --git a/pkgs/clan-cli/clan_cli/history/__init__.py b/pkgs/clan-cli/clan_cli/history/__init__.py deleted file mode 100644 index bb9cefe0b..000000000 --- a/pkgs/clan-cli/clan_cli/history/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# !/usr/bin/env python3 -import argparse - -from .add import register_add_parser -from .list import register_list_parser - - -# takes a (sub)parser and configures it -def register_parser(parser: argparse.ArgumentParser) -> None: - subparser = parser.add_subparsers( - title="command", - description="the command to run", - help="the command to run", - required=True, - ) - add_parser = subparser.add_parser("add", help="Add a clan flake") - register_add_parser(add_parser) - list_parser = subparser.add_parser("list", help="List recently used flakes") - register_list_parser(list_parser) diff --git a/pkgs/clan-cli/clan_cli/history/list.py b/pkgs/clan-cli/clan_cli/history/list.py deleted file mode 100644 index 778a6c311..000000000 --- a/pkgs/clan-cli/clan_cli/history/list.py +++ /dev/null @@ -1,26 +0,0 @@ -# !/usr/bin/env python3 -import argparse -from datetime import datetime - -from .add import HistoryEntry, list_history - - -def list_history_command(args: argparse.Namespace) -> None: - res: dict[str, list[HistoryEntry]] = {} - for history_entry in list_history(): - url = str(history_entry.flake.flake_url) - if res.get(url) is None: - res[url] = [] - res[url].append(history_entry) - - for flake_url, entries in res.items(): - print(flake_url) - for entry in entries: - d = datetime.fromisoformat(entry.last_used) - last_used = d.strftime("%d/%m/%Y %H:%M:%S") - print(f" {entry.flake.flake_attr} ({last_used})") - - -# takes a (sub)parser and configures it -def register_list_parser(parser: argparse.ArgumentParser) -> None: - parser.set_defaults(func=list_history_command) diff --git a/pkgs/clan-cli/clan_cli/tests/test_history_cli.py b/pkgs/clan-cli/clan_cli/tests/test_history_cli.py deleted file mode 100644 index 2377fd70d..000000000 --- a/pkgs/clan-cli/clan_cli/tests/test_history_cli.py +++ /dev/null @@ -1,47 +0,0 @@ -import json -from typing import TYPE_CHECKING - -import pytest -from clan_cli.dirs import user_history_file -from clan_cli.history.add import HistoryEntry -from clan_cli.tests.fixtures_flakes import FlakeForTest -from clan_cli.tests.helpers import cli -from clan_cli.tests.stdout import CaptureOutput - -if TYPE_CHECKING: - pass - - -@pytest.mark.impure -def test_history_add( - test_flake_with_core: FlakeForTest, -) -> None: - cmd = [ - "history", - "add", - f"clan://{test_flake_with_core.path}#vm1", - ] - cli.run(cmd) - - history_file = user_history_file() - assert history_file.exists() - history = [ - HistoryEntry.from_json(entry) for entry in json.loads(history_file.read_text()) - ] - assert str(history[0].flake.flake_url) == str(test_flake_with_core.path) - - -@pytest.mark.impure -def test_history_list( - capture_output: CaptureOutput, - test_flake_with_core: FlakeForTest, -) -> None: - with capture_output as output: - cli.run(["history", "list"]) - assert str(test_flake_with_core.path) not in output.out - - cli.run(["history", "add", f"clan://{test_flake_with_core.path}#vm1"]) - - with capture_output as output: - cli.run(["history", "list"]) - assert str(test_flake_with_core.path) in output.out diff --git a/pkgs/clan-vm-manager/clan_vm_manager/components/vmobj.py b/pkgs/clan-vm-manager/clan_vm_manager/components/vmobj.py index f83945ea7..741d0fcb3 100644 --- a/pkgs/clan-vm-manager/clan_vm_manager/components/vmobj.py +++ b/pkgs/clan-vm-manager/clan_vm_manager/components/vmobj.py @@ -15,12 +15,12 @@ import gi from clan_cli import vms from clan_cli.clan_uri import ClanURI from clan_cli.dirs import vm_state_dir -from clan_cli.history.add import HistoryEntry from clan_cli.machines.machines import Machine from clan_cli.vms.inspect import inspect_vm from clan_cli.vms.qemu import QMPWrapper from clan_vm_manager.components.executor import MPProcess, spawn +from clan_vm_manager.history import HistoryEntry from clan_vm_manager.singletons.toast import ( InfoToast, SuccessToast, diff --git a/pkgs/clan-cli/clan_cli/history/add.py b/pkgs/clan-vm-manager/clan_vm_manager/history.py similarity index 74% rename from pkgs/clan-cli/clan_cli/history/add.py rename to pkgs/clan-vm-manager/clan_vm_manager/history.py index 38aa743a8..566cd2a44 100644 --- a/pkgs/clan-cli/clan_cli/history/add.py +++ b/pkgs/clan-vm-manager/clan_vm_manager/history.py @@ -1,4 +1,3 @@ -# !/usr/bin/env python3 import argparse import dataclasses import datetime @@ -113,12 +112,46 @@ def add_history_command(args: argparse.Namespace) -> None: add_history(args.uri) -# takes a (sub)parser and configures it -def register_add_parser(parser: argparse.ArgumentParser) -> None: - parser.add_argument( +def list_history_command(args: argparse.Namespace) -> None: + res: dict[str, list[HistoryEntry]] = {} + for history_entry in list_history(): + url = str(history_entry.flake.flake_url) + if res.get(url) is None: + res[url] = [] + res[url].append(history_entry) + + for flake_url, entries in res.items(): + print(flake_url) + for entry in entries: + d = datetime.datetime.fromisoformat(entry.last_used) + last_used = d.strftime("%d/%m/%Y %H:%M:%S") + print(f" {entry.flake.flake_attr} ({last_used})") + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + prog="clan history", + description="Manage clan history", + ) + subparser = parser.add_subparsers( + title="command", + description="the command to run", + help="the command to run", + required=True, + ) + add_parser = subparser.add_parser("add", help="Add a clan flake") + add_parser.add_argument( "uri", type=ClanURI.from_str, help="Path to the flake", default="." ) - parser.add_argument( + add_parser.add_argument( "--all", help="Add all machines", default=False, action="store_true" ) - parser.set_defaults(func=add_history_command) + add_parser.set_defaults(func=add_history_command) + list_parser = subparser.add_parser("list", help="List recently used flakes") + list_parser.set_defaults(func=list_history_command) + return parser.parse_args() + + +def main() -> None: + args = parse_args() + args.func(args) diff --git a/pkgs/clan-vm-manager/clan_vm_manager/singletons/use_join.py b/pkgs/clan-vm-manager/clan_vm_manager/singletons/use_join.py index 1d720f978..d8fc062da 100644 --- a/pkgs/clan-vm-manager/clan_vm_manager/singletons/use_join.py +++ b/pkgs/clan-vm-manager/clan_vm_manager/singletons/use_join.py @@ -5,10 +5,10 @@ from typing import Any, ClassVar, cast import gi from clan_cli.clan_uri import ClanURI -from clan_cli.history.add import HistoryEntry, add_history from clan_cli.machines.machines import Machine from clan_vm_manager.components.gkvstore import GKVStore +from clan_vm_manager.history import HistoryEntry, add_history from clan_vm_manager.singletons.use_vms import ClanStore gi.require_version("Gtk", "4.0") diff --git a/pkgs/clan-vm-manager/clan_vm_manager/singletons/use_vms.py b/pkgs/clan-vm-manager/clan_vm_manager/singletons/use_vms.py index 83418c084..5725ffc30 100644 --- a/pkgs/clan-vm-manager/clan_vm_manager/singletons/use_vms.py +++ b/pkgs/clan-vm-manager/clan_vm_manager/singletons/use_vms.py @@ -6,12 +6,12 @@ from typing import Any, ClassVar import gi from clan_cli.clan_uri import ClanURI from clan_cli.flake import Flake -from clan_cli.history.add import HistoryEntry from clan_cli.machines.machines import Machine from clan_vm_manager import assets from clan_vm_manager.components.gkvstore import GKVStore from clan_vm_manager.components.vmobj import VMObject +from clan_vm_manager.history import HistoryEntry from clan_vm_manager.singletons.use_views import ViewStack from clan_vm_manager.views.logs import Logs diff --git a/pkgs/clan-vm-manager/clan_vm_manager/windows/main_window.py b/pkgs/clan-vm-manager/clan_vm_manager/windows/main_window.py index 8d875cb74..f7fd2948e 100644 --- a/pkgs/clan-vm-manager/clan_vm_manager/windows/main_window.py +++ b/pkgs/clan-vm-manager/clan_vm_manager/windows/main_window.py @@ -2,9 +2,9 @@ import logging import threading import gi -from clan_cli.history.list import list_history from clan_vm_manager.components.interfaces import ClanConfig +from clan_vm_manager.history import list_history from clan_vm_manager.singletons.toast import ToastOverlay from clan_vm_manager.singletons.use_views import ViewStack from clan_vm_manager.singletons.use_vms import ClanStore diff --git a/pkgs/clan-vm-manager/pyproject.toml b/pkgs/clan-vm-manager/pyproject.toml index 0762eb1a3..3196965c7 100644 --- a/pkgs/clan-vm-manager/pyproject.toml +++ b/pkgs/clan-vm-manager/pyproject.toml @@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta" name = "clan-vm-manager" description = "clan vm manager" dynamic = ["version"] -scripts = { clan-vm-manager = "clan_vm_manager:main" } +scripts = { clan-vm-manager = "clan_vm_manager:main", clan-vm-manager-history = "clan_vm_manager.history:main" } [project.urls] Homepage = "https://clan.lol/" diff --git a/pkgs/clan-vm-manager/tests/conftest.py b/pkgs/clan-vm-manager/tests/conftest.py index 1841dc81e..4db37f1ca 100644 --- a/pkgs/clan-vm-manager/tests/conftest.py +++ b/pkgs/clan-vm-manager/tests/conftest.py @@ -16,6 +16,7 @@ pytest_plugins = [ "root", "command", "wayland", + "stdout", ] diff --git a/pkgs/clan-vm-manager/tests/stdout.py b/pkgs/clan-vm-manager/tests/stdout.py new file mode 100644 index 000000000..8d460c9c0 --- /dev/null +++ b/pkgs/clan-vm-manager/tests/stdout.py @@ -0,0 +1,34 @@ +import types + +import pytest + + +class CaptureOutput: + def __init__(self, capsys: pytest.CaptureFixture) -> None: + self.capsys = capsys + self.capsys_disabled = capsys.disabled() + self.capsys_disabled.__enter__() + + def __enter__(self) -> "CaptureOutput": + self.capsys_disabled.__exit__(None, None, None) + self.capsys.readouterr() + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: types.TracebackType | None, + ) -> None: + res = self.capsys.readouterr() + self.out = res.out + self.err = res.err + + # Disable capsys again + self.capsys_disabled = self.capsys.disabled() + self.capsys_disabled.__enter__() + + +@pytest.fixture +def capture_output(capsys: pytest.CaptureFixture) -> CaptureOutput: + return CaptureOutput(capsys)