From 11fb73432ba575a3a476397352e14b567bd1250c Mon Sep 17 00:00:00 2001 From: DavHau Date: Fri, 17 Nov 2023 17:05:15 +0700 Subject: [PATCH] api/flake/add: init Adds an endpoint to memoize clans. clan flakes can be added to the history either via the endpoint or by executing `clan flakes add` --- pkgs/clan-cli/clan_cli/dirs.py | 4 +++ pkgs/clan-cli/clan_cli/flakes/__init__.py | 4 +++ pkgs/clan-cli/clan_cli/flakes/add.py | 35 +++++++++++++++++++ pkgs/clan-cli/clan_cli/webui/routers/flake.py | 7 +++- pkgs/clan-cli/tests/test_flake_api.py | 15 ++++++++ pkgs/clan-cli/tests/test_flakes_cli.py | 26 ++++++++++++++ 6 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 pkgs/clan-cli/clan_cli/flakes/add.py create mode 100644 pkgs/clan-cli/tests/test_flakes_cli.py diff --git a/pkgs/clan-cli/clan_cli/dirs.py b/pkgs/clan-cli/clan_cli/dirs.py index e5701b3e1..9160b3342 100644 --- a/pkgs/clan-cli/clan_cli/dirs.py +++ b/pkgs/clan-cli/clan_cli/dirs.py @@ -36,6 +36,10 @@ def user_config_dir() -> Path: return Path(os.getenv("XDG_CONFIG_HOME", os.path.expanduser("~/.config"))) +def user_history_file() -> Path: + return user_config_dir() / "clan" / "history" + + def machines_dir(flake_dir: Path) -> Path: return flake_dir / "machines" diff --git a/pkgs/clan-cli/clan_cli/flakes/__init__.py b/pkgs/clan-cli/clan_cli/flakes/__init__.py index a24e84d11..2c9c82c08 100644 --- a/pkgs/clan-cli/clan_cli/flakes/__init__.py +++ b/pkgs/clan-cli/clan_cli/flakes/__init__.py @@ -1,6 +1,8 @@ # !/usr/bin/env python3 import argparse +from clan_cli.flakes.add import register_add_parser + from .create import register_create_parser @@ -14,3 +16,5 @@ def register_parser(parser: argparse.ArgumentParser) -> None: ) create_parser = subparser.add_parser("create", help="Create a clan flake") register_create_parser(create_parser) + add_parser = subparser.add_parser("add", help="Add a clan flake") + register_add_parser(add_parser) diff --git a/pkgs/clan-cli/clan_cli/flakes/add.py b/pkgs/clan-cli/clan_cli/flakes/add.py new file mode 100644 index 000000000..8b2327305 --- /dev/null +++ b/pkgs/clan-cli/clan_cli/flakes/add.py @@ -0,0 +1,35 @@ +# !/usr/bin/env python3 +import argparse +from pathlib import Path +from typing import Dict + +from pydantic import AnyUrl +from pydantic.tools import parse_obj_as + +from clan_cli.dirs import user_history_file + +from ..async_cmd import CmdOut, runforcli + +DEFAULT_URL: AnyUrl = parse_obj_as( + AnyUrl, + "git+https://git.clan.lol/clan/clan-core?new-clan", +) + + +async def add_flake(path: Path) -> Dict[str, CmdOut]: + user_history_file().parent.mkdir(parents=True, exist_ok=True) + # append line to history file + # TODO: Is this atomic? + with open(user_history_file(), "a+") as f: + f.write(f"{path}\n") + return {} + + +def add_flake_command(args: argparse.Namespace) -> None: + runforcli(add_flake, args.path) + + +# takes a (sub)parser and configures it +def register_add_parser(parser: argparse.ArgumentParser) -> None: + parser.add_argument("path", type=Path, help="Path to the flake", default=Path(".")) + parser.set_defaults(func=add_flake_command) diff --git a/pkgs/clan-cli/clan_cli/webui/routers/flake.py b/pkgs/clan-cli/clan_cli/webui/routers/flake.py index b8bbec767..babf1c5c2 100644 --- a/pkgs/clan-cli/clan_cli/webui/routers/flake.py +++ b/pkgs/clan-cli/clan_cli/webui/routers/flake.py @@ -17,7 +17,7 @@ from clan_cli.webui.api_outputs import ( ) from ...async_cmd import run -from ...flakes import create +from ...flakes import add, create from ...nix import nix_command, nix_flake_show from ..tags import Tags @@ -45,6 +45,11 @@ async def get_attrs(url: AnyUrl | Path) -> list[str]: return flake_attrs +@router.put("/api/flake/add", tags=[Tags.flake]) +async def add_flake(flake_dir: Path) -> None: + await add.add_flake(flake_dir) + + # TODO: Check for directory traversal @router.get("/api/flake/attrs", tags=[Tags.flake]) async def inspect_flake_attrs(url: AnyUrl | Path) -> FlakeAttrResponse: diff --git a/pkgs/clan-cli/tests/test_flake_api.py b/pkgs/clan-cli/tests/test_flake_api.py index 7bca5fbc1..0d598a19d 100644 --- a/pkgs/clan-cli/tests/test_flake_api.py +++ b/pkgs/clan-cli/tests/test_flake_api.py @@ -4,10 +4,25 @@ import logging import pytest from api import TestClient from fixtures_flakes import FlakeForTest +from path import Path + +from clan_cli.dirs import user_history_file log = logging.getLogger(__name__) +def test_flake_add( + api: TestClient, test_flake: FlakeForTest, temporary_home: Path +) -> None: + response = api.put( + f"/api/flake/add?flake_dir={str(test_flake.path)}", + json={}, + ) + assert response.status_code == 200, response.json() + assert user_history_file().exists() + assert open(user_history_file()).read().strip() == str(test_flake.path) + + @pytest.mark.impure def test_inspect_ok(api: TestClient, test_flake_with_core: FlakeForTest) -> None: params = {"url": str(test_flake_with_core.path)} diff --git a/pkgs/clan-cli/tests/test_flakes_cli.py b/pkgs/clan-cli/tests/test_flakes_cli.py new file mode 100644 index 000000000..8cb33dc63 --- /dev/null +++ b/pkgs/clan-cli/tests/test_flakes_cli.py @@ -0,0 +1,26 @@ +from typing import TYPE_CHECKING + +from cli import Cli +from fixtures_flakes import FlakeForTest + +from clan_cli.dirs import user_history_file + +if TYPE_CHECKING: + pass + + +def test_flakes_add( + test_flake: FlakeForTest, +) -> None: + cli = Cli() + cmd = [ + "flakes", + "add", + str(test_flake.path), + ] + + cli.run(cmd) + + history_file = user_history_file() + assert history_file.exists() + assert open(history_file).read().strip() == str(test_flake.path)