Skip to content

Instantly share code, notes, and snippets.

@ewhauser
Last active February 16, 2024 23:11
Show Gist options
  • Save ewhauser/9e4269b9c871620bc2a4b8d58f1799a3 to your computer and use it in GitHub Desktop.
Save ewhauser/9e4269b9c871620bc2a4b8d58f1799a3 to your computer and use it in GitHub Desktop.
diff --git a/internal_setup.bzl b/internal_setup.bzl
index a80099f..56eb486 100644
--- a/internal_setup.bzl
+++ b/internal_setup.bzl
@@ -21,7 +21,7 @@ load("@rules_bazel_integration_test//bazel_integration_test:deps.bzl", "bazel_in
load("@rules_bazel_integration_test//bazel_integration_test:repo_defs.bzl", "bazel_binaries")
load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies", "rules_proto_toolchains")
load("//:version.bzl", "SUPPORTED_BAZEL_VERSIONS")
-load("//python/pip_install:repositories.bzl", "pip_install_dependencies")
+load("//python/pip_install:repositories.bzl", "pip_install_dependencies", "uv_dependencies")
load("//python/private:internal_config_repo.bzl", "internal_config_repo") # buildifier: disable=bzl-visibility
def rules_python_internal_setup():
@@ -31,6 +31,7 @@ def rules_python_internal_setup():
# Because we don't use the pip_install rule, we have to call this to fetch its deps
pip_install_dependencies()
+ uv_dependencies()
bazel_skylib_workspace()
diff --git a/python/pip_install/mirror_uv.sh b/python/pip_install/mirror_uv.sh
new file mode 100755
index 0000000..8d9c719
--- /dev/null
+++ b/python/pip_install/mirror_uv.sh
@@ -0,0 +1,67 @@
+#!/usr/bin/env bash
+
+set -o errexit -o nounset -o pipefail
+SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
+RELEASES=$(mktemp)
+RAW=$(mktemp)
+
+REPOSITORY=${1:-"astral-sh/uv"}
+
+JQ_FILTER=\
+'map(
+ {
+ "key": .tag_name,
+ "value": .assets
+ | map(select((.name | contains("uv-")) and (.name | contains("sha256") | not) ))
+ | map({
+ "key": .name | capture("uv-(?<platform>.*)\\.(tar\\.gz|zip)") | .platform,
+ "value": (.browser_download_url + ".sha256"),
+ })
+ | from_entries
+ }
+) | from_entries'
+
+SHA256_FILTER=\
+'
+map(
+ select(.name == $tag)
+ | .assets
+ | map(.browser_download_url)[]
+ | select(endswith(".sha256"))
+)[]
+'
+
+curl > $RELEASES \
+ --silent \
+ --header "Accept: application/vnd.github.v3+json" \
+ https://api.github.com/repos/${REPOSITORY}/releases?per_page=1
+
+cat $RELEASES
+
+jq "$JQ_FILTER" <$RELEASES >$RAW
+
+# Combine the new versions with the existing ones.
+# New versions should appear first, but existing content should overwrite new
+CURRENT=$(mktemp)
+python3 -c "import json; exec(open('$SCRIPT_DIR/uv_versions.bzl').read()); print(json.dumps(UV_VERSIONS))" > $CURRENT
+OUT=$(mktemp)
+jq --slurp '.[0] * .[1]' $RAW $CURRENT > $OUT
+
+FIXED=$(mktemp)
+# Replace placeholder sha256 URLs with their content
+for tag in $(jq -r 'keys | .[]' < $OUT); do
+ # Download checksums for this tag
+ # Note: this is wasteful; we will curl for sha256 files even if the CURRENT content already had resolved them
+ for sha256url in $(jq --arg tag $tag -r "$SHA256_FILTER" < $RELEASES); do
+ sha256=$(curl --silent --location $sha256url | awk '{print $1}')
+ jq ".[\"$tag\"] |= with_entries(.value = (if .value == \"$sha256url\" then \"$sha256\" else .value end))" < $OUT > $FIXED
+ mv $FIXED $OUT
+ done
+done
+
+# Overwrite the file with updated content
+(
+ echo '"This file is automatically updated by mirror_uv.sh"'
+ echo -n "UV_VERSIONS = "
+ cat $OUT
+)>$SCRIPT_DIR/uv_versions.bzl
diff --git a/python/pip_install/repositories.bzl b/python/pip_install/repositories.bzl
index 91bdd4b..b7179ff 100644
--- a/python/pip_install/repositories.bzl
+++ b/python/pip_install/repositories.bzl
@@ -16,6 +16,7 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
+load(":uv_versions.bzl", "UV_VERSIONS")
_RULE_DEPS = [
# START: maintained by 'bazel run //tools/private:update_pip_deps'
@@ -142,3 +143,25 @@ def pip_install_dependencies():
type = "zip",
build_file_content = _GENERIC_WHEEL,
)
+
+def uv_dependencies(tag = UV_VERSIONS.keys()[0]):
+ version = tag.lstrip("v")
+ url = "https://github.com/astral-sh/uv/releases/download/{tag}/uv-{plat}.{ext}"
+
+ for plat, sha256 in UV_VERSIONS[tag].items():
+ fetch_rule = http_archive
+ is_windows = plat.endswith("windows-msvc")
+
+ maybe(
+ http_archive,
+ name = "uv_" + plat,
+ url = url.format(
+ tag = tag,
+ plat = plat,
+ version = version,
+ ext = "zip" if is_windows else "tar.gz",
+ ),
+ sha256 = sha256,
+ strip_prefix = "uv-" + plat,
+ build_file_content = """exports_files(["uv", "uv.exe"])""",
+ )
diff --git a/python/pip_install/requirements.bzl b/python/pip_install/requirements.bzl
index 5caf762..1a80389 100644
--- a/python/pip_install/requirements.bzl
+++ b/python/pip_install/requirements.bzl
@@ -84,7 +84,11 @@ def compile_pip_requirements(
visibility = visibility,
)
- data = [name, requirements_txt, src] + [f for f in (requirements_linux, requirements_darwin, requirements_windows) if f != None]
+ data = [name, requirements_txt, src] + [f for f in (
+ requirements_linux,
+ requirements_darwin,
+ requirements_windows,
+ ) if f != None] + [Label("@//tools:uv")]
# Use the Label constructor so this is expanded in the context of the file
# where it appears, which is to say, in @rules_python
diff --git a/python/pip_install/tools/dependency_resolver/dependency_resolver.py b/python/pip_install/tools/dependency_resolver/dependency_resolver.py
index 5e914bc..4ae603a 100644
--- a/python/pip_install/tools/dependency_resolver/dependency_resolver.py
+++ b/python/pip_install/tools/dependency_resolver/dependency_resolver.py
@@ -17,6 +17,7 @@
import atexit
import os
import shutil
+import subprocess
import sys
from pathlib import Path
from typing import Optional, Tuple
@@ -79,6 +80,18 @@ def _locate(bazel_runfiles, file):
return bazel_runfiles.Rlocation(file)
+def _run_uv(uv, argv):
+ seen = set()
+ # Construct the command list while maintaining order, removing duplicates,
+ # and excluding "--allow-unsafe" arguments
+ cmd = [uv] + [arg for arg in argv if arg != "--allow-unsafe" and (arg not in seen and seen.add(arg) is None)]
+ print(" ".join(cmd), file=sys.stderr)
+ result = subprocess.run(cmd, capture_output=True, text=True)
+ print(result.stdout, file=sys.stderr)
+ print(result.stderr, file=sys.stderr)
+ raise SystemExit(result.returncode)
+
+
@click.command(context_settings={"ignore_unknown_options": True})
@click.argument("requirements_in")
@click.argument("requirements_txt")
@@ -157,6 +170,8 @@ def main(
os.environ["CUSTOM_COMPILE_COMMAND"] = update_command
os.environ["PIP_CONFIG_FILE"] = os.getenv("PIP_CONFIG_FILE") or os.devnull
+ argv.append("pip")
+ argv.append("compile")
argv.append(f"--output-file={requirements_file_relative if UPDATE else requirements_out}")
argv.append(
requirements_in_relative
@@ -165,6 +180,12 @@ def main(
)
argv.extend(extra_args)
+ plat = sys.platform
+ if plat == "linux":
+ uv = _locate(bazel_runfiles, "uv_x86_64-unknown-linux-gnu/uv")
+ elif plat == "darwin":
+ uv = _locate(bazel_runfiles, "uv_aarch64-apple-darwin/uv")
+
if UPDATE:
print("Updating " + requirements_file_relative)
if "BUILD_WORKSPACE_DIRECTORY" in os.environ:
@@ -179,7 +200,7 @@ def main(
resolved_requirements_file, requirements_file_tree
)
)
- cli(argv)
+ _run_uv(uv, argv)
requirements_file_relative_path = Path(requirements_file_relative)
content = requirements_file_relative_path.read_text()
content = content.replace(absolute_path_prefix, "")
@@ -188,7 +209,7 @@ def main(
# cli will exit(0) on success
try:
print("Checking " + requirements_file)
- cli(argv)
+ _run_uv(uv, argv)
print("cli() should exit", file=sys.stderr)
sys.exit(1)
except SystemExit as e:
diff --git a/python/pip_install/uv_versions.bzl b/python/pip_install/uv_versions.bzl
new file mode 100644
index 0000000..3d5e012
--- /dev/null
+++ b/python/pip_install/uv_versions.bzl
@@ -0,0 +1,20 @@
+"This file is automatically updated by mirror_uv.sh"
+UV_VERSIONS = {
+ "0.1.2": {
+ "aarch64-apple-darwin": "13289f543d96c2506f7c3319e8bbc5fb944c8109374b61188593567dc2dae454",
+ "aarch64-unknown-linux-gnu": "5d4a1e82e78080ba308a06ecc408b3f17a13077dd35174031ed37646a4c24bfd",
+ "aarch64-unknown-linux-musl": "c869e839347f2fd9e0302d25470659df99918ad8bdfad2477a61393a32d1a361",
+ "armv7-unknown-linux-gnueabihf": "67f6d19583bb24d628c6d3a97fd412a81b0f15f88491b6b244cda2832365d3a3",
+ "armv7-unknown-linux-musleabihf": "7acbfaef69adffb9591766c1e6b25b5750ddac8c43bded8b8b6301852b3bb436",
+ "i686-pc-windows-msvc": "7c923a8c0198da91094c96fe9bf9f737e09aa67f569b5c0f76b5f492b9394190",
+ "i686-unknown-linux-gnu": "d5462c8746aaf8f36ca43829c6bc71f8ad303bec83d9173f44e1a3ad36d83871",
+ "i686-unknown-linux-musl": "aa85ccbac61b7e8153dd7239f9757ca3a95fb01d0782949f554fd88a396edb29",
+ "powerpc64-unknown-linux-gnu": "4055b1ce30f7786fa49fcc9dd7eb3b818aa8903930fc49a42dd11ce99507f8d9",
+ "powerpc64le-unknown-linux-gnu": "d36b4d8c78ad8816a760f2d888d52c732b2eae5d62fc0830e6918a0732361c96",
+ "s390x-unknown-linux-gnu": "5829510eb1684d2f0f58ddab2e80313e5858d5e5be6e315b9b9a74c9742f6fac",
+ "x86_64-apple-darwin": "20777b7f904ec9cf7e4f7ee19fe8a0b64afada1a7168908c14557130768f46b7",
+ "x86_64-pc-windows-msvc": "35b7fdb10fad5e644125bfb3d7f5aff83d9aca24268701359e9fef767b8a4a15",
+ "x86_64-unknown-linux-gnu": "89624cd11aa20bc4a841bdcb110940ecb9f05555d79c3f8f4758e34d76c5c7ca",
+ "x86_64-unknown-linux-musl": "f69cbd79dfea3bd69c4db064565f9eaebb86db2c0ba0609c090be86366d5db42"
+ }
+}
# put this in tools/BUILD.bazel
alias(
name = "uv",
actual = select({
"@bazel_tools//src/conditions:linux_x86_64": "@uv_x86_64-unknown-linux-gnu//:uv",
"@bazel_tools//src/conditions:linux_aarch64": "@uv_aarch64-unknown-linux-gnu//:uv",
"@bazel_tools//src/conditions:darwin_arm64": "@uv_aarch64-apple-darwin//:uv",
"@bazel_tools//src/conditions:darwin_x86_64": "@uv_x86_64-apple-darwin//:uv",
}),
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment