2021-10-22 15:50:26 +00:00
|
|
|
import functools
|
|
|
|
import re
|
|
|
|
from pathlib import Path
|
2021-11-13 02:27:27 +00:00
|
|
|
from typing import Generator, List, Optional, Dict, Any
|
2021-10-22 15:50:26 +00:00
|
|
|
|
|
|
|
import attr
|
2021-10-28 13:53:32 +00:00
|
|
|
from ruamel.yaml.comments import CommentedMap
|
2021-10-22 15:50:26 +00:00
|
|
|
|
2021-11-13 02:27:27 +00:00
|
|
|
from ._constants import COMPOSE_FILE_NAME, CONF_DIRECTORY_NAME
|
|
|
|
from .config import KiwiConfig, ProjectConfig
|
2021-10-27 11:33:26 +00:00
|
|
|
from .misc import YAML
|
2021-10-22 15:50:26 +00:00
|
|
|
|
|
|
|
_RE_CONFDIR = re.compile(r"^\s*\$(?:CONFDIR|{CONFDIR})/+(.*)$", flags=re.UNICODE)
|
|
|
|
|
|
|
|
|
|
|
|
@attr.s
|
|
|
|
class Service:
|
|
|
|
name: str = attr.ib()
|
2021-11-03 15:32:01 +00:00
|
|
|
content: CommentedMap = attr.ib()
|
2021-10-22 15:50:26 +00:00
|
|
|
|
2021-10-28 13:53:32 +00:00
|
|
|
@property
|
|
|
|
def configs(self) -> Generator[Path, None, None]:
|
2021-11-03 15:32:01 +00:00
|
|
|
if "volumes" not in self.content:
|
2021-10-28 13:53:32 +00:00
|
|
|
return
|
2021-10-22 15:50:26 +00:00
|
|
|
|
2021-11-03 15:32:01 +00:00
|
|
|
for volume in self.content["volumes"]:
|
2021-10-28 13:53:32 +00:00
|
|
|
host_part = volume.split(":")[0]
|
|
|
|
cd_match = _RE_CONFDIR.match(host_part)
|
2021-10-22 15:50:26 +00:00
|
|
|
|
2021-10-28 13:53:32 +00:00
|
|
|
if cd_match:
|
2021-10-28 14:48:54 +00:00
|
|
|
yield Path(cd_match.group(1))
|
2021-10-22 15:50:26 +00:00
|
|
|
|
|
|
|
|
2021-10-28 13:53:32 +00:00
|
|
|
@attr.s
|
|
|
|
class Services:
|
|
|
|
content: List[Service] = attr.ib()
|
|
|
|
|
|
|
|
def __str__(self) -> str:
|
|
|
|
return YAML().dump({
|
|
|
|
"services": {
|
2021-11-03 15:32:01 +00:00
|
|
|
service.name: service.content
|
2021-10-28 13:53:32 +00:00
|
|
|
for service in self.content
|
|
|
|
}
|
2021-10-28 14:48:54 +00:00
|
|
|
}).strip()
|
|
|
|
|
2021-11-06 02:45:27 +00:00
|
|
|
def __bool__(self) -> bool:
|
|
|
|
return bool(self.content)
|
|
|
|
|
2021-11-27 15:21:54 +00:00
|
|
|
def filter_existing(self, service_names: List[str]) -> "Services":
|
2021-11-06 02:45:27 +00:00
|
|
|
return Services([
|
|
|
|
service
|
|
|
|
for service in self.content
|
|
|
|
if service.name in service_names
|
|
|
|
])
|
|
|
|
|
2021-10-22 15:50:26 +00:00
|
|
|
|
|
|
|
@attr.s
|
2021-11-03 15:32:01 +00:00
|
|
|
class Project:
|
|
|
|
directory: Path = attr.ib()
|
2021-11-13 02:27:27 +00:00
|
|
|
config: KiwiConfig = attr.ib()
|
2021-10-26 10:28:06 +00:00
|
|
|
|
2021-10-28 13:53:32 +00:00
|
|
|
@staticmethod
|
2021-10-26 13:59:38 +00:00
|
|
|
@functools.lru_cache(maxsize=10)
|
2021-11-03 15:32:01 +00:00
|
|
|
def _parse_compose_file(directory: Path) -> CommentedMap:
|
2021-10-26 13:59:38 +00:00
|
|
|
with open(directory.joinpath(COMPOSE_FILE_NAME), "r") as cf:
|
2021-10-27 11:33:26 +00:00
|
|
|
return YAML().load(cf)
|
2021-10-26 13:59:38 +00:00
|
|
|
|
2021-11-06 02:45:27 +00:00
|
|
|
@property
|
|
|
|
def name(self) -> str:
|
|
|
|
return self.directory.name
|
|
|
|
|
2021-11-13 02:27:27 +00:00
|
|
|
@property
|
|
|
|
def project_config(self) -> ProjectConfig:
|
|
|
|
return self.config.get_project_config(self.name)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def process_kwargs(self) -> Dict[str, Any]:
|
|
|
|
directory: Path = self.directory
|
|
|
|
project_name: str = self.name
|
|
|
|
kiwi_hub_name: str = self.config.network.name
|
|
|
|
target_root_dir: Path = self.config.storage.directory
|
|
|
|
conf_dir: Path = target_root_dir.joinpath(CONF_DIRECTORY_NAME)
|
|
|
|
target_dir: Path = target_root_dir.joinpath(project_name)
|
|
|
|
|
|
|
|
result: Dict[str, Any] = {
|
|
|
|
"cwd": str(directory),
|
|
|
|
"env": {
|
|
|
|
"COMPOSE_PROJECT_NAME": project_name,
|
|
|
|
"KIWI_HUB_NAME": kiwi_hub_name,
|
|
|
|
"TARGETROOT": str(target_root_dir),
|
|
|
|
"CONFDIR": str(conf_dir),
|
|
|
|
"TARGETDIR": str(target_dir),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
result["env"].update(self.config.environment)
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
2021-11-06 02:45:27 +00:00
|
|
|
@property
|
|
|
|
def services(self) -> Services:
|
2021-11-03 15:32:01 +00:00
|
|
|
yml = Project._parse_compose_file(self.directory)
|
2021-11-06 02:45:27 +00:00
|
|
|
|
|
|
|
return Services([
|
2021-10-28 13:53:32 +00:00
|
|
|
Service(name, description)
|
2021-10-26 13:59:38 +00:00
|
|
|
for name, description in yml["services"].items()
|
2021-11-06 02:45:27 +00:00
|
|
|
])
|
2021-11-03 15:32:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
@attr.s
|
|
|
|
class Instance:
|
|
|
|
directory: Path = attr.ib(default=Path('.'))
|
|
|
|
|
|
|
|
@property
|
|
|
|
def config(self) -> KiwiConfig:
|
|
|
|
"""shorthand: get the current configuration"""
|
|
|
|
|
|
|
|
return KiwiConfig.from_directory(self.directory)
|
|
|
|
|
2021-11-13 02:27:27 +00:00
|
|
|
@staticmethod
|
|
|
|
@functools.lru_cache(maxsize=None)
|
|
|
|
def __get_project(instance_directory: Path, project_name: str) -> Optional[Project]:
|
|
|
|
instance = Instance(instance_directory)
|
|
|
|
config = instance.config
|
|
|
|
|
|
|
|
for project in config.projects:
|
2021-11-03 15:32:01 +00:00
|
|
|
if project.name == project_name:
|
2021-11-13 02:27:27 +00:00
|
|
|
return Project(
|
|
|
|
directory=instance_directory.joinpath(project.name),
|
|
|
|
config=config,
|
|
|
|
)
|
|
|
|
|
|
|
|
def get_project(self, project_name: str) -> Optional[Project]:
|
|
|
|
project = Instance.__get_project(self.directory, project_name)
|
2021-11-17 14:58:31 +00:00
|
|
|
if project is None:
|
|
|
|
return
|
|
|
|
|
2021-11-13 02:27:27 +00:00
|
|
|
project.instance = self
|
|
|
|
return project
|