Skip to content

Commit e23bd66

Browse files
authored
PYTHON-6091 Pin a consistent uv binary version in CI and locally (#3053)
1 parent 6ab44be commit e23bd66

7 files changed

Lines changed: 327 additions & 59 deletions

File tree

‎.evergreen/scripts/configure-env.sh‎

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,53 @@ fi
1414
PROJECT_DIRECTORY="$(pwd)"
1515
DRIVERS_TOOLS="$(dirname $PROJECT_DIRECTORY)/drivers-tools"
1616
CARGO_HOME=${CARGO_HOME:-${DRIVERS_TOOLS}/.cargo}
17-
UV_TOOL_DIR=$PROJECT_DIRECTORY/.local/uv/tools
18-
UV_CACHE_DIR=$PROJECT_DIRECTORY/.local/uv/cache
1917
DRIVERS_TOOLS_BINARIES="$DRIVERS_TOOLS/.bin"
2018
MONGODB_BINARIES="$DRIVERS_TOOLS/mongodb/bin"
2119

22-
# On Evergreen jobs, "CI" will be set, and we don't want to write to $HOME.
20+
# On Evergreen jobs, "CI" will be set, and we don't want to write to $HOME or
21+
# have binaries shared across tasks, so use a TMPDIR. On non-CI hosts
22+
# (spawn hosts, VMs such as GCP/Azure, and local dev), use the conventional
23+
# ~/.local/bin which tools on the PATH (or the shell rc) can find.
2324
if [ "${CI:-}" == "true" ]; then
24-
PYMONGO_BIN_DIR=${DRIVERS_TOOLS_BINARIES:-}
25-
# We want to use a path that's already on PATH on spawn hosts.
25+
PYMONGO_BIN_DIR="${TMPDIR:-/tmp}"/pymongo_bin
2626
else
27-
PYMONGO_BIN_DIR=$HOME/cli_bin
27+
PYMONGO_BIN_DIR=$HOME/.local/bin
2828
fi
2929

30-
PATH_EXT="$MONGODB_BINARIES:$DRIVERS_TOOLS_BINARIES:$PYMONGO_BIN_DIR:\$PATH"
30+
# Cygwin spelling for bash PATH entries; PYMONGO_BIN_DIR itself is converted
31+
# to native form below for consumers like uv.
32+
if [ "Windows_NT" = "${OS:-}" ]; then
33+
PYMONGO_BIN_DIR_POSIX="$(cygpath -u "$PYMONGO_BIN_DIR")"
34+
else
35+
PYMONGO_BIN_DIR_POSIX="$PYMONGO_BIN_DIR"
36+
fi
37+
38+
# Add the latest MongoDB toolchain bin dir to PATH if it exists, so that hosts
39+
# with an old system Python (e.g. RHEL8's 3.6) still get a modern interpreter
40+
# for tool installs like `uv tool install rust-just`. It goes after
41+
# PYMONGO_BIN_DIR so the pinned uv (installed there by setup-uv.py) takes
42+
# precedence over the toolchain's uv.
43+
if [ "Windows_NT" = "${OS:-}" ]; then
44+
_toolchain_bin="/cygdrive/c/Python/Current/Scripts"
45+
elif [ "$(uname -s)" == "Darwin" ]; then
46+
_toolchain_bin="/Library/Frameworks/Python.Framework/Versions/Current/bin"
47+
else
48+
_toolchain_bin="/opt/python/Current/bin"
49+
fi
50+
if [ -d "$_toolchain_bin" ]; then
51+
PATH_EXT="$MONGODB_BINARIES:$PYMONGO_BIN_DIR_POSIX:$_toolchain_bin:$DRIVERS_TOOLS_BINARIES:\$PATH"
52+
else
53+
PATH_EXT="$MONGODB_BINARIES:$PYMONGO_BIN_DIR_POSIX:$DRIVERS_TOOLS_BINARIES:\$PATH"
54+
fi
3155

3256
# Python has cygwin path problems on Windows. Detect prospective mongo-orchestration home directory
3357
if [ "Windows_NT" = "${OS:-}" ]; then # Magic variable in cygwin
3458
DRIVERS_TOOLS=$(cygpath -m $DRIVERS_TOOLS)
3559
PROJECT_DIRECTORY=$(cygpath -m $PROJECT_DIRECTORY)
3660
CARGO_HOME=$(cygpath -m $CARGO_HOME)
37-
UV_TOOL_DIR=$(cygpath -m "$UV_TOOL_DIR")
38-
UV_CACHE_DIR=$(cygpath -m "$UV_CACHE_DIR")
3961
DRIVERS_TOOLS_BINARIES=$(cygpath -m "$DRIVERS_TOOLS_BINARIES")
4062
MONGODB_BINARIES=$(cygpath -m "$MONGODB_BINARIES")
63+
# Native form, uniform with the paths above, for consumers like uv.
4164
PYMONGO_BIN_DIR=$(cygpath -m "$PYMONGO_BIN_DIR")
4265
fi
4366

@@ -62,10 +85,8 @@ export DRIVERS_TOOLS_BINARIES="$DRIVERS_TOOLS_BINARIES"
6285
export PROJECT_DIRECTORY="$PROJECT_DIRECTORY"
6386
6487
export CARGO_HOME="$CARGO_HOME"
65-
export UV_TOOL_DIR="$UV_TOOL_DIR"
66-
export UV_CACHE_DIR="$UV_CACHE_DIR"
67-
export UV_TOOL_BIN_DIR="$DRIVERS_TOOLS_BINARIES"
6888
export PYMONGO_BIN_DIR="$PYMONGO_BIN_DIR"
89+
export PYMONGO_BIN_DIR_POSIX="$PYMONGO_BIN_DIR_POSIX"
6990
export PATH="$PATH_EXT"
7091
# shellcheck disable=SC2154
7192
export PROJECT="${project:-mongo-python-driver}"
@@ -90,25 +111,3 @@ cat <<EOT > expansion.yml
90111
DRIVERS_TOOLS: "$DRIVERS_TOOLS"
91112
PROJECT_DIRECTORY: "$PROJECT_DIRECTORY"
92113
EOT
93-
94-
# If the toolchain is available, symlink binaries to the bin dir. This has to be done
95-
# after drivers-tools is cloned, since we might be using its binary dir.
96-
_bin_path=""
97-
if [ "Windows_NT" == "${OS:-}" ]; then
98-
_bin_path="/cygdrive/c/Python/Current/Scripts"
99-
elif [ "$(uname -s)" == "Darwin" ]; then
100-
_bin_path="/Library/Frameworks/Python.Framework/Versions/Current/bin"
101-
else
102-
_bin_path="/opt/python/Current/bin"
103-
fi
104-
if [ -d "${_bin_path}" ]; then
105-
_suffix=""
106-
if [ "Windows_NT" == "${OS:-}" ]; then
107-
_suffix=".exe"
108-
fi
109-
echo "Symlinking binaries from toolchain"
110-
mkdir -p $PYMONGO_BIN_DIR
111-
ln -s ${_bin_path}/just${_suffix} $PYMONGO_BIN_DIR/just${_suffix}
112-
ln -s ${_bin_path}/uv${_suffix} $PYMONGO_BIN_DIR/uv${_suffix}
113-
ln -s ${_bin_path}/uvx${_suffix} $PYMONGO_BIN_DIR/uvx${_suffix}
114-
fi
Lines changed: 66 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/bin/bash
22
# Install the necessary dependencies.
3-
set -eu
3+
set -euo pipefail
44

55
HERE=$(dirname ${BASH_SOURCE:-$0})
66
HERE="$( cd -- "$HERE" > /dev/null 2>&1 && pwd )"
@@ -11,27 +11,76 @@ if [ -f $HERE/env.sh ]; then
1111
. $HERE/env.sh
1212
fi
1313

14-
# Set up the default bin directory.
15-
if [ -z "${PYMONGO_BIN_DIR:-}" ]; then
16-
PYMONGO_BIN_DIR="$HOME/.local/bin"
14+
# PYMONGO_BIN_DIR is set by setup-system.sh/env.sh (or setup-dev-env.sh); default
15+
# it for robustness. Native (Windows) form on cygwin, for consumers like uv;
16+
# PYMONGO_BIN_DIR_POSIX is the cygwin form for bash PATH contexts.
17+
export PYMONGO_BIN_DIR="${PYMONGO_BIN_DIR:-$HOME/.local/bin}"
18+
if [ "Windows_NT" = "${OS:-}" ]; then
19+
_bin_dir="$(cygpath -m "$PYMONGO_BIN_DIR")"
20+
export PYMONGO_BIN_DIR="$_bin_dir"
21+
_posix_bin_dir="$(cygpath -u "$_bin_dir")"
22+
export PYMONGO_BIN_DIR_POSIX="$_posix_bin_dir"
23+
else
24+
export PYMONGO_BIN_DIR_POSIX="$PYMONGO_BIN_DIR"
1725
fi
26+
# UV_TOOL_BIN_DIR is uv's name for the same dir (setup-uv.py reads both).
27+
# UV_TOOL_DIR is left to ensure_uv.sh.
28+
export UV_TOOL_BIN_DIR="${UV_TOOL_BIN_DIR:-$PYMONGO_BIN_DIR}"
1829

19-
# Ensure uv is installed.
20-
if ! command -v uv &>/dev/null; then
21-
_BIN_DIR=$PYMONGO_BIN_DIR
22-
mkdir -p ${_BIN_DIR}
23-
echo "Installing uv..."
24-
curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR="$_BIN_DIR" INSTALLER_NO_MODIFY_PATH=1 sh
25-
if [ "Windows_NT" = "${OS:-}" ]; then
26-
chmod +x "$(cygpath -u $_BIN_DIR)/uv.exe"
30+
# Ensure the bin dir is on PATH: hosts without env.sh (e.g. auth-aws-ecs) never
31+
# export it, so a fresh pinned install there would be invisible to the probe
32+
# below and to later steps like `uv tool install` and `uv sync`.
33+
case ":$PATH:" in
34+
*":$PYMONGO_BIN_DIR_POSIX:"*) ;;
35+
*) export PATH="$PYMONGO_BIN_DIR_POSIX:$PATH" ;;
36+
esac
37+
38+
# Compute the setup script path once (native Windows path on cygwin).
39+
_uv_setup_script="$HERE/setup-uv.py"
40+
if [ "Windows_NT" = "${OS:-}" ]; then
41+
_uv_setup_script="$(cygpath -m "$_uv_setup_script")"
42+
fi
43+
44+
# Skip setup when the pinned uv is already installed: `setup-uv.py --check`
45+
# compares the uv on PATH with the required-version pin, without side effects.
46+
# A full `uv sync` here would download Python and install/build dependencies
47+
# just to make this decision, and would run before setup-uv-python.sh sets
48+
# UV_PYTHON, creating the environment twice on local dev.
49+
#
50+
# On CI we also require UV_CACHE_DIR to be set: ensure_uv.sh scopes uv's cache
51+
# to a task-local dir, so an unset UV_CACHE_DIR means the uv setup has not run
52+
# yet in this task and we must do the setup phase.
53+
_need_setup=1
54+
if [ "${CI:-}" != "true" ] || [ -n "${UV_CACHE_DIR:-}" ]; then
55+
if python3 "$_uv_setup_script" --check >/dev/null 2>&1; then
56+
echo "uv is already set up; skipping uv setup."
57+
_need_setup=0
58+
fi
59+
fi
60+
61+
# Set up uv if needed.
62+
if [ "$_need_setup" = "1" ]; then
63+
# ensure-uv.sh (drivers-evergreen-tools) finds or installs uv and scopes its env.
64+
if [ -n "${DRIVERS_TOOLS:-}" ] && [ -f "$DRIVERS_TOOLS/.evergreen/ensure-uv.sh" ]; then
65+
. "$DRIVERS_TOOLS/.evergreen/ensure-uv.sh"
66+
ensure_uv || exit 1
67+
fi
68+
69+
# Do the uv setup (bin dir, pinning, env.sh). Uses the toolchain python3
70+
# (added to PATH by configure-env.sh) so no project .venv is created here,
71+
# and no required-version check is triggered.
72+
python3 "$_uv_setup_script"
73+
74+
# Re-source env.sh so the values setup-uv.py wrote are available.
75+
if [ -f $HERE/env.sh ]; then
76+
. $HERE/env.sh
2777
fi
28-
export PATH="$PYMONGO_BIN_DIR:$PATH"
29-
echo "Installing uv... done."
3078
fi
3179

32-
# Ensure just is installed.
33-
if ! command -v just &>/dev/null; then
34-
uv tool install rust-just
80+
# Make just available. It has no version constraint, so if it is already on PATH
81+
# there is nothing to do; otherwise install it into the bin dir via uv.
82+
if ! command -v just >/dev/null 2>&1; then
83+
uv tool install --no-config rust-just
3584
fi
3685

3786
popd > /dev/null

‎.evergreen/scripts/setup-dev-env.sh‎

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,54 @@ if [ -f $HERE/test-env.sh ]; then
1616
. $HERE/test-env.sh
1717
fi
1818

19-
# Handle the value for UV_PYTHON.
20-
. $HERE/setup-uv-python.sh
19+
# The bin dir for the pinned uv/just. setup-system.sh sets it on evergreen hosts;
20+
# default it here so local dev (without setup-system.sh) also has a usable value.
21+
# Native (Windows) form on cygwin, like install-dependencies.sh.
22+
export PYMONGO_BIN_DIR="${PYMONGO_BIN_DIR:-$HOME/.local/bin}"
23+
if [ "Windows_NT" = "${OS:-}" ]; then
24+
_bin_dir="$(cygpath -m "$PYMONGO_BIN_DIR")"
25+
export PYMONGO_BIN_DIR="$_bin_dir"
26+
_posix_bin_dir="$(cygpath -u "$_bin_dir")"
27+
export PYMONGO_BIN_DIR_POSIX="$_posix_bin_dir"
28+
else
29+
export PYMONGO_BIN_DIR_POSIX="$PYMONGO_BIN_DIR"
30+
fi
31+
32+
# install-dependencies.sh runs as a child process, so its PATH changes do not
33+
# propagate back here: ensure the bin dir is on this process's PATH too, so a
34+
# fresh install (first run, bin dir not on PATH yet) is visible to the
35+
# `uv sync` and pre-commit setup below.
36+
case ":$PATH:" in
37+
*":$PYMONGO_BIN_DIR_POSIX:"*) ;;
38+
*) export PATH="$PYMONGO_BIN_DIR_POSIX:$PATH" ;;
39+
esac
40+
41+
# Make sure a login shell can find the bin dir by adding it to the rc file, so
42+
# local dev (which may never run setup-system.sh) still has it on PATH. env.sh's
43+
# PATH does not persist past this session. Select the rc file from $SHELL (not
44+
# by which rc file happens to exist) so the user's actual shell is updated, and
45+
# create it if it does not exist yet.
46+
if [ "${CI:-}" != "true" ] && [ "${GITHUB_ACTIONS:-}" != "true" ]; then
47+
case "${SHELL:-}" in
48+
*/zsh) _rc="$HOME/.zshrc" ;;
49+
*) _rc="$HOME/.bashrc" ;;
50+
esac
51+
touch "$_rc"
52+
grep -qF 'export PATH="'"$PYMONGO_BIN_DIR_POSIX"':$PATH"' "$_rc" 2>/dev/null || \
53+
printf 'export PATH="%s:$PATH"\n' "$PYMONGO_BIN_DIR_POSIX" >> "$_rc"
54+
fi
2155

2256
# Ensure dependencies are installed.
2357
bash $HERE/install-dependencies.sh
2458

25-
# Re-source env.sh: install-dependencies.sh may have appended to it, e.g. when it
26-
# had to install Python on an image that lacks a toolchain.
59+
# Re-source env.sh in case a dependency install updated it, e.g. on a host
60+
# without a toolchain where uv was installed into a shared bin dir.
2761
if [ -f $HERE/env.sh ]; then
2862
. $HERE/env.sh
2963
fi
3064

31-
# Add the default install path to the path if needed.
32-
if [ -z "${PYMONGO_BIN_DIR:-}" ]; then
33-
export PATH="$PATH:$HOME/.local/bin"
34-
fi
65+
# Handle the value for UV_PYTHON.
66+
. $HERE/setup-uv-python.sh
3567

3668
# Only run the next part if not running on CI.
3769
if [ -z "${CI:-}" ]; then

0 commit comments

Comments
 (0)