From dcc073ff85aff71d97574a4732c80d6202144525 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 17 Sep 2020 16:33:01 +0200 Subject: [PATCH] fix build and pype bootstrap --- build.ps1 | 7 +- igniter/bootstrap_repos.py | 41 +++++++- pype.py | 132 +++++++++++++++++++------- setup.py | 3 +- tests/igniter/test_bootstrap_repos.py | 51 +++++++--- 5 files changed, 179 insertions(+), 55 deletions(-) diff --git a/build.ps1 b/build.ps1 index 9b65dae896..ec1be5e33b 100644 --- a/build.ps1 +++ b/build.ps1 @@ -38,8 +38,9 @@ $art = @' Write-Host $art -ForegroundColor DarkGreen -$version_file = Get-Content -Path "version.py" -$pype_version = $version_file -match '(\d+\.\d+.\d+)' +$version_file = Get-Content -Path ".\pype\version.py" +$result = [regex]::Matches($version_file, '__version__ = "(?\d+\.\d+.\d+)"') +$pype_version = $result[0].Groups['version'].Value if (-not $pype_version) { Write-Host "!!! " -ForegroundColor yellow -NoNewline Write-Host "Cannot determine Pype version." @@ -48,7 +49,7 @@ if (-not $pype_version) { Write-Host ">>> " -NoNewline -ForegroundColor green Write-Host "Building Pype [ " -NoNewline -ForegroundColor white -Write-host "v$($matches[1])" -NoNewline -ForegroundColor green +Write-host $pype_version -NoNewline -ForegroundColor green Write-Host " ]..." -ForegroundColor white Write-Host ">>> " -NoNewline -ForegroundColor green diff --git a/igniter/bootstrap_repos.py b/igniter/bootstrap_repos.py index b028fa3401..c0007b6604 100644 --- a/igniter/bootstrap_repos.py +++ b/igniter/bootstrap_repos.py @@ -7,6 +7,7 @@ Attrbutes: """ import sys import os +import re import logging as log import shutil import tempfile @@ -32,7 +33,10 @@ class BootstrapRepos(): self._log = log.getLogger(str(__class__)) self.data_dir = user_data_dir(self._app, self._vendor) if getattr(sys, 'frozen', False): - self.live_repo_dir = None + self.live_repo_dir = os.path.join( + os.path.dirname(sys.executable), + "repos" + ) else: self.live_repo_dir = os.path.abspath( os.path.join( @@ -77,7 +81,7 @@ class BootstrapRepos(): f"pype-repositories-v{local_version}.zip" ) self._log.info(f"creating zip: {temp_zip}") - # shutil.make_archive(temp_zip, "zip", repo_dir) + self._create_pype_zip( temp_zip, repo_dir, progress_callback=progress_callback) if not os.path.exists(temp_zip): @@ -176,7 +180,34 @@ class BootstrapRepos(): root = item.split("/")[0] if root not in roots: roots.append(root) - sys.path.append(f"{archive}{os.path.sep}{root}") + sys.path.insert(0, f"{archive}{os.path.sep}{root}") - os.environ["PYTHONPATH"] = "{}{}{}".format( - os.environ["PYTHONPATH"], os.pathsep, os.pathsep.join(roots)) + pythonpath = os.getenv("PYTHONPATH", "") + paths = pythonpath.split(os.pathsep) + paths += roots + + os.environ["PYTHONPATH"] = os.pathsep.join(paths) + + def find_pype(self) -> Union[str, None]: + """Get ordered dict of detected Pype version. + + Returns: + dict: Dictionary of detected Pype version. Key is version, value + is path to zip file. + None: if Pype is not found. + """ + # pype installation dir doesn't exists + if not os.path.exists(self.data_dir): + return None + + # f"pype-repositories-v{local_version}.zip" + files = os.listdir(self.data_dir) + _pype_versions = {} + for file in files: + m = re.match( + r"^pype-repositories-v(?P\d+\.\d+\.\d+).zip$", file) + if m: + _pype_versions[m.group("version")] = os.path.join( + self.data_dir, file) + + return dict(sorted(_pype_versions.items())) diff --git a/pype.py b/pype.py index 0274f22370..f4efc20a45 100644 --- a/pype.py +++ b/pype.py @@ -1,44 +1,106 @@ # -*- coding: utf-8 -*- -"""Main entry point for Pype command.""" -import sys -import os -import traceback +"""Main entry point for Pype command. -from appdirs import user_data_dir +Bootstrapping process of Pype is as follows: -from pype import cli -from pype.lib import terminal as t -from pype.version import __version__ +If no Pype repositories are found in default install location (user data dir) +then Igniter (Pype setup tool) will launch its GUI. +If pype repositories zip file is found in default install location +(user data dir), it will get list of those zips there and use latest one +or the one specified with `--use-version` command line argument. If the +one specified doesn't exist then latest available version will be used. All +repositories in that zip will be added to `sys.path` and `PYTHONPATH`. -vendor = "pypeclub" -app = "pype" -pype_dir = user_data_dir(app, vendor) -repo_zip = os.path.join(pype_dir, f"pype-repositories-v{__version__}.zip") -if getattr(sys, 'frozen', False): - datadir = os.path.dirname(sys.executable) -else: - datadir = os.path.dirname(__file__) - -art = r""" - ____________ - /\ __ \ - \ \ \/_\ \ - \ \ _____/ ______ - \ \ \___/ /\ \ - \ \____\ \ \_____\ - \/____/ \/_____/ PYPE Club . +If Pype is live (ie not freezed) then current version of Pype module will be +used. All directories under `repos` will be added to `sys.path` and +`PYTHONPATH`. """ +import sys +import os +import re +import traceback -print(art) -t.echo(f"*** Pype [{__version__}] --------------------") -t.echo(">>> Validating installation ...") -try: - cli.main(obj={}, prog_name="pype") -except Exception: - exc_info = sys.exc_info() - print("!!! Pype crashed:") - traceback.print_exception(*exc_info) - sys.exit(1) +# find Pype installation. +from igniter.bootstrap_repos import BootstrapRepos + +bootstrap = BootstrapRepos() +pype_versions = bootstrap.find_pype() +# if nothing found, run installer - only when running freezed +if getattr(sys, 'frozen', False): + if not pype_versions: + import igniter + igniter.run() + + +def boot(): + """Bootstrap Pype.""" + # test for `--use-version=3.0.0` argument. + use_version = None + + 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') + break + + if getattr(sys, 'frozen', False): + if use_version in pype_versions.keys(): + # use specified + bootstrap.add_paths_from_archive(pype_versions[use_version]) + else: + if use_version is not None: + print(("!!! Specified version was not found, using " + "latest available")) + # use latest + bootstrap.add_paths_from_archive(list(pype_versions.values())[-1]) + use_version = list(pype_versions.keys())[-1] + else: + # run throught repos and add them to sys.path and PYTHONPATH + pype_root = os.path.dirname(sys.executable) + repos = os.listdir(os.path.join(pype_root, "repos")) + for repo in repos: + sys.path.append(repo) + + pythonpath = os.getenv("PYTHONPATH", "") + paths = pythonpath.split(os.pathsep) + paths += repos + os.environ["PYTHONPATH"] = os.pathsep.join(paths) + + # delete Pype module from cache so it is used from specific version + try: + del sys.modules["pype"] + del sys.modules["pype.version"] + except AttributeError: + pass + + from pype import cli + from pype.lib import terminal as t + from pype.version import __version__ + + art = r""" + ____________ + /\ ___ \ + \ \ \/_\ \ + \ \ _____/ ______ ___ ___ ___ + \ \ \___/ /\ \ \ \\ \\ \ + \ \____\ \ \_____\ \__\\__\\__\ + \/____/ \/_____/ . PYPE Club . + + """ + + print(art) + t.echo(f"*** Pype [{__version__}] --------------------------------------") + t.echo(">>> Using Pype from [ {} ]".format(os.path.dirname(cli.__file__))) + try: + cli.main(obj={}, prog_name="pype") + except Exception: + exc_info = sys.exc_info() + print("!!! Pype crashed:") + traceback.print_exception(*exc_info) + sys.exit(1) + + +boot() diff --git a/setup.py b/setup.py index 983dce8021..756a132251 100644 --- a/setup.py +++ b/setup.py @@ -31,7 +31,6 @@ if sys.platform == "win32": buildOptions = dict( packages=install_requires, includes=[ - 'pype', 'repos/acre/acre', 'repos/avalon-core/avalon', 'repos/pyblish-base/pyblish', @@ -40,6 +39,8 @@ buildOptions = dict( excludes=[], bin_includes=[], include_files=[ + "pype", + "repos", "schema", "setup", "vendor", diff --git a/tests/igniter/test_bootstrap_repos.py b/tests/igniter/test_bootstrap_repos.py index 05c35c697f..81581294ad 100644 --- a/tests/igniter/test_bootstrap_repos.py +++ b/tests/igniter/test_bootstrap_repos.py @@ -7,28 +7,57 @@ from igniter.bootstrap_repos import BootstrapRepos @pytest.fixture -def fix_bootrap(tmp_path_factory): +def fix_bootrap(tmp_path): bs = BootstrapRepos() bs.live_repo_dir = os.path.abspath('repos') - session_temp = tmp_path_factory.mktemp('test_bootstrap') - bs.data_dir = session_temp + bs.data_dir = tmp_path return bs def test_install_live_repos(fix_bootrap, printer): rf = fix_bootrap.install_live_repos() + sep = os.path.sep expected_paths = [ - f"{rf}{os.path.sep}acre", - f"{rf}{os.path.sep}avalon-core", - f"{rf}{os.path.sep}avalon-unreal-integration", - f"{rf}{os.path.sep}maya-look-assigner", - f"{rf}{os.path.sep}pyblish-base", - f"{rf}{os.path.sep}pype", - f"{rf}{os.path.sep}pype-config" + f"{rf}{sep}acre", + f"{rf}{sep}avalon-core", + f"{rf}{sep}avalon-unreal-integration", + f"{rf}{sep}maya-look-assigner", + f"{rf}{sep}pyblish-base", + f"{rf}{sep}pype", + f"{rf}{sep}pype-config" ] + printer("testing zip creation") assert os.path.exists(rf), "zip archive was not created" fix_bootrap.add_paths_from_archive(rf) for ep in expected_paths: assert ep in sys.path, f"{ep} not set correctly" - import pype + printer("testing pype imported") + del sys.modules["pype"] + import pype # noqa: F401 + + # test if pype is imported from specific location in zip + print(pype.__file__) + assert "pype" in sys.modules.keys(), "Pype not imported" + assert sys.modules["pype"].__file__ == \ + f"{rf}{sep}pype{sep}pype{sep}__init__.py" + + +def test_find_pype(fix_bootrap): + test_versions = [ + "pype-repositories-v3.0.0.zip", + "pype-repositories-v3.0.1.zip", + "pype-repositories-v4.1.0.zip", + "pype-repositories-v4.1.2.zip", + "pype-repositories-v3.2.0.zip", + ] + for test_file in test_versions: + with open(os.path.join(fix_bootrap.data_dir, test_file), "w") as fp: + fp.write(test_file) + + result = fix_bootrap.find_pype() + # we should have results as file were created + assert result is not None, "no Pype version found" + # latest item in `result` should be latest version found. + assert list(result.values())[-1] == os.path.join( + fix_bootrap.data_dir, test_versions[3]), "not a latest version of Pype"