mirror of
https://github.com/yavook/kiwi-scp.git
synced 2024-12-24 18:22:59 +00:00
abandoned utils.misc for project handling
This commit is contained in:
parent
0cf934965e
commit
267f85fa8d
9 changed files with 182 additions and 204 deletions
|
@ -2,7 +2,7 @@
|
|||
import logging
|
||||
|
||||
# local
|
||||
from .utils.misc import get_first_project_name, get_services, list_projects
|
||||
from .utils.project import Projects
|
||||
|
||||
# parent
|
||||
from ..parser import Parser
|
||||
|
@ -16,12 +16,13 @@ class SubCommand:
|
|||
# command parser
|
||||
_sub_parser = None
|
||||
|
||||
def __init__(self, name, **kwargs):
|
||||
def __init__(self, name, add_parser=True, **kwargs):
|
||||
self.__name = name
|
||||
self._sub_parser = Parser().get_subparsers().add_parser(
|
||||
name,
|
||||
**kwargs
|
||||
)
|
||||
if add_parser:
|
||||
self._sub_parser = Parser().get_subparsers().add_parser(
|
||||
name,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.__name
|
||||
|
@ -34,9 +35,9 @@ class SubCommand:
|
|||
class ProjectCommand(SubCommand):
|
||||
"""this command concerns a project in current instance"""
|
||||
|
||||
def __init__(self, name, num_projects, **kwargs):
|
||||
def __init__(self, name, num_projects, add_parser=True, **kwargs):
|
||||
super().__init__(
|
||||
name,
|
||||
name, add_parser=add_parser,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
@ -54,9 +55,9 @@ class ProjectCommand(SubCommand):
|
|||
class ServiceCommand(ProjectCommand):
|
||||
"""this command concerns service(s) in a project"""
|
||||
|
||||
def __init__(self, name, num_projects, num_services, **kwargs):
|
||||
def __init__(self, name, num_projects, num_services, add_parser=True, **kwargs):
|
||||
super().__init__(
|
||||
name, num_projects=num_projects,
|
||||
name, num_projects=num_projects, add_parser=add_parser,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
@ -76,9 +77,9 @@ class FlexCommand(ServiceCommand):
|
|||
|
||||
__action = None
|
||||
|
||||
def __init__(self, name, action='', **kwargs):
|
||||
def __init__(self, name, action='', add_parser=True, **kwargs):
|
||||
super().__init__(
|
||||
name, num_projects='?', num_services='*',
|
||||
name, num_projects='?', num_services='*', add_parser=add_parser,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
@ -91,8 +92,8 @@ class FlexCommand(ServiceCommand):
|
|||
def _run_instance(self, runner, config, args):
|
||||
result = True
|
||||
|
||||
for project_name in list_projects(config):
|
||||
args.projects = project_name
|
||||
for project in Projects.from_args(args):
|
||||
args.projects = project.get_name()
|
||||
result &= runner.run(str(self))
|
||||
|
||||
return result
|
||||
|
@ -104,19 +105,18 @@ class FlexCommand(ServiceCommand):
|
|||
pass
|
||||
|
||||
def run(self, runner, config, args):
|
||||
project_name = get_first_project_name(args)
|
||||
services = get_services(args)
|
||||
|
||||
if project_name is None:
|
||||
projects = Projects.from_args(args)
|
||||
if not projects:
|
||||
# no project given, run for entire instance
|
||||
logging.info(f"{self.__action} this instance")
|
||||
return self._run_instance(runner, config, args)
|
||||
|
||||
if not services:
|
||||
project = projects[0]
|
||||
if args is None or 'services' not in args or not args.services:
|
||||
# no services given, run for whole project
|
||||
logging.info(f"{self.__action} project '{project_name}'")
|
||||
logging.info(f"{self.__action} project '{project.get_name()}'")
|
||||
return self._run_project(runner, config, args)
|
||||
|
||||
# run for service(s) inside project
|
||||
logging.info(f"{self.__action} services {services} in project '{project_name}'")
|
||||
return self._run_services(runner, config, args, services)
|
||||
logging.info(f"{self.__action} services {args.services} in project '{project.get_name()}'")
|
||||
return self._run_services(runner, config, args, args.services)
|
||||
|
|
|
@ -5,7 +5,7 @@ import subprocess
|
|||
|
||||
# local
|
||||
from ._subcommand import SubCommand
|
||||
from .utils.misc import list_projects, get_project_dir
|
||||
from .utils.project import Projects
|
||||
from .utils.rootkit import Rootkit, prefix_path_mnt
|
||||
|
||||
# parent
|
||||
|
@ -22,13 +22,11 @@ class ConfCopyCommand(SubCommand):
|
|||
)
|
||||
|
||||
def run(self, runner, config, args):
|
||||
conf_dirs = []
|
||||
|
||||
for project_name in list_projects(config):
|
||||
project_conf = f"{get_project_dir(config, project_name)}/{CONF_DIRECTORY_NAME}"
|
||||
|
||||
if os.path.isdir(project_conf):
|
||||
conf_dirs.append(project_conf)
|
||||
conf_dirs = [
|
||||
project.conf_dir_name()
|
||||
for project in Projects.all()
|
||||
if project.is_enabled()
|
||||
]
|
||||
|
||||
if conf_dirs:
|
||||
# add target directory
|
||||
|
@ -76,14 +74,11 @@ class ConfCleanCommand(SubCommand):
|
|||
def run(self, runner, config, args):
|
||||
result = True
|
||||
|
||||
# down all projects with config directories
|
||||
affected_projects = []
|
||||
|
||||
for project_name in list_projects(config):
|
||||
project_conf = f"{get_project_dir(config, project_name)}/{CONF_DIRECTORY_NAME}"
|
||||
|
||||
if os.path.isdir(project_conf):
|
||||
affected_projects.append(project_name)
|
||||
affected_projects = [
|
||||
project.conf_dir_name()
|
||||
for project in Projects.all()
|
||||
if project.has_configs()
|
||||
]
|
||||
|
||||
for project_name in affected_projects:
|
||||
args.projects = project_name
|
||||
|
@ -91,7 +86,7 @@ class ConfCleanCommand(SubCommand):
|
|||
|
||||
# cleanly sync configs
|
||||
result &= runner.run('conf-purge')
|
||||
result &= runner.run('conf-purge')
|
||||
result &= runner.run('conf-copy')
|
||||
|
||||
# bring projects back up
|
||||
for project_name in affected_projects:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# local
|
||||
from .utils.project import Project
|
||||
from .utils.project import Projects
|
||||
from ._subcommand import ProjectCommand
|
||||
|
||||
|
||||
|
@ -13,9 +13,7 @@ class DisableCommand(ProjectCommand):
|
|||
)
|
||||
|
||||
def run(self, runner, config, args):
|
||||
result = True
|
||||
|
||||
for project in Project.from_args(args):
|
||||
result = project.disable()
|
||||
|
||||
return result
|
||||
return all([
|
||||
project.disable()
|
||||
for project in Projects.from_args(args)
|
||||
])
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# local
|
||||
from .utils.project import Project
|
||||
from .utils.project import Projects
|
||||
from ._subcommand import ProjectCommand
|
||||
|
||||
|
||||
|
@ -13,9 +13,7 @@ class EnableCommand(ProjectCommand):
|
|||
)
|
||||
|
||||
def run(self, runner, config, args):
|
||||
result = True
|
||||
|
||||
for project in Project.from_args(args):
|
||||
result = project.enable()
|
||||
|
||||
return result
|
||||
return all([
|
||||
project.enable()
|
||||
for project in Projects.from_args(args)
|
||||
])
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import yaml
|
||||
|
||||
# local
|
||||
from ._subcommand import FlexCommand
|
||||
from .utils.dockercommand import DockerCommand
|
||||
from .utils.misc import list_projects, get_first_project_name, get_project_dir
|
||||
from .utils.project import Projects
|
||||
|
||||
|
||||
def _print_list(strings):
|
||||
|
@ -31,35 +32,61 @@ class ListCommand(FlexCommand):
|
|||
)
|
||||
|
||||
def _run_instance(self, runner, config, args):
|
||||
print(f"Projects in instance {os.getcwd()}:")
|
||||
print("")
|
||||
print(f"kiwi-config instance at '{os.getcwd()}'")
|
||||
print("#########")
|
||||
projects = Projects.all()
|
||||
|
||||
_print_list(list_projects(config))
|
||||
enableds = [
|
||||
project.get_name()
|
||||
for project in projects
|
||||
if project.is_enabled()
|
||||
]
|
||||
|
||||
if enableds:
|
||||
print(f"Enabled projects:")
|
||||
_print_list(enableds)
|
||||
|
||||
disableds = [
|
||||
project.get_name()
|
||||
for project in projects
|
||||
if project.is_disabled()
|
||||
]
|
||||
|
||||
if disableds:
|
||||
print(f"Disabled projects:")
|
||||
_print_list(disableds)
|
||||
|
||||
return True
|
||||
|
||||
def _run_project(self, runner, config, args):
|
||||
project_name = get_first_project_name(args)
|
||||
print(f"Services in project '{project_name}':")
|
||||
print("")
|
||||
project = Projects.from_args(args)[0]
|
||||
|
||||
if not project.exists():
|
||||
logging.error(f"Project '{project.get_name()}' not found")
|
||||
return False
|
||||
|
||||
print(f"Services in project '{project.get_name()}':")
|
||||
print("#########")
|
||||
|
||||
ps = DockerCommand('docker-compose').run(
|
||||
config, args, ['config', '--services'],
|
||||
stdout=subprocess.PIPE
|
||||
)
|
||||
_print_list(ps.stdout)
|
||||
|
||||
_print_list(ps.stdout)
|
||||
return True
|
||||
|
||||
def _run_services(self, runner, config, args, services):
|
||||
import yaml
|
||||
project = Projects.from_args(args)[0]
|
||||
|
||||
project_name = get_first_project_name(args)
|
||||
project_dir = get_project_dir(config, project_name)
|
||||
print(f"Configuration of services {services} in project '{project_name}':")
|
||||
print("")
|
||||
if not project.exists():
|
||||
logging.error(f"Project '{project.get_name()}' not found")
|
||||
return False
|
||||
|
||||
with open(os.path.join(project_dir, 'docker-compose.yml'), 'r') as stream:
|
||||
print(f"Configuration of services {services} in project '{project.get_name()}':")
|
||||
print("#########")
|
||||
|
||||
with open(project.compose_file_name(), 'r') as stream:
|
||||
try:
|
||||
docker_compose_yml = yaml.safe_load(stream)
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import os
|
|||
import shutil
|
||||
|
||||
# local
|
||||
from .utils.misc import get_project_names, get_project_dir, get_project_down_dir
|
||||
from .utils.project import Projects
|
||||
from ._subcommand import ProjectCommand
|
||||
|
||||
# parent
|
||||
|
@ -22,18 +22,16 @@ class NewCommand(ProjectCommand):
|
|||
|
||||
def run(self, runner, config, args):
|
||||
result = True
|
||||
projects = Projects.from_args(args)
|
||||
|
||||
for project_name in get_project_names(args):
|
||||
project_dir = get_project_dir(config, project_name)
|
||||
project_down_dir = get_project_down_dir(config, project_name)
|
||||
|
||||
if os.path.isdir(project_dir) or os.path.isdir(project_down_dir):
|
||||
logging.error(f"Project '{project_name}' exists in this instance!")
|
||||
for project in projects:
|
||||
if project.exists():
|
||||
logging.error(f"Project '{project.get_name()}' exists in this instance!")
|
||||
result = False
|
||||
|
||||
else:
|
||||
logging.info(f"Creating project '{project_name}'")
|
||||
os.mkdir(project_dir)
|
||||
shutil.copy(DEFAULT_DOCKER_COMPOSE_NAME, os.path.join(project_dir, "docker-compose.yml"))
|
||||
logging.info(f"Creating project '{project.get_name()}'")
|
||||
os.mkdir(project.enabled_dir_name())
|
||||
shutil.copy(DEFAULT_DOCKER_COMPOSE_NAME, project.compose_file_name())
|
||||
|
||||
return result
|
||||
|
|
|
@ -5,18 +5,24 @@ import subprocess
|
|||
|
||||
# local
|
||||
from .executable import Executable
|
||||
from .misc import get_project_dir, get_first_project_name
|
||||
from .project import Projects
|
||||
|
||||
# parent
|
||||
from ..._constants import CONF_DIRECTORY_NAME
|
||||
from ...parser import Parser
|
||||
from ...config import LoadedConfig
|
||||
|
||||
|
||||
def _update_kwargs(config, args, **kwargs):
|
||||
def _update_kwargs(**kwargs):
|
||||
config = LoadedConfig.get()
|
||||
projects = Projects.from_args(Parser().get_args())
|
||||
|
||||
# project given in args: command affects a project in this instance
|
||||
project_name = get_first_project_name(args)
|
||||
if project_name is not None:
|
||||
if projects:
|
||||
project = projects[0]
|
||||
|
||||
# execute command in project directory
|
||||
kwargs['cwd'] = get_project_dir(config, project_name)
|
||||
kwargs['cwd'] = project.dir_name()
|
||||
|
||||
# ensure there is an environment
|
||||
if 'env' not in kwargs:
|
||||
|
@ -24,10 +30,10 @@ def _update_kwargs(config, args, **kwargs):
|
|||
|
||||
# create environment variables for docker commands
|
||||
kwargs['env'].update({
|
||||
'COMPOSE_PROJECT_NAME': project_name,
|
||||
'COMPOSE_PROJECT_NAME': project.get_name(),
|
||||
'KIWI_HUB_NAME': config['network:name'],
|
||||
'CONFDIR': os.path.join(config['runtime:storage'], CONF_DIRECTORY_NAME),
|
||||
'TARGETDIR': os.path.join(config['runtime:storage'], get_project_dir(config, project_name))
|
||||
'TARGETDIR': project.target_dir_name()
|
||||
})
|
||||
|
||||
logging.debug(f"kwargs updated: {kwargs}")
|
||||
|
@ -53,7 +59,7 @@ class DockerCommand(Executable):
|
|||
raise PermissionError("Cannot access docker, please get into the docker group or run as root!")
|
||||
|
||||
def run(self, config, args, process_args, **kwargs):
|
||||
kwargs = _update_kwargs(config, args, **kwargs)
|
||||
kwargs = _update_kwargs(**kwargs)
|
||||
|
||||
# equivalent to 'super().run' but agnostic of nested class construct
|
||||
return super().__getattr__("run")(
|
||||
|
@ -62,7 +68,7 @@ class DockerCommand(Executable):
|
|||
)
|
||||
|
||||
def run_less(self, config, args, process_args, **kwargs):
|
||||
kwargs = _update_kwargs(config, args, **kwargs)
|
||||
kwargs = _update_kwargs(**kwargs)
|
||||
|
||||
return super().__getattr__("run_less")(
|
||||
process_args, config,
|
||||
|
|
|
@ -1,76 +1,3 @@
|
|||
import os
|
||||
|
||||
|
||||
def get_project_names(args):
|
||||
"""get project names from CLI args"""
|
||||
|
||||
if args is not None and 'projects' in args:
|
||||
if isinstance(args.projects, list):
|
||||
if args.projects:
|
||||
return args.projects
|
||||
else:
|
||||
return None
|
||||
elif isinstance(args.projects, str):
|
||||
return [args.projects]
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def get_first_project_name(args):
|
||||
"""get first project name from CLI args"""
|
||||
|
||||
names = get_project_names(args)
|
||||
if names is not None:
|
||||
return names[0]
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def get_services(args):
|
||||
"""get services list from CLI args"""
|
||||
|
||||
if args is not None and 'services' in args:
|
||||
return args.services
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def get_project_dir(config, project_name):
|
||||
"""get project directory"""
|
||||
|
||||
return f"{project_name}{config['markers:project']}"
|
||||
|
||||
|
||||
def get_project_down_dir(config, project_name):
|
||||
"""get project directory"""
|
||||
|
||||
return f"{get_project_dir(config, project_name)}{config['markers:down']}"
|
||||
|
||||
|
||||
def get_target_dir(config, project_name):
|
||||
"""get project's target directory"""
|
||||
|
||||
return os.path.join(config['runtime:storage'], get_project_dir(config, project_name))
|
||||
|
||||
|
||||
def list_projects(config):
|
||||
"""list projects in current instance"""
|
||||
|
||||
# complete dir listing
|
||||
content = os.listdir()
|
||||
|
||||
# filter directories
|
||||
dirs = [d for d in content if os.path.isdir(d)]
|
||||
|
||||
# filter suffix
|
||||
project_dirs = [p for p in dirs if p.endswith(config['markers:project'])]
|
||||
|
||||
# remove suffix
|
||||
projects = [p[:-len(config['markers:project'])] for p in project_dirs]
|
||||
|
||||
return projects
|
||||
|
||||
|
||||
def _surround(string, bang):
|
||||
midlane = f"{bang * 3} {string} {bang * 3}"
|
||||
sidelane = bang*len(midlane)
|
||||
|
@ -86,6 +13,7 @@ def _emphasize(lines):
|
|||
else:
|
||||
return lines
|
||||
|
||||
|
||||
def are_you_sure(prompt, default="no"):
|
||||
if default.lower() == 'yes':
|
||||
suffix = "[YES|no]"
|
||||
|
|
|
@ -1,79 +1,58 @@
|
|||
import logging
|
||||
import os
|
||||
|
||||
from kiwi._constants import CONF_DIRECTORY_NAME
|
||||
from kiwi.config import LoadedConfig
|
||||
from ..._constants import CONF_DIRECTORY_NAME
|
||||
from ...config import LoadedConfig
|
||||
|
||||
|
||||
class Project:
|
||||
__name = None
|
||||
__config = None
|
||||
|
||||
def __init__(self, name):
|
||||
self.__name = name
|
||||
self.__config = LoadedConfig.get()
|
||||
|
||||
@classmethod
|
||||
def from_names(cls, names):
|
||||
return [cls(name) for name in names]
|
||||
|
||||
@classmethod
|
||||
def all(cls):
|
||||
# current directory content
|
||||
content = os.listdir()
|
||||
|
||||
# filter subdirectories
|
||||
dirs = [dir_name for dir_name in content if os.path.isdir(dir_name)]
|
||||
|
||||
# filter by suffix
|
||||
project_dirs = [dir_name for dir_name in dirs if dir_name.endswith(cls.__config['markers:project'])]
|
||||
|
||||
# remove suffix
|
||||
project_names = [project_name[:-len(cls.__config['markers:project'])] for project_name in project_dirs]
|
||||
|
||||
return cls.from_names(project_names)
|
||||
|
||||
@classmethod
|
||||
def from_args(cls, args):
|
||||
if args is not None and 'projects' in args:
|
||||
if isinstance(args.projects, list) and args.projects:
|
||||
return cls.from_names(args.projects)
|
||||
elif isinstance(args.projects, str):
|
||||
return cls.from_names([args.projects])
|
||||
|
||||
return []
|
||||
|
||||
def get_name(self):
|
||||
return self.__name
|
||||
|
||||
def dir_name(self):
|
||||
return f"{self.__name}{self.__config['markers:project']}"
|
||||
if self.is_enabled():
|
||||
return self.enabled_dir_name()
|
||||
elif self.is_disabled():
|
||||
return self.disabled_dir_name()
|
||||
else:
|
||||
return None
|
||||
|
||||
def down_dir_name(self):
|
||||
return f"{self.dir_name()}{self.__config['markers:down']}"
|
||||
def enabled_dir_name(self):
|
||||
return f"{self.__name}{LoadedConfig.get()['markers:project']}"
|
||||
|
||||
def disabled_dir_name(self):
|
||||
return f"{self.enabled_dir_name()}{LoadedConfig.get()['markers:down']}"
|
||||
|
||||
def conf_dir_name(self):
|
||||
return os.path.join(self.dir_name(), CONF_DIRECTORY_NAME)
|
||||
|
||||
def compose_file_name(self):
|
||||
return os.path.join(self.dir_name(), 'docker-compose.yml')
|
||||
|
||||
def target_dir_name(self):
|
||||
return os.path.join(self.__config['runtime:storage'], self.dir_name())
|
||||
return os.path.join(LoadedConfig.get()['runtime:storage'], self.enabled_dir_name())
|
||||
|
||||
def exists(self):
|
||||
return os.path.isdir(self.dir_name()) or os.path.isdir(self.down_dir_name())
|
||||
return os.path.isdir(self.enabled_dir_name()) or os.path.isdir(self.disabled_dir_name())
|
||||
|
||||
def is_enabled(self):
|
||||
return os.path.isdir(self.dir_name())
|
||||
return os.path.isdir(self.enabled_dir_name())
|
||||
|
||||
def is_disabled(self):
|
||||
return os.path.isdir(self.down_dir_name())
|
||||
return os.path.isdir(self.disabled_dir_name())
|
||||
|
||||
def has_configs(self):
|
||||
return os.path.isdir(self.dir_name())
|
||||
return os.path.isdir(self.conf_dir_name())
|
||||
|
||||
def enable(self):
|
||||
if self.is_disabled():
|
||||
logging.info(f"Enabling project '{self.get_name()}'")
|
||||
os.rename(self.down_dir_name(), self.dir_name())
|
||||
os.rename(self.dir_name(), self.enabled_dir_name())
|
||||
|
||||
elif self.is_enabled():
|
||||
logging.warning(f"Project '{self.get_name()}' is enabled!")
|
||||
|
@ -87,7 +66,7 @@ class Project:
|
|||
def disable(self):
|
||||
if self.is_enabled():
|
||||
logging.info(f"Disabling project '{self.get_name()}'")
|
||||
os.rename(self.dir_name(), self.down_dir_name())
|
||||
os.rename(self.dir_name(), self.disabled_dir_name())
|
||||
|
||||
elif self.is_disabled():
|
||||
logging.warning(f"Project '{self.get_name()}' is disabled!")
|
||||
|
@ -96,4 +75,53 @@ class Project:
|
|||
logging.warning(f"Project '{self.get_name()}' not found in instance!")
|
||||
return False
|
||||
|
||||
return True
|
||||
return True
|
||||
|
||||
|
||||
def _extract_project_name(file_name):
|
||||
config = LoadedConfig.get()
|
||||
enabled_suffix = config['markers:project']
|
||||
disabled_suffix = f"{enabled_suffix}{config['markers:down']}"
|
||||
|
||||
if os.path.isdir(file_name):
|
||||
# all subdirectories
|
||||
if file_name.endswith(enabled_suffix):
|
||||
# enabled projects
|
||||
return file_name[:-len(enabled_suffix)]
|
||||
|
||||
elif file_name.endswith(disabled_suffix):
|
||||
# disabled projects
|
||||
return file_name[:-len(disabled_suffix)]
|
||||
|
||||
return None
|
||||
|
||||
|
||||
class Projects:
|
||||
__projects = None
|
||||
|
||||
def __init__(self, names):
|
||||
self.__projects = [
|
||||
Project(name)
|
||||
for name in names if isinstance(name, str)
|
||||
]
|
||||
|
||||
def __getitem__(self, item):
|
||||
return self.__projects[item]
|
||||
|
||||
@classmethod
|
||||
def all(cls):
|
||||
return cls([
|
||||
_extract_project_name(file_name)
|
||||
for file_name in os.listdir()
|
||||
])
|
||||
|
||||
@classmethod
|
||||
def from_args(cls, args):
|
||||
if args is not None and 'projects' in args:
|
||||
if isinstance(args.projects, list) and args.projects:
|
||||
return cls(args.projects)
|
||||
|
||||
elif isinstance(args.projects, str):
|
||||
return cls([args.projects])
|
||||
|
||||
return []
|
||||
|
|
Loading…
Reference in a new issue