Split instance.py

This commit is contained in:
Jörn-Michael Miehe 2021-12-02 17:08:14 +01:00
parent 00bb2adee4
commit 1d5c4ccbee
16 changed files with 178 additions and 141 deletions

View file

@ -7,7 +7,9 @@ from typing import List, Iterable, Type, Optional, TypeVar
import click import click
from ..instance import Instance, Project, Services from ..instance import Instance
from ..project import Project
from ..services import Services
from ..wstring import WParagraph, WAlignment from ..wstring import WParagraph, WAlignment
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)

View file

@ -3,7 +3,8 @@ from typing import List
from .cli import KiwiCommand, KiwiCommandType from .cli import KiwiCommand, KiwiCommandType
from .decorators import kiwi_command from .decorators import kiwi_command
from ..executable import COMPOSE_EXE from ..executable import COMPOSE_EXE
from ..instance import Instance, Project from ..instance import Instance
from ..project import Project
@kiwi_command( @kiwi_command(

View file

@ -5,7 +5,8 @@ import click
from .cli import KiwiCommand, KiwiCommandType from .cli import KiwiCommand, KiwiCommandType
from .decorators import kiwi_command from .decorators import kiwi_command
from ..executable import COMPOSE_EXE from ..executable import COMPOSE_EXE
from ..instance import Instance, Project from ..instance import Instance
from ..project import Project
@click.argument( @click.argument(

View file

@ -3,7 +3,8 @@ import click
from .cli import KiwiCommand, KiwiCommandType from .cli import KiwiCommand, KiwiCommandType
from .decorators import kiwi_command from .decorators import kiwi_command
from .._constants import KIWI_CONF_NAME from .._constants import KIWI_CONF_NAME
from ..instance import Instance, Project from ..instance import Instance
from ..project import Project
@click.option( @click.option(

View file

@ -5,7 +5,9 @@ import click
from .cli import KiwiCommand, KiwiCommandType from .cli import KiwiCommand, KiwiCommandType
from .decorators import kiwi_command from .decorators import kiwi_command
from ..executable import COMPOSE_EXE from ..executable import COMPOSE_EXE
from ..instance import Instance, Project, Services from ..instance import Instance
from ..project import Project
from ..services import Services
@click.option( @click.option(

View file

@ -3,7 +3,8 @@ import click
from .cli import KiwiCommand, KiwiCommandType from .cli import KiwiCommand, KiwiCommandType
from .decorators import kiwi_command from .decorators import kiwi_command
from .._constants import KIWI_CONF_NAME from .._constants import KIWI_CONF_NAME
from ..instance import Instance, Project from ..instance import Instance
from ..project import Project
@click.option( @click.option(

View file

@ -4,7 +4,8 @@ import click
from .cli import KiwiCommandType, KiwiCommand from .cli import KiwiCommandType, KiwiCommand
from .decorators import kiwi_command from .decorators import kiwi_command
from ..instance import Instance, Project from ..instance import Instance
from ..project import Project
@click.option( @click.option(

View file

@ -5,7 +5,9 @@ import click
from .cli import KiwiCommand, KiwiCommandType from .cli import KiwiCommand, KiwiCommandType
from .decorators import kiwi_command from .decorators import kiwi_command
from ..executable import COMPOSE_EXE from ..executable import COMPOSE_EXE
from ..instance import Instance, Project, Services from ..instance import Instance
from ..project import Project
from ..services import Services
@click.option( @click.option(

View file

@ -5,7 +5,9 @@ import click
from .cli import KiwiCommand, KiwiCommandType from .cli import KiwiCommand, KiwiCommandType
from .decorators import kiwi_command from .decorators import kiwi_command
from ..executable import COMPOSE_EXE from ..executable import COMPOSE_EXE
from ..instance import Instance, Project, Services from ..instance import Instance
from ..project import Project
from ..services import Services
@kiwi_command(short_help="Bring up kiwi services") @kiwi_command(short_help="Bring up kiwi services")

View file

@ -1,136 +1,10 @@
import functools
import re
import subprocess
from pathlib import Path from pathlib import Path
from typing import Generator, List, Optional, Dict, Any from typing import Generator
import attr import attr
from ruamel.yaml.comments import CommentedMap
from ._constants import COMPOSE_FILE_NAME, CONF_DIRECTORY_NAME from .config import KiwiConfig
from .config import KiwiConfig, ProjectConfig from .project import Project
from .executable import COMPOSE_EXE
from .yaml import YAML
@attr.s
class Service:
name: str = attr.ib()
content: CommentedMap = attr.ib()
parent: "Project" = attr.ib()
_RE_CONFDIR = re.compile(r"^\s*\$(?:CONFDIR|{CONFDIR})/+(.*)$", flags=re.UNICODE)
@property
def configs(self) -> Generator[Path, None, None]:
if "volumes" not in self.content:
return
for volume in self.content["volumes"]:
host_part = volume.split(":")[0]
cd_match = Service._RE_CONFDIR.match(host_part)
if cd_match:
yield Path(cd_match.group(1))
def has_executable(self, exe_name: str) -> bool:
try:
# test if desired executable exists
COMPOSE_EXE.run(
["exec", "-T", self.name, "/bin/sh", "-c", f"command -v {exe_name}"],
check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
**self.parent.process_kwargs,
)
return True
except subprocess.CalledProcessError:
return False
@attr.s
class Services:
content: List[Service] = attr.ib()
def __str__(self) -> str:
return YAML().dump({
"services": {
service.name: service.content
for service in self.content
}
}).strip()
def __bool__(self) -> bool:
return bool(self.content)
@property
def names(self) -> Generator[str, None, None]:
return (
service.name
for service in self.content
)
def filter_existing(self, service_names: List[str]) -> "Services":
return Services([
service
for service in self.content
if service.name in service_names
])
@attr.s
class Project:
directory: Path = attr.ib()
parent: "Instance" = attr.ib()
@staticmethod
@functools.lru_cache(maxsize=10)
def _parse_compose_file(directory: Path) -> CommentedMap:
with open(directory.joinpath(COMPOSE_FILE_NAME), "r") as cf:
return YAML().load(cf)
@property
def name(self) -> str:
return self.directory.name
@property
def config(self) -> Optional[ProjectConfig]:
return self.parent.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.parent.config.network.name
target_root_dir: Path = self.parent.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.parent.config.environment)
return result
@property
def services(self) -> Services:
yml = Project._parse_compose_file(self.directory)
return Services([
Service(
name=name,
content=content,
parent=self,
) for name, content in yml["services"].items()
])
@attr.s @attr.s

69
kiwi_scp/project.py Normal file
View file

@ -0,0 +1,69 @@
import functools
from pathlib import Path
from typing import Optional, Dict, Any
import attr
from ruamel.yaml import CommentedMap
from ._constants import COMPOSE_FILE_NAME, CONF_DIRECTORY_NAME
from .config import ProjectConfig
from .instance import Instance
from .service import Service
from .services import Services
from .yaml import YAML
@attr.s
class Project:
directory: Path = attr.ib()
parent: "Instance" = attr.ib()
@staticmethod
@functools.lru_cache(maxsize=10)
def _parse_compose_file(directory: Path) -> CommentedMap:
with open(directory.joinpath(COMPOSE_FILE_NAME), "r") as cf:
return YAML().load(cf)
@property
def name(self) -> str:
return self.directory.name
@property
def config(self) -> Optional[ProjectConfig]:
return self.parent.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.parent.config.network.name
target_root_dir: Path = self.parent.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.parent.config.environment)
return result
@property
def services(self) -> Services:
yml = Project._parse_compose_file(self.directory)
return Services([
Service(
name=name,
content=content,
parent=self,
) for name, content in yml["services"].items()
])

44
kiwi_scp/service.py Normal file
View file

@ -0,0 +1,44 @@
import re
import subprocess
from pathlib import Path
from typing import Generator
import attr
from ruamel.yaml import CommentedMap
from .executable import COMPOSE_EXE
from .project import Project
@attr.s
class Service:
name: str = attr.ib()
content: CommentedMap = attr.ib()
parent: "Project" = attr.ib()
_RE_CONFDIR = re.compile(r"^\s*\$(?:CONFDIR|{CONFDIR})/+(.*)$", flags=re.UNICODE)
@property
def configs(self) -> Generator[Path, None, None]:
if "volumes" not in self.content:
return
for volume in self.content["volumes"]:
host_part = volume.split(":")[0]
cd_match = Service._RE_CONFDIR.match(host_part)
if cd_match:
yield Path(cd_match.group(1))
def has_executable(self, exe_name: str) -> bool:
try:
# test if desired executable exists
COMPOSE_EXE.run(
["exec", "-T", self.name, "/bin/sh", "-c", f"command -v {exe_name}"],
check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
**self.parent.process_kwargs,
)
return True
except subprocess.CalledProcessError:
return False

36
kiwi_scp/services.py Normal file
View file

@ -0,0 +1,36 @@
from typing import List, Generator
import attr
from kiwi_scp.service import Service
from kiwi_scp.yaml import YAML
@attr.s
class Services:
content: List[Service] = attr.ib()
def __str__(self) -> str:
return YAML().dump({
"services": {
service.name: service.content
for service in self.content
}
}).strip()
def __bool__(self) -> bool:
return bool(self.content)
@property
def names(self) -> Generator[str, None, None]:
return (
service.name
for service in self.content
)
def filter_existing(self, service_names: List[str]) -> "Services":
return Services([
service
for service in self.content
if service.name in service_names
])

View file

@ -4,7 +4,7 @@ import pytest
from kiwi_scp._constants import COMPOSE_FILE_NAME from kiwi_scp._constants import COMPOSE_FILE_NAME
from kiwi_scp.config import KiwiConfig from kiwi_scp.config import KiwiConfig
from kiwi_scp.instance import Project from kiwi_scp.project import Project
class TestDefault: class TestDefault:

View file

@ -2,7 +2,7 @@ from pathlib import Path
from ruamel.yaml import CommentedMap from ruamel.yaml import CommentedMap
from kiwi_scp.instance import Service from kiwi_scp.service import Service
class TestDefault: class TestDefault:

View file

@ -1,6 +1,7 @@
from ruamel.yaml import CommentedMap from ruamel.yaml import CommentedMap
from kiwi_scp.instance import Service, Services from kiwi_scp.services import Services
from kiwi_scp.service import Service
class TestServices: class TestServices: