From 323e363b4286270082ae5f3b27efa4bea6636a41 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Mon, 27 Jun 2022 11:50:22 +0200 Subject: [PATCH] Improved venv support to all related commands --- src/cpl_cli/command/install_service.py | 21 ++----------- src/cpl_cli/command/new_service.py | 31 +++++++++++++++++-- src/cpl_cli/command/uninstall_service.py | 4 +-- src/cpl_cli/command/update_service.py | 4 ++- .../configuration/venv_helper_service.py | 28 +++++++++++++++++ src/cpl_cli/startup_argument_extension.py | 3 +- unittests/unittests_cli/new_test_case.py | 18 ++++++++--- 7 files changed, 81 insertions(+), 28 deletions(-) diff --git a/src/cpl_cli/command/install_service.py b/src/cpl_cli/command/install_service.py index ec27a067..43db92b9 100644 --- a/src/cpl_cli/command/install_service.py +++ b/src/cpl_cli/command/install_service.py @@ -58,22 +58,6 @@ class InstallService(CommandABC): def _wait(self, t: int, *args, source: str = None, stdout=None, stderr=None): time.sleep(t) - def _init_venv(self): - if self._is_virtual: - return - venv_path = os.path.abspath(os.path.join(self._env.working_directory, self._project_settings.python_executable)) - - if not os.path.exists(venv_path): - Console.spinner( - f'Creating venv {venv_path}', - VenvHelper.create_venv, - venv_path, - text_foreground_color=ForegroundColorEnum.green, - spinner_foreground_color=ForegroundColorEnum.cyan - ) - - Pip.set_executable(venv_path) - def _install_project(self): """ Installs dependencies of CPl project @@ -211,11 +195,12 @@ class InstallService(CommandABC): args.remove('simulate') Console.write_line('Running in simulation mode:') - self._init_venv() + VenvHelper.init_venv(self._is_virtual, self._env, self._project_settings) if len(args) == 0: self._install_project() else: self._install_package(args[0]) - # shutil.rmtree(os.path.abspath(os.path.join(self._env.working_directory, self._project_settings.python_executable))) + if not self._is_virtual: + Pip.reset_executable() diff --git a/src/cpl_cli/command/new_service.py b/src/cpl_cli/command/new_service.py index 73f50ced..e01bbf92 100644 --- a/src/cpl_cli/command/new_service.py +++ b/src/cpl_cli/command/new_service.py @@ -6,6 +6,7 @@ from typing import Optional from packaging import version import cpl_core +from cpl_cli.configuration.venv_helper_service import VenvHelper from cpl_cli.source_creator.unittest_builder import UnittestBuilder from cpl_core.configuration.configuration_abc import ConfigurationABC @@ -36,7 +37,7 @@ class NewService(CommandABC): self._config = configuration self._env = self._config.environment - self._workspace = self._config.get_configuration(WorkspaceSettings) + self._workspace: WorkspaceSettings = self._config.get_configuration(WorkspaceSettings) self._project: ProjectSettings = ProjectSettings() self._project_dict = {} self._build: BuildSettings = BuildSettings() @@ -51,6 +52,7 @@ class NewService(CommandABC): self._use_startup: bool = False self._use_service_providing: bool = False self._use_async: bool = False + self._use_venv: bool = False @property def help_message(self) -> str: @@ -107,7 +109,7 @@ class NewService(CommandABC): ], ProjectSettingsNameEnum.python_version.value: f'>={sys.version.split(" ")[0]}', ProjectSettingsNameEnum.python_path.value: { - sys.platform: '' + sys.platform: '../../venv/bin/python' if self._use_venv else '' }, ProjectSettingsNameEnum.classifiers.value: [] } @@ -275,6 +277,22 @@ class NewService(CommandABC): except Exception as e: Console.error('Could not create project', str(e)) + def _create_venv(self): + + project = self._project.name + if self._workspace is not None: + project = self._workspace.default_project + + if self._env.working_directory.endswith(project): + project = '' + + VenvHelper.init_venv( + False, + self._env, + self._project, + explicit_path=os.path.join(self._env.working_directory, project, self._project.python_executable.replace('../', '')) + ) + def execute(self, args: list[str]): """ Entry point of command @@ -308,6 +326,9 @@ class NewService(CommandABC): if 'service-providing' in args: self._use_service_providing = True args.remove('service-providing') + if 'venv' in args: + self._use_venv = True + args.remove('venv') console = self._config.get_configuration(ProjectTypeEnum.console.value) library = self._config.get_configuration(ProjectTypeEnum.library.value) @@ -316,16 +337,22 @@ class NewService(CommandABC): self._name = console self._schematic = ProjectTypeEnum.console.value self._console(args) + if self._use_venv: + self._create_venv() elif console is None and library is not None and unittest is None: self._name = library self._schematic = ProjectTypeEnum.library.value self._library(args) + if self._use_venv: + self._create_venv() elif console is None and library is None and unittest is not None: self._name = unittest self._schematic = ProjectTypeEnum.unittest.value self._unittest(args) + if self._use_venv: + self._create_venv() else: self._help('Usage: cpl new [options]') diff --git a/src/cpl_cli/command/uninstall_service.py b/src/cpl_cli/command/uninstall_service.py index f2b88d5f..ab83dcbd 100644 --- a/src/cpl_cli/command/uninstall_service.py +++ b/src/cpl_cli/command/uninstall_service.py @@ -4,6 +4,7 @@ import subprocess import textwrap import time +from cpl_cli.configuration.venv_helper_service import VenvHelper from cpl_core.configuration.configuration_abc import ConfigurationABC from cpl_core.console.console import Console from cpl_core.console.foreground_color_enum import ForegroundColorEnum @@ -71,8 +72,7 @@ class UninstallService(CommandABC): args.remove('--simulate') Console.write_line('Running in simulation mode:') - if not self._is_virtual: - Pip.set_executable(self._project_settings.python_executable) + VenvHelper.init_venv(self._is_virtual, self._env, self._project_settings) package = args[0] is_in_dependencies = False diff --git a/src/cpl_cli/command/update_service.py b/src/cpl_cli/command/update_service.py index 3b1895f5..5ce2df95 100644 --- a/src/cpl_cli/command/update_service.py +++ b/src/cpl_cli/command/update_service.py @@ -3,6 +3,7 @@ import os import subprocess import textwrap +from cpl_cli.configuration.venv_helper_service import VenvHelper from cpl_core.configuration.configuration_abc import ConfigurationABC from cpl_core.console.console import Console from cpl_core.console.foreground_color_enum import ForegroundColorEnum @@ -168,7 +169,8 @@ class UpdateService(CommandABC): Console.write_line('Running in simulation mode:') self._is_simulation = True - Pip.set_executable(self._project_settings.python_executable) + VenvHelper.init_venv(False, self._env, self._project_settings) + self._check_project_dependencies() self._check_outdated() Pip.reset_executable() diff --git a/src/cpl_cli/configuration/venv_helper_service.py b/src/cpl_cli/configuration/venv_helper_service.py index fcc6b9b9..28a59171 100644 --- a/src/cpl_cli/configuration/venv_helper_service.py +++ b/src/cpl_cli/configuration/venv_helper_service.py @@ -2,9 +2,37 @@ import os import subprocess import sys +from cpl_cli.configuration import ProjectSettings +from cpl_core.environment import ApplicationEnvironmentABC + +from cpl_core.utils import Pip + +from cpl_core.console import Console, ForegroundColorEnum + class VenvHelper: + @staticmethod + def init_venv(is_virtual: bool, env: ApplicationEnvironmentABC, project_settings: ProjectSettings, explicit_path=None): + if is_virtual: + return + + venv_path = os.path.abspath(os.path.join(env.working_directory, project_settings.python_executable)) + + if explicit_path is not None: + venv_path = os.path.abspath(explicit_path) + + if not os.path.exists(venv_path): + Console.spinner( + f'Creating venv: {venv_path}', + VenvHelper.create_venv, + venv_path, + text_foreground_color=ForegroundColorEnum.green, + spinner_foreground_color=ForegroundColorEnum.cyan + ) + + Pip.set_executable(venv_path) + @staticmethod def create_venv(path): subprocess.run( diff --git a/src/cpl_cli/startup_argument_extension.py b/src/cpl_cli/startup_argument_extension.py index 8e795305..e3f1fef4 100644 --- a/src/cpl_cli/startup_argument_extension.py +++ b/src/cpl_cli/startup_argument_extension.py @@ -50,7 +50,8 @@ class StartupArgumentExtension(StartupExtensionABC): .add_console_argument(ArgumentTypeEnum.Flag, '--', 'application-base', ['ab', 'AB']) \ .add_console_argument(ArgumentTypeEnum.Flag, '--', 'startup', ['s', 'S']) \ .add_console_argument(ArgumentTypeEnum.Flag, '--', 'service-providing', ['sp', 'SP']) \ - .add_console_argument(ArgumentTypeEnum.Flag, '--', 'nothing', ['n', 'N']) + .add_console_argument(ArgumentTypeEnum.Flag, '--', 'nothing', ['n', 'N']) \ + .add_console_argument(ArgumentTypeEnum.Flag, '--', 'venv', ['v', 'V']) config.create_console_argument(ArgumentTypeEnum.Executable, '', 'publish', ['p', 'P'], PublishService, True, validators=[ProjectValidator]) config.create_console_argument(ArgumentTypeEnum.Executable, '', 'remove', ['r', 'R'], RemoveService, True, validators=[WorkspaceValidator]) \ .add_console_argument(ArgumentTypeEnum.Flag, '--', 'simulate', ['s', 'S']) diff --git a/unittests/unittests_cli/new_test_case.py b/unittests/unittests_cli/new_test_case.py index 4125993d..b2b24177 100644 --- a/unittests/unittests_cli/new_test_case.py +++ b/unittests/unittests_cli/new_test_case.py @@ -12,10 +12,15 @@ class NewTestCase(unittest.TestCase): def setUp(self): os.chdir(os.path.abspath(PLAYGROUND_PATH)) - def _test_project(self, project_type: str, name: str, *args): + def _test_project(self, project_type: str, name: str, *args, test_venv=False): CLICommands.new(project_type, name, *args) workspace_path = os.path.abspath(os.path.join(PLAYGROUND_PATH, name)) self.assertTrue(os.path.exists(workspace_path)) + if test_venv: + self.assertTrue(os.path.exists(os.path.join(workspace_path, 'venv'))) + self.assertTrue(os.path.exists(os.path.join(workspace_path, 'venv/bin'))) + self.assertTrue(os.path.exists(os.path.join(workspace_path, 'venv/bin/python'))) + self.assertTrue(os.path.islink(os.path.join(workspace_path, 'venv/bin/python'))) project_path = os.path.abspath(os.path.join(PLAYGROUND_PATH, name, 'src', String.convert_to_snake_case(name))) self.assertTrue(os.path.exists(project_path)) @@ -38,11 +43,16 @@ class NewTestCase(unittest.TestCase): else: self.assertFalse(os.path.isfile(os.path.join(project_path, f'test_case.py'))) - def _test_sub_project(self, project_type: str, name: str, workspace_name: str, *args): + def _test_sub_project(self, project_type: str, name: str, workspace_name: str, *args, test_venv=False): os.chdir(os.path.abspath(os.path.join(os.getcwd(), workspace_name))) CLICommands.new(project_type, name, *args) workspace_path = os.path.abspath(os.path.join(PLAYGROUND_PATH, workspace_name)) self.assertTrue(os.path.exists(workspace_path)) + if test_venv: + self.assertTrue(os.path.exists(os.path.join(workspace_path, 'venv'))) + self.assertTrue(os.path.exists(os.path.join(workspace_path, 'venv/bin'))) + self.assertTrue(os.path.exists(os.path.join(workspace_path, 'venv/bin/python'))) + self.assertTrue(os.path.islink(os.path.join(workspace_path, 'venv/bin/python'))) project_path = os.path.abspath(os.path.join(PLAYGROUND_PATH, workspace_name, 'src', String.convert_to_snake_case(name))) self.assertTrue(os.path.exists(project_path)) @@ -76,7 +86,7 @@ class NewTestCase(unittest.TestCase): os.chdir(os.path.abspath(os.path.join(os.getcwd(), '../'))) def test_console(self): - self._test_project('console', 'test-console', '--ab', '--s') + self._test_project('console', 'test-console', '--ab', '--s', '--venv', test_venv=True) def test_console_without_s(self): self._test_project('console', 'test-console-without-s', '--ab') @@ -88,7 +98,7 @@ class NewTestCase(unittest.TestCase): self._test_project('console', 'test-console-without-anything', '--n') def test_sub_console(self): - self._test_sub_project('console', 'test-sub-console', 'test-console', '--ab', '--s', '--sp') + self._test_sub_project('console', 'test-sub-console', 'test-console', '--ab', '--s', '--sp', '--venv', test_venv=True) def test_library(self): self._test_project('library', 'test-library', '--ab', '--s', '--sp')