This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch v3-0-test
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/v3-0-test by this push:
new 04278f1e206 Install python from source again (#53150) (#53202)
04278f1e206 is described below
commit 04278f1e206fe5cb3dcfe6f7fc9f85e2ede7566a
Author: Jarek Potiuk <[email protected]>
AuthorDate: Sat Jul 12 07:35:17 2025 +0200
Install python from source again (#53150) (#53202)
* Draft: Build python from source
Builds python from source, also installs
golang from official distribution. Does
both of these for the ci image only.
* Updates path
* Adds version upgrade check for python version
Adds support for using the airflow api to fetch
the newest python patch version available for specific
major_minor pair
* Updated to use args in dockerfile for python
* Added support for golang upgrade
* Fixed go version sorting in pre_commit install
* Added github token usage and fixed version regex
Updated python fetch request during upgrade to use
github token and fixed the regex
* Updated dockerfile.ci file
* Added support for multiple python versions
Adds python version from global consts into
build args now for the docker ci.
* Updated python install
* Increases timeout for ci image build
(cherry picked from commit 5aec2d5ea87bf110e384187851acfb9a856da38f)
Co-authored-by: Aritra Basu <[email protected]>
---
.dockerignore | 1 +
.github/workflows/additional-ci-image-checks.yml | 2 +-
.github/workflows/basic-tests.yml | 6 +
.pre-commit-config.yaml | 2 +-
Dockerfile.ci | 67 +++++++--
dev/breeze/src/airflow_breeze/global_constants.py | 10 ++
.../src/airflow_breeze/params/build_ci_params.py | 4 +
.../pre_commit/update_installers_and_pre_commit.py | 68 +++++++++
scripts/docker/entrypoint_ci.sh | 2 +-
scripts/docker/install_os_dependencies_ci.sh | 167 +++++++++++++++++++++
10 files changed, 310 insertions(+), 19 deletions(-)
diff --git a/.dockerignore b/.dockerignore
index c50ed5ae24e..75e6291445a 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -38,6 +38,7 @@
!providers/
!task-sdk/
!airflow-ctl/
+!go-sdk/
# Add all "test" distributions
!tests
diff --git a/.github/workflows/additional-ci-image-checks.yml
b/.github/workflows/additional-ci-image-checks.yml
index 024f4a4ea0a..5709e658bfd 100644
--- a/.github/workflows/additional-ci-image-checks.yml
+++ b/.github/workflows/additional-ci-image-checks.yml
@@ -150,4 +150,4 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: echo "$GITHUB_TOKEN" | docker login ghcr.io -u "$actor"
--password-stdin
- name: "Check that image builds quickly"
- run: breeze shell --max-time 600 --platform "${PLATFORM}"
+ run: breeze shell --max-time 900 --platform "${PLATFORM}"
diff --git a/.github/workflows/basic-tests.yml
b/.github/workflows/basic-tests.yml
index bc23674f442..24c0e8eb02e 100644
--- a/.github/workflows/basic-tests.yml
+++ b/.github/workflows/basic-tests.yml
@@ -293,6 +293,9 @@ jobs:
--hook-stage manual update-installers-and-pre-commit || true
if: always()
env:
+ UPGRADE_UV: "true"
+ UPGRADE_PYTHON: "false"
+ UPGRADE_GOLANG: "true"
UPGRADE_PIP: "false"
UPGRADE_PRE_COMMIT: "false"
UPGRADE_NODE_LTS: "false"
@@ -303,6 +306,9 @@ jobs:
--hook-stage manual update-installers-and-pre-commit
if: always()
env:
+ UPGRADE_UV: "false"
+ UPGRADE_PYTHON: "true"
+ UPGRADE_GOLANG: "false"
UPGRADE_PIP: "true"
UPGRADE_PRE_COMMIT: "true"
UPGRADE_NODE_LTS: "true"
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 3adeefd79b6..bdafd8421e5 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -204,7 +204,7 @@ repos:
files:
^\.pre-commit-config\.yaml$|^scripts/ci/pre_commit/update_installers_and_pre_commit\.py$
pass_filenames: false
require_serial: true
- additional_dependencies: ['pyyaml>=6.0.2', 'rich>=12.4.4',
'requests>=2.31.0']
+ additional_dependencies: ['pyyaml>=6.0.2', 'rich>=12.4.4',
'requests>=2.31.0',"packaging>=25"]
- id: update-chart-dependencies
name: Update chart dependencies to latest (manual)
entry: ./scripts/ci/pre_commit/update_chart_dependencies.py
diff --git a/Dockerfile.ci b/Dockerfile.ci
index 066f5a98f55..82f370d7389 100644
--- a/Dockerfile.ci
+++ b/Dockerfile.ci
@@ -16,13 +16,13 @@
#
# WARNING: THIS DOCKERFILE IS NOT INTENDED FOR PRODUCTION USE OR DEPLOYMENT.
#
-ARG PYTHON_BASE_IMAGE="python:3.9-slim-bookworm"
+ARG BASE_IMAGE="debian:bookworm-slim"
##############################################################################################
# This is the script image where we keep all inlined bash scripts needed in
other segments
-# We use PYTHON_BASE_IMAGE to make sure that the scripts are different for
different platforms.
+# We use BASE_IMAGE to make sure that the scripts are different for different
platforms.
##############################################################################################
-FROM ${PYTHON_BASE_IMAGE} as scripts
+FROM ${BASE_IMAGE} as scripts
##############################################################################################
# Please DO NOT modify the inlined scripts manually. The content of those
files will be
@@ -31,22 +31,27 @@ FROM ${PYTHON_BASE_IMAGE} as scripts
# make the PROD Dockerfile standalone
##############################################################################################
-# The content below is automatically copied from
scripts/docker/install_os_dependencies.sh
-COPY <<"EOF" /install_os_dependencies.sh
+# The content below is automatically copied from
scripts/docker/install_os_dependencies_ci.sh
+COPY <<"EOF" /install_os_dependencies_ci.sh
#!/usr/bin/env bash
set -euo pipefail
if [[ "$#" != 1 ]]; then
- echo "ERROR! There should be 'runtime' or 'dev' parameter passed as
argument.".
+ echo "ERROR! There should be 'runtime', 'ci' or 'dev' parameter passed as
argument.".
exit 1
fi
+AIRFLOW_PYTHON_VERSION=${AIRFLOW_PYTHON_VERSION:-v3.10.10}
+GOLANG_MAJOR_MINOR_VERSION=${GOLANG_MAJOR_MINOR_VERSION:-1.24.4}
+
if [[ "${1}" == "runtime" ]]; then
INSTALLATION_TYPE="RUNTIME"
elif [[ "${1}" == "dev" ]]; then
- INSTALLATION_TYPE="dev"
+ INSTALLATION_TYPE="DEV"
+elif [[ "${1}" == "ci" ]]; then
+ INSTALLATION_TYPE="CI"
else
- echo "ERROR! Wrong argument. Passed ${1} and it should be one of 'runtime'
or 'dev'.".
+ echo "ERROR! Wrong argument. Passed ${1} and it should be one of
'runtime', 'ci' or 'dev'.".
exit 1
fi
@@ -56,7 +61,10 @@ function get_dev_apt_deps() {
freetds-bin freetds-dev git graphviz graphviz-dev krb5-user ldap-utils libev4
libev-dev libffi-dev libgeos-dev \
libkrb5-dev libldap2-dev libleveldb1d libleveldb-dev libsasl2-2 libsasl2-dev
libsasl2-modules \
libssl-dev libxmlsec1 libxmlsec1-dev locales lsb-release openssh-client
pkgconf sasl2-bin \
-software-properties-common sqlite3 sudo unixodbc unixodbc-dev zlib1g-dev"
+software-properties-common sqlite3 sudo unixodbc unixodbc-dev zlib1g-dev \
+gdb lcov pkg-config libbz2-dev libgdbm-dev libgdbm-compat-dev liblzma-dev \
+libncurses5-dev libreadline6-dev libsqlite3-dev lzma lzma-dev tk-dev uuid-dev \
+libzstd-dev"
export DEV_APT_DEPS
fi
}
@@ -143,14 +151,36 @@ function install_debian_runtime_dependencies() {
rm -rf /var/lib/apt/lists/* /var/log/*
}
+function install_python() {
+ git clone --branch "${AIRFLOW_PYTHON_VERSION}" --depth 1
https://github.com/python/cpython.git
+ cd cpython
+ ./configure --enable-optimizations
+ make -s -j "$(nproc)" all
+ make -s -j "$(nproc)" install
+ ln -s /usr/local/bin/python3 /usr/local/bin/python
+ ln -s /usr/local/bin/pip3 /usr/local/bin/pip
+ cd ..
+ rm -rf cpython
+}
+
+function install_golang() {
+ curl
"https://dl.google.com/go/go${GOLANG_MAJOR_MINOR_VERSION}.linux-$(dpkg
--print-architecture).tar.gz" -o "go${GOLANG_MAJOR_MINOR_VERSION}.linux.tar.gz"
+ rm -rf /usr/local/go && tar -C /usr/local -xzf
go"${GOLANG_MAJOR_MINOR_VERSION}".linux.tar.gz
+}
+
if [[ "${INSTALLATION_TYPE}" == "RUNTIME" ]]; then
get_runtime_apt_deps
install_debian_runtime_dependencies
install_docker_cli
else
+
get_dev_apt_deps
install_debian_dev_dependencies
+ install_python
+ if [[ "${INSTALLATION_TYPE}" == "CI" ]]; then
+ install_golang
+ fi
install_docker_cli
fi
EOF
@@ -936,7 +966,7 @@ function environment_initialization() {
CI=${CI:="false"}
# Added to have run-tests on path
- export PATH=${PATH}:${AIRFLOW_SOURCES}
+ export PATH=${PATH}:${AIRFLOW_SOURCES}:/usr/local/go/bin/
mkdir -pv "${AIRFLOW_HOME}/logs/"
@@ -1240,13 +1270,13 @@ COPY <<"EOF" /entrypoint_exec.sh
exec /bin/bash "${@}"
EOF
-FROM ${PYTHON_BASE_IMAGE} as main
+FROM ${BASE_IMAGE} as main
# Nolog bash flag is currently ignored - but you can replace it with other
flags (for example
# xtrace - to show commands executed)
SHELL ["/bin/bash", "-o", "pipefail", "-o", "errexit", "-o", "nounset", "-o",
"nolog", "-c"]
-ARG PYTHON_BASE_IMAGE
+ARG BASE_IMAGE
ARG AIRFLOW_IMAGE_REPOSITORY="https://github.com/apache/airflow"
# By increasing this number we can do force build of all dependencies.
@@ -1256,7 +1286,7 @@ ARG
AIRFLOW_IMAGE_REPOSITORY="https://github.com/apache/airflow"
ARG DEPENDENCIES_EPOCH_NUMBER="15"
# Make sure noninteractive debian install is used and language variables set
-ENV PYTHON_BASE_IMAGE=${PYTHON_BASE_IMAGE} \
+ENV BASE_IMAGE=${BASE_IMAGE} \
DEBIAN_FRONTEND=noninteractive LANGUAGE=C.UTF-8 LANG=C.UTF-8
LC_ALL=C.UTF-8 \
LC_CTYPE=C.UTF-8 LC_MESSAGES=C.UTF-8 \
DEPENDENCIES_EPOCH_NUMBER=${DEPENDENCIES_EPOCH_NUMBER} \
@@ -1267,7 +1297,7 @@ ENV PYTHON_BASE_IMAGE=${PYTHON_BASE_IMAGE} \
UV_CACHE_DIR=/root/.cache/uv
-RUN echo "Base image version: ${PYTHON_BASE_IMAGE}"
+RUN echo "Base image version: ${BASE_IMAGE}"
ARG DEV_APT_COMMAND=""
ARG ADDITIONAL_DEV_APT_COMMAND=""
@@ -1282,8 +1312,13 @@ ENV DEV_APT_COMMAND=${DEV_APT_COMMAND} \
ADDITIONAL_DEV_APT_DEPS=${ADDITIONAL_DEV_APT_DEPS} \
ADDITIONAL_DEV_APT_COMMAND=${ADDITIONAL_DEV_APT_COMMAND}
-COPY --from=scripts install_os_dependencies.sh /scripts/docker/
-RUN bash /scripts/docker/install_os_dependencies.sh dev
+ARG AIRFLOW_PYTHON_VERSION=v3.10.18
+ENV AIRFLOW_PYTHON_VERSION=$AIRFLOW_PYTHON_VERSION
+ENV GOLANG_MAJOR_MINOR_VERSION=1.24.4
+
+COPY --from=scripts install_os_dependencies_ci.sh /scripts/docker/
+
+RUN bash /scripts/docker/install_os_dependencies_ci.sh ci
COPY --from=scripts common.sh /scripts/docker/
diff --git a/dev/breeze/src/airflow_breeze/global_constants.py
b/dev/breeze/src/airflow_breeze/global_constants.py
index 7e0f5fff5f9..c680ddca5a8 100644
--- a/dev/breeze/src/airflow_breeze/global_constants.py
+++ b/dev/breeze/src/airflow_breeze/global_constants.py
@@ -753,6 +753,16 @@ PROVIDERS_COMPATIBILITY_TESTS_MATRIX: list[dict[str, str |
list[str]]] = [
},
]
+ALL_PYTHON_VERSION_TO_PATCH_VERSION: dict[str, str] = {
+ "3.6": "v3.6.1",
+ "3.7": "v3.7.1",
+ "3.8": "v3.8.1",
+ "3.9": "v3.9.23",
+ "3.10": "v3.10.18",
+ "3.11": "v3.11.13",
+ "3.12": "v3.12.11",
+}
+
# Number of slices for low dep tests
NUMBER_OF_LOW_DEP_SLICES = 5
diff --git a/dev/breeze/src/airflow_breeze/params/build_ci_params.py
b/dev/breeze/src/airflow_breeze/params/build_ci_params.py
index 65adcf6efde..b4c42c341de 100644
--- a/dev/breeze/src/airflow_breeze/params/build_ci_params.py
+++ b/dev/breeze/src/airflow_breeze/params/build_ci_params.py
@@ -21,6 +21,7 @@ from dataclasses import dataclass
from pathlib import Path
from airflow_breeze.branch_defaults import DEFAULT_AIRFLOW_CONSTRAINTS_BRANCH
+from airflow_breeze.global_constants import ALL_PYTHON_VERSION_TO_PATCH_VERSION
from airflow_breeze.params.common_build_params import CommonBuildParams
from airflow_breeze.utils.path_utils import BUILD_CACHE_PATH
@@ -68,6 +69,9 @@ class BuildCiParams(CommonBuildParams):
self._opt_arg("UV_HTTP_TIMEOUT", get_uv_timeout(self))
self._req_arg("AIRFLOW_VERSION", self.airflow_version)
self._req_arg("PYTHON_BASE_IMAGE", self.python_base_image)
+ self._req_arg(
+ "AIRFLOW_PYTHON_VERSION",
ALL_PYTHON_VERSION_TO_PATCH_VERSION.get(self.python, self.python)
+ )
if self.upgrade_to_newer_dependencies:
self._opt_arg("UPGRADE_RANDOM_INDICATOR_STRING",
f"{random.randrange(2**32):x}")
# optional build args
diff --git a/scripts/ci/pre_commit/update_installers_and_pre_commit.py
b/scripts/ci/pre_commit/update_installers_and_pre_commit.py
index 612acdaaa2f..eed555e93fe 100755
--- a/scripts/ci/pre_commit/update_installers_and_pre_commit.py
+++ b/scripts/ci/pre_commit/update_installers_and_pre_commit.py
@@ -24,6 +24,7 @@ from enum import Enum
from pathlib import Path
import requests
+from packaging.version import Version
sys.path.insert(0, str(Path(__file__).parent.resolve())) # make sure
common_precommit_utils is imported
from common_precommit_utils import AIRFLOW_CORE_ROOT_PATH, AIRFLOW_ROOT_PATH,
console
@@ -65,6 +66,35 @@ def get_latest_pypi_version(package_name: str) -> str:
return latest_version
+def get_latest_python_version(python_major_minor: str, github_token: str |
None) -> str | None:
+ latest_version = None
+ # Matches versions of vA.B.C and vA.B where C can only be numeric and v is
optional
+ version_match = re.compile(rf"^v?{python_major_minor}\.?\d*$")
+ headers = {"User-Agent": "Python requests"}
+ if github_token:
+ headers["Authorization"] = f"Bearer {github_token}"
+ for i in range(5):
+ response = requests.get(
+
f"https://api.github.com/repos/python/cpython/tags?per_page=100&page={i + 1}",
+ headers=headers,
+ )
+ response.raise_for_status() # Ensure we got a successful response
+ data = response.json()
+ versions = [str(tag["name"]) for tag in data if
version_match.match(tag.get("name", ""))]
+ if versions:
+ latest_version = sorted(versions, key=Version, reverse=True)[0]
+ break
+ return latest_version
+
+
+def get_latest_golang_version() -> str:
+ response = requests.get("https://go.dev/dl/?mode=json")
+ response.raise_for_status() # Ensure we got a successful response
+ versions = response.json()
+ stable_versions = [release["version"].replace("go", "") for release in
versions if release["stable"]]
+ return sorted(stable_versions, key=Version, reverse=True)[0]
+
+
def get_latest_lts_node_version() -> str:
response = requests.get("https://nodejs.org/dist/index.json")
response.raise_for_status() # Ensure we got a successful response
@@ -92,6 +122,15 @@ PIP_PATTERNS: list[tuple[re.Pattern, Quoting]] = [
(re.compile(r"(\| *`AIRFLOW_PIP_VERSION` *\| *)(`[0-9.]+`)( *\|)"),
Quoting.REVERSE_SINGLE_QUOTED),
]
+PYTHON_PATTERNS: list[tuple[str, Quoting]] = [
+ (r"(\"{python_major_minor}\": \")(v[0-9.]+)(\")", Quoting.UNQUOTED),
+]
+
+GOLANG_PATTERNS: list[tuple[re.Pattern, Quoting]] = [
+ (re.compile(r"(GOLANG_MAJOR_MINOR_VERSION=)([0-9.]+)"), Quoting.UNQUOTED),
+ (re.compile(r"(\| *`GOLANG_MAJOR_MINOR_VERSION` *\| *)(`[0-9.]+`)( *\|)"),
Quoting.REVERSE_SINGLE_QUOTED),
+]
+
UV_PATTERNS: list[tuple[re.Pattern, Quoting]] = [
(re.compile(r"(AIRFLOW_UV_VERSION=)([0-9.]+)"), Quoting.UNQUOTED),
(re.compile(r"(uv>=)([0-9.]+)"), Quoting.UNQUOTED),
@@ -167,6 +206,8 @@ def get_replacement(value: str, quoting: Quoting) -> str:
UPGRADE_UV: bool = os.environ.get("UPGRADE_UV", "true").lower() == "true"
UPGRADE_PIP: bool = os.environ.get("UPGRADE_PIP", "true").lower() == "true"
+UPGRADE_PYTHON: bool = os.environ.get("UPGRADE_PYTHON", "true").lower() ==
"true"
+UPGRADE_GOLANG: bool = os.environ.get("UPGRADE_GOLANG", "true").lower() ==
"true"
UPGRADE_SETUPTOOLS: bool = os.environ.get("UPGRADE_SETUPTOOLS",
"true").lower() == "true"
UPGRADE_PRE_COMMIT: bool = os.environ.get("UPGRADE_PRE_COMMIT",
"true").lower() == "true"
UPGRADE_NODE_LTS: bool = os.environ.get("UPGRADE_NODE_LTS", "true").lower() ==
"true"
@@ -175,6 +216,10 @@ UPGRADE_PYYAML: bool = os.environ.get("UPGRADE_PYYAML",
"true").lower() == "true
UPGRADE_GITPYTHON: bool = os.environ.get("UPGRADE_GITPYTHON", "true").lower()
== "true"
UPGRADE_RICH: bool = os.environ.get("UPGRADE_RICH", "true").lower() == "true"
+ALL_PYTHON_MAJOR_MINOR_VERSIONS = ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11",
"3.12"]
+
+GITHUB_TOKEN: str | None = os.environ.get("GITHUB_TOKEN")
+
def replace_version(pattern: re.Pattern[str], version: str, text: str,
keep_total_length: bool = True) -> str:
# Assume that the pattern has up to 3 replacement groups:
@@ -205,6 +250,7 @@ def replace_version(pattern: re.Pattern[str], version: str,
text: str, keep_tota
if __name__ == "__main__":
changed = False
+ golang_version = get_latest_golang_version()
pip_version = get_latest_pypi_version("pip")
uv_version = get_latest_pypi_version("uv")
setuptools_version = get_latest_pypi_version("setuptools")
@@ -225,6 +271,28 @@ if __name__ == "__main__":
new_content = replace_version(
line_pattern, get_replacement(pip_version, quoting),
new_content, keep_length
)
+ if UPGRADE_PYTHON:
+ for python_version in ALL_PYTHON_MAJOR_MINOR_VERSIONS:
+ latest_python_version =
get_latest_python_version(python_version, GITHUB_TOKEN)
+ if latest_python_version:
+ console.print(
+ f"[bright_blue]Latest python {python_version} version:
{latest_python_version}"
+ )
+ for line_format, quoting in PYTHON_PATTERNS:
+ line_pattern =
re.compile(line_format.format(python_major_minor=python_version))
+ console.print(line_pattern)
+ new_content = replace_version(
+ line_pattern,
+ get_replacement(latest_python_version, quoting),
+ new_content,
+ keep_length,
+ )
+ if UPGRADE_GOLANG:
+ console.print(f"[bright_blue]Latest golang version:
{golang_version}")
+ for line_pattern, quoting in GOLANG_PATTERNS:
+ new_content = replace_version(
+ line_pattern, get_replacement(golang_version, quoting),
new_content, keep_length
+ )
if UPGRADE_SETUPTOOLS:
console.print(f"[bright_blue]Latest setuptools version:
{setuptools_version}")
for line_pattern, quoting in SETUPTOOLS_PATTERNS:
diff --git a/scripts/docker/entrypoint_ci.sh b/scripts/docker/entrypoint_ci.sh
index b8a4e994ceb..831be7e241f 100755
--- a/scripts/docker/entrypoint_ci.sh
+++ b/scripts/docker/entrypoint_ci.sh
@@ -130,7 +130,7 @@ function environment_initialization() {
CI=${CI:="false"}
# Added to have run-tests on path
- export PATH=${PATH}:${AIRFLOW_SOURCES}
+ export PATH=${PATH}:${AIRFLOW_SOURCES}:/usr/local/go/bin/
mkdir -pv "${AIRFLOW_HOME}/logs/"
diff --git a/scripts/docker/install_os_dependencies_ci.sh
b/scripts/docker/install_os_dependencies_ci.sh
new file mode 100644
index 00000000000..0873ac69c8c
--- /dev/null
+++ b/scripts/docker/install_os_dependencies_ci.sh
@@ -0,0 +1,167 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# shellcheck shell=bash
+set -euo pipefail
+
+if [[ "$#" != 1 ]]; then
+ echo "ERROR! There should be 'runtime', 'ci' or 'dev' parameter passed as
argument.".
+ exit 1
+fi
+
+AIRFLOW_PYTHON_VERSION=${AIRFLOW_PYTHON_VERSION:-v3.10.10}
+GOLANG_MAJOR_MINOR_VERSION=${GOLANG_MAJOR_MINOR_VERSION:-1.24.4}
+
+if [[ "${1}" == "runtime" ]]; then
+ INSTALLATION_TYPE="RUNTIME"
+elif [[ "${1}" == "dev" ]]; then
+ INSTALLATION_TYPE="DEV"
+elif [[ "${1}" == "ci" ]]; then
+ INSTALLATION_TYPE="CI"
+else
+ echo "ERROR! Wrong argument. Passed ${1} and it should be one of
'runtime', 'ci' or 'dev'.".
+ exit 1
+fi
+
+function get_dev_apt_deps() {
+ if [[ "${DEV_APT_DEPS=}" == "" ]]; then
+ DEV_APT_DEPS="apt-transport-https apt-utils build-essential
ca-certificates dirmngr \
+freetds-bin freetds-dev git graphviz graphviz-dev krb5-user ldap-utils libev4
libev-dev libffi-dev libgeos-dev \
+libkrb5-dev libldap2-dev libleveldb1d libleveldb-dev libsasl2-2 libsasl2-dev
libsasl2-modules \
+libssl-dev libxmlsec1 libxmlsec1-dev locales lsb-release openssh-client
pkgconf sasl2-bin \
+software-properties-common sqlite3 sudo unixodbc unixodbc-dev zlib1g-dev \
+gdb lcov pkg-config libbz2-dev libgdbm-dev libgdbm-compat-dev liblzma-dev \
+libncurses5-dev libreadline6-dev libsqlite3-dev lzma lzma-dev tk-dev uuid-dev \
+libzstd-dev"
+ export DEV_APT_DEPS
+ fi
+}
+
+function get_runtime_apt_deps() {
+ local debian_version
+ local debian_version_apt_deps
+ # Get debian version without installing lsb_release
+ # shellcheck disable=SC1091
+ debian_version=$(. /etc/os-release; printf '%s\n' "$VERSION_CODENAME";)
+ echo
+ echo "DEBIAN CODENAME: ${debian_version}"
+ echo
+ debian_version_apt_deps="libffi8 libldap-2.5-0 libssl3 netcat-openbsd"
+ echo
+ echo "APPLIED INSTALLATION CONFIGURATION FOR DEBIAN VERSION:
${debian_version}"
+ echo
+ if [[ "${RUNTIME_APT_DEPS=}" == "" ]]; then
+ RUNTIME_APT_DEPS="apt-transport-https apt-utils ca-certificates \
+curl dumb-init freetds-bin git krb5-user libev4 libgeos-dev \
+ldap-utils libsasl2-2 libsasl2-modules libxmlsec1 locales
${debian_version_apt_deps} \
+lsb-release openssh-client python3-selinux rsync sasl2-bin sqlite3 sudo
unixodbc"
+ export RUNTIME_APT_DEPS
+ fi
+}
+
+function install_docker_cli() {
+ apt-get update
+ apt-get install ca-certificates curl
+ install -m 0755 -d /etc/apt/keyrings
+ curl -fsSL https://download.docker.com/linux/debian/gpg -o
/etc/apt/keyrings/docker.asc
+ chmod a+r /etc/apt/keyrings/docker.asc
+ # shellcheck disable=SC1091
+ echo \
+ "deb [arch=$(dpkg --print-architecture)
signed-by=/etc/apt/keyrings/docker.asc]
https://download.docker.com/linux/debian \
+ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
+ tee /etc/apt/sources.list.d/docker.list > /dev/null
+ apt-get update
+ apt-get install -y --no-install-recommends docker-ce-cli
+}
+
+function install_debian_dev_dependencies() {
+ apt-get update
+ apt-get install -yqq --no-install-recommends apt-utils >/dev/null 2>&1
+ apt-get install -y --no-install-recommends curl gnupg2 lsb-release
+ # shellcheck disable=SC2086
+ export ${ADDITIONAL_DEV_APT_ENV?}
+ if [[ ${DEV_APT_COMMAND} != "" ]]; then
+ bash -o pipefail -o errexit -o nounset -o nolog -c "${DEV_APT_COMMAND}"
+ fi
+ if [[ ${ADDITIONAL_DEV_APT_COMMAND} != "" ]]; then
+ bash -o pipefail -o errexit -o nounset -o nolog -c
"${ADDITIONAL_DEV_APT_COMMAND}"
+ fi
+ apt-get update
+ local debian_version
+ local debian_version_apt_deps
+ # Get debian version without installing lsb_release
+ # shellcheck disable=SC1091
+ debian_version=$(. /etc/os-release; printf '%s\n' "$VERSION_CODENAME";)
+ echo
+ echo "DEBIAN CODENAME: ${debian_version}"
+ echo
+ # shellcheck disable=SC2086
+ apt-get install -y --no-install-recommends ${DEV_APT_DEPS}
${ADDITIONAL_DEV_APT_DEPS}
+}
+
+function install_debian_runtime_dependencies() {
+ apt-get update
+ apt-get install --no-install-recommends -yqq apt-utils >/dev/null 2>&1
+ apt-get install -y --no-install-recommends curl gnupg2 lsb-release
+ # shellcheck disable=SC2086
+ export ${ADDITIONAL_RUNTIME_APT_ENV?}
+ if [[ "${RUNTIME_APT_COMMAND}" != "" ]]; then
+ bash -o pipefail -o errexit -o nounset -o nolog -c
"${RUNTIME_APT_COMMAND}"
+ fi
+ if [[ "${ADDITIONAL_RUNTIME_APT_COMMAND}" != "" ]]; then
+ bash -o pipefail -o errexit -o nounset -o nolog -c
"${ADDITIONAL_RUNTIME_APT_COMMAND}"
+ fi
+ apt-get update
+ # shellcheck disable=SC2086
+ apt-get install -y --no-install-recommends ${RUNTIME_APT_DEPS}
${ADDITIONAL_RUNTIME_APT_DEPS}
+ apt-get autoremove -yqq --purge
+ apt-get clean
+ rm -rf /var/lib/apt/lists/* /var/log/*
+}
+
+function install_python() {
+ git clone --branch "${AIRFLOW_PYTHON_VERSION}" --depth 1
https://github.com/python/cpython.git
+ cd cpython
+ ./configure --enable-optimizations
+ make -s -j "$(nproc)" all
+ make -s -j "$(nproc)" install
+ ln -s /usr/local/bin/python3 /usr/local/bin/python
+ ln -s /usr/local/bin/pip3 /usr/local/bin/pip
+ cd ..
+ rm -rf cpython
+}
+
+function install_golang() {
+ curl
"https://dl.google.com/go/go${GOLANG_MAJOR_MINOR_VERSION}.linux-$(dpkg
--print-architecture).tar.gz" -o "go${GOLANG_MAJOR_MINOR_VERSION}.linux.tar.gz"
+ rm -rf /usr/local/go && tar -C /usr/local -xzf
go"${GOLANG_MAJOR_MINOR_VERSION}".linux.tar.gz
+}
+
+if [[ "${INSTALLATION_TYPE}" == "RUNTIME" ]]; then
+ get_runtime_apt_deps
+ install_debian_runtime_dependencies
+ install_docker_cli
+
+else
+
+ get_dev_apt_deps
+ install_debian_dev_dependencies
+ install_python
+ if [[ "${INSTALLATION_TYPE}" == "CI" ]]; then
+ install_golang
+ fi
+ install_docker_cli
+fi