ModuleUpdate/Setup: install pkg_resources, check pip, typing and cleanup (#1593)

* ModuleUpdater/setup: install pkg_resources and check for pip

plus minor cleanup in the github actions

* ModuleUpdate/setup: make flake8 happy

* ModuleUpdate/setup: make mypy happier
This commit is contained in:
black-sliver 2023-03-25 19:54:42 +01:00 committed by GitHub
parent 67eb370200
commit ffd7d5da74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 77 additions and 32 deletions

View File

@ -36,8 +36,7 @@ jobs:
Expand-Archive -Path enemizer.zip -DestinationPath EnemizerCLI -Force Expand-Archive -Path enemizer.zip -DestinationPath EnemizerCLI -Force
- name: Build - name: Build
run: | run: |
python -m pip install --upgrade pip setuptools python -m pip install --upgrade pip
pip install -r requirements.txt
python setup.py build_exe --yes python setup.py build_exe --yes
$NAME="$(ls build)".Split('.',2)[1] $NAME="$(ls build)".Split('.',2)[1]
$ZIP_NAME="Archipelago_$NAME.7z" $ZIP_NAME="Archipelago_$NAME.7z"
@ -85,8 +84,7 @@ jobs:
# charset-normalizer was somehow incomplete in the github runner # charset-normalizer was somehow incomplete in the github runner
"${{ env.PYTHON }}" -m venv venv "${{ env.PYTHON }}" -m venv venv
source venv/bin/activate source venv/bin/activate
"${{ env.PYTHON }}" -m pip install --upgrade pip PyGObject setuptools charset-normalizer "${{ env.PYTHON }}" -m pip install --upgrade pip PyGObject charset-normalizer
pip install -r requirements.txt
python setup.py build_exe --yes bdist_appimage --yes python setup.py build_exe --yes bdist_appimage --yes
echo -e "setup.py build output:\n `ls build`" echo -e "setup.py build output:\n `ls build`"
echo -e "setup.py dist output:\n `ls dist`" echo -e "setup.py dist output:\n `ls dist`"

View File

@ -12,7 +12,7 @@ on:
- '**.py' - '**.py'
jobs: jobs:
build: flake8:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -25,7 +25,7 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: | run: |
python -m pip install --upgrade pip wheel python -m pip install --upgrade pip wheel
pip install flake8 pytest pytest-subtests pip install flake8
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Lint with flake8 - name: Lint with flake8
run: | run: |

View File

@ -63,9 +63,8 @@ jobs:
# charset-normalizer was somehow incomplete in the github runner # charset-normalizer was somehow incomplete in the github runner
"${{ env.PYTHON }}" -m venv venv "${{ env.PYTHON }}" -m venv venv
source venv/bin/activate source venv/bin/activate
"${{ env.PYTHON }}" -m pip install --upgrade pip PyGObject setuptools charset-normalizer "${{ env.PYTHON }}" -m pip install --upgrade pip PyGObject charset-normalizer
pip install -r requirements.txt python setup.py build_exe --yes bdist_appimage --yes
python setup.py build --yes bdist_appimage --yes
echo -e "setup.py build output:\n `ls build`" echo -e "setup.py build output:\n `ls build`"
echo -e "setup.py dist output:\n `ls dist`" echo -e "setup.py dist output:\n `ls dist`"
cd dist && export APPIMAGE_NAME="`ls *.AppImage`" && cd .. cd dist && export APPIMAGE_NAME="`ls *.AppImage`" && cd ..

View File

@ -52,8 +52,8 @@ jobs:
python-version: ${{ matrix.python.version }} python-version: ${{ matrix.python.version }}
- name: Install dependencies - name: Install dependencies
run: | run: |
python -m pip install --upgrade pip wheel python -m pip install --upgrade pip
pip install flake8 pytest pytest-subtests pip install pytest pytest-subtests
python ModuleUpdate.py --yes --force --append "WebHostLib/requirements.txt" python ModuleUpdate.py --yes --force --append "WebHostLib/requirements.txt"
- name: Unittests - name: Unittests
run: | run: |

View File

@ -1,7 +1,6 @@
import os import os
import sys import sys
import subprocess import subprocess
import pkg_resources
import warnings import warnings
local_dir = os.path.dirname(__file__) local_dir = os.path.dirname(__file__)
@ -22,18 +21,50 @@ if not update_ran:
requirements_files.add(req_file) requirements_files.add(req_file)
def check_pip():
# detect if pip is available
try:
import pip # noqa: F401
except ImportError:
raise RuntimeError("pip not available. Please install pip.")
def confirm(msg: str):
try:
input(f"\n{msg}")
except KeyboardInterrupt:
print("\nAborting")
sys.exit(1)
def update_command(): def update_command():
check_pip()
for file in requirements_files: for file in requirements_files:
subprocess.call([sys.executable, '-m', 'pip', 'install', '-r', file, '--upgrade']) subprocess.call([sys.executable, "-m", "pip", "install", "-r", file, "--upgrade"])
def install_pkg_resources(yes=False):
try:
import pkg_resources # noqa: F401
except ImportError:
check_pip()
if not yes:
confirm("pkg_resources not found, press enter to install it")
subprocess.call([sys.executable, "-m", "pip", "install", "--upgrade", "setuptools"])
def update(yes=False, force=False): def update(yes=False, force=False):
global update_ran global update_ran
if not update_ran: if not update_ran:
update_ran = True update_ran = True
if force: if force:
update_command() update_command()
return return
install_pkg_resources(yes=yes)
import pkg_resources
for req_file in requirements_files: for req_file in requirements_files:
path = os.path.join(os.path.dirname(sys.argv[0]), req_file) path = os.path.join(os.path.dirname(sys.argv[0]), req_file)
if not os.path.exists(path): if not os.path.exists(path):
@ -52,7 +83,7 @@ def update(yes=False, force=False):
egg = egg.split(";", 1)[0].rstrip() egg = egg.split(";", 1)[0].rstrip()
if any(compare in egg for compare in ("==", ">=", ">", "<", "<=", "!=")): if any(compare in egg for compare in ("==", ">=", ">", "<", "<=", "!=")):
warnings.warn(f"Specifying version as #egg={egg} will become unavailable in pip 25.0. " warnings.warn(f"Specifying version as #egg={egg} will become unavailable in pip 25.0. "
"Use name @ url#version instead.", DeprecationWarning) "Use name @ url#version instead.", DeprecationWarning)
line = egg line = egg
else: else:
egg = "" egg = ""
@ -79,11 +110,7 @@ def update(yes=False, force=False):
if not yes: if not yes:
import traceback import traceback
traceback.print_exc() traceback.print_exc()
try: confirm(f"Requirement {requirement} is not satisfied, press enter to install it")
input(f"\nRequirement {requirement} is not satisfied, press enter to install it")
except KeyboardInterrupt:
print("\nAborting")
sys.exit(1)
update_command() update_command()
return return

View File

@ -12,7 +12,6 @@ import io
import json import json
import threading import threading
import subprocess import subprocess
import pkg_resources
from collections.abc import Iterable from collections.abc import Iterable
from hashlib import sha3_512 from hashlib import sha3_512
@ -22,12 +21,27 @@ from pathlib import Path
# This is a bit jank. We need cx-Freeze to be able to run anything from this script, so install it # This is a bit jank. We need cx-Freeze to be able to run anything from this script, so install it
try: try:
requirement = 'cx-Freeze>=6.14.7' requirement = 'cx-Freeze>=6.14.7'
pkg_resources.require(requirement) import pkg_resources
import cx_Freeze try:
except pkg_resources.ResolutionError: pkg_resources.require(requirement)
install_cx_freeze = False
except pkg_resources.ResolutionError:
install_cx_freeze = True
except ImportError:
install_cx_freeze = True
pkg_resources = None # type: ignore [assignment]
if install_cx_freeze:
# check if pip is available
try:
import pip # noqa: F401
except ImportError:
raise RuntimeError("pip not available. Please install pip.")
# install and import cx_freeze
if '--yes' not in sys.argv and '-y' not in sys.argv: if '--yes' not in sys.argv and '-y' not in sys.argv:
input(f'Requirement {requirement} is not satisfied, press enter to install it') input(f'Requirement {requirement} is not satisfied, press enter to install it')
subprocess.call([sys.executable, '-m', 'pip', 'install', requirement, '--upgrade']) subprocess.call([sys.executable, '-m', 'pip', 'install', requirement, '--upgrade'])
import pkg_resources
import cx_Freeze import cx_Freeze
# .build only exists if cx-Freeze is the right version, so we have to update/install that first before this line # .build only exists if cx-Freeze is the right version, so we have to update/install that first before this line
@ -120,6 +134,7 @@ def download_SNI():
print(f"No SNI found for system spec {platform_name} {machine_name}") print(f"No SNI found for system spec {platform_name} {machine_name}")
signtool: typing.Optional[str]
if os.path.exists("X:/pw.txt"): if os.path.exists("X:/pw.txt"):
print("Using signtool") print("Using signtool")
with open("X:/pw.txt", encoding="utf-8-sig") as f: with open("X:/pw.txt", encoding="utf-8-sig") as f:
@ -144,7 +159,7 @@ exes = [
target_name=c.frozen_name + (".exe" if is_windows else ""), target_name=c.frozen_name + (".exe" if is_windows else ""),
icon=icon_paths[c.icon], icon=icon_paths[c.icon],
base="Win32GUI" if is_windows and not c.cli else None base="Win32GUI" if is_windows and not c.cli else None
) for c in components if c.script_name ) for c in components if c.script_name and c.frozen_name
] ]
extra_data = ["LICENSE", "data", "EnemizerCLI", "host.yaml", "SNI"] extra_data = ["LICENSE", "data", "EnemizerCLI", "host.yaml", "SNI"]
@ -307,7 +322,6 @@ class BuildExeCommand(cx_Freeze.command.build_exe.BuildEXE):
# which should be ok # which should be ok
with zipfile.ZipFile(self.libfolder / "worlds" / (file_name + ".apworld"), "x", zipfile.ZIP_DEFLATED, with zipfile.ZipFile(self.libfolder / "worlds" / (file_name + ".apworld"), "x", zipfile.ZIP_DEFLATED,
compresslevel=9) as zf: compresslevel=9) as zf:
entry: os.DirEntry
for path in world_directory.rglob("*.*"): for path in world_directory.rglob("*.*"):
relative_path = os.path.join(*path.parts[path.parts.index("worlds")+1:]) relative_path = os.path.join(*path.parts[path.parts.index("worlds")+1:])
zf.write(path, relative_path) zf.write(path, relative_path)
@ -330,9 +344,9 @@ class BuildExeCommand(cx_Freeze.command.build_exe.BuildEXE):
for exe in self.distribution.executables: for exe in self.distribution.executables:
print(f"Signing {exe.target_name}") print(f"Signing {exe.target_name}")
os.system(signtool + os.path.join(self.buildfolder, exe.target_name)) os.system(signtool + os.path.join(self.buildfolder, exe.target_name))
print(f"Signing SNI") print("Signing SNI")
os.system(signtool + os.path.join(self.buildfolder, "SNI", "SNI.exe")) os.system(signtool + os.path.join(self.buildfolder, "SNI", "SNI.exe"))
print(f"Signing OoT Utils") print("Signing OoT Utils")
for exe_path in (("Compress", "Compress.exe"), ("Decompress", "Decompress.exe")): for exe_path in (("Compress", "Compress.exe"), ("Decompress", "Decompress.exe")):
os.system(signtool + os.path.join(self.buildfolder, "lib", "worlds", "oot", "data", *exe_path)) os.system(signtool + os.path.join(self.buildfolder, "lib", "worlds", "oot", "data", *exe_path))
@ -386,7 +400,8 @@ class AppImageCommand(setuptools.Command):
yes: bool yes: bool
def write_desktop(self): def write_desktop(self):
desktop_filename = self.app_dir / f'{self.app_id}.desktop' assert self.app_dir, "Invalid app_dir"
desktop_filename = self.app_dir / f"{self.app_id}.desktop"
with open(desktop_filename, 'w', encoding="utf-8") as f: with open(desktop_filename, 'w', encoding="utf-8") as f:
f.write("\n".join(( f.write("\n".join((
"[Desktop Entry]", "[Desktop Entry]",
@ -400,7 +415,8 @@ class AppImageCommand(setuptools.Command):
desktop_filename.chmod(0o755) desktop_filename.chmod(0o755)
def write_launcher(self, default_exe: Path): def write_launcher(self, default_exe: Path):
launcher_filename = self.app_dir / f'AppRun' assert self.app_dir, "Invalid app_dir"
launcher_filename = self.app_dir / "AppRun"
with open(launcher_filename, 'w', encoding="utf-8") as f: with open(launcher_filename, 'w', encoding="utf-8") as f:
f.write(f"""#!/bin/sh f.write(f"""#!/bin/sh
exe="{default_exe}" exe="{default_exe}"
@ -422,11 +438,12 @@ $APPDIR/$exe "$@"
launcher_filename.chmod(0o755) launcher_filename.chmod(0o755)
def install_icon(self, src: Path, name: typing.Optional[str] = None, symlink: typing.Optional[Path] = None): def install_icon(self, src: Path, name: typing.Optional[str] = None, symlink: typing.Optional[Path] = None):
assert self.app_dir, "Invalid app_dir"
try: try:
from PIL import Image from PIL import Image
except ModuleNotFoundError: except ModuleNotFoundError:
if not self.yes: if not self.yes:
input(f'Requirement PIL is not satisfied, press enter to install it') input("Requirement PIL is not satisfied, press enter to install it")
subprocess.call([sys.executable, '-m', 'pip', 'install', 'Pillow', '--upgrade']) subprocess.call([sys.executable, '-m', 'pip', 'install', 'Pillow', '--upgrade'])
from PIL import Image from PIL import Image
im = Image.open(src) im = Image.open(src)
@ -503,8 +520,12 @@ def find_libs(*args: str) -> typing.Sequence[typing.Tuple[str, str]]:
return (lib, lib_arch, lib_libc), path return (lib, lib_arch, lib_libc), path
if not hasattr(find_libs, "cache"): if not hasattr(find_libs, "cache"):
data = subprocess.run([shutil.which('ldconfig'), '-p'], capture_output=True, text=True).stdout.split('\n')[1:] ldconfig = shutil.which("ldconfig")
find_libs.cache = {k: v for k, v in (parse(line) for line in data if '=>' in line)} assert ldconfig, "Make sure ldconfig is in PATH"
data = subprocess.run([ldconfig, "-p"], capture_output=True, text=True).stdout.split("\n")[1:]
find_libs.cache = { # type: ignore [attr-defined]
k: v for k, v in (parse(line) for line in data if "=>" in line)
}
def find_lib(lib, arch, libc): def find_lib(lib, arch, libc):
for k, v in find_libs.cache.items(): for k, v in find_libs.cache.items():