You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by po...@apache.org on 2024/02/29 14:03:03 UTC
(airflow) branch use-uv-for-prod-image updated (392b4b5a6d -> a3008e0a50)
This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a change to branch use-uv-for-prod-image
in repository https://gitbox.apache.org/repos/asf/airflow.git
discard 392b4b5a6d Create a joint .local (--user) and venv environment for PROD image
new a3008e0a50 Switch from --user to venv environment for PROD image
This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version. This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:
* -- * -- B -- O -- O -- O (392b4b5a6d)
\
N -- N -- N refs/heads/use-uv-for-prod-image (a3008e0a50)
You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.
Any revisions marked "omit" are not gone; other references still
refer to them. Any revisions marked "discard" are gone forever.
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
(airflow) 01/01: Switch from --user to venv environment for PROD image
Posted by po...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch use-uv-for-prod-image
in repository https://gitbox.apache.org/repos/asf/airflow.git
commit a3008e0a50f0acaa02bd18f4a95b3f3add83f903
Author: Jarek Potiuk <ja...@potiuk.com>
AuthorDate: Thu Feb 29 11:28:57 2024 +0100
Switch from --user to venv environment for PROD image
This PR introduces a joint way to treat the .local (--user) folder
as both - venv and `--user` package installation. This allow two
things:
* we can use `uv` to built the production image, which gives
40%-50% saving for image build time.
* user do not have to use `pip install --user` to install new
packages
* python -m venv --system-site-packages continues to use the
.local packages from the .local installation (and not uses
them if --system-site-packages is not used
* you can use uv to install packages when you extend the image as
a user
* this PR switches to use `uv` by default for all prod images,
but it adds a check if the image still builds with `pip`.
Fixes: #37785
---
.github/workflows/build-images.yml | 2 +
.github/workflows/ci.yml | 59 ++++++
Dockerfile | 148 ++++++++-------
Dockerfile.ci | 78 +++-----
dev/breeze/doc/images/output_prod-image_build.svg | 206 +++++++++++----------
dev/breeze/doc/images/output_prod-image_build.txt | 2 +-
.../src/airflow_breeze/commands/common_options.py | 9 +
.../commands/production_image_commands.py | 4 +
.../commands/production_image_commands_config.py | 11 +-
.../src/airflow_breeze/params/build_prod_params.py | 2 +
docs/docker-stack/build-arg-ref.rst | 2 +-
docs/docker-stack/build.rst | 10 +-
docs/docker-stack/changelog.rst | 21 ++-
scripts/docker/common.sh | 38 ++--
...{install_pip_version.sh => create_prod_venv.sh} | 11 +-
scripts/docker/install_additional_dependencies.sh | 5 +-
scripts/docker/install_airflow.sh | 7 +-
...install_airflow_dependencies_from_branch_tip.sh | 3 +-
.../docker/install_from_docker_context_files.sh | 5 +-
...l_pip_version.sh => install_packaging_tools.sh} | 7 +-
scripts/in_container/_in_container_utils.sh | 6 +-
21 files changed, 355 insertions(+), 281 deletions(-)
diff --git a/.github/workflows/build-images.yml b/.github/workflows/build-images.yml
index da76fcbeff..42dc2da0ac 100644
--- a/.github/workflows/build-images.yml
+++ b/.github/workflows/build-images.yml
@@ -180,6 +180,7 @@ jobs:
RUNS_ON: "${{ needs.build-info.outputs.runs-on }}"
BACKEND: sqlite
VERSION_SUFFIX_FOR_PYPI: "dev0"
+ USE_UV: "true"
steps:
- name: Cleanup repo
run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*"
@@ -258,6 +259,7 @@ jobs:
BACKEND: sqlite
VERSION_SUFFIX_FOR_PYPI: "dev0"
INCLUDE_NOT_READY_PROVIDERS: "true"
+ USE_UV: "true"
steps:
- name: Cleanup repo
run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1cb19201dd..abe3fbeafc 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -282,6 +282,7 @@ jobs:
# Force more parallelism for build even on public images
PARALLELISM: 6
VERSION_SUFFIX_FOR_PYPI: "dev0"
+ USE_UV: "true"
steps:
- name: Cleanup repo
run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*"
@@ -1863,6 +1864,7 @@ jobs:
BACKEND: sqlite
VERSION_SUFFIX_FOR_PYPI: "dev0"
DEBUG_RESOURCES: ${{needs.build-info.outputs.debug-resources}}
+ USE_UV: "true"
steps:
- name: Cleanup repo
run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*"
@@ -1898,6 +1900,57 @@ jobs:
PYTHON_VERSIONS: ${{needs.build-info.outputs.all-python-versions-list-as-string}}
DEBUG_RESOURCES: ${{ needs.build-info.outputs.debug-resources }}
+ build-prod-images-pip:
+ strategy:
+ matrix:
+ python-version: ${{fromJson(needs.build-info.outputs.python-versions)}}
+ timeout-minutes: 80
+ name: ${{needs.build-info.outputs.build-job-description}} PROD image pip (main) ${{matrix.python-version}}
+ runs-on: ["ubuntu-22.04"]
+ needs: [build-info, build-ci-images]
+ env:
+ DEFAULT_BRANCH: ${{ needs.build-info.outputs.default-branch }}
+ DEFAULT_CONSTRAINTS_BRANCH: ${{ needs.build-info.outputs.default-constraints-branch }}
+ RUNS_ON: "${{needs.build-info.outputs.runs-on}}"
+ BACKEND: sqlite
+ VERSION_SUFFIX_FOR_PYPI: "dev0"
+ DEBUG_RESOURCES: ${{needs.build-info.outputs.debug-resources}}
+ USE_UV: "false"
+ steps:
+ - name: Cleanup repo
+ run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*"
+ if: >
+ needs.build-info.outputs.in-workflow-build == 'true' &&
+ needs.build-info.outputs.default-branch == 'main'
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ needs.build-info.outputs.targetCommitSha }}
+ persist-credentials: false
+ if: >
+ needs.build-info.outputs.in-workflow-build == 'true' &&
+ needs.build-info.outputs.default-branch == 'main'
+ - name: "Install Breeze"
+ uses: ./.github/actions/breeze
+ with:
+ python-version: ${{ env.REPRODUCIBLE_PYTHON_VERSION }}
+ if: >
+ needs.build-info.outputs.in-workflow-build == 'true' &&
+ needs.build-info.outputs.default-branch == 'main'
+ - name: Build PROD Image pip ${{ matrix.python-version }}:${{env.IMAGE_TAG}}
+ uses: ./.github/actions/build-prod-images
+ if: >
+ needs.build-info.outputs.in-workflow-build == 'true' &&
+ needs.build-info.outputs.default-branch == 'main'
+ with:
+ build-provider-packages: ${{ needs.build-info.outputs.default-branch == 'main' }}
+ chicken-egg-providers: ${{ needs.build-info.outputs.chicken-egg-providers }}
+ python-version: ${{ matrix.python-version }}
+ env:
+ UPGRADE_TO_NEWER_DEPENDENCIES: ${{ needs.build-info.outputs.upgrade-to-newer-dependencies }}
+ DOCKER_CACHE: ${{ needs.build-info.outputs.cache-directive }}
+ PYTHON_VERSIONS: ${{needs.build-info.outputs.all-python-versions-list-as-string}}
+ DEBUG_RESOURCES: ${{ needs.build-info.outputs.debug-resources }}
+
build-prod-images-bullseye:
strategy:
matrix:
@@ -1914,6 +1967,7 @@ jobs:
BACKEND: sqlite
VERSION_SUFFIX_FOR_PYPI: "dev0"
DEBUG_RESOURCES: ${{needs.build-info.outputs.debug-resources}}
+ USE_UV: "true"
steps:
- name: Cleanup repo
run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*"
@@ -1970,6 +2024,7 @@ jobs:
BACKEND: sqlite
VERSION_SUFFIX_FOR_PYPI: "dev0"
DEBUG_RESOURCES: ${{needs.build-info.outputs.debug-resources}}
+ USE_UV: "true"
steps:
- name: Cleanup repo
run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*"
@@ -2027,6 +2082,7 @@ jobs:
BACKEND: sqlite
VERSION_SUFFIX_FOR_PYPI: "dev0"
DEBUG_RESOURCES: ${{needs.build-info.outputs.debug-resources}}
+ USE_UV: "true"
steps:
- name: Cleanup repo
run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*"
@@ -2078,6 +2134,7 @@ jobs:
BACKEND: sqlite
VERSION_SUFFIX_FOR_PYPI: "dev0"
DEBUG_RESOURCES: ${{needs.build-info.outputs.debug-resources}}
+ USE_UV: "true"
steps:
- name: Cleanup repo
run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*"
@@ -2134,6 +2191,7 @@ jobs:
BACKEND: sqlite
VERSION_SUFFIX_FOR_PYPI: "dev0"
DEBUG_RESOURCES: ${{needs.build-info.outputs.debug-resources}}
+ USE_UV: "true"
steps:
- name: Cleanup repo
run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*"
@@ -2530,6 +2588,7 @@ jobs:
RUNS_ON: "${{needs.build-info.outputs.runs-on}}"
# Force more parallelism for build even on small instances
PARALLELISM: 6
+ USE_UV: "true"
if: >
needs.build-info.outputs.in-workflow-build == 'true' &&
needs.build-info.outputs.canary-run != 'true'
diff --git a/Dockerfile b/Dockerfile
index a6ab7af291..1aa821aaba 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -23,8 +23,9 @@
# airflow-build-image - there all airflow dependencies can be installed (and
# built - for those dependencies that require
# build essentials). Airflow is installed there with
-# --user switch so that all the dependencies are
-# installed to ${HOME}/.local
+# ${HOME}/.local virtualenv which is also considered
+# As --user folder by python when creating venv with
+# --system-site-packages
#
# main - this is the actual production image that is much
# smaller because it does not contain all the build
@@ -50,7 +51,7 @@ ARG PYTHON_BASE_IMAGE="python:3.8-slim-bookworm"
ARG AIRFLOW_PIP_VERSION=24.0
ARG AIRFLOW_UV_VERSION=0.1.12
-ARG AIRFLOW_USE_UV="false"
+ARG AIRFLOW_USE_UV="true"
ARG AIRFLOW_IMAGE_REPOSITORY="https://github.com/apache/airflow"
ARG AIRFLOW_IMAGE_README_URL="https://raw.githubusercontent.com/apache/airflow/main/docs/docker-stack/README.md"
@@ -412,18 +413,13 @@ if [[ ${INSTALL_POSTGRES_CLIENT:="true"} == "true" ]]; then
fi
EOF
-# The content below is automatically copied from scripts/docker/install_pip_version.sh
-COPY <<"EOF" /install_pip_version.sh
+# The content below is automatically copied from scripts/docker/install_packaging_tools.sh
+COPY <<"EOF" /install_packaging_tools.sh
#!/usr/bin/env bash
. "$( dirname "${BASH_SOURCE[0]}" )/common.sh"
common::get_colors
-common::get_packaging_tool
-common::get_airflow_version_specification
-common::override_pip_version_if_needed
-common::show_packaging_tool_version_and_location
-
-common::install_packaging_tool
+common::install_packaging_tools
EOF
# The content below is automatically copied from scripts/docker/install_airflow_dependencies_from_branch_tip.sh
@@ -454,7 +450,7 @@ function install_airflow_dependencies_from_branch_tip() {
${PACKAGING_TOOL_CMD} install ${EXTRA_INSTALL_FLAGS} \
${ADDITIONAL_PIP_INSTALL_FLAGS} \
"apache-airflow[${AIRFLOW_EXTRAS}] @ https://github.com/${AIRFLOW_REPO}/archive/${AIRFLOW_BRANCH}.tar.gz"
- common::install_packaging_tool
+ common::install_packaging_tools
# Uninstall airflow and providers to keep only the dependencies. In the future when
# planned https://github.com/pypa/pip/issues/11440 is implemented in pip we might be able to use this
# flag and skip the remove step.
@@ -469,7 +465,6 @@ function install_airflow_dependencies_from_branch_tip() {
common::get_colors
common::get_packaging_tool
common::get_airflow_version_specification
-common::override_pip_version_if_needed
common::get_constraints_location
common::show_packaging_tool_version_and_location
@@ -509,7 +504,11 @@ function common::get_packaging_tool() {
echo
export PACKAGING_TOOL="uv"
export PACKAGING_TOOL_CMD="uv pip"
- export EXTRA_INSTALL_FLAGS="--python ${PYTHON_BIN}"
+ if [[ -z ${VIRTUAL_ENV=} ]]; then
+ export EXTRA_INSTALL_FLAGS="--python ${PYTHON_BIN}"
+ else
+ export EXTRA_INSTALL_FLAGS=""
+ fi
export EXTRA_UNINSTALL_FLAGS="--python ${PYTHON_BIN}"
export RESOLUTION_HIGHEST_FLAG="--resolution highest"
export RESOLUTION_LOWEST_DIRECT_FLAG="--resolution lowest-direct"
@@ -534,14 +533,6 @@ function common::get_airflow_version_specification() {
fi
}
-function common::override_pip_version_if_needed() {
- if [[ -n ${AIRFLOW_VERSION} ]]; then
- if [[ ${AIRFLOW_VERSION} =~ ^2\.0.* || ${AIRFLOW_VERSION} =~ ^1\.* ]]; then
- export AIRFLOW_PIP_VERSION=24.0
- fi
- fi
-}
-
function common::get_constraints_location() {
# auto-detect Airflow-constraint reference and location
if [[ -z "${AIRFLOW_CONSTRAINTS_REFERENCE=}" ]]; then
@@ -568,12 +559,12 @@ function common::show_packaging_tool_version_and_location() {
echo "Using pip: $(pip --version)"
else
echo "${COLOR_BLUE}Using 'uv' to install Airflow${COLOR_RESET}"
- echo "uv on path: $(which uv)"
+ echo "uv on path: $(which uv 2>/dev/null || echo "Not installed")"
echo "Using uv: $(uv --version)"
fi
}
-function common::install_packaging_tool() {
+function common::install_packaging_tools() {
echo
echo "${COLOR_BLUE}Installing pip version ${AIRFLOW_PIP_VERSION}${COLOR_RESET}"
echo
@@ -584,17 +575,15 @@ function common::install_packaging_tool() {
# shellcheck disable=SC2086
pip install --root-user-action ignore --disable-pip-version-check "pip==${AIRFLOW_PIP_VERSION}"
fi
- if [[ ${AIRFLOW_USE_UV} == "true" ]]; then
- echo
- echo "${COLOR_BLUE}Installing uv version ${AIRFLOW_UV_VERSION}${COLOR_RESET}"
- echo
- if [[ ${AIRFLOW_UV_VERSION} =~ .*https.* ]]; then
- # shellcheck disable=SC2086
- pip install --root-user-action ignore --disable-pip-version-check "uv @ ${AIRFLOW_UV_VERSION}"
- else
- # shellcheck disable=SC2086
- pip install --root-user-action ignore --disable-pip-version-check "uv==${AIRFLOW_UV_VERSION}"
- fi
+ echo
+ echo "${COLOR_BLUE}Installing uv version ${AIRFLOW_UV_VERSION}${COLOR_RESET}"
+ echo
+ if [[ ${AIRFLOW_UV_VERSION} =~ .*https.* ]]; then
+ # shellcheck disable=SC2086
+ pip install --root-user-action ignore --disable-pip-version-check "uv @ ${AIRFLOW_UV_VERSION}"
+ else
+ # shellcheck disable=SC2086
+ pip install --root-user-action ignore --disable-pip-version-check "uv==${AIRFLOW_UV_VERSION}"
fi
mkdir -p "${HOME}/.local/bin"
}
@@ -744,7 +733,7 @@ function install_airflow_and_providers_from_docker_context_files(){
${reinstalling_apache_airflow_package} ${reinstalling_apache_airflow_providers_packages}
set +x
fi
- common::install_packaging_tool
+ common::install_packaging_tools
pip check
}
@@ -760,7 +749,7 @@ function install_all_other_packages_from_docker_context_files() {
set -x
${PACKAGING_TOOL_CMD} install ${EXTRA_INSTALL_FLAGS} ${ADDITIONAL_PIP_INSTALL_FLAGS} \
--force-reinstall --no-deps --no-index ${reinstalling_other_packages}
- common::install_packaging_tool
+ common::install_packaging_tools
set +x
fi
}
@@ -768,7 +757,6 @@ function install_all_other_packages_from_docker_context_files() {
common::get_colors
common::get_packaging_tool
common::get_airflow_version_specification
-common::override_pip_version_if_needed
common::get_constraints_location
common::show_packaging_tool_version_and_location
@@ -819,7 +807,7 @@ function install_airflow() {
"${AIRFLOW_INSTALLATION_METHOD}[${AIRFLOW_EXTRAS}]${AIRFLOW_VERSION_SPECIFICATION}" \
${EAGER_UPGRADE_ADDITIONAL_REQUIREMENTS=}
set +x
- common::install_packaging_tool
+ common::install_packaging_tools
echo
echo "${COLOR_BLUE}Running '${PACKAGING_TOOL} check'${COLOR_RESET}"
echo
@@ -833,13 +821,13 @@ function install_airflow() {
${ADDITIONAL_PIP_INSTALL_FLAGS} \
"${AIRFLOW_INSTALLATION_METHOD}[${AIRFLOW_EXTRAS}]${AIRFLOW_VERSION_SPECIFICATION}" \
--constraint "${AIRFLOW_CONSTRAINTS_LOCATION}" || true
- common::install_packaging_tool
+ common::install_packaging_tools
# then upgrade if needed without using constraints to account for new limits in pyproject.toml
${PACKAGING_TOOL_CMD} install ${EXTRA_INSTALL_FLAGS} --upgrade ${RESOLUTION_LOWEST_DIRECT_FLAG} \
${ADDITIONAL_PIP_INSTALL_FLAGS} \
${AIRFLOW_INSTALL_EDITABLE_FLAG} \
"${AIRFLOW_INSTALLATION_METHOD}[${AIRFLOW_EXTRAS}]${AIRFLOW_VERSION_SPECIFICATION}"
- common::install_packaging_tool
+ common::install_packaging_tools
set +x
echo
echo "${COLOR_BLUE}Running 'pip check'${COLOR_RESET}"
@@ -852,7 +840,6 @@ function install_airflow() {
common::get_colors
common::get_packaging_tool
common::get_airflow_version_specification
-common::override_pip_version_if_needed
common::get_constraints_location
common::show_packaging_tool_version_and_location
@@ -878,7 +865,7 @@ function install_additional_dependencies() {
${PACKAGING_TOOL_CMD} install ${EXTRA_INSTALL_FLAGS} --upgrade ${RESOLUTION_HIGHEST_FLAG} \
${ADDITIONAL_PIP_INSTALL_FLAGS} \
${ADDITIONAL_PYTHON_DEPS} ${EAGER_UPGRADE_ADDITIONAL_REQUIREMENTS=}
- common::install_packaging_tool
+ common::install_packaging_tools
set +x
echo
echo "${COLOR_BLUE}Running 'pip check'${COLOR_RESET}"
@@ -892,7 +879,7 @@ function install_additional_dependencies() {
${PACKAGING_TOOL_CMD} install ${EXTRA_INSTALL_FLAGS} --upgrade "${RESOLUTION_LOWEST_DIRECT_FLAG}" \
${ADDITIONAL_PIP_INSTALL_FLAGS} \
${ADDITIONAL_PYTHON_DEPS}
- common::install_packaging_tool
+ common::install_packaging_tools
set +x
echo
echo "${COLOR_BLUE}Running 'pip check'${COLOR_RESET}"
@@ -904,13 +891,30 @@ function install_additional_dependencies() {
common::get_colors
common::get_packaging_tool
common::get_airflow_version_specification
-common::override_pip_version_if_needed
common::get_constraints_location
common::show_packaging_tool_version_and_location
install_additional_dependencies
EOF
+# The content below is automatically copied from scripts/docker/create_prod_venv.sh
+COPY <<"EOF" /create_prod_venv.sh
+#!/usr/bin/env bash
+. "$( dirname "${BASH_SOURCE[0]}" )/common.sh"
+
+function create_prod_venv() {
+ rm -rf ~/.local
+ python -m venv ~/.local
+}
+
+common::get_colors
+common::get_packaging_tool
+common::show_packaging_tool_version_and_location
+create_prod_venv
+common::install_packaging_tools
+EOF
+
+
# The content below is automatically copied from scripts/docker/entrypoint_prod.sh
COPY <<"EOF" /entrypoint_prod.sh
@@ -1292,9 +1296,6 @@ ARG INSTALL_MYSQL_CLIENT="true"
ARG INSTALL_MYSQL_CLIENT_TYPE="mariadb"
ARG INSTALL_MSSQL_CLIENT="true"
ARG INSTALL_POSTGRES_CLIENT="true"
-ARG AIRFLOW_PIP_VERSION
-ARG AIRFLOW_UV_VERSION
-ARG AIRFLOW_USE_UV
ENV INSTALL_MYSQL_CLIENT=${INSTALL_MYSQL_CLIENT} \
INSTALL_MYSQL_CLIENT_TYPE=${INSTALL_MYSQL_CLIENT_TYPE} \
@@ -1375,6 +1376,10 @@ RUN if [[ -f /docker-context-files/pip.conf ]]; then \
# Additional PIP flags passed to all pip install commands except reinstalling pip itself
ARG ADDITIONAL_PIP_INSTALL_FLAGS=""
+ARG AIRFLOW_PIP_VERSION
+ARG AIRFLOW_UV_VERSION
+ARG AIRFLOW_USE_UV
+
ENV AIRFLOW_PIP_VERSION=${AIRFLOW_PIP_VERSION} \
AIRFLOW_UV_VERSION=${AIRFLOW_UV_VERSION} \
AIRFLOW_USE_UV=${AIRFLOW_USE_UV} \
@@ -1392,21 +1397,20 @@ ENV AIRFLOW_PIP_VERSION=${AIRFLOW_PIP_VERSION} \
AIRFLOW_CONSTRAINTS_REFERENCE=${AIRFLOW_CONSTRAINTS_REFERENCE} \
AIRFLOW_CONSTRAINTS_LOCATION=${AIRFLOW_CONSTRAINTS_LOCATION} \
DEFAULT_CONSTRAINTS_BRANCH=${DEFAULT_CONSTRAINTS_BRANCH} \
- PATH=${PATH}:${AIRFLOW_USER_HOME_DIR}/.local/bin \
+ PATH=${AIRFLOW_USER_HOME_DIR}/.local/bin:${PATH} \
PIP_PROGRESS_BAR=${PIP_PROGRESS_BAR} \
ADDITIONAL_PIP_INSTALL_FLAGS=${ADDITIONAL_PIP_INSTALL_FLAGS} \
AIRFLOW_USER_HOME_DIR=${AIRFLOW_USER_HOME_DIR} \
AIRFLOW_HOME=${AIRFLOW_HOME} \
AIRFLOW_UID=${AIRFLOW_UID} \
AIRFLOW_INSTALL_EDITABLE_FLAG="" \
- UPGRADE_TO_NEWER_DEPENDENCIES=${UPGRADE_TO_NEWER_DEPENDENCIES} \
- # By default PIP installs everything to ~/.local
- PIP_USER="true"
+ UPGRADE_TO_NEWER_DEPENDENCIES=${UPGRADE_TO_NEWER_DEPENDENCIES}
+
# Copy all scripts required for installation - changing any of those should lead to
# rebuilding from here
-COPY --from=scripts common.sh install_pip_version.sh \
- install_airflow_dependencies_from_branch_tip.sh /scripts/docker/
+COPY --from=scripts common.sh install_packaging_tools.sh \
+ install_airflow_dependencies_from_branch_tip.sh create_prod_venv.sh /scripts/docker/
# We can set this value to true in case we want to install .whl/.tar.gz packages placed in the
# docker-context-files folder. This can be done for both additional packages you want to install
@@ -1425,13 +1429,19 @@ ARG USE_CONSTRAINTS_FOR_CONTEXT_PACKAGES="false"
ARG AIRFLOW_CI_BUILD_EPOCH="10"
ENV AIRFLOW_CI_BUILD_EPOCH=${AIRFLOW_CI_BUILD_EPOCH}
+
# In case of Production build image segment we want to pre-install main version of airflow
# dependencies from GitHub so that we do not have to always reinstall it from the scratch.
# The Airflow and providers are uninstalled, only dependencies remain
# the cache is only used when "upgrade to newer dependencies" is not set to automatically
# account for removed dependencies (we do not install them in the first place) and in case
# INSTALL_PACKAGES_FROM_CONTEXT is not set (because then caching it from main makes no sense).
-RUN bash /scripts/docker/install_pip_version.sh; \
+
+# By default PIP installs everything to ~/.local and it's also treated as VIRTUALENV
+ENV VIRTUAL_ENV="${AIRFLOW_USER_HOME_DIR}/.local"
+
+RUN bash /scripts/docker/install_packaging_tools.sh; \
+ bash /scripts/docker/create_prod_venv.sh; \
if [[ ${AIRFLOW_PRE_CACHED_PIP_PACKAGES} == "true" && \
${INSTALL_PACKAGES_FROM_CONTEXT} == "false" && \
${UPGRADE_TO_NEWER_DEPENDENCIES} == "false" ]]; then \
@@ -1454,7 +1464,7 @@ ENV ADDITIONAL_PYTHON_DEPS=${ADDITIONAL_PYTHON_DEPS} \
WORKDIR ${AIRFLOW_HOME}
COPY --from=scripts install_from_docker_context_files.sh install_airflow.sh \
- install_additional_dependencies.sh /scripts/docker/
+ install_additional_dependencies.sh create_prod_venv.sh /scripts/docker/
# Useful for creating a cache id based on the underlying architecture, preventing the use of cached python packages from
# an incorrect architecture.
@@ -1476,8 +1486,8 @@ RUN --mount=type=cache,id=$PYTHON_BASE_IMAGE-$AIRFLOW_PIP_VERSION-$TARGETARCH-$P
find "${AIRFLOW_USER_HOME_DIR}/.local/" -name '*.pyc' -print0 | xargs -0 rm -f || true ; \
find "${AIRFLOW_USER_HOME_DIR}/.local/" -type d -name '__pycache__' -print0 | xargs -0 rm -rf || true ; \
# make sure that all directories and files in .local are also group accessible
- find "${AIRFLOW_USER_HOME_DIR}/.local" -executable -print0 | xargs --null chmod g+x; \
- find "${AIRFLOW_USER_HOME_DIR}/.local" -print0 | xargs --null chmod g+rw
+ find "${AIRFLOW_USER_HOME_DIR}/.local" -executable ! -type l -print0 | xargs --null chmod g+x; \
+ find "${AIRFLOW_USER_HOME_DIR}/.local" ! -type l -print0 | xargs --null chmod g+rw
# In case there is a requirements.txt file in "docker-context-files" it will be installed
# during the build additionally to whatever has been installed so far. It is recommended that
@@ -1485,7 +1495,7 @@ RUN --mount=type=cache,id=$PYTHON_BASE_IMAGE-$AIRFLOW_PIP_VERSION-$TARGETARCH-$P
# hadolint ignore=DL3042
RUN --mount=type=cache,id=additional-requirements-$PYTHON_BASE_IMAGE-$AIRFLOW_PIP_VERSION-$TARGETARCH-$PIP_CACHE_EPOCH,target=/tmp/.cache/pip,uid=${AIRFLOW_UID} \
if [[ -f /docker-context-files/requirements.txt ]]; then \
- pip install --user -r /docker-context-files/requirements.txt; \
+ pip install -r /docker-context-files/requirements.txt; \
fi
##############################################################################################
@@ -1507,9 +1517,6 @@ LABEL org.apache.airflow.distro="debian" \
org.apache.airflow.uid="${AIRFLOW_UID}"
ARG PYTHON_BASE_IMAGE
-ARG AIRFLOW_PIP_VERSION
-ARG AIRFLOW_UV_VERSION
-ARG AIRFLOW_USE_UV
ENV PYTHON_BASE_IMAGE=${PYTHON_BASE_IMAGE} \
# Make sure noninteractive debian install is used and language variables set
@@ -1550,6 +1557,7 @@ ARG AIRFLOW_HOME
# By default PIP installs everything to ~/.local
ENV PATH="${AIRFLOW_USER_HOME_DIR}/.local/bin:${PATH}" \
+ VIRTUAL_ENV="${AIRFLOW_USER_HOME_DIR}/.local" \
AIRFLOW_UID=${AIRFLOW_UID} \
AIRFLOW_USER_HOME_DIR=${AIRFLOW_USER_HOME_DIR} \
AIRFLOW_HOME=${AIRFLOW_HOME}
@@ -1575,8 +1583,12 @@ RUN bash /scripts/docker/install_mysql.sh prod \
&& mkdir -pv "${AIRFLOW_HOME}/logs" \
&& chown -R airflow:0 "${AIRFLOW_USER_HOME_DIR}" "${AIRFLOW_HOME}" \
&& chmod -R g+rw "${AIRFLOW_USER_HOME_DIR}" "${AIRFLOW_HOME}" \
- && find "${AIRFLOW_HOME}" -executable -print0 | xargs --null chmod g+x \
- && find "${AIRFLOW_USER_HOME_DIR}" -executable -print0 | xargs --null chmod g+x
+ && find "${AIRFLOW_HOME}" -executable ! -type l -print0 | xargs --null chmod g+x \
+ && find "${AIRFLOW_USER_HOME_DIR}" -executable ! -type l -print0 | xargs --null chmod g+x
+
+ARG AIRFLOW_PIP_VERSION
+ARG AIRFLOW_UV_VERSION
+ARG AIRFLOW_USE_UV
COPY --from=airflow-build-image --chown=airflow:0 \
"${AIRFLOW_USER_HOME_DIR}/.local" "${AIRFLOW_USER_HOME_DIR}/.local"
@@ -1585,9 +1597,6 @@ COPY --from=scripts clean-logs.sh /clean-logs
COPY --from=scripts airflow-scheduler-autorestart.sh /airflow-scheduler-autorestart
-ARG AIRFLOW_PIP_VERSION
-ARG AIRFLOW_UV_VERSION
-ARG AIRFLOW_USE_UV
# Make /etc/passwd root-group-writeable so that user can be dynamically added by OpenShift
# See https://github.com/apache/airflow/issues/9248
@@ -1604,8 +1613,8 @@ RUN sed --in-place=.bak "s/secure_path=\"/secure_path=\"\/.venv\/bin:/" /etc/sud
ARG AIRFLOW_VERSION
-COPY --from=scripts install_pip_version.sh /scripts/docker/
-RUN bash /scripts/docker/install_pip_version.sh
+COPY --from=scripts install_packaging_tools.sh /scripts/docker/
+RUN bash /scripts/docker/install_packaging_tools.sh
# See https://airflow.apache.org/docs/docker-stack/entrypoint.html#signal-propagation
# to learn more about the way how signals are handled by the image
@@ -1614,7 +1623,6 @@ ENV DUMB_INIT_SETSID="1" \
PS1="(airflow)" \
AIRFLOW_VERSION=${AIRFLOW_VERSION} \
AIRFLOW__CORE__LOAD_EXAMPLES="false" \
- PIP_USER="true" \
PATH="/root/bin:${PATH}" \
AIRFLOW_PIP_VERSION=${AIRFLOW_PIP_VERSION} \
AIRFLOW_UV_VERSION=${AIRFLOW_UV_VERSION} \
diff --git a/Dockerfile.ci b/Dockerfile.ci
index 9b1aaf3aa0..16266a2abb 100644
--- a/Dockerfile.ci
+++ b/Dockerfile.ci
@@ -370,18 +370,13 @@ if [[ ${INSTALL_POSTGRES_CLIENT:="true"} == "true" ]]; then
fi
EOF
-# The content below is automatically copied from scripts/docker/install_pip_version.sh
-COPY <<"EOF" /install_pip_version.sh
+# The content below is automatically copied from scripts/docker/install_packaging_tools.sh
+COPY <<"EOF" /install_packaging_tools.sh
#!/usr/bin/env bash
. "$( dirname "${BASH_SOURCE[0]}" )/common.sh"
common::get_colors
-common::get_packaging_tool
-common::get_airflow_version_specification
-common::override_pip_version_if_needed
-common::show_packaging_tool_version_and_location
-
-common::install_packaging_tool
+common::install_packaging_tools
EOF
# The content below is automatically copied from scripts/docker/install_airflow_dependencies_from_branch_tip.sh
@@ -412,7 +407,7 @@ function install_airflow_dependencies_from_branch_tip() {
${PACKAGING_TOOL_CMD} install ${EXTRA_INSTALL_FLAGS} \
${ADDITIONAL_PIP_INSTALL_FLAGS} \
"apache-airflow[${AIRFLOW_EXTRAS}] @ https://github.com/${AIRFLOW_REPO}/archive/${AIRFLOW_BRANCH}.tar.gz"
- common::install_packaging_tool
+ common::install_packaging_tools
# Uninstall airflow and providers to keep only the dependencies. In the future when
# planned https://github.com/pypa/pip/issues/11440 is implemented in pip we might be able to use this
# flag and skip the remove step.
@@ -427,7 +422,6 @@ function install_airflow_dependencies_from_branch_tip() {
common::get_colors
common::get_packaging_tool
common::get_airflow_version_specification
-common::override_pip_version_if_needed
common::get_constraints_location
common::show_packaging_tool_version_and_location
@@ -467,7 +461,11 @@ function common::get_packaging_tool() {
echo
export PACKAGING_TOOL="uv"
export PACKAGING_TOOL_CMD="uv pip"
- export EXTRA_INSTALL_FLAGS="--python ${PYTHON_BIN}"
+ if [[ -z ${VIRTUAL_ENV=} ]]; then
+ export EXTRA_INSTALL_FLAGS="--python ${PYTHON_BIN}"
+ else
+ export EXTRA_INSTALL_FLAGS=""
+ fi
export EXTRA_UNINSTALL_FLAGS="--python ${PYTHON_BIN}"
export RESOLUTION_HIGHEST_FLAG="--resolution highest"
export RESOLUTION_LOWEST_DIRECT_FLAG="--resolution lowest-direct"
@@ -492,14 +490,6 @@ function common::get_airflow_version_specification() {
fi
}
-function common::override_pip_version_if_needed() {
- if [[ -n ${AIRFLOW_VERSION} ]]; then
- if [[ ${AIRFLOW_VERSION} =~ ^2\.0.* || ${AIRFLOW_VERSION} =~ ^1\.* ]]; then
- export AIRFLOW_PIP_VERSION=24.0
- fi
- fi
-}
-
function common::get_constraints_location() {
# auto-detect Airflow-constraint reference and location
if [[ -z "${AIRFLOW_CONSTRAINTS_REFERENCE=}" ]]; then
@@ -526,12 +516,12 @@ function common::show_packaging_tool_version_and_location() {
echo "Using pip: $(pip --version)"
else
echo "${COLOR_BLUE}Using 'uv' to install Airflow${COLOR_RESET}"
- echo "uv on path: $(which uv)"
+ echo "uv on path: $(which uv 2>/dev/null || echo "Not installed")"
echo "Using uv: $(uv --version)"
fi
}
-function common::install_packaging_tool() {
+function common::install_packaging_tools() {
echo
echo "${COLOR_BLUE}Installing pip version ${AIRFLOW_PIP_VERSION}${COLOR_RESET}"
echo
@@ -542,17 +532,15 @@ function common::install_packaging_tool() {
# shellcheck disable=SC2086
pip install --root-user-action ignore --disable-pip-version-check "pip==${AIRFLOW_PIP_VERSION}"
fi
- if [[ ${AIRFLOW_USE_UV} == "true" ]]; then
- echo
- echo "${COLOR_BLUE}Installing uv version ${AIRFLOW_UV_VERSION}${COLOR_RESET}"
- echo
- if [[ ${AIRFLOW_UV_VERSION} =~ .*https.* ]]; then
- # shellcheck disable=SC2086
- pip install --root-user-action ignore --disable-pip-version-check "uv @ ${AIRFLOW_UV_VERSION}"
- else
- # shellcheck disable=SC2086
- pip install --root-user-action ignore --disable-pip-version-check "uv==${AIRFLOW_UV_VERSION}"
- fi
+ echo
+ echo "${COLOR_BLUE}Installing uv version ${AIRFLOW_UV_VERSION}${COLOR_RESET}"
+ echo
+ if [[ ${AIRFLOW_UV_VERSION} =~ .*https.* ]]; then
+ # shellcheck disable=SC2086
+ pip install --root-user-action ignore --disable-pip-version-check "uv @ ${AIRFLOW_UV_VERSION}"
+ else
+ # shellcheck disable=SC2086
+ pip install --root-user-action ignore --disable-pip-version-check "uv==${AIRFLOW_UV_VERSION}"
fi
mkdir -p "${HOME}/.local/bin"
}
@@ -659,7 +647,7 @@ function install_airflow() {
"${AIRFLOW_INSTALLATION_METHOD}[${AIRFLOW_EXTRAS}]${AIRFLOW_VERSION_SPECIFICATION}" \
${EAGER_UPGRADE_ADDITIONAL_REQUIREMENTS=}
set +x
- common::install_packaging_tool
+ common::install_packaging_tools
echo
echo "${COLOR_BLUE}Running '${PACKAGING_TOOL} check'${COLOR_RESET}"
echo
@@ -673,13 +661,13 @@ function install_airflow() {
${ADDITIONAL_PIP_INSTALL_FLAGS} \
"${AIRFLOW_INSTALLATION_METHOD}[${AIRFLOW_EXTRAS}]${AIRFLOW_VERSION_SPECIFICATION}" \
--constraint "${AIRFLOW_CONSTRAINTS_LOCATION}" || true
- common::install_packaging_tool
+ common::install_packaging_tools
# then upgrade if needed without using constraints to account for new limits in pyproject.toml
${PACKAGING_TOOL_CMD} install ${EXTRA_INSTALL_FLAGS} --upgrade ${RESOLUTION_LOWEST_DIRECT_FLAG} \
${ADDITIONAL_PIP_INSTALL_FLAGS} \
${AIRFLOW_INSTALL_EDITABLE_FLAG} \
"${AIRFLOW_INSTALLATION_METHOD}[${AIRFLOW_EXTRAS}]${AIRFLOW_VERSION_SPECIFICATION}"
- common::install_packaging_tool
+ common::install_packaging_tools
set +x
echo
echo "${COLOR_BLUE}Running 'pip check'${COLOR_RESET}"
@@ -692,7 +680,6 @@ function install_airflow() {
common::get_colors
common::get_packaging_tool
common::get_airflow_version_specification
-common::override_pip_version_if_needed
common::get_constraints_location
common::show_packaging_tool_version_and_location
@@ -718,7 +705,7 @@ function install_additional_dependencies() {
${PACKAGING_TOOL_CMD} install ${EXTRA_INSTALL_FLAGS} --upgrade ${RESOLUTION_HIGHEST_FLAG} \
${ADDITIONAL_PIP_INSTALL_FLAGS} \
${ADDITIONAL_PYTHON_DEPS} ${EAGER_UPGRADE_ADDITIONAL_REQUIREMENTS=}
- common::install_packaging_tool
+ common::install_packaging_tools
set +x
echo
echo "${COLOR_BLUE}Running 'pip check'${COLOR_RESET}"
@@ -732,7 +719,7 @@ function install_additional_dependencies() {
${PACKAGING_TOOL_CMD} install ${EXTRA_INSTALL_FLAGS} --upgrade "${RESOLUTION_LOWEST_DIRECT_FLAG}" \
${ADDITIONAL_PIP_INSTALL_FLAGS} \
${ADDITIONAL_PYTHON_DEPS}
- common::install_packaging_tool
+ common::install_packaging_tools
set +x
echo
echo "${COLOR_BLUE}Running 'pip check'${COLOR_RESET}"
@@ -744,7 +731,6 @@ function install_additional_dependencies() {
common::get_colors
common::get_packaging_tool
common::get_airflow_version_specification
-common::override_pip_version_if_needed
common::get_constraints_location
common::show_packaging_tool_version_and_location
@@ -1205,12 +1191,6 @@ ENV AIRFLOW_REPO=${AIRFLOW_REPO}\
AIRFLOW_PIP_VERSION=${AIRFLOW_PIP_VERSION} \
AIRFLOW_UV_VERSION=${AIRFLOW_UV_VERSION} \
AIRFLOW_USE_UV=${AIRFLOW_USE_UV} \
-# In the CI image we always:
-# * install MySQL, MsSQL
-# * install airflow from current sources, not from PyPI package
-# * install airflow without `--user` flag
-# * install airflow in editable mode
-# * install always current version of airflow
INSTALL_MYSQL_CLIENT="true" \
INSTALL_MYSQL_CLIENT_TYPE=${INSTALL_MYSQL_CLIENT_TYPE} \
INSTALL_MSSQL_CLIENT="true" \
@@ -1229,7 +1209,7 @@ RUN echo "Airflow version: ${AIRFLOW_VERSION}"
# Copy all scripts required for installation - changing any of those should lead to
# rebuilding from here
-COPY --from=scripts install_pip_version.sh install_airflow_dependencies_from_branch_tip.sh \
+COPY --from=scripts install_packaging_tools.sh install_airflow_dependencies_from_branch_tip.sh \
common.sh /scripts/docker/
# We are first creating a venv where all python packages and .so binaries needed by those are
@@ -1240,7 +1220,7 @@ COPY --from=scripts install_pip_version.sh install_airflow_dependencies_from_bra
# The Airflow and providers are uninstalled, only dependencies remain.
# the cache is only used when "upgrade to newer dependencies" is not set to automatically
# account for removed dependencies (we do not install them in the first place)
-RUN bash /scripts/docker/install_pip_version.sh; \
+RUN bash /scripts/docker/install_packaging_tools.sh; \
if [[ ${AIRFLOW_PRE_CACHED_PIP_PACKAGES} == "true" ]]; then \
bash /scripts/docker/install_airflow_dependencies_from_branch_tip.sh; \
fi
@@ -1290,12 +1270,12 @@ COPY --from=scripts entrypoint_ci.sh /entrypoint
COPY --from=scripts entrypoint_exec.sh /entrypoint-exec
RUN chmod a+x /entrypoint /entrypoint-exec
-COPY --from=scripts install_pip_version.sh install_additional_dependencies.sh /scripts/docker/
+COPY --from=scripts install_packaging_tools.sh install_additional_dependencies.sh /scripts/docker/
# Additional python deps to install
ARG ADDITIONAL_PYTHON_DEPS=""
-RUN bash /scripts/docker/install_pip_version.sh; \
+RUN bash /scripts/docker/install_packaging_tools.sh; \
if [[ -n "${ADDITIONAL_PYTHON_DEPS}" ]]; then \
bash /scripts/docker/install_additional_dependencies.sh; \
fi
diff --git a/dev/breeze/doc/images/output_prod-image_build.svg b/dev/breeze/doc/images/output_prod-image_build.svg
index be7de879be..2922742183 100644
--- a/dev/breeze/doc/images/output_prod-image_build.svg
+++ b/dev/breeze/doc/images/output_prod-image_build.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 2538.7999999999997" xmlns="http://www.w3.org/2000/svg">
+<svg class="rich-terminal" viewBox="0 0 1482 2563.2" xmlns="http://www.w3.org/2000/svg">
<!-- Generated with Rich https://www.textualize.io -->
<style>
@@ -37,13 +37,13 @@
.breeze-prod-image-build-r3 { fill: #c5c8c6;font-weight: bold }
.breeze-prod-image-build-r4 { fill: #68a0b3;font-weight: bold }
.breeze-prod-image-build-r5 { fill: #868887 }
-.breeze-prod-image-build-r6 { fill: #98a84b;font-weight: bold }
-.breeze-prod-image-build-r7 { fill: #8d7b39 }
+.breeze-prod-image-build-r6 { fill: #8d7b39 }
+.breeze-prod-image-build-r7 { fill: #98a84b;font-weight: bold }
</style>
<defs>
<clipPath id="breeze-prod-image-build-clip-terminal">
- <rect x="0" y="0" width="1463.0" height="2487.7999999999997" />
+ <rect x="0" y="0" width="1463.0" height="2512.2" />
</clipPath>
<clipPath id="breeze-prod-image-build-line-0">
<rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -348,9 +348,12 @@
<clipPath id="breeze-prod-image-build-line-100">
<rect x="0" y="2441.5" width="1464" height="24.65"/>
</clipPath>
+<clipPath id="breeze-prod-image-build-line-101">
+ <rect x="0" y="2465.9" width="1464" height="24.65"/>
+ </clipPath>
</defs>
- <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="1" y="1" width="1480" height="2536.8" rx="8"/><text class="breeze-prod-image-build-title" fill="#c5c8c6" text-anchor="middle" x="740" y="27">Command: prod-image build</text>
+ <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="1" y="1" width="1480" height="2561.2" rx="8"/><text class="breeze-prod-image-build-title" fill="#c5c8c6" text-anchor="middle" x="740" y="27">Command: prod-image build</text>
<g transform="translate(26,22)">
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -366,102 +369,103 @@
</text><text class="breeze-prod-image-build-r1" x="12.2" y="93.2" textLength="1293.2" clip-path="url(#breeze-prod-image-build-line-3)">Build Production image. Include building multiple images for all or selected Python versions sequentially.</text><text class="breeze-prod-image-build-r1" x="1464" y="93.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-3)">
</text><text class="breeze-prod-image-build-r1" x="1464" y="117.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-4)">
</text><text class="breeze-prod-image-build-r5" x="0" y="142" textLength="24.4" clip-path="url(#breeze-prod-image-build-line-5)">╭─</text><text class="breeze-prod-image-build-r5" x="24.4" y="142" textLength="158.6" clip-path="url(#breeze-prod-image-build-line-5)"> Basic usage </text><text class="breeze-prod-image-build-r5" x="183" y="142" textLength="1256.6" clip-path="url(#breeze-prod-image-build-line-5)">─────────────────────────────────────────────────────────────────── [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="166.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-6)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="166.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-6)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="166.4" textLength="85.4" clip-path="url(#breeze-prod-image-build-line-6)">-python</text><text class="breeze-prod-image-build-r6" x="353.8" y="166.4" textLength="24.4 [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="190.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-7)">│</text><text class="breeze-prod-image-build-r7" x="402.6" y="190.8" textLength="732" clip-path="url(#breeze-prod-image-build-line-7)">(>3.8< | 3.9 | 3.10 | 3.11)                           & [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="215.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-8)">│</text><text class="breeze-prod-image-build-r5" x="402.6" y="215.2" textLength="732" clip-path="url(#breeze-prod-image-build-line-8)">[default: 3.8]                                   [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="239.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-9)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="239.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-9)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="239.6" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-9)">-install</text><text class="breeze-prod-image-build-r4" x="134.2" y="239.6" textLength="195 [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="264" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-10)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="264" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-10)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="264" textLength="73.2" clip-path="url(#breeze-prod-image-build-line-10)">-image</text><text class="breeze-prod-image-build-r4" x="109.8" y="264" textLength="48.8" clip [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="288.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-11)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="288.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-11)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="288.4" textLength="48.8" clip-path="url(#breeze-prod-image-build-line-11)">-tag</text><text class="breeze-prod-image-build-r4" x="85.4" y="288.4" textLength="122" [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="312.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-12)">│</text><text class="breeze-prod-image-build-r1" x="402.6" y="312.8" textLength="353.8" clip-path="url(#breeze-prod-image-build-line-12)">you build or pull image with </text><text class="breeze-prod-image-build-r4" x="756.4" y="312.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-12)">-</text><text class="breeze [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="337.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-13)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="337.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-13)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="337.2" textLength="85.4" clip-path="url(#breeze-prod-image-build-line-13)">-docker</text><text class="breeze-prod-image-build-r4" x="122" y="337.2" textLength="73. [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="361.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-14)">│</text><text class="breeze-prod-image-build-r5" x="402.6" y="361.6" textLength="549" clip-path="url(#breeze-prod-image-build-line-14)">[default: registry]                          </text><text class="breeze-prod-image-build- [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="386" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-15)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="386" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-15)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="386" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-15)">-version</text><text class="breeze-prod-image-build-r4" x="134.2" y="386" textLength="195.2" c [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="410.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-16)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="410.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-16)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="410.4" textLength="73.2" clip-path="url(#breeze-prod-image-build-line-16)">-build</text><text class="breeze-prod-image-build-r4" x="109.8" y="410.4" textLength="10 [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="434.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-17)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="434.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-17)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="434.8" textLength="85.4" clip-path="url(#breeze-prod-image-build-line-17)">-docker</text><text class="breeze-prod-image-build-r4" x="122" y="434.8" textLength="61" [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="459.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-18)">│</text><text class="breeze-prod-image-build-r1" x="402.6" y="459.2" textLength="1037" clip-path="url(#breeze-prod-image-build-line-18)">option is ignored when building images.                           [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="483.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-19)">│</text><text class="breeze-prod-image-build-r7" x="402.6" y="483.6" textLength="1037" clip-path="url(#breeze-prod-image-build-line-19)">(TEXT)                                    & [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="508" textLength="1464" clip-path="url(#breeze-prod-image-build-line-20)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text class="breeze-prod-image-build-r1" x="1464" y="508" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-20)">
-</text><text class="breeze-prod-image-build-r5" x="0" y="532.4" textLength="24.4" clip-path="url(#breeze-prod-image-build-line-21)">╭─</text><text class="breeze-prod-image-build-r5" x="24.4" y="532.4" textLength="353.8" clip-path="url(#breeze-prod-image-build-line-21)"> Building images in parallel </text><text class="breeze-prod-image-build-r5" x="378.2" y="532.4" textLength="1061.4" clip-path="url(#breeze-prod-image-build-line-21)">────────────────────────────── [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="556.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-22)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="556.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-22)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="556.8" textLength="48.8" clip-path="url(#breeze-prod-image-build-line-22)">-run</text><text class="breeze-prod-image-build-r4" x="85.4" y="556.8" textLength="146.4 [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="581.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-23)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="581.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-23)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="581.2" textLength="146.4" clip-path="url(#breeze-prod-image-build-line-23)">-parallelism</text><text class="breeze-prod-image-build-r1" x="378.2" y="581.2" textLen [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="605.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-24)">│</text><text class="breeze-prod-image-build-r7" x="378.2" y="605.6" textLength="915" clip-path="url(#breeze-prod-image-build-line-24)">(INTEGER RANGE)                                   [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="630" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-25)">│</text><text class="breeze-prod-image-build-r5" x="378.2" y="630" textLength="915" clip-path="url(#breeze-prod-image-build-line-25)">[default: 4; 1<=x<=8]                                 [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="654.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-26)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="654.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-26)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="654.4" textLength="85.4" clip-path="url(#breeze-prod-image-build-line-26)">-python</text><text class="breeze-prod-image-build-r4" x="122" y="654.4" textLength="109 [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="678.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-27)">│</text><text class="breeze-prod-image-build-r5" x="378.2" y="678.8" textLength="951.6" clip-path="url(#breeze-prod-image-build-line-27)">[default: 3.8 3.9 3.10 3.11]                              [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="703.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-28)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="703.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-28)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="703.2" textLength="61" clip-path="url(#breeze-prod-image-build-line-28)">-skip</text><text class="breeze-prod-image-build-r4" x="97.6" y="703.2" textLength="97.6" [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="727.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-29)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="727.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-29)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="727.6" textLength="73.2" clip-path="url(#breeze-prod-image-build-line-29)">-debug</text><text class="breeze-prod-image-build-r4" x="109.8" y="727.6" textLength="12 [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="752" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-30)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="752" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-30)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="752" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-30)">-include</text><text class="breeze-prod-image-build-r4" x="134.2" y="752" textLength="195.2" c [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="776.4" textLength="1464" clip-path="url(#breeze-prod-image-build-line-31)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text class="breeze-prod-image-build-r1" x="1464" y="776.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-31)">
-</text><text class="breeze-prod-image-build-r5" x="0" y="800.8" textLength="24.4" clip-path="url(#breeze-prod-image-build-line-32)">╭─</text><text class="breeze-prod-image-build-r5" x="24.4" y="800.8" textLength="512.4" clip-path="url(#breeze-prod-image-build-line-32)"> Advanced build options (for power users) </text><text class="breeze-prod-image-build-r5" x="536.8" y="800.8" textLength="902.8" clip-path="url(#breeze-prod-image-build-line-32)">──────── [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="825.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-33)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="825.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-33)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="825.2" textLength="134.2" clip-path="url(#breeze-prod-image-build-line-33)">-additional</text><text class="breeze-prod-image-build-r4" x="170.8" y="825.2" textLeng [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="849.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-34)">│</text><text class="breeze-prod-image-build-r1" x="439.2" y="849.6" textLength="1000.4" clip-path="url(#breeze-prod-image-build-line-34)">itself).                                    [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="874" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-35)">│</text><text class="breeze-prod-image-build-r7" x="439.2" y="874" textLength="1000.4" clip-path="url(#breeze-prod-image-build-line-35)">(TEXT)                                     [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="898.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-36)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="898.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-36)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="898.4" textLength="85.4" clip-path="url(#breeze-prod-image-build-line-36)">-commit</text><text class="breeze-prod-image-build-r4" x="122" y="898.4" textLength="48. [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="922.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-37)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="922.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-37)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="922.8" textLength="85.4" clip-path="url(#breeze-prod-image-build-line-37)">-debian</text><text class="breeze-prod-image-build-r4" x="122" y="922.8" textLength="97. [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="947.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-38)">│</text><text class="breeze-prod-image-build-r7" x="439.2" y="947.2" textLength="793" clip-path="url(#breeze-prod-image-build-line-38)">(bookworm | bullseye)                                & [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="971.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-39)">│</text><text class="breeze-prod-image-build-r5" x="439.2" y="971.6" textLength="793" clip-path="url(#breeze-prod-image-build-line-39)">[default: bookworm]                                 &# [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="996" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-40)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="996" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-40)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="996" textLength="85.4" clip-path="url(#breeze-prod-image-build-line-40)">-python</text><text class="breeze-prod-image-build-r4" x="122" y="996" textLength="73.2" clip- [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1020.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-41)">│</text><text class="breeze-prod-image-build-r1" x="439.2" y="1020.4" textLength="1000.4" clip-path="url(#breeze-prod-image-build-line-41)">something like: python:VERSION-slim-bookworm.                           &# [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1044.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-42)">│</text><text class="breeze-prod-image-build-r7" x="439.2" y="1044.8" textLength="1000.4" clip-path="url(#breeze-prod-image-build-line-42)">(TEXT)                                    [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1069.2" textLength="1464" clip-path="url(#breeze-prod-image-build-line-43)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text class="breeze-prod-image-build-r1" x="1464" y="1069.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-43)">
-</text><text class="breeze-prod-image-build-r5" x="0" y="1093.6" textLength="24.4" clip-path="url(#breeze-prod-image-build-line-44)">╭─</text><text class="breeze-prod-image-build-r5" x="24.4" y="1093.6" textLength="597.8" clip-path="url(#breeze-prod-image-build-line-44)"> Selecting constraint location (for power users) </text><text class="breeze-prod-image-build-r5" x="622.2" y="1093.6" textLength="817.4" clip-path="url(#breeze-prod-image-build-line-44) [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1118" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-45)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1118" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-45)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1118" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-45)">-airflow</text><text class="breeze-prod-image-build-r4" x="134.2" y="1118" textLength="256. [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1142.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-46)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1142.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-46)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1142.4" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-46)">-airflow</text><text class="breeze-prod-image-build-r4" x="134.2" y="1142.4" textLeng [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1166.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-47)">│</text><text class="breeze-prod-image-build-r7" x="451.4" y="1166.8" textLength="866.2" clip-path="url(#breeze-prod-image-build-line-47)">(constraints | constraints-no-providers | constraints-source-providers)</text><text class="breeze-prod-image-build-r5" x="1451.8" y="1166.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-l [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1191.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-48)">│</text><text class="breeze-prod-image-build-r5" x="451.4" y="1191.2" textLength="866.2" clip-path="url(#breeze-prod-image-build-line-48)">[default: constraints]                                & [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1215.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-49)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1215.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-49)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1215.6" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-49)">-airflow</text><text class="breeze-prod-image-build-r4" x="134.2" y="1215.6" textLeng [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1240" textLength="1464" clip-path="url(#breeze-prod-image-build-line-50)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text class="breeze-prod-image-build-r1" x="1464" y="1240" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-50)">
-</text><text class="breeze-prod-image-build-r5" x="0" y="1264.4" textLength="24.4" clip-path="url(#breeze-prod-image-build-line-51)">╭─</text><text class="breeze-prod-image-build-r5" x="24.4" y="1264.4" textLength="634.4" clip-path="url(#breeze-prod-image-build-line-51)"> Choosing dependencies and extras (for power users) </text><text class="breeze-prod-image-build-r5" x="658.8" y="1264.4" textLength="780.8" clip-path="url(#breeze-prod-image-build- [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1288.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-52)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1288.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-52)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1288.8" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-52)">-airflow</text><text class="breeze-prod-image-build-r4" x="134.2" y="1288.8" textLeng [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1313.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-53)">│</text><text class="breeze-prod-image-build-r7" x="463.6" y="1313.2" textLength="976" clip-path="url(#breeze-prod-image-build-line-53)">(TEXT)                                     [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1337.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-54)">│</text><text class="breeze-prod-image-build-r5" x="463.6" y="1337.6" textLength="976" clip-path="url(#breeze-prod-image-build-line-54)">[default:                                    [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1362" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-55)">│</text><text class="breeze-prod-image-build-r5" x="463.6" y="1362" textLength="976" clip-path="url(#breeze-prod-image-build-line-55)">aiobotocore,amazon,async,celery,cncf-kubernetes,common-io,docker,elasticsearch,…</text><text class="breeze-prod-image-build-r5" x="1451.8" y="1362" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-55)">│</text><t [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1386.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-56)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1386.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-56)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1386.4" textLength="134.2" clip-path="url(#breeze-prod-image-build-line-56)">-additional</text><text class="breeze-prod-image-build-r4" x="170.8" y="1386.4" text [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1410.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-57)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1410.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-57)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1410.8" textLength="134.2" clip-path="url(#breeze-prod-image-build-line-57)">-additional</text><text class="breeze-prod-image-build-r4" x="170.8" y="1410.8" text [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1435.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-58)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1435.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-58)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1435.2" textLength="48.8" clip-path="url(#breeze-prod-image-build-line-58)">-dev</text><text class="breeze-prod-image-build-r4" x="85.4" y="1435.2" textLength="1 [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1459.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-59)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1459.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-59)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1459.6" textLength="134.2" clip-path="url(#breeze-prod-image-build-line-59)">-additional</text><text class="breeze-prod-image-build-r4" x="170.8" y="1459.6" text [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1484" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-60)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1484" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-60)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1484" textLength="48.8" clip-path="url(#breeze-prod-image-build-line-60)">-dev</text><text class="breeze-prod-image-build-r4" x="85.4" y="1484" textLength="146.4" cl [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1508.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-61)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1508.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-61)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1508.4" textLength="134.2" clip-path="url(#breeze-prod-image-build-line-61)">-additional</text><text class="breeze-prod-image-build-r4" x="170.8" y="1508.4" text [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1532.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-62)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1532.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-62)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1532.8" textLength="134.2" clip-path="url(#breeze-prod-image-build-line-62)">-additional</text><text class="breeze-prod-image-build-r4" x="170.8" y="1532.8" text [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1557.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-63)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1557.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-63)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1557.2" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-63)">-runtime</text><text class="breeze-prod-image-build-r4" x="134.2" y="1557.2" textLeng [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1581.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-64)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1581.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-64)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1581.6" textLength="134.2" clip-path="url(#breeze-prod-image-build-line-64)">-additional</text><text class="breeze-prod-image-build-r4" x="170.8" y="1581.6" text [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1606" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-65)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1606" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-65)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1606" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-65)">-runtime</text><text class="breeze-prod-image-build-r4" x="134.2" y="1606" textLength="146. [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1630.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-66)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1630.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-66)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1630.4" textLength="134.2" clip-path="url(#breeze-prod-image-build-line-66)">-additional</text><text class="breeze-prod-image-build-r4" x="170.8" y="1630.4" text [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1654.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-67)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1654.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-67)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1654.8" textLength="134.2" clip-path="url(#breeze-prod-image-build-line-67)">-additional</text><text class="breeze-prod-image-build-r4" x="170.8" y="1654.8" text [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1679.2" textLength="1464" clip-path="url(#breeze-prod-image-build-line-68)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text class="breeze-prod-image-build-r1" x="1464" y="1679.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-68)">
-</text><text class="breeze-prod-image-build-r5" x="0" y="1703.6" textLength="24.4" clip-path="url(#breeze-prod-image-build-line-69)">╭─</text><text class="breeze-prod-image-build-r5" x="24.4" y="1703.6" textLength="817.4" clip-path="url(#breeze-prod-image-build-line-69)"> Advanced customization options (for specific customization needs) </text><text class="breeze-prod-image-build-r5" x="841.8" y="1703.6" textLength="597.8" clip-path="url(#breeze-pr [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1728" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-70)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1728" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-70)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1728" textLength="158.6" clip-path="url(#breeze-prod-image-build-line-70)">-installation</text><text class="breeze-prod-image-build-r4" x="195.2" y="1728" textLength [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1752.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-71)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1752.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-71)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1752.4" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-71)">-install</text><text class="breeze-prod-image-build-r4" x="134.2" y="1752.4" textLeng [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1776.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-72)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1776.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-72)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1776.8" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-72)">-install</text><text class="breeze-prod-image-build-r4" x="134.2" y="1776.8" textLeng [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1801.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-73)">│</text><text class="breeze-prod-image-build-r1" x="536.8" y="1801.2" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-73)">Implies </text><text class="breeze-prod-image-build-r4" x="634.4" y="1801.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-73)">-</text><text class="breeze-prod-image-build-r4" x="646.6" y="1801.2" t [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1825.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-74)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1825.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-74)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1825.6" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-74)">-install</text><text class="breeze-prod-image-build-r4" x="134.2" y="1825.6" textLeng [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1850" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-75)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1850" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-75)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1850" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-75)">-cleanup</text><text class="breeze-prod-image-build-r4" x="134.2" y="1850" textLength="97.6 [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1874.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-76)">│</text><text class="breeze-prod-image-build-r1" x="536.8" y="1874.4" textLength="170.8" clip-path="url(#breeze-prod-image-build-line-76)">together with </text><text class="breeze-prod-image-build-r4" x="707.6" y="1874.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-76)">-</text><text class="breeze-prod-image-build-r4" x="719.8" [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1898.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-77)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1898.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-77)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1898.8" textLength="48.8" clip-path="url(#breeze-prod-image-build-line-77)">-use</text><text class="breeze-prod-image-build-r4" x="85.4" y="1898.8" textLength="4 [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1923.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-78)">│</text><text class="breeze-prod-image-build-r1" x="536.8" y="1923.2" textLength="902.8" clip-path="url(#breeze-prod-image-build-line-78)">constraints store in docker-context-files or from github.                 </text><text class="breeze-prod [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1947.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-79)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1947.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-79)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1947.6" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-79)">-disable</text><text class="breeze-prod-image-build-r4" x="134.2" y="1947.6" textLeng [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1972" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-80)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1972" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-80)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1972" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-80)">-disable</text><text class="breeze-prod-image-build-r4" x="134.2" y="1972" textLength="317. [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="1996.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-81)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1996.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-81)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1996.4" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-81)">-disable</text><text class="breeze-prod-image-build-r4" x="134.2" y="1996.4" textLeng [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="2020.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-82)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2020.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-82)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2020.8" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-82)">-disable</text><text class="breeze-prod-image-build-r4" x="134.2" y="2020.8" textLeng [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="2045.2" textLength="1464" clip-path="url(#breeze-prod-image-build-line-83)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text class="breeze-prod-image-build-r1" x="1464" y="2045.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-83)">
-</text><text class="breeze-prod-image-build-r5" x="0" y="2069.6" textLength="24.4" clip-path="url(#breeze-prod-image-build-line-84)">╭─</text><text class="breeze-prod-image-build-r5" x="24.4" y="2069.6" textLength="622.2" clip-path="url(#breeze-prod-image-build-line-84)"> Preparing cache and push (for maintainers and CI) </text><text class="breeze-prod-image-build-r5" x="646.6" y="2069.6" textLength="793" clip-path="url(#breeze-prod-image-buil [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="2094" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-85)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2094" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-85)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2094" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-85)">-builder</text><text class="breeze-prod-image-build-r1" x="341.6" y="2094" textLength="756. [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="2118.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-86)">│</text><text class="breeze-prod-image-build-r5" x="341.6" y="2118.4" textLength="756.4" clip-path="url(#breeze-prod-image-build-line-86)">[default: autodetect]                                &# [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="2142.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-87)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2142.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-87)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2142.8" textLength="109.8" clip-path="url(#breeze-prod-image-build-line-87)">-platform</text><text class="breeze-prod-image-build-r1" x="341.6" y="2142.8" textLe [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="2167.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-88)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2167.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-88)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2167.2" textLength="61" clip-path="url(#breeze-prod-image-build-line-88)">-push</text><text class="breeze-prod-image-build-r1" x="341.6" y="2167.2" textLength="3 [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="2191.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-89)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2191.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-89)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2191.6" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-89)">-prepare</text><text class="breeze-prod-image-build-r4" x="134.2" y="2191.6" textLeng [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="2216" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-90)">│</text><text class="breeze-prod-image-build-r1" x="341.6" y="2216" textLength="1098" clip-path="url(#breeze-prod-image-build-line-90)">image).                                    &# [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="2240.4" textLength="1464" clip-path="url(#breeze-prod-image-build-line-91)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text class="breeze-prod-image-build-r1" x="1464" y="2240.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-91)">
-</text><text class="breeze-prod-image-build-r5" x="0" y="2264.8" textLength="24.4" clip-path="url(#breeze-prod-image-build-line-92)">╭─</text><text class="breeze-prod-image-build-r5" x="24.4" y="2264.8" textLength="280.6" clip-path="url(#breeze-prod-image-build-line-92)"> Github authentication </text><text class="breeze-prod-image-build-r5" x="305" y="2264.8" textLength="1134.6" clip-path="url(#breeze-prod-image-build-line-92)">───────────────────────────────────────────── [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="2289.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-93)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2289.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-93)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2289.2" textLength="85.4" clip-path="url(#breeze-prod-image-build-line-93)">-github</text><text class="breeze-prod-image-build-r4" x="122" y="2289.2" textLength= [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="2313.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-94)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2313.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-94)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2313.6" textLength="85.4" clip-path="url(#breeze-prod-image-build-line-94)">-github</text><text class="breeze-prod-image-build-r4" x="122" y="2313.6" textLength= [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="2338" textLength="1464" clip-path="url(#breeze-prod-image-build-line-95)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text class="breeze-prod-image-build-r1" x="1464" y="2338" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-95)">
-</text><text class="breeze-prod-image-build-r5" x="0" y="2362.4" textLength="24.4" clip-path="url(#breeze-prod-image-build-line-96)">╭─</text><text class="breeze-prod-image-build-r5" x="24.4" y="2362.4" textLength="195.2" clip-path="url(#breeze-prod-image-build-line-96)"> Common options </text><text class="breeze-prod-image-build-r5" x="219.6" y="2362.4" textLength="1220" clip-path="url(#breeze-prod-image-build-line-96)">──────────────────────────────────────────────────── [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="2386.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-97)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2386.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-97)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2386.8" textLength="85.4" clip-path="url(#breeze-prod-image-build-line-97)">-answer</text><text class="breeze-prod-image-build-r6" x="158.6" y="2386.8" textLengt [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="2411.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-98)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2411.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-98)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2411.2" textLength="48.8" clip-path="url(#breeze-prod-image-build-line-98)">-dry</text><text class="breeze-prod-image-build-r4" x="85.4" y="2411.2" textLength="4 [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="2435.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-99)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2435.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-99)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2435.6" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-99)">-verbose</text><text class="breeze-prod-image-build-r6" x="158.6" y="2435.6" textLeng [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="2460" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-100)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2460" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-100)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2460" textLength="61" clip-path="url(#breeze-prod-image-build-line-100)">-help</text><text class="breeze-prod-image-build-r6" x="158.6" y="2460" textLength="24.4" [...]
-</text><text class="breeze-prod-image-build-r5" x="0" y="2484.4" textLength="1464" clip-path="url(#breeze-prod-image-build-line-101)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text class="breeze-prod-image-build-r1" x="1464" y="2484.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-101)">
+</text><text class="breeze-prod-image-build-r5" x="0" y="166.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-6)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="166.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-6)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="166.4" textLength="73.2" clip-path="url(#breeze-prod-image-build-line-6)">-build</text><text class="breeze-prod-image-build-r4" x="109.8" y="166.4" textLength="109.8 [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="190.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-7)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="190.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-7)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="190.8" textLength="85.4" clip-path="url(#breeze-prod-image-build-line-7)">-docker</text><text class="breeze-prod-image-build-r4" x="122" y="190.8" textLength="73.2" [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="215.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-8)">│</text><text class="breeze-prod-image-build-r5" x="402.6" y="215.2" textLength="549" clip-path="url(#breeze-prod-image-build-line-8)">[default: registry]                          </text><text class="breeze-prod-image-build-r5 [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="239.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-9)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="239.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-9)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="239.6" textLength="85.4" clip-path="url(#breeze-prod-image-build-line-9)">-docker</text><text class="breeze-prod-image-build-r4" x="122" y="239.6" textLength="61" cl [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="264" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-10)">│</text><text class="breeze-prod-image-build-r1" x="402.6" y="264" textLength="1037" clip-path="url(#breeze-prod-image-build-line-10)">option is ignored when building images.                           & [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="288.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-11)">│</text><text class="breeze-prod-image-build-r6" x="402.6" y="288.4" textLength="1037" clip-path="url(#breeze-prod-image-build-line-11)">(TEXT)                                    & [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="312.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-12)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="312.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-12)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="312.8" textLength="73.2" clip-path="url(#breeze-prod-image-build-line-12)">-image</text><text class="breeze-prod-image-build-r4" x="109.8" y="312.8" textLength="48 [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="337.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-13)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="337.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-13)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="337.2" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-13)">-install</text><text class="breeze-prod-image-build-r4" x="134.2" y="337.2" textLength=" [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="361.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-14)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="361.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-14)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="361.6" textLength="85.4" clip-path="url(#breeze-prod-image-build-line-14)">-python</text><text class="breeze-prod-image-build-r7" x="353.8" y="361.6" textLength="2 [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="386" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-15)">│</text><text class="breeze-prod-image-build-r6" x="402.6" y="386" textLength="732" clip-path="url(#breeze-prod-image-build-line-15)">(>3.8< | 3.9 | 3.10 | 3.11)                            [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="410.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-16)">│</text><text class="breeze-prod-image-build-r5" x="402.6" y="410.4" textLength="732" clip-path="url(#breeze-prod-image-build-line-16)">[default: 3.8]                                  & [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="434.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-17)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="434.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-17)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="434.8" textLength="48.8" clip-path="url(#breeze-prod-image-build-line-17)">-tag</text><text class="breeze-prod-image-build-r4" x="85.4" y="434.8" textLength="122" [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="459.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-18)">│</text><text class="breeze-prod-image-build-r1" x="402.6" y="459.2" textLength="353.8" clip-path="url(#breeze-prod-image-build-line-18)">you build or pull image with </text><text class="breeze-prod-image-build-r4" x="756.4" y="459.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-18)">-</text><text class="breeze [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="483.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-19)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="483.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-19)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="483.6" textLength="48.8" clip-path="url(#breeze-prod-image-build-line-19)">-use</text><text class="breeze-prod-image-build-r4" x="85.4" y="483.6" textLength="36.6" [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="508" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-20)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="508" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-20)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="508" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-20)">-version</text><text class="breeze-prod-image-build-r4" x="134.2" y="508" textLength="195.2" c [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="532.4" textLength="1464" clip-path="url(#breeze-prod-image-build-line-21)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text class="breeze-prod-image-build-r1" x="1464" y="532.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-21)">
+</text><text class="breeze-prod-image-build-r5" x="0" y="556.8" textLength="24.4" clip-path="url(#breeze-prod-image-build-line-22)">╭─</text><text class="breeze-prod-image-build-r5" x="24.4" y="556.8" textLength="353.8" clip-path="url(#breeze-prod-image-build-line-22)"> Building images in parallel </text><text class="breeze-prod-image-build-r5" x="378.2" y="556.8" textLength="1061.4" clip-path="url(#breeze-prod-image-build-line-22)">────────────────────────────── [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="581.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-23)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="581.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-23)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="581.2" textLength="48.8" clip-path="url(#breeze-prod-image-build-line-23)">-run</text><text class="breeze-prod-image-build-r4" x="85.4" y="581.2" textLength="146.4 [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="605.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-24)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="605.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-24)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="605.6" textLength="146.4" clip-path="url(#breeze-prod-image-build-line-24)">-parallelism</text><text class="breeze-prod-image-build-r1" x="378.2" y="605.6" textLen [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="630" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-25)">│</text><text class="breeze-prod-image-build-r6" x="378.2" y="630" textLength="915" clip-path="url(#breeze-prod-image-build-line-25)">(INTEGER RANGE)                                   [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="654.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-26)">│</text><text class="breeze-prod-image-build-r5" x="378.2" y="654.4" textLength="915" clip-path="url(#breeze-prod-image-build-line-26)">[default: 4; 1<=x<=8]                               & [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="678.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-27)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="678.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-27)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="678.8" textLength="85.4" clip-path="url(#breeze-prod-image-build-line-27)">-python</text><text class="breeze-prod-image-build-r4" x="122" y="678.8" textLength="109 [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="703.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-28)">│</text><text class="breeze-prod-image-build-r5" x="378.2" y="703.2" textLength="951.6" clip-path="url(#breeze-prod-image-build-line-28)">[default: 3.8 3.9 3.10 3.11]                              [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="727.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-29)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="727.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-29)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="727.6" textLength="61" clip-path="url(#breeze-prod-image-build-line-29)">-skip</text><text class="breeze-prod-image-build-r4" x="97.6" y="727.6" textLength="97.6" [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="752" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-30)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="752" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-30)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="752" textLength="73.2" clip-path="url(#breeze-prod-image-build-line-30)">-debug</text><text class="breeze-prod-image-build-r4" x="109.8" y="752" textLength="122" clip- [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="776.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-31)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="776.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-31)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="776.4" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-31)">-include</text><text class="breeze-prod-image-build-r4" x="134.2" y="776.4" textLength=" [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="800.8" textLength="1464" clip-path="url(#breeze-prod-image-build-line-32)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text class="breeze-prod-image-build-r1" x="1464" y="800.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-32)">
+</text><text class="breeze-prod-image-build-r5" x="0" y="825.2" textLength="24.4" clip-path="url(#breeze-prod-image-build-line-33)">╭─</text><text class="breeze-prod-image-build-r5" x="24.4" y="825.2" textLength="512.4" clip-path="url(#breeze-prod-image-build-line-33)"> Advanced build options (for power users) </text><text class="breeze-prod-image-build-r5" x="536.8" y="825.2" textLength="902.8" clip-path="url(#breeze-prod-image-build-line-33)">──────── [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="849.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-34)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="849.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-34)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="849.6" textLength="134.2" clip-path="url(#breeze-prod-image-build-line-34)">-additional</text><text class="breeze-prod-image-build-r4" x="170.8" y="849.6" textLeng [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="874" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-35)">│</text><text class="breeze-prod-image-build-r1" x="439.2" y="874" textLength="1000.4" clip-path="url(#breeze-prod-image-build-line-35)">itself).                                    & [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="898.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-36)">│</text><text class="breeze-prod-image-build-r6" x="439.2" y="898.4" textLength="1000.4" clip-path="url(#breeze-prod-image-build-line-36)">(TEXT)                                     [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="922.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-37)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="922.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-37)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="922.8" textLength="85.4" clip-path="url(#breeze-prod-image-build-line-37)">-commit</text><text class="breeze-prod-image-build-r4" x="122" y="922.8" textLength="48. [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="947.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-38)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="947.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-38)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="947.2" textLength="85.4" clip-path="url(#breeze-prod-image-build-line-38)">-debian</text><text class="breeze-prod-image-build-r4" x="122" y="947.2" textLength="97. [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="971.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-39)">│</text><text class="breeze-prod-image-build-r6" x="439.2" y="971.6" textLength="793" clip-path="url(#breeze-prod-image-build-line-39)">(bookworm | bullseye)                                & [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="996" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-40)">│</text><text class="breeze-prod-image-build-r5" x="439.2" y="996" textLength="793" clip-path="url(#breeze-prod-image-build-line-40)">[default: bookworm]                                   [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1020.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-41)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1020.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-41)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1020.4" textLength="85.4" clip-path="url(#breeze-prod-image-build-line-41)">-python</text><text class="breeze-prod-image-build-r4" x="122" y="1020.4" textLength= [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1044.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-42)">│</text><text class="breeze-prod-image-build-r1" x="439.2" y="1044.8" textLength="1000.4" clip-path="url(#breeze-prod-image-build-line-42)">something like: python:VERSION-slim-bookworm.                           &# [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1069.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-43)">│</text><text class="breeze-prod-image-build-r6" x="439.2" y="1069.2" textLength="1000.4" clip-path="url(#breeze-prod-image-build-line-43)">(TEXT)                                    [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1093.6" textLength="1464" clip-path="url(#breeze-prod-image-build-line-44)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text class="breeze-prod-image-build-r1" x="1464" y="1093.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-44)">
+</text><text class="breeze-prod-image-build-r5" x="0" y="1118" textLength="24.4" clip-path="url(#breeze-prod-image-build-line-45)">╭─</text><text class="breeze-prod-image-build-r5" x="24.4" y="1118" textLength="597.8" clip-path="url(#breeze-prod-image-build-line-45)"> Selecting constraint location (for power users) </text><text class="breeze-prod-image-build-r5" x="622.2" y="1118" textLength="817.4" clip-path="url(#breeze-prod-image-build-line-45)">──── [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1142.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-46)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1142.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-46)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1142.4" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-46)">-airflow</text><text class="breeze-prod-image-build-r4" x="134.2" y="1142.4" textLeng [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1166.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-47)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1166.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-47)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1166.8" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-47)">-airflow</text><text class="breeze-prod-image-build-r4" x="134.2" y="1166.8" textLeng [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1191.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-48)">│</text><text class="breeze-prod-image-build-r6" x="451.4" y="1191.2" textLength="866.2" clip-path="url(#breeze-prod-image-build-line-48)">(constraints | constraints-no-providers | constraints-source-providers)</text><text class="breeze-prod-image-build-r5" x="1451.8" y="1191.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-l [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1215.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-49)">│</text><text class="breeze-prod-image-build-r5" x="451.4" y="1215.6" textLength="866.2" clip-path="url(#breeze-prod-image-build-line-49)">[default: constraints]                                & [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1240" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-50)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1240" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-50)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1240" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-50)">-airflow</text><text class="breeze-prod-image-build-r4" x="134.2" y="1240" textLength="268. [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1264.4" textLength="1464" clip-path="url(#breeze-prod-image-build-line-51)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text class="breeze-prod-image-build-r1" x="1464" y="1264.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-51)">
+</text><text class="breeze-prod-image-build-r5" x="0" y="1288.8" textLength="24.4" clip-path="url(#breeze-prod-image-build-line-52)">╭─</text><text class="breeze-prod-image-build-r5" x="24.4" y="1288.8" textLength="634.4" clip-path="url(#breeze-prod-image-build-line-52)"> Choosing dependencies and extras (for power users) </text><text class="breeze-prod-image-build-r5" x="658.8" y="1288.8" textLength="780.8" clip-path="url(#breeze-prod-image-build- [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1313.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-53)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1313.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-53)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1313.2" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-53)">-airflow</text><text class="breeze-prod-image-build-r4" x="134.2" y="1313.2" textLeng [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1337.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-54)">│</text><text class="breeze-prod-image-build-r6" x="463.6" y="1337.6" textLength="976" clip-path="url(#breeze-prod-image-build-line-54)">(TEXT)                                     [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1362" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-55)">│</text><text class="breeze-prod-image-build-r5" x="463.6" y="1362" textLength="976" clip-path="url(#breeze-prod-image-build-line-55)">[default:                                    & [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1386.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-56)">│</text><text class="breeze-prod-image-build-r5" x="463.6" y="1386.4" textLength="976" clip-path="url(#breeze-prod-image-build-line-56)">aiobotocore,amazon,async,celery,cncf-kubernetes,common-io,docker,elasticsearch,…</text><text class="breeze-prod-image-build-r5" x="1451.8" y="1386.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-56)">│</t [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1410.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-57)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1410.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-57)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1410.8" textLength="134.2" clip-path="url(#breeze-prod-image-build-line-57)">-additional</text><text class="breeze-prod-image-build-r4" x="170.8" y="1410.8" text [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1435.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-58)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1435.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-58)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1435.2" textLength="134.2" clip-path="url(#breeze-prod-image-build-line-58)">-additional</text><text class="breeze-prod-image-build-r4" x="170.8" y="1435.2" text [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1459.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-59)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1459.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-59)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1459.6" textLength="48.8" clip-path="url(#breeze-prod-image-build-line-59)">-dev</text><text class="breeze-prod-image-build-r4" x="85.4" y="1459.6" textLength="1 [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1484" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-60)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1484" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-60)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1484" textLength="134.2" clip-path="url(#breeze-prod-image-build-line-60)">-additional</text><text class="breeze-prod-image-build-r4" x="170.8" y="1484" textLength=" [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1508.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-61)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1508.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-61)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1508.4" textLength="48.8" clip-path="url(#breeze-prod-image-build-line-61)">-dev</text><text class="breeze-prod-image-build-r4" x="85.4" y="1508.4" textLength="1 [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1532.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-62)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1532.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-62)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1532.8" textLength="134.2" clip-path="url(#breeze-prod-image-build-line-62)">-additional</text><text class="breeze-prod-image-build-r4" x="170.8" y="1532.8" text [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1557.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-63)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1557.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-63)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1557.2" textLength="134.2" clip-path="url(#breeze-prod-image-build-line-63)">-additional</text><text class="breeze-prod-image-build-r4" x="170.8" y="1557.2" text [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1581.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-64)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1581.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-64)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1581.6" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-64)">-runtime</text><text class="breeze-prod-image-build-r4" x="134.2" y="1581.6" textLeng [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1606" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-65)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1606" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-65)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1606" textLength="134.2" clip-path="url(#breeze-prod-image-build-line-65)">-additional</text><text class="breeze-prod-image-build-r4" x="170.8" y="1606" textLength=" [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1630.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-66)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1630.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-66)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1630.4" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-66)">-runtime</text><text class="breeze-prod-image-build-r4" x="134.2" y="1630.4" textLeng [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1654.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-67)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1654.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-67)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1654.8" textLength="134.2" clip-path="url(#breeze-prod-image-build-line-67)">-additional</text><text class="breeze-prod-image-build-r4" x="170.8" y="1654.8" text [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1679.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-68)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1679.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-68)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1679.2" textLength="134.2" clip-path="url(#breeze-prod-image-build-line-68)">-additional</text><text class="breeze-prod-image-build-r4" x="170.8" y="1679.2" text [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1703.6" textLength="1464" clip-path="url(#breeze-prod-image-build-line-69)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text class="breeze-prod-image-build-r1" x="1464" y="1703.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-69)">
+</text><text class="breeze-prod-image-build-r5" x="0" y="1728" textLength="24.4" clip-path="url(#breeze-prod-image-build-line-70)">╭─</text><text class="breeze-prod-image-build-r5" x="24.4" y="1728" textLength="817.4" clip-path="url(#breeze-prod-image-build-line-70)"> Advanced customization options (for specific customization needs) </text><text class="breeze-prod-image-build-r5" x="841.8" y="1728" textLength="597.8" clip-path="url(#breeze-prod-ima [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1752.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-71)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1752.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-71)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1752.4" textLength="158.6" clip-path="url(#breeze-prod-image-build-line-71)">-installation</text><text class="breeze-prod-image-build-r4" x="195.2" y="1752.4" te [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1776.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-72)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1776.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-72)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1776.8" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-72)">-install</text><text class="breeze-prod-image-build-r4" x="134.2" y="1776.8" textLeng [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1801.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-73)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1801.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-73)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1801.2" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-73)">-install</text><text class="breeze-prod-image-build-r4" x="134.2" y="1801.2" textLeng [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1825.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-74)">│</text><text class="breeze-prod-image-build-r1" x="536.8" y="1825.6" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-74)">Implies </text><text class="breeze-prod-image-build-r4" x="634.4" y="1825.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-74)">-</text><text class="breeze-prod-image-build-r4" x="646.6" y="1825.6" t [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1850" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-75)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1850" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-75)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1850" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-75)">-install</text><text class="breeze-prod-image-build-r4" x="134.2" y="1850" textLength="219. [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1874.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-76)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1874.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-76)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1874.4" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-76)">-cleanup</text><text class="breeze-prod-image-build-r4" x="134.2" y="1874.4" textLeng [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1898.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-77)">│</text><text class="breeze-prod-image-build-r1" x="536.8" y="1898.8" textLength="170.8" clip-path="url(#breeze-prod-image-build-line-77)">together with </text><text class="breeze-prod-image-build-r4" x="707.6" y="1898.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-77)">-</text><text class="breeze-prod-image-build-r4" x="719.8" [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1923.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-78)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1923.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-78)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1923.2" textLength="48.8" clip-path="url(#breeze-prod-image-build-line-78)">-use</text><text class="breeze-prod-image-build-r4" x="85.4" y="1923.2" textLength="4 [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1947.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-79)">│</text><text class="breeze-prod-image-build-r1" x="536.8" y="1947.6" textLength="902.8" clip-path="url(#breeze-prod-image-build-line-79)">constraints store in docker-context-files or from github.                 </text><text class="breeze-prod [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1972" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-80)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1972" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-80)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1972" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-80)">-disable</text><text class="breeze-prod-image-build-r4" x="134.2" y="1972" textLength="231. [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="1996.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-81)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="1996.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-81)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="1996.4" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-81)">-disable</text><text class="breeze-prod-image-build-r4" x="134.2" y="1996.4" textLeng [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="2020.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-82)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2020.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-82)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2020.8" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-82)">-disable</text><text class="breeze-prod-image-build-r4" x="134.2" y="2020.8" textLeng [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="2045.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-83)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2045.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-83)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2045.2" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-83)">-disable</text><text class="breeze-prod-image-build-r4" x="134.2" y="2045.2" textLeng [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="2069.6" textLength="1464" clip-path="url(#breeze-prod-image-build-line-84)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text class="breeze-prod-image-build-r1" x="1464" y="2069.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-84)">
+</text><text class="breeze-prod-image-build-r5" x="0" y="2094" textLength="24.4" clip-path="url(#breeze-prod-image-build-line-85)">╭─</text><text class="breeze-prod-image-build-r5" x="24.4" y="2094" textLength="622.2" clip-path="url(#breeze-prod-image-build-line-85)"> Preparing cache and push (for maintainers and CI) </text><text class="breeze-prod-image-build-r5" x="646.6" y="2094" textLength="793" clip-path="url(#breeze-prod-image-build-line [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="2118.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-86)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2118.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-86)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2118.4" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-86)">-builder</text><text class="breeze-prod-image-build-r1" x="341.6" y="2118.4" textLeng [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="2142.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-87)">│</text><text class="breeze-prod-image-build-r5" x="341.6" y="2142.8" textLength="756.4" clip-path="url(#breeze-prod-image-build-line-87)">[default: autodetect]                                &# [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="2167.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-88)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2167.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-88)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2167.2" textLength="109.8" clip-path="url(#breeze-prod-image-build-line-88)">-platform</text><text class="breeze-prod-image-build-r1" x="341.6" y="2167.2" textLe [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="2191.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-89)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2191.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-89)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2191.6" textLength="61" clip-path="url(#breeze-prod-image-build-line-89)">-push</text><text class="breeze-prod-image-build-r1" x="341.6" y="2191.6" textLength="3 [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="2216" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-90)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2216" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-90)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2216" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-90)">-prepare</text><text class="breeze-prod-image-build-r4" x="134.2" y="2216" textLength="158. [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="2240.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-91)">│</text><text class="breeze-prod-image-build-r1" x="341.6" y="2240.4" textLength="1098" clip-path="url(#breeze-prod-image-build-line-91)">image).                                    [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="2264.8" textLength="1464" clip-path="url(#breeze-prod-image-build-line-92)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text class="breeze-prod-image-build-r1" x="1464" y="2264.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-92)">
+</text><text class="breeze-prod-image-build-r5" x="0" y="2289.2" textLength="24.4" clip-path="url(#breeze-prod-image-build-line-93)">╭─</text><text class="breeze-prod-image-build-r5" x="24.4" y="2289.2" textLength="280.6" clip-path="url(#breeze-prod-image-build-line-93)"> Github authentication </text><text class="breeze-prod-image-build-r5" x="305" y="2289.2" textLength="1134.6" clip-path="url(#breeze-prod-image-build-line-93)">───────────────────────────────────────────── [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="2313.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-94)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2313.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-94)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2313.6" textLength="85.4" clip-path="url(#breeze-prod-image-build-line-94)">-github</text><text class="breeze-prod-image-build-r4" x="122" y="2313.6" textLength= [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="2338" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-95)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2338" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-95)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2338" textLength="85.4" clip-path="url(#breeze-prod-image-build-line-95)">-github</text><text class="breeze-prod-image-build-r4" x="122" y="2338" textLength="73.2" c [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="2362.4" textLength="1464" clip-path="url(#breeze-prod-image-build-line-96)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text class="breeze-prod-image-build-r1" x="1464" y="2362.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-96)">
+</text><text class="breeze-prod-image-build-r5" x="0" y="2386.8" textLength="24.4" clip-path="url(#breeze-prod-image-build-line-97)">╭─</text><text class="breeze-prod-image-build-r5" x="24.4" y="2386.8" textLength="195.2" clip-path="url(#breeze-prod-image-build-line-97)"> Common options </text><text class="breeze-prod-image-build-r5" x="219.6" y="2386.8" textLength="1220" clip-path="url(#breeze-prod-image-build-line-97)">──────────────────────────────────────────────────── [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="2411.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-98)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2411.2" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-98)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2411.2" textLength="85.4" clip-path="url(#breeze-prod-image-build-line-98)">-answer</text><text class="breeze-prod-image-build-r7" x="158.6" y="2411.2" textLengt [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="2435.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-99)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2435.6" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-99)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2435.6" textLength="48.8" clip-path="url(#breeze-prod-image-build-line-99)">-dry</text><text class="breeze-prod-image-build-r4" x="85.4" y="2435.6" textLength="4 [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="2460" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-100)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2460" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-100)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2460" textLength="97.6" clip-path="url(#breeze-prod-image-build-line-100)">-verbose</text><text class="breeze-prod-image-build-r7" x="158.6" y="2460" textLength="2 [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="2484.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-101)">│</text><text class="breeze-prod-image-build-r4" x="24.4" y="2484.4" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-101)">-</text><text class="breeze-prod-image-build-r4" x="36.6" y="2484.4" textLength="61" clip-path="url(#breeze-prod-image-build-line-101)">-help</text><text class="breeze-prod-image-build-r7" x="158.6" y="2484.4" textLength [...]
+</text><text class="breeze-prod-image-build-r5" x="0" y="2508.8" textLength="1464" clip-path="url(#breeze-prod-image-build-line-102)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text class="breeze-prod-image-build-r1" x="1464" y="2508.8" textLength="12.2" clip-path="url(#breeze-prod-image-build-line-102)">
</text>
</g>
</g>
diff --git a/dev/breeze/doc/images/output_prod-image_build.txt b/dev/breeze/doc/images/output_prod-image_build.txt
index 86876deb7f..053a0ab2c1 100644
--- a/dev/breeze/doc/images/output_prod-image_build.txt
+++ b/dev/breeze/doc/images/output_prod-image_build.txt
@@ -1 +1 @@
-07693b2597b00fdb156949c753dae783
+a0215fc3b5c463f6dc50af34d4e18759
diff --git a/dev/breeze/src/airflow_breeze/commands/common_options.py b/dev/breeze/src/airflow_breeze/commands/common_options.py
index af30a9d299..ed82061059 100644
--- a/dev/breeze/src/airflow_breeze/commands/common_options.py
+++ b/dev/breeze/src/airflow_breeze/commands/common_options.py
@@ -341,6 +341,15 @@ option_use_uv = click.option(
"--use-uv/--no-use-uv",
is_flag=True,
default=True,
+ show_default=True,
+ help="Use uv instead of pip as packaging tool.",
+ envvar="USE_UV",
+)
+option_use_uv_default_disabled = click.option(
+ "--use-uv/--no-use-uv",
+ is_flag=True,
+ default=False,
+ show_default=True,
help="Use uv instead of pip as packaging tool.",
envvar="USE_UV",
)
diff --git a/dev/breeze/src/airflow_breeze/commands/production_image_commands.py b/dev/breeze/src/airflow_breeze/commands/production_image_commands.py
index a98462c163..8178b09d26 100644
--- a/dev/breeze/src/airflow_breeze/commands/production_image_commands.py
+++ b/dev/breeze/src/airflow_breeze/commands/production_image_commands.py
@@ -68,6 +68,7 @@ from airflow_breeze.commands.common_options import (
option_python_versions,
option_run_in_parallel,
option_skip_cleanup,
+ option_use_uv,
option_verbose,
option_version_suffix_for_pypi,
)
@@ -244,6 +245,7 @@ def prod_image():
@option_runtime_apt_deps
@option_skip_cleanup
@option_tag_as_latest
+@option_use_uv
@option_verbose
@option_version_suffix_for_pypi
def build(
@@ -296,6 +298,7 @@ def build(
skip_cleanup: bool,
tag_as_latest: bool,
use_constraints_for_context_packages: bool,
+ use_uv: bool,
version_suffix_for_pypi: str,
):
"""
@@ -354,6 +357,7 @@ def build(
runtime_apt_deps=runtime_apt_deps,
tag_as_latest=tag_as_latest,
use_constraints_for_context_packages=use_constraints_for_context_packages,
+ use_uv=use_uv,
version_suffix_for_pypi=version_suffix_for_pypi,
)
if platform:
diff --git a/dev/breeze/src/airflow_breeze/commands/production_image_commands_config.py b/dev/breeze/src/airflow_breeze/commands/production_image_commands_config.py
index df780dbbd8..3be1c16026 100644
--- a/dev/breeze/src/airflow_breeze/commands/production_image_commands_config.py
+++ b/dev/breeze/src/airflow_breeze/commands/production_image_commands_config.py
@@ -29,14 +29,15 @@ PRODUCTION_IMAGE_TOOLS_PARAMETERS: dict[str, list[dict[str, str | list[str]]]] =
{
"name": "Basic usage",
"options": [
- "--python",
- "--install-airflow-version",
+ "--build-progress",
+ "--docker-cache",
+ "--docker-host",
"--image-tag",
+ "--install-airflow-version",
+ "--python",
"--tag-as-latest",
- "--docker-cache",
+ "--use-uv",
"--version-suffix-for-pypi",
- "--build-progress",
- "--docker-host",
],
},
{
diff --git a/dev/breeze/src/airflow_breeze/params/build_prod_params.py b/dev/breeze/src/airflow_breeze/params/build_prod_params.py
index 342ac0c143..b5cb80d216 100644
--- a/dev/breeze/src/airflow_breeze/params/build_prod_params.py
+++ b/dev/breeze/src/airflow_breeze/params/build_prod_params.py
@@ -55,6 +55,7 @@ class BuildProdParams(CommonBuildParams):
runtime_apt_command: str | None = None
runtime_apt_deps: str | None = None
use_constraints_for_context_packages: bool = False
+ use_uv: bool = True
@property
def airflow_version(self) -> str:
@@ -206,6 +207,7 @@ class BuildProdParams(CommonBuildParams):
self._req_arg("AIRFLOW_IMAGE_README_URL", self.airflow_image_readme_url)
self._req_arg("AIRFLOW_IMAGE_REPOSITORY", self.airflow_image_repository)
self._req_arg("AIRFLOW_PRE_CACHED_PIP_PACKAGES", self.airflow_pre_cached_pip_packages)
+ self._opt_arg("AIRFLOW_USE_UV", self.use_uv)
self._req_arg("AIRFLOW_VERSION", self.airflow_version)
self._req_arg("BUILD_ID", self.build_id)
self._req_arg("CONSTRAINTS_GITHUB_REPOSITORY", self.constraints_github_repository)
diff --git a/docs/docker-stack/build-arg-ref.rst b/docs/docker-stack/build-arg-ref.rst
index 9a63e67213..768a73c8ee 100644
--- a/docs/docker-stack/build-arg-ref.rst
+++ b/docs/docker-stack/build-arg-ref.rst
@@ -49,7 +49,7 @@ Those are the most common arguments that you use when you want to build a custom
+------------------------------------------+------------------------------------------+---------------------------------------------+
| ``AIRFLOW_UV_VERSION`` | ``<LATEST_AVAILABLE_IN_PYPI>`` | UV version used. |
+------------------------------------------+------------------------------------------+---------------------------------------------+
-| ``AIRFLOW_USE_UV`` | ``false`` | Whether to use UV. |
+| ``AIRFLOW_USE_UV`` | ``false`` | Whether to use UV to build the image. |
+------------------------------------------+------------------------------------------+---------------------------------------------+
| ``ADDITIONAL_PIP_INSTALL_FLAGS`` | | additional ``pip`` flags passed to the |
| | | installation commands (except when |
diff --git a/docs/docker-stack/build.rst b/docs/docker-stack/build.rst
index b94aaff59f..7831ec5504 100644
--- a/docs/docker-stack/build.rst
+++ b/docs/docker-stack/build.rst
@@ -342,14 +342,18 @@ You should be aware, about a few things:
`best practices of Dockerfiles <https://docs.docker.com/develop/develop-images/dockerfile_best-practices/>`_
to make sure your image is lean and small.
-* The PyPI dependencies in Apache Airflow are installed in the user library, of the "airflow" user, so
- PIP packages are installed to ``~/.local`` folder as if the ``--user`` flag was specified when running PIP.
+* The PyPI dependencies in Apache Airflow are installed in the ``~/.local`` virtualenv, of the "airflow" user,
+ so PIP packages are installed to ``~/.local`` folder as if the ``--user`` flag was specified when running
+ PIP. This has the effect that when you create a virtualenv with ``--system-site-packages`` flag, the
+ virtualenv created will automatically have all the same packages installed as local airflow installation.
Note also that using ``--no-cache-dir`` is a good idea that can help to make your image smaller.
.. note::
Only as of ``2.0.1`` image the ``--user`` flag is turned on by default by setting ``PIP_USER`` environment
variable to ``true``. This can be disabled by un-setting the variable or by setting it to ``false``. In the
- 2.0.0 image you had to add the ``--user`` flag as ``pip install --user`` command.
+ 2.0.0 image you had to add the ``--user`` flag as ``pip install --user`` command. In the 2.9.0 image
+ the ``PIP_USER`` flag is removed, because the ``.local`` directory is treated as virtualenv and by default
+ all packages are installed there.
* If your apt, or PyPI dependencies require some of the ``build-essential`` or other packages that need
to compile your python dependencies, then your best choice is to follow the "Customize the image" route,
diff --git a/docs/docker-stack/changelog.rst b/docs/docker-stack/changelog.rst
index 90930afdda..b1a78fe3bb 100644
--- a/docs/docker-stack/changelog.rst
+++ b/docs/docker-stack/changelog.rst
@@ -45,12 +45,21 @@ Airflow 2.9
``apache/airflow:slim-2.9.0-python-3.8`` images respectively so while the change is potentially
breaking, it is very easy to switch to the previous behaviour.
-Airflow 2.9
-~~~~~~~~~~~
-
-The ``gosu`` binary was removed from the image. This is a potentially breaking change for users who relied on
-``gosu`` to change the user in the container. The ``gosu`` binary was removed because it was a source of
-security vulnerabilities as it was linked against older go standard libraries.
+ * The ``PIP_USER`` flag is removed and replaced by ``VIRTUAL_ENV`` pointing to ``~/.local`` where Airflow
+ is installed. This has the effect that Airflow installation is treated as regular virtual environment,
+ but unlike a regular virtualenv, the ``~/.local`` directory is seen as ``system level`` and when
+ worker creates dynamically virtualenv with ``--system-site-packages`` flag, Airflow installation and all
+ packages there are also present in the new virtualenv - but when you do not use the flag, they are not
+ copied there which is backwards-compatible behaviour with having ``PIP_USER`` set.
+
+ * The image contains latest ``uv`` binary (latest at the moment of release) - which is a new faster
+ replacement for ``pip``. While the image is still using ``pip`` by default, you can use ``uv`` by default
+ to install packages and - experimentally - you can also build custom images with
+ ``--arg AIRFLOW_USE_UV=true`` which will us ``uv`` to perform the installation.
+
+ * The ``gosu`` binary was removed from the image. This is a potentially breaking change for users who relied on
+ ``gosu`` to change the user in the container. The ``gosu`` binary was removed because it was a source of
+ security vulnerabilities as it was linked against older go standard libraries.
Airflow 2.8
diff --git a/scripts/docker/common.sh b/scripts/docker/common.sh
index 29da11bac7..5c5bf2b706 100644
--- a/scripts/docker/common.sh
+++ b/scripts/docker/common.sh
@@ -46,7 +46,11 @@ function common::get_packaging_tool() {
echo
export PACKAGING_TOOL="uv"
export PACKAGING_TOOL_CMD="uv pip"
- export EXTRA_INSTALL_FLAGS="--python ${PYTHON_BIN}"
+ if [[ -z ${VIRTUAL_ENV=} ]]; then
+ export EXTRA_INSTALL_FLAGS="--python ${PYTHON_BIN}"
+ else
+ export EXTRA_INSTALL_FLAGS=""
+ fi
export EXTRA_UNINSTALL_FLAGS="--python ${PYTHON_BIN}"
export RESOLUTION_HIGHEST_FLAG="--resolution highest"
export RESOLUTION_LOWEST_DIRECT_FLAG="--resolution lowest-direct"
@@ -71,14 +75,6 @@ function common::get_airflow_version_specification() {
fi
}
-function common::override_pip_version_if_needed() {
- if [[ -n ${AIRFLOW_VERSION} ]]; then
- if [[ ${AIRFLOW_VERSION} =~ ^2\.0.* || ${AIRFLOW_VERSION} =~ ^1\.* ]]; then
- export AIRFLOW_PIP_VERSION=24.0
- fi
- fi
-}
-
function common::get_constraints_location() {
# auto-detect Airflow-constraint reference and location
if [[ -z "${AIRFLOW_CONSTRAINTS_REFERENCE=}" ]]; then
@@ -105,12 +101,12 @@ function common::show_packaging_tool_version_and_location() {
echo "Using pip: $(pip --version)"
else
echo "${COLOR_BLUE}Using 'uv' to install Airflow${COLOR_RESET}"
- echo "uv on path: $(which uv)"
+ echo "uv on path: $(which uv 2>/dev/null || echo "Not installed")"
echo "Using uv: $(uv --version)"
fi
}
-function common::install_packaging_tool() {
+function common::install_packaging_tools() {
echo
echo "${COLOR_BLUE}Installing pip version ${AIRFLOW_PIP_VERSION}${COLOR_RESET}"
echo
@@ -121,17 +117,15 @@ function common::install_packaging_tool() {
# shellcheck disable=SC2086
pip install --root-user-action ignore --disable-pip-version-check "pip==${AIRFLOW_PIP_VERSION}"
fi
- if [[ ${AIRFLOW_USE_UV} == "true" ]]; then
- echo
- echo "${COLOR_BLUE}Installing uv version ${AIRFLOW_UV_VERSION}${COLOR_RESET}"
- echo
- if [[ ${AIRFLOW_UV_VERSION} =~ .*https.* ]]; then
- # shellcheck disable=SC2086
- pip install --root-user-action ignore --disable-pip-version-check "uv @ ${AIRFLOW_UV_VERSION}"
- else
- # shellcheck disable=SC2086
- pip install --root-user-action ignore --disable-pip-version-check "uv==${AIRFLOW_UV_VERSION}"
- fi
+ echo
+ echo "${COLOR_BLUE}Installing uv version ${AIRFLOW_UV_VERSION}${COLOR_RESET}"
+ echo
+ if [[ ${AIRFLOW_UV_VERSION} =~ .*https.* ]]; then
+ # shellcheck disable=SC2086
+ pip install --root-user-action ignore --disable-pip-version-check "uv @ ${AIRFLOW_UV_VERSION}"
+ else
+ # shellcheck disable=SC2086
+ pip install --root-user-action ignore --disable-pip-version-check "uv==${AIRFLOW_UV_VERSION}"
fi
mkdir -p "${HOME}/.local/bin"
}
diff --git a/scripts/docker/install_pip_version.sh b/scripts/docker/create_prod_venv.sh
similarity index 88%
copy from scripts/docker/install_pip_version.sh
copy to scripts/docker/create_prod_venv.sh
index af8d25e06e..0a8115d626 100644
--- a/scripts/docker/install_pip_version.sh
+++ b/scripts/docker/create_prod_venv.sh
@@ -19,10 +19,13 @@
# shellcheck source=scripts/docker/common.sh
. "$( dirname "${BASH_SOURCE[0]}" )/common.sh"
+function create_prod_venv() {
+ rm -rf ~/.local
+ python -m venv ~/.local
+}
+
common::get_colors
common::get_packaging_tool
-common::get_airflow_version_specification
-common::override_pip_version_if_needed
common::show_packaging_tool_version_and_location
-
-common::install_packaging_tool
+create_prod_venv
+common::install_packaging_tools
diff --git a/scripts/docker/install_additional_dependencies.sh b/scripts/docker/install_additional_dependencies.sh
index 79e83eeb9e..952de84ed3 100644
--- a/scripts/docker/install_additional_dependencies.sh
+++ b/scripts/docker/install_additional_dependencies.sh
@@ -34,7 +34,7 @@ function install_additional_dependencies() {
${PACKAGING_TOOL_CMD} install ${EXTRA_INSTALL_FLAGS} --upgrade ${RESOLUTION_HIGHEST_FLAG} \
${ADDITIONAL_PIP_INSTALL_FLAGS} \
${ADDITIONAL_PYTHON_DEPS} ${EAGER_UPGRADE_ADDITIONAL_REQUIREMENTS=}
- common::install_packaging_tool
+ common::install_packaging_tools
set +x
echo
echo "${COLOR_BLUE}Running 'pip check'${COLOR_RESET}"
@@ -48,7 +48,7 @@ function install_additional_dependencies() {
${PACKAGING_TOOL_CMD} install ${EXTRA_INSTALL_FLAGS} --upgrade "${RESOLUTION_LOWEST_DIRECT_FLAG}" \
${ADDITIONAL_PIP_INSTALL_FLAGS} \
${ADDITIONAL_PYTHON_DEPS}
- common::install_packaging_tool
+ common::install_packaging_tools
set +x
echo
echo "${COLOR_BLUE}Running 'pip check'${COLOR_RESET}"
@@ -60,7 +60,6 @@ function install_additional_dependencies() {
common::get_colors
common::get_packaging_tool
common::get_airflow_version_specification
-common::override_pip_version_if_needed
common::get_constraints_location
common::show_packaging_tool_version_and_location
diff --git a/scripts/docker/install_airflow.sh b/scripts/docker/install_airflow.sh
index e8fb806ac6..79b8b51bc1 100644
--- a/scripts/docker/install_airflow.sh
+++ b/scripts/docker/install_airflow.sh
@@ -65,7 +65,7 @@ function install_airflow() {
"${AIRFLOW_INSTALLATION_METHOD}[${AIRFLOW_EXTRAS}]${AIRFLOW_VERSION_SPECIFICATION}" \
${EAGER_UPGRADE_ADDITIONAL_REQUIREMENTS=}
set +x
- common::install_packaging_tool
+ common::install_packaging_tools
echo
echo "${COLOR_BLUE}Running '${PACKAGING_TOOL} check'${COLOR_RESET}"
echo
@@ -79,13 +79,13 @@ function install_airflow() {
${ADDITIONAL_PIP_INSTALL_FLAGS} \
"${AIRFLOW_INSTALLATION_METHOD}[${AIRFLOW_EXTRAS}]${AIRFLOW_VERSION_SPECIFICATION}" \
--constraint "${AIRFLOW_CONSTRAINTS_LOCATION}" || true
- common::install_packaging_tool
+ common::install_packaging_tools
# then upgrade if needed without using constraints to account for new limits in pyproject.toml
${PACKAGING_TOOL_CMD} install ${EXTRA_INSTALL_FLAGS} --upgrade ${RESOLUTION_LOWEST_DIRECT_FLAG} \
${ADDITIONAL_PIP_INSTALL_FLAGS} \
${AIRFLOW_INSTALL_EDITABLE_FLAG} \
"${AIRFLOW_INSTALLATION_METHOD}[${AIRFLOW_EXTRAS}]${AIRFLOW_VERSION_SPECIFICATION}"
- common::install_packaging_tool
+ common::install_packaging_tools
set +x
echo
echo "${COLOR_BLUE}Running 'pip check'${COLOR_RESET}"
@@ -98,7 +98,6 @@ function install_airflow() {
common::get_colors
common::get_packaging_tool
common::get_airflow_version_specification
-common::override_pip_version_if_needed
common::get_constraints_location
common::show_packaging_tool_version_and_location
diff --git a/scripts/docker/install_airflow_dependencies_from_branch_tip.sh b/scripts/docker/install_airflow_dependencies_from_branch_tip.sh
index 202a40c41e..1510b7b189 100644
--- a/scripts/docker/install_airflow_dependencies_from_branch_tip.sh
+++ b/scripts/docker/install_airflow_dependencies_from_branch_tip.sh
@@ -52,7 +52,7 @@ function install_airflow_dependencies_from_branch_tip() {
${PACKAGING_TOOL_CMD} install ${EXTRA_INSTALL_FLAGS} \
${ADDITIONAL_PIP_INSTALL_FLAGS} \
"apache-airflow[${AIRFLOW_EXTRAS}] @ https://github.com/${AIRFLOW_REPO}/archive/${AIRFLOW_BRANCH}.tar.gz"
- common::install_packaging_tool
+ common::install_packaging_tools
# Uninstall airflow and providers to keep only the dependencies. In the future when
# planned https://github.com/pypa/pip/issues/11440 is implemented in pip we might be able to use this
# flag and skip the remove step.
@@ -67,7 +67,6 @@ function install_airflow_dependencies_from_branch_tip() {
common::get_colors
common::get_packaging_tool
common::get_airflow_version_specification
-common::override_pip_version_if_needed
common::get_constraints_location
common::show_packaging_tool_version_and_location
diff --git a/scripts/docker/install_from_docker_context_files.sh b/scripts/docker/install_from_docker_context_files.sh
index 6e286b9d9c..cf90a89726 100644
--- a/scripts/docker/install_from_docker_context_files.sh
+++ b/scripts/docker/install_from_docker_context_files.sh
@@ -115,7 +115,7 @@ function install_airflow_and_providers_from_docker_context_files(){
${reinstalling_apache_airflow_package} ${reinstalling_apache_airflow_providers_packages}
set +x
fi
- common::install_packaging_tool
+ common::install_packaging_tools
pip check
}
@@ -135,7 +135,7 @@ function install_all_other_packages_from_docker_context_files() {
set -x
${PACKAGING_TOOL_CMD} install ${EXTRA_INSTALL_FLAGS} ${ADDITIONAL_PIP_INSTALL_FLAGS} \
--force-reinstall --no-deps --no-index ${reinstalling_other_packages}
- common::install_packaging_tool
+ common::install_packaging_tools
set +x
fi
}
@@ -143,7 +143,6 @@ function install_all_other_packages_from_docker_context_files() {
common::get_colors
common::get_packaging_tool
common::get_airflow_version_specification
-common::override_pip_version_if_needed
common::get_constraints_location
common::show_packaging_tool_version_and_location
diff --git a/scripts/docker/install_pip_version.sh b/scripts/docker/install_packaging_tools.sh
similarity index 83%
rename from scripts/docker/install_pip_version.sh
rename to scripts/docker/install_packaging_tools.sh
index af8d25e06e..ca4d125777 100644
--- a/scripts/docker/install_pip_version.sh
+++ b/scripts/docker/install_packaging_tools.sh
@@ -20,9 +20,4 @@
. "$( dirname "${BASH_SOURCE[0]}" )/common.sh"
common::get_colors
-common::get_packaging_tool
-common::get_airflow_version_specification
-common::override_pip_version_if_needed
-common::show_packaging_tool_version_and_location
-
-common::install_packaging_tool
+common::install_packaging_tools
diff --git a/scripts/in_container/_in_container_utils.sh b/scripts/in_container/_in_container_utils.sh
index 4e3cce5114..9e95af43ad 100644
--- a/scripts/in_container/_in_container_utils.sh
+++ b/scripts/in_container/_in_container_utils.sh
@@ -71,7 +71,11 @@ function in_container_get_packaging_tool() {
echo
export PACKAGING_TOOL=""
export PACKAGING_TOOL_CMD="uv pip"
- export EXTRA_INSTALL_FLAGS="--python ${PYTHON_BIN}"
+ if [[ -z ${VIRTUAL_ENV=} ]]; then
+ export EXTRA_INSTALL_FLAGS="--python ${PYTHON_BIN}"
+ else
+ export EXTRA_INSTALL_FLAGS=""
+ fi
export EXTRA_UNINSTALL_FLAGS="--python ${PYTHON_BIN}"
export RESOLUTION_HIGHEST_FLAG="--resolution highest"
export RESOLUTION_LOWEST_DIRECT_FLAG="--resolution lowest-direct"