2022-01-06 21:31:48 +00:00
|
|
|
"""
|
|
|
|
This builder functions as a pseudo builder that instead downloads and installs a binary file using
|
2022-01-06 23:10:17 +00:00
|
|
|
release-gitter based on a pyproject.toml file. It's a total hack...
|
2022-01-06 21:31:48 +00:00
|
|
|
"""
|
2024-05-14 21:14:57 +00:00
|
|
|
|
2022-06-30 20:46:04 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2023-10-27 00:35:33 +00:00
|
|
|
from dataclasses import dataclass
|
2022-01-06 21:31:48 +00:00
|
|
|
from pathlib import Path
|
2023-10-27 00:35:33 +00:00
|
|
|
from shutil import copy
|
2022-01-06 21:31:48 +00:00
|
|
|
from shutil import copytree
|
|
|
|
|
|
|
|
import toml
|
2022-01-06 21:49:07 +00:00
|
|
|
from wheel.wheelfile import WheelFile
|
2022-01-06 21:31:48 +00:00
|
|
|
|
|
|
|
import release_gitter as rg
|
|
|
|
|
|
|
|
|
2023-10-27 00:35:33 +00:00
|
|
|
@dataclass
|
|
|
|
class Config:
|
2024-11-07 00:16:27 +00:00
|
|
|
name: str
|
2023-10-27 00:35:33 +00:00
|
|
|
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
|
|
|
|
|
|
|
|
|
2024-10-31 20:19:47 +00:00
|
|
|
def download(config: Config, wheel_scripts: Path) -> list[Path]:
|
2024-11-07 00:21:19 +00:00
|
|
|
"""Download and extract files to the wheel_scripts directory"""
|
|
|
|
return rg.download_release(
|
|
|
|
rg.GitRemoteInfo(config.hostname, config.owner, config.repo),
|
|
|
|
wheel_scripts,
|
2022-01-06 21:31:48 +00:00
|
|
|
config.format,
|
|
|
|
version=config.version,
|
|
|
|
system_mapping=config.map_system,
|
|
|
|
arch_mapping=config.map_arch,
|
2024-11-07 00:21:19 +00:00
|
|
|
extract_files=config.extract_files,
|
|
|
|
pre_release=config.pre_release,
|
|
|
|
exec=config.exec,
|
2022-01-06 21:31:48 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2023-10-27 00:35:33 +00:00
|
|
|
def read_metadata() -> Config:
|
2024-11-07 00:16:27 +00:00
|
|
|
"""Read configuration from pyproject.toml"""
|
|
|
|
pyproject = toml.load("pyproject.toml").get("tool", {}).get("release-gitter")
|
|
|
|
if not pyproject:
|
2022-01-06 21:31:48 +00:00
|
|
|
raise ValueError("Must have configuration in [tool.release-gitter]")
|
|
|
|
|
2024-11-07 00:16:27 +00:00
|
|
|
git_url = pyproject.pop("git-url", None)
|
2023-10-27 00:35:33 +00:00
|
|
|
remote_info = rg.parse_git_remote(git_url)
|
|
|
|
|
2024-11-07 00:16:27 +00:00
|
|
|
config = Config(
|
|
|
|
name=pyproject.pop("name", remote_info.repo),
|
|
|
|
format=pyproject.pop("format"),
|
2023-10-27 00:35:33 +00:00
|
|
|
git_url=git_url,
|
2024-11-07 00:16:27 +00:00
|
|
|
hostname=pyproject.pop("hostname", remote_info.hostname),
|
|
|
|
owner=pyproject.pop("owner", remote_info.owner),
|
|
|
|
repo=pyproject.pop("repo", remote_info.repo),
|
2023-10-27 00:35:33 +00:00
|
|
|
)
|
|
|
|
|
2024-11-07 00:16:27 +00:00
|
|
|
for key, value in pyproject.items():
|
|
|
|
setattr(config, str(key).replace("-", "_"), value)
|
2022-01-06 21:31:48 +00:00
|
|
|
|
2024-11-07 00:16:27 +00:00
|
|
|
if config.version is None:
|
|
|
|
config.version = rg.read_version(
|
|
|
|
config.version_git_tag,
|
|
|
|
not config.version_git_no_fetch,
|
2023-10-27 00:35:33 +00:00
|
|
|
)
|
|
|
|
|
2024-11-07 00:16:27 +00:00
|
|
|
if config.extract_all:
|
|
|
|
config.extract_files = []
|
2023-10-27 00:35:33 +00:00
|
|
|
|
2024-11-07 00:16:27 +00:00
|
|
|
return config
|
2022-01-06 21:31:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
class _PseudoBuildBackend:
|
|
|
|
# Should allow passing args as `--build-option`
|
|
|
|
_gitter_args = None
|
|
|
|
|
2022-01-06 21:49:07 +00:00
|
|
|
def prepare_metadata_for_build_wheel(
|
|
|
|
self, metadata_directory, config_settings=None
|
|
|
|
):
|
2023-10-27 00:35:33 +00:00
|
|
|
# Create a .dist-info directory containing wheel metadata inside metadata_directory. Eg {metadata_directory}/{package}-{version}.dist-info/
|
2022-01-06 21:31:48 +00:00
|
|
|
print("Prepare meta", metadata_directory, config_settings)
|
|
|
|
|
|
|
|
metadata = read_metadata()
|
2024-11-07 19:47:33 +00:00
|
|
|
version = metadata.version.removeprefix("v") if metadata.version else "0.0.0"
|
2022-01-06 21:31:48 +00:00
|
|
|
|
|
|
|
# Returns distinfo dir?
|
2024-11-07 00:16:27 +00:00
|
|
|
dist_info = Path(metadata_directory) / f"{metadata.name}-{version}.dist-info"
|
2022-01-06 21:31:48 +00:00
|
|
|
dist_info.mkdir()
|
|
|
|
|
|
|
|
# Write metadata
|
|
|
|
pkg_info = dist_info / "METADATA"
|
2022-01-06 21:49:07 +00:00
|
|
|
pkg_info.write_text(
|
|
|
|
"\n".join(
|
|
|
|
[
|
|
|
|
"Metadata-Version: 2.1",
|
2024-11-07 00:16:27 +00:00
|
|
|
f"Name: {metadata.name}",
|
2022-01-06 21:49:07 +00:00
|
|
|
f"Version: {version}",
|
|
|
|
]
|
|
|
|
)
|
|
|
|
)
|
2022-01-06 21:31:48 +00:00
|
|
|
|
|
|
|
# Write wheel info
|
|
|
|
wheel_info = dist_info / "WHEEL"
|
2022-01-06 21:49:07 +00:00
|
|
|
wheel_info.write_text(
|
|
|
|
"\n".join(
|
|
|
|
[
|
|
|
|
"Wheel-Version: 1.0",
|
|
|
|
"Root-Is-Purelib: true",
|
|
|
|
"Tag: py2-none-any",
|
|
|
|
"Tag: py3-none-any",
|
|
|
|
]
|
|
|
|
)
|
|
|
|
)
|
2022-01-06 21:31:48 +00:00
|
|
|
|
|
|
|
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
|
2022-01-06 21:49:07 +00:00
|
|
|
p = Path(sdist_directory + ".dist-info")
|
2022-01-06 21:31:48 +00:00
|
|
|
return p
|
|
|
|
|
2022-01-06 21:49:07 +00:00
|
|
|
def build_wheel(
|
|
|
|
self, wheel_directory, config_settings=None, metadata_directory=None
|
|
|
|
):
|
2024-11-07 00:16:27 +00:00
|
|
|
if metadata_directory is None:
|
|
|
|
raise ValueError("Cannot build wheel without metadata_directory")
|
2022-01-06 21:31:48 +00:00
|
|
|
metadata_directory = Path(metadata_directory)
|
|
|
|
|
|
|
|
metadata = read_metadata()
|
2024-11-07 19:47:33 +00:00
|
|
|
version = metadata.version.removeprefix("v") if metadata.version else "0.0.0"
|
2022-01-06 21:31:48 +00:00
|
|
|
|
|
|
|
wheel_directory = Path(wheel_directory)
|
|
|
|
wheel_directory.mkdir(exist_ok=True)
|
|
|
|
|
2024-11-07 00:16:27 +00:00
|
|
|
wheel_scripts = wheel_directory / f"{metadata.name}-{version}.data/scripts"
|
2022-01-06 21:31:48 +00:00
|
|
|
wheel_scripts.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
|
|
copytree(metadata_directory, wheel_directory / metadata_directory.name)
|
|
|
|
|
|
|
|
metadata = read_metadata()
|
2024-10-31 20:19:47 +00:00
|
|
|
download(metadata, wheel_scripts)
|
2022-01-06 21:31:48 +00:00
|
|
|
|
2023-10-27 00:35:33 +00:00
|
|
|
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('*'))}")
|
2022-01-06 21:31:48 +00:00
|
|
|
|
2024-11-07 00:16:27 +00:00
|
|
|
wheel_filename = f"{metadata.name}-{version}-py2.py3-none-any.whl"
|
2022-01-06 21:49:07 +00:00
|
|
|
with WheelFile(wheel_directory / wheel_filename, "w") as wf:
|
|
|
|
print("Repacking wheel as {}...".format(wheel_filename), end="")
|
2022-01-06 21:31:48 +00:00
|
|
|
# sys.stdout.flush()
|
2024-11-07 00:16:27 +00:00
|
|
|
wf.write_files(str(wheel_directory))
|
2022-01-06 21:31:48 +00:00
|
|
|
|
|
|
|
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
|