""" This builder functions as a pseudo builder that instead downloads and installs a binary file using release-gitter based on a pyproject.toml file. It's a total hack... """ from __future__ import annotations from dataclasses import dataclass from pathlib import Path from shutil import copy from shutil import copytree from shutil import move from subprocess import check_call import toml from wheel.wheelfile import WheelFile import release_gitter as rg from release_gitter import removeprefix PACKAGE_NAME = "pseudo" @dataclass class Config: format: str git_url: str hostname: str owner: str repo: str version: str | None = None pre_release: bool = False version_git_tag: bool = False version_git_no_fetch: bool = False map_system: dict[str, str] | None = None map_arch: dict[str, str] | None = None exec: str | None = None extract_all: bool = False extract_files: list[str] | None = None include_extra_files: list[str] | None = None def download(config: Config, wheel_scripts: Path) -> list[Path]: release = rg.fetch_release( rg.GitRemoteInfo(config.hostname, config.owner, config.repo), config.version ) asset = rg.match_asset( release, config.format, version=config.version, system_mapping=config.map_system, arch_mapping=config.map_arch, ) files = rg.download_asset( asset, extract_files=config.extract_files, destination=wheel_scripts ) # Optionally execute post command if config.exec: check_call(config.exec, shell=True, cwd=wheel_scripts) return files def read_metadata() -> Config: config = toml.load("pyproject.toml").get("tool", {}).get("release-gitter") if not config: raise ValueError("Must have configuration in [tool.release-gitter]") git_url = config.pop("git-url", None) remote_info = rg.parse_git_remote(git_url) args = Config( format=config.pop("format"), git_url=git_url, hostname=config.pop("hostname", remote_info.hostname), owner=config.pop("owner", remote_info.owner), repo=config.pop("repo", remote_info.repo), ) for key, value in config.items(): setattr(args, str(key).replace("-", "_"), value) if args.version is None: args.version = rg.read_version( args.version_git_tag, not args.version_git_no_fetch, ) if args.extract_all: args.extract_files = [] return args class _PseudoBuildBackend: # Should allow passing args as `--build-option` _gitter_args = None def prepare_metadata_for_build_wheel( self, metadata_directory, config_settings=None ): # Create a .dist-info directory containing wheel metadata inside metadata_directory. Eg {metadata_directory}/{package}-{version}.dist-info/ print("Prepare meta", metadata_directory, config_settings) metadata = read_metadata() version = removeprefix(metadata.version, "v") if metadata.version else "0.0.0" # Returns distinfo dir? dist_info = Path(metadata_directory) / f"{PACKAGE_NAME}-{version}.dist-info" dist_info.mkdir() # Write metadata pkg_info = dist_info / "METADATA" pkg_info.write_text( "\n".join( [ "Metadata-Version: 2.1", f"Name: {PACKAGE_NAME}", f"Version: {version}", ] ) ) # Write wheel info wheel_info = dist_info / "WHEEL" wheel_info.write_text( "\n".join( [ "Wheel-Version: 1.0", "Root-Is-Purelib: true", "Tag: py2-none-any", "Tag: py3-none-any", ] ) ) return str(dist_info) def build_sdist(self, sdist_directory, config_settings=None): # Builds a .tar.gz and places it in specified sdist_directory # That should contain a toplevel drectory of `name-version` containing source files and the pyproject.toml # HACK: This isn't needed or used p = Path(sdist_directory + ".dist-info") return p def build_wheel( self, wheel_directory, config_settings=None, metadata_directory=None ): metadata_directory = Path(metadata_directory) metadata = read_metadata() version = removeprefix(metadata.version, "v") if metadata.version else "0.0.0" wheel_directory = Path(wheel_directory) wheel_directory.mkdir(exist_ok=True) wheel_scripts = wheel_directory / f"{PACKAGE_NAME}-{version}.data/scripts" wheel_scripts.mkdir(parents=True, exist_ok=True) copytree(metadata_directory, wheel_directory / metadata_directory.name) metadata = read_metadata() download(metadata, wheel_scripts) for file_name in metadata.include_extra_files or []: file = Path(file_name) if Path.cwd() in file.absolute().parents: copy(file_name, wheel_scripts / file) else: raise ValueError( f"Cannot include any path that is not within the current directory: {file_name}" ) print(f"ls {wheel_directory}: {list(wheel_directory.rglob('*'))}") wheel_filename = f"{PACKAGE_NAME}-{version}-py2.py3-none-any.whl" with WheelFile(wheel_directory / wheel_filename, "w") as wf: print("Repacking wheel as {}...".format(wheel_filename), end="") # sys.stdout.flush() wf.write_files(wheel_directory) return wheel_filename _BACKEND = _PseudoBuildBackend() prepare_metadata_for_build_wheel = _BACKEND.prepare_metadata_for_build_wheel build_sdist = _BACKEND.build_sdist build_wheel = _BACKEND.build_wheel