Skip to content

Commit 605eb90

Browse files
committed
poc move to uv
1 parent 1f40274 commit 605eb90

4 files changed

Lines changed: 65 additions & 67 deletions

File tree

Dockerfile

Lines changed: 45 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ RUN NODE_ENV=production npm run build
4343
# We'll build a light-weight layer along the way with just docs stuff
4444
FROM python:${PYTHON_IMAGE_VERSION} AS docs
4545

46+
# Pull the uv binary in so we can use it as a faster pip / pip-compile.
47+
COPY --from=ghcr.io/astral-sh/uv:0.11.7 /uv /uvx /usr/local/bin/
48+
4649
# By default, Docker has special steps to avoid keeping APT caches in the layers, which
4750
# is good, but in our case, we're going to mount a special cache volume (kept between
4851
# builds), so we WANT the cache to persist.
@@ -68,36 +71,33 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
6871
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
6972

7073
# We create an /opt directory with a virtual environment in it to store our
71-
# application in.
74+
# application in. uv picks this up via VIRTUAL_ENV below.
7275
RUN set -x \
7376
&& python3 -m venv /opt/warehouse
7477

75-
# Now that we've created our virtual environment, we'll go ahead and update
76-
# our $PATH to refer to it first.
78+
# Point uv (and shells) at the venv we just created.
79+
# Hynek-recommended uv tuning (see https://hynek.me/articles/docker-uv/):
80+
# UV_LINK_MODE=copy — silence hardlink-across-FS warnings (cache mount)
81+
# UV_COMPILE_BYTECODE=1 — pay the compile cost once, at build time
82+
# UV_PYTHON_DOWNLOADS=never — never auto-fetch a Python; use the system one
83+
# UV_PYTHON — pin uv to the venv's interpreter
84+
ENV VIRTUAL_ENV="/opt/warehouse" \
85+
UV_LINK_MODE=copy \
86+
UV_COMPILE_BYTECODE=1 \
87+
UV_PYTHON_DOWNLOADS=never \
88+
UV_PYTHON="/opt/warehouse/bin/python"
7789
ENV PATH="/opt/warehouse/bin:${PATH}"
7890

79-
# Next, we want to update pip inside of this virtual
80-
# environment to ensure that we have the latest version.
81-
RUN pip --no-cache-dir --disable-pip-version-check install --upgrade pip
82-
83-
# We copy this into the docker container prior to copying in the rest of our
84-
# application so that we can skip installing requirements if the only thing
85-
# that has changed is the Warehouse code itself.
86-
COPY requirements /tmp/requirements
87-
88-
# Install the Python level Warehouse requirements, this is done after copying
89-
# the requirements but prior to copying Warehouse itself into the container so
90-
# that code changes don't require triggering an entire install of all of
91-
# Warehouse's dependencies.
92-
RUN --mount=type=cache,target=/root/.cache/pip \
91+
# Install the Python level Warehouse requirements. requirements/ is bind-mounted
92+
# rather than COPY'd to keep it out of the layer.
93+
RUN --mount=type=cache,target=/root/.cache/uv \
94+
--mount=type=bind,source=requirements,target=/tmp/requirements \
9395
set -x \
94-
&& pip --disable-pip-version-check \
95-
install --no-deps --only-binary :all: \
96+
&& uv pip install --no-deps --only-binary :all: \
9697
-r /tmp/requirements/docs-dev.txt \
9798
-r /tmp/requirements/docs-user.txt \
9899
-r /tmp/requirements/docs-blog.txt \
99-
&& pip check \
100-
&& find /opt/warehouse -name '*.pyc' -delete
100+
&& uv pip check
101101

102102
WORKDIR /opt/warehouse/src/
103103

@@ -117,6 +117,9 @@ USER docs
117117
# image that it gets deployed into.
118118
FROM python:${PYTHON_IMAGE_VERSION} AS build
119119

120+
# Pull the uv binary in so we can use it as a faster pip / pip-compile.
121+
COPY --from=ghcr.io/astral-sh/uv:0.11.7 /uv /uvx /usr/local/bin/
122+
120123
# Define whether we're building a production or a development image. This will
121124
# generally be used to control whether or not we install our development and
122125
# test dependencies.
@@ -132,47 +135,42 @@ ARG CI=no
132135
ARG IPYTHON=no
133136

134137
# We create an /opt directory with a virtual environment in it to store our
135-
# application in.
138+
# application in. uv picks this up via VIRTUAL_ENV below.
136139
RUN set -x \
137140
&& python3 -m venv /opt/warehouse
138141

139-
# Now that we've created our virtual environment, we'll go ahead and update
140-
# our $PATH to refer to it first.
142+
# Point uv (and shells) at the venv we just created.
143+
# See the docs stage above for the rationale behind each UV_* variable.
144+
ENV VIRTUAL_ENV="/opt/warehouse" \
145+
UV_LINK_MODE=copy \
146+
UV_COMPILE_BYTECODE=1 \
147+
UV_PYTHON_DOWNLOADS=never \
148+
UV_PYTHON="/opt/warehouse/bin/python"
141149
ENV PATH="/opt/warehouse/bin:${PATH}"
142150

143-
# Next, we want to update pip inside of this virtual
144-
# environment to ensure that we have the latest version.
145-
RUN pip --no-cache-dir --disable-pip-version-check install --upgrade pip
146-
147-
# We copy this into the docker container prior to copying in the rest of our
148-
# application so that we can skip installing requirements if the only thing
149-
# that has changed is the Warehouse code itself.
150-
COPY requirements /tmp/requirements
151-
152151
# Install our development dependencies if we're building a development install
153-
# otherwise this will do nothing.
154-
RUN --mount=type=cache,target=/root/.cache/pip \
152+
# otherwise this will do nothing. requirements/ is bind-mounted to stay out of
153+
# the layer.
154+
RUN --mount=type=cache,target=/root/.cache/uv \
155+
--mount=type=bind,source=requirements,target=/tmp/requirements \
155156
set -x \
156-
&& if [ "$DEVEL" = "yes" ]; then pip --disable-pip-version-check install -r /tmp/requirements/dev.txt; fi
157+
&& if [ "$DEVEL" = "yes" ]; then uv pip install -r /tmp/requirements/dev.txt; fi
157158

158-
RUN --mount=type=cache,target=/root/.cache/pip \
159+
RUN --mount=type=cache,target=/root/.cache/uv \
160+
--mount=type=bind,source=requirements,target=/tmp/requirements \
159161
set -x \
160-
&& if [ "$DEVEL" = "yes" ] && [ "$IPYTHON" = "yes" ]; then pip --disable-pip-version-check install -r /tmp/requirements/ipython.txt; fi
162+
&& if [ "$DEVEL" = "yes" ] && [ "$IPYTHON" = "yes" ]; then uv pip install -r /tmp/requirements/ipython.txt; fi
161163

162-
# Install the Python level Warehouse requirements, this is done after copying
163-
# the requirements but prior to copying Warehouse itself into the container so
164-
# that code changes don't require triggering an entire install of all of
165-
# Warehouse's dependencies.
166-
RUN --mount=type=cache,target=/root/.cache/pip \
164+
# Install the Python level Warehouse requirements.
165+
RUN --mount=type=cache,target=/root/.cache/uv \
166+
--mount=type=bind,source=requirements,target=/tmp/requirements \
167167
set -x \
168-
&& pip --disable-pip-version-check \
169-
install --no-deps --only-binary :all: \
168+
&& uv pip install --no-deps --only-binary :all: \
170169
-r /tmp/requirements/deploy.txt \
171170
-r /tmp/requirements/main.txt \
172171
$(if [ "$DEVEL" = "yes" ]; then echo '-r /tmp/requirements/tests.txt -r /tmp/requirements/lint.txt'; fi) \
173172
$(if [ "$CI" = "yes" ]; then echo '-r /tmp/requirements/docs-dev.txt -r /tmp/requirements/docs-user.txt -r /tmp/requirements/docs-blog.txt'; fi ) \
174-
&& pip check \
175-
&& find /opt/warehouse -name '*.pyc' -delete
173+
&& uv pip check
176174

177175

178176

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ translations: .state/docker-build-base
124124
docker compose run --rm base bin/translations
125125

126126
requirements/%.txt: requirements/%.in
127-
docker compose run --rm base pip-compile --generate-hashes --output-file=$@ $<
127+
docker compose run --rm base uv pip compile --generate-hashes --output-file=$@ $<
128128

129129
resetdb: .state/docker-build-base
130130
docker compose pause web worker

bin/deps

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ set -ex
33

44
export TMPDIR=$(mktemp -d)
55
cp requirements/*.txt $TMPDIR/
6-
pip-compile -o $TMPDIR/deploy.txt requirements/deploy.in > /dev/null
7-
pip-compile -o $TMPDIR/main.txt requirements/main.in > /dev/null
8-
pip-compile -o $TMPDIR/lint.txt requirements/lint.in > /dev/null
9-
pip-compile -o $TMPDIR/tests.txt requirements/tests.in > /dev/null
10-
pip-compile -o $TMPDIR/dev.txt requirements/dev.in > /dev/null
11-
pip-compile -o $TMPDIR/docs-dev.txt requirements/docs-dev.in > /dev/null
12-
pip-compile -o $TMPDIR/docs-user.txt requirements/docs-user.in > /dev/null
13-
pip-compile -o $TMPDIR/docs-blog.txt requirements/docs-blog.in > /dev/null
6+
uv pip compile --quiet -o $TMPDIR/deploy.txt requirements/deploy.in
7+
uv pip compile --quiet -o $TMPDIR/main.txt requirements/main.in
8+
uv pip compile --quiet -o $TMPDIR/lint.txt requirements/lint.in
9+
uv pip compile --quiet -o $TMPDIR/tests.txt requirements/tests.in
10+
uv pip compile --quiet -o $TMPDIR/dev.txt requirements/dev.in
11+
uv pip compile --quiet -o $TMPDIR/docs-dev.txt requirements/docs-dev.in
12+
uv pip compile --quiet -o $TMPDIR/docs-user.txt requirements/docs-user.in
13+
uv pip compile --quiet -o $TMPDIR/docs-blog.txt requirements/docs-blog.in
1414
python bin/depchecker.py $TMPDIR/deploy.txt requirements/deploy.txt
1515
python bin/depchecker.py $TMPDIR/main.txt requirements/main.txt
1616
python bin/depchecker.py $TMPDIR/lint.txt requirements/lint.txt
@@ -20,4 +20,4 @@ python bin/depchecker.py $TMPDIR/docs-dev.txt requirements/docs-dev.txt
2020
python bin/depchecker.py $TMPDIR/docs-user.txt requirements/docs-user.txt
2121
python bin/depchecker.py $TMPDIR/docs-blog.txt requirements/docs-blog.txt
2222
rm -r $TMPDIR
23-
pip check
23+
uv pip check

bin/deps-upgrade

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ extract_argument() {
1616
echo "${2:-${1#*=}}"
1717
}
1818

19-
pip_compile_args=""
19+
uv_compile_args=""
2020

2121
handle_options() {
2222
while [ $# -gt 0 ]; do
@@ -26,7 +26,7 @@ handle_options() {
2626
exit 0
2727
;;
2828
-a | --all)
29-
pip_compile_args="--upgrade"
29+
uv_compile_args="--upgrade"
3030
;;
3131
-p | --package*)
3232
if ! has_argument $@; then
@@ -35,7 +35,7 @@ handle_options() {
3535
exit 1
3636
fi
3737

38-
pip_compile_args="--upgrade-package $(extract_argument $@)"
38+
uv_compile_args="--upgrade-package $(extract_argument $@)"
3939

4040
shift
4141
;;
@@ -53,10 +53,10 @@ handle_options() {
5353
handle_options "$@"
5454

5555
set -ex
56-
pip-compile --allow-unsafe --generate-hashes $pip_compile_args --output-file=requirements/deploy.txt requirements/deploy.in
57-
pip-compile --allow-unsafe --generate-hashes $pip_compile_args --output-file=requirements/main.txt requirements/main.in
58-
pip-compile --allow-unsafe --generate-hashes $pip_compile_args --output-file=requirements/lint.txt requirements/lint.in
59-
pip-compile --allow-unsafe --generate-hashes $pip_compile_args --output-file=requirements/tests.txt requirements/tests.in
60-
pip-compile --allow-unsafe --generate-hashes $pip_compile_args --output-file=requirements/docs-dev.txt requirements/docs-dev.in
61-
pip-compile --allow-unsafe --generate-hashes $pip_compile_args --output-file=requirements/docs-user.txt requirements/docs-user.in
62-
pip-compile --allow-unsafe --generate-hashes $pip_compile_args --output-file=requirements/docs-blog.txt requirements/docs-blog.in
56+
uv pip compile --generate-hashes $uv_compile_args --output-file=requirements/deploy.txt requirements/deploy.in
57+
uv pip compile --generate-hashes $uv_compile_args --output-file=requirements/main.txt requirements/main.in
58+
uv pip compile --generate-hashes $uv_compile_args --output-file=requirements/lint.txt requirements/lint.in
59+
uv pip compile --generate-hashes $uv_compile_args --output-file=requirements/tests.txt requirements/tests.in
60+
uv pip compile --generate-hashes $uv_compile_args --output-file=requirements/docs-dev.txt requirements/docs-dev.in
61+
uv pip compile --generate-hashes $uv_compile_args --output-file=requirements/docs-user.txt requirements/docs-user.in
62+
uv pip compile --generate-hashes $uv_compile_args --output-file=requirements/docs-blog.txt requirements/docs-blog.in

0 commit comments

Comments
 (0)