import sys import time import psutil import json import os import subprocess import shutil from pathlib import Path from invoke import task import github from galaxy.tools import zip_folder_to_file with open('src/manifest.json') as f: __version__ = json.load(f)['version'] REQUIREMENTS = 'requirements.txt' REQUIREMENTS_DEV = 'requirements-dev' CURRENT_VERSION_FILE = 'current_version.json' GALAXY_PATH = '' DIST_DIR = '' GALAXY_PYTHONPATH = '' if sys.platform == 'win32': PLATFORM = 'Windows' GALAXY_PATH = 'C:\\Program Files (x86)\\GOG Galaxy\\GalaxyClient.exe' DIST_DIR = os.environ['localappdata'] + '\\GOG.com\\Galaxy\\plugins\\installed' PYTHON = 'python' GALAXY_PYTHONPATH = str(Path(os.path.expandvars("%programfiles(x86)%")) / "GOG Galaxy" / "python" / "python.exe") elif sys.platform == 'darwin': PLATFORM = 'Mac' GALAXY_PATH = "/Applications/GOG Galaxy.app/Contents/MacOS/GOG Galaxy" DIST_DIR = os.environ['HOME'] + r"/Library/Application\ Support/GOG.com/Galaxy/plugins/installed" PYTHON = 'python3' DIST_PLUGIN = os.path.join(DIST_DIR, 'humblebundle') THIRD_PARTY_RELATIVE_DEST = 'modules' def get_repo(): token = os.environ['GITHUB_TOKEN'] g = github.Github(token) return g.get_repo('UncleGoogle/galaxy-integration-humblebundle') def asset_name(tag, platform): return f'humble_{tag}_{platform[:3].lower()}.zip' @task def install(c, dev=False): req = REQUIREMENTS_DEV if dev else REQUIREMENTS c.run(f"{PYTHON} -m pip install -r {req}") @task def build(c, output=DIST_PLUGIN): print(f'Preparing build to folder `{output}`') output = Path(output).resolve() print('Removing', output) if os.path.exists(output): try: shutil.rmtree(output) except OSError as e: if hasattr(e, 'winerror') and e.winerror in [145, 5]: # type: ignore # something e.g. antivirus check holds a file. Try to wait to be released for a moment time.sleep(3) shutil.rmtree(output) else: raise print('Copying source code to ', str(output)) shutil.copytree('src', output, ignore=shutil.ignore_patterns( '__pycache__', '.mypy_cache', 'tests')) args = [ PYTHON, "-m", "pip", "install", "-r", REQUIREMENTS, "--target", str(output / THIRD_PARTY_RELATIVE_DEST), # "--implementation", "cp", # "--python-version", "37", # "--no-deps" ] print(f'Running `{" ".join(args)}`') subprocess.check_call(args) @task def dist(c, output=DIST_PLUGIN, galaxy_path=GALAXY_PATH, no_deps=False): for proc in psutil.process_iter(attrs=['exe'], ad_value=''): if proc.info['exe'] == galaxy_path: print(f'Galaxy at {galaxy_path} is running!. Terminating...') proc.terminate() break else: print('Galaxy instance not found.') if no_deps: c.run(f'inv copy -o {output}') else: c.run(f'inv build -o {output}') print(f'Reopening Galaxy from {galaxy_path}') subprocess.Popen([galaxy_path]) @task def debug(c, output=DIST_PLUGIN, deps=False): this_plugin = 'plugin-humble' for proc in psutil.process_iter(attrs=['exe'], ad_value=''): if proc.info['exe'] == GALAXY_PYTHONPATH: if this_plugin in proc.cmdline()[-1]: print(f'Running plugin instance found!. Terminating...') proc.terminate() break if not deps: c.run(f'inv copy -o {output}') else: c.run(f'inv build -o {output}') print("Now, click 'retry' for crashed plugin in Settings") def recursive_overwrite(src, dest): if os.path.isdir(src): if not os.path.isdir(dest): os.makedirs(dest) files = os.listdir(src) for f in files: recursive_overwrite( os.path.join(src, f), os.path.join(dest, f) ) else: shutil.copyfile(src, dest) @task def copy(c, output=DIST_PLUGIN): print('copying source code ...') recursive_overwrite('src', output) @task def test(c, target=None): print(f'Running tests vs code dumped in folder `{target}`') if target is not None: config = str(Path(__file__).parent / 'pytest-build.ini') with open(config, 'w') as f: f.write("[pytest]\n") f.write(f"python_paths = {target}") # pytest-pythonpaths required else: config = 'pytest.ini' c.run(f"{PYTHON} -m pytest -c {config} -vv tests/common src --color=yes") if sys.platform == 'win32': c.run(f"{PYTHON} -m pytest tests/windows") if target: modules = ['local', 'model', 'plugin.py', 'consts.py', 'humbledownloader.py', 'webservice.py', 'settings.py', 'library.py'] os.environ['MYPYPATH'] = str(Path(target) / THIRD_PARTY_RELATIVE_DEST) modules_full_path = [str(Path(target) / mod) for mod in modules] print(f'running mypy check for {str(Path(target))} directory') c.run(f"{PYTHON} -m mypy {' '.join(modules_full_path)} --follow-imports silent") print('done') @task def archive(c, zip_name=None, target=None): if target is None: build(c, 'build') target = 'build' if zip_name is None: zip_name = f'humblebundle_{__version__}.zip' print(f'Zipping build from `{target}` to `{zip_name}`') zip_folder_to_file(target, zip_name) zip_path = Path('.') / zip_name return str(zip_path.resolve()) @task def curr_ver(c, tag=None): """Refresh CURRENT_VERSION_FILE""" if tag is None: tag = get_repo().get_latest_release().tag_name content = { "tag_name": tag, "assets": [] } for platform in ["Windows", "Mac"]: name = asset_name(tag, platform) content['assets'].append({ "browser_download_url": f"https://github.com/UncleGoogle/galaxy-integration-humblebundle/releases/download/{tag}/{name}", "name": name }) with open(CURRENT_VERSION_FILE, 'w') as f: json.dump(content, f, indent=4) @task(aliases=['tag']) def create_tag(c, tag=None): if tag is None: tag = 'v' + __version__ branch = c.run("git rev-parse --abbrev-ref HEAD").stdout.strip() print(f'New tag version will be: [{tag}] on [{branch}] branch. Is it OK? (make sure new version is committed)') if input('y/n').lower() != 'y': return print(f'Creating and pushing a new tag `{tag}`.') c.run(f'git tag {tag}') c.run(f'git push origin {tag}') print(f'Refreshing {CURRENT_VERSION_FILE}. Push it to master after release') curr_ver(c, tag) @task def release(c, automa=False): tag = 'v' + __version__ if automa: print(f'Creating/updating release with assets for {PLATFORM} to version {tag}') else: print(f'New tag version for release will be: {tag}. is it OK?') if input('y/n').lower() != 'y': return repo = get_repo() for release in repo.get_releases(): if release.tag_name == tag and release.draft: draft_release = release break else: print('No draft release with given tag found.') if not automa: create_tag(c, tag) print(f'Creating new release for tag `{tag}`') draft_release = repo.create_git_release( tag=tag, name=__version__, message="draft", draft=True, prerelease=not automa ) build(c, output='build') test(c, target='build') asset_path = archive(c, target='build', zip_name=asset_name(tag, PLATFORM)) print(f'Uploading asset for {PLATFORM}: {asset_path}') draft_release.upload_asset(asset_path)