From a0d2ecf43466083925291e749ab9c2a451f6963d Mon Sep 17 00:00:00 2001 From: Ivan Gabaldon Date: Sun, 14 Sep 2025 10:36:21 +0200 Subject: [PATCH] [enh] container: build with uv (#5199) This commit replaces `pip` in container builds with `uv` pip compat with a 1:1 parity. The only thing that changes is the installation speed of the wheels, which seems to be considerably faster, although I haven't been able to properly quantify this yet. uv also gives us more tools to manage the cache. We can revert the prior cache changes in `container.yml` as we won't have duplicated wheels anymore. --- .github/workflows/container.yml | 34 ++++------------------ container/base-builder.yml | 2 +- container/builder.dockerfile | 23 ++++++++------- setup.py | 51 ++++++++++++++++----------------- utils/lib_sxng_container.sh | 3 +- 5 files changed, 46 insertions(+), 67 deletions(-) diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml index 03cbdcd59..d331ed050 100644 --- a/.github/workflows/container.yml +++ b/.github/workflows/container.yml @@ -104,8 +104,6 @@ jobs: needs: build-base strategy: fail-fast: false - # Faster runners first to cache arch independent wheels - max-parallel: 1 matrix: include: - arch: amd64 @@ -121,8 +119,6 @@ jobs: permissions: # Organization GHCR packages: write - # Clean key cache step - actions: write outputs: docker_tag: ${{ steps.build.outputs.docker_tag }} @@ -146,23 +142,12 @@ jobs: restore-keys: "python-${{ env.PYTHON_VERSION }}-${{ runner.arch }}-" path: "./local/" - - name: Restore cache container mounts - id: cache-container-mounts - uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + - name: Setup cache container uv + uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 with: - key: "container-mounts-${{ hashFiles('./container/*.dockerfile') }}" - restore-keys: "container-mounts-" - path: | - /var/tmp/buildah-cache/ - /var/tmp/buildah-cache-*/ - - # https://github.com/actions/cache/pull/1308 - - if: steps.cache-container-mounts.outputs.cache-hit == 'true' - name: Clean key cache container mounts - continue-on-error: true - env: - GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - run: gh cache delete container-mounts-${{ hashFiles('./container/*.dockerfile') }} + key: "container-uv-${{ matrix.arch }}-${{ hashFiles('./requirements*.txt') }}" + restore-keys: "container-uv-${{ matrix.arch }}-" + path: "/var/tmp/buildah-cache-1001/uv/" - if: ${{ matrix.emulation }} name: Setup QEMU @@ -181,15 +166,6 @@ jobs: OVERRIDE_ARCH: "${{ matrix.arch }}" run: make podman.build - - if: always() - name: Save cache container mounts - uses: actions/cache/save@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 - with: - key: "container-mounts-${{ hashFiles('./container/*.dockerfile') }}" - path: | - /var/tmp/buildah-cache/ - /var/tmp/buildah-cache-*/ - test: name: Test (${{ matrix.arch }}) runs-on: ${{ matrix.os }} diff --git a/container/base-builder.yml b/container/base-builder.yml index e065a346e..0b16e4be7 100644 --- a/container/base-builder.yml +++ b/container/base-builder.yml @@ -6,7 +6,7 @@ contents: - alpine-base - build-base - python3-dev - - py3-pip + - uv - brotli entrypoint: diff --git a/container/builder.dockerfile b/container/builder.dockerfile index dc2279dd9..99b22fcc2 100644 --- a/container/builder.dockerfile +++ b/container/builder.dockerfile @@ -2,10 +2,13 @@ FROM ghcr.io/searxng/base:searxng-builder AS builder COPY ./requirements*.txt ./ -RUN --mount=type=cache,id=pip,target=/root/.cache/pip set -eux; \ - python -m venv ./.venv/; \ - . ./.venv/bin/activate; \ - pip install -r ./requirements.txt -r ./requirements-server.txt +ARG TIMESTAMP="0" + +RUN --mount=type=cache,id=uv,target=/root/.cache/uv set -eux; \ + uv venv; \ + uv pip install --no-managed-python --compile-bytecode --requirements ./requirements.txt --requirements ./requirements-server.txt; \ + uv cache prune --ci; \ + find ./.venv/ -exec touch -h -t $TIMESTAMP {} + COPY ./searx/ ./searx/ @@ -13,12 +16,12 @@ ARG TIMESTAMP_SETTINGS="0" RUN set -eux; \ python -m compileall -q ./searx/; \ - touch -c --date=@$TIMESTAMP_SETTINGS ./searx/settings.yml; \ + touch -c -t $TIMESTAMP_SETTINGS ./searx/settings.yml; \ find ./searx/static/ -type f \ - \( -name "*.html" -o -name "*.css" -o -name "*.js" -o -name "*.svg" \) \ - -exec gzip -9 -k {} + \ - -exec brotli -9 -k {} + \ - -exec gzip --test {}.gz + \ - -exec brotli --test {}.br +; \ + \( -name "*.html" -o -name "*.css" -o -name "*.js" -o -name "*.svg" \) \ + -exec gzip -9 -k {} + \ + -exec brotli -9 -k {} + \ + -exec gzip --test {}.gz + \ + -exec brotli --test {}.br +; \ # Move always changing files to /usr/local/searxng/ mv ./searx/version_frozen.py ./ diff --git a/setup.py b/setup.py index baab24a1a..bae30fb40 100644 --- a/setup.py +++ b/setup.py @@ -10,48 +10,45 @@ with open('README.rst', encoding='utf-8') as f: long_description = f.read() with open('requirements.txt') as f: - requirements = [ l.strip() for l in f.readlines()] + requirements = [l.strip() for l in f.readlines()] with open('requirements-dev.txt') as f: - dev_requirements = [ l.strip() for l in f.readlines()] + dev_requirements = [l.strip() for l in f.readlines()] setup( name='searxng', - python_requires=">=3.8", - version=VERSION_TAG, - description="A privacy-respecting, hackable metasearch engine", + description="SearXNG is a metasearch engine. Users are neither tracked nor profiled.", long_description=long_description, + license="AGPL-3.0-or-later", + author='SearXNG', + author_email='contact@searxng.org', + python_requires=">=3.10", + version=VERSION_TAG, + keywords='metasearch searchengine search web http', url=get_setting('brand.docs_url'), - project_urls={ - "Code": GIT_URL, - "Issue tracker": get_setting('brand.issue_url') - }, classifiers=[ - "Programming Language :: Python", + "Development Status :: 5 - Production/Stable", "Topic :: Internet", "Topic :: Internet :: WWW/HTTP :: HTTP Servers", "Topic :: Internet :: WWW/HTTP :: WSGI :: Application", - 'License :: OSI Approved :: GNU Affero General Public License v3' + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ], - keywords='metasearch searchengine search web http', - author='SearXNG dev team', - author_email='contact@searxng.org', - license='GNU Affero General Public License', + project_urls={"Code": GIT_URL, "Issue tracker": get_setting('brand.issue_url')}, + entry_points={ + 'console_scripts': ['searxng-run = searx.webapp:run', 'searxng-checker = searx.search.checker.__main__:main'] + }, packages=find_packages( include=[ - 'searx', 'searx.*', 'searx.*.*', 'searx.*.*.*', + 'searx', + 'searx.*', + 'searx.*.*', + 'searx.*.*.*', ] ), - install_requires=requirements, - extras_require={ - 'test': dev_requirements - }, - entry_points={ - 'console_scripts': [ - 'searxng-run = searx.webapp:run', - 'searxng-checker = searx.search.checker.__main__:main' - ] - }, package_data={ 'searx': [ 'settings.yml', @@ -74,4 +71,6 @@ setup( 'translations/*/*/*', ], }, + install_requires=requirements, + extras_require={'test': dev_requirements}, ) diff --git a/utils/lib_sxng_container.sh b/utils/lib_sxng_container.sh index 65b2c4b9b..73947bdba 100644 --- a/utils/lib_sxng_container.sh +++ b/utils/lib_sxng_container.sh @@ -102,7 +102,8 @@ container.build() { # shellcheck disable=SC2086 "$container_engine" $params_build_builder \ - --build-arg="TIMESTAMP_SETTINGS=$(git log -1 --format="%cd" --date=unix -- ./searx/settings.yml)" \ + --build-arg="TIMESTAMP=$(git log -1 --date=format:'%Y%m%d%H%M.%S' --format='%ad')" \ + --build-arg="TIMESTAMP_SETTINGS=$(git log -1 --date=format:'%Y%m%d%H%M.%S' --format='%ad' ./searx/settings.yml)" \ --tag="localhost/$CONTAINER_IMAGE_ORGANIZATION/$CONTAINER_IMAGE_NAME:builder" \ --file="./container/builder.dockerfile" \ .