From f82281adb9978cac89be32a2add8eb8411cfaf76 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 14 Jan 2021 18:22:15 +0100 Subject: [PATCH] fix create_env, add icon, igniter as subprocess, refactored start --- igniter/__init__.py | 8 +- igniter/bootstrap_repos.py | 143 ++++++++++++++++++-- igniter/install_thread.py | 7 +- igniter/pype.ico | Bin 0 -> 109515 bytes setup.py | 17 ++- start.py | 182 +++++++++++++++++++++----- tests/igniter/test_bootstrap_repos.py | 5 + tools/create_env.ps1 | 3 +- 8 files changed, 311 insertions(+), 54 deletions(-) create mode 100644 igniter/pype.ico diff --git a/igniter/__init__.py b/igniter/__init__.py index 8de58cd6d4..eda37c5af3 100644 --- a/igniter/__init__.py +++ b/igniter/__init__.py @@ -9,10 +9,12 @@ from .bootstrap_repos import BootstrapRepos def run(): - app = QtWidgets.QApplication(sys.argv) + """Show Igniter dialog.""" + # app = QtWidgets.QApplication(sys.argv) d = InstallDialog() - d.show() - sys.exit(app.exec_()) + d.exec_() + #d.show() + #sys.exit(app.exec_()) __all__ = [ diff --git a/igniter/bootstrap_repos.py b/igniter/bootstrap_repos.py index ba4a21d5d7..2a71887fbf 100644 --- a/igniter/bootstrap_repos.py +++ b/igniter/bootstrap_repos.py @@ -140,6 +140,22 @@ class PypeVersion: return False + def is_staging(self) -> bool: + """Test if current version is staging one.""" + return self.variant == "staging" + + def get_main_version(self) -> str: + """Return main version component. + + This returns x.x.x part of version from possibly more complex one + like x.x.x-foo-bar. + + Returns: + str: main version component + + """ + return "{}.{}.{}".format(self.major, self.minor, self.subversion) + @staticmethod def version_in_str(string: str) -> Tuple: """Find Pype version in given string. @@ -227,7 +243,7 @@ class BootstrapRepos: return v.path @staticmethod - def get_local_version() -> str: + def get_local_live_version() -> str: """Get version of local Pype.""" return __version__ @@ -273,7 +289,7 @@ class BootstrapRepos: # version and use it as a source. Otherwise repo_dir is user # entered location. if not repo_dir: - version = self.get_local_version() + version = self.get_local_live_version() repo_dir = self.live_repo_dir else: version = self.get_version(repo_dir) @@ -516,11 +532,7 @@ class BootstrapRepos: for file in dir_to_search.iterdir(): # if file, strip extension, in case of dir not. - if file.is_dir(): - name = file.name - else: - name = file.stem - + name = file.name if file.is_dir() else file.stem result = PypeVersion.version_in_str(name) if result[0]: @@ -540,7 +552,10 @@ class BootstrapRepos: self._log.error( f"cannot determine version from {file}") continue - if version_check != detected_version: + + version_main = version_check.get_main_version() + detected_main = detected_version.get_main_version() + if version_main != detected_main: self._log.error( (f"dir version ({detected_version}) and " f"its content version ({version_check}) " @@ -568,7 +583,10 @@ class BootstrapRepos: version_check = PypeVersion( version=zip_version["__version__"]) - if version_check != detected_version: + version_main = version_check.get_main_version() + detected_main = detected_version.get_main_version() + + if version_main != detected_main: self._log.error( (f"zip version ({detected_version}) " f"and its content version " @@ -769,3 +787,110 @@ class BootstrapRepos: zip_ref.extractall(destination) self._print(f"Installed as {version.path.stem}") + + def install_version(self, pype_version: PypeVersion, force: bool = False): + """Install Pype version to user data directory. + + Args: + pype_version (PypeVersion): Pype version to install. + force (bool, optional): Force overwrite existing version. + + Returns: + Path: Path to installed Pype. + + Raises: + PypeVersionExists: If not forced and this version already exist + in user data directory. + PypeVersionInvalid: If version to install is invalid. + PypeVersionIOError: If copying or zipping fail. + + """ + + # test if version is located (in user data dir) + is_inside = False + try: + is_inside = pype_version.path.resolve().relative_to( + self.data_dir) + except ValueError: + # if relative path cannot be calculated, Pype version is not + # inside user data dir + pass + + if is_inside: + raise PypeVersionExists("Pype already inside user data dir") + + # determine destination directory name + # for zip file strip suffix + destination = self.data_dir / pype_version.path.stem + + # test if destination file already exist, if so lets delete it. + # we consider path on location as authoritative place. + if destination.exists() and force: + try: + destination.unlink() + except OSError: + self._log.error( + f"cannot remove already existing {destination}", + exc_info=True) + return None + else: + raise PypeVersionExists(f"{destination} already exist.") + + # create destination parent directories even if they don't exist. + if not destination.exists(): + destination.mkdir(parents=True) + + # version is directory + if pype_version.path.is_dir(): + # create zip inside temporary directory. + self._log.info("Creating zip from directory ...") + with tempfile.TemporaryDirectory() as temp_dir: + temp_zip = \ + Path(temp_dir) / f"pype-v{pype_version}.zip" + self._log.info(f"creating zip: {temp_zip}") + + self._create_pype_zip(temp_zip, pype_version.path) + if not os.path.exists(temp_zip): + self._log.error("make archive failed.") + raise PypeVersionIOError("Zip creation failed.") + + # set zip as version source + pype_version.path = temp_zip + + elif pype_version.path.is_file(): + # check if file is zip (by extension) + if pype_version.path.suffix.lower() != ".zip": + raise PypeVersionInvalid("Invalid file format") + + try: + # copy file to destination + self._log.info("Copying zip to destination ...") + copyfile(pype_version.path.as_posix(), destination.as_posix()) + except OSError as e: + self._log.error( + "cannot copy version to user data directory", + exc_info=True) + raise PypeVersionIOError( + "can't copy version to destination") from e + + # extract zip there + self._log.info("extracting zip to destination ...") + with ZipFile(pype_version.path, "r") as zip: + zip.extractall(destination) + + return destination + + +class PypeVersionExists(Exception): + """Exception for handling existing Pype version.""" + pass + + +class PypeVersionInvalid(Exception): + """Exception for handling invalid Pype version.""" + pass + + +class PypeVersionIOError(Exception): + """Exception for handling IO errors in Pype version.""" + pass diff --git a/igniter/install_thread.py b/igniter/install_thread.py index 37232bb88e..ad24913ed7 100644 --- a/igniter/install_thread.py +++ b/igniter/install_thread.py @@ -48,7 +48,7 @@ class InstallThread(QThread): # find local version of Pype bs = BootstrapRepos( progress_callback=self.set_progress, message=self.message) - local_version = bs.get_local_version() + local_version = bs.get_local_live_version() # if user did entered nothing, we install Pype from local version. # zip content of `repos`, copy it to user data dir and append @@ -93,8 +93,6 @@ class InstallThread(QThread): f"currently running {local_version}" ), False) self.message.emit("Skipping Pype install ...", False) - if detected[-1].path.suffix.lower() == ".zip": - bs.extract_pype(detected[-1]) return self.message.emit(( @@ -150,6 +148,9 @@ class InstallThread(QThread): bs.registry.set_secure_item("pypeMongo", self._mongo) os.environ["PYPE_MONGO"] = self._mongo + if os.getenv("PYPE_PATH") == self._path: + ... + self.message.emit(f"processing {self._path}", True) repo_file = bs.process_entered_location(self._path) diff --git a/igniter/pype.ico b/igniter/pype.ico new file mode 100644 index 0000000000000000000000000000000000000000..746fc36ba29274127740c24feb3fb834424bfdbc GIT binary patch literal 109515 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 P00000NkvXXu0mjf8ME^t literal 0 HcmV?d00001 diff --git a/setup.py b/setup.py index 99e1fe75b9..fbf8f3ec1d 100644 --- a/setup.py +++ b/setup.py @@ -2,12 +2,16 @@ """Setup info for building Pype 3.0.""" import os import sys +from pathlib import Path from cx_Freeze import setup, Executable from sphinx.setup_command import BuildDoc version = {} -with open(os.path.join("pype", "version.py")) as fp: + +pype_root = Path(os.path.dirname(__file__)) + +with open(pype_root / "pype" / "version.py") as fp: exec(fp.read(), version) __version__ = version["__version__"] @@ -65,10 +69,13 @@ build_options = dict( include_files=include_files ) +icon_path = pype_root / "igniter" / "pype.ico" executables = [ - Executable("start.py", base=None, target_name="pype_console"), - Executable("start.py", base=base, target_name="pype") + Executable("start.py", base=None, + target_name="pype_console", icon=icon_path.as_posix()), + Executable("start.py", base=base, + target_name="pype", icon=icon_path.as_posix()) ] setup( @@ -82,8 +89,8 @@ setup( "project": "Pype", "version": __version__, "release": __version__, - "source_dir": "./docs/source", - "build_dir": "./docs/build" + "source_dir": (pype_root / "docs" / "source").as_posix(), + "build_dir": (pype_root / "docs" / "build").as_posix() } }, executables=executables diff --git a/start.py b/start.py index 82dfc1dce9..55fb979b8d 100644 --- a/start.py +++ b/start.py @@ -84,6 +84,10 @@ So, bootstrapping Pype looks like this:: Todo: Move or remove bootstrapping environments out of the code. +Attributes: + silent_commands (list): list of commands for which we won't print Pype + logo and info header. + .. _MongoDB: https://www.mongodb.com/ @@ -92,6 +96,7 @@ import os import re import sys import traceback +import subprocess import acre @@ -99,6 +104,9 @@ from igniter import BootstrapRepos from igniter.tools import load_environments +silent_commands = ["run", "igniter"] + + def set_environments() -> None: """Set loaded environments. @@ -106,14 +114,49 @@ def set_environments() -> None: better handling of environments """ - env = load_environments(["global"]) + env = {} + try: + env = load_environments(["global"]) + except OSError as e: + print(f"!!! {e}") + exit() + env = acre.merge(env, dict(os.environ)) os.environ.clear() os.environ.update(env) +def run(arguments: list, env: dict = None) -> int: + """Use correct executable to run stuff. + + This passing arguments to correct Pype executable. If Pype is run from + live sources, executable will be `python` in virtual environment. + If running from frozen code, executable will be `pype`. Its equivalent in + live code is `python start.py`. + + Args: + arguments (list): Argument list to pass Pype. + env (dict, optional): Dictionary containing environment. + + Returns: + int: Process return code. + + """ + if getattr(sys, 'frozen', False): + interpreter = [sys.executable] + else: + interpreter = [sys.executable, __file__] + + interpreter.extend(arguments) + + p = subprocess.Popen(interpreter, env=env) + p.wait() + print(f">>> done [{p.returncode}]") + return p.returncode + + def set_modules_environments(): - """Set global environments for pype's modules. + """Set global environments for pype modules. This requires to have pype in `sys.path`. """ @@ -129,10 +172,9 @@ def set_modules_environments(): if publish_plugin_dirs: publish_paths_str = os.environ.get("PYBLISHPLUGINPATH") or "" publish_paths = publish_paths_str.split(os.pathsep) - _publish_paths = set() - for path in publish_paths: - if path: - _publish_paths.add(os.path.normpath(path)) + _publish_paths = { + os.path.normpath(path) for path in publish_paths if path + } for path in publish_plugin_dirs: _publish_paths.add(os.path.normpath(path)) module_envs["PYBLISHPLUGINPATH"] = os.pathsep.join(_publish_paths) @@ -149,61 +191,133 @@ def boot(): """Bootstrap Pype.""" from pype.lib.terminal_splash import play_animation - play_animation() - - # find pype versions bootstrap = BootstrapRepos() - pype_versions = bootstrap.find_pype() - # check for `--use-version=3.0.0` argument. + # ------------------------------------------------------------------------ + # Process arguments + # ------------------------------------------------------------------------ + + # don't play for silenced commands + if all(item not in sys.argv for item in silent_commands): + play_animation() + + # check for `--use-version=3.0.0` argument and `--use-staging` use_version = None - + use_staging = False for arg in sys.argv: m = re.search(r"--use-version=(?P\d+\.\d+\.\d*.+?)", arg) if m and m.group('version'): use_version = m.group('version') sys.argv.remove(arg) break + if "--use-staging" in sys.argv: + use_staging = True + sys.argv.remove("--use-staging") + # handle igniter + # this is helper to run igniter before anything else + if "igniter" in sys.argv: + import igniter + igniter.run() + return + + # ------------------------------------------------------------------------ + # Determine mongodb connection + # ------------------------------------------------------------------------ + + # try env variable if not os.getenv("PYPE_MONGO"): + # try system keyring + pype_mongo = "" try: pype_mongo = bootstrap.registry.get_secure_item("pypeMongo") except ValueError: print("*** No DB connection string specified.") print("--- launching setup UI ...") - import igniter - igniter.run() - return - else: + run(["igniter"]) + try: + pype_mongo = bootstrap.registry.get_secure_item("pypeMongo") + except ValueError: + print("!!! Still no DB connection string.") + exit() + finally: os.environ["PYPE_MONGO"] = pype_mongo + # ------------------------------------------------------------------------ + # Load environments from database + # ------------------------------------------------------------------------ + set_environments() + + # ------------------------------------------------------------------------ + # Find Pype versions + # ------------------------------------------------------------------------ + + pype_versions = bootstrap.find_pype(include_zips=True) + pype_version = pype_versions[-1] + if getattr(sys, 'frozen', False): if not pype_versions: - import igniter - igniter.run() + print('*** No Pype versions found.') + print("--- launching setup UI ...") + run(["igniter"]) + pype_versions = bootstrap.find_pype() + if not pype_versions: + print('!!! Still no Pype versions found.') + return + # find only staging versions + if use_staging: + staging_versions = [v for v in pype_versions if v.is_staging()] + if not staging_versions: + print("!!! No staging versions detected.") + return + staging_versions.sort() + # get latest + pype_version = staging_versions[-1] + + # get path of version specified in `--use-version` version_path = BootstrapRepos.get_version_path_from_list( use_version, pype_versions) - if version_path: - # use specified - bootstrap.add_paths_from_directory(version_path) - - else: + if not version_path: if use_version is not None: print(("!!! Specified version was not found, using " "latest available")) - # use latest - version_path = pype_versions[-1].path - bootstrap.add_paths_from_directory(version_path) - use_version = str(pype_versions[-1]) + # specified version was not found so use latest detected. + version_path = pype_version.path + # test if latest detected is installed (in user data dir) + is_inside = False + try: + is_inside = pype_version.path.resolve().relative_to( + bootstrap.data_dir) + except ValueError: + # if relative path cannot be calculated, Pype version is not + # inside user data dir + pass + + if not is_inside: + # install latest version to user data dir + version_path = bootstrap.install_version( + pype_version, force=True) + + # inject version to Python environment (sys.path, ...) + bootstrap.add_paths_from_directory(version_path) + + # add stuff from `/lib` to PYTHONPATH. + os.environ["PYTHONPATH"] += os.pathsep + os.path.normpath( + os.path.join(os.path.dirname(sys.executable), "lib") + ) + + # set PYPE_ROOT to point to currently used Pype version. os.environ["PYPE_ROOT"] = os.path.normpath(version_path.as_posix()) else: # run through repos and add them to sys.path and PYTHONPATH + # set root pype_root = os.path.normpath( os.path.dirname(os.path.realpath(__file__))) - local_version = bootstrap.get_local_version() + # get current version of Pype + local_version = bootstrap.get_local_live_version() if use_version and use_version != local_version: version_path = BootstrapRepos.get_version_path_from_list( use_version, pype_versions) @@ -248,10 +362,14 @@ def boot(): info.insert(0, ">>> Using Pype from [ {} ]".format( os.path.dirname(cli.__file__))) - info_length = len(max(info, key=len)) - info.insert(0, f"*** Pype [{__version__}] " + "-" * info_length) + t_width = os.get_terminal_size().columns + _header = f"*** Pype [{__version__}] " + + info.insert(0, _header + "-" * (t_width - len(_header))) for i in info: - t.echo(i) + # don't show for running scripts + if all(item not in sys.argv for item in silent_commands): + t.echo(i) try: cli.main(obj={}, prog_name="pype") @@ -302,7 +420,7 @@ def get_info() -> list: if log_components["auth_db"]: infos.append((" - auth source", log_components["auth_db"])) - maximum = max([len(i[0]) for i in infos]) + maximum = max(len(i[0]) for i in infos) formatted = [] for info in infos: padding = (maximum - len(info[0])) + 1 diff --git a/tests/igniter/test_bootstrap_repos.py b/tests/igniter/test_bootstrap_repos.py index c0ce1be012..34ddc12550 100644 --- a/tests/igniter/test_bootstrap_repos.py +++ b/tests/igniter/test_bootstrap_repos.py @@ -108,6 +108,11 @@ def test_pype_version(): assert v11.client == "client" +def test_get_main_version(): + ver = PypeVersion(1, 2, 3, variant="staging", client="foo") + assert ver.get_main_version() == "1.2.3" + + def test_get_version_path_from_list(): versions = [ PypeVersion(1, 2, 3, path=Path('/foo/bar')), diff --git a/tools/create_env.ps1 b/tools/create_env.ps1 index 1fee947a38..bb04368964 100644 --- a/tools/create_env.ps1 +++ b/tools/create_env.ps1 @@ -105,14 +105,13 @@ catch { Exit-WithCode 1 } - Write-Host ">>> " -NoNewline -ForegroundColor green Write-Host "Creating virtual env ..." & python -m venv venv Write-Host ">>> " -NoNewline -ForegroundColor green Write-Host "Entering venv ..." try { - . (".\venv\Scripts\Activate.ps1") + . ("$($pype_root)\venv\Scripts\Activate.ps1") } catch { Write-Host "!!! Failed to activate" -ForegroundColor red