From adec0f35eea3b9d955e5631d5b8e54092022116d Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 11 Nov 2024 01:12:29 +0800 Subject: HALF WORK: 2024.1.3 --- tools/cru-py/cru/service/_base.py | 33 ++++++++++++++++++++++++++++++++- tools/cru-py/cru/service/_config.py | 15 +++++++++++++++ tools/cru-py/cru/service/_data.py | 12 ++++++++++++ tools/cru-py/cru/service/_docker.py | 19 +++++++------------ tools/cru-py/cru/service/_template.py | 4 ++-- 5 files changed, 68 insertions(+), 15 deletions(-) create mode 100644 tools/cru-py/cru/service/_config.py create mode 100644 tools/cru-py/cru/service/_data.py (limited to 'tools/cru-py/cru/service') diff --git a/tools/cru-py/cru/service/_base.py b/tools/cru-py/cru/service/_base.py index 7bb09ad..c84ab05 100644 --- a/tools/cru-py/cru/service/_base.py +++ b/tools/cru-py/cru/service/_base.py @@ -3,12 +3,19 @@ from __future__ import annotations from argparse import ArgumentParser, Namespace from abc import ABC, abstractmethod from collections.abc import Iterable +from typing import TypeVar, overload from cru import CruIterator, CruInternalError from cru.app import ApplicationPath, CruApplication +_F = TypeVar("_F") -class AppFeatureProvider(ABC): + +class InternalAppException(CruInternalError): + pass + + +class AppFeatureProvider: def __init__(self, name: str, /, app: AppBase | None = None): super().__init__() self._name = name @@ -33,6 +40,8 @@ class AppFeatureProvider(ABC): self._app_paths.append(p) return p + +class AppCommandFeatureProvider(AppFeatureProvider, ABC): @abstractmethod def add_arg_parser(self, arg_parser: ArgumentParser) -> None: ... @@ -71,3 +80,25 @@ class AppBase(CruApplication): def add_app_feature(self, feature: AppFeatureProvider) -> None: self._app_features.append(feature) + + @overload + def get_feature(self, feature: str) -> AppFeatureProvider: ... + + @overload + def get_feature(self, feature: type[_F]) -> _F: ... + + def get_feature(self, feature: str | type[_F]) -> AppFeatureProvider | _F: + if isinstance(feature, str): + for f in self._app_features: + if f.name == feature: + return f + elif isinstance(feature, type): + for f in self._app_features: + if isinstance(f, feature): + return f + else: + raise InternalAppException( + "Argument must be the name of feature or its class." + ) + + raise InternalAppException(f"Feature {feature} not found.") diff --git a/tools/cru-py/cru/service/_config.py b/tools/cru-py/cru/service/_config.py new file mode 100644 index 0000000..1838015 --- /dev/null +++ b/tools/cru-py/cru/service/_config.py @@ -0,0 +1,15 @@ +import os.path +from ._base import AppFeatureProvider +from ._data import DataManager + + +class ConfigManager(AppFeatureProvider): + def __init__(self, config_file_name="config") -> None: + super().__init__("config-manager") + self._file_name = config_file_name + + @property + def config_file_path(self) -> str: + return os.path.join( + self.app.get_feature(DataManager).data_dir.full_path, self._file_name + ) diff --git a/tools/cru-py/cru/service/_data.py b/tools/cru-py/cru/service/_data.py new file mode 100644 index 0000000..f38dc23 --- /dev/null +++ b/tools/cru-py/cru/service/_data.py @@ -0,0 +1,12 @@ +from cru.app import ApplicationPath +from ._base import AppFeatureProvider + + +class DataManager(AppFeatureProvider): + def __init__(self) -> None: + super().__init__("data-manager") + self._dir = self.add_app_path("data", True) + + @property + def data_dir(self) -> ApplicationPath: + return self._dir diff --git a/tools/cru-py/cru/service/_docker.py b/tools/cru-py/cru/service/_docker.py index 5958f4f..9b801c4 100644 --- a/tools/cru-py/cru/service/_docker.py +++ b/tools/cru-py/cru/service/_docker.py @@ -1,24 +1,19 @@ -import shutil import subprocess -from .._util import L +from cru.tool import ExternalTool -class DockerController: +class DockerController(ExternalTool): DOCKER_BIN_NAME = "docker" def __init__(self, docker_bin: None | str = None) -> None: - self._docker_bin = docker_bin - - @property - def docker_bin(self) -> str: - if self._docker_bin is None: - self._docker_bin = shutil.which(self.DOCKER_BIN_NAME) - return self._docker_bin + super().__init__(docker_bin or self.DOCKER_BIN_NAME) def list_containers(self) -> L[str]: - p = subprocess.run([self.docker_bin, "container", "ls", ""], capture_output=True) + p = subprocess.run( + [self.docker_bin, "container", "ls", ""], capture_output=True + ) return p.stdout.decode("utf-8").splitlines() def restart_container(self, container_name: str) -> None: - subprocess.run([self.docker_bin, "restart", container_name]) \ No newline at end of file + subprocess.run([self.docker_bin, "restart", container_name]) diff --git a/tools/cru-py/cru/service/_template.py b/tools/cru-py/cru/service/_template.py index 5da00ba..bf13212 100644 --- a/tools/cru-py/cru/service/_template.py +++ b/tools/cru-py/cru/service/_template.py @@ -1,12 +1,12 @@ from argparse import ArgumentParser, Namespace -from ._base import AppFeatureProvider +from ._base import AppCommandFeatureProvider from cru.app import ApplicationPath from cru.template import TemplateTree -class TemplateManager(AppFeatureProvider): +class TemplateManager(AppCommandFeatureProvider): def __init__(self, prefix: str = "CRUPEST"): super().__init__("template-manager") self._templates_dir = self.add_app_path("templates", True) -- cgit v1.2.3