Improved command handling

This commit is contained in:
Sven Heidemann 2021-03-04 19:06:53 +01:00
parent 2c43e55f77
commit 700bf9c937
17 changed files with 197 additions and 19 deletions

View File

@ -1,11 +1,14 @@
from typing import Optional from typing import Optional
from cpl.application.application_abc import ApplicationABC from cpl.application.application_abc import ApplicationABC
from cpl_cli.command import Command from cpl.console.console import Console
from cpl_cli.command.build import Build
from cpl_cli.command_handler import CommandHandler from cpl_cli.command_handler import CommandHandler
from cpl_cli.command_model import CommandModel
from cpl_cli.error import Error from cpl_cli.error import Error
from cpl_cli.commands.help import Help from cpl_cli.command.help import Help
from cpl_cli.commands.version import Version from cpl_cli.command.version import Version
from cpl_cli.publish.project_settings import ProjectSettings
class CLI(ApplicationABC): class CLI(ApplicationABC):
@ -18,8 +21,9 @@ class CLI(ApplicationABC):
def configure(self): def configure(self):
self._command_handler: CommandHandler = self._services.get_service(CommandHandler) self._command_handler: CommandHandler = self._services.get_service(CommandHandler)
self._command_handler.add_command(Command('help', ['h', 'H'], self._services.get_service(Help))) self._command_handler.add_command(CommandModel('build', ['h', 'B'], Build))
self._command_handler.add_command(Command('version', ['v', 'V'], self._services.get_service(Version))) self._command_handler.add_command(CommandModel('help', ['h', 'H'], Help))
self._command_handler.add_command(CommandModel('version', ['v', 'V'], Version))
def main(self): def main(self):
if len(self._configuration.additional_arguments) < 1: if len(self._configuration.additional_arguments) < 1:

View File

View File

@ -0,0 +1,13 @@
from cpl_cli.command_abc import CommandABC
from cpl_cli.publish.publisher_abc import PublisherABC
class Build(CommandABC):
def __init__(self, publisher: PublisherABC):
CommandABC.__init__(self)
self._publisher = publisher
def run(self, args: list[str]):
self._publisher.build()

View File

View File

@ -10,12 +10,12 @@ class Help(CommandABC):
def run(self, args: list[str]): def run(self, args: list[str]):
Console.write_line('Available Commands:') Console.write_line('Available Commands:')
commands = [ commands = [
['build (-b|-B)', 'Prepares files for publishing into an output directory named dist/ at the given output path. Must be executed from within a workspace directory.'], ['build (-b|-B)', 'Prepares files for publish into an output directory named dist/ at the given output path. Must be executed from within a workspace directory.'],
['generate (-g|-G)', 'Generate a new file.'], ['generate (-g|-G)', 'Generate a new file.'],
['help (-h|-H)', 'Lists available commands and their short descriptions.'], ['help (-h|-H)', 'Lists available command and their short descriptions.'],
['new (-n|-N)', 'Creates new CPL project.'], ['new (-n|-N)', 'Creates new CPL project.'],
['start (-s|-S)', 'Starts CPL project, restarting on file changes'], ['start (-s|-S)', 'Starts CPL project, restarting on file changes'],
['publish (-p|-P)', 'Prepares files for publishing into an output directory named dist/ at the given output path and executes setup.py. Must be executed from within a workspace directory.'], ['publish (-p|-P)', 'Prepares files for publish into an output directory named dist/ at the given output path and executes setup.py. Must be executed from within a workspace directory.'],
['update (-u|-u)', 'Update CPL and project dependencies.'], ['update (-u|-u)', 'Update CPL and project dependencies.'],
['version (-v|-V)', 'Outputs CPL CLI version.'] ['version (-v|-V)', 'Outputs CPL CLI version.']
] ]

View File

View File

View File

View File

View File

@ -1,24 +1,26 @@
from cpl.application.application_runtime_abc import ApplicationRuntimeABC from cpl.application.application_runtime_abc import ApplicationRuntimeABC
from cpl.dependency_injection.service_abc import ServiceABC from cpl.dependency_injection.service_abc import ServiceABC
from cpl_cli.command import Command from cpl.dependency_injection.service_provider_base import ServiceProviderABC
from cpl_cli.command_model import CommandModel
class CommandHandler(ServiceABC): class CommandHandler(ServiceABC):
def __init__(self, runtime: ApplicationRuntimeABC): def __init__(self, runtime: ApplicationRuntimeABC, services: ServiceProviderABC):
ServiceABC.__init__(self) ServiceABC.__init__(self)
self._runtime = runtime self._runtime = runtime
self._services = services
self._commands: list[Command] = [] self._commands: list[CommandModel] = []
def add_command(self, cmd: Command): def add_command(self, cmd: CommandModel):
self._commands.append(cmd) self._commands.append(cmd)
def remove_command(self, cmd: Command): def remove_command(self, cmd: CommandModel):
self._commands.remove(cmd) self._commands.remove(cmd)
def handle(self, cmd: str, args: list[str]): def handle(self, cmd: str, args: list[str]):
for command in self._commands: for command in self._commands:
if cmd == command.name or cmd in command.aliases: if cmd == command.name or cmd in command.aliases:
command.command.run(args) self._services.get_service(command.command).run(args)

View File

View File

@ -0,0 +1,46 @@
import traceback
from typing import Optional
from cpl.configuration.configuration_model_abc import ConfigurationModelABC
from cpl.console.console import Console
from cpl.console.foreground_color import ForegroundColor
from cpl.version.version import Version
from cpl_cli.publish.project_settings_name import ProjectSettingsName
class ProjectSettings(ConfigurationModelABC):
def __init__(self):
ConfigurationModelABC.__init__(self)
self._dist_path: Optional[str] = None
self._excluded_files: list[str] = []
self._version: Optional[Version] = None
@property
def excluded_files(self) -> list[str]:
return self._excluded_files
@property
def dist_path(self) -> str:
return self._dist_path
@dist_path.setter
def dist_path(self, dist_path: str):
self._dist_path = dist_path
@property
def version(self) -> Version:
return self._version
def from_dict(self, settings: dict):
try:
self._dist_path = settings[ProjectSettingsName.dist_path.value]
self._excluded_files = settings[ProjectSettingsName.excluded_files.value]
self._version = settings[ProjectSettingsName.version.value]
except Exception as e:
Console.set_foreground_color(ForegroundColor.red)
Console.write_line(
f'[ ERROR ] [ {__name__} ]: Reading error in {ProjectSettingsName.project.value} settings')
Console.write_line(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}')
Console.set_foreground_color(ForegroundColor.default)

View File

@ -0,0 +1,9 @@
from enum import Enum
class ProjectSettingsName(Enum):
dist_path = 'DistPath'
excluded_files = 'ExcludedFiles'
version = 'Version'
project = 'Project'

View File

@ -0,0 +1,65 @@
import os
import shutil
from cpl.application.application_runtime_abc import ApplicationRuntimeABC
from cpl.console.console import Console
from cpl_cli.publish.project_settings import ProjectSettings
from cpl_cli.publish.publisher_abc import PublisherABC
class Publisher(PublisherABC):
def __init__(self, runtime: ApplicationRuntimeABC, project: ProjectSettings):
PublisherABC.__init__(self)
self._runtime = runtime
self._project = project
@property
def source_path(self) -> str:
return ''
@property
def dist_path(self) -> str:
return ''
def _create_dist_path(self):
self._project.dist_path = os.path.join(self._runtime.working_directory, self._project.dist_path)
Console.write_line('DIST:', self._project.dist_path)
if os.path.isdir(self._project.dist_path):
try:
shutil.rmtree(self._project.dist_path)
except Exception as e:
Console.error(f'{e}')
exit()
if not os.path.isdir(self._project.dist_path):
try:
os.makedirs(self._project.dist_path)
except Exception as e:
Console.error(f'{e}')
exit()
def _create_packages(self):
pass
def _dist_files(self):
pass
def include(self, path: str):
pass
def exclude(self, path: str):
pass
def build(self):
Console.write_line('Creating internal packages:')
self._create_packages()
Console.write_line('Building application:')
self._dist_files()
def publish(self):
pass

View File

@ -0,0 +1,30 @@
from abc import abstractmethod
from cpl.dependency_injection.service_abc import ServiceABC
class PublisherABC(ServiceABC):
@abstractmethod
def __init__(self):
ServiceABC.__init__(self)
@property
@abstractmethod
def source_path(self) -> str: pass
@property
@abstractmethod
def dist_path(self) -> str: pass
@abstractmethod
def include(self, path: str): pass
@abstractmethod
def exclude(self, path: str): pass
@abstractmethod
def build(self): pass
@abstractmethod
def publish(self): pass

View File

@ -4,11 +4,15 @@ from cpl.application.application_host import ApplicationHost
from cpl.application.application_host_abc import ApplicationHostABC from cpl.application.application_host_abc import ApplicationHostABC
from cpl.application.startup_abc import StartupABC from cpl.application.startup_abc import StartupABC
from cpl.configuration.configuration_abc import ConfigurationABC from cpl.configuration.configuration_abc import ConfigurationABC
from cpl.console.console import Console
from cpl.dependency_injection.service_provider_base import ServiceProviderABC from cpl.dependency_injection.service_provider_base import ServiceProviderABC
from cpl_cli.command.build import Build
from cpl_cli.command_handler import CommandHandler from cpl_cli.command_handler import CommandHandler
from cpl_cli.commands.help import Help from cpl_cli.command.help import Help
from cpl_cli.commands.version import Version from cpl_cli.command.version import Version
from cpl_cli.error import Error from cpl_cli.error import Error
from cpl_cli.publish.publisher import Publisher
from cpl_cli.publish.publisher_abc import PublisherABC
class Startup(StartupABC): class Startup(StartupABC):
@ -34,6 +38,8 @@ class Startup(StartupABC):
def create_configuration(self) -> ConfigurationABC: def create_configuration(self) -> ConfigurationABC:
self._configuration.add_environment_variables('PYTHON_') self._configuration.add_environment_variables('PYTHON_')
self._configuration.add_environment_variables('CPL_') self._configuration.add_environment_variables('CPL_')
self._configuration.add_json_file('cpl.json', optional=True, output=False)
self._configuration.add_console_argument('', 'build', ['-b', '-B'], '')
self._configuration.add_console_argument('', 'help', ['-h', '-H'], '') self._configuration.add_console_argument('', 'help', ['-h', '-H'], '')
self._configuration.add_console_argument('', 'version', ['-v', '-V'], '') self._configuration.add_console_argument('', 'version', ['-v', '-V'], '')
self._configuration.add_console_arguments() self._configuration.add_console_arguments()
@ -41,9 +47,12 @@ class Startup(StartupABC):
return self._configuration return self._configuration
def create_services(self) -> ServiceProviderABC: def create_services(self) -> ServiceProviderABC:
self._services.add_singleton(CommandHandler, CommandHandler) self._services.add_singleton(CommandHandler)
self._services.add_scoped(Help, Help) self._services.add_transient(PublisherABC, Publisher)
self._services.add_scoped(Version, Version)
self._services.add_transient(Build)
self._services.add_transient(Help)
self._services.add_transient(Version)
return self._services return self._services