[ADD] Python packaging, through Arch's own bootstrap path
Three stage-2 builds -- brotli, libseccomp, meson -- stopped on
/usr/bin/python: No module named build
and building python-build means running `python -m build`. Its dependencies are
the same cycle: packaging and pyproject-hooks are flit_core-backed, installing a
wheel wants python-installer, and none of the six exist yet.
On the host the cycle was already broken -- apt had python3-build -- so stage 1
never met it. Breaking it there again is not possible: apt has no
python3-flit-core at all, so the backend all six need cannot be installed on the
host by any means.
Arch had already solved it, in the PKGBUILDs: `_bootstrap=1` selects a vendored
builder that needs none of the six. That is upstream's supported path through
exactly this situation, and it replaced a half-written alternative here -- three
bespoke hooks calling `python -m flit_core.wheel` and unzipping into $pkgdir --
which would have reimplemented what the PKGBUILD already does properly.
--- FR ---
Trois constructions d'étage 2 — brotli, libseccomp, meson — se sont arrêtées sur
/usr/bin/python: No module named build
et bâtir python-build suppose d'exécuter `python -m build`. Ses dépendances sont
le même cycle : packaging et pyproject-hooks passent par flit_core, installer une
roue demande python-installer, et aucun des six n'existe encore.
Sur l'hôte le cycle était déjà rompu — apt fournissait python3-build — donc
l'étage 1 ne l'a jamais rencontré. Le rompre à nouveau là est impossible : apt
n'a aucun python3-flit-core, donc le moteur dont les six ont besoin ne peut être
installé sur l'hôte par aucun moyen.
Arch l'avait déjà résolu, dans les PKGBUILD : `_bootstrap=1` sélectionne un
constructeur embarqué qui n'a besoin d'aucun des six. C'est la voie prévue en
amont pour exactement cette situation, et elle a remplacé une solution
à demi écrite ici — trois hooks sur mesure appelant `python -m flit_core.wheel`
puis dézippant dans $pkgdir — qui aurait réimplémenté ce que le PKGBUILD fait
déjà correctement.
Assisted-by: Claude Opus 5
2026-08-21 16:37:55 -04:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
# Arch's own escape hatch for the Python packaging cycle. Sourced by the six
|
|
|
|
|
# hooks that need it; not a hook itself.
|
|
|
|
|
#
|
|
|
|
|
# THE CYCLE. Three stage-2 builds -- brotli, libseccomp, meson -- stopped on
|
|
|
|
|
#
|
|
|
|
|
# /usr/bin/python: No module named build
|
|
|
|
|
#
|
|
|
|
|
# and building python-build means running `python -m build`, which is
|
|
|
|
|
# python-build. Its dependencies are the same: packaging and pyproject-hooks are
|
|
|
|
|
# flit_core-backed, installing a wheel wants python-installer, and none of them
|
|
|
|
|
# exist yet.
|
|
|
|
|
#
|
|
|
|
|
# On the host the cycle was already broken -- apt had python3-build -- so stage 1
|
|
|
|
|
# never met it. Trying to break it there again failed for a reason worth
|
|
|
|
|
# recording: `apt-cache policy python3-flit-core` returns no candidate at all.
|
|
|
|
|
# Ubuntu does not package it, so the backend every one of these needs cannot be
|
|
|
|
|
# installed on the host by any means. Our own python-flit-core builds fine, but
|
|
|
|
|
# building a package is not installing it.
|
|
|
|
|
#
|
|
|
|
|
# ARCH ALREADY SOLVED THIS, and the solution is in the PKGBUILDs:
|
|
|
|
|
#
|
|
|
|
|
# if (( _bootstrap == 0 )); then
|
|
|
|
|
# python -m build -wn --skip-dependency-check
|
|
|
|
|
# else
|
|
|
|
|
# cd python-bootstrap
|
|
|
|
|
# python -m bootstrap.build
|
|
|
|
|
# fi
|
|
|
|
|
#
|
|
|
|
|
# python-bootstrap is a vendored builder that needs none of the six. Setting
|
|
|
|
|
# _bootstrap=1 is upstream's supported path through exactly this situation --
|
|
|
|
|
# far better than the alternative that was half-written here first, which was a
|
|
|
|
|
# per-package hook calling `python -m flit_core.wheel` and unzipping the result
|
|
|
|
|
# into $pkgdir by hand. That would have been three bespoke reimplementations of
|
|
|
|
|
# something the PKGBUILD already does properly.
|
|
|
|
|
#
|
|
|
|
|
# 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
|
[FIX] the Python bootstrap installed older code than it claimed
python-packaging's PKGBUILD says pkgver=26.3 and the installed module reported
25.0. The vendored builder selected by _bootstrap=1 carries its OWN copy of each
project, older than the release the PKGBUILD names. Nothing about the package
looked wrong; only `packaging.__version__` disagreed with its own name, 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.
_bootstrap is now a probe evaluated by makepkg, in the build environment: if
`build` and `installer` import, the real path works and the vendored copies are
not wanted. A hook could not decide this -- hooks run on the HOST even for stage
2, so a probe written there cannot answer for the chroot.
The license install then had to handle both layouts, since the source tree is a
git clone under $pkgname when bootstrapping and a release tarball otherwise.
Hardcoding either breaks the other, and this hook had hardcoded the clone -- right
only while _bootstrap was always 1.
--- FR ---
Le PKGBUILD de python-packaging annonce pkgver=26.3 et le module installé
rapportait 25.0. Le constructeur embarqué que sélectionne _bootstrap=1 porte ses
PROPRES copies de chaque projet, plus anciennes que la version nommée. Rien dans
le paquet n'avait l'air faux ; seul `packaging.__version__` contredisait son
propre nom, et l'écart est apparu deux paquets plus loin :
python-vcs-versioning: packaging>=26.2
un plancher que notre paquet satisfaisait sur le papier et non en fait.
_bootstrap est désormais une sonde évaluée par makepkg, dans l'environnement de
construction : si `build` et `installer` s'importent, la voie normale fonctionne et
les copies embarquées ne sont pas voulues. Un hook ne pouvait pas trancher — les
hooks tournent sur l'HÔTE même pour l'étage 2, donc une sonde écrite là ne peut
pas répondre pour le chroot.
L'installation de la licence devait alors gérer les deux dispositions, l'arbre
source étant un clone git sous $pkgname en mode bootstrap et une archive sinon.
Écrire l'une en dur casse l'autre, et ce hook avait écrit le clone en dur — juste
seulement tant que _bootstrap valait toujours 1.
Assisted-by: Claude Opus 5
2026-08-23 23:50:06 -04:00
|
|
|
# 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.
|
[ADD] Python packaging, through Arch's own bootstrap path
Three stage-2 builds -- brotli, libseccomp, meson -- stopped on
/usr/bin/python: No module named build
and building python-build means running `python -m build`. Its dependencies are
the same cycle: packaging and pyproject-hooks are flit_core-backed, installing a
wheel wants python-installer, and none of the six exist yet.
On the host the cycle was already broken -- apt had python3-build -- so stage 1
never met it. Breaking it there again is not possible: apt has no
python3-flit-core at all, so the backend all six need cannot be installed on the
host by any means.
Arch had already solved it, in the PKGBUILDs: `_bootstrap=1` selects a vendored
builder that needs none of the six. That is upstream's supported path through
exactly this situation, and it replaced a half-written alternative here -- three
bespoke hooks calling `python -m flit_core.wheel` and unzipping into $pkgdir --
which would have reimplemented what the PKGBUILD already does properly.
--- FR ---
Trois constructions d'étage 2 — brotli, libseccomp, meson — se sont arrêtées sur
/usr/bin/python: No module named build
et bâtir python-build suppose d'exécuter `python -m build`. Ses dépendances sont
le même cycle : packaging et pyproject-hooks passent par flit_core, installer une
roue demande python-installer, et aucun des six n'existe encore.
Sur l'hôte le cycle était déjà rompu — apt fournissait python3-build — donc
l'étage 1 ne l'a jamais rencontré. Le rompre à nouveau là est impossible : apt
n'a aucun python3-flit-core, donc le moteur dont les six ont besoin ne peut être
installé sur l'hôte par aucun moyen.
Arch l'avait déjà résolu, dans les PKGBUILD : `_bootstrap=1` sélectionne un
constructeur embarqué qui n'a besoin d'aucun des six. C'est la voie prévue en
amont pour exactement cette situation, et elle a remplacé une solution
à demi écrite ici — trois hooks sur mesure appelant `python -m flit_core.wheel`
puis dézippant dans $pkgdir — qui aurait réimplémenté ce que le PKGBUILD fait
déjà correctement.
Assisted-by: Claude Opus 5
2026-08-21 16:37:55 -04:00
|
|
|
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)
|
[FIX] the Python bootstrap installed older code than it claimed
python-packaging's PKGBUILD says pkgver=26.3 and the installed module reported
25.0. The vendored builder selected by _bootstrap=1 carries its OWN copy of each
project, older than the release the PKGBUILD names. Nothing about the package
looked wrong; only `packaging.__version__` disagreed with its own name, 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.
_bootstrap is now a probe evaluated by makepkg, in the build environment: if
`build` and `installer` import, the real path works and the vendored copies are
not wanted. A hook could not decide this -- hooks run on the HOST even for stage
2, so a probe written there cannot answer for the chroot.
The license install then had to handle both layouts, since the source tree is a
git clone under $pkgname when bootstrapping and a release tarball otherwise.
Hardcoding either breaks the other, and this hook had hardcoded the clone -- right
only while _bootstrap was always 1.
--- FR ---
Le PKGBUILD de python-packaging annonce pkgver=26.3 et le module installé
rapportait 25.0. Le constructeur embarqué que sélectionne _bootstrap=1 porte ses
PROPRES copies de chaque projet, plus anciennes que la version nommée. Rien dans
le paquet n'avait l'air faux ; seul `packaging.__version__` contredisait son
propre nom, et l'écart est apparu deux paquets plus loin :
python-vcs-versioning: packaging>=26.2
un plancher que notre paquet satisfaisait sur le papier et non en fait.
_bootstrap est désormais une sonde évaluée par makepkg, dans l'environnement de
construction : si `build` et `installer` s'importent, la voie normale fonctionne et
les copies embarquées ne sont pas voulues. Un hook ne pouvait pas trancher — les
hooks tournent sur l'HÔTE même pour l'étage 2, donc une sonde écrite là ne peut
pas répondre pour le chroot.
L'installation de la licence devait alors gérer les deux dispositions, l'arbre
source étant un clone git sous $pkgname en mode bootstrap et une archive sinon.
Écrire l'une en dur casse l'autre, et ce hook avait écrit le clone en dur — juste
seulement tant que _bootstrap valait toujours 1.
Assisted-by: Claude Opus 5
2026-08-23 23:50:06 -04:00
|
|
|
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)
|
[ADD] Python packaging, through Arch's own bootstrap path
Three stage-2 builds -- brotli, libseccomp, meson -- stopped on
/usr/bin/python: No module named build
and building python-build means running `python -m build`. Its dependencies are
the same cycle: packaging and pyproject-hooks are flit_core-backed, installing a
wheel wants python-installer, and none of the six exist yet.
On the host the cycle was already broken -- apt had python3-build -- so stage 1
never met it. Breaking it there again is not possible: apt has no
python3-flit-core at all, so the backend all six need cannot be installed on the
host by any means.
Arch had already solved it, in the PKGBUILDs: `_bootstrap=1` selects a vendored
builder that needs none of the six. That is upstream's supported path through
exactly this situation, and it replaced a half-written alternative here -- three
bespoke hooks calling `python -m flit_core.wheel` and unzipping into $pkgdir --
which would have reimplemented what the PKGBUILD already does properly.
--- FR ---
Trois constructions d'étage 2 — brotli, libseccomp, meson — se sont arrêtées sur
/usr/bin/python: No module named build
et bâtir python-build suppose d'exécuter `python -m build`. Ses dépendances sont
le même cycle : packaging et pyproject-hooks passent par flit_core, installer une
roue demande python-installer, et aucun des six n'existe encore.
Sur l'hôte le cycle était déjà rompu — apt fournissait python3-build — donc
l'étage 1 ne l'a jamais rencontré. Le rompre à nouveau là est impossible : apt
n'a aucun python3-flit-core, donc le moteur dont les six ont besoin ne peut être
installé sur l'hôte par aucun moyen.
Arch l'avait déjà résolu, dans les PKGBUILD : `_bootstrap=1` sélectionne un
constructeur embarqué qui n'a besoin d'aucun des six. C'est la voie prévue en
amont pour exactement cette situation, et elle a remplacé une solution
à demi écrite ici — trois hooks sur mesure appelant `python -m flit_core.wheel`
puis dézippant dans $pkgdir — qui aurait réimplémenté ce que le PKGBUILD fait
déjà correctement.
Assisted-by: Claude Opus 5
2026-08-21 16:37:55 -04:00
|
|
|
io.open("PKGBUILD", "w", encoding="utf-8").write(s)
|
|
|
|
|
ZZPY
|
[FIX] the Python bootstrap installed older code than it claimed
python-packaging's PKGBUILD says pkgver=26.3 and the installed module reported
25.0. The vendored builder selected by _bootstrap=1 carries its OWN copy of each
project, older than the release the PKGBUILD names. Nothing about the package
looked wrong; only `packaging.__version__` disagreed with its own name, 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.
_bootstrap is now a probe evaluated by makepkg, in the build environment: if
`build` and `installer` import, the real path works and the vendored copies are
not wanted. A hook could not decide this -- hooks run on the HOST even for stage
2, so a probe written there cannot answer for the chroot.
The license install then had to handle both layouts, since the source tree is a
git clone under $pkgname when bootstrapping and a release tarball otherwise.
Hardcoding either breaks the other, and this hook had hardcoded the clone -- right
only while _bootstrap was always 1.
--- FR ---
Le PKGBUILD de python-packaging annonce pkgver=26.3 et le module installé
rapportait 25.0. Le constructeur embarqué que sélectionne _bootstrap=1 porte ses
PROPRES copies de chaque projet, plus anciennes que la version nommée. Rien dans
le paquet n'avait l'air faux ; seul `packaging.__version__` contredisait son
propre nom, et l'écart est apparu deux paquets plus loin :
python-vcs-versioning: packaging>=26.2
un plancher que notre paquet satisfaisait sur le papier et non en fait.
_bootstrap est désormais une sonde évaluée par makepkg, dans l'environnement de
construction : si `build` et `installer` s'importent, la voie normale fonctionne et
les copies embarquées ne sont pas voulues. Un hook ne pouvait pas trancher — les
hooks tournent sur l'HÔTE même pour l'étage 2, donc une sonde écrite là ne peut
pas répondre pour le chroot.
L'installation de la licence devait alors gérer les deux dispositions, l'arbre
source étant un clone git sous $pkgname en mode bootstrap et une archive sinon.
Écrire l'une en dur casse l'autre, et ce hook avait écrit le clone en dur — juste
seulement tant que _bootstrap valait toujours 1.
Assisted-by: Claude Opus 5
2026-08-23 23:50:06 -04:00
|
|
|
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; }
|
[ADD] Python packaging, through Arch's own bootstrap path
Three stage-2 builds -- brotli, libseccomp, meson -- stopped on
/usr/bin/python: No module named build
and building python-build means running `python -m build`. Its dependencies are
the same cycle: packaging and pyproject-hooks are flit_core-backed, installing a
wheel wants python-installer, and none of the six exist yet.
On the host the cycle was already broken -- apt had python3-build -- so stage 1
never met it. Breaking it there again is not possible: apt has no
python3-flit-core at all, so the backend all six need cannot be installed on the
host by any means.
Arch had already solved it, in the PKGBUILDs: `_bootstrap=1` selects a vendored
builder that needs none of the six. That is upstream's supported path through
exactly this situation, and it replaced a half-written alternative here -- three
bespoke hooks calling `python -m flit_core.wheel` and unzipping into $pkgdir --
which would have reimplemented what the PKGBUILD already does properly.
--- FR ---
Trois constructions d'étage 2 — brotli, libseccomp, meson — se sont arrêtées sur
/usr/bin/python: No module named build
et bâtir python-build suppose d'exécuter `python -m build`. Ses dépendances sont
le même cycle : packaging et pyproject-hooks passent par flit_core, installer une
roue demande python-installer, et aucun des six n'existe encore.
Sur l'hôte le cycle était déjà rompu — apt fournissait python3-build — donc
l'étage 1 ne l'a jamais rencontré. Le rompre à nouveau là est impossible : apt
n'a aucun python3-flit-core, donc le moteur dont les six ont besoin ne peut être
installé sur l'hôte par aucun moyen.
Arch l'avait déjà résolu, dans les PKGBUILD : `_bootstrap=1` sélectionne un
constructeur embarqué qui n'a besoin d'aucun des six. C'est la voie prévue en
amont pour exactement cette situation, et elle a remplacé une solution
à demi écrite ici — trois hooks sur mesure appelant `python -m flit_core.wheel`
puis dézippant dans $pkgdir — qui aurait réimplémenté ce que le PKGBUILD fait
déjà correctement.
Assisted-by: Claude Opus 5
2026-08-21 16:37:55 -04:00
|
|
|
# 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 || {
|
|
|
|
|
echo "python bootstrap: no bootstrap.build branch in this PKGBUILD" >&2; exit 1; }
|
|
|
|
|
echo "$(basename "$PWD"): _bootstrap=1 (Arch's vendored builder)"
|