aboutsummaryrefslogtreecommitdiff
path: root/tools/cru-py/cru
diff options
context:
space:
mode:
Diffstat (limited to 'tools/cru-py/cru')
-rw-r--r--tools/cru-py/cru/app.py81
-rw-r--r--tools/cru-py/cru/service/_base.py214
-rw-r--r--tools/cru-py/cru/service/_config.py15
-rw-r--r--tools/cru-py/cru/service/_data.py7
-rw-r--r--tools/cru-py/cru/service/_template.py13
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: