Skip to content

Commit 370f85b

Browse files
rpardiniigorpecovnik
authored andcommitted
python3: do not rely on hostdeps python3-pip nor python3-dev; deploy pip via get-pip.py
- python3-pip implies a very old setuptools (which is system-wide and takes precedence) - python3-dev implies python3-distutils (which is long deprecated) - get-pip.py allows us to version pip in requirements.txt just like everything else - in the end this fixes the conundrum with pylibfdt / dtschema on Jammy - and, finally, the setuptools we specify in requirements.txt will be actually used
1 parent 1033729 commit 370f85b

File tree

3 files changed

+28
-32
lines changed

3 files changed

+28
-32
lines changed

lib/functions/general/python-tools.sh

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,6 @@ function prepare_python_and_pip() {
4646
# Construct the version string (e.g., "python3.12")
4747
python3_version_string="python$python3_version_majorminor"
4848

49-
# Check actual pip3 version
50-
# Note: we don't use "/usr/bin/pip3" at all, since it's commonly missing. instead "python -m pip"
51-
# The hostdep package python3-pip is still required, and other crazy might impact this.
52-
# We might need to install our own pip if it gets bad enough.
53-
declare pip3_version
54-
pip3_version="$("${python3_binary_path}" -m pip --version)"
55-
56-
# get the pip3 version number only (eg, "21.2.4" from "pip 21.2.4 from /usr/lib/python3/dist-packages/pip (python 3.9)")
57-
declare pip3_version_number
58-
pip3_version_number="$(echo "${pip3_version}" | cut -d' ' -f2)" # @TODO: brittle. how to do this better?
59-
display_alert "pip3 version" "${pip3_version_number}: '${pip3_version}'" "info"
60-
6149
# Hash the contents of the dependencies array + the Python version + the release
6250
declare python3_pip_dependencies_path
6351
declare python3_pip_dependencies_hash
@@ -66,8 +54,15 @@ function prepare_python_and_pip() {
6654
# Check for the existence of requirements.txt, fail if not found
6755
[[ ! -f "${python3_pip_dependencies_path}" ]] && exit_with_error "Python Pip requirements.txt file not found at path: ${python3_pip_dependencies_path}"
6856

57+
# We will install our own pip; we don't want to rely on the host's pip version, as that implies old setuptools etc.
58+
# Parse the pip version from the requirements.txt file; use grep to find the line starting with "pip == "
59+
# Example line: "pip == 25.0.1 # pip is the package installer for Python" so get rid of comments
60+
declare pip3_version_number="undetermined"
61+
pip3_version_number=$(grep -E "^pip[[:space:]]*==" "${python3_pip_dependencies_path}" | cut -d'=' -f3 | cut -d'#' -f 1 | tr -d '[:space:]')
62+
display_alert "pip3 version" "${pip3_version_number}" "info"
63+
6964
# Calculate the hash for the Pip requirements
70-
python3_pip_dependencies_hash="$(echo "${HOSTRELEASE}" "${python3_version}" "${pip3_version}" "$(cat "${python3_pip_dependencies_path}")" | sha256sum | cut -d' ' -f1)"
65+
python3_pip_dependencies_hash="$(echo "${HOSTRELEASE}" "${python3_version}" "${pip3_version_number}" "$(cat "${python3_pip_dependencies_path}")" | sha256sum | cut -d' ' -f1)"
7166

7267
declare non_cache_dir="/armbian-pip"
7368
declare python_pip_cache="${SRC}/cache/pip"
@@ -83,16 +78,8 @@ function prepare_python_and_pip() {
8378
fi
8479
fi
8580

86-
declare -a pip3_extra_args=("--no-warn-script-location" "--user")
87-
# if pip 23+, add "--break-system-packages" to pip3 invocations.
88-
# See See PEP 668 -- System-wide package management with pip
89-
# but the fact is that we're _not_ managing system-wide, instead --user
90-
if linux-version compare "${pip3_version_number}" ge "23.0"; then
91-
pip3_extra_args+=("--break-system-packages")
92-
fi
93-
if linux-version compare "${pip3_version_number}" ge "22.1"; then
94-
pip3_extra_args+=("--root-user-action=ignore")
95-
fi
81+
# we run as root, but with --user; --break-system-packages is required due to PEP 668 (no system packages are installed here anyway)
82+
declare -a pip3_extra_args=("--no-warn-script-location" "--user" "--root-user-action=ignore" "--break-system-packages")
9683

9784
declare python_hash_base="${python_pip_cache}/pip_pkg_hash"
9885
declare python_hash_file="${python_hash_base}_${python3_pip_dependencies_hash}"
@@ -110,11 +97,13 @@ function prepare_python_and_pip() {
11097
[REQUIREMENTS_PATH]="${python3_pip_dependencies_path}"
11198
[VERSION]="${python3_version}"
11299
[VERSION_STRING]="${python3_version_string}"
113-
[PIP_VERSION]="${pip3_version}"
100+
[PIP_VERSION]="${pip3_version_number}"
101+
[GET_PIP_BIN]="${PYTHON3_INFO[USERBASE]}/bin/get-pip-${pip3_version_number}.py"
114102
)
115103

116104
# declare a readonly global array for ENV vars to invoke python3 with
117105
declare -r -g -a PYTHON3_VARS=(
106+
"PYTHONPATH=/does/not/exist/armbian/uses/user/packages/only"
118107
"PYTHONUSERBASE=${PYTHON3_INFO[USERBASE]}"
119108
"PYTHONUNBUFFERED=yes"
120109
"PYTHONPYCACHEPREFIX=${PYTHON3_INFO[PYCACHEPREFIX]}"
@@ -129,6 +118,18 @@ function prepare_python_and_pip() {
129118
# remove the old hashes matching base, don't leave junk behind
130119
run_host_command_logged rm -fv "${python_hash_base}*"
131120

121+
# If get-pip.py is not present, download it, using curl.
122+
if [[ ! -f "${PYTHON3_INFO[GET_PIP_BIN]}" ]]; then
123+
display_alert "Downloading get-pip.py" "from https://bootstrap.pypa.io/get-pip.py" "info"
124+
run_host_command_logged curl -sSL -o "${PYTHON3_INFO[GET_PIP_BIN]}" "https://bootstrap.pypa.io/get-pip.py"
125+
fi
126+
127+
# Install pip, using get-pip.py; that bootstraps pip using an embedded, temporary, pip contained in get-pip.py
128+
display_alert "Installing pip using get-pip.py" "${pip3_version_number}" "info"
129+
run_host_command_logged env -i "${PYTHON3_VARS[@]@Q}" "${PYTHON3_INFO[BIN]}" "${PYTHON3_INFO[GET_PIP_BIN]}" "${pip3_extra_args[@]}" "pip==${pip3_version_number}"
130+
131+
# Install the dependencies
132+
display_alert "Installing Python dependencies" "from ${python3_pip_dependencies_path}" "info"
132133
run_host_command_logged env -i "${PYTHON3_VARS[@]@Q}" "${PYTHON3_INFO[BIN]}" -m pip install "${pip3_extra_args[@]}" -r "${python3_pip_dependencies_path}"
133134

134135
# Create the hash file

lib/functions/host/prepare-host.sh

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -219,18 +219,12 @@ function adaptative_prepare_host_dependencies() {
219219

220220
### Python3 -- required for Armbian's Python tooling, and also for more recent u-boot builds. Needs 3.9+; ffi-dev is needed for some Python packages when the wheel is not prebuilt
221221
### 'python3-setuptools' and 'python3-pyelftools' moved to requirements.txt to make sure build hosts use the same/latest versions of these tools.
222-
host_dependencies+=("python3-dev" "python3-pip" "libffi-dev")
222+
### 'python3-dev' depends on distutils, so instead depend on libpython3-dev which doesn't.
223+
host_dependencies+=("python3" "libpython3-dev" "libffi-dev")
223224

224225
# Needed for some u-boot's, lest "tools/mkeficapsule.c:21:10: fatal error: gnutls/gnutls.h"
225226
host_dependencies+=("libgnutls28-dev")
226227

227-
# Noble/Trixie and later releases do not carry "python3-distutils" https://docs.python.org/3.10/whatsnew/3.10.html#distutils-deprecated
228-
if [[ "$host_release" =~ ^(trixie|sid|noble|wilma)$ ]]; then
229-
display_alert "python3-distutils not available on host release '${host_release}'" "distutils was deprecated with Python 3.12" "debug"
230-
else
231-
host_dependencies+=("python3-distutils")
232-
fi
233-
234228
### Python2 -- required for some older u-boot builds
235229
# Debian newer than 'bookworm' and Ubuntu newer than 'lunar'/'mantic' does not carry python2 anymore; in this case some u-boot's might fail to build.
236230
# Last versions to support python2 were Debian 'bullseye' and Ubuntu 'jammy'

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
# Always use a fixed version, this is important for correct hashing.
66
# Dependabot will keep these versions up to date.
77

8+
pip == 25.0.1 # pip is the package installer for Python
89
setuptools == 75.8.0 # for building Python packages
910
pyelftools == 0.31 # for building U-Boot
1011
unidiff == 0.7.5 # for parsing unified diff

0 commit comments

Comments
 (0)