From dac3d9c6bbc7fb9f3433f28431d09f1367007884 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Fri, 20 May 2022 10:27:55 +0200 Subject: [PATCH] Added validators (closes #59) --- src/cpl_cli/startup_argument_extension.py | 42 +++++++++---------- src/cpl_cli/validators/__init__.py | 25 +++++++++++ src/cpl_cli/validators/project_validator.py | 18 ++++++++ src/cpl_cli/validators/workspace_validator.py | 17 ++++++++ src/cpl_core/configuration/configuration.py | 15 ++++++- .../configuration/executable_argument.py | 11 ++++- src/cpl_core/configuration/flag_argument.py | 3 +- src/cpl_core/configuration/validator_abc.py | 10 +++++ .../configuration/variable_argument.py | 3 +- 9 files changed, 119 insertions(+), 25 deletions(-) create mode 100644 src/cpl_cli/validators/__init__.py create mode 100644 src/cpl_cli/validators/project_validator.py create mode 100644 src/cpl_cli/validators/workspace_validator.py create mode 100644 src/cpl_core/configuration/validator_abc.py diff --git a/src/cpl_cli/startup_argument_extension.py b/src/cpl_cli/startup_argument_extension.py index d6ef1e7c..a9de79f2 100644 --- a/src/cpl_cli/startup_argument_extension.py +++ b/src/cpl_cli/startup_argument_extension.py @@ -1,7 +1,6 @@ import os from typing import Optional -from cpl_cli import CommandABC from cpl_cli.command.add_service import AddService from cpl_cli.command.build_service import BuildService from cpl_cli.command.custom_script_service import CustomScriptService @@ -16,6 +15,8 @@ from cpl_cli.command.uninstall_service import UninstallService from cpl_cli.command.update_service import UpdateService from cpl_cli.command.version_service import VersionService from cpl_cli.configuration.workspace_settings import WorkspaceSettings +from cpl_cli.validators.project_validator import ProjectValidator +from cpl_cli.validators.workspace_validator import WorkspaceValidator from cpl_core.application import StartupExtensionABC from cpl_core.configuration.argument_type_enum import ArgumentTypeEnum from cpl_core.configuration.configuration_abc import ConfigurationABC @@ -37,9 +38,7 @@ class StartupArgumentExtension(StartupExtensionABC): for file in f: if file.endswith('.json'): f_name = file.split('.json')[0] - if f_name == name or \ - String.convert_to_camel_case(f_name).lower() == String.convert_to_camel_case( - name).lower(): + if f_name == name or String.convert_to_camel_case(f_name).lower() == String.convert_to_camel_case(name).lower(): project_name = f_name break @@ -62,7 +61,7 @@ class StartupArgumentExtension(StartupExtensionABC): config.create_console_argument(ArgumentTypeEnum.Executable, '', 'add', ['a', 'A'], AddService, True) \ .add_console_argument(ArgumentTypeEnum.Flag, '--', 'simulate', ['s', 'S']) - config.create_console_argument(ArgumentTypeEnum.Executable, '', 'build', ['b', 'B'], BuildService, True) + config.create_console_argument(ArgumentTypeEnum.Executable, '', 'build', ['b', 'B'], BuildService, True, validators=[ProjectValidator]) config.create_console_argument(ArgumentTypeEnum.Executable, '', 'generate', ['g', 'G'], GenerateService, True) \ .add_console_argument(ArgumentTypeEnum.Variable, '', 'abc', ['a', 'A'], ' ') \ .add_console_argument(ArgumentTypeEnum.Variable, '', 'class', ['c', 'C'], ' ') \ @@ -87,24 +86,25 @@ class StartupArgumentExtension(StartupExtensionABC): .add_console_argument(ArgumentTypeEnum.Flag, '--', 'simulate', ['s', 'S']) config.create_console_argument(ArgumentTypeEnum.Executable, '', 'version', ['v', 'V'], VersionService, True) - config.for_each_argument( - lambda a: a.add_console_argument(ArgumentTypeEnum.Flag, '--', 'help', ['h', 'H']) - ) + config.for_each_argument(lambda a: a.add_console_argument(ArgumentTypeEnum.Flag, '--', 'help', ['h', 'H'])) config.create_console_argument(ArgumentTypeEnum.Executable, '', 'help', ['h', 'H'], HelpService) self._read_cpl_environment(config, env) def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC): - services.add_transient(CommandABC, AddService) - services.add_transient(CommandABC, BuildService) - services.add_transient(CommandABC, CustomScriptService) - services.add_transient(CommandABC, GenerateService) - services.add_transient(CommandABC, HelpService) - services.add_transient(CommandABC, InstallService) - services.add_transient(CommandABC, NewService) - services.add_transient(CommandABC, PublishService) - services.add_transient(CommandABC, RemoveService) - services.add_transient(CommandABC, StartService) - services.add_transient(CommandABC, UninstallService) - services.add_transient(CommandABC, UpdateService) - services.add_transient(CommandABC, VersionService) + services.add_transient(WorkspaceValidator) + services.add_transient(ProjectValidator) + + services.add_transient(AddService) + services.add_transient(BuildService) + services.add_transient(CustomScriptService) + services.add_transient(GenerateService) + services.add_transient(HelpService) + services.add_transient(InstallService) + services.add_transient(NewService) + services.add_transient(PublishService) + services.add_transient(RemoveService) + services.add_transient(StartService) + services.add_transient(UninstallService) + services.add_transient(UpdateService) + services.add_transient(VersionService) diff --git a/src/cpl_cli/validators/__init__.py b/src/cpl_cli/validators/__init__.py new file mode 100644 index 00000000..b6cfae8f --- /dev/null +++ b/src/cpl_cli/validators/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- + +""" +cpl-cli sh-edraft Common Python library CLI +~~~~~~~~~~~~~~~~~~~ + +sh-edraft Common Python library Command Line Interface + +:copyright: (c) 2020 - 2022 sh-edraft.de +:license: MIT, see LICENSE for more details. + +""" + +__title__ = 'cpl_cli.validators' +__author__ = 'Sven Heidemann' +__license__ = 'MIT' +__copyright__ = 'Copyright (c) 2020 - 2022 sh-edraft.de' +__version__ = '2022.6.3.dev6' + +from collections import namedtuple + +# imports: + +VersionInfo = namedtuple('VersionInfo', 'major minor micro') +version_info = VersionInfo(major='2022', minor='6', micro='3.dev6') diff --git a/src/cpl_cli/validators/project_validator.py b/src/cpl_cli/validators/project_validator.py new file mode 100644 index 00000000..4f21d0e2 --- /dev/null +++ b/src/cpl_cli/validators/project_validator.py @@ -0,0 +1,18 @@ +from cpl_cli import Error +from cpl_cli.configuration import WorkspaceSettings, ProjectSettings +from cpl_core.configuration.validator_abc import ValidatorABC + + +class ProjectValidator(ValidatorABC): + + def __init__(self, workspace: WorkspaceSettings, project: ProjectSettings): + self._workspace = workspace + self._project = project + + ValidatorABC.__init__(self) + + def validate(self) -> bool: + result = self._project is not None or self._workspace is not None + if not result: + Error.error('The command requires to be run in an CPL project, but a project could not be found.') + return result diff --git a/src/cpl_cli/validators/workspace_validator.py b/src/cpl_cli/validators/workspace_validator.py new file mode 100644 index 00000000..d8c50033 --- /dev/null +++ b/src/cpl_cli/validators/workspace_validator.py @@ -0,0 +1,17 @@ +from cpl_cli import Error +from cpl_cli.configuration import WorkspaceSettings +from cpl_core.configuration.validator_abc import ValidatorABC + + +class WorkspaceValidator(ValidatorABC): + + def __init__(self, workspace: WorkspaceSettings): + self._workspace = workspace + + ValidatorABC.__init__(self) + + def validate(self) -> bool: + result = self._workspace is not None + if not result: + Error.error('The command requires to be run in an CPL workspace, but a workspace could not be found.') + return result diff --git a/src/cpl_core/configuration/configuration.py b/src/cpl_core/configuration/configuration.py index a7d08c07..96966d18 100644 --- a/src/cpl_core/configuration/configuration.py +++ b/src/cpl_core/configuration/configuration.py @@ -13,6 +13,7 @@ from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC from cpl_core.configuration.configuration_variable_name_enum import ConfigurationVariableNameEnum from cpl_core.configuration.executable_argument import ExecutableArgument from cpl_core.configuration.flag_argument import FlagArgument +from cpl_core.configuration.validator_abc import ValidatorABC from cpl_core.configuration.variable_argument import VariableArgument from cpl_core.console.console import Console from cpl_core.console.foreground_color_enum import ForegroundColorEnum @@ -245,7 +246,7 @@ class Configuration(ConfigurationABC): def create_console_argument(self, arg_type: ArgumentTypeEnum, token: str, name: str, aliases: list[str], *args, **kwargs) -> ArgumentABC: - argument = ArgumentBuilder.build_argument(arg_type, token, name, aliases, *args, *kwargs) + argument = ArgumentBuilder.build_argument(arg_type, token, name, aliases, *args, **kwargs) self._argument_types.append(argument) return argument @@ -285,6 +286,18 @@ class Configuration(ConfigurationABC): for exe in executables: if prevent: continue + + abort = False + for validator_type in exe.validators: + validator: ValidatorABC = services.get_service(validator_type) + result = validator.validate() + abort = not result + if abort: + break + + if abort: + continue + cmd: CommandABC = services.get_service(exe.executable_type) self.add_configuration('ACTIVE_EXECUTABLE', exe.name) cmd.execute(self._additional_arguments) diff --git a/src/cpl_core/configuration/executable_argument.py b/src/cpl_core/configuration/executable_argument.py index a9d512d4..fd061a8e 100644 --- a/src/cpl_core/configuration/executable_argument.py +++ b/src/cpl_core/configuration/executable_argument.py @@ -2,6 +2,8 @@ from typing import Type, Optional from cpl_core.configuration.argument_executable_abc import ArgumentExecutableABC from cpl_core.configuration.argument_abc import ArgumentABC +from cpl_core.configuration.validator_abc import ValidatorABC +from cpl_core.console import Console class ExecutableArgument(ArgumentABC): @@ -11,13 +13,16 @@ class ExecutableArgument(ArgumentABC): name: str, aliases: list[str], executable: Type[ArgumentExecutableABC], + prevent_next_executable: bool = False, + validators: list[Type[ValidatorABC]] = None, console_arguments: list['ArgumentABC'] = None ): self._executable_type = executable + self._validators = validators self._executable: Optional[ArgumentExecutableABC] = None - ArgumentABC.__init__(self, token, name, aliases, console_arguments) + ArgumentABC.__init__(self, token, name, aliases, prevent_next_executable, console_arguments) @property def executable_type(self) -> type: @@ -26,6 +31,10 @@ class ExecutableArgument(ArgumentABC): def set_executable(self, executable: ArgumentExecutableABC): self._executable = executable + @property + def validators(self) -> list[Type[ValidatorABC]]: + return self._validators + def run(self, args: list[str]): r"""Executes runnable if exists """ diff --git a/src/cpl_core/configuration/flag_argument.py b/src/cpl_core/configuration/flag_argument.py index 0d57af2a..c22c5689 100644 --- a/src/cpl_core/configuration/flag_argument.py +++ b/src/cpl_core/configuration/flag_argument.py @@ -7,7 +7,8 @@ class FlagArgument(ArgumentABC): token: str, name: str, aliases: list[str], + prevent_next_executable: bool = False, console_arguments: list['ArgumentABC'] = None ): - ArgumentABC.__init__(self, token, name, aliases, console_arguments) + ArgumentABC.__init__(self, token, name, aliases, prevent_next_executable, console_arguments) diff --git a/src/cpl_core/configuration/validator_abc.py b/src/cpl_core/configuration/validator_abc.py new file mode 100644 index 00000000..a79e8621 --- /dev/null +++ b/src/cpl_core/configuration/validator_abc.py @@ -0,0 +1,10 @@ +from abc import ABC, abstractmethod + + +class ValidatorABC(ABC): + + @abstractmethod + def __init__(self): pass + + @abstractmethod + def validate(self) -> bool: pass diff --git a/src/cpl_core/configuration/variable_argument.py b/src/cpl_core/configuration/variable_argument.py index bcf7b0cc..1f8597e5 100644 --- a/src/cpl_core/configuration/variable_argument.py +++ b/src/cpl_core/configuration/variable_argument.py @@ -8,12 +8,13 @@ class VariableArgument(ArgumentABC): name: str, aliases: list[str], value_token: str, + prevent_next_executable: bool = False, console_arguments: list['ArgumentABC'] = None ): self._value_token = value_token self._value: str = '' - ArgumentABC.__init__(self, token, name, aliases, console_arguments) + ArgumentABC.__init__(self, token, name, aliases, prevent_next_executable, console_arguments) @property def value_token(self) -> str: