Skip to content

Commit

Permalink
ci(wrappers/python): more logging for python build scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
SKalt committed Sep 28, 2024
1 parent 7f670f0 commit 27032b2
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 23 deletions.
10 changes: 8 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,16 @@ jobs:
run: ./wrappers/python/scripts/ci/github/debug_python_paths.sh
- name: package binaries
working-directory: ./wrappers/python
run: python -m scripts.build.all ./vendor # should take ~30s
run: | # should take ~30s; writes wheels to wrappers/python/dist
export PAGEFIND_PYTHON_LOG_LEVEL=DEBUG
python -m scripts.build.all_binary_only_wheels \
--git-tag "${{ github.ref_name }}" \
--bin-dir ./vendor
- name: package python api
working-directory: ./wrappers/python
run: python3 -m scripts.build.api_package
run: | # writes stdist + wheel to wrappers/python/dist
export PAGEFIND_PYTHON_LOG_LEVEL=DEBUG
python -m scripts.build.api_package --tag "${{ github.ref_name }}"
- name: Archive dist
uses: actions/upload-artifact@v4
with:
Expand Down
4 changes: 2 additions & 2 deletions wrappers/python/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@

[tool.poetry]
name = "pagefind"
version = "0.0.0a0"
# note that ^this^ is the version number of the python API, not the version of
# the pagefind executable.
# note this^^^^^^^ version will be replaced by scripts/build/api_package.py
description = "Python API for Pagefind"
authors = ["CloudCannon"]
license = "MIT"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
"""A script that builds all the pagefind binary-only wheels."""

import os
import logging
import re
import tarfile
import tempfile
from pathlib import Path
from typing import List, Optional, Tuple
from typing import List, NamedTuple, Optional
from argparse import ArgumentParser

from . import dist_dir, setup_logging
Expand All @@ -21,9 +22,12 @@
"pagefind_extended.exe",
)

log = logging.getLogger(__name__)


def find_bin(dir: Path) -> Path:
for file in dir.iterdir():
log.debug("Checking for executable @ %s", (dir / file).absolute())
if file.is_file() and file.name in __candidates:
return file
raise FileNotFoundError(f"Could not find any of {__candidates} in {dir}")
Expand All @@ -36,6 +40,7 @@ def get_llvm_triple(tar_gz: Path) -> str:
llvm_triple = llvm_triple.removesuffix(".tar.gz")
llvm_triple = llvm_triple.removeprefix(f"pagefind-{tag_name}-")
llvm_triple = llvm_triple.removeprefix(f"pagefind_extended-{tag_name}-")
log.debug(f"derived llvm_triple {llvm_triple} from {tar_gz.name}")
return llvm_triple


Expand All @@ -51,36 +56,51 @@ def check_platforms(certified: List[Path]) -> None:
raise ValueError(err_message)


def parse_args() -> Tuple[bool, Optional[Path]]:
class Args(NamedTuple):
dry_run: bool
bin_dir: Optional[Path]
tag: Optional[str]


def parse_args() -> Args:
parser = ArgumentParser()
parser.add_argument("--tag", type=str, default=None)
parser.add_argument("--dry-run", action="store_true")
parser.add_argument("DIR", type=Path, default=None, nargs="?")
parser.add_argument("--bin-dir", type=Path, default=None)
args = parser.parse_args()
dry_run: bool = args.dry_run
bin_dir: Optional[Path] = args.DIR
return dry_run, bin_dir
bin_dir: Optional[Path] = args.bin_dir
tag: Optional[str] = args.tag
return Args(dry_run=dry_run, bin_dir=bin_dir, tag=tag)


if __name__ == "__main__":
dry_run, bin_dir = parse_args()
dry_run, bin_dir, tag_name = parse_args()
log.debug("args: dry_run=%s; bin_dir=%s; tag_name=%s", dry_run, bin_dir, tag_name)
setup_logging()
if bin_dir is None:
log.debug("no bin_dir specified, downloading latest release")
assert tag_name is None, f"--tag={tag_name} conflicts with downloading"
certified, tag_name = download("latest", dry_run=False)
else:
if os.environ.get("GIT_VERSION") is None:
raise KeyError("Missing DIR argument and GIT_VERSION environment variable")
else:
tag_name = os.environ["GIT_VERSION"]
certified = find_bins(bin_dir)
if tag_name is None:
raise ValueError("tag_name is None")
assert re.match(
r"^v\d+\.\d+\.\d+(-\w+)?", tag_name
), f"Invalid tag_name: {tag_name}"
check_platforms(certified)

if not dry_run:
dist_dir.rmdir()
dist_dir.mkdir(exist_ok=True)

for tar_gz in certified:
log.info("Processing %s", tar_gz)
llvm_triple = get_llvm_triple(tar_gz)
log.debug("llvm_triple=%s", llvm_triple)
platform = LLVM_TRIPLES_TO_PYTHON_WHEEL_PLATFORMS[llvm_triple]
log.debug("platform=%s", platform)
if platform is None:
raise ValueError(f"Unsupported platform: {llvm_triple}")
# TODO: avoid writing the extracted bin to disk
Expand Down
78 changes: 70 additions & 8 deletions wrappers/python/scripts/build/api_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,92 @@
# optional dependencies. It might be preferable to use setuptools directly rather than
# work around poetry.

from . import python_root, setup_logging
import logging
import subprocess
import re
import os
from argparse import ArgumentParser

from . import python_root, setup_logging

pyproject_toml = python_root / "pyproject.toml"

cli = ArgumentParser()
cli.add_argument("--dry-run", action="store_true")
cli.add_argument("--tag", required=True, help="The version to build.")
log = logging.getLogger(__name__)


def process_tag(tag: str) -> str:
"""Convert a git tag to a version string compliant with PEP 440.
See https://peps.python.org/pep-0440/#public-version-identifiers
"""
pattern = (
# note that this pattern accepts a superset of the tagging pattern used
# in this repository.
r"^v(?P<major>\d+)"
r"\.(?P<minor>\d+)"
r"\.(?P<patch>\d+)"
r"(-"
r"(?P<prerelease_kind>alpha|beta|rc)"
r"\.?(?P<prerelease_number>\d+)"
")?"
)
parts = re.match(pattern, tag)
if parts is None:
raise ValueError(f"Invalid tag: `{tag}` does not match pattern `{pattern}`")
major = int(parts["major"])
minor = int(parts["minor"])
patch = int(parts["patch"])
suffix = ""

if (prerelease_kind := parts["prerelease_kind"]) is not None:
if prerelease_kind == "rc":
suffix = "rc"
elif prerelease_kind.startswith("alpha"):
suffix = "a"
elif prerelease_kind.startswith("beta"):
suffix = "b"
if (prerelease_number := parts["prerelease_number"]) is not None:
suffix += str(int(prerelease_number))

return f"{major}.{minor}.{patch}{suffix}"


def main() -> None:
version = os.environ.get("PAGEFIND_VERSION")
if version is None:
version = "1"
setup_logging()
args = cli.parse_args()
tag: str = args.tag
dry_run: bool = args.dry_run
log.debug("args: dry_run=%s; tag=%s", dry_run, tag)
version = process_tag(tag)

log.info("Building version %s", version)
# create a pyproject.toml with updated versions
original = pyproject_toml.read_text()
temp = ""
for line in original.splitlines():
if line.endswith("#!!opt"):
line = line.removeprefix("# ") + "\n"
if "0.0.0a0" in line:
line = line.replace("0.0.0a0", version)
log.debug("patching: %s", line)
elif line.endswith("#!!opt"):
line = line.removeprefix("# ").removesuffix("#!!opt")
line = re.sub(r'version = "[^"]+"', f'version = "~={version}"', line)
log.debug("patching: %s", line)
temp += line + "\n"
log.debug("patched pyproject.toml", extra={"updated": temp})

if dry_run:
return

with pyproject_toml.open("w") as f:
f.write(temp)
log.debug("wrote patched pyproject.toml")

log.info("Building API package")
subprocess.run(["poetry", "build"], check=True)
with pyproject_toml.open("w") as f:
with pyproject_toml.open("w") as f: # restore the original
f.write(original)
log.debug("restored original pyproject.toml")


if __name__ == "__main__":
Expand Down

0 comments on commit 27032b2

Please sign in to comment.