Skip to content

Commit 29edfd5

Browse files
committed
Add python-as-wrapper package and use it in asciidoc build.
Hopefully the use here in asciidoc shows the usefulness of this wrapper. Many programs or build systems really want to use 'python3', but we really want them to use 'python3.X'. This wrapper package provides a compromise that gets rid of the "sticky" results of calling 'python3'. The big change is that now a program that uses 'python3' to write its scripts will write a shbang as '#!/usr/bin/python3.XX'
1 parent e32af5b commit 29edfd5

File tree

3 files changed

+179
-87
lines changed

3 files changed

+179
-87
lines changed

asciidoc.yaml

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package:
22
name: asciidoc
33
version: 10.2.1
4-
epoch: 1
4+
epoch: 2
55
description: "Text based documentation"
66
copyright:
77
- license: GPL-2.0-or-later
@@ -21,7 +21,8 @@ environment:
2121
- libxml2-utils
2222
- libxslt
2323
- py${{vars.py-version}}-pip
24-
- python-${{vars.py-version}}
24+
- python-${{vars.py-version}}-base
25+
- python3-as-${{vars.py-version}}
2526
- wolfi-base
2627

2728
pipeline:
@@ -31,10 +32,6 @@ pipeline:
3132
tag: ${{package.version}}
3233
expected-commit: 21e33efe96ba9a51d99d1150691dae750afd6ed1
3334

34-
- uses: patch
35-
with:
36-
patches: allow-specify-python.yaml
37-
3835
- runs: |
3936
autoreconf -fi
4037
@@ -47,12 +44,8 @@ pipeline:
4744
--infodir=/usr/share/info
4845
4946
- uses: autoconf/make
50-
with:
51-
opts: PYTHON=python${{vars.py-version}}
5247

5348
- uses: autoconf/make-install
54-
with:
55-
opts: PYTHON=python${{vars.py-version}}
5649

5750
update:
5851
enabled: true

asciidoc/allow-specify-python.yaml

Lines changed: 0 additions & 77 deletions
This file was deleted.

python-as-wrapper.yaml

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
package:
2+
name: python-as-wrapper
3+
version: 0.1.0
4+
epoch: 0
5+
description: Shell script wrapper to exec python3.XX
6+
copyright:
7+
- license: Apache-2.0
8+
9+
# In a "normal" installation of python, 'python3' is a symlink
10+
# to 'pythonX.Y' where X.Y is Major.Minor (3.13). In that scenario,
11+
# if caller invokes 'python3', then when python reads its sys.executable,
12+
# the executable is 'python3'.
13+
#
14+
# That value of sys.executable is "sticky" and finds its way into shbangs that
15+
# are installed with 'pip install' or other places.
16+
#
17+
# In the vast majority of places, we do not want shebang with
18+
# /usr/bin/python3 because at runtime:
19+
# * python3 might be a symlink to another python version
20+
# * python3 may not exist at all - with only python3.XX installed.
21+
#
22+
# Using the wrapper that this package provides if you do
23+
# 'python3 -m pip install pkg', then 'pkg's provided scripts will have
24+
# a shbang of /usr/bin/python3.XX.
25+
data:
26+
- name: py-versions
27+
items:
28+
3.10: '310'
29+
3.11: '311'
30+
3.12: '312'
31+
3.13: '313'
32+
- name: python-as-names
33+
items:
34+
python: PYTHON_AS
35+
python3: PYTHON3_AS
36+
37+
environment:
38+
contents:
39+
packages:
40+
- busybox
41+
42+
pipeline:
43+
- runs: |
44+
cat > write-strict <<"EOF"
45+
#!/bin/sh -e
46+
input="$1"
47+
outf="$2"
48+
mkdir -p "${outf%/*}"
49+
printf '#!/bin/sh\nexec "%s" "$@"\n' "$input" > "$outf"
50+
chmod 755 "$outf"
51+
EOF
52+
chmod 755 write-strict
53+
54+
cat > wrapper-env.tmpl <<"EOF"
55+
#!/bin/sh
56+
fail() { echo "FATAL:" "$0" "$@"; exit 9; }
57+
[ -n "${ENV_NAME}" ] || fail "invoked without ENV_NAME set"
58+
[ "$ENV_NAME" -ef "$0" ] && fail "invoked with ENV_NAME = $0"
59+
[ "${ENV_NAME}" != "${0##*/}" ] || fail "invoked with ENV_NAME = basename($0)"
60+
command -v "$ENV_NAME" >/dev/null ||
61+
fail "invoked with ENV_NAME=$ENV_NAME, but $ENV_NAME not found in PATH"
62+
exec "${ENV_NAME}" "$@"
63+
EOF
64+
65+
cat > write-env <<"EOF"
66+
#!/bin/sh -e
67+
input="$1"
68+
outf="$2"
69+
d=$(dirname "$0")
70+
tmpl="$d/wrapper-env.tmpl"
71+
[ -f "$tmpl" ] || { echo "no 'wrapper-env.tmpl' in dir '$d/'"; exit 1; }
72+
mkdir -p "${outf%/*}"
73+
sed "s,ENV_NAME,$input,g" "$tmpl" > "$outf"
74+
chmod 755 "$outf"
75+
EOF
76+
chmod 755 write-env
77+
78+
subpackages:
79+
- range: py-versions
80+
name: python3-as-${{range.key}}
81+
description: provides /usr/bin/python3 that execs python${{range.key}}
82+
dependencies:
83+
runtime:
84+
- python-${{range.key}}-base
85+
pipeline:
86+
- runs: |
87+
./write-strict "python${{range.key}}" ${{targets.contextdir}}/usr/bin/python3
88+
test:
89+
pipeline:
90+
- name: validate wrapper 'python3' for ${{range.key}}
91+
runs: |
92+
set +x
93+
tmpd=$(mktemp -d)
94+
tmpf="$tmpd/test-wrapper.py"
95+
trap "rm -r $tmpd" EXIT
96+
97+
cat >"$tmpf" <<"EOF"
98+
#!/usr/bin/env python3
99+
import os, sys
100+
assert "/usr/bin/python${{range.key}}" == sys.executable
101+
assert "${{range.key}}" == "%s.%s" % (sys.version_info.major, sys.version_info.minor)
102+
assert os.path.basename(sys.argv[0]) == "test-wrapper.py"
103+
assert len(sys.argv) == 3
104+
print("PASS: %s wrapped %s successfully" % (sys.argv[1], sys.executable))
105+
EOF
106+
chmod 755 "$tmpf"
107+
"$tmpf" python3 "argument 1"
108+
109+
- range: py-versions
110+
name: python-as-${{range.key}}
111+
description: provides /usr/bin/python that execs python${{range.key}}
112+
dependencies:
113+
runtime:
114+
- python-${{range.key}}-base
115+
pipeline:
116+
- runs: |
117+
./write-strict "python${{range.key}}" ${{targets.contextdir}}/usr/bin/python
118+
test:
119+
pipeline:
120+
- name: validate wrapper 'python' for ${{range.key}}
121+
runs: |
122+
set +x
123+
tmpd=$(mktemp -d)
124+
tmpf="$tmpd/test-wrapper.py"
125+
trap "rm -r $tmpd" EXIT
126+
127+
cat >"$tmpf" <<"EOF"
128+
#!/usr/bin/env python
129+
import os, sys
130+
assert "/usr/bin/python${{range.key}}" == sys.executable
131+
assert "${{range.key}}" == "%s.%s" % (sys.version_info.major, sys.version_info.minor)
132+
assert os.path.basename(sys.argv[0]) == "test-wrapper.py"
133+
assert len(sys.argv) == 3
134+
print("PASS: %s wrapped %s successfully" % (sys.argv[1], sys.executable))
135+
EOF
136+
chmod 755 "$tmpf"
137+
"$tmpf" python "argument 1"
138+
139+
- range: python-as-names
140+
name: ${{range.key}}-as-env
141+
description: provides /usr/bin/${{range.key}} that execs env var ${{range.value}}
142+
pipeline:
143+
- runs: |
144+
./write-env "${{range.value}}" ${{targets.contextdir}}/usr/bin/${{range.key}}
145+
test:
146+
pipeline:
147+
- name: validate wrapper '${{range.key}}'
148+
runs: |
149+
set +x
150+
fail() { echo "FAIL:" "$@"; exit 1; }
151+
p=/usr/bin/${{range.key}}
152+
[ -x "$p" ] || fail "$p is not executable file"
153+
echo "PASS: $p is executable"
154+
155+
env "${{range.value}}=true" "$p" &&
156+
echo "PASS: ${{range.value}}=true exited 0" ||
157+
fail "$p exited $? with ${{range.value}}=true"
158+
159+
env "${{range.value}}=false" "$p" &&
160+
fail "$p exited 0 with ${{range.value}}=false" ||
161+
echo "PASS: ${{range.value}}=false exited $?"
162+
163+
# test that bad values are caught by the wrapper
164+
# range.value here is 'python' or 'python3' which might cause recursive
165+
for val in bogus-prog-name ${{range.key}} /usr/bin/${{range.key}}; do
166+
out=$(env "${{range.value}}=$val" "$p" 2>&1) && rc=0 || rc=$?
167+
case "$rc" in
168+
9) echo "PASS: $p exited $rc with ${{range.value}}=$val";;
169+
*) echo "output: $out";
170+
fail "$p exited $rc with ${{range.value}}=$val";;
171+
esac
172+
done
173+
174+
update:
175+
enabled: false
176+
exclude-reason: No source to watch for the new versions - this is the source.

0 commit comments

Comments
 (0)