diff --git a/src/cpl_cli/cli.py b/src/cpl_cli/cli.py index 3a11e4e7..0f03eac6 100644 --- a/src/cpl_cli/cli.py +++ b/src/cpl_cli/cli.py @@ -1,28 +1,10 @@ -import os import sys -from typing import Optional +import traceback from cpl_core.application.application_abc import ApplicationABC from cpl_core.configuration.configuration_abc import ConfigurationABC from cpl_core.console.console import Console from cpl_core.dependency_injection import ServiceProviderABC -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 -from cpl_cli.command.generate_service import GenerateService -from cpl_cli.command.install_service import InstallService -from cpl_cli.command.new_service import NewService -from cpl_cli.command.publish_service import PublishService -from cpl_cli.command.remove_service import RemoveService -from cpl_cli.command.start_service import StartService -from cpl_cli.command.uninstall_service import UninstallService -from cpl_cli.command.update_service import UpdateService -from cpl_cli.command_handler_service import CommandHandler -from cpl_cli.command_model import CommandModel -from cpl_cli.configuration.workspace_settings import WorkspaceSettings -from cpl_cli.error import Error -from cpl_cli.command.help_service import HelpService -from cpl_cli.command.version_service import VersionService class CLI(ApplicationABC): @@ -33,33 +15,10 @@ class CLI(ApplicationABC): """ ApplicationABC.__init__(self, config, services) - # self._command_handler: Optional[CommandHandler] = None self._options: list[str] = [] def configure(self): pass - # self._command_handler: CommandHandler = self._services.get_service(CommandHandler) - # - # self._command_handler.add_command(CommandModel('add', ['a', 'a'], AddService, False, False, False)) - # self._command_handler.add_command(CommandModel('build', ['b', 'B'], BuildService, False, True, True)) - # self._command_handler.add_command(CommandModel('generate', ['g', 'G'], GenerateService, False, True, False)) - # self._command_handler.add_command(CommandModel('help', ['h', 'H'], HelpService, False, False, False)) - # self._command_handler.add_command(CommandModel('install', ['i', 'I'], InstallService, False, True, True)) - # self._command_handler.add_command(CommandModel('new', ['n', 'N'], NewService, False, False, True)) - # self._command_handler.add_command(CommandModel('publish', ['p', 'P'], PublishService, False, True, True)) - # self._command_handler.add_command(CommandModel('remove', ['r', 'R'], RemoveService, True, True, False)) - # self._command_handler.add_command(CommandModel('start', ['s', 'S'], StartService, False, True, True)) - # self._command_handler.add_command(CommandModel('uninstall', ['ui', 'UI'], UninstallService, False, True, True)) - # self._command_handler.add_command(CommandModel('update', ['u', 'U'], UpdateService, False, True, True)) - # self._command_handler.add_command(CommandModel('version', ['v', 'V'], VersionService, False, False, False)) - # - # if os.path.isfile(os.path.join(self._environment.working_directory, 'cpl-workspace.json')): - # workspace: Optional[WorkspaceSettings] = self._configuration.get_configuration(WorkspaceSettings) - # for script in workspace.scripts: - # self._command_handler.add_command(CommandModel(script, [], CustomScriptService, True, True, False)) - # - # self._command_handler.add_command(CommandModel('--help', ['-h', '-H'], HelpService, False, False, False)) - # self._options.append('--help') def main(self): """ @@ -67,62 +26,10 @@ class CLI(ApplicationABC): :return: """ try: - pass - # command = None - # args = [] - # if len(self._configuration.additional_arguments) > 0: - # is_option = False - # for opt in self._options: - # if opt in self._configuration.additional_arguments: - # is_option = True - # command = opt - # args = self._configuration.additional_arguments - # args.remove(opt) - # - # if not is_option: - # command = self._configuration.additional_arguments[0] - # if len(self._configuration.additional_arguments) > 1: - # args = self._configuration.additional_arguments[1:] - # else: - # for cmd in self._command_handler.commands: - # result = self._configuration.get_configuration(cmd.name) - # result_args: list[str] = self._configuration.get_configuration(f'{cmd.name}AdditionalArguments') - # is_option = False - # if result is None: - # continue - # - # for opt in self._options: - # if opt == result: - # is_option = True - # command = opt - # - # elif result_args is not None and opt in result_args: - # is_option = True - # command = opt - # result_args.remove(opt) - # - # if is_option: - # args.append(cmd.name) - # if result_args is not None: - # for arg in result_args: - # args.append(arg) - # - # elif result is not None: - # command = cmd.name - # args.append(result) - # - # for arg in result_args: - # args.append(arg) - # - # else: - # Error.error(f'Unexpected command') - # return - # - # if command is None: - # Error.error(f'Expected command') - # return - # - # self._command_handler.handle(command, args) + self._configuration.parse_console_arguments() except KeyboardInterrupt: Console.write_line() sys.exit() + except Exception as e: + Console.error(str(e), traceback.format_exc()) + sys.exit() diff --git a/src/cpl_cli/command/add_service.py b/src/cpl_cli/command/add_service.py index 4cbc4133..3f127bb4 100644 --- a/src/cpl_cli/command/add_service.py +++ b/src/cpl_cli/command/add_service.py @@ -23,6 +23,7 @@ class AddService(CommandABC): self._config = config self._workspace = workspace + self._is_simulation = False @property def help_message(self) -> str: @@ -35,8 +36,9 @@ class AddService(CommandABC): target-project: Name of the project to be referenced """) - @staticmethod - def _edit_project_file(source: str, project_settings: ProjectSettings, build_settings: BuildSettings): + def _edit_project_file(self, source: str, project_settings: ProjectSettings, build_settings: BuildSettings): + if self._is_simulation: + return with open(source, 'w') as file: file.write(json.dumps({ ProjectSettings.__name__: SettingsHelper.get_project_settings_dict(project_settings), @@ -50,6 +52,11 @@ class AddService(CommandABC): :param args: :return: """ + if 'simulate' in args: + args.remove('simulate') + Console.write_line('Simulating:') + self._is_simulation = True + if len(args) == 0: Console.error('Expected source and target project') return @@ -59,7 +66,7 @@ class AddService(CommandABC): return elif len(args) > 2: - Console.error(f'Unexpected argument: {" ".join(args[2:])}') + Console.error(f'Unexpected argument(s): {", ".join(args[2:])}') return # file names diff --git a/src/cpl_cli/command/help_service.py b/src/cpl_cli/command/help_service.py index 0d857ed8..4088ab54 100644 --- a/src/cpl_cli/command/help_service.py +++ b/src/cpl_cli/command/help_service.py @@ -4,20 +4,18 @@ from typing import Optional from cpl_core.console.console import Console from cpl_core.console.foreground_color_enum import ForegroundColorEnum from cpl_core.dependency_injection.service_provider_abc import ServiceProviderABC -from cpl_cli.command_handler_service import CommandHandler from cpl_cli.command_abc import CommandABC class HelpService(CommandABC): - def __init__(self, services: ServiceProviderABC, cmd_handler: CommandHandler): + def __init__(self, services: ServiceProviderABC): """ Service for CLI command help """ CommandABC.__init__(self) self._services = services - self._commands = cmd_handler.commands @property def help_message(self) -> str: @@ -35,20 +33,20 @@ class HelpService(CommandABC): :param args: :return: """ - if len(args) > 0: - command_name = args[0] - command: Optional[CommandABC] = None - for cmd in self._commands: - if cmd.name == command_name or command_name in cmd.aliases: - command = self._services.get_service(cmd.command) - - if command is None: - Console.error(f'Invalid argument: {command_name}') - return - - Console.write_line(command.help_message) - - return + # if len(args) > 0: + # command_name = args[0] + # command: Optional[CommandABC] = None + # for cmd in self._commands: + # if cmd.name == command_name or command_name in cmd.aliases: + # command = self._services.get_service(cmd.command) + # + # if command is None: + # Console.error(f'Invalid argument: {command_name}') + # return + # + # Console.write_line(command.help_message) + # + # return Console.write_line('Available Commands:') commands = [ diff --git a/src/cpl_cli/command/remove_service.py b/src/cpl_cli/command/remove_service.py index b148e7b4..b40a23df 100644 --- a/src/cpl_cli/command/remove_service.py +++ b/src/cpl_cli/command/remove_service.py @@ -25,6 +25,7 @@ class RemoveService(CommandABC): self._env = env self._workspace: WorkspaceSettings = self._config.get_configuration(WorkspaceSettings) + self._is_simulation = False @property def help_message(self) -> str: @@ -36,8 +37,10 @@ class RemoveService(CommandABC): project The name of the project to delete """) - @staticmethod - def _create_file(file_name: str, content: dict): + def _create_file(self, file_name: str, content: dict): + if self._is_simulation: + return + if not os.path.isabs(file_name): file_name = os.path.abspath(file_name) @@ -70,6 +73,11 @@ class RemoveService(CommandABC): :param args: :return: """ + if 'simulate' in args: + args.remove('simulate') + Console.write_line('Simulating:') + self._is_simulation = True + project_name = args[0] if project_name not in self._workspace.projects: Console.error(f'Project {project_name} not found in workspace.') diff --git a/src/cpl_cli/cpl_cli.json b/src/cpl_cli/cpl_cli.json index 0f5f58c7..e895b319 100644 --- a/src/cpl_cli/cpl_cli.json +++ b/src/cpl_cli/cpl_cli.json @@ -42,8 +42,6 @@ "*.json" ] }, - "ProjectReferences": [ - "../cpl_core/cpl_core.json" - ] + "ProjectReferences": [] } } \ No newline at end of file diff --git a/src/cpl_cli/main.py b/src/cpl_cli/main.py index b96f89b6..192a18ae 100644 --- a/src/cpl_cli/main.py +++ b/src/cpl_cli/main.py @@ -1,3 +1,4 @@ +from cpl_cli.startup_argument_extension import StartupArgumentExtension from cpl_core.application.application_builder import ApplicationBuilder from cpl_cli.cli import CLI from cpl_cli.startup import Startup @@ -6,6 +7,7 @@ from cpl_cli.startup import Startup def main(): app_builder = ApplicationBuilder(CLI) app_builder.use_startup(Startup) + app_builder.use_extension(StartupArgumentExtension) app_builder.build().run() diff --git a/src/cpl_cli/startup.py b/src/cpl_cli/startup.py index de9692a5..cfae7fc6 100644 --- a/src/cpl_cli/startup.py +++ b/src/cpl_cli/startup.py @@ -1,16 +1,10 @@ import os -from typing import Optional -from cpl_core.application.startup_abc import StartupABC -from cpl_core.configuration.argument_type_enum import ArgumentTypeEnum -from cpl_core.configuration.configuration_abc import ConfigurationABC -from cpl_core.console import Console -from cpl_core.dependency_injection.service_collection_abc import ServiceCollectionABC -from cpl_core.dependency_injection.service_provider_abc import ServiceProviderABC 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 from cpl_cli.command.generate_service import GenerateService +from cpl_cli.command.help_service import HelpService from cpl_cli.command.install_service import InstallService from cpl_cli.command.new_service import NewService from cpl_cli.command.publish_service import PublishService @@ -18,14 +12,15 @@ from cpl_cli.command.remove_service import RemoveService from cpl_cli.command.start_service import StartService from cpl_cli.command.uninstall_service import UninstallService from cpl_cli.command.update_service import UpdateService -from cpl_cli.command_handler_service import CommandHandler -from cpl_cli.command.help_service import HelpService from cpl_cli.command.version_service import VersionService -from cpl_cli.configuration.workspace_settings import WorkspaceSettings from cpl_cli.error import Error from cpl_cli.live_server.live_server_service import LiveServerService -from cpl_cli.publish.publisher_service import PublisherService from cpl_cli.publish.publisher_abc import PublisherABC +from cpl_cli.publish.publisher_service import PublisherService +from cpl_core.application.startup_abc import StartupABC +from cpl_core.configuration.configuration_abc import ConfigurationABC +from cpl_core.dependency_injection.service_collection_abc import ServiceCollectionABC +from cpl_core.dependency_injection.service_provider_abc import ServiceProviderABC from cpl_core.environment import ApplicationEnvironment @@ -41,49 +36,10 @@ class Startup(StartupABC): configuration.add_environment_variables('PYTHON_') configuration.add_environment_variables('CPL_') configuration.add_json_file('appsettings.json', path=environment.runtime_directory, optional=False, output=False) - configuration.add_json_file('cpl-workspace.json', path=environment.working_directory, optional=True, output=False) - - configuration.create_console_argument(ArgumentTypeEnum.Executable, '', 'add', ['a', 'A'], AddService) \ - .add_console_argument(ArgumentTypeEnum.Flag, '--', 'simulate', ['s', 'S']) - configuration.create_console_argument(ArgumentTypeEnum.Executable, '', 'build', ['b', 'B'], BuildService) - configuration.create_console_argument(ArgumentTypeEnum.Executable, '', 'generate', ['g', 'G'], GenerateService) \ - .add_console_argument(ArgumentTypeEnum.Variable, '', 'abc', ['a', 'A'], ' ') \ - .add_console_argument(ArgumentTypeEnum.Variable, '', 'class', ['c', 'C'], ' ') \ - .add_console_argument(ArgumentTypeEnum.Variable, '', 'enum', ['e', 'E'], ' ') \ - .add_console_argument(ArgumentTypeEnum.Variable, '', 'service', ['s', 'S'], ' ') \ - .add_console_argument(ArgumentTypeEnum.Variable, '', 'settings', ['st', 'ST'], ' ') \ - .add_console_argument(ArgumentTypeEnum.Variable, '', 'thread', ['t', 't'], ' ') - configuration.create_console_argument(ArgumentTypeEnum.Executable, '', 'install', ['i', 'I'], InstallService) \ - .add_console_argument(ArgumentTypeEnum.Flag, '--', 'virtual', ['v', 'V']) \ - .add_console_argument(ArgumentTypeEnum.Flag, '--', 'simulate', ['s', 'S']) - configuration.create_console_argument(ArgumentTypeEnum.Executable, '', 'new', ['n', 'N'], NewService) \ - .add_console_argument(ArgumentTypeEnum.Variable, '', 'console', ['c', 'C'], ' ') \ - .add_console_argument(ArgumentTypeEnum.Variable, '', 'library', ['l', 'L'], ' ') - configuration.create_console_argument(ArgumentTypeEnum.Executable, '', 'publish', ['p', 'P'], PublishService) - configuration.create_console_argument(ArgumentTypeEnum.Executable, '', 'remove', ['r', 'R'], RemoveService) \ - .add_console_argument(ArgumentTypeEnum.Flag, '--', 'simulate', ['s', 'S']) - configuration.create_console_argument(ArgumentTypeEnum.Executable, '', 'start', ['S', 'S'], StartService) - configuration.create_console_argument(ArgumentTypeEnum.Executable, '', 'uninstall', ['ui', 'UI'], UninstallService) \ - .add_console_argument(ArgumentTypeEnum.Flag, '--', 'virtual', ['v', 'V']) \ - .add_console_argument(ArgumentTypeEnum.Flag, '--', 'simulate', ['s', 'S']) - configuration.create_console_argument(ArgumentTypeEnum.Executable, '', 'update', ['u', 'U'], UpdateService) - configuration.create_console_argument(ArgumentTypeEnum.Executable, '', 'version', ['v', 'V'], VersionService) - - configuration.for_each_argument( - lambda a: a.add_console_argument(ArgumentTypeEnum.Executable, '--', 'help', ['h', 'H'], HelpService) - ) - configuration.create_console_argument(ArgumentTypeEnum.Executable, '', 'help', ['h', 'H'], HelpService) - - workspace: Optional[WorkspaceSettings] = configuration.get_configuration(WorkspaceSettings) - if workspace is not None: - for script in workspace.scripts: - configuration.create_console_argument(ArgumentTypeEnum.Executable, '', script, [], CustomScriptService) return configuration def configure_services(self, services: ServiceCollectionABC, environment: ApplicationEnvironment) -> ServiceProviderABC: - # services.add_singleton(CommandHandler) - services.add_transient(PublisherABC, PublisherService) services.add_transient(LiveServerService) diff --git a/src/cpl_cli/startup_argument_extension.py b/src/cpl_cli/startup_argument_extension.py new file mode 100644 index 00000000..6e2db944 --- /dev/null +++ b/src/cpl_cli/startup_argument_extension.py @@ -0,0 +1,97 @@ +import os +from typing import Optional + +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 +from cpl_cli.command.generate_service import GenerateService +from cpl_cli.command.help_service import HelpService +from cpl_cli.command.install_service import InstallService +from cpl_cli.command.new_service import NewService +from cpl_cli.command.publish_service import PublishService +from cpl_cli.command.remove_service import RemoveService +from cpl_cli.command.start_service import StartService +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_core.application import StartupExtensionABC +from cpl_core.configuration.argument_type_enum import ArgumentTypeEnum +from cpl_core.configuration.configuration_abc import ConfigurationABC +from cpl_core.console import Console +from cpl_core.dependency_injection.service_collection_abc import ServiceCollectionABC +from cpl_core.environment import ApplicationEnvironmentABC +from cpl_core.utils import String + + +class StartupArgumentExtension(StartupExtensionABC): + + def __init__(self): + pass + + @staticmethod + def _search_project_json(env: ApplicationEnvironmentABC) -> Optional[str]: + project_name = None + name = os.path.basename(env.working_directory) + for r, d, f in os.walk(env.working_directory): + 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(): + project_name = f_name + break + + return project_name + + def _read_cpl_environment(self, config: ConfigurationABC, env: ApplicationEnvironmentABC): + workspace: Optional[WorkspaceSettings] = config.get_configuration(WorkspaceSettings) + if workspace is not None: + for script in workspace.scripts: + config.create_console_argument(ArgumentTypeEnum.Executable, '', script, [], CustomScriptService) + + project = workspace.projects[workspace.default_project] + else: + project = f'{self._search_project_json(env)}.json' + + config.add_json_file(project, optional=True, output=False) + + def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC): + config.add_json_file('cpl-workspace.json', path=env.working_directory, optional=True, output=False) + + config.create_console_argument(ArgumentTypeEnum.Executable, '', 'add', ['a', 'A'], AddService) \ + .add_console_argument(ArgumentTypeEnum.Flag, '--', 'simulate', ['s', 'S']) + config.create_console_argument(ArgumentTypeEnum.Executable, '', 'build', ['b', 'B'], BuildService) + config.create_console_argument(ArgumentTypeEnum.Executable, '', 'generate', ['g', 'G'], GenerateService) \ + .add_console_argument(ArgumentTypeEnum.Variable, '', 'abc', ['a', 'A'], ' ') \ + .add_console_argument(ArgumentTypeEnum.Variable, '', 'class', ['c', 'C'], ' ') \ + .add_console_argument(ArgumentTypeEnum.Variable, '', 'enum', ['e', 'E'], ' ') \ + .add_console_argument(ArgumentTypeEnum.Variable, '', 'service', ['s', 'S'], ' ') \ + .add_console_argument(ArgumentTypeEnum.Variable, '', 'settings', ['st', 'ST'], ' ') \ + .add_console_argument(ArgumentTypeEnum.Variable, '', 'thread', ['t', 't'], ' ') + config.create_console_argument(ArgumentTypeEnum.Executable, '', 'install', ['i', 'I'], InstallService) \ + .add_console_argument(ArgumentTypeEnum.Flag, '--', 'virtual', ['v', 'V']) \ + .add_console_argument(ArgumentTypeEnum.Flag, '--', 'simulate', ['s', 'S']) + config.create_console_argument(ArgumentTypeEnum.Executable, '', 'new', ['n', 'N'], NewService) \ + .add_console_argument(ArgumentTypeEnum.Variable, '', 'console', ['c', 'C'], ' ') \ + .add_console_argument(ArgumentTypeEnum.Variable, '', 'library', ['l', 'L'], ' ') + config.create_console_argument(ArgumentTypeEnum.Executable, '', 'publish', ['p', 'P'], PublishService) + config.create_console_argument(ArgumentTypeEnum.Executable, '', 'remove', ['r', 'R'], RemoveService) \ + .add_console_argument(ArgumentTypeEnum.Flag, '--', 'simulate', ['s', 'S']) + config.create_console_argument(ArgumentTypeEnum.Executable, '', 'start', ['S', 'S'], StartService) + config.create_console_argument(ArgumentTypeEnum.Executable, '', 'uninstall', ['ui', 'UI'], UninstallService) \ + .add_console_argument(ArgumentTypeEnum.Flag, '--', 'virtual', ['v', 'V']) \ + .add_console_argument(ArgumentTypeEnum.Flag, '--', 'simulate', ['s', 'S']) + config.create_console_argument(ArgumentTypeEnum.Executable, '', 'update', ['u', 'U'], UpdateService) + config.create_console_argument(ArgumentTypeEnum.Executable, '', 'version', ['v', 'V'], VersionService) + + config.for_each_argument( + lambda a: a.add_console_argument(ArgumentTypeEnum.Executable, '--', 'help', ['h', 'H'], HelpService) + ) + config.create_console_argument(ArgumentTypeEnum.Executable, '', 'help', ['h', 'H'], HelpService) + + self._read_cpl_environment(config, env) + + def configure_services(self, service: ServiceCollectionABC, env: ApplicationEnvironmentABC): + pass diff --git a/src/cpl_core/application/application_builder.py b/src/cpl_core/application/application_builder.py index e81f7f04..c879ae69 100644 --- a/src/cpl_core/application/application_builder.py +++ b/src/cpl_core/application/application_builder.py @@ -55,7 +55,6 @@ class ApplicationBuilder(ApplicationBuilderABC): config = self._configuration services = self._services.build_service_provider() config.resolve_runnable_argument_types(services) - config.parse_console_arguments() for ex in self._app_extensions: extension = ex() diff --git a/src/cpl_core/configuration/configuration.py b/src/cpl_core/configuration/configuration.py index 2047b145..fc33dd3f 100644 --- a/src/cpl_core/configuration/configuration.py +++ b/src/cpl_core/configuration/configuration.py @@ -150,7 +150,8 @@ class Configuration(ConfigurationABC): def _parse_arguments(self, call_stack: list[Callable], arg_list: list[str], args_types: list[ArgumentABC]): for i in range(0, len(arg_list)): arg_str = arg_list[i] - for arg in args_types: + for n in range(0, len(args_types)): + arg = args_types[n] arg_str_without_token = arg_str if arg.token != "" and arg.token in arg_str: arg_str_without_token = arg_str.split(arg.token)[1] @@ -160,8 +161,8 @@ class Configuration(ConfigurationABC): if arg_str.startswith(arg.token) \ and arg_str_without_token == arg.name or arg_str_without_token in arg.aliases: call_stack.append(arg.run) + self._handled_args.append(arg_str) self._parse_arguments(call_stack, arg_list[i + 1:], arg.console_arguments) - break # variables elif isinstance(arg, VariableArgument): @@ -176,20 +177,20 @@ class Configuration(ConfigurationABC): else: value = arg_list[i + 1] self._set_variable(arg.name, value) + self._handled_args.append(arg_str) self._parse_arguments(call_stack, arg_list[i + 1:], arg.console_arguments) - break # flags elif isinstance(arg, FlagArgument): if arg_str.startswith(arg.token) \ and arg_str_without_token == arg.name or arg_str_without_token in arg.aliases: self._additional_arguments.append(arg.name) + self._handled_args.append(arg_str) self._parse_arguments(call_stack, arg_list[i + 1:], arg.console_arguments) - break - # add left over values to args - if arg_str not in self._additional_arguments: - self._additional_arguments.append(arg_str) + # add left over values to args + if arg_str not in self._additional_arguments and arg_str not in self._handled_args: + self._additional_arguments.append(arg_str) def add_environment_variables(self, prefix: str): for variable in ConfigurationVariableNameEnum.to_list():