diff --git a/patches/pkgbuild/lib-python-bootstrap.sh b/patches/pkgbuild/lib-python-bootstrap.sh index d004cf2..9c61031 100755 --- a/patches/pkgbuild/lib-python-bootstrap.sh +++ b/patches/pkgbuild/lib-python-bootstrap.sh @@ -37,16 +37,41 @@ # It also means these build on the HOST, where they had failed, so they need no # stage-2 special handling at all. set -euo pipefail +# A PROBE, not a constant, and it runs in the BUILD ENVIRONMENT. +# +# The first version set _bootstrap=1 unconditionally. That is right on a machine +# with no Python packaging stack and wrong the moment there is one, because the +# vendored builder carries its OWN copy of each project -- older than the +# PKGBUILD's pkgver. python-packaging was labelled 26.3 and installed 25.0, and +# the mismatch surfaced two packages later: +# +# python-vcs-versioning: packaging>=26.2 +# +# a floor our own package met on paper and not in fact. Nothing about the +# installed package looked wrong; only `import packaging; packaging.__version__` +# disagreed with its name. +# +# So the PKGBUILD decides at build time, where the answer is knowable: if `build` +# and `installer` import, the real path works and the vendored copies are not +# wanted. Hooks run on the HOST even for stage 2, so a probe written here could +# not answer for the chroot -- this one is evaluated by makepkg, inside it. python3 - <<'ZZPY' import io s = io.open("PKGBUILD", encoding="utf-8").read() old = "_bootstrap=0" assert s.count(old) == 1, "python bootstrap: expected one _bootstrap=0, got %d" % s.count(old) -s = s.replace(old, "_bootstrap=1 # see patches/pkgbuild/lib-python-bootstrap.sh", 1) +new = ("# Bootstrap only when the real path is unavailable -- see\n" + "# patches/pkgbuild/lib-python-bootstrap.sh. Evaluated by makepkg, in the\n" + "# build environment, because that is where the answer lives.\n" + "_bootstrap=1\n" + "python -c 'import build, installer' >/dev/null 2>&1 && _bootstrap=0") +s = s.replace(old, new, 1) io.open("PKGBUILD", "w", encoding="utf-8").write(s) ZZPY -grep -q "^_bootstrap=1" PKGBUILD || { - echo "python bootstrap: _bootstrap was not switched" >&2; exit 1; } +grep -q "^_bootstrap=1$" PKGBUILD || { + echo "python bootstrap: the default was not set to 1" >&2; exit 1; } +grep -q "import build, installer" PKGBUILD || { + echo "python bootstrap: the probe was not inserted" >&2; exit 1; } # The branch it selects must actually exist, or the switch silently builds # nothing -- these PKGBUILDs are not required to have both halves. grep -q "bootstrap.build" PKGBUILD || { diff --git a/patches/pkgbuild/python-packaging.sh b/patches/pkgbuild/python-packaging.sh index 7639dd7..a18afc6 100755 --- a/patches/pkgbuild/python-packaging.sh +++ b/patches/pkgbuild/python-packaging.sh @@ -23,10 +23,34 @@ import io, re lines = io.open("PKGBUILD", encoding="utf-8").read().split("\n") hit = [i for i, l in enumerate(lines) if "LICENSE*" in l and "$_name-$pkgver" in l] assert len(hit) == 1, "python-packaging: expected one license install, got %d" % len(hit) -lines[hit[0]] = lines[hit[0]].replace("$srcdir/$_name-$pkgver/LICENSE*", - "$srcdir/$pkgname/LICENSE*") +# BOTH LAYOUTS, because _bootstrap is now a probe rather than a constant +# (see lib-python-bootstrap.sh). With the vendored builder the sources are git +# clones under $srcdir/$pkgname; without it they are the release tarball under +# $srcdir/$_name-$pkgver. Hardcoding either one breaks the other, and the first +# version of this hook hardcoded the clone -- correct only while _bootstrap was +# always 1. +lines[hit[0]] = re.sub( + r"\$srcdir/\$_name-\$pkgver/LICENSE\*", + '"$srcdir/$pkgname"/LICENSE* "$srcdir/$_name-$pkgver"/LICENSE*', + lines[hit[0]]) +# install -t with two globs would fail on whichever does not exist, so the +# whole line becomes a loop over what is actually there. +ind = re.match(r"^[ \t]*", lines[hit[0]]).group(0) +lines[hit[0]:hit[0] + 1] = [ + ind + '# The sources are a git clone under $pkgname when the vendored builder', + ind + '# is used, and the release tarball otherwise. Take whichever exists.', + ind + 'for _lic in "$srcdir/$pkgname"/LICENSE* "$srcdir/$_name-$pkgver"/LICENSE*; do', + ind + ' [ -f "$_lic" ] && install -vDm644 "$_lic" -t "$pkgdir/usr/share/licenses/$pkgname"', + ind + 'done', +] io.open("PKGBUILD", "w", encoding="utf-8").write("\n".join(lines)) ZZPY -grep -q 'srcdir/\$pkgname/LICENSE\*' PKGBUILD || { - echo "python-packaging: the license path was not redirected" >&2; exit 1; } +grep -q 'Take whichever exists' PKGBUILD || { + echo "python-packaging: the license loop was not inserted" >&2; exit 1; } +# Matched against what is actually written -- the inserted line quotes the +# directory, `"$srcdir/$_name-$pkgver"/LICENSE*`, so a pattern expecting the +# slash to follow $pkgver directly finds nothing. The first version of this guard +# did exactly that and failed on a correct file. +grep -q '_name-\$pkgver"/LICENSE\*' PKGBUILD || { + echo "python-packaging: the tarball layout was dropped" >&2; exit 1; } echo "python-packaging: license taken from the bootstrap clone"