diff options
author | crupest <crupest@outlook.com> | 2024-11-11 01:12:29 +0800 |
---|---|---|
committer | Yuqian Yang <crupest@crupest.life> | 2025-01-04 17:14:00 +0800 |
commit | 0c7905bfc7bd19b70c7ec213dac041a07f53fdd5 (patch) | |
tree | 37957ec274d4a6b211aff395ff8be6a6b555d25c /tools/cru-py/cru | |
parent | adec0f35eea3b9d955e5631d5b8e54092022116d (diff) | |
download | crupest-0c7905bfc7bd19b70c7ec213dac041a07f53fdd5.tar.gz crupest-0c7905bfc7bd19b70c7ec213dac041a07f53fdd5.tar.bz2 crupest-0c7905bfc7bd19b70c7ec213dac041a07f53fdd5.zip |
HALF WORK: 2024.1.4
Diffstat (limited to 'tools/cru-py/cru')
-rw-r--r-- | tools/cru-py/cru/app.py | 81 | ||||
-rw-r--r-- | tools/cru-py/cru/service/_base.py | 214 | ||||
-rw-r--r-- | tools/cru-py/cru/service/_config.py | 15 | ||||
-rw-r--r-- | tools/cru-py/cru/service/_data.py | 7 | ||||
-rw-r--r-- | tools/cru-py/cru/service/_template.py | 13 |
5 files changed, 199 insertions, 131 deletions
diff --git a/tools/cru-py/cru/app.py b/tools/cru-py/cru/app.py deleted file mode 100644 index d45fd30..0000000 --- a/tools/cru-py/cru/app.py +++ /dev/null @@ -1,81 +0,0 @@ -import os -from pathlib import Path - -from ._error import CruException -from ._path import CruPath - - -class CruApplication: - def __init__(self, name: str) -> None: - self._name = name - - -class ApplicationPathError(CruException): - def __init__(self, message, _path: Path, *args, **kwargs): - super().__init__(message, *args, **kwargs) - self._path = _path - - @property - def path(self) -> Path: - return self._path - - -class ApplicationPath: - def __init__(self, app_dir: str, subpath: str, is_dir: bool) -> None: - self._app_dir = app_dir - self._subpath = subpath - self._full_path = CruPath(app_dir, subpath) - self._is_dir = is_dir - - @property - def app_dir(self) -> str: - return self._app_dir - - @property - def subpath(self) -> str: - return self._subpath - - @property - def full_path(self) -> CruPath: - return self._full_path - - @property - def full_path_str(self) -> str: - return str(self._full_path) - - @property - def is_dir(self) -> bool: - return self._is_dir - - def check_parents(self, must_exist: bool = False) -> bool: - return self.full_path.check_parents_dir(must_exist) - - def check_self(self, must_exist: bool = False) -> bool: - if not self.check_parents(must_exist): - return False - if not self.full_path.exists(): - if not must_exist: - return False - raise ApplicationPathError("Not exist.", self.full_path) - if self.is_dir: - if not self.full_path.is_dir(): - raise ApplicationPathError( - "Should be a directory, but not.", self.full_path - ) - else: - return False - else: - if not self.full_path.is_file(): - raise ApplicationPathError("Should be a file, but not.", self.full_path) - else: - return False - - def ensure(self, create_file: bool = False) -> None: - e = self.check_self(False) - if not e: - os.makedirs(self.full_path.parent, exist_ok=True) - if self.is_dir: - os.mkdir(self.full_path) - elif create_file: - with open(self.full_path, "w") as f: - f.write("") diff --git a/tools/cru-py/cru/service/_base.py b/tools/cru-py/cru/service/_base.py index c84ab05..f91eadd 100644 --- a/tools/cru-py/cru/service/_base.py +++ b/tools/cru-py/cru/service/_base.py @@ -2,11 +2,11 @@ from __future__ import annotations from argparse import ArgumentParser, Namespace from abc import ABC, abstractmethod -from collections.abc import Iterable +import os +from pathlib import Path from typing import TypeVar, overload -from cru import CruIterator, CruInternalError -from cru.app import ApplicationPath, CruApplication +from cru import CruException, CruInternalError, CruPath _F = TypeVar("_F") @@ -15,13 +15,149 @@ class InternalAppException(CruInternalError): pass +class AppPathError(CruException): + def __init__(self, message, _path: str | Path, *args, **kwargs): + super().__init__(message, *args, **kwargs) + self._path = str(_path) + + @property + def path(self) -> str: + return self._path + + +class AppPath(ABC): + def __init__( + self, + name: str, + is_dir: bool, + /, + id: str | None = None, + description: str = "", + ) -> None: + self._name = name + self._is_dir = is_dir + self._id = id or name + self._description = description + + @property + @abstractmethod + def parent(self) -> AppPath | None: ... + + @property + def name(self) -> str: + return self._name + + @property + @abstractmethod + def app(self) -> AppBase: ... + + @property + def id(self) -> str: + return self._id + + @property + def description(self) -> str: + return self._description + + @property + def is_dir(self) -> bool: + return self._is_dir + + @property + def full_path(self) -> CruPath: + if self.parent is None: + return CruPath(self.name) + else: + return CruPath(self.parent.full_path, self.name) + + @property + def full_path_str(self) -> str: + return str(self.full_path) + + def check_parents(self, must_exist: bool = False) -> bool: + return self.full_path.check_parents_dir(must_exist) + + def check_self(self, must_exist: bool = False) -> bool: + if not self.check_parents(must_exist): + return False + if not self.full_path.exists(): + if not must_exist: + return False + raise AppPathError("Not exist.", self.full_path) + if self.is_dir: + if not self.full_path.is_dir(): + raise AppPathError("Should be a directory, but not.", self.full_path) + else: + return False + else: + if not self.full_path.is_file(): + raise AppPathError("Should be a file, but not.", self.full_path) + else: + return False + + def ensure(self, create_file: bool = False) -> None: + e = self.check_self(False) + if not e: + os.makedirs(self.full_path.parent, exist_ok=True) + if self.is_dir: + os.mkdir(self.full_path) + elif create_file: + with open(self.full_path, "w") as f: + f.write("") + + def add_subpath( + self, + name: str, + is_dir: bool, + /, + id: str | None = None, + description: str = "", + ) -> AppFeaturePath: + return self.app.add_path(name, is_dir, self, id, description) + + +class AppFeaturePath(AppPath): + def __init__( + self, + parent: AppPath, + name: str, + is_dir: bool, + /, + id: str | None = None, + description: str = "", + ) -> None: + super().__init__(name, is_dir, id, description) + self._parent = parent + + @property + def parent(self) -> AppPath: + return self._parent + + @property + def app(self) -> AppBase: + return self.parent.app + + +class AppRootPath(AppPath): + def __init__(self, app: AppBase, path: str): + super().__init__(path, True, "root", "Application root path.") + self._app = app + + @property + def parent(self) -> None: + return None + + @property + def app(self) -> AppBase: + return self._app + + class AppFeatureProvider: def __init__(self, name: str, /, app: AppBase | None = None): super().__init__() self._name = name self._app = app if app else AppBase.get_instance() - self._app_paths: list[ApplicationPath] = [] - self.app.add_app_feature(self) + self.app.add_feature(self) @property def app(self) -> AppBase: @@ -31,15 +167,6 @@ class AppFeatureProvider: def name(self) -> str: return self._name - @property - def app_paths(self) -> list[ApplicationPath]: - return self._app_paths - - def add_app_path(self, subpath: str, is_dir: bool) -> ApplicationPath: - p = ApplicationPath(self.app.app_dir, subpath, is_dir) - self._app_paths.append(p) - return p - class AppCommandFeatureProvider(AppFeatureProvider, ABC): @abstractmethod @@ -49,7 +176,7 @@ class AppCommandFeatureProvider(AppFeatureProvider, ABC): def run_command(self, args: Namespace) -> None: ... -class AppBase(CruApplication): +class AppBase: _instance: AppBase | None = None @staticmethod @@ -58,28 +185,47 @@ class AppBase(CruApplication): raise CruInternalError("App instance not initialized") return AppBase._instance - def __init__(self, name: str, app_dir: str): - super().__init__(name) + def __init__(self, name: str, root: str): AppBase._instance = self - self._app_dir = app_dir - self._app_features: list[AppFeatureProvider] = [] + self._name = name + self._root = AppRootPath(self, root) + self._paths: list[AppFeaturePath] = [] + self._features: list[AppFeatureProvider] = [] @property - def app_dir(self) -> str: - return self._app_dir + def name(self) -> str: + return self._name @property - def app_features(self) -> list[AppFeatureProvider]: - return self._app_features + def root(self) -> AppRootPath: + return self._root @property - def app_paths(self) -> Iterable[ApplicationPath]: - return ( - CruIterator(self._app_features).transform(lambda x: x.app_paths).flatten(1) - ) + def features(self) -> list[AppFeatureProvider]: + return self._features + + @property + def paths(self) -> list[AppFeaturePath]: + return self._paths - def add_app_feature(self, feature: AppFeatureProvider) -> None: - self._app_features.append(feature) + def add_feature(self, feature: AppFeatureProvider) -> AppFeatureProvider: + self._features.append(feature) + return feature + + def add_path( + self, + name: str, + is_dir: bool, + /, + parent: AppPath | None = None, + id: str | None = None, + description: str = "", + ) -> AppFeaturePath: + p = AppFeaturePath( + parent or self.root, name, is_dir, id=id, description=description + ) + self._paths.append(p) + return p @overload def get_feature(self, feature: str) -> AppFeatureProvider: ... @@ -89,11 +235,11 @@ class AppBase(CruApplication): def get_feature(self, feature: str | type[_F]) -> AppFeatureProvider | _F: if isinstance(feature, str): - for f in self._app_features: + for f in self._features: if f.name == feature: return f elif isinstance(feature, type): - for f in self._app_features: + for f in self._features: if isinstance(f, feature): return f else: @@ -102,3 +248,9 @@ class AppBase(CruApplication): ) raise InternalAppException(f"Feature {feature} not found.") + + def get_path(self, name: str) -> AppFeaturePath: + for p in self._paths: + if p.id == name or p.name == name: + return p + raise InternalAppException(f"Application path {name} not found.") diff --git a/tools/cru-py/cru/service/_config.py b/tools/cru-py/cru/service/_config.py index 1838015..a387ef7 100644 --- a/tools/cru-py/cru/service/_config.py +++ b/tools/cru-py/cru/service/_config.py @@ -1,15 +1,14 @@ -import os.path -from ._base import AppFeatureProvider +from ._base import AppFeaturePath, AppFeatureProvider from ._data import DataManager class ConfigManager(AppFeatureProvider): - def __init__(self, config_file_name="config") -> None: + def __init__(self) -> None: super().__init__("config-manager") - self._file_name = config_file_name + self._config_path = self.app.get_feature(DataManager).data_dir.add_subpath( + "config", False, description="Configuration file path." + ) @property - def config_file_path(self) -> str: - return os.path.join( - self.app.get_feature(DataManager).data_dir.full_path, self._file_name - ) + def config_path(self) -> AppFeaturePath: + return self._config_path diff --git a/tools/cru-py/cru/service/_data.py b/tools/cru-py/cru/service/_data.py index f38dc23..3cddfc8 100644 --- a/tools/cru-py/cru/service/_data.py +++ b/tools/cru-py/cru/service/_data.py @@ -1,12 +1,11 @@ -from cru.app import ApplicationPath -from ._base import AppFeatureProvider +from ._base import AppFeaturePath, AppFeatureProvider class DataManager(AppFeatureProvider): def __init__(self) -> None: super().__init__("data-manager") - self._dir = self.add_app_path("data", True) + self._dir = self.app.add_path("data", True) @property - def data_dir(self) -> ApplicationPath: + def data_dir(self) -> AppFeaturePath: return self._dir diff --git a/tools/cru-py/cru/service/_template.py b/tools/cru-py/cru/service/_template.py index bf13212..fcc5658 100644 --- a/tools/cru-py/cru/service/_template.py +++ b/tools/cru-py/cru/service/_template.py @@ -1,26 +1,25 @@ from argparse import ArgumentParser, Namespace - -from ._base import AppCommandFeatureProvider -from cru.app import ApplicationPath from cru.template import TemplateTree +from ._base import AppCommandFeatureProvider, AppFeaturePath + class TemplateManager(AppCommandFeatureProvider): def __init__(self, prefix: str = "CRUPEST"): super().__init__("template-manager") - self._templates_dir = self.add_app_path("templates", True) - self._generated_dir = self.add_app_path("generated", True) + self._templates_dir = self.app.add_path("templates", True) + self._generated_dir = self.app.add_path("generated", True) self._template_tree = TemplateTree( prefix, self._templates_dir.full_path_str, self._generated_dir.full_path_str ) @property - def templates_dir(self) -> ApplicationPath: + def templates_dir(self) -> AppFeaturePath: return self._templates_dir @property - def generated_dir(self) -> ApplicationPath: + def generated_dir(self) -> AppFeaturePath: return self._generated_dir def add_arg_parser(self, arg_parser: ArgumentParser) -> None: |