aboutsummaryrefslogtreecommitdiff
path: root/tools/cru-py/cru/service
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2024-11-11 01:12:29 +0800
committerYuqian Yang <crupest@crupest.life>2025-01-08 22:37:23 +0800
commit43892b892cfdc4e15f7ab191c42ccb32279fd7f6 (patch)
tree9161420d397b95d24a0ac90629e0eab27f1b337f /tools/cru-py/cru/service
parentc3308421b665e5d8dcb70b78acf137541a026555 (diff)
downloadcrupest-43892b892cfdc4e15f7ab191c42ccb32279fd7f6.tar.gz
crupest-43892b892cfdc4e15f7ab191c42ccb32279fd7f6.tar.bz2
crupest-43892b892cfdc4e15f7ab191c42ccb32279fd7f6.zip
HALF WORK: 2024.1.8
Diffstat (limited to 'tools/cru-py/cru/service')
-rw-r--r--tools/cru-py/cru/service/__main__.py54
-rw-r--r--tools/cru-py/cru/service/_base.py50
-rw-r--r--tools/cru-py/cru/service/_config.py2
-rw-r--r--tools/cru-py/cru/service/_data.py2
-rw-r--r--tools/cru-py/cru/service/_template.py9
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.")