Ian Fijolek
f9c462b94a
This also includes one fix that I discovered while improving the logging. Even if a git url was provided, release_gitter was lookig for a local package declaration (Cargo.toml) to identify the version. With this change, the url parsing and the local repo logic are split allowing for more detailed logging as well as avoiding this potential bug.
187 lines
5.8 KiB
Python
187 lines
5.8 KiB
Python
"""
|
|
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
|
|
|
|
import toml
|
|
from wheel.wheelfile import WheelFile
|
|
|
|
import release_gitter as rg
|
|
from release_gitter import removeprefix
|
|
|
|
|
|
@dataclass
|
|
class Config:
|
|
name: str
|
|
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]:
|
|
"""Download and extract files to the wheel_scripts directory"""
|
|
return rg.download_release(
|
|
rg.GitRemoteInfo(config.hostname, config.owner, config.repo),
|
|
wheel_scripts,
|
|
config.format,
|
|
version=config.version,
|
|
system_mapping=config.map_system,
|
|
arch_mapping=config.map_arch,
|
|
extract_files=config.extract_files,
|
|
pre_release=config.pre_release,
|
|
exec=config.exec,
|
|
)
|
|
|
|
|
|
def read_metadata() -> Config:
|
|
"""Read configuration from pyproject.toml"""
|
|
pyproject = toml.load("pyproject.toml").get("tool", {}).get("release-gitter")
|
|
if not pyproject:
|
|
raise ValueError("Must have configuration in [tool.release-gitter]")
|
|
|
|
git_url = pyproject.pop("git-url", None)
|
|
remote_info = rg.parse_git_url(git_url)
|
|
|
|
config = Config(
|
|
name=pyproject.pop("name", remote_info.repo),
|
|
format=pyproject.pop("format"),
|
|
git_url=git_url,
|
|
hostname=pyproject.pop("hostname", remote_info.hostname),
|
|
owner=pyproject.pop("owner", remote_info.owner),
|
|
repo=pyproject.pop("repo", remote_info.repo),
|
|
)
|
|
|
|
for key, value in pyproject.items():
|
|
setattr(config, str(key).replace("-", "_"), value)
|
|
|
|
if config.version is None:
|
|
config.version = rg.read_version(
|
|
config.version_git_tag,
|
|
not config.version_git_no_fetch,
|
|
)
|
|
|
|
if config.extract_all:
|
|
config.extract_files = []
|
|
|
|
return config
|
|
|
|
|
|
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"{metadata.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: {metadata.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
|
|
):
|
|
if metadata_directory is None:
|
|
raise ValueError("Cannot build wheel without metadata_directory")
|
|
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"{metadata.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"{metadata.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(str(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
|