diff --git a/__init__.py b/__init__.py index 06efde69..5bea5ccd 100644 --- a/__init__.py +++ b/__init__.py @@ -5,6 +5,8 @@ import subprocess from shutil import which import pathlib +import json +import requests import bpy import addon_utils @@ -25,35 +27,92 @@ os.environ["SSL_CERT_FILE"] = certifi.where() os.environ["REQUESTS_CA_BUNDLE"] = certifi.where() +def get_wheel_filename(package_name, target_folder): + # Get the current Python version and architecture + python_version = sys.version_info + python_version_str = f'cp{python_version.major}{python_version.minor}' + architecture = None + machine = None + if platform.system() == "Darwin": + architecture = 'macosx_' + machine = platform.machine() + elif platform.system() == "Linux": + architecture = 'manylinux_' + machine = 'x86_64' + elif platform.system() == "Windows": + architecture = 'win_' # including the underscore just to be safe this never pops up elsewhere in the future, 'win' is a pretty short string and common term + machine = 'amd64' + + if architecture is None or machine is None: + print('Warning: Platform could not be resolved in function get_wheel_filename(). Check is considered failed.') + return None + + # Fetch package metadata from PyPI + url = f'https://pypi.org/pypi/{package_name}/json' + response = requests.get(url) + if response.status_code != 200: + raise ValueError(f"Failed to fetch metadata for package '{package_name}'") + + # Extract latest version of the package + metadata = response.json() + versions = metadata['releases'] + latest = list(versions.keys())[-1] + + # Iterate through all versions and look for appropriate wheel files + for file in versions[latest]: + fname = file['filename'] + if fname.endswith('.whl'): + wheel_filename = fname + if python_version_str in file['python_version'] and architecture in fname and machine in fname: + return wheel_filename + + return None + +def is_latest_wheel_present(package_name, target_folder): + wheel_filename = get_wheel_filename(package_name, target_folder) + if wheel_filename: + wheel_path = os.path.join(target_folder, wheel_filename) + if os.path.exists(wheel_path): + return True + # Finally, if wheel_filename is None or os.path.exists() returned False + return False def install_pyluxcore(): # We cannot 'pip install' directly, as it would install pyluxcore system-wide # instead of in Blender environment # Blender has got its own logic for wheel installation, we'll rely on it - # Download wheel root_folder = pathlib.Path(__file__).parent.resolve() wheel_folder = root_folder / "wheels" - command = [ - sys.executable, - '-m', - 'pip', - 'download', - 'pyluxcore', - '-d', - wheel_folder - ] - process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = process.communicate() - output = stdout.decode() - error_output = stderr.decode() - if output: - print("Output:\n", output) - if error_output: - print("Errors:\n", error_output) - - if process.returncode != 0: - raise RuntimeError(f'Failed to download LuxCore with return code {result.returncode}.') from None + + # check if latest pyluxcore version has already been downloaded. + # If yes, skip the download to save time + pyluxcore_downloaded = is_latest_wheel_present('pyluxcore', wheel_folder) + if pyluxcore_downloaded: + print('Download of pyluxcore skipped, latest version was found on system') + else: + print('Downloading pyluxcore') + # Download wheel + command = [ + sys.executable, + '-m', + 'pip', + 'download', + 'pyluxcore', + '-d', + wheel_folder + ] + process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = process.communicate() + output = stdout.decode() + error_output = stderr.decode() + if output: + print("Output:\n", output) + if error_output: + print("Errors:\n", error_output) + + if process.returncode != 0: + raise RuntimeError(f'Failed to download LuxCore with return code {result.returncode}.') from None # Setup manifest with wheel list manifest_path = root_folder / "blender_manifest.toml"