diff options
author | crupest <crupest@outlook.com> | 2024-11-11 01:12:29 +0800 |
---|---|---|
committer | Yuqian Yang <crupest@crupest.life> | 2025-01-08 22:37:23 +0800 |
commit | 43892b892cfdc4e15f7ab191c42ccb32279fd7f6 (patch) | |
tree | 9161420d397b95d24a0ac90629e0eab27f1b337f /tools | |
parent | c3308421b665e5d8dcb70b78acf137541a026555 (diff) | |
download | crupest-43892b892cfdc4e15f7ab191c42ccb32279fd7f6.tar.gz crupest-43892b892cfdc4e15f7ab191c42ccb32279fd7f6.tar.bz2 crupest-43892b892cfdc4e15f7ab191c42ccb32279fd7f6.zip |
HALF WORK: 2024.1.8
Diffstat (limited to 'tools')
-rw-r--r-- | tools/cru-py/cru/service/__main__.py | 54 | ||||
-rw-r--r-- | tools/cru-py/cru/service/_base.py | 50 | ||||
-rw-r--r-- | tools/cru-py/cru/service/_config.py | 2 | ||||
-rw-r--r-- | tools/cru-py/cru/service/_data.py | 2 | ||||
-rw-r--r-- | tools/cru-py/cru/service/_template.py | 9 |
5 files changed, 105 insertions, 12 deletions
diff --git a/tools/cru-py/cru/service/__main__.py b/tools/cru-py/cru/service/__main__.py index a7add4d..923c25b 100644 --- a/tools/cru-py/cru/service/__main__.py +++ b/tools/cru-py/cru/service/__main__.py @@ -1,11 +1,51 @@ -import argparse +from pathlib import Path +from cru import CruException -arg_parser = argparse.ArgumentParser(description="Service management") -command_subparser = arg_parser.add_subparsers(dest="command") +from ._base import AppBase, DATA_DIR_NAME, CommandDispatcher +from ._config import ConfigManager +from ._data import DataManager +from ._template import TemplateManager -template_parser = command_subparser.add_parser("template", help="Template management") -template_subparser = template_parser.add_subparsers(dest="template_command") -template_subparser.add_parser('list', description="List templates") -template_subparser.add_parser('generate') +class App(AppBase): + def __init__(self, root: str): + super().__init__("crupest-service", root) + self.add_feature(DataManager()) + self.add_feature(ConfigManager()) + self.add_feature(TemplateManager()) + self.add_feature(CommandDispatcher()) + + def setup(self): + for feature in self.features: + feature.setup() + + def run_command(self): + command_dispatcher = self.get_feature(CommandDispatcher) + command_dispatcher.run_command() + + +def _find_root() -> Path: + cwd = Path.cwd() + data_dir = cwd / DATA_DIR_NAME + if data_dir.is_dir(): + return data_dir + raise CruException( + "No valid data directory found. Please run 'init' to create one." + ) + + +def create_app() -> App: + root = _find_root() + app = App(str(root)) + app.setup() + return app + + +def main(): + app = create_app() + app.run_command() + + +if __name__ == "__main__": + main() diff --git a/tools/cru-py/cru/service/_base.py b/tools/cru-py/cru/service/_base.py index 98eed89..3b511a1 100644 --- a/tools/cru-py/cru/service/_base.py +++ b/tools/cru-py/cru/service/_base.py @@ -2,6 +2,8 @@ from __future__ import annotations from argparse import ArgumentParser, Namespace from abc import ABC, abstractmethod +import argparse +from collections.abc import Sequence import os from pathlib import Path from typing import TypeVar, overload @@ -12,6 +14,7 @@ _F = TypeVar("_F") OWNER_NAME = "crupest" + class InternalAppException(CruInternalError): pass @@ -153,7 +156,7 @@ class AppRootPath(AppPath): return self._app -class AppFeatureProvider: +class AppFeatureProvider(ABC): def __init__(self, name: str, /, app: AppBase | None = None): super().__init__() self._name = name @@ -168,15 +171,56 @@ class AppFeatureProvider: def name(self) -> str: return self._name + @abstractmethod + def setup(self) -> None: ... + + +class AppCommandFeatureProvider(AppFeatureProvider): + @abstractmethod + def get_command_info(self) -> tuple[str, str]: ... -class AppCommandFeatureProvider(AppFeatureProvider, ABC): @abstractmethod - def add_arg_parser(self, arg_parser: ArgumentParser) -> None: ... + def setup_arg_parser(self, arg_parser: ArgumentParser): ... @abstractmethod def run_command(self, args: Namespace) -> None: ... +DATA_DIR_NAME = "data" + + +class CommandDispatcher(AppFeatureProvider): + def __init__(self) -> None: + super().__init__("command-dispatcher") + + def _setup_arg_parser(self) -> None: + self._map: dict[str, AppCommandFeatureProvider] = {} + arg_parser = argparse.ArgumentParser(description="Service management") + subparsers = arg_parser.add_subparsers(dest="command") + for feature in self.app.features: + if isinstance(feature, AppCommandFeatureProvider): + info = feature.get_command_info() + command_subparser = subparsers.add_parser(info[0], help=info[1]) + feature.setup_arg_parser(command_subparser) + self._map[info[0]] = feature + self._arg_parser = arg_parser + + def setup(self): + self._setup_arg_parser() + + @property + def arg_parser(self) -> argparse.ArgumentParser: + return self._arg_parser + + @property + def map(self) -> dict[str, AppCommandFeatureProvider]: + return self._map + + def run_command(self, _args: Sequence[str] | None = None) -> None: + args = self.arg_parser.parse_args(_args) + self.map[args.command].run_command(args) + + class AppBase: _instance: AppBase | None = None diff --git a/tools/cru-py/cru/service/_config.py b/tools/cru-py/cru/service/_config.py index 63b73b3..1c3a571 100644 --- a/tools/cru-py/cru/service/_config.py +++ b/tools/cru-py/cru/service/_config.py @@ -5,6 +5,8 @@ from ._data import DataManager class ConfigManager(AppFeatureProvider): def __init__(self) -> None: super().__init__("config-manager") + + def setup(self) -> None: self._config_path = self.app.get_feature(DataManager).data_dir.add_subpath( "config", False, description="Configuration file path." ) diff --git a/tools/cru-py/cru/service/_data.py b/tools/cru-py/cru/service/_data.py index 3cddfc8..79a1f64 100644 --- a/tools/cru-py/cru/service/_data.py +++ b/tools/cru-py/cru/service/_data.py @@ -4,6 +4,8 @@ from ._base import AppFeaturePath, AppFeatureProvider class DataManager(AppFeatureProvider): def __init__(self) -> None: super().__init__("data-manager") + + def setup(self) -> None: self._dir = self.app.add_path("data", True) @property diff --git a/tools/cru-py/cru/service/_template.py b/tools/cru-py/cru/service/_template.py index 5f0252a..23bff4d 100644 --- a/tools/cru-py/cru/service/_template.py +++ b/tools/cru-py/cru/service/_template.py @@ -1,4 +1,4 @@ -from argparse import ArgumentParser, Namespace +from argparse import Namespace from cru import CruIterator from cru.template import TemplateTree @@ -11,6 +11,8 @@ class TemplateManager(AppCommandFeatureProvider): def __init__(self, prefix: str = OWNER_NAME.upper()): super().__init__("template-manager") self._prefix = prefix + + def setup(self) -> None: self._templates_dir = self.app.add_path("templates", True) self._generated_dir = self.app.add_path("generated", True) self._template_tree: TemplateTree | None = None @@ -56,7 +58,10 @@ class TemplateManager(AppCommandFeatureProvider): self.generated_dir.full_path_str, config_manager.config_map ) - def add_arg_parser(self, arg_parser: ArgumentParser) -> None: + def get_command_info(self): + return ("template", "Template Management") + + def setup_arg_parser(self, arg_parser): subparsers = arg_parser.add_subparsers(dest="template_command") _list_parser = subparsers.add_parser("list", help="List templates.") _generate_parser = subparsers.add_parser("generate", help="Generate template.") |