mirror of https://github.com/astral-sh/uv
Compare commits
No commits in common. "main" and "0.9.14" have entirely different histories.
|
|
@ -1,81 +0,0 @@
|
||||||
# /// script
|
|
||||||
# requires-python = ">=3.12"
|
|
||||||
# dependencies = []
|
|
||||||
# ///
|
|
||||||
|
|
||||||
"""Post-edit hook to auto-format files after Claude edits."""
|
|
||||||
|
|
||||||
import json
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
|
|
||||||
def format_rust(file_path: str, cwd: str) -> None:
|
|
||||||
"""Format Rust files with cargo fmt."""
|
|
||||||
try:
|
|
||||||
subprocess.run(
|
|
||||||
["cargo", "fmt", "--", file_path],
|
|
||||||
cwd=cwd,
|
|
||||||
capture_output=True,
|
|
||||||
)
|
|
||||||
except FileNotFoundError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def format_python(file_path: str, cwd: str) -> None:
|
|
||||||
"""Format Python files with ruff."""
|
|
||||||
try:
|
|
||||||
subprocess.run(
|
|
||||||
["uvx", "ruff", "format", file_path],
|
|
||||||
cwd=cwd,
|
|
||||||
capture_output=True,
|
|
||||||
)
|
|
||||||
except FileNotFoundError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def format_prettier(file_path: str, cwd: str, prose_wrap: bool = False) -> None:
|
|
||||||
"""Format files with prettier."""
|
|
||||||
args = ["npx", "prettier", "--write"]
|
|
||||||
if prose_wrap:
|
|
||||||
args.extend(["--prose-wrap", "always"])
|
|
||||||
args.append(file_path)
|
|
||||||
try:
|
|
||||||
subprocess.run(args, cwd=cwd, capture_output=True)
|
|
||||||
except FileNotFoundError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
|
||||||
import os
|
|
||||||
|
|
||||||
input_data = json.load(sys.stdin)
|
|
||||||
|
|
||||||
tool_name = input_data.get("tool_name")
|
|
||||||
tool_input = input_data.get("tool_input", {})
|
|
||||||
file_path = tool_input.get("file_path")
|
|
||||||
|
|
||||||
# Only process Write, Edit, and MultiEdit tools
|
|
||||||
if tool_name not in ("Write", "Edit", "MultiEdit"):
|
|
||||||
return
|
|
||||||
|
|
||||||
if not file_path:
|
|
||||||
return
|
|
||||||
|
|
||||||
cwd = os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd())
|
|
||||||
path = Path(file_path)
|
|
||||||
ext = path.suffix
|
|
||||||
|
|
||||||
if ext == ".rs":
|
|
||||||
format_rust(file_path, cwd)
|
|
||||||
elif ext in (".py", ".pyi"):
|
|
||||||
format_python(file_path, cwd)
|
|
||||||
elif ext in (".json5", ".yaml", ".yml"):
|
|
||||||
format_prettier(file_path, cwd)
|
|
||||||
elif ext == ".md":
|
|
||||||
format_prettier(file_path, cwd, prose_wrap=True)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
{
|
|
||||||
"hooks": {
|
|
||||||
"PostToolUse": [
|
|
||||||
{
|
|
||||||
"matcher": "Edit|Write|MultiEdit",
|
|
||||||
"hooks": [
|
|
||||||
{
|
|
||||||
"type": "command",
|
|
||||||
"command": "uv run .claude/hooks/post-edit-format.py"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
dependencyDashboard: true,
|
dependencyDashboard: true,
|
||||||
suppressNotifications: ["prEditedNotification"],
|
suppressNotifications: ["prEditedNotification"],
|
||||||
extends: [
|
extends: [
|
||||||
"github>astral-sh/renovate-config",
|
"config:recommended",
|
||||||
// For tool versions defined in GitHub Actions:
|
// For tool versions defined in GitHub Actions:
|
||||||
"customManagers:githubActionsVersions",
|
"customManagers:githubActionsVersions",
|
||||||
],
|
],
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
schedule: ["* 0-3 * * 1"],
|
schedule: ["* 0-3 * * 1"],
|
||||||
semanticCommits: "disabled",
|
semanticCommits: "disabled",
|
||||||
separateMajorMinor: false,
|
separateMajorMinor: false,
|
||||||
|
prHourlyLimit: 10,
|
||||||
enabledManagers: ["github-actions", "pre-commit", "cargo", "custom.regex"],
|
enabledManagers: ["github-actions", "pre-commit", "cargo", "custom.regex"],
|
||||||
cargo: {
|
cargo: {
|
||||||
// See https://docs.renovatebot.com/configuration-options/#rangestrategy
|
// See https://docs.renovatebot.com/configuration-options/#rangestrategy
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ jobs:
|
||||||
|
|
||||||
macos-x86_64:
|
macos-x86_64:
|
||||||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }}
|
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }}
|
||||||
runs-on: depot-macos-14
|
runs-on: macos-14
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
|
|
@ -157,7 +157,7 @@ jobs:
|
||||||
|
|
||||||
macos-aarch64:
|
macos-aarch64:
|
||||||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }}
|
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }}
|
||||||
runs-on: depot-macos-14
|
runs-on: macos-14
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
|
|
@ -417,7 +417,7 @@ jobs:
|
||||||
|
|
||||||
linux-arm:
|
linux-arm:
|
||||||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }}
|
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }}
|
||||||
runs-on: depot-ubuntu-22.04-8
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
|
@ -956,7 +956,7 @@ jobs:
|
||||||
|
|
||||||
musllinux-cross:
|
musllinux-cross:
|
||||||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }}
|
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }}
|
||||||
runs-on: depot-ubuntu-22.04-8
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
platform:
|
platform:
|
||||||
|
|
|
||||||
|
|
@ -184,13 +184,13 @@ jobs:
|
||||||
- buildpack-deps:trixie,trixie,debian
|
- buildpack-deps:trixie,trixie,debian
|
||||||
- debian:bookworm-slim,bookworm-slim
|
- debian:bookworm-slim,bookworm-slim
|
||||||
- buildpack-deps:bookworm,bookworm
|
- buildpack-deps:bookworm,bookworm
|
||||||
- python:3.14-alpine3.23,python3.14-alpine3.23,python3.14-alpine
|
- python:3.14-alpine,python3.14-alpine
|
||||||
- python:3.13-alpine3.23,python3.13-alpine3.23,python3.13-alpine
|
- python:3.13-alpine,python3.13-alpine
|
||||||
- python:3.12-alpine3.23,python3.12-alpine3.23,python3.12-alpine
|
- python:3.12-alpine,python3.12-alpine
|
||||||
- python:3.11-alpine3.23,python3.11-alpine3.23,python3.11-alpine
|
- python:3.11-alpine,python3.11-alpine
|
||||||
- python:3.10-alpine3.23,python3.10-alpine3.23,python3.10-alpine
|
- python:3.10-alpine,python3.10-alpine
|
||||||
- python:3.9-alpine3.22,python3.9-alpine3.22,python3.9-alpine
|
- python:3.9-alpine,python3.9-alpine
|
||||||
- python:3.8-alpine3.20,python3.8-alpine3.20,python3.8-alpine
|
- python:3.8-alpine,python3.8-alpine
|
||||||
- python:3.14-trixie,python3.14-trixie
|
- python:3.14-trixie,python3.14-trixie
|
||||||
- python:3.13-trixie,python3.13-trixie
|
- python:3.13-trixie,python3.13-trixie
|
||||||
- python:3.12-trixie,python3.12-trixie
|
- python:3.12-trixie,python3.12-trixie
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,6 @@ jobs:
|
||||||
outputs:
|
outputs:
|
||||||
# Flag that is raised when any code is changed
|
# Flag that is raised when any code is changed
|
||||||
code: ${{ steps.changed.outputs.code_any_changed }}
|
code: ${{ steps.changed.outputs.code_any_changed }}
|
||||||
# Flag that is raised when uv.schema.json is changed (e.g., in a release PR)
|
|
||||||
schema: ${{ steps.changed.outputs.schema_changed }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
|
|
@ -42,16 +40,10 @@ jobs:
|
||||||
CHANGED_FILES=$(git diff --name-only ${{ github.event.pull_request.base.sha || 'origin/main' }}...HEAD)
|
CHANGED_FILES=$(git diff --name-only ${{ github.event.pull_request.base.sha || 'origin/main' }}...HEAD)
|
||||||
|
|
||||||
CODE_CHANGED=false
|
CODE_CHANGED=false
|
||||||
SCHEMA_CHANGED=false
|
|
||||||
|
|
||||||
while IFS= read -r file; do
|
while IFS= read -r file; do
|
||||||
# Check if the schema file changed (e.g., in a release PR)
|
# Generated markdown and JSON files are checked during test runs.
|
||||||
if [[ "${file}" == "uv.schema.json" ]]; then
|
if [[ "${file}" =~ ^docs/ && ! "${file}" =~ ^docs/reference/(cli|settings).md && ! "${file}" =~ ^docs/reference/environment.md ]]; then
|
||||||
echo "Detected schema change: ${file}"
|
|
||||||
SCHEMA_CHANGED=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "${file}" =~ ^docs/ ]]; then
|
|
||||||
echo "Skipping ${file} (matches docs/ pattern)"
|
echo "Skipping ${file} (matches docs/ pattern)"
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
@ -78,7 +70,6 @@ jobs:
|
||||||
|
|
||||||
done <<< "${CHANGED_FILES}"
|
done <<< "${CHANGED_FILES}"
|
||||||
echo "code_any_changed=${CODE_CHANGED}" >> "${GITHUB_OUTPUT}"
|
echo "code_any_changed=${CODE_CHANGED}" >> "${GITHUB_OUTPUT}"
|
||||||
echo "schema_changed=${SCHEMA_CHANGED}" >> "${GITHUB_OUTPUT}"
|
|
||||||
lint:
|
lint:
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
name: "lint"
|
name: "lint"
|
||||||
|
|
@ -144,7 +135,7 @@ jobs:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
||||||
with:
|
with:
|
||||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
||||||
- name: "Check uv_build dependencies"
|
- name: "Check uv_build dependencies"
|
||||||
|
|
@ -176,7 +167,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
Copy-Item -Path "${{ github.workspace }}" -Destination "$Env:UV_WORKSPACE" -Recurse
|
Copy-Item -Path "${{ github.workspace }}" -Destination "$Env:UV_WORKSPACE" -Recurse
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
||||||
with:
|
with:
|
||||||
workspaces: ${{ env.UV_WORKSPACE }}
|
workspaces: ${{ env.UV_WORKSPACE }}
|
||||||
|
|
||||||
|
|
@ -197,7 +188,7 @@ jobs:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
||||||
with:
|
with:
|
||||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
||||||
- name: "cargo publish dry-run"
|
- name: "cargo publish dry-run"
|
||||||
|
|
@ -213,16 +204,11 @@ jobs:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
||||||
with:
|
with:
|
||||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
||||||
- name: "Generate all"
|
- name: "Generate all"
|
||||||
run: cargo dev generate-all --mode dry-run
|
run: cargo dev generate-all --mode check
|
||||||
- name: "Check sysconfig mappings"
|
|
||||||
run: cargo dev generate-sysconfig-metadata --mode check
|
|
||||||
- name: "Check JSON schema"
|
|
||||||
if: ${{ needs.determine_changes.outputs.schema == 'true' }}
|
|
||||||
run: cargo dev generate-json-schema --mode check
|
|
||||||
|
|
||||||
cargo-shear:
|
cargo-shear:
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
|
|
@ -233,7 +219,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: "Install cargo shear"
|
- name: "Install cargo shear"
|
||||||
uses: taiki-e/install-action@d850aa816998e5cf15f67a78c7b933f2a5033f8a # v2.63.3
|
uses: taiki-e/install-action@a416ddeedbd372e614cc1386e8b642692f66865e # v2.57.1
|
||||||
with:
|
with:
|
||||||
tool: cargo-shear
|
tool: cargo-shear
|
||||||
- run: cargo shear
|
- run: cargo shear
|
||||||
|
|
@ -255,7 +241,7 @@ jobs:
|
||||||
|
|
||||||
- uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1
|
- uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
||||||
|
|
||||||
- name: "Install Rust toolchain"
|
- name: "Install Rust toolchain"
|
||||||
run: rustup show
|
run: rustup show
|
||||||
|
|
@ -289,13 +275,12 @@ jobs:
|
||||||
UV_HTTP_RETRIES: 5
|
UV_HTTP_RETRIES: 5
|
||||||
run: |
|
run: |
|
||||||
cargo nextest run \
|
cargo nextest run \
|
||||||
--cargo-profile fast-build \
|
|
||||||
--features python-patch,native-auth,secret-service \
|
--features python-patch,native-auth,secret-service \
|
||||||
--workspace \
|
--workspace \
|
||||||
--status-level skip --failure-output immediate-final --no-fail-fast -j 20 --final-status-level slow
|
--status-level skip --failure-output immediate-final --no-fail-fast -j 20 --final-status-level slow
|
||||||
|
|
||||||
cargo-test-macos:
|
cargo-test-macos:
|
||||||
timeout-minutes: 20
|
timeout-minutes: 15
|
||||||
needs: determine_changes
|
needs: determine_changes
|
||||||
# Only run macOS tests on main without opt-in
|
# Only run macOS tests on main without opt-in
|
||||||
if: ${{ contains(github.event.pull_request.labels.*.name, 'test:macos') || github.ref == 'refs/heads/main' }}
|
if: ${{ contains(github.event.pull_request.labels.*.name, 'test:macos') || github.ref == 'refs/heads/main' }}
|
||||||
|
|
@ -308,7 +293,7 @@ jobs:
|
||||||
|
|
||||||
- uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1
|
- uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
||||||
|
|
||||||
- name: "Install Rust toolchain"
|
- name: "Install Rust toolchain"
|
||||||
run: rustup show
|
run: rustup show
|
||||||
|
|
@ -331,9 +316,8 @@ jobs:
|
||||||
UV_HTTP_RETRIES: 5
|
UV_HTTP_RETRIES: 5
|
||||||
run: |
|
run: |
|
||||||
cargo nextest run \
|
cargo nextest run \
|
||||||
--cargo-profile fast-build \
|
|
||||||
--no-default-features \
|
--no-default-features \
|
||||||
--features python,python-managed,pypi,git,git-lfs,performance,crates-io,native-auth,apple-native \
|
--features python,python-managed,pypi,git,performance,crates-io,native-auth,apple-native \
|
||||||
--workspace \
|
--workspace \
|
||||||
--status-level skip --failure-output immediate-final --no-fail-fast -j 12 --final-status-level slow
|
--status-level skip --failure-output immediate-final --no-fail-fast -j 12 --final-status-level slow
|
||||||
|
|
||||||
|
|
@ -363,7 +347,7 @@ jobs:
|
||||||
- name: "Install required Python versions"
|
- name: "Install required Python versions"
|
||||||
run: uv python install
|
run: uv python install
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
||||||
with:
|
with:
|
||||||
workspaces: ${{ env.UV_WORKSPACE }}
|
workspaces: ${{ env.UV_WORKSPACE }}
|
||||||
|
|
||||||
|
|
@ -387,7 +371,6 @@ jobs:
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
cargo nextest run \
|
cargo nextest run \
|
||||||
--cargo-profile fast-build \
|
|
||||||
--no-default-features \
|
--no-default-features \
|
||||||
--features python,pypi,python-managed,native-auth,windows-native \
|
--features python,pypi,python-managed,native-auth,windows-native \
|
||||||
--workspace \
|
--workspace \
|
||||||
|
|
@ -417,7 +400,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
Copy-Item -Path "${{ github.workspace }}" -Destination "$Env:UV_WORKSPACE" -Recurse
|
Copy-Item -Path "${{ github.workspace }}" -Destination "$Env:UV_WORKSPACE" -Recurse
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
||||||
with:
|
with:
|
||||||
workspaces: ${{ env.UV_WORKSPACE }}/crates/uv-trampoline
|
workspaces: ${{ env.UV_WORKSPACE }}/crates/uv-trampoline
|
||||||
|
|
||||||
|
|
@ -477,7 +460,7 @@ jobs:
|
||||||
- name: Copy Git Repo to Dev Drive
|
- name: Copy Git Repo to Dev Drive
|
||||||
run: |
|
run: |
|
||||||
Copy-Item -Path "${{ github.workspace }}" -Destination "$Env:UV_WORKSPACE" -Recurse
|
Copy-Item -Path "${{ github.workspace }}" -Destination "$Env:UV_WORKSPACE" -Recurse
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
||||||
with:
|
with:
|
||||||
workspaces: ${{ env.UV_WORKSPACE }}/crates/uv-trampoline
|
workspaces: ${{ env.UV_WORKSPACE }}/crates/uv-trampoline
|
||||||
- name: "Install Rust toolchain"
|
- name: "Install Rust toolchain"
|
||||||
|
|
@ -495,8 +478,8 @@ jobs:
|
||||||
working-directory: ${{ env.UV_WORKSPACE }}/crates/uv-trampoline
|
working-directory: ${{ env.UV_WORKSPACE }}/crates/uv-trampoline
|
||||||
run: |
|
run: |
|
||||||
cargo build --target ${{ matrix.target-arch }}-pc-windows-msvc
|
cargo build --target ${{ matrix.target-arch }}-pc-windows-msvc
|
||||||
cp target/${{ matrix.target-arch }}-pc-windows-msvc/debug/uv-trampoline-console.exe ../uv-trampoline-builder/trampolines/uv-trampoline-${{ matrix.target-arch }}-console.exe
|
cp target/${{ matrix.target-arch }}-pc-windows-msvc/debug/uv-trampoline-console.exe trampolines/uv-trampoline-${{ matrix.target-arch }}-console.exe
|
||||||
cp target/${{ matrix.target-arch }}-pc-windows-msvc/debug/uv-trampoline-gui.exe ../uv-trampoline-builder/trampolines/uv-trampoline-${{ matrix.target-arch }}-gui.exe
|
cp target/${{ matrix.target-arch }}-pc-windows-msvc/debug/uv-trampoline-gui.exe trampolines/uv-trampoline-${{ matrix.target-arch }}-gui.exe
|
||||||
- name: "Test new binaries"
|
- name: "Test new binaries"
|
||||||
working-directory: ${{ env.UV_WORKSPACE }}
|
working-directory: ${{ env.UV_WORKSPACE }}
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -527,14 +510,6 @@ jobs:
|
||||||
version: "0.9.13"
|
version: "0.9.13"
|
||||||
|
|
||||||
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||||
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
|
||||||
with:
|
|
||||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
|
||||||
- name: "Generate reference documentation"
|
|
||||||
run: |
|
|
||||||
cargo dev generate-options-reference
|
|
||||||
cargo dev generate-cli-reference
|
|
||||||
cargo dev generate-env-vars-reference
|
|
||||||
- name: "Add SSH key"
|
- name: "Add SSH key"
|
||||||
if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS == 'true' }}
|
if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS == 'true' }}
|
||||||
uses: webfactory/ssh-agent@a6f90b1f127823b31d4d4a8d96047790581349bd # v0.9.1
|
uses: webfactory/ssh-agent@a6f90b1f127823b31d4d4a8d96047790581349bd # v0.9.1
|
||||||
|
|
@ -561,18 +536,18 @@ jobs:
|
||||||
|
|
||||||
- uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1
|
- uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
||||||
|
|
||||||
- name: "Build"
|
- name: "Build"
|
||||||
run: cargo build --profile no-debug
|
run: cargo build
|
||||||
|
|
||||||
- name: "Upload binary"
|
- name: "Upload binary"
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||||
with:
|
with:
|
||||||
name: uv-linux-libc-${{ github.sha }}
|
name: uv-linux-libc-${{ github.sha }}
|
||||||
path: |
|
path: |
|
||||||
./target/no-debug/uv
|
./target/debug/uv
|
||||||
./target/no-debug/uvx
|
./target/debug/uvx
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
build-binary-linux-aarch64:
|
build-binary-linux-aarch64:
|
||||||
|
|
@ -588,18 +563,18 @@ jobs:
|
||||||
|
|
||||||
- uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1
|
- uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
||||||
|
|
||||||
- name: "Build"
|
- name: "Build"
|
||||||
run: cargo build --profile no-debug
|
run: cargo build
|
||||||
|
|
||||||
- name: "Upload binary"
|
- name: "Upload binary"
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||||
with:
|
with:
|
||||||
name: uv-linux-aarch64-${{ github.sha }}
|
name: uv-linux-aarch64-${{ github.sha }}
|
||||||
path: |
|
path: |
|
||||||
./target/no-debug/uv
|
./target/debug/uv
|
||||||
./target/no-debug/uvx
|
./target/debug/uvx
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
build-binary-linux-musl:
|
build-binary-linux-musl:
|
||||||
|
|
@ -620,18 +595,18 @@ jobs:
|
||||||
sudo apt-get install musl-tools
|
sudo apt-get install musl-tools
|
||||||
rustup target add x86_64-unknown-linux-musl
|
rustup target add x86_64-unknown-linux-musl
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
||||||
|
|
||||||
- name: "Build"
|
- name: "Build"
|
||||||
run: cargo build --profile no-debug --target x86_64-unknown-linux-musl --bin uv --bin uvx
|
run: cargo build --target x86_64-unknown-linux-musl --bin uv --bin uvx
|
||||||
|
|
||||||
- name: "Upload binary"
|
- name: "Upload binary"
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||||
with:
|
with:
|
||||||
name: uv-linux-musl-${{ github.sha }}
|
name: uv-linux-musl-${{ github.sha }}
|
||||||
path: |
|
path: |
|
||||||
./target/x86_64-unknown-linux-musl/no-debug/uv
|
./target/x86_64-unknown-linux-musl/debug/uv
|
||||||
./target/x86_64-unknown-linux-musl/no-debug/uvx
|
./target/x86_64-unknown-linux-musl/debug/uvx
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
build-binary-macos-aarch64:
|
build-binary-macos-aarch64:
|
||||||
|
|
@ -647,17 +622,17 @@ jobs:
|
||||||
|
|
||||||
- uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1
|
- uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
||||||
- name: "Build"
|
- name: "Build"
|
||||||
run: cargo build --profile no-debug --bin uv --bin uvx
|
run: cargo build --bin uv --bin uvx
|
||||||
|
|
||||||
- name: "Upload binary"
|
- name: "Upload binary"
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||||
with:
|
with:
|
||||||
name: uv-macos-aarch64-${{ github.sha }}
|
name: uv-macos-aarch64-${{ github.sha }}
|
||||||
path: |
|
path: |
|
||||||
./target/no-debug/uv
|
./target/debug/uv
|
||||||
./target/no-debug/uvx
|
./target/debug/uvx
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
build-binary-macos-x86_64:
|
build-binary-macos-x86_64:
|
||||||
|
|
@ -673,17 +648,17 @@ jobs:
|
||||||
|
|
||||||
- uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1
|
- uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
||||||
- name: "Build"
|
- name: "Build"
|
||||||
run: cargo build --profile no-debug --bin uv --bin uvx
|
run: cargo build --bin uv --bin uvx
|
||||||
|
|
||||||
- name: "Upload binary"
|
- name: "Upload binary"
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||||
with:
|
with:
|
||||||
name: uv-macos-x86_64-${{ github.sha }}
|
name: uv-macos-x86_64-${{ github.sha }}
|
||||||
path: |
|
path: |
|
||||||
./target/no-debug/uv
|
./target/debug/uv
|
||||||
./target/no-debug/uvx
|
./target/debug/uvx
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
build-binary-windows-x86_64:
|
build-binary-windows-x86_64:
|
||||||
|
|
@ -705,21 +680,21 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
Copy-Item -Path "${{ github.workspace }}" -Destination "$Env:UV_WORKSPACE" -Recurse
|
Copy-Item -Path "${{ github.workspace }}" -Destination "$Env:UV_WORKSPACE" -Recurse
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
||||||
with:
|
with:
|
||||||
workspaces: ${{ env.UV_WORKSPACE }}
|
workspaces: ${{ env.UV_WORKSPACE }}
|
||||||
|
|
||||||
- name: "Build"
|
- name: "Build"
|
||||||
working-directory: ${{ env.UV_WORKSPACE }}
|
working-directory: ${{ env.UV_WORKSPACE }}
|
||||||
run: cargo build --profile no-debug --bin uv --bin uvx
|
run: cargo build --bin uv --bin uvx
|
||||||
|
|
||||||
- name: "Upload binary"
|
- name: "Upload binary"
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||||
with:
|
with:
|
||||||
name: uv-windows-x86_64-${{ github.sha }}
|
name: uv-windows-x86_64-${{ github.sha }}
|
||||||
path: |
|
path: |
|
||||||
${{ env.UV_WORKSPACE }}/target/no-debug/uv.exe
|
${{ env.UV_WORKSPACE }}/target/debug/uv.exe
|
||||||
${{ env.UV_WORKSPACE }}/target/no-debug/uvx.exe
|
${{ env.UV_WORKSPACE }}/target/debug/uvx.exe
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
build-binary-windows-aarch64:
|
build-binary-windows-aarch64:
|
||||||
|
|
@ -742,7 +717,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
Copy-Item -Path "${{ github.workspace }}" -Destination "$Env:UV_WORKSPACE" -Recurse
|
Copy-Item -Path "${{ github.workspace }}" -Destination "$Env:UV_WORKSPACE" -Recurse
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
||||||
with:
|
with:
|
||||||
workspaces: ${{ env.UV_WORKSPACE }}
|
workspaces: ${{ env.UV_WORKSPACE }}
|
||||||
|
|
||||||
|
|
@ -751,15 +726,15 @@ jobs:
|
||||||
|
|
||||||
- name: "Build"
|
- name: "Build"
|
||||||
working-directory: ${{ env.UV_WORKSPACE }}
|
working-directory: ${{ env.UV_WORKSPACE }}
|
||||||
run: cargo build --profile no-debug --target aarch64-pc-windows-msvc
|
run: cargo build --target aarch64-pc-windows-msvc
|
||||||
|
|
||||||
- name: "Upload binary"
|
- name: "Upload binary"
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||||
with:
|
with:
|
||||||
name: uv-windows-aarch64-${{ github.sha }}
|
name: uv-windows-aarch64-${{ github.sha }}
|
||||||
path: |
|
path: |
|
||||||
${{ env.UV_WORKSPACE }}/target/aarch64-pc-windows-msvc/no-debug/uv.exe
|
${{ env.UV_WORKSPACE }}/target/aarch64-pc-windows-msvc/debug/uv.exe
|
||||||
${{ env.UV_WORKSPACE }}/target/aarch64-pc-windows-msvc/no-debug/uvx.exe
|
${{ env.UV_WORKSPACE }}/target/aarch64-pc-windows-msvc/debug/uvx.exe
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
build-binary-msrv:
|
build-binary-msrv:
|
||||||
|
|
@ -783,11 +758,11 @@ jobs:
|
||||||
MSRV: ${{ steps.msrv.outputs.value }}
|
MSRV: ${{ steps.msrv.outputs.value }}
|
||||||
- name: "Install mold"
|
- name: "Install mold"
|
||||||
uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1
|
uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
||||||
- run: cargo +${MSRV} build --profile no-debug
|
- run: cargo +${MSRV} build
|
||||||
env:
|
env:
|
||||||
MSRV: ${{ steps.msrv.outputs.value }}
|
MSRV: ${{ steps.msrv.outputs.value }}
|
||||||
- run: ./target/no-debug/uv --version
|
- run: ./target/debug/uv --version
|
||||||
|
|
||||||
build-binary-freebsd:
|
build-binary-freebsd:
|
||||||
needs: determine_changes
|
needs: determine_changes
|
||||||
|
|
@ -800,7 +775,7 @@ jobs:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
||||||
- name: "Cross build"
|
- name: "Cross build"
|
||||||
run: |
|
run: |
|
||||||
# Install cross from `freebsd-firecracker`
|
# Install cross from `freebsd-firecracker`
|
||||||
|
|
@ -808,7 +783,7 @@ jobs:
|
||||||
chmod +x cross
|
chmod +x cross
|
||||||
mv cross /usr/local/bin/cross
|
mv cross /usr/local/bin/cross
|
||||||
|
|
||||||
cross build --target x86_64-unknown-freebsd --profile no-debug
|
cross build --target x86_64-unknown-freebsd
|
||||||
|
|
||||||
- name: Test in Firecracker VM
|
- name: Test in Firecracker VM
|
||||||
uses: acj/freebsd-firecracker-action@a5a3fc1709c5b5368141a5699f10259aca3cd965 # v0.6.0
|
uses: acj/freebsd-firecracker-action@a5a3fc1709c5b5368141a5699f10259aca3cd965 # v0.6.0
|
||||||
|
|
@ -822,8 +797,8 @@ jobs:
|
||||||
cat <<EOF > $include_path
|
cat <<EOF > $include_path
|
||||||
target
|
target
|
||||||
target/x86_64-unknown-freebsd
|
target/x86_64-unknown-freebsd
|
||||||
target/x86_64-unknown-freebsd/no-debug
|
target/x86_64-unknown-freebsd/debug
|
||||||
target/x86_64-unknown-freebsd/no-debug/uv
|
target/x86_64-unknown-freebsd/debug/uv
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
rsync -r -e "ssh" \
|
rsync -r -e "ssh" \
|
||||||
|
|
@ -833,7 +808,7 @@ jobs:
|
||||||
--exclude "*" \
|
--exclude "*" \
|
||||||
. firecracker:
|
. firecracker:
|
||||||
run-in-vm: |
|
run-in-vm: |
|
||||||
mv target/x86_64-unknown-freebsd/no-debug/uv uv
|
mv target/x86_64-unknown-freebsd/debug/uv uv
|
||||||
chmod +x uv
|
chmod +x uv
|
||||||
./uv --version
|
./uv --version
|
||||||
|
|
||||||
|
|
@ -2067,22 +2042,22 @@ jobs:
|
||||||
|
|
||||||
# Test the main path (`build_wheel`) through pip
|
# Test the main path (`build_wheel`) through pip
|
||||||
./uv venv -v --seed
|
./uv venv -v --seed
|
||||||
./uv run --no-project python -m pip install -v test/packages/built-by-uv --find-links crates/uv-build/dist --no-index --no-deps
|
./uv run --no-project python -m pip install -v scripts/packages/built-by-uv --find-links crates/uv-build/dist --no-index --no-deps
|
||||||
./uv run --no-project python -c "from built_by_uv import greet; print(greet())"
|
./uv run --no-project python -c "from built_by_uv import greet; print(greet())"
|
||||||
|
|
||||||
# Test both `build_wheel` and `build_sdist` through uv
|
# Test both `build_wheel` and `build_sdist` through uv
|
||||||
./uv venv -c -v
|
./uv venv -c -v
|
||||||
./uv build -v --force-pep517 test/packages/built-by-uv --find-links crates/uv-build/dist --offline
|
./uv build -v --force-pep517 scripts/packages/built-by-uv --find-links crates/uv-build/dist --offline
|
||||||
./uv pip install -v test/packages/built-by-uv/dist/*.tar.gz --find-links crates/uv-build/dist --offline --no-deps
|
./uv pip install -v scripts/packages/built-by-uv/dist/*.tar.gz --find-links crates/uv-build/dist --offline --no-deps
|
||||||
./uv run --no-project python -c "from built_by_uv import greet; print(greet())"
|
./uv run --no-project python -c "from built_by_uv import greet; print(greet())"
|
||||||
|
|
||||||
# Test both `build_wheel` and `build_sdist` through the official `build`
|
# Test both `build_wheel` and `build_sdist` through the official `build`
|
||||||
rm -rf test/packages/built-by-uv/dist/
|
rm -rf scripts/packages/built-by-uv/dist/
|
||||||
./uv venv -c -v
|
./uv venv -c -v
|
||||||
./uv pip install build
|
./uv pip install build
|
||||||
# Add the uv binary to PATH for `build` to find
|
# Add the uv binary to PATH for `build` to find
|
||||||
PATH="$(pwd):$PATH" UV_OFFLINE=1 UV_FIND_LINKS=crates/uv-build/dist ./uv run --no-project python -m build -v --installer uv test/packages/built-by-uv
|
PATH="$(pwd):$PATH" UV_OFFLINE=1 UV_FIND_LINKS=crates/uv-build/dist ./uv run --no-project python -m build -v --installer uv scripts/packages/built-by-uv
|
||||||
./uv pip install -v test/packages/built-by-uv/dist/*.tar.gz --find-links crates/uv-build/dist --offline --no-deps
|
./uv pip install -v scripts/packages/built-by-uv/dist/*.tar.gz --find-links crates/uv-build/dist --offline --no-deps
|
||||||
./uv run --no-project python -c "from built_by_uv import greet; print(greet())"
|
./uv run --no-project python -c "from built_by_uv import greet; print(greet())"
|
||||||
|
|
||||||
cache-test-ubuntu:
|
cache-test-ubuntu:
|
||||||
|
|
@ -2931,7 +2906,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
||||||
|
|
||||||
- name: "Install Rust toolchain"
|
- name: "Install Rust toolchain"
|
||||||
run: rustup show
|
run: rustup show
|
||||||
|
|
@ -2946,8 +2921,8 @@ jobs:
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y libsasl2-dev libldap2-dev libkrb5-dev
|
sudo apt-get install -y libsasl2-dev libldap2-dev libkrb5-dev
|
||||||
cargo run --bin uv -- venv --cache-dir .cache
|
cargo run --bin uv -- venv --cache-dir .cache
|
||||||
cargo run --bin uv -- pip compile test/requirements/jupyter.in --universal --exclude-newer 2024-08-08 --cache-dir .cache
|
cargo run --bin uv -- pip compile scripts/requirements/jupyter.in --universal --exclude-newer 2024-08-08 --cache-dir .cache
|
||||||
cargo run --bin uv -- pip compile test/requirements/airflow.in --universal --exclude-newer 2024-08-08 --cache-dir .cache
|
cargo run --bin uv -- pip compile scripts/requirements/airflow.in --universal --exclude-newer 2024-08-08 --cache-dir .cache
|
||||||
|
|
||||||
- name: "Build benchmarks"
|
- name: "Build benchmarks"
|
||||||
run: cargo codspeed build --profile profiling -p uv-bench
|
run: cargo codspeed build --profile profiling -p uv-bench
|
||||||
|
|
@ -2971,7 +2946,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
||||||
|
|
||||||
- name: "Install Rust toolchain"
|
- name: "Install Rust toolchain"
|
||||||
run: rustup show
|
run: rustup show
|
||||||
|
|
@ -2986,8 +2961,8 @@ jobs:
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y libsasl2-dev libldap2-dev libkrb5-dev
|
sudo apt-get install -y libsasl2-dev libldap2-dev libkrb5-dev
|
||||||
cargo run --bin uv -- venv --cache-dir .cache
|
cargo run --bin uv -- venv --cache-dir .cache
|
||||||
cargo run --bin uv -- pip compile test/requirements/jupyter.in --universal --exclude-newer 2024-08-08 --cache-dir .cache
|
cargo run --bin uv -- pip compile scripts/requirements/jupyter.in --universal --exclude-newer 2024-08-08 --cache-dir .cache
|
||||||
cargo run --bin uv -- pip compile test/requirements/airflow.in --universal --exclude-newer 2024-08-08 --cache-dir .cache
|
cargo run --bin uv -- pip compile scripts/requirements/airflow.in --universal --exclude-newer 2024-08-08 --cache-dir .cache
|
||||||
|
|
||||||
- name: "Build benchmarks"
|
- name: "Build benchmarks"
|
||||||
run: cargo codspeed build --profile profiling -p uv-bench
|
run: cargo codspeed build --profile profiling -p uv-bench
|
||||||
|
|
|
||||||
|
|
@ -36,14 +36,6 @@ jobs:
|
||||||
with:
|
with:
|
||||||
python-version: 3.12
|
python-version: 3.12
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
|
|
||||||
|
|
||||||
- name: "Generate reference documentation"
|
|
||||||
run: |
|
|
||||||
cargo dev generate-options-reference
|
|
||||||
cargo dev generate-cli-reference
|
|
||||||
cargo dev generate-env-vars-reference
|
|
||||||
|
|
||||||
- name: "Set docs display name"
|
- name: "Set docs display name"
|
||||||
run: |
|
run: |
|
||||||
version="${VERSION}"
|
version="${VERSION}"
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ jobs:
|
||||||
environment:
|
environment:
|
||||||
name: release
|
name: release
|
||||||
permissions:
|
permissions:
|
||||||
id-token: write # For PyPI's trusted publishing
|
# For PyPI's trusted publishing.
|
||||||
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- name: "Install uv"
|
- name: "Install uv"
|
||||||
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
|
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
|
||||||
|
|
@ -36,7 +37,8 @@ jobs:
|
||||||
environment:
|
environment:
|
||||||
name: release
|
name: release
|
||||||
permissions:
|
permissions:
|
||||||
id-token: write # For PyPI's trusted publishing
|
# For PyPI's trusted publishing.
|
||||||
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- name: "Install uv"
|
- name: "Install uv"
|
||||||
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
|
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,6 @@ jobs:
|
||||||
needs:
|
needs:
|
||||||
- plan
|
- plan
|
||||||
- host
|
- host
|
||||||
- custom-publish-pypi # DIRTY: see #16989
|
|
||||||
if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }}
|
if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }}
|
||||||
uses: ./.github/workflows/publish-crates.yml
|
uses: ./.github/workflows/publish-crates.yml
|
||||||
with:
|
with:
|
||||||
|
|
|
||||||
|
|
@ -37,11 +37,6 @@ profile.json.gz
|
||||||
# MkDocs
|
# MkDocs
|
||||||
/site
|
/site
|
||||||
|
|
||||||
# Generated reference docs (use `cargo dev generate-all` to regenerate)
|
|
||||||
/docs/reference/cli.md
|
|
||||||
/docs/reference/environment.md
|
|
||||||
/docs/reference/settings.md
|
|
||||||
|
|
||||||
# macOS
|
# macOS
|
||||||
**/.DS_Store
|
**/.DS_Store
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,5 +4,5 @@ PREVIEW-CHANGELOG.md
|
||||||
docs/reference/cli.md
|
docs/reference/cli.md
|
||||||
docs/reference/settings.md
|
docs/reference/settings.md
|
||||||
docs/reference/environment.md
|
docs/reference/environment.md
|
||||||
test/ecosystem/home-assistant-core/LICENSE.md
|
ecosystem/home-assistant-core/LICENSE.md
|
||||||
docs/guides/integration/gitlab.md
|
docs/guides/integration/gitlab.md
|
||||||
|
|
|
||||||
135
CHANGELOG.md
135
CHANGELOG.md
|
|
@ -3,139 +3,6 @@
|
||||||
<!-- prettier-ignore-start -->
|
<!-- prettier-ignore-start -->
|
||||||
|
|
||||||
|
|
||||||
## 0.9.18
|
|
||||||
|
|
||||||
Released on 2025-12-16.
|
|
||||||
|
|
||||||
### Enhancements
|
|
||||||
|
|
||||||
- Add value hints to command line arguments to improve shell completion accuracy ([#17080](https://github.com/astral-sh/uv/pull/17080))
|
|
||||||
- Improve error handling in `uv publish` ([#17096](https://github.com/astral-sh/uv/pull/17096))
|
|
||||||
- Improve rendering of multiline error messages ([#17132](https://github.com/astral-sh/uv/pull/17132))
|
|
||||||
- Support redirects in `uv publish` ([#17130](https://github.com/astral-sh/uv/pull/17130))
|
|
||||||
- Include Docker images with the alpine version, e.g., `python3.x-alpine3.23` ([#17100](https://github.com/astral-sh/uv/pull/17100))
|
|
||||||
|
|
||||||
### Configuration
|
|
||||||
|
|
||||||
- Accept `--torch-backend` in `[tool.uv]` ([#17116](https://github.com/astral-sh/uv/pull/17116))
|
|
||||||
|
|
||||||
### Performance
|
|
||||||
|
|
||||||
- Speed up `uv cache size` ([#17015](https://github.com/astral-sh/uv/pull/17015))
|
|
||||||
- Initialize S3 signer once ([#17092](https://github.com/astral-sh/uv/pull/17092))
|
|
||||||
|
|
||||||
### Bug fixes
|
|
||||||
|
|
||||||
- Avoid panics due to reads on failed requests ([#17098](https://github.com/astral-sh/uv/pull/17098))
|
|
||||||
- Enforce latest-version in `@latest` requests ([#17114](https://github.com/astral-sh/uv/pull/17114))
|
|
||||||
- Explicitly set `EntryType` for file entries in tar ([#17043](https://github.com/astral-sh/uv/pull/17043))
|
|
||||||
- Ignore `pyproject.toml` index username in lockfile comparison ([#16995](https://github.com/astral-sh/uv/pull/16995))
|
|
||||||
- Relax error when using `uv add` with `UV_GIT_LFS` set ([#17127](https://github.com/astral-sh/uv/pull/17127))
|
|
||||||
- Support file locks on ExFAT on macOS ([#17115](https://github.com/astral-sh/uv/pull/17115))
|
|
||||||
- Change schema for `exclude-newer` into optional string ([#17121](https://github.com/astral-sh/uv/pull/17121))
|
|
||||||
|
|
||||||
### Documentation
|
|
||||||
|
|
||||||
- Drop arm musl caveat from Docker documentation ([#17111](https://github.com/astral-sh/uv/pull/17111))
|
|
||||||
- Fix version reference in resolver example ([#17085](https://github.com/astral-sh/uv/pull/17085))
|
|
||||||
- Better documentation for `exclude-newer*` ([#17079](https://github.com/astral-sh/uv/pull/17079))
|
|
||||||
|
|
||||||
## 0.9.17
|
|
||||||
|
|
||||||
Released on 2025-12-09.
|
|
||||||
|
|
||||||
### Enhancements
|
|
||||||
|
|
||||||
- Add `torch-tensorrt` and `torchao` to the PyTorch list ([#17053](https://github.com/astral-sh/uv/pull/17053))
|
|
||||||
- Add hint for misplaced `--verbose` in `uv tool run` ([#17020](https://github.com/astral-sh/uv/pull/17020))
|
|
||||||
- Add support for relative durations in `exclude-newer` (a.k.a., dependency cooldowns) ([#16814](https://github.com/astral-sh/uv/pull/16814))
|
|
||||||
- Add support for relocatable nushell activation script ([#17036](https://github.com/astral-sh/uv/pull/17036))
|
|
||||||
|
|
||||||
### Bug fixes
|
|
||||||
|
|
||||||
- Respect dropped (but explicit) indexes in dependency groups ([#17012](https://github.com/astral-sh/uv/pull/17012))
|
|
||||||
|
|
||||||
### Documentation
|
|
||||||
|
|
||||||
- Improve `source-exclude` reference docs ([#16832](https://github.com/astral-sh/uv/pull/16832))
|
|
||||||
- Recommend `UV_NO_DEV` in Docker installs ([#17030](https://github.com/astral-sh/uv/pull/17030))
|
|
||||||
- Update `UV_VERSION` in docs for GitLab CI/CD ([#17040](https://github.com/astral-sh/uv/pull/17040))
|
|
||||||
|
|
||||||
## 0.9.16
|
|
||||||
|
|
||||||
Released on 2025-12-06.
|
|
||||||
|
|
||||||
### Python
|
|
||||||
|
|
||||||
- Add CPython 3.14.2
|
|
||||||
- Add CPython 3.13.11
|
|
||||||
|
|
||||||
### Enhancements
|
|
||||||
|
|
||||||
- Add a 5m default timeout to acquiring file locks to fail faster on deadlock ([#16342](https://github.com/astral-sh/uv/pull/16342))
|
|
||||||
- Add a stub `debug` subcommand to `uv pip` announcing its intentional absence ([#16966](https://github.com/astral-sh/uv/pull/16966))
|
|
||||||
- Add bounds in `uv add --script` ([#16954](https://github.com/astral-sh/uv/pull/16954))
|
|
||||||
- Add brew specific message for `uv self update` ([#16838](https://github.com/astral-sh/uv/pull/16838))
|
|
||||||
- Error when built wheel is for the wrong platform ([#16074](https://github.com/astral-sh/uv/pull/16074))
|
|
||||||
- Filter wheels from PEP 751 files based on `--no-binary` et al in `uv pip compile` ([#16956](https://github.com/astral-sh/uv/pull/16956))
|
|
||||||
- Support `--target` and `--prefix` in `uv pip list`, `uv pip freeze`, and `uv pip show` ([#16955](https://github.com/astral-sh/uv/pull/16955))
|
|
||||||
- Tweak language for build backend validation errors ([#16720](https://github.com/astral-sh/uv/pull/16720))
|
|
||||||
- Use explicit credentials cache instead of global static ([#16768](https://github.com/astral-sh/uv/pull/16768))
|
|
||||||
- Enable SIMD in HTML parsing ([#17010](https://github.com/astral-sh/uv/pull/17010))
|
|
||||||
|
|
||||||
### Preview features
|
|
||||||
|
|
||||||
- Fix missing preview warning in `uv workspace metadata` ([#16988](https://github.com/astral-sh/uv/pull/16988))
|
|
||||||
- Add a `uv auth helper --protocol bazel` command ([#16886](https://github.com/astral-sh/uv/pull/16886))
|
|
||||||
|
|
||||||
### Bug fixes
|
|
||||||
|
|
||||||
- Fix Pyston wheel compatibility tags ([#16972](https://github.com/astral-sh/uv/pull/16972))
|
|
||||||
- Allow redundant entries in `tool.uv.build-backend.module-name` but emit warnings ([#16928](https://github.com/astral-sh/uv/pull/16928))
|
|
||||||
- Fix infinite loop in non-attribute re-treats during HTML parsing ([#17010](https://github.com/astral-sh/uv/pull/17010))
|
|
||||||
|
|
||||||
### Documentation
|
|
||||||
|
|
||||||
- Clarify `--project` flag help text to indicate project discovery ([#16965](https://github.com/astral-sh/uv/pull/16965))
|
|
||||||
- Regenerate the crates.io READMEs on release ([#16992](https://github.com/astral-sh/uv/pull/16992))
|
|
||||||
- Update Docker integration guide to prefer `COPY` over `ADD` for simple cases ([#16883](https://github.com/astral-sh/uv/pull/16883))
|
|
||||||
- Update PyTorch documentation to include information about supporting CUDA 13.0.x ([#16957](https://github.com/astral-sh/uv/pull/16957))
|
|
||||||
- Update the versioning policy ([#16710](https://github.com/astral-sh/uv/pull/16710))
|
|
||||||
- Upgrade PyTorch documentation to latest versions ([#16970](https://github.com/astral-sh/uv/pull/16970))
|
|
||||||
|
|
||||||
## 0.9.15
|
|
||||||
|
|
||||||
Released on 2025-12-02.
|
|
||||||
|
|
||||||
### Python
|
|
||||||
|
|
||||||
- Add CPython 3.14.1
|
|
||||||
- Add CPython 3.13.10
|
|
||||||
|
|
||||||
### Enhancements
|
|
||||||
|
|
||||||
- Add ROCm 6.4 to `--torch-backend=auto` ([#16919](https://github.com/astral-sh/uv/pull/16919))
|
|
||||||
- Add a Windows manifest to uv binaries ([#16894](https://github.com/astral-sh/uv/pull/16894))
|
|
||||||
- Add LFS toggle to Git sources ([#16143](https://github.com/astral-sh/uv/pull/16143))
|
|
||||||
- Cache source reads during resolution ([#16888](https://github.com/astral-sh/uv/pull/16888))
|
|
||||||
- Allow reading requirements from scripts without an extension ([#16923](https://github.com/astral-sh/uv/pull/16923))
|
|
||||||
- Allow reading requirements from scripts with HTTP(S) paths ([#16891](https://github.com/astral-sh/uv/pull/16891))
|
|
||||||
|
|
||||||
### Configuration
|
|
||||||
|
|
||||||
- Add `UV_HIDE_BUILD_OUTPUT` to omit build logs ([#16885](https://github.com/astral-sh/uv/pull/16885))
|
|
||||||
|
|
||||||
### Bug fixes
|
|
||||||
|
|
||||||
- Fix `uv-trampoline-builder` builds from crates.io by moving bundled executables ([#16922](https://github.com/astral-sh/uv/pull/16922))
|
|
||||||
- Respect `NO_COLOR` and always show the command as a header when paging `uv help` output ([#16908](https://github.com/astral-sh/uv/pull/16908))
|
|
||||||
- Use `0o666` permissions for flock files instead of `0o777` ([#16845](https://github.com/astral-sh/uv/pull/16845))
|
|
||||||
- Revert "Bump `astral-tl` to v0.7.10 (#16887)" to narrow down a regression causing hangs in metadata retrieval ([#16938](https://github.com/astral-sh/uv/pull/16938))
|
|
||||||
|
|
||||||
### Documentation
|
|
||||||
|
|
||||||
- Link to the uv version in crates.io member READMEs ([#16939](https://github.com/astral-sh/uv/pull/16939))
|
|
||||||
|
|
||||||
## 0.9.14
|
## 0.9.14
|
||||||
|
|
||||||
Released on 2025-12-01.
|
Released on 2025-12-01.
|
||||||
|
|
@ -577,5 +444,3 @@ See [changelogs/0.2.x](./changelogs/0.2.x.md)
|
||||||
See [changelogs/0.1.x](./changelogs/0.1.x.md)
|
See [changelogs/0.1.x](./changelogs/0.1.x.md)
|
||||||
|
|
||||||
<!-- prettier-ignore-end -->
|
<!-- prettier-ignore-end -->
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,125 +0,0 @@
|
||||||
# Contributor Covenant Code of Conduct
|
|
||||||
|
|
||||||
- [Our Pledge](#our-pledge)
|
|
||||||
- [Our Standards](#our-standards)
|
|
||||||
- [Enforcement Responsibilities](#enforcement-responsibilities)
|
|
||||||
- [Scope](#scope)
|
|
||||||
- [Enforcement](#enforcement)
|
|
||||||
- [Enforcement Guidelines](#enforcement-guidelines)
|
|
||||||
- [1. Correction](#1-correction)
|
|
||||||
- [2. Warning](#2-warning)
|
|
||||||
- [3. Temporary Ban](#3-temporary-ban)
|
|
||||||
- [4. Permanent Ban](#4-permanent-ban)
|
|
||||||
- [Attribution](#attribution)
|
|
||||||
|
|
||||||
## Our Pledge
|
|
||||||
|
|
||||||
We as members, contributors, and leaders pledge to make participation in our community a
|
|
||||||
harassment-free experience for everyone, regardless of age, body size, visible or invisible
|
|
||||||
disability, ethnicity, sex characteristics, gender identity and expression, level of experience,
|
|
||||||
education, socio-economic status, nationality, personal appearance, race, religion, or sexual
|
|
||||||
identity and orientation.
|
|
||||||
|
|
||||||
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and
|
|
||||||
healthy community.
|
|
||||||
|
|
||||||
## Our Standards
|
|
||||||
|
|
||||||
Examples of behavior that contributes to a positive environment for our community include:
|
|
||||||
|
|
||||||
- Demonstrating empathy and kindness toward other people
|
|
||||||
- Being respectful of differing opinions, viewpoints, and experiences
|
|
||||||
- Giving and gracefully accepting constructive feedback
|
|
||||||
- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the
|
|
||||||
experience
|
|
||||||
- Focusing on what is best not just for us as individuals, but for the overall community
|
|
||||||
|
|
||||||
Examples of unacceptable behavior include:
|
|
||||||
|
|
||||||
- The use of sexualized language or imagery, and sexual attention or advances of any kind
|
|
||||||
- Trolling, insulting or derogatory comments, and personal or political attacks
|
|
||||||
- Public or private harassment
|
|
||||||
- Publishing others' private information, such as a physical or email address, without their
|
|
||||||
explicit permission
|
|
||||||
- Other conduct which could reasonably be considered inappropriate in a professional setting
|
|
||||||
|
|
||||||
## Enforcement Responsibilities
|
|
||||||
|
|
||||||
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior
|
|
||||||
and will take appropriate and fair corrective action in response to any behavior that they deem
|
|
||||||
inappropriate, threatening, offensive, or harmful.
|
|
||||||
|
|
||||||
Community leaders have the right and responsibility to remove, edit, or reject comments, commits,
|
|
||||||
code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and
|
|
||||||
will communicate reasons for moderation decisions when appropriate.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
This Code of Conduct applies within all community spaces, and also applies when an individual is
|
|
||||||
officially representing the community in public spaces. Examples of representing our community
|
|
||||||
include using an official e-mail address, posting via an official social media account, or acting as
|
|
||||||
an appointed representative at an online or offline event.
|
|
||||||
|
|
||||||
## Enforcement
|
|
||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community
|
|
||||||
leaders responsible for enforcement at <hey@astral.sh>. All complaints will be reviewed and
|
|
||||||
investigated promptly and fairly.
|
|
||||||
|
|
||||||
All community leaders are obligated to respect the privacy and security of the reporter of any
|
|
||||||
incident.
|
|
||||||
|
|
||||||
## Enforcement Guidelines
|
|
||||||
|
|
||||||
Community leaders will follow these Community Impact Guidelines in determining the consequences for
|
|
||||||
any action they deem in violation of this Code of Conduct:
|
|
||||||
|
|
||||||
### 1. Correction
|
|
||||||
|
|
||||||
**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or
|
|
||||||
unwelcome in the community.
|
|
||||||
|
|
||||||
**Consequence**: A private, written warning from community leaders, providing clarity around the
|
|
||||||
nature of the violation and an explanation of why the behavior was inappropriate. A public apology
|
|
||||||
may be requested.
|
|
||||||
|
|
||||||
### 2. Warning
|
|
||||||
|
|
||||||
**Community Impact**: A violation through a single incident or series of actions.
|
|
||||||
|
|
||||||
**Consequence**: A warning with consequences for continued behavior. No interaction with the people
|
|
||||||
involved, including unsolicited interaction with those enforcing the Code of Conduct, for a
|
|
||||||
specified period of time. This includes avoiding interactions in community spaces as well as
|
|
||||||
external channels like social media. Violating these terms may lead to a temporary or permanent ban.
|
|
||||||
|
|
||||||
### 3. Temporary Ban
|
|
||||||
|
|
||||||
**Community Impact**: A serious violation of community standards, including sustained inappropriate
|
|
||||||
behavior.
|
|
||||||
|
|
||||||
**Consequence**: A temporary ban from any sort of interaction or public communication with the
|
|
||||||
community for a specified period of time. No public or private interaction with the people involved,
|
|
||||||
including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this
|
|
||||||
period. Violating these terms may lead to a permanent ban.
|
|
||||||
|
|
||||||
### 4. Permanent Ban
|
|
||||||
|
|
||||||
**Community Impact**: Demonstrating a pattern of violation of community standards, including
|
|
||||||
sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement
|
|
||||||
of classes of individuals.
|
|
||||||
|
|
||||||
**Consequence**: A permanent ban from any sort of public interaction within the community.
|
|
||||||
|
|
||||||
## Attribution
|
|
||||||
|
|
||||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available
|
|
||||||
[here](https://www.contributor-covenant.org/version/2/0/code_of_conduct.html).
|
|
||||||
|
|
||||||
Community Impact Guidelines were inspired by
|
|
||||||
[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
|
|
||||||
|
|
||||||
For answers to common questions about this code of conduct, see the
|
|
||||||
[FAQ](https://www.contributor-covenant.org/faq). Translations are available
|
|
||||||
[here](https://www.contributor-covenant.org/translations).
|
|
||||||
|
|
||||||
[homepage]: https://www.contributor-covenant.org
|
|
||||||
|
|
@ -86,13 +86,6 @@ cargo test --package <package> --test <test> -- <test_name> -- --exact
|
||||||
cargo insta review
|
cargo insta review
|
||||||
```
|
```
|
||||||
|
|
||||||
### Git and Git LFS
|
|
||||||
|
|
||||||
A subset of uv tests require both [Git](https://git-scm.com) and [Git LFS](https://git-lfs.com/) to
|
|
||||||
execute properly.
|
|
||||||
|
|
||||||
These tests can be disabled by turning off either `git` or `git-lfs` uv features.
|
|
||||||
|
|
||||||
### Local testing
|
### Local testing
|
||||||
|
|
||||||
You can invoke your development version of uv with `cargo run -- <args>`. For example:
|
You can invoke your development version of uv with `cargo run -- <args>`. For example:
|
||||||
|
|
@ -102,15 +95,6 @@ cargo run -- venv
|
||||||
cargo run -- pip install requests
|
cargo run -- pip install requests
|
||||||
```
|
```
|
||||||
|
|
||||||
## Crate structure
|
|
||||||
|
|
||||||
Rust does not allow circular dependencies between crates. To visualize the crate hierarchy, install
|
|
||||||
[cargo-depgraph](https://github.com/jplatte/cargo-depgraph) and graphviz, then run:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cargo depgraph --dedup-transitive-deps --workspace-only | dot -Tpng > graph.png
|
|
||||||
```
|
|
||||||
|
|
||||||
## Running inside a Docker container
|
## Running inside a Docker container
|
||||||
|
|
||||||
Source distributions can run arbitrary code on build and can make unwanted modifications to your
|
Source distributions can run arbitrary code on build and can make unwanted modifications to your
|
||||||
|
|
@ -136,7 +120,7 @@ Please refer to Ruff's
|
||||||
it applies to uv, too.
|
it applies to uv, too.
|
||||||
|
|
||||||
We provide diverse sets of requirements for testing and benchmarking the resolver in
|
We provide diverse sets of requirements for testing and benchmarking the resolver in
|
||||||
`test/requirements` and for the installer in `test/requirements/compiled`.
|
`scripts/requirements` and for the installer in `scripts/requirements/compiled`.
|
||||||
|
|
||||||
You can use `scripts/benchmark` to benchmark predefined workloads between uv versions and with other
|
You can use `scripts/benchmark` to benchmark predefined workloads between uv versions and with other
|
||||||
tools, e.g., from the `scripts/benchmark` directory:
|
tools, e.g., from the `scripts/benchmark` directory:
|
||||||
|
|
@ -147,7 +131,7 @@ uv run resolver \
|
||||||
--poetry \
|
--poetry \
|
||||||
--benchmark \
|
--benchmark \
|
||||||
resolve-cold \
|
resolve-cold \
|
||||||
../test/requirements/trio.in
|
../scripts/requirements/trio.in
|
||||||
```
|
```
|
||||||
|
|
||||||
### Analyzing concurrency
|
### Analyzing concurrency
|
||||||
|
|
@ -157,7 +141,7 @@ visualize parallel requests and find any spots where uv is CPU-bound. Example us
|
||||||
`uv-dev` respectively:
|
`uv-dev` respectively:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
RUST_LOG=uv=info TRACING_DURATIONS_FILE=target/traces/jupyter.ndjson cargo run --features tracing-durations-export --profile profiling -- pip compile test/requirements/jupyter.in
|
RUST_LOG=uv=info TRACING_DURATIONS_FILE=target/traces/jupyter.ndjson cargo run --features tracing-durations-export --profile profiling -- pip compile scripts/requirements/jupyter.in
|
||||||
```
|
```
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
|
|
||||||
|
|
@ -45,9 +45,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ambient-id"
|
name = "ambient-id"
|
||||||
version = "0.0.7"
|
version = "0.0.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b8cad022ed72ad2176498be1c097bb46e598193e92f3491ea0766980edeee168"
|
checksum = "36b48a3b1ad866e5034859be45edd1ebba2f097289c8a34b61623c76f10480f3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"astral-reqwest-middleware",
|
"astral-reqwest-middleware",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
|
|
@ -248,9 +248,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "astral-tl"
|
name = "astral-tl"
|
||||||
version = "0.7.11"
|
version = "0.7.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d90933ffb0f97e2fc2e0de21da9d3f20597b804012d199843a6fe7c2810d28f3"
|
checksum = "b8dfa40da988ff8327db15678418b2394b0546514b7a5c9fac75e1eb3fa40550"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
@ -1038,15 +1038,6 @@ dependencies = [
|
||||||
"itertools 0.10.5",
|
"itertools 0.10.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-channel"
|
|
||||||
version = "0.5.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-deque"
|
name = "crossbeam-deque"
|
||||||
version = "0.8.6"
|
version = "0.8.6"
|
||||||
|
|
@ -1264,16 +1255,6 @@ dependencies = [
|
||||||
"windows-sys 0.61.0",
|
"windows-sys 0.61.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "diskus"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ec07379c016f78e7ddcd953663b9ed17928ff384928d34d824ed7e463bd3d908"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-channel",
|
|
||||||
"rayon",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dispatch2"
|
name = "dispatch2"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
|
@ -1336,12 +1317,6 @@ version = "1.15.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "embed-manifest"
|
|
||||||
version = "1.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "94cdc65b1cf9e871453ce2f86f5aaec24ff2eaa36a1fa3e02e441dddc3613b99"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encode_unicode"
|
name = "encode_unicode"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
|
@ -3462,9 +3437,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon"
|
name = "rayon"
|
||||||
version = "1.11.0"
|
version = "1.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
|
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
"rayon-core",
|
"rayon-core",
|
||||||
|
|
@ -3472,9 +3447,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon-core"
|
name = "rayon-core"
|
||||||
version = "1.13.0"
|
version = "1.12.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
|
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-deque",
|
"crossbeam-deque",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
|
|
@ -4397,9 +4372,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spdx"
|
name = "spdx"
|
||||||
version = "0.13.2"
|
version = "0.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "35107b1c818f4e9cb9e6c4444ca560ba03b4ee1288dcecc6d7830c2023a7609e"
|
checksum = "41cf87c0efffc158b9dde4d6e0567a43e4383adc4c949e687a2039732db2f23a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"smallvec",
|
"smallvec",
|
||||||
]
|
]
|
||||||
|
|
@ -5406,7 +5381,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv"
|
name = "uv"
|
||||||
version = "0.9.18"
|
version = "0.9.14"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
|
@ -5421,14 +5396,13 @@ dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"console 0.16.1",
|
"console 0.16.1",
|
||||||
"ctrlc",
|
"ctrlc",
|
||||||
"diskus",
|
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
"dunce",
|
"dunce",
|
||||||
"embed-manifest",
|
|
||||||
"filetime",
|
"filetime",
|
||||||
"flate2",
|
"flate2",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
"futures",
|
"futures",
|
||||||
|
"h2",
|
||||||
"http",
|
"http",
|
||||||
"ignore",
|
"ignore",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
|
@ -5525,7 +5499,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-auth"
|
name = "uv-auth"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arcstr",
|
"arcstr",
|
||||||
|
|
@ -5568,7 +5542,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-bench"
|
name = "uv-bench"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"codspeed-criterion-compat",
|
"codspeed-criterion-compat",
|
||||||
|
|
@ -5595,7 +5569,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-bin-install"
|
name = "uv-bin-install"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"astral-reqwest-middleware",
|
"astral-reqwest-middleware",
|
||||||
"astral-reqwest-retry",
|
"astral-reqwest-retry",
|
||||||
|
|
@ -5619,7 +5593,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-build"
|
name = "uv-build"
|
||||||
version = "0.9.18"
|
version = "0.9.14"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
|
@ -5631,7 +5605,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-build-backend"
|
name = "uv-build-backend"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"astral-version-ranges",
|
"astral-version-ranges",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
|
|
@ -5647,7 +5621,7 @@ dependencies = [
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"sha2",
|
"sha2",
|
||||||
"spdx 0.13.2",
|
"spdx 0.12.0",
|
||||||
"tar",
|
"tar",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"thiserror 2.0.17",
|
"thiserror 2.0.17",
|
||||||
|
|
@ -5671,7 +5645,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-build-frontend"
|
name = "uv-build-frontend"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
|
|
@ -5688,7 +5662,6 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml_edit 0.23.7",
|
"toml_edit 0.23.7",
|
||||||
"tracing",
|
"tracing",
|
||||||
"uv-auth",
|
|
||||||
"uv-cache-key",
|
"uv-cache-key",
|
||||||
"uv-configuration",
|
"uv-configuration",
|
||||||
"uv-distribution",
|
"uv-distribution",
|
||||||
|
|
@ -5709,7 +5682,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-cache"
|
name = "uv-cache"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
|
|
@ -5719,7 +5692,6 @@ dependencies = [
|
||||||
"same-file",
|
"same-file",
|
||||||
"serde",
|
"serde",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"thiserror 2.0.17",
|
|
||||||
"tracing",
|
"tracing",
|
||||||
"uv-cache-info",
|
"uv-cache-info",
|
||||||
"uv-cache-key",
|
"uv-cache-key",
|
||||||
|
|
@ -5735,7 +5707,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-cache-info"
|
name = "uv-cache-info"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
|
|
@ -5752,7 +5724,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-cache-key"
|
name = "uv-cache-key"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hex",
|
"hex",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
|
@ -5764,7 +5736,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-cli"
|
name = "uv-cli"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
|
@ -5796,7 +5768,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-client"
|
name = "uv-client"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"astral-reqwest-middleware",
|
"astral-reqwest-middleware",
|
||||||
|
|
@ -5859,7 +5831,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-configuration"
|
name = "uv-configuration"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
|
|
@ -5888,14 +5860,14 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-console"
|
name = "uv-console"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console 0.16.1",
|
"console 0.16.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-dev"
|
name = "uv-dev"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
|
@ -5944,7 +5916,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-dirs"
|
name = "uv-dirs"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_fs",
|
"assert_fs",
|
||||||
"etcetera",
|
"etcetera",
|
||||||
|
|
@ -5956,7 +5928,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-dispatch"
|
name = "uv-dispatch"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"futures",
|
"futures",
|
||||||
|
|
@ -5988,7 +5960,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-distribution"
|
name = "uv-distribution"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"astral-reqwest-middleware",
|
"astral-reqwest-middleware",
|
||||||
|
|
@ -6018,7 +5990,6 @@ dependencies = [
|
||||||
"uv-distribution-filename",
|
"uv-distribution-filename",
|
||||||
"uv-distribution-types",
|
"uv-distribution-types",
|
||||||
"uv-extract",
|
"uv-extract",
|
||||||
"uv-flags",
|
|
||||||
"uv-fs",
|
"uv-fs",
|
||||||
"uv-git",
|
"uv-git",
|
||||||
"uv-git-types",
|
"uv-git-types",
|
||||||
|
|
@ -6037,7 +6008,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-distribution-filename"
|
name = "uv-distribution-filename"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"insta",
|
"insta",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
|
@ -6054,7 +6025,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-distribution-types"
|
name = "uv-distribution-types"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arcstr",
|
"arcstr",
|
||||||
"astral-version-ranges",
|
"astral-version-ranges",
|
||||||
|
|
@ -6094,7 +6065,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-extract"
|
name = "uv-extract"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"astral-tokio-tar",
|
"astral-tokio-tar",
|
||||||
"astral_async_zip",
|
"astral_async_zip",
|
||||||
|
|
@ -6124,14 +6095,14 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-flags"
|
name = "uv-flags"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.4",
|
"bitflags 2.9.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-fs"
|
name = "uv-fs"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backon",
|
"backon",
|
||||||
"dunce",
|
"dunce",
|
||||||
|
|
@ -6146,23 +6117,20 @@ dependencies = [
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"thiserror 2.0.17",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"uv-static",
|
|
||||||
"windows 0.59.0",
|
"windows 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-git"
|
name = "uv-git"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"astral-reqwest-middleware",
|
"astral-reqwest-middleware",
|
||||||
"cargo-util",
|
"cargo-util",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
"owo-colors",
|
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"thiserror 2.0.17",
|
"thiserror 2.0.17",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
|
@ -6175,25 +6143,23 @@ dependencies = [
|
||||||
"uv-redacted",
|
"uv-redacted",
|
||||||
"uv-static",
|
"uv-static",
|
||||||
"uv-version",
|
"uv-version",
|
||||||
"uv-warnings",
|
|
||||||
"which",
|
"which",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-git-types"
|
name = "uv-git-types"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror 2.0.17",
|
"thiserror 2.0.17",
|
||||||
"tracing",
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
"uv-redacted",
|
"uv-redacted",
|
||||||
"uv-static",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-globfilter"
|
name = "uv-globfilter"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
|
|
@ -6210,7 +6176,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-install-wheel"
|
name = "uv-install-wheel"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"assert_fs",
|
"assert_fs",
|
||||||
|
|
@ -6250,7 +6216,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-installer"
|
name = "uv-installer"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-channel",
|
"async-channel",
|
||||||
|
|
@ -6291,7 +6257,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-keyring"
|
name = "uv-keyring"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
|
|
@ -6308,7 +6274,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-logging"
|
name = "uv-logging"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jiff",
|
"jiff",
|
||||||
"owo-colors",
|
"owo-colors",
|
||||||
|
|
@ -6318,7 +6284,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-macros"
|
name = "uv-macros"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -6328,7 +6294,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-metadata"
|
name = "uv-metadata"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"astral_async_zip",
|
"astral_async_zip",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
|
|
@ -6345,7 +6311,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-normalize"
|
name = "uv-normalize"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rkyv",
|
"rkyv",
|
||||||
"schemars",
|
"schemars",
|
||||||
|
|
@ -6355,7 +6321,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-once-map"
|
name = "uv-once-map"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dashmap",
|
"dashmap",
|
||||||
"futures",
|
"futures",
|
||||||
|
|
@ -6364,14 +6330,14 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-options-metadata"
|
name = "uv-options-metadata"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-pep440"
|
name = "uv-pep440"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"astral-version-ranges",
|
"astral-version-ranges",
|
||||||
"indoc",
|
"indoc",
|
||||||
|
|
@ -6385,7 +6351,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-pep508"
|
name = "uv-pep508"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arcstr",
|
"arcstr",
|
||||||
"astral-version-ranges",
|
"astral-version-ranges",
|
||||||
|
|
@ -6414,7 +6380,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-performance-memory-allocator"
|
name = "uv-performance-memory-allocator"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"mimalloc",
|
"mimalloc",
|
||||||
"tikv-jemallocator",
|
"tikv-jemallocator",
|
||||||
|
|
@ -6422,7 +6388,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-platform"
|
name = "uv-platform"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fs-err",
|
"fs-err",
|
||||||
"goblin",
|
"goblin",
|
||||||
|
|
@ -6439,7 +6405,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-platform-tags"
|
name = "uv-platform-tags"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"insta",
|
"insta",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
|
@ -6452,7 +6418,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-preview"
|
name = "uv-preview"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.4",
|
"bitflags 2.9.4",
|
||||||
"thiserror 2.0.17",
|
"thiserror 2.0.17",
|
||||||
|
|
@ -6461,10 +6427,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-publish"
|
name = "uv-publish"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ambient-id",
|
"ambient-id",
|
||||||
"anstream",
|
|
||||||
"astral-reqwest-middleware",
|
"astral-reqwest-middleware",
|
||||||
"astral-reqwest-retry",
|
"astral-reqwest-retry",
|
||||||
"astral-tokio-tar",
|
"astral-tokio-tar",
|
||||||
|
|
@ -6498,12 +6463,11 @@ dependencies = [
|
||||||
"uv-redacted",
|
"uv-redacted",
|
||||||
"uv-static",
|
"uv-static",
|
||||||
"uv-warnings",
|
"uv-warnings",
|
||||||
"wiremock",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-pypi-types"
|
name = "uv-pypi-types"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"hashbrown 0.16.1",
|
"hashbrown 0.16.1",
|
||||||
|
|
@ -6535,7 +6499,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-python"
|
name = "uv-python"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"assert_fs",
|
"assert_fs",
|
||||||
|
|
@ -6597,7 +6561,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-redacted"
|
name = "uv-redacted"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ref-cast",
|
"ref-cast",
|
||||||
"schemars",
|
"schemars",
|
||||||
|
|
@ -6608,7 +6572,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-requirements"
|
name = "uv-requirements"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"configparser",
|
"configparser",
|
||||||
|
|
@ -6643,7 +6607,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-requirements-txt"
|
name = "uv-requirements-txt"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"assert_fs",
|
"assert_fs",
|
||||||
|
|
@ -6676,7 +6640,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-resolver"
|
name = "uv-resolver"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arcstr",
|
"arcstr",
|
||||||
"astral-pubgrub",
|
"astral-pubgrub",
|
||||||
|
|
@ -6741,7 +6705,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-scripts"
|
name = "uv-scripts"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fs-err",
|
"fs-err",
|
||||||
"indoc",
|
"indoc",
|
||||||
|
|
@ -6765,7 +6729,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-settings"
|
name = "uv-settings"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
|
|
@ -6800,7 +6764,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-shell"
|
name = "uv-shell"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
|
|
@ -6817,7 +6781,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-small-str"
|
name = "uv-small-str"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arcstr",
|
"arcstr",
|
||||||
"rkyv",
|
"rkyv",
|
||||||
|
|
@ -6827,7 +6791,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-state"
|
name = "uv-state"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fs-err",
|
"fs-err",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
|
|
@ -6836,14 +6800,14 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-static"
|
name = "uv-static"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"uv-macros",
|
"uv-macros",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-tool"
|
name = "uv-tool"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fs-err",
|
"fs-err",
|
||||||
"pathdiff",
|
"pathdiff",
|
||||||
|
|
@ -6872,7 +6836,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-torch"
|
name = "uv-torch"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"either",
|
"either",
|
||||||
|
|
@ -6892,7 +6856,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-trampoline-builder"
|
name = "uv-trampoline-builder"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"assert_cmd",
|
"assert_cmd",
|
||||||
|
|
@ -6909,7 +6873,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-types"
|
name = "uv-types"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
|
|
@ -6931,11 +6895,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-version"
|
name = "uv-version"
|
||||||
version = "0.9.18"
|
version = "0.9.14"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-virtualenv"
|
name = "uv-virtualenv"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console 0.16.1",
|
"console 0.16.1",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
|
|
@ -6957,19 +6921,16 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-warnings"
|
name = "uv-warnings"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anyhow",
|
|
||||||
"indoc",
|
|
||||||
"insta",
|
|
||||||
"owo-colors",
|
"owo-colors",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-workspace"
|
name = "uv-workspace"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"assert_fs",
|
"assert_fs",
|
||||||
|
|
|
||||||
138
Cargo.toml
138
Cargo.toml
|
|
@ -16,66 +16,66 @@ authors = ["uv"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
uv-auth = { version = "0.0.8", path = "crates/uv-auth" }
|
uv-auth = { version = "0.0.4", path = "crates/uv-auth" }
|
||||||
uv-bin-install = { version = "0.0.8", path = "crates/uv-bin-install" }
|
uv-bin-install = { version = "0.0.4", path = "crates/uv-bin-install" }
|
||||||
uv-build-backend = { version = "0.0.8", path = "crates/uv-build-backend" }
|
uv-build-backend = { version = "0.0.4", path = "crates/uv-build-backend" }
|
||||||
uv-build-frontend = { version = "0.0.8", path = "crates/uv-build-frontend" }
|
uv-build-frontend = { version = "0.0.4", path = "crates/uv-build-frontend" }
|
||||||
uv-cache = { version = "0.0.8", path = "crates/uv-cache" }
|
uv-cache = { version = "0.0.4", path = "crates/uv-cache" }
|
||||||
uv-cache-info = { version = "0.0.8", path = "crates/uv-cache-info" }
|
uv-cache-info = { version = "0.0.4", path = "crates/uv-cache-info" }
|
||||||
uv-cache-key = { version = "0.0.8", path = "crates/uv-cache-key" }
|
uv-cache-key = { version = "0.0.4", path = "crates/uv-cache-key" }
|
||||||
uv-cli = { version = "0.0.8", path = "crates/uv-cli" }
|
uv-cli = { version = "0.0.4", path = "crates/uv-cli" }
|
||||||
uv-client = { version = "0.0.8", path = "crates/uv-client" }
|
uv-client = { version = "0.0.4", path = "crates/uv-client" }
|
||||||
uv-configuration = { version = "0.0.8", path = "crates/uv-configuration" }
|
uv-configuration = { version = "0.0.4", path = "crates/uv-configuration" }
|
||||||
uv-console = { version = "0.0.8", path = "crates/uv-console" }
|
uv-console = { version = "0.0.4", path = "crates/uv-console" }
|
||||||
uv-dirs = { version = "0.0.8", path = "crates/uv-dirs" }
|
uv-dirs = { version = "0.0.4", path = "crates/uv-dirs" }
|
||||||
uv-dispatch = { version = "0.0.8", path = "crates/uv-dispatch" }
|
uv-dispatch = { version = "0.0.4", path = "crates/uv-dispatch" }
|
||||||
uv-distribution = { version = "0.0.8", path = "crates/uv-distribution" }
|
uv-distribution = { version = "0.0.4", path = "crates/uv-distribution" }
|
||||||
uv-distribution-filename = { version = "0.0.8", path = "crates/uv-distribution-filename" }
|
uv-distribution-filename = { version = "0.0.4", path = "crates/uv-distribution-filename" }
|
||||||
uv-distribution-types = { version = "0.0.8", path = "crates/uv-distribution-types" }
|
uv-distribution-types = { version = "0.0.4", path = "crates/uv-distribution-types" }
|
||||||
uv-extract = { version = "0.0.8", path = "crates/uv-extract" }
|
uv-extract = { version = "0.0.4", path = "crates/uv-extract" }
|
||||||
uv-flags = { version = "0.0.8", path = "crates/uv-flags" }
|
uv-flags = { version = "0.0.4", path = "crates/uv-flags" }
|
||||||
uv-fs = { version = "0.0.8", path = "crates/uv-fs", features = ["serde", "tokio"] }
|
uv-fs = { version = "0.0.4", path = "crates/uv-fs", features = ["serde", "tokio"] }
|
||||||
uv-git = { version = "0.0.8", path = "crates/uv-git" }
|
uv-git = { version = "0.0.4", path = "crates/uv-git" }
|
||||||
uv-git-types = { version = "0.0.8", path = "crates/uv-git-types" }
|
uv-git-types = { version = "0.0.4", path = "crates/uv-git-types" }
|
||||||
uv-globfilter = { version = "0.0.8", path = "crates/uv-globfilter" }
|
uv-globfilter = { version = "0.0.4", path = "crates/uv-globfilter" }
|
||||||
uv-install-wheel = { version = "0.0.8", path = "crates/uv-install-wheel", default-features = false }
|
uv-install-wheel = { version = "0.0.4", path = "crates/uv-install-wheel", default-features = false }
|
||||||
uv-installer = { version = "0.0.8", path = "crates/uv-installer" }
|
uv-installer = { version = "0.0.4", path = "crates/uv-installer" }
|
||||||
uv-keyring = { version = "0.0.8", path = "crates/uv-keyring" }
|
uv-keyring = { version = "0.0.4", path = "crates/uv-keyring" }
|
||||||
uv-logging = { version = "0.0.8", path = "crates/uv-logging" }
|
uv-logging = { version = "0.0.4", path = "crates/uv-logging" }
|
||||||
uv-macros = { version = "0.0.8", path = "crates/uv-macros" }
|
uv-macros = { version = "0.0.4", path = "crates/uv-macros" }
|
||||||
uv-metadata = { version = "0.0.8", path = "crates/uv-metadata" }
|
uv-metadata = { version = "0.0.4", path = "crates/uv-metadata" }
|
||||||
uv-normalize = { version = "0.0.8", path = "crates/uv-normalize" }
|
uv-normalize = { version = "0.0.4", path = "crates/uv-normalize" }
|
||||||
uv-once-map = { version = "0.0.8", path = "crates/uv-once-map" }
|
uv-once-map = { version = "0.0.4", path = "crates/uv-once-map" }
|
||||||
uv-options-metadata = { version = "0.0.8", path = "crates/uv-options-metadata" }
|
uv-options-metadata = { version = "0.0.4", path = "crates/uv-options-metadata" }
|
||||||
uv-performance-memory-allocator = { version = "0.0.8", path = "crates/uv-performance-memory-allocator" }
|
uv-performance-memory-allocator = { version = "0.0.4", path = "crates/uv-performance-memory-allocator" }
|
||||||
uv-pep440 = { version = "0.0.8", path = "crates/uv-pep440", features = ["tracing", "rkyv", "version-ranges"] }
|
uv-pep440 = { version = "0.0.4", path = "crates/uv-pep440", features = ["tracing", "rkyv", "version-ranges"] }
|
||||||
uv-pep508 = { version = "0.0.8", path = "crates/uv-pep508", features = ["non-pep508-extensions"] }
|
uv-pep508 = { version = "0.0.4", path = "crates/uv-pep508", features = ["non-pep508-extensions"] }
|
||||||
uv-platform = { version = "0.0.8", path = "crates/uv-platform" }
|
uv-platform = { version = "0.0.4", path = "crates/uv-platform" }
|
||||||
uv-platform-tags = { version = "0.0.8", path = "crates/uv-platform-tags" }
|
uv-platform-tags = { version = "0.0.4", path = "crates/uv-platform-tags" }
|
||||||
uv-preview = { version = "0.0.8", path = "crates/uv-preview" }
|
uv-preview = { version = "0.0.4", path = "crates/uv-preview" }
|
||||||
uv-publish = { version = "0.0.8", path = "crates/uv-publish" }
|
uv-publish = { version = "0.0.4", path = "crates/uv-publish" }
|
||||||
uv-pypi-types = { version = "0.0.8", path = "crates/uv-pypi-types" }
|
uv-pypi-types = { version = "0.0.4", path = "crates/uv-pypi-types" }
|
||||||
uv-python = { version = "0.0.8", path = "crates/uv-python" }
|
uv-python = { version = "0.0.4", path = "crates/uv-python" }
|
||||||
uv-redacted = { version = "0.0.8", path = "crates/uv-redacted" }
|
uv-redacted = { version = "0.0.4", path = "crates/uv-redacted" }
|
||||||
uv-requirements = { version = "0.0.8", path = "crates/uv-requirements" }
|
uv-requirements = { version = "0.0.4", path = "crates/uv-requirements" }
|
||||||
uv-requirements-txt = { version = "0.0.8", path = "crates/uv-requirements-txt" }
|
uv-requirements-txt = { version = "0.0.4", path = "crates/uv-requirements-txt" }
|
||||||
uv-resolver = { version = "0.0.8", path = "crates/uv-resolver" }
|
uv-resolver = { version = "0.0.4", path = "crates/uv-resolver" }
|
||||||
uv-scripts = { version = "0.0.8", path = "crates/uv-scripts" }
|
uv-scripts = { version = "0.0.4", path = "crates/uv-scripts" }
|
||||||
uv-settings = { version = "0.0.8", path = "crates/uv-settings" }
|
uv-settings = { version = "0.0.4", path = "crates/uv-settings" }
|
||||||
uv-shell = { version = "0.0.8", path = "crates/uv-shell" }
|
uv-shell = { version = "0.0.4", path = "crates/uv-shell" }
|
||||||
uv-small-str = { version = "0.0.8", path = "crates/uv-small-str" }
|
uv-small-str = { version = "0.0.4", path = "crates/uv-small-str" }
|
||||||
uv-state = { version = "0.0.8", path = "crates/uv-state" }
|
uv-state = { version = "0.0.4", path = "crates/uv-state" }
|
||||||
uv-static = { version = "0.0.8", path = "crates/uv-static" }
|
uv-static = { version = "0.0.4", path = "crates/uv-static" }
|
||||||
uv-tool = { version = "0.0.8", path = "crates/uv-tool" }
|
uv-tool = { version = "0.0.4", path = "crates/uv-tool" }
|
||||||
uv-torch = { version = "0.0.8", path = "crates/uv-torch" }
|
uv-torch = { version = "0.0.4", path = "crates/uv-torch" }
|
||||||
uv-trampoline-builder = { version = "0.0.8", path = "crates/uv-trampoline-builder" }
|
uv-trampoline-builder = { version = "0.0.4", path = "crates/uv-trampoline-builder" }
|
||||||
uv-types = { version = "0.0.8", path = "crates/uv-types" }
|
uv-types = { version = "0.0.4", path = "crates/uv-types" }
|
||||||
uv-version = { version = "0.9.18", path = "crates/uv-version" }
|
uv-version = { version = "0.9.14", path = "crates/uv-version" }
|
||||||
uv-virtualenv = { version = "0.0.8", path = "crates/uv-virtualenv" }
|
uv-virtualenv = { version = "0.0.4", path = "crates/uv-virtualenv" }
|
||||||
uv-warnings = { version = "0.0.8", path = "crates/uv-warnings" }
|
uv-warnings = { version = "0.0.4", path = "crates/uv-warnings" }
|
||||||
uv-workspace = { version = "0.0.8", path = "crates/uv-workspace" }
|
uv-workspace = { version = "0.0.4", path = "crates/uv-workspace" }
|
||||||
|
|
||||||
ambient-id = { version = "0.0.7", default-features = false, features = ["astral-reqwest-middleware"] }
|
ambient-id = { version = "0.0.6", default-features = false, features = ["astral-reqwest-middleware"] }
|
||||||
anstream = { version = "0.6.15" }
|
anstream = { version = "0.6.15" }
|
||||||
anyhow = { version = "1.0.89" }
|
anyhow = { version = "1.0.89" }
|
||||||
arcstr = { version = "1.2.0" }
|
arcstr = { version = "1.2.0" }
|
||||||
|
|
@ -103,12 +103,10 @@ ctrlc = { version = "3.4.5" }
|
||||||
cyclonedx-bom = { version = "0.8.0" }
|
cyclonedx-bom = { version = "0.8.0" }
|
||||||
dashmap = { version = "6.1.0" }
|
dashmap = { version = "6.1.0" }
|
||||||
data-encoding = { version = "2.6.0" }
|
data-encoding = { version = "2.6.0" }
|
||||||
diskus = { version = "0.9.0", default-features = false }
|
|
||||||
dotenvy = { version = "0.15.7" }
|
dotenvy = { version = "0.15.7" }
|
||||||
dunce = { version = "1.0.5" }
|
dunce = { version = "1.0.5" }
|
||||||
either = { version = "1.13.0" }
|
either = { version = "1.13.0" }
|
||||||
encoding_rs_io = { version = "0.1.7" }
|
encoding_rs_io = { version = "0.1.7" }
|
||||||
embed-manifest = { version = "1.5.0" }
|
|
||||||
etcetera = { version = "0.11.0" }
|
etcetera = { version = "0.11.0" }
|
||||||
fastrand = { version = "2.3.0" }
|
fastrand = { version = "2.3.0" }
|
||||||
flate2 = { version = "1.0.33", default-features = false, features = ["zlib-rs"] }
|
flate2 = { version = "1.0.33", default-features = false, features = ["zlib-rs"] }
|
||||||
|
|
@ -170,7 +168,7 @@ serde-untagged = { version = "0.1.6" }
|
||||||
serde_json = { version = "1.0.128" }
|
serde_json = { version = "1.0.128" }
|
||||||
sha2 = { version = "0.10.8" }
|
sha2 = { version = "0.10.8" }
|
||||||
smallvec = { version = "1.13.2" }
|
smallvec = { version = "1.13.2" }
|
||||||
spdx = { version = "0.13.0" }
|
spdx = { version = "0.12.0" }
|
||||||
syn = { version = "2.0.77" }
|
syn = { version = "2.0.77" }
|
||||||
sys-info = { version = "0.9.1" }
|
sys-info = { version = "0.9.1" }
|
||||||
tar = { version = "0.4.43" }
|
tar = { version = "0.4.43" }
|
||||||
|
|
@ -178,8 +176,8 @@ target-lexicon = { version = "0.13.0" }
|
||||||
tempfile = { version = "3.14.0" }
|
tempfile = { version = "3.14.0" }
|
||||||
textwrap = { version = "0.16.1" }
|
textwrap = { version = "0.16.1" }
|
||||||
thiserror = { version = "2.0.0" }
|
thiserror = { version = "2.0.0" }
|
||||||
astral-tl = { version = "0.7.11" }
|
astral-tl = { version = "0.7.10" }
|
||||||
tokio = { version = "1.40.0", features = ["fs", "io-util", "macros", "process", "rt", "signal", "sync", "time"] }
|
tokio = { version = "1.40.0", features = ["fs", "io-util", "macros", "process", "rt", "signal", "sync"] }
|
||||||
tokio-stream = { version = "0.1.16" }
|
tokio-stream = { version = "0.1.16" }
|
||||||
tokio-util = { version = "0.7.12", features = ["compat", "io"] }
|
tokio-util = { version = "0.7.12", features = ["compat", "io"] }
|
||||||
toml = { version = "0.9.2", features = ["fast_hash"] }
|
toml = { version = "0.9.2", features = ["fast_hash"] }
|
||||||
|
|
@ -225,6 +223,9 @@ test-log = { version = "0.2.16", features = ["trace"], default-features = false
|
||||||
tokio-rustls = { version = "0.26.2", default-features = false }
|
tokio-rustls = { version = "0.26.2", default-features = false }
|
||||||
whoami = { version = "1.6.0" }
|
whoami = { version = "1.6.0" }
|
||||||
|
|
||||||
|
[workspace.metadata.cargo-shear]
|
||||||
|
ignored = ["flate2", "xz2", "h2", "uv-performance-memory-allocator"]
|
||||||
|
|
||||||
[workspace.lints.rust]
|
[workspace.lints.rust]
|
||||||
unsafe_code = "warn"
|
unsafe_code = "warn"
|
||||||
unreachable_pub = "warn"
|
unreachable_pub = "warn"
|
||||||
|
|
@ -310,21 +311,12 @@ strip = false
|
||||||
debug = "full"
|
debug = "full"
|
||||||
lto = false
|
lto = false
|
||||||
|
|
||||||
# Profile for fast test execution: Skip debug info generation, and
|
|
||||||
# apply basic optimization, which speed up build and running tests.
|
|
||||||
[profile.fast-build]
|
[profile.fast-build]
|
||||||
inherits = "dev"
|
inherits = "dev"
|
||||||
opt-level = 1
|
opt-level = 1
|
||||||
debug = 0
|
debug = 0
|
||||||
strip = "debuginfo"
|
strip = "debuginfo"
|
||||||
|
|
||||||
# Profile for faster builds: Skip debug info generation, for faster
|
|
||||||
# builds of smaller binaries.
|
|
||||||
[profile.no-debug]
|
|
||||||
inherits = "dev"
|
|
||||||
debug = 0
|
|
||||||
strip = "debuginfo"
|
|
||||||
|
|
||||||
# Profile to build a minimally sized binary for uv-build
|
# Profile to build a minimally sized binary for uv-build
|
||||||
[profile.minimal-size]
|
[profile.minimal-size]
|
||||||
inherits = "release"
|
inherits = "release"
|
||||||
|
|
|
||||||
33
README.md
33
README.md
|
|
@ -42,7 +42,7 @@ An extremely fast Python package and project manager, written in Rust.
|
||||||
- 🖥️ Supports macOS, Linux, and Windows.
|
- 🖥️ Supports macOS, Linux, and Windows.
|
||||||
|
|
||||||
uv is backed by [Astral](https://astral.sh), the creators of
|
uv is backed by [Astral](https://astral.sh), the creators of
|
||||||
[Ruff](https://github.com/astral-sh/ruff) and [ty](https://github.com/astral-sh/ty).
|
[Ruff](https://github.com/astral-sh/ruff).
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|
@ -192,12 +192,14 @@ uv installs Python and allows quickly switching between versions.
|
||||||
Install multiple Python versions:
|
Install multiple Python versions:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ uv python install 3.12 3.13 3.14
|
$ uv python install 3.10 3.11 3.12
|
||||||
Installed 3 versions in 972ms
|
Searching for Python versions matching: Python 3.10
|
||||||
+ cpython-3.12.12-macos-aarch64-none (python3.12)
|
Searching for Python versions matching: Python 3.11
|
||||||
+ cpython-3.13.9-macos-aarch64-none (python3.13)
|
Searching for Python versions matching: Python 3.12
|
||||||
+ cpython-3.14.0-macos-aarch64-none (python3.14)
|
Installed 3 versions in 3.42s
|
||||||
|
+ cpython-3.10.14-macos-aarch64-none
|
||||||
|
+ cpython-3.11.9-macos-aarch64-none
|
||||||
|
+ cpython-3.12.4-macos-aarch64-none
|
||||||
```
|
```
|
||||||
|
|
||||||
Download Python versions as needed:
|
Download Python versions as needed:
|
||||||
|
|
@ -268,6 +270,14 @@ Installed 43 packages in 208ms
|
||||||
|
|
||||||
See the [pip interface documentation](https://docs.astral.sh/uv/pip/index/) to get started.
|
See the [pip interface documentation](https://docs.astral.sh/uv/pip/index/) to get started.
|
||||||
|
|
||||||
|
## Platform support
|
||||||
|
|
||||||
|
See uv's [platform support](https://docs.astral.sh/uv/reference/platforms/) document.
|
||||||
|
|
||||||
|
## Versioning policy
|
||||||
|
|
||||||
|
See uv's [versioning policy](https://docs.astral.sh/uv/reference/versioning/) document.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
We are passionate about supporting contributors of all levels of experience and would love to see
|
We are passionate about supporting contributors of all levels of experience and would love to see
|
||||||
|
|
@ -284,15 +294,6 @@ It's pronounced as "you - vee" ([`/juː viː/`](https://en.wikipedia.org/wiki/He
|
||||||
|
|
||||||
Just "uv", please. See the [style guide](./STYLE.md#styling-uv) for details.
|
Just "uv", please. See the [style guide](./STYLE.md#styling-uv) for details.
|
||||||
|
|
||||||
#### What platforms does uv support?
|
|
||||||
|
|
||||||
See uv's [platform support](https://docs.astral.sh/uv/reference/platforms/) document.
|
|
||||||
|
|
||||||
#### Is uv ready for production?
|
|
||||||
|
|
||||||
Yes, uv is stable and widely used in production. See uv's
|
|
||||||
[versioning policy](https://docs.astral.sh/uv/reference/versioning/) document for details.
|
|
||||||
|
|
||||||
## Acknowledgements
|
## Acknowledgements
|
||||||
|
|
||||||
uv's dependency resolver uses [PubGrub](https://github.com/pubgrub-rs/pubgrub) under the hood. We're
|
uv's dependency resolver uses [PubGrub](https://github.com/pubgrub-rs/pubgrub) under the hood. We're
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
[files]
|
[files]
|
||||||
extend-exclude = [
|
extend-exclude = [
|
||||||
"**/snapshots/",
|
"**/snapshots/",
|
||||||
"test/ecosystem/**",
|
"ecosystem/**",
|
||||||
"test/requirements/**/*.in",
|
"scripts/**/*.in",
|
||||||
"crates/uv-build-frontend/src/pipreqs/mapping",
|
"crates/uv-build-frontend/src/pipreqs/mapping",
|
||||||
]
|
]
|
||||||
ignore-hidden = false
|
ignore-hidden = false
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-auth"
|
name = "uv-auth"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
description = "This is an internal component crate of uv"
|
description = "This is an internal component crate of uv"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@
|
||||||
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
||||||
is unstable and will have frequent breaking changes.
|
is unstable and will have frequent breaking changes.
|
||||||
|
|
||||||
This version (0.0.8) is a component of [uv 0.9.18](https://crates.io/crates/uv/0.9.18). The source
|
|
||||||
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-auth).
|
|
||||||
|
|
||||||
See uv's
|
See uv's
|
||||||
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
||||||
for details on versioning.
|
for details on versioning.
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ use url::Url;
|
||||||
use uv_once_map::OnceMap;
|
use uv_once_map::OnceMap;
|
||||||
use uv_redacted::DisplaySafeUrl;
|
use uv_redacted::DisplaySafeUrl;
|
||||||
|
|
||||||
|
use crate::Realm;
|
||||||
use crate::credentials::{Authentication, Username};
|
use crate::credentials::{Authentication, Username};
|
||||||
use crate::{Credentials, Realm};
|
|
||||||
|
|
||||||
type FxOnceMap<K, V> = OnceMap<K, V, BuildHasherDefault<FxHasher>>;
|
type FxOnceMap<K, V> = OnceMap<K, V, BuildHasherDefault<FxHasher>>;
|
||||||
|
|
||||||
|
|
@ -33,7 +33,6 @@ impl Display for FetchUrl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)] // All internal types are redacted.
|
|
||||||
pub struct CredentialsCache {
|
pub struct CredentialsCache {
|
||||||
/// A cache per realm and username
|
/// A cache per realm and username
|
||||||
realms: RwLock<FxHashMap<(Realm, Username), Arc<Authentication>>>,
|
realms: RwLock<FxHashMap<(Realm, Username), Arc<Authentication>>>,
|
||||||
|
|
@ -59,27 +58,6 @@ impl CredentialsCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Populate the global authentication store with credentials on a URL, if there are any.
|
|
||||||
///
|
|
||||||
/// Returns `true` if the store was updated.
|
|
||||||
pub fn store_credentials_from_url(&self, url: &DisplaySafeUrl) -> bool {
|
|
||||||
if let Some(credentials) = Credentials::from_url(url) {
|
|
||||||
trace!("Caching credentials for {url}");
|
|
||||||
self.insert(url, Arc::new(Authentication::from(credentials)));
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Populate the global authentication store with credentials on a URL, if there are any.
|
|
||||||
///
|
|
||||||
/// Returns `true` if the store was updated.
|
|
||||||
pub fn store_credentials(&self, url: &DisplaySafeUrl, credentials: Credentials) {
|
|
||||||
trace!("Caching credentials for {url}");
|
|
||||||
self.insert(url, Arc::new(Authentication::from(credentials)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the credentials that should be used for a realm and username, if any.
|
/// Return the credentials that should be used for a realm and username, if any.
|
||||||
pub(crate) fn get_realm(
|
pub(crate) fn get_realm(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
|
use std::sync::{Arc, LazyLock};
|
||||||
|
|
||||||
|
use tracing::trace;
|
||||||
|
|
||||||
|
use uv_redacted::DisplaySafeUrl;
|
||||||
|
|
||||||
|
use crate::credentials::Authentication;
|
||||||
pub use access_token::AccessToken;
|
pub use access_token::AccessToken;
|
||||||
pub use cache::CredentialsCache;
|
use cache::CredentialsCache;
|
||||||
pub use credentials::{Credentials, Username};
|
pub use credentials::{Credentials, Username};
|
||||||
pub use index::{AuthPolicy, Index, Indexes};
|
pub use index::{AuthPolicy, Index, Indexes};
|
||||||
pub use keyring::KeyringProvider;
|
pub use keyring::KeyringProvider;
|
||||||
|
|
@ -22,3 +29,32 @@ mod pyx;
|
||||||
mod realm;
|
mod realm;
|
||||||
mod service;
|
mod service;
|
||||||
mod store;
|
mod store;
|
||||||
|
|
||||||
|
// TODO(zanieb): Consider passing a cache explicitly throughout
|
||||||
|
|
||||||
|
/// Global authentication cache for a uv invocation
|
||||||
|
///
|
||||||
|
/// This is used to share credentials across uv clients.
|
||||||
|
pub(crate) static CREDENTIALS_CACHE: LazyLock<CredentialsCache> =
|
||||||
|
LazyLock::new(CredentialsCache::default);
|
||||||
|
|
||||||
|
/// Populate the global authentication store with credentials on a URL, if there are any.
|
||||||
|
///
|
||||||
|
/// Returns `true` if the store was updated.
|
||||||
|
pub fn store_credentials_from_url(url: &DisplaySafeUrl) -> bool {
|
||||||
|
if let Some(credentials) = Credentials::from_url(url) {
|
||||||
|
trace!("Caching credentials for {url}");
|
||||||
|
CREDENTIALS_CACHE.insert(url, Arc::new(Authentication::from(credentials)));
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Populate the global authentication store with credentials on a URL, if there are any.
|
||||||
|
///
|
||||||
|
/// Returns `true` if the store was updated.
|
||||||
|
pub fn store_credentials(url: &DisplaySafeUrl, credentials: Credentials) {
|
||||||
|
trace!("Caching credentials for {url}");
|
||||||
|
CREDENTIALS_CACHE.insert(url, Arc::new(Authentication::from(credentials)));
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,13 @@ use crate::credentials::Authentication;
|
||||||
use crate::providers::{HuggingFaceProvider, S3EndpointProvider};
|
use crate::providers::{HuggingFaceProvider, S3EndpointProvider};
|
||||||
use crate::pyx::{DEFAULT_TOLERANCE_SECS, PyxTokenStore};
|
use crate::pyx::{DEFAULT_TOLERANCE_SECS, PyxTokenStore};
|
||||||
use crate::{
|
use crate::{
|
||||||
AccessToken, CredentialsCache, KeyringProvider,
|
AccessToken, CREDENTIALS_CACHE, CredentialsCache, KeyringProvider,
|
||||||
cache::FetchUrl,
|
cache::FetchUrl,
|
||||||
credentials::{Credentials, Username},
|
credentials::{Credentials, Username},
|
||||||
index::{AuthPolicy, Indexes},
|
index::{AuthPolicy, Indexes},
|
||||||
realm::Realm,
|
realm::Realm,
|
||||||
};
|
};
|
||||||
use crate::{Index, TextCredentialStore};
|
use crate::{Index, TextCredentialStore, TomlCredentialError};
|
||||||
|
|
||||||
/// Cached check for whether we're running in Dependabot.
|
/// Cached check for whether we're running in Dependabot.
|
||||||
static IS_DEPENDABOT: LazyLock<bool> =
|
static IS_DEPENDABOT: LazyLock<bool> =
|
||||||
|
|
@ -65,55 +65,49 @@ impl NetrcMode {
|
||||||
|
|
||||||
/// Strategy for loading text-based credential files.
|
/// Strategy for loading text-based credential files.
|
||||||
enum TextStoreMode {
|
enum TextStoreMode {
|
||||||
Automatic(tokio::sync::OnceCell<Option<TextCredentialStore>>),
|
Automatic(LazyLock<Option<TextCredentialStore>>),
|
||||||
Enabled(TextCredentialStore),
|
Enabled(TextCredentialStore),
|
||||||
Disabled,
|
Disabled,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TextStoreMode {
|
impl Default for TextStoreMode {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::Automatic(tokio::sync::OnceCell::new())
|
// TODO(zanieb): Reconsider this pattern. We're just mirroring the [`NetrcMode`]
|
||||||
|
// implementation for now.
|
||||||
|
Self::Automatic(LazyLock::new(|| {
|
||||||
|
let path = TextCredentialStore::default_file()
|
||||||
|
.inspect_err(|err| {
|
||||||
|
warn!("Failed to determine credentials file path: {}", err);
|
||||||
|
})
|
||||||
|
.ok()?;
|
||||||
|
|
||||||
|
match TextCredentialStore::read(&path) {
|
||||||
|
Ok((store, _lock)) => {
|
||||||
|
debug!("Loaded credential file {}", path.display());
|
||||||
|
Some(store)
|
||||||
|
}
|
||||||
|
Err(TomlCredentialError::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => {
|
||||||
|
debug!("No credentials file found at {}", path.display());
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
warn!(
|
||||||
|
"Failed to load credentials from {}: {}",
|
||||||
|
path.display(),
|
||||||
|
err
|
||||||
|
);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextStoreMode {
|
impl TextStoreMode {
|
||||||
async fn load_default_store() -> Option<TextCredentialStore> {
|
|
||||||
let path = TextCredentialStore::default_file()
|
|
||||||
.inspect_err(|err| {
|
|
||||||
warn!("Failed to determine credentials file path: {}", err);
|
|
||||||
})
|
|
||||||
.ok()?;
|
|
||||||
|
|
||||||
match TextCredentialStore::read(&path).await {
|
|
||||||
Ok((store, _lock)) => {
|
|
||||||
debug!("Loaded credential file {}", path.display());
|
|
||||||
Some(store)
|
|
||||||
}
|
|
||||||
Err(err)
|
|
||||||
if err
|
|
||||||
.as_io_error()
|
|
||||||
.is_some_and(|err| err.kind() == std::io::ErrorKind::NotFound) =>
|
|
||||||
{
|
|
||||||
debug!("No credentials file found at {}", path.display());
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
warn!(
|
|
||||||
"Failed to load credentials from {}: {}",
|
|
||||||
path.display(),
|
|
||||||
err
|
|
||||||
);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the parsed credential store, if enabled.
|
/// Get the parsed credential store, if enabled.
|
||||||
async fn get(&self) -> Option<&TextCredentialStore> {
|
fn get(&self) -> Option<&TextCredentialStore> {
|
||||||
match self {
|
match self {
|
||||||
// TODO(zanieb): Reconsider this pattern. We're just mirroring the [`NetrcMode`]
|
Self::Automatic(lock) => lock.as_ref(),
|
||||||
// implementation for now.
|
|
||||||
Self::Automatic(lock) => lock.get_or_init(Self::load_default_store).await.as_ref(),
|
|
||||||
Self::Enabled(store) => Some(store),
|
Self::Enabled(store) => Some(store),
|
||||||
Self::Disabled => None,
|
Self::Disabled => None,
|
||||||
}
|
}
|
||||||
|
|
@ -129,15 +123,6 @@ enum TokenState {
|
||||||
Initialized(Option<AccessToken>),
|
Initialized(Option<AccessToken>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
enum S3CredentialState {
|
|
||||||
/// The S3 credential state has not yet been initialized.
|
|
||||||
Uninitialized,
|
|
||||||
/// The S3 credential state has been initialized, with either a signer or `None` if
|
|
||||||
/// no S3 endpoint is configured.
|
|
||||||
Initialized(Option<Arc<Authentication>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A middleware that adds basic authentication to requests.
|
/// A middleware that adds basic authentication to requests.
|
||||||
///
|
///
|
||||||
/// Uses a cache to propagate credentials from previously seen requests and
|
/// Uses a cache to propagate credentials from previously seen requests and
|
||||||
|
|
@ -146,8 +131,7 @@ pub struct AuthMiddleware {
|
||||||
netrc: NetrcMode,
|
netrc: NetrcMode,
|
||||||
text_store: TextStoreMode,
|
text_store: TextStoreMode,
|
||||||
keyring: Option<KeyringProvider>,
|
keyring: Option<KeyringProvider>,
|
||||||
/// Global authentication cache for a uv invocation to share credentials across uv clients.
|
cache: Option<CredentialsCache>,
|
||||||
cache: Arc<CredentialsCache>,
|
|
||||||
/// Auth policies for specific URLs.
|
/// Auth policies for specific URLs.
|
||||||
indexes: Indexes,
|
indexes: Indexes,
|
||||||
/// Set all endpoints as needing authentication. We never try to send an
|
/// Set all endpoints as needing authentication. We never try to send an
|
||||||
|
|
@ -159,31 +143,21 @@ pub struct AuthMiddleware {
|
||||||
pyx_token_store: Option<PyxTokenStore>,
|
pyx_token_store: Option<PyxTokenStore>,
|
||||||
/// Tokens to use for persistent credentials.
|
/// Tokens to use for persistent credentials.
|
||||||
pyx_token_state: Mutex<TokenState>,
|
pyx_token_state: Mutex<TokenState>,
|
||||||
/// Cached S3 credentials to avoid running the credential helper multiple times.
|
|
||||||
s3_credential_state: Mutex<S3CredentialState>,
|
|
||||||
preview: Preview,
|
preview: Preview,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for AuthMiddleware {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AuthMiddleware {
|
impl AuthMiddleware {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
netrc: NetrcMode::default(),
|
netrc: NetrcMode::default(),
|
||||||
text_store: TextStoreMode::default(),
|
text_store: TextStoreMode::default(),
|
||||||
keyring: None,
|
keyring: None,
|
||||||
// TODO(konsti): There shouldn't be a credential cache without that in the initializer.
|
cache: None,
|
||||||
cache: Arc::new(CredentialsCache::default()),
|
|
||||||
indexes: Indexes::new(),
|
indexes: Indexes::new(),
|
||||||
only_authenticated: false,
|
only_authenticated: false,
|
||||||
base_client: None,
|
base_client: None,
|
||||||
pyx_token_store: None,
|
pyx_token_store: None,
|
||||||
pyx_token_state: Mutex::new(TokenState::Uninitialized),
|
pyx_token_state: Mutex::new(TokenState::Uninitialized),
|
||||||
s3_credential_state: Mutex::new(S3CredentialState::Uninitialized),
|
|
||||||
preview: Preview::default(),
|
preview: Preview::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -231,14 +205,7 @@ impl AuthMiddleware {
|
||||||
/// Configure the [`CredentialsCache`] to use.
|
/// Configure the [`CredentialsCache`] to use.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_cache(mut self, cache: CredentialsCache) -> Self {
|
pub fn with_cache(mut self, cache: CredentialsCache) -> Self {
|
||||||
self.cache = Arc::new(cache);
|
self.cache = Some(cache);
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Configure the [`CredentialsCache`] to use from an existing [`Arc`].
|
|
||||||
#[must_use]
|
|
||||||
pub fn with_cache_arc(mut self, cache: Arc<CredentialsCache>) -> Self {
|
|
||||||
self.cache = cache;
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -271,9 +238,17 @@ impl AuthMiddleware {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Global authentication cache for a uv invocation to share credentials across uv clients.
|
/// Get the configured authentication store.
|
||||||
|
///
|
||||||
|
/// If not set, the global store is used.
|
||||||
fn cache(&self) -> &CredentialsCache {
|
fn cache(&self) -> &CredentialsCache {
|
||||||
&self.cache
|
self.cache.as_ref().unwrap_or(&CREDENTIALS_CACHE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for AuthMiddleware {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -690,26 +665,13 @@ impl AuthMiddleware {
|
||||||
return Some(credentials);
|
return Some(credentials);
|
||||||
}
|
}
|
||||||
|
|
||||||
if S3EndpointProvider::is_s3_endpoint(url, self.preview) {
|
if let Some(credentials) = S3EndpointProvider::credentials_for(url, self.preview)
|
||||||
let mut s3_state = self.s3_credential_state.lock().await;
|
.map(Authentication::from)
|
||||||
|
.map(Arc::new)
|
||||||
// If the S3 credential state is uninitialized, initialize it.
|
{
|
||||||
let credentials = match &*s3_state {
|
debug!("Found S3 credentials for {url}");
|
||||||
S3CredentialState::Uninitialized => {
|
self.cache().fetches.done(key, Some(credentials.clone()));
|
||||||
trace!("Initializing S3 credentials for {url}");
|
return Some(credentials);
|
||||||
let signer = S3EndpointProvider::create_signer();
|
|
||||||
let credentials = Arc::new(Authentication::from(signer));
|
|
||||||
*s3_state = S3CredentialState::Initialized(Some(credentials.clone()));
|
|
||||||
Some(credentials)
|
|
||||||
}
|
|
||||||
S3CredentialState::Initialized(credentials) => credentials.clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(credentials) = credentials {
|
|
||||||
debug!("Found S3 credentials for {url}");
|
|
||||||
self.cache().fetches.done(key, Some(credentials.clone()));
|
|
||||||
return Some(credentials);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a known URL, authenticate it via the token store.
|
// If this is a known URL, authenticate it via the token store.
|
||||||
|
|
@ -767,16 +729,9 @@ impl AuthMiddleware {
|
||||||
Some(credentials)
|
Some(credentials)
|
||||||
|
|
||||||
// Text credential store support.
|
// Text credential store support.
|
||||||
} else if let Some(credentials) = self.text_store.get().await.and_then(|text_store| {
|
} else if let Some(credentials) = self.text_store.get().and_then(|text_store| {
|
||||||
debug!("Checking text store for credentials for {url}");
|
debug!("Checking text store for credentials for {url}");
|
||||||
text_store
|
text_store.get_credentials(url, credentials.as_ref().and_then(|credentials| credentials.username())).cloned()
|
||||||
.get_credentials(
|
|
||||||
url,
|
|
||||||
credentials
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|credentials| credentials.username()),
|
|
||||||
)
|
|
||||||
.cloned()
|
|
||||||
}) {
|
}) {
|
||||||
debug!("Found credentials in plaintext store for {url}");
|
debug!("Found credentials in plaintext store for {url}");
|
||||||
Some(credentials)
|
Some(credentials)
|
||||||
|
|
@ -792,16 +747,10 @@ impl AuthMiddleware {
|
||||||
if let Some(index) = index {
|
if let Some(index) = index {
|
||||||
// N.B. The native store performs an exact look up right now, so we use the root
|
// N.B. The native store performs an exact look up right now, so we use the root
|
||||||
// URL of the index instead of relying on prefix-matching.
|
// URL of the index instead of relying on prefix-matching.
|
||||||
debug!(
|
debug!("Checking native store for credentials for index URL {}{}", display_username, index.root_url);
|
||||||
"Checking native store for credentials for index URL {}{}",
|
|
||||||
display_username, index.root_url
|
|
||||||
);
|
|
||||||
native_store.fetch(&index.root_url, username).await
|
native_store.fetch(&index.root_url, username).await
|
||||||
} else {
|
} else {
|
||||||
debug!(
|
debug!("Checking native store for credentials for URL {}{}", display_username, url);
|
||||||
"Checking native store for credentials for URL {}{}",
|
|
||||||
display_username, url
|
|
||||||
);
|
|
||||||
native_store.fetch(url, username).await
|
native_store.fetch(url, username).await
|
||||||
}
|
}
|
||||||
// TODO(zanieb): We should have a realm fallback here too
|
// TODO(zanieb): We should have a realm fallback here too
|
||||||
|
|
@ -822,18 +771,10 @@ impl AuthMiddleware {
|
||||||
// always authenticate.
|
// always authenticate.
|
||||||
if let Some(username) = credentials.and_then(|credentials| credentials.username()) {
|
if let Some(username) = credentials.and_then(|credentials| credentials.username()) {
|
||||||
if let Some(index) = index {
|
if let Some(index) = index {
|
||||||
debug!(
|
debug!("Checking keyring for credentials for index URL {}@{}", username, index.url);
|
||||||
"Checking keyring for credentials for index URL {}@{}",
|
keyring.fetch(DisplaySafeUrl::ref_cast(&index.url), Some(username)).await
|
||||||
username, index.url
|
|
||||||
);
|
|
||||||
keyring
|
|
||||||
.fetch(DisplaySafeUrl::ref_cast(&index.url), Some(username))
|
|
||||||
.await
|
|
||||||
} else {
|
} else {
|
||||||
debug!(
|
debug!("Checking keyring for credentials for full URL {}@{}", username, url);
|
||||||
"Checking keyring for credentials for full URL {}@{}",
|
|
||||||
username, url
|
|
||||||
);
|
|
||||||
keyring.fetch(url, Some(username)).await
|
keyring.fetch(url, Some(username)).await
|
||||||
}
|
}
|
||||||
} else if matches!(auth_policy, AuthPolicy::Always) {
|
} else if matches!(auth_policy, AuthPolicy::Always) {
|
||||||
|
|
@ -842,16 +783,12 @@ impl AuthMiddleware {
|
||||||
"Checking keyring for credentials for index URL {} without username due to `authenticate = always`",
|
"Checking keyring for credentials for index URL {} without username due to `authenticate = always`",
|
||||||
index.url
|
index.url
|
||||||
);
|
);
|
||||||
keyring
|
keyring.fetch(DisplaySafeUrl::ref_cast(&index.url), None).await
|
||||||
.fetch(DisplaySafeUrl::ref_cast(&index.url), None)
|
|
||||||
.await
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
debug!(
|
debug!("Skipping keyring fetch for {url} without username; use `authenticate = always` to force");
|
||||||
"Skipping keyring fetch for {url} without username; use `authenticate = always` to force"
|
|
||||||
);
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -861,9 +798,9 @@ impl AuthMiddleware {
|
||||||
Some(credentials)
|
Some(credentials)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
}
|
||||||
|
.map(Authentication::from)
|
||||||
let credentials = credentials.map(Authentication::from).map(Arc::new);
|
.map(Arc::new);
|
||||||
|
|
||||||
// Register the fetch for this key
|
// Register the fetch for this key
|
||||||
self.cache().fetches.done(key, credentials.clone());
|
self.cache().fetches.done(key, credentials.clone());
|
||||||
|
|
|
||||||
|
|
@ -66,8 +66,8 @@ static S3_ENDPOINT_REALM: LazyLock<Option<Realm>> = LazyLock::new(|| {
|
||||||
pub(crate) struct S3EndpointProvider;
|
pub(crate) struct S3EndpointProvider;
|
||||||
|
|
||||||
impl S3EndpointProvider {
|
impl S3EndpointProvider {
|
||||||
/// Returns `true` if the URL matches the configured S3 endpoint.
|
/// Returns the credentials for the S3 endpoint, if available.
|
||||||
pub(crate) fn is_s3_endpoint(url: &Url, preview: Preview) -> bool {
|
pub(crate) fn credentials_for(url: &Url, preview: Preview) -> Option<DefaultSigner> {
|
||||||
if let Some(s3_endpoint_realm) = S3_ENDPOINT_REALM.as_ref().map(RealmRef::from) {
|
if let Some(s3_endpoint_realm) = S3_ENDPOINT_REALM.as_ref().map(RealmRef::from) {
|
||||||
if !preview.is_enabled(PreviewFeatures::S3_ENDPOINT) {
|
if !preview.is_enabled(PreviewFeatures::S3_ENDPOINT) {
|
||||||
warn_user_once!(
|
warn_user_once!(
|
||||||
|
|
@ -79,26 +79,19 @@ impl S3EndpointProvider {
|
||||||
// Treat any URL on the same domain or subdomain as available for S3 signing.
|
// Treat any URL on the same domain or subdomain as available for S3 signing.
|
||||||
let realm = RealmRef::from(url);
|
let realm = RealmRef::from(url);
|
||||||
if realm == s3_endpoint_realm || realm.is_subdomain_of(s3_endpoint_realm) {
|
if realm == s3_endpoint_realm || realm.is_subdomain_of(s3_endpoint_realm) {
|
||||||
return true;
|
// TODO(charlie): Can `reqsign` infer the region for us? Profiles, for example,
|
||||||
|
// often have a region set already.
|
||||||
|
let region = std::env::var(EnvVars::AWS_REGION)
|
||||||
|
.map(Cow::Owned)
|
||||||
|
.unwrap_or_else(|_| {
|
||||||
|
std::env::var(EnvVars::AWS_DEFAULT_REGION)
|
||||||
|
.map(Cow::Owned)
|
||||||
|
.unwrap_or_else(|_| Cow::Borrowed("us-east-1"))
|
||||||
|
});
|
||||||
|
let signer = reqsign::aws::default_signer("s3", ®ion);
|
||||||
|
return Some(signer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
false
|
None
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new S3 signer with the configured region.
|
|
||||||
///
|
|
||||||
/// This is potentially expensive as it may invoke credential helpers, so the result
|
|
||||||
/// should be cached.
|
|
||||||
pub(crate) fn create_signer() -> DefaultSigner {
|
|
||||||
// TODO(charlie): Can `reqsign` infer the region for us? Profiles, for example,
|
|
||||||
// often have a region set already.
|
|
||||||
let region = std::env::var(EnvVars::AWS_REGION)
|
|
||||||
.map(Cow::Owned)
|
|
||||||
.unwrap_or_else(|_| {
|
|
||||||
std::env::var(EnvVars::AWS_DEFAULT_REGION)
|
|
||||||
.map(Cow::Owned)
|
|
||||||
.unwrap_or_else(|_| Cow::Borrowed("us-east-1"))
|
|
||||||
});
|
|
||||||
reqsign::aws::default_signer("s3", ®ion)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use fs_err as fs;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use uv_fs::{LockedFile, LockedFileError, LockedFileMode, with_added_extension};
|
use uv_fs::{LockedFile, with_added_extension};
|
||||||
use uv_preview::{Preview, PreviewFeatures};
|
use uv_preview::{Preview, PreviewFeatures};
|
||||||
use uv_redacted::DisplaySafeUrl;
|
use uv_redacted::DisplaySafeUrl;
|
||||||
|
|
||||||
|
|
@ -28,7 +28,7 @@ pub enum AuthBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AuthBackend {
|
impl AuthBackend {
|
||||||
pub async fn from_settings(preview: Preview) -> Result<Self, TomlCredentialError> {
|
pub fn from_settings(preview: Preview) -> Result<Self, TomlCredentialError> {
|
||||||
// If preview is enabled, we'll use the system-native store
|
// If preview is enabled, we'll use the system-native store
|
||||||
if preview.is_enabled(PreviewFeatures::NATIVE_AUTH) {
|
if preview.is_enabled(PreviewFeatures::NATIVE_AUTH) {
|
||||||
return Ok(Self::System(KeyringProvider::native()));
|
return Ok(Self::System(KeyringProvider::native()));
|
||||||
|
|
@ -36,16 +36,12 @@ impl AuthBackend {
|
||||||
|
|
||||||
// Otherwise, we'll use the plaintext credential store
|
// Otherwise, we'll use the plaintext credential store
|
||||||
let path = TextCredentialStore::default_file()?;
|
let path = TextCredentialStore::default_file()?;
|
||||||
match TextCredentialStore::read(&path).await {
|
match TextCredentialStore::read(&path) {
|
||||||
Ok((store, lock)) => Ok(Self::TextStore(store, lock)),
|
Ok((store, lock)) => Ok(Self::TextStore(store, lock)),
|
||||||
Err(err)
|
Err(TomlCredentialError::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => {
|
||||||
if err
|
|
||||||
.as_io_error()
|
|
||||||
.is_some_and(|err| err.kind() == std::io::ErrorKind::NotFound) =>
|
|
||||||
{
|
|
||||||
Ok(Self::TextStore(
|
Ok(Self::TextStore(
|
||||||
TextCredentialStore::default(),
|
TextCredentialStore::default(),
|
||||||
TextCredentialStore::lock(&path).await?,
|
TextCredentialStore::lock(&path)?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Err(err) => Err(err),
|
Err(err) => Err(err),
|
||||||
|
|
@ -73,8 +69,6 @@ pub enum AuthScheme {
|
||||||
pub enum TomlCredentialError {
|
pub enum TomlCredentialError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
#[error(transparent)]
|
|
||||||
LockedFile(#[from] LockedFileError),
|
|
||||||
#[error("Failed to parse TOML credential file: {0}")]
|
#[error("Failed to parse TOML credential file: {0}")]
|
||||||
ParseError(#[from] toml::de::Error),
|
ParseError(#[from] toml::de::Error),
|
||||||
#[error("Failed to serialize credentials to TOML")]
|
#[error("Failed to serialize credentials to TOML")]
|
||||||
|
|
@ -89,21 +83,6 @@ pub enum TomlCredentialError {
|
||||||
TokenNotUnicode(#[from] std::string::FromUtf8Error),
|
TokenNotUnicode(#[from] std::string::FromUtf8Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TomlCredentialError {
|
|
||||||
pub fn as_io_error(&self) -> Option<&std::io::Error> {
|
|
||||||
match self {
|
|
||||||
Self::Io(err) => Some(err),
|
|
||||||
Self::LockedFile(err) => err.as_io_error(),
|
|
||||||
Self::ParseError(_)
|
|
||||||
| Self::SerializeError(_)
|
|
||||||
| Self::BasicAuthError(_)
|
|
||||||
| Self::BearerAuthError(_)
|
|
||||||
| Self::CredentialsDirError
|
|
||||||
| Self::TokenNotUnicode(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum BasicAuthError {
|
pub enum BasicAuthError {
|
||||||
#[error("`username` is required with `scheme = basic`")]
|
#[error("`username` is required with `scheme = basic`")]
|
||||||
|
|
@ -254,12 +233,12 @@ impl TextCredentialStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Acquire a lock on the credentials file at the given path.
|
/// Acquire a lock on the credentials file at the given path.
|
||||||
pub async fn lock(path: &Path) -> Result<LockedFile, TomlCredentialError> {
|
pub fn lock(path: &Path) -> Result<LockedFile, TomlCredentialError> {
|
||||||
if let Some(parent) = path.parent() {
|
if let Some(parent) = path.parent() {
|
||||||
fs::create_dir_all(parent)?;
|
fs::create_dir_all(parent)?;
|
||||||
}
|
}
|
||||||
let lock = with_added_extension(path, ".lock");
|
let lock = with_added_extension(path, ".lock");
|
||||||
Ok(LockedFile::acquire(lock, LockedFileMode::Exclusive, "credentials store").await?)
|
Ok(LockedFile::acquire_blocking(lock, "credentials store")?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read credentials from a file.
|
/// Read credentials from a file.
|
||||||
|
|
@ -290,8 +269,8 @@ impl TextCredentialStore {
|
||||||
/// Returns [`TextCredentialStore`] and a [`LockedFile`] to hold if mutating the store.
|
/// Returns [`TextCredentialStore`] and a [`LockedFile`] to hold if mutating the store.
|
||||||
///
|
///
|
||||||
/// If the store will not be written to following the read, the lock can be dropped.
|
/// If the store will not be written to following the read, the lock can be dropped.
|
||||||
pub async fn read<P: AsRef<Path>>(path: P) -> Result<(Self, LockedFile), TomlCredentialError> {
|
pub fn read<P: AsRef<Path>>(path: P) -> Result<(Self, LockedFile), TomlCredentialError> {
|
||||||
let lock = Self::lock(path.as_ref()).await?;
|
let lock = Self::lock(path.as_ref())?;
|
||||||
let store = Self::from_file(path)?;
|
let store = Self::from_file(path)?;
|
||||||
Ok((store, lock))
|
Ok((store, lock))
|
||||||
}
|
}
|
||||||
|
|
@ -471,8 +450,8 @@ mod tests {
|
||||||
assert!(store.get_credentials(&url, None).is_none());
|
assert!(store.get_credentials(&url, None).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[test]
|
||||||
async fn test_file_operations() {
|
fn test_file_operations() {
|
||||||
let mut temp_file = NamedTempFile::new().unwrap();
|
let mut temp_file = NamedTempFile::new().unwrap();
|
||||||
writeln!(
|
writeln!(
|
||||||
temp_file,
|
temp_file,
|
||||||
|
|
@ -508,7 +487,7 @@ password = "pass2"
|
||||||
store
|
store
|
||||||
.write(
|
.write(
|
||||||
temp_output.path(),
|
temp_output.path(),
|
||||||
TextCredentialStore::lock(temp_file.path()).await.unwrap(),
|
TextCredentialStore::lock(temp_file.path()).unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-bench"
|
name = "uv-bench"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
description = "This is an internal component crate of uv"
|
description = "This is an internal component crate of uv"
|
||||||
publish = false
|
publish = false
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
|
|
@ -22,14 +22,14 @@ name = "uv"
|
||||||
path = "benches/uv.rs"
|
path = "benches/uv.rs"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
[dev-dependencies]
|
[dependencies]
|
||||||
uv-cache = { workspace = true }
|
uv-cache = { workspace = true }
|
||||||
uv-client = { workspace = true }
|
uv-client = { workspace = true }
|
||||||
uv-configuration = { workspace = true }
|
uv-configuration = { workspace = true }
|
||||||
uv-dispatch = { workspace = true }
|
uv-dispatch = { workspace = true }
|
||||||
uv-distribution = { workspace = true }
|
uv-distribution = { workspace = true }
|
||||||
uv-distribution-types = { workspace = true }
|
uv-distribution-types = { workspace = true }
|
||||||
uv-extract = { workspace = true }
|
uv-extract = { workspace = true, optional = true }
|
||||||
uv-install-wheel = { workspace = true }
|
uv-install-wheel = { workspace = true }
|
||||||
uv-pep440 = { workspace = true }
|
uv-pep440 = { workspace = true }
|
||||||
uv-pep508 = { workspace = true }
|
uv-pep508 = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@
|
||||||
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
||||||
is unstable and will have frequent breaking changes.
|
is unstable and will have frequent breaking changes.
|
||||||
|
|
||||||
This version (0.0.8) is a component of [uv 0.9.18](https://crates.io/crates/uv/0.9.18). The source
|
|
||||||
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-bench).
|
|
||||||
|
|
||||||
See uv's
|
See uv's
|
||||||
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
||||||
for details on versioning.
|
for details on versioning.
|
||||||
|
|
|
||||||
|
|
@ -59,10 +59,7 @@ fn setup(manifest: Manifest) -> impl Fn(bool) {
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let cache = Cache::from_path("../../.cache")
|
let cache = Cache::from_path("../../.cache").init().unwrap();
|
||||||
.init_no_wait()
|
|
||||||
.expect("No cache contention when running benchmarks")
|
|
||||||
.unwrap();
|
|
||||||
let interpreter = PythonEnvironment::from_root("../../.venv", &cache)
|
let interpreter = PythonEnvironment::from_root("../../.venv", &cache)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into_interpreter();
|
.into_interpreter();
|
||||||
|
|
@ -134,7 +131,7 @@ mod resolver {
|
||||||
);
|
);
|
||||||
|
|
||||||
static TAGS: LazyLock<Tags> = LazyLock::new(|| {
|
static TAGS: LazyLock<Tags> = LazyLock::new(|| {
|
||||||
Tags::from_env(&PLATFORM, (3, 11), "cpython", (3, 11), false, false, false).unwrap()
|
Tags::from_env(&PLATFORM, (3, 11), "cpython", (3, 11), false, false).unwrap()
|
||||||
});
|
});
|
||||||
|
|
||||||
pub(crate) async fn resolve(
|
pub(crate) async fn resolve(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-bin-install"
|
name = "uv-bin-install"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
description = "This is an internal component crate of uv"
|
description = "This is an internal component crate of uv"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
@ -23,7 +23,6 @@ uv-extract = { workspace = true }
|
||||||
uv-pep440 = { workspace = true }
|
uv-pep440 = { workspace = true }
|
||||||
uv-platform = { workspace = true }
|
uv-platform = { workspace = true }
|
||||||
uv-redacted = { workspace = true }
|
uv-redacted = { workspace = true }
|
||||||
|
|
||||||
fs-err = { workspace = true, features = ["tokio"] }
|
fs-err = { workspace = true, features = ["tokio"] }
|
||||||
futures = { workspace = true }
|
futures = { workspace = true }
|
||||||
reqwest = { workspace = true }
|
reqwest = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@
|
||||||
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
||||||
is unstable and will have frequent breaking changes.
|
is unstable and will have frequent breaking changes.
|
||||||
|
|
||||||
This version (0.0.8) is a component of [uv 0.9.18](https://crates.io/crates/uv/0.9.18). The source
|
|
||||||
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-bin-install).
|
|
||||||
|
|
||||||
See uv's
|
See uv's
|
||||||
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
||||||
for details on versioning.
|
for details on versioning.
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ use tracing::debug;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use uv_distribution_filename::SourceDistExtension;
|
use uv_distribution_filename::SourceDistExtension;
|
||||||
|
|
||||||
use uv_cache::{Cache, CacheBucket, CacheEntry, Error as CacheError};
|
use uv_cache::{Cache, CacheBucket, CacheEntry};
|
||||||
use uv_client::{BaseClient, is_transient_network_error};
|
use uv_client::{BaseClient, is_transient_network_error};
|
||||||
use uv_extract::{Error as ExtractError, stream};
|
use uv_extract::{Error as ExtractError, stream};
|
||||||
use uv_pep440::Version;
|
use uv_pep440::Version;
|
||||||
|
|
@ -135,9 +135,6 @@ pub enum Error {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
|
|
||||||
#[error(transparent)]
|
|
||||||
Cache(#[from] CacheError),
|
|
||||||
|
|
||||||
#[error("Failed to detect platform")]
|
#[error("Failed to detect platform")]
|
||||||
Platform(#[from] uv_platform::Error),
|
Platform(#[from] uv_platform::Error),
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-build-backend"
|
name = "uv-build-backend"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
description = "This is an internal component crate of uv"
|
description = "This is an internal component crate of uv"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@
|
||||||
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
||||||
is unstable and will have frequent breaking changes.
|
is unstable and will have frequent breaking changes.
|
||||||
|
|
||||||
This version (0.0.8) is a component of [uv 0.9.18](https://crates.io/crates/uv/0.9.18). The source
|
|
||||||
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-build-backend).
|
|
||||||
|
|
||||||
See uv's
|
See uv's
|
||||||
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
||||||
for details on versioning.
|
for details on versioning.
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
use itertools::Itertools;
|
|
||||||
mod metadata;
|
mod metadata;
|
||||||
mod serde_verbatim;
|
mod serde_verbatim;
|
||||||
mod settings;
|
mod settings;
|
||||||
|
|
@ -8,10 +7,8 @@ mod wheel;
|
||||||
pub use metadata::{PyProjectToml, check_direct_build};
|
pub use metadata::{PyProjectToml, check_direct_build};
|
||||||
pub use settings::{BuildBackendSettings, WheelDataIncludes};
|
pub use settings::{BuildBackendSettings, WheelDataIncludes};
|
||||||
pub use source_dist::{build_source_dist, list_source_dist};
|
pub use source_dist::{build_source_dist, list_source_dist};
|
||||||
use uv_warnings::warn_user_once;
|
|
||||||
pub use wheel::{build_editable, build_wheel, list_wheel, metadata};
|
pub use wheel::{build_editable, build_wheel, list_wheel, metadata};
|
||||||
|
|
||||||
use std::collections::HashSet;
|
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
@ -32,9 +29,9 @@ use crate::settings::ModuleName;
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Io(#[from] io::Error),
|
Io(#[from] io::Error),
|
||||||
#[error("Invalid metadata format in: {}", _0.user_display())]
|
#[error("Invalid pyproject.toml")]
|
||||||
Toml(PathBuf, #[source] toml::de::Error),
|
Toml(#[from] toml::de::Error),
|
||||||
#[error("Invalid project metadata")]
|
#[error("Invalid pyproject.toml")]
|
||||||
Validation(#[from] ValidationError),
|
Validation(#[from] ValidationError),
|
||||||
#[error("Invalid module name: {0}")]
|
#[error("Invalid module name: {0}")]
|
||||||
InvalidModuleName(String, #[source] IdentifierParseError),
|
InvalidModuleName(String, #[source] IdentifierParseError),
|
||||||
|
|
@ -194,60 +191,6 @@ fn check_metadata_directory(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the list of module names without names which would be included twice
|
|
||||||
///
|
|
||||||
/// In normal cases it should do nothing:
|
|
||||||
///
|
|
||||||
/// * `["aaa"] -> ["aaa"]`
|
|
||||||
/// * `["aaa", "bbb"] -> ["aaa", "bbb"]`
|
|
||||||
///
|
|
||||||
/// Duplicate elements are removed:
|
|
||||||
///
|
|
||||||
/// * `["aaa", "aaa"] -> ["aaa"]`
|
|
||||||
/// * `["bbb", "aaa", "bbb"] -> ["aaa", "bbb"]`
|
|
||||||
///
|
|
||||||
/// Names with more specific paths are removed in favour of more general paths:
|
|
||||||
///
|
|
||||||
/// * `["aaa.foo", "aaa"] -> ["aaa"]`
|
|
||||||
/// * `["bbb", "aaa", "bbb.foo", "ccc.foo", "ccc.foo.bar", "aaa"] -> ["aaa", "bbb.foo", "ccc.foo"]`
|
|
||||||
///
|
|
||||||
/// This does not preserve the order of the elements.
|
|
||||||
fn prune_redundant_modules(mut names: Vec<String>) -> Vec<String> {
|
|
||||||
names.sort();
|
|
||||||
let mut pruned = Vec::with_capacity(names.len());
|
|
||||||
for name in names {
|
|
||||||
if let Some(last) = pruned.last() {
|
|
||||||
if name == *last {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// This is a more specific (narrow) module name than what came before
|
|
||||||
if name
|
|
||||||
.strip_prefix(last)
|
|
||||||
.is_some_and(|suffix| suffix.starts_with('.'))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pruned.push(name);
|
|
||||||
}
|
|
||||||
pruned
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wraps [`prune_redundant_modules`] with a conditional warning when modules are ignored
|
|
||||||
fn prune_redundant_modules_warn(names: &[String], show_warnings: bool) -> Vec<String> {
|
|
||||||
let pruned = prune_redundant_modules(names.to_vec());
|
|
||||||
if show_warnings && names.len() != pruned.len() {
|
|
||||||
let mut pruned: HashSet<_> = pruned.iter().collect();
|
|
||||||
let ignored: Vec<_> = names.iter().filter(|name| !pruned.remove(name)).collect();
|
|
||||||
let s = if ignored.len() == 1 { "" } else { "s" };
|
|
||||||
warn_user_once!(
|
|
||||||
"Ignoring redundant module name{s} in `tool.uv.build-backend.module-name`: `{}`",
|
|
||||||
ignored.into_iter().join("`, `")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
pruned
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the source root and the module path(s) with the `__init__.py[i]` below to it while
|
/// Returns the source root and the module path(s) with the `__init__.py[i]` below to it while
|
||||||
/// checking the project layout and names.
|
/// checking the project layout and names.
|
||||||
///
|
///
|
||||||
|
|
@ -270,7 +213,6 @@ fn find_roots(
|
||||||
relative_module_root: &Path,
|
relative_module_root: &Path,
|
||||||
module_name: Option<&ModuleName>,
|
module_name: Option<&ModuleName>,
|
||||||
namespace: bool,
|
namespace: bool,
|
||||||
show_warnings: bool,
|
|
||||||
) -> Result<(PathBuf, Vec<PathBuf>), Error> {
|
) -> Result<(PathBuf, Vec<PathBuf>), Error> {
|
||||||
let relative_module_root = uv_fs::normalize_path(relative_module_root);
|
let relative_module_root = uv_fs::normalize_path(relative_module_root);
|
||||||
// Check that even if a path contains `..`, we only include files below the module root.
|
// Check that even if a path contains `..`, we only include files below the module root.
|
||||||
|
|
@ -289,8 +231,8 @@ fn find_roots(
|
||||||
ModuleName::Name(name) => {
|
ModuleName::Name(name) => {
|
||||||
vec![name.split('.').collect::<PathBuf>()]
|
vec![name.split('.').collect::<PathBuf>()]
|
||||||
}
|
}
|
||||||
ModuleName::Names(names) => prune_redundant_modules_warn(names, show_warnings)
|
ModuleName::Names(names) => names
|
||||||
.into_iter()
|
.iter()
|
||||||
.map(|name| name.split('.').collect::<PathBuf>())
|
.map(|name| name.split('.').collect::<PathBuf>())
|
||||||
.collect(),
|
.collect(),
|
||||||
}
|
}
|
||||||
|
|
@ -308,9 +250,9 @@ fn find_roots(
|
||||||
let modules_relative = if let Some(module_name) = module_name {
|
let modules_relative = if let Some(module_name) = module_name {
|
||||||
match module_name {
|
match module_name {
|
||||||
ModuleName::Name(name) => vec![module_path_from_module_name(&src_root, name)?],
|
ModuleName::Name(name) => vec![module_path_from_module_name(&src_root, name)?],
|
||||||
ModuleName::Names(names) => prune_redundant_modules_warn(names, show_warnings)
|
ModuleName::Names(names) => names
|
||||||
.into_iter()
|
.iter()
|
||||||
.map(|name| module_path_from_module_name(&src_root, &name))
|
.map(|name| module_path_from_module_name(&src_root, name))
|
||||||
.collect::<Result<_, _>>()?,
|
.collect::<Result<_, _>>()?,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -478,20 +420,19 @@ mod tests {
|
||||||
fn build(source_root: &Path, dist: &Path) -> Result<BuildResults, Error> {
|
fn build(source_root: &Path, dist: &Path) -> Result<BuildResults, Error> {
|
||||||
// Build a direct wheel, capture all its properties to compare it with the indirect wheel
|
// Build a direct wheel, capture all its properties to compare it with the indirect wheel
|
||||||
// latest and remove it since it has the same filename as the indirect wheel.
|
// latest and remove it since it has the same filename as the indirect wheel.
|
||||||
let (_name, direct_wheel_list_files) = list_wheel(source_root, MOCK_UV_VERSION, false)?;
|
let (_name, direct_wheel_list_files) = list_wheel(source_root, MOCK_UV_VERSION)?;
|
||||||
let direct_wheel_filename = build_wheel(source_root, dist, None, MOCK_UV_VERSION, false)?;
|
let direct_wheel_filename = build_wheel(source_root, dist, None, MOCK_UV_VERSION)?;
|
||||||
let direct_wheel_path = dist.join(direct_wheel_filename.to_string());
|
let direct_wheel_path = dist.join(direct_wheel_filename.to_string());
|
||||||
let direct_wheel_contents = wheel_contents(&direct_wheel_path);
|
let direct_wheel_contents = wheel_contents(&direct_wheel_path);
|
||||||
let direct_wheel_hash = sha2::Sha256::digest(fs_err::read(&direct_wheel_path)?);
|
let direct_wheel_hash = sha2::Sha256::digest(fs_err::read(&direct_wheel_path)?);
|
||||||
fs_err::remove_file(&direct_wheel_path)?;
|
fs_err::remove_file(&direct_wheel_path)?;
|
||||||
|
|
||||||
// Build a source distribution.
|
// Build a source distribution.
|
||||||
let (_name, source_dist_list_files) =
|
let (_name, source_dist_list_files) = list_source_dist(source_root, MOCK_UV_VERSION)?;
|
||||||
list_source_dist(source_root, MOCK_UV_VERSION, false)?;
|
|
||||||
// TODO(konsti): This should run in the unpacked source dist tempdir, but we need to
|
// TODO(konsti): This should run in the unpacked source dist tempdir, but we need to
|
||||||
// normalize the path.
|
// normalize the path.
|
||||||
let (_name, wheel_list_files) = list_wheel(source_root, MOCK_UV_VERSION, false)?;
|
let (_name, wheel_list_files) = list_wheel(source_root, MOCK_UV_VERSION)?;
|
||||||
let source_dist_filename = build_source_dist(source_root, dist, MOCK_UV_VERSION, false)?;
|
let source_dist_filename = build_source_dist(source_root, dist, MOCK_UV_VERSION)?;
|
||||||
let source_dist_path = dist.join(source_dist_filename.to_string());
|
let source_dist_path = dist.join(source_dist_filename.to_string());
|
||||||
let source_dist_contents = sdist_contents(&source_dist_path);
|
let source_dist_contents = sdist_contents(&source_dist_path);
|
||||||
|
|
||||||
|
|
@ -505,13 +446,7 @@ mod tests {
|
||||||
source_dist_filename.name.as_dist_info_name(),
|
source_dist_filename.name.as_dist_info_name(),
|
||||||
source_dist_filename.version
|
source_dist_filename.version
|
||||||
));
|
));
|
||||||
let wheel_filename = build_wheel(
|
let wheel_filename = build_wheel(&sdist_top_level_directory, dist, None, MOCK_UV_VERSION)?;
|
||||||
&sdist_top_level_directory,
|
|
||||||
dist,
|
|
||||||
None,
|
|
||||||
MOCK_UV_VERSION,
|
|
||||||
false,
|
|
||||||
)?;
|
|
||||||
let wheel_contents = wheel_contents(&dist.join(wheel_filename.to_string()));
|
let wheel_contents = wheel_contents(&dist.join(wheel_filename.to_string()));
|
||||||
|
|
||||||
// Check that direct and indirect wheels are identical.
|
// Check that direct and indirect wheels are identical.
|
||||||
|
|
@ -599,7 +534,7 @@ mod tests {
|
||||||
/// platform-independent deterministic builds.
|
/// platform-independent deterministic builds.
|
||||||
#[test]
|
#[test]
|
||||||
fn built_by_uv_building() {
|
fn built_by_uv_building() {
|
||||||
let built_by_uv = Path::new("../../test/packages/built-by-uv");
|
let built_by_uv = Path::new("../../scripts/packages/built-by-uv");
|
||||||
let src = TempDir::new().unwrap();
|
let src = TempDir::new().unwrap();
|
||||||
for dir in [
|
for dir in [
|
||||||
"src",
|
"src",
|
||||||
|
|
@ -662,7 +597,7 @@ mod tests {
|
||||||
// Check that the source dist is reproducible across platforms.
|
// Check that the source dist is reproducible across platforms.
|
||||||
assert_snapshot!(
|
assert_snapshot!(
|
||||||
format!("{:x}", sha2::Sha256::digest(fs_err::read(&source_dist_path).unwrap())),
|
format!("{:x}", sha2::Sha256::digest(fs_err::read(&source_dist_path).unwrap())),
|
||||||
@"bb74bff575b135bb39e5c9bce56349441fb0923bb8857e32a5eaf34ec1843967"
|
@"871d1f859140721b67cbeaca074e7a2740c88c38028d0509eba87d1285f1da9e"
|
||||||
);
|
);
|
||||||
// Check both the files we report and the actual files
|
// Check both the files we report and the actual files
|
||||||
assert_snapshot!(format_file_list(build.source_dist_list_files, src.path()), @r"
|
assert_snapshot!(format_file_list(build.source_dist_list_files, src.path()), @r"
|
||||||
|
|
@ -821,7 +756,7 @@ mod tests {
|
||||||
|
|
||||||
// Build a wheel from a source distribution
|
// Build a wheel from a source distribution
|
||||||
let output_dir = TempDir::new().unwrap();
|
let output_dir = TempDir::new().unwrap();
|
||||||
build_source_dist(src.path(), output_dir.path(), "0.5.15", false).unwrap();
|
build_source_dist(src.path(), output_dir.path(), "0.5.15").unwrap();
|
||||||
let sdist_tree = TempDir::new().unwrap();
|
let sdist_tree = TempDir::new().unwrap();
|
||||||
let source_dist_path = output_dir.path().join("pep_pep639_license-1.0.0.tar.gz");
|
let source_dist_path = output_dir.path().join("pep_pep639_license-1.0.0.tar.gz");
|
||||||
let sdist_reader = BufReader::new(File::open(&source_dist_path).unwrap());
|
let sdist_reader = BufReader::new(File::open(&source_dist_path).unwrap());
|
||||||
|
|
@ -832,7 +767,6 @@ mod tests {
|
||||||
output_dir.path(),
|
output_dir.path(),
|
||||||
None,
|
None,
|
||||||
"0.5.15",
|
"0.5.15",
|
||||||
false,
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let wheel = output_dir
|
let wheel = output_dir
|
||||||
|
|
@ -897,7 +831,6 @@ mod tests {
|
||||||
output_dir.path(),
|
output_dir.path(),
|
||||||
Some(&metadata_dir.path().join(&dist_info_dir)),
|
Some(&metadata_dir.path().join(&dist_info_dir)),
|
||||||
"0.5.15",
|
"0.5.15",
|
||||||
false,
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let wheel = output_dir
|
let wheel = output_dir
|
||||||
|
|
@ -1481,114 +1414,4 @@ mod tests {
|
||||||
simple_namespace_part-1.0.0.dist-info/WHEEL
|
simple_namespace_part-1.0.0.dist-info/WHEEL
|
||||||
");
|
");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `prune_redundant_modules` should remove modules which are already
|
|
||||||
/// included (either directly or via their parent)
|
|
||||||
#[test]
|
|
||||||
fn test_prune_redundant_modules() {
|
|
||||||
fn check(input: &[&str], expect: &[&str]) {
|
|
||||||
let input = input.iter().map(|s| (*s).to_string()).collect();
|
|
||||||
let expect: Vec<_> = expect.iter().map(|s| (*s).to_string()).collect();
|
|
||||||
assert_eq!(prune_redundant_modules(input), expect);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Basic cases
|
|
||||||
check(&[], &[]);
|
|
||||||
check(&["foo"], &["foo"]);
|
|
||||||
check(&["foo", "bar"], &["bar", "foo"]);
|
|
||||||
|
|
||||||
// Deshadowing
|
|
||||||
check(&["foo", "foo.bar"], &["foo"]);
|
|
||||||
check(&["foo.bar", "foo"], &["foo"]);
|
|
||||||
check(
|
|
||||||
&["foo.bar.a", "foo.bar.b", "foo.bar", "foo", "foo.bar.a.c"],
|
|
||||||
&["foo"],
|
|
||||||
);
|
|
||||||
check(
|
|
||||||
&["bar.one", "bar.two", "baz", "bar", "baz.one"],
|
|
||||||
&["bar", "baz"],
|
|
||||||
);
|
|
||||||
|
|
||||||
// Potential false positives
|
|
||||||
check(&["foo", "foobar"], &["foo", "foobar"]);
|
|
||||||
check(
|
|
||||||
&["foo", "foobar", "foo.bar", "foobar.baz"],
|
|
||||||
&["foo", "foobar"],
|
|
||||||
);
|
|
||||||
check(&["foo.bar", "foo.baz"], &["foo.bar", "foo.baz"]);
|
|
||||||
check(&["foo", "foo", "foo.bar", "foo.bar"], &["foo"]);
|
|
||||||
|
|
||||||
// Everything
|
|
||||||
check(
|
|
||||||
&[
|
|
||||||
"foo.inner",
|
|
||||||
"foo.inner.deeper",
|
|
||||||
"foo",
|
|
||||||
"bar",
|
|
||||||
"bar.sub",
|
|
||||||
"bar.sub.deep",
|
|
||||||
"foobar",
|
|
||||||
"baz.baz.bar",
|
|
||||||
"baz.baz",
|
|
||||||
"qux",
|
|
||||||
],
|
|
||||||
&["bar", "baz.baz", "foo", "foobar", "qux"],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A package with duplicate module names.
|
|
||||||
#[test]
|
|
||||||
fn duplicate_module_names() {
|
|
||||||
let src = TempDir::new().unwrap();
|
|
||||||
let pyproject_toml = indoc! {r#"
|
|
||||||
[project]
|
|
||||||
name = "duplicate"
|
|
||||||
version = "1.0.0"
|
|
||||||
|
|
||||||
[tool.uv.build-backend]
|
|
||||||
module-name = ["foo", "foo", "bar.baz", "bar.baz.submodule"]
|
|
||||||
|
|
||||||
[build-system]
|
|
||||||
requires = ["uv_build>=0.5.15,<0.6.0"]
|
|
||||||
build-backend = "uv_build"
|
|
||||||
"#
|
|
||||||
};
|
|
||||||
fs_err::write(src.path().join("pyproject.toml"), pyproject_toml).unwrap();
|
|
||||||
fs_err::create_dir_all(src.path().join("src").join("foo")).unwrap();
|
|
||||||
File::create(src.path().join("src").join("foo").join("__init__.py")).unwrap();
|
|
||||||
fs_err::create_dir_all(src.path().join("src").join("bar").join("baz")).unwrap();
|
|
||||||
File::create(
|
|
||||||
src.path()
|
|
||||||
.join("src")
|
|
||||||
.join("bar")
|
|
||||||
.join("baz")
|
|
||||||
.join("__init__.py"),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let dist = TempDir::new().unwrap();
|
|
||||||
let build = build(src.path(), dist.path()).unwrap();
|
|
||||||
assert_snapshot!(build.source_dist_contents.join("\n"), @r"
|
|
||||||
duplicate-1.0.0/
|
|
||||||
duplicate-1.0.0/PKG-INFO
|
|
||||||
duplicate-1.0.0/pyproject.toml
|
|
||||||
duplicate-1.0.0/src
|
|
||||||
duplicate-1.0.0/src/bar
|
|
||||||
duplicate-1.0.0/src/bar/baz
|
|
||||||
duplicate-1.0.0/src/bar/baz/__init__.py
|
|
||||||
duplicate-1.0.0/src/foo
|
|
||||||
duplicate-1.0.0/src/foo/__init__.py
|
|
||||||
");
|
|
||||||
assert_snapshot!(build.wheel_contents.join("\n"), @r"
|
|
||||||
bar/
|
|
||||||
bar/baz/
|
|
||||||
bar/baz/__init__.py
|
|
||||||
duplicate-1.0.0.dist-info/
|
|
||||||
duplicate-1.0.0.dist-info/METADATA
|
|
||||||
duplicate-1.0.0.dist-info/RECORD
|
|
||||||
duplicate-1.0.0.dist-info/WHEEL
|
|
||||||
foo/
|
|
||||||
foo/__init__.py
|
|
||||||
");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -154,11 +154,8 @@ impl PyProjectToml {
|
||||||
&self.project.version
|
&self.project.version
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn parse(path: &Path) -> Result<Self, Error> {
|
pub(crate) fn parse(contents: &str) -> Result<Self, Error> {
|
||||||
let contents = fs_err::read_to_string(path)?;
|
Ok(toml::from_str(contents)?)
|
||||||
let pyproject_toml =
|
|
||||||
toml::from_str(&contents).map_err(|err| Error::Toml(path.to_path_buf(), err))?;
|
|
||||||
Ok(pyproject_toml)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn readme(&self) -> Option<&Readme> {
|
pub(crate) fn readme(&self) -> Option<&Readme> {
|
||||||
|
|
@ -952,7 +949,7 @@ mod tests {
|
||||||
requires = ["uv_build>=0.4.15,<0.5.0"]
|
requires = ["uv_build>=0.4.15,<0.5.0"]
|
||||||
build-backend = "uv_build"
|
build-backend = "uv_build"
|
||||||
"#;
|
"#;
|
||||||
let pyproject_toml: PyProjectToml = toml::from_str(contents).unwrap();
|
let pyproject_toml = PyProjectToml::parse(contents).unwrap();
|
||||||
let temp_dir = TempDir::new().unwrap();
|
let temp_dir = TempDir::new().unwrap();
|
||||||
|
|
||||||
let metadata = pyproject_toml.to_metadata(temp_dir.path()).unwrap();
|
let metadata = pyproject_toml.to_metadata(temp_dir.path()).unwrap();
|
||||||
|
|
@ -1037,7 +1034,7 @@ mod tests {
|
||||||
"#
|
"#
|
||||||
};
|
};
|
||||||
|
|
||||||
let pyproject_toml: PyProjectToml = toml::from_str(contents).unwrap();
|
let pyproject_toml = PyProjectToml::parse(contents).unwrap();
|
||||||
let metadata = pyproject_toml.to_metadata(temp_dir.path()).unwrap();
|
let metadata = pyproject_toml.to_metadata(temp_dir.path()).unwrap();
|
||||||
|
|
||||||
assert_snapshot!(metadata.core_metadata_format(), @r###"
|
assert_snapshot!(metadata.core_metadata_format(), @r###"
|
||||||
|
|
@ -1131,7 +1128,7 @@ mod tests {
|
||||||
"#
|
"#
|
||||||
};
|
};
|
||||||
|
|
||||||
let pyproject_toml: PyProjectToml = toml::from_str(contents).unwrap();
|
let pyproject_toml = PyProjectToml::parse(contents).unwrap();
|
||||||
let metadata = pyproject_toml.to_metadata(temp_dir.path()).unwrap();
|
let metadata = pyproject_toml.to_metadata(temp_dir.path()).unwrap();
|
||||||
|
|
||||||
assert_snapshot!(metadata.core_metadata_format(), @r"
|
assert_snapshot!(metadata.core_metadata_format(), @r"
|
||||||
|
|
@ -1223,7 +1220,7 @@ mod tests {
|
||||||
"#
|
"#
|
||||||
};
|
};
|
||||||
|
|
||||||
let pyproject_toml: PyProjectToml = toml::from_str(contents).unwrap();
|
let pyproject_toml = PyProjectToml::parse(contents).unwrap();
|
||||||
let metadata = pyproject_toml.to_metadata(temp_dir.path()).unwrap();
|
let metadata = pyproject_toml.to_metadata(temp_dir.path()).unwrap();
|
||||||
|
|
||||||
assert_snapshot!(metadata.core_metadata_format(), @r###"
|
assert_snapshot!(metadata.core_metadata_format(), @r###"
|
||||||
|
|
@ -1284,7 +1281,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn build_system_valid() {
|
fn build_system_valid() {
|
||||||
let contents = extend_project("");
|
let contents = extend_project("");
|
||||||
let pyproject_toml: PyProjectToml = toml::from_str(&contents).unwrap();
|
let pyproject_toml = PyProjectToml::parse(&contents).unwrap();
|
||||||
assert_snapshot!(
|
assert_snapshot!(
|
||||||
pyproject_toml.check_build_system("0.4.15+test").join("\n"),
|
pyproject_toml.check_build_system("0.4.15+test").join("\n"),
|
||||||
@""
|
@""
|
||||||
|
|
@ -1302,7 +1299,7 @@ mod tests {
|
||||||
requires = ["uv_build"]
|
requires = ["uv_build"]
|
||||||
build-backend = "uv_build"
|
build-backend = "uv_build"
|
||||||
"#};
|
"#};
|
||||||
let pyproject_toml: PyProjectToml = toml::from_str(contents).unwrap();
|
let pyproject_toml = PyProjectToml::parse(contents).unwrap();
|
||||||
assert_snapshot!(
|
assert_snapshot!(
|
||||||
pyproject_toml.check_build_system("0.4.15+test").join("\n"),
|
pyproject_toml.check_build_system("0.4.15+test").join("\n"),
|
||||||
@r###"`build_system.requires = ["uv_build"]` is missing an upper bound on the `uv_build` version such as `<0.5`. Without bounding the `uv_build` version, the source distribution will break when a future, breaking version of `uv_build` is released."###
|
@r###"`build_system.requires = ["uv_build"]` is missing an upper bound on the `uv_build` version such as `<0.5`. Without bounding the `uv_build` version, the source distribution will break when a future, breaking version of `uv_build` is released."###
|
||||||
|
|
@ -1320,7 +1317,7 @@ mod tests {
|
||||||
requires = ["uv_build>=0.4.15,<0.5.0", "wheel"]
|
requires = ["uv_build>=0.4.15,<0.5.0", "wheel"]
|
||||||
build-backend = "uv_build"
|
build-backend = "uv_build"
|
||||||
"#};
|
"#};
|
||||||
let pyproject_toml: PyProjectToml = toml::from_str(contents).unwrap();
|
let pyproject_toml = PyProjectToml::parse(contents).unwrap();
|
||||||
assert_snapshot!(
|
assert_snapshot!(
|
||||||
pyproject_toml.check_build_system("0.4.15+test").join("\n"),
|
pyproject_toml.check_build_system("0.4.15+test").join("\n"),
|
||||||
@"Expected a single uv requirement in `build-system.requires`, found ``"
|
@"Expected a single uv requirement in `build-system.requires`, found ``"
|
||||||
|
|
@ -1338,7 +1335,7 @@ mod tests {
|
||||||
requires = ["setuptools"]
|
requires = ["setuptools"]
|
||||||
build-backend = "uv_build"
|
build-backend = "uv_build"
|
||||||
"#};
|
"#};
|
||||||
let pyproject_toml: PyProjectToml = toml::from_str(contents).unwrap();
|
let pyproject_toml = PyProjectToml::parse(contents).unwrap();
|
||||||
assert_snapshot!(
|
assert_snapshot!(
|
||||||
pyproject_toml.check_build_system("0.4.15+test").join("\n"),
|
pyproject_toml.check_build_system("0.4.15+test").join("\n"),
|
||||||
@"Expected a single uv requirement in `build-system.requires`, found ``"
|
@"Expected a single uv requirement in `build-system.requires`, found ``"
|
||||||
|
|
@ -1356,7 +1353,7 @@ mod tests {
|
||||||
requires = ["uv_build>=0.4.15,<0.5.0"]
|
requires = ["uv_build>=0.4.15,<0.5.0"]
|
||||||
build-backend = "setuptools"
|
build-backend = "setuptools"
|
||||||
"#};
|
"#};
|
||||||
let pyproject_toml: PyProjectToml = toml::from_str(contents).unwrap();
|
let pyproject_toml = PyProjectToml::parse(contents).unwrap();
|
||||||
assert_snapshot!(
|
assert_snapshot!(
|
||||||
pyproject_toml.check_build_system("0.4.15+test").join("\n"),
|
pyproject_toml.check_build_system("0.4.15+test").join("\n"),
|
||||||
@r###"The value for `build_system.build-backend` should be `"uv_build"`, not `"setuptools"`"###
|
@r###"The value for `build_system.build-backend` should be `"uv_build"`, not `"setuptools"`"###
|
||||||
|
|
@ -1367,7 +1364,7 @@ mod tests {
|
||||||
fn minimal() {
|
fn minimal() {
|
||||||
let contents = extend_project("");
|
let contents = extend_project("");
|
||||||
|
|
||||||
let metadata = toml::from_str::<PyProjectToml>(&contents)
|
let metadata = PyProjectToml::parse(&contents)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_metadata(Path::new("/do/not/read"))
|
.to_metadata(Path::new("/do/not/read"))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -1386,14 +1383,15 @@ mod tests {
|
||||||
"#
|
"#
|
||||||
});
|
});
|
||||||
|
|
||||||
let err = toml::from_str::<PyProjectToml>(&contents).unwrap_err();
|
let err = PyProjectToml::parse(&contents).unwrap_err();
|
||||||
assert_snapshot!(format_err(err), @r#"
|
assert_snapshot!(format_err(err), @r###"
|
||||||
TOML parse error at line 4, column 10
|
Invalid pyproject.toml
|
||||||
|
Caused by: TOML parse error at line 4, column 10
|
||||||
|
|
|
|
||||||
4 | readme = { path = "Readme.md" }
|
4 | readme = { path = "Readme.md" }
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
data did not match any variant of untagged enum Readme
|
data did not match any variant of untagged enum Readme
|
||||||
"#);
|
"###);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -1403,7 +1401,7 @@ mod tests {
|
||||||
"#
|
"#
|
||||||
});
|
});
|
||||||
|
|
||||||
let err = toml::from_str::<PyProjectToml>(&contents)
|
let err = PyProjectToml::parse(&contents)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_metadata(Path::new("/do/not/read"))
|
.to_metadata(Path::new("/do/not/read"))
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
|
@ -1425,14 +1423,14 @@ mod tests {
|
||||||
"#
|
"#
|
||||||
});
|
});
|
||||||
|
|
||||||
let err = toml::from_str::<PyProjectToml>(&contents)
|
let err = PyProjectToml::parse(&contents)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_metadata(Path::new("/do/not/read"))
|
.to_metadata(Path::new("/do/not/read"))
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
assert_snapshot!(format_err(err), @r"
|
assert_snapshot!(format_err(err), @r###"
|
||||||
Invalid project metadata
|
Invalid pyproject.toml
|
||||||
Caused by: `project.description` must be a single line
|
Caused by: `project.description` must be a single line
|
||||||
");
|
"###);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -1443,14 +1441,14 @@ mod tests {
|
||||||
"#
|
"#
|
||||||
});
|
});
|
||||||
|
|
||||||
let err = toml::from_str::<PyProjectToml>(&contents)
|
let err = PyProjectToml::parse(&contents)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_metadata(Path::new("/do/not/read"))
|
.to_metadata(Path::new("/do/not/read"))
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
assert_snapshot!(format_err(err), @r"
|
assert_snapshot!(format_err(err), @r###"
|
||||||
Invalid project metadata
|
Invalid pyproject.toml
|
||||||
Caused by: When `project.license-files` is defined, `project.license` must be an SPDX expression string
|
Caused by: When `project.license-files` is defined, `project.license` must be an SPDX expression string
|
||||||
");
|
"###);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -1459,7 +1457,7 @@ mod tests {
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
"#
|
"#
|
||||||
});
|
});
|
||||||
let metadata = toml::from_str::<PyProjectToml>(&contents)
|
let metadata = PyProjectToml::parse(&contents)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_metadata(Path::new("/do/not/read"))
|
.to_metadata(Path::new("/do/not/read"))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -1477,13 +1475,13 @@ mod tests {
|
||||||
license = "MIT XOR Apache-2"
|
license = "MIT XOR Apache-2"
|
||||||
"#
|
"#
|
||||||
});
|
});
|
||||||
let err = toml::from_str::<PyProjectToml>(&contents)
|
let err = PyProjectToml::parse(&contents)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_metadata(Path::new("/do/not/read"))
|
.to_metadata(Path::new("/do/not/read"))
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
// TODO(konsti): We mess up the indentation in the error.
|
// TODO(konsti): We mess up the indentation in the error.
|
||||||
assert_snapshot!(format_err(err), @r"
|
assert_snapshot!(format_err(err), @r"
|
||||||
Invalid project metadata
|
Invalid pyproject.toml
|
||||||
Caused by: `project.license` is not a valid SPDX expression: MIT XOR Apache-2
|
Caused by: `project.license` is not a valid SPDX expression: MIT XOR Apache-2
|
||||||
Caused by: MIT XOR Apache-2
|
Caused by: MIT XOR Apache-2
|
||||||
^^^ unknown term
|
^^^ unknown term
|
||||||
|
|
@ -1497,18 +1495,18 @@ mod tests {
|
||||||
"#
|
"#
|
||||||
});
|
});
|
||||||
|
|
||||||
let err = toml::from_str::<PyProjectToml>(&contents)
|
let err = PyProjectToml::parse(&contents)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_metadata(Path::new("/do/not/read"))
|
.to_metadata(Path::new("/do/not/read"))
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
assert_snapshot!(format_err(err), @r"
|
assert_snapshot!(format_err(err), @r###"
|
||||||
Invalid project metadata
|
Invalid pyproject.toml
|
||||||
Caused by: Dynamic metadata is not supported
|
Caused by: Dynamic metadata is not supported
|
||||||
");
|
"###);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn script_error(contents: &str) -> String {
|
fn script_error(contents: &str) -> String {
|
||||||
let err = toml::from_str::<PyProjectToml>(contents)
|
let err = PyProjectToml::parse(contents)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_entry_points()
|
.to_entry_points()
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
|
|
||||||
|
|
@ -70,9 +70,6 @@ pub struct BuildBackendSettings {
|
||||||
pub default_excludes: bool,
|
pub default_excludes: bool,
|
||||||
|
|
||||||
/// Glob expressions which files and directories to exclude from the source distribution.
|
/// Glob expressions which files and directories to exclude from the source distribution.
|
||||||
///
|
|
||||||
/// These exclusions are also applied to wheels to ensure that a wheel built from a source tree
|
|
||||||
/// is consistent with a wheel built from a source distribution.
|
|
||||||
#[option(
|
#[option(
|
||||||
default = r#"[]"#,
|
default = r#"[]"#,
|
||||||
value_type = "list[str]",
|
value_type = "list[str]",
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,9 @@ pub fn build_source_dist(
|
||||||
source_tree: &Path,
|
source_tree: &Path,
|
||||||
source_dist_directory: &Path,
|
source_dist_directory: &Path,
|
||||||
uv_version: &str,
|
uv_version: &str,
|
||||||
show_warnings: bool,
|
|
||||||
) -> Result<SourceDistFilename, Error> {
|
) -> Result<SourceDistFilename, Error> {
|
||||||
let pyproject_toml = PyProjectToml::parse(&source_tree.join("pyproject.toml"))?;
|
let contents = fs_err::read_to_string(source_tree.join("pyproject.toml"))?;
|
||||||
|
let pyproject_toml = PyProjectToml::parse(&contents)?;
|
||||||
let filename = SourceDistFilename {
|
let filename = SourceDistFilename {
|
||||||
name: pyproject_toml.name().clone(),
|
name: pyproject_toml.name().clone(),
|
||||||
version: pyproject_toml.version().clone(),
|
version: pyproject_toml.version().clone(),
|
||||||
|
|
@ -34,7 +34,7 @@ pub fn build_source_dist(
|
||||||
};
|
};
|
||||||
let source_dist_path = source_dist_directory.join(filename.to_string());
|
let source_dist_path = source_dist_directory.join(filename.to_string());
|
||||||
let writer = TarGzWriter::new(&source_dist_path)?;
|
let writer = TarGzWriter::new(&source_dist_path)?;
|
||||||
write_source_dist(source_tree, writer, uv_version, show_warnings)?;
|
write_source_dist(source_tree, writer, uv_version)?;
|
||||||
Ok(filename)
|
Ok(filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,9 +42,9 @@ pub fn build_source_dist(
|
||||||
pub fn list_source_dist(
|
pub fn list_source_dist(
|
||||||
source_tree: &Path,
|
source_tree: &Path,
|
||||||
uv_version: &str,
|
uv_version: &str,
|
||||||
show_warnings: bool,
|
|
||||||
) -> Result<(SourceDistFilename, FileList), Error> {
|
) -> Result<(SourceDistFilename, FileList), Error> {
|
||||||
let pyproject_toml = PyProjectToml::parse(&source_tree.join("pyproject.toml"))?;
|
let contents = fs_err::read_to_string(source_tree.join("pyproject.toml"))?;
|
||||||
|
let pyproject_toml = PyProjectToml::parse(&contents)?;
|
||||||
let filename = SourceDistFilename {
|
let filename = SourceDistFilename {
|
||||||
name: pyproject_toml.name().clone(),
|
name: pyproject_toml.name().clone(),
|
||||||
version: pyproject_toml.version().clone(),
|
version: pyproject_toml.version().clone(),
|
||||||
|
|
@ -52,7 +52,7 @@ pub fn list_source_dist(
|
||||||
};
|
};
|
||||||
let mut files = FileList::new();
|
let mut files = FileList::new();
|
||||||
let writer = ListWriter::new(&mut files);
|
let writer = ListWriter::new(&mut files);
|
||||||
write_source_dist(source_tree, writer, uv_version, show_warnings)?;
|
write_source_dist(source_tree, writer, uv_version)?;
|
||||||
Ok((filename, files))
|
Ok((filename, files))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,7 +61,6 @@ fn source_dist_matcher(
|
||||||
source_tree: &Path,
|
source_tree: &Path,
|
||||||
pyproject_toml: &PyProjectToml,
|
pyproject_toml: &PyProjectToml,
|
||||||
settings: BuildBackendSettings,
|
settings: BuildBackendSettings,
|
||||||
show_warnings: bool,
|
|
||||||
) -> Result<(GlobDirFilter, GlobSet), Error> {
|
) -> Result<(GlobDirFilter, GlobSet), Error> {
|
||||||
// File and directories to include in the source directory
|
// File and directories to include in the source directory
|
||||||
let mut include_globs = Vec::new();
|
let mut include_globs = Vec::new();
|
||||||
|
|
@ -76,7 +75,6 @@ fn source_dist_matcher(
|
||||||
&settings.module_root,
|
&settings.module_root,
|
||||||
settings.module_name.as_ref(),
|
settings.module_name.as_ref(),
|
||||||
settings.namespace,
|
settings.namespace,
|
||||||
show_warnings,
|
|
||||||
)?;
|
)?;
|
||||||
for module_relative in modules_relative {
|
for module_relative in modules_relative {
|
||||||
// The wheel must not include any files included by the source distribution (at least until we
|
// The wheel must not include any files included by the source distribution (at least until we
|
||||||
|
|
@ -184,9 +182,9 @@ fn write_source_dist(
|
||||||
source_tree: &Path,
|
source_tree: &Path,
|
||||||
mut writer: impl DirectoryWriter,
|
mut writer: impl DirectoryWriter,
|
||||||
uv_version: &str,
|
uv_version: &str,
|
||||||
show_warnings: bool,
|
|
||||||
) -> Result<SourceDistFilename, Error> {
|
) -> Result<SourceDistFilename, Error> {
|
||||||
let pyproject_toml = PyProjectToml::parse(&source_tree.join("pyproject.toml"))?;
|
let contents = fs_err::read_to_string(source_tree.join("pyproject.toml"))?;
|
||||||
|
let pyproject_toml = PyProjectToml::parse(&contents)?;
|
||||||
for warning in pyproject_toml.check_build_system(uv_version) {
|
for warning in pyproject_toml.check_build_system(uv_version) {
|
||||||
warn_user_once!("{warning}");
|
warn_user_once!("{warning}");
|
||||||
}
|
}
|
||||||
|
|
@ -220,7 +218,7 @@ fn write_source_dist(
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let (include_matcher, exclude_matcher) =
|
let (include_matcher, exclude_matcher) =
|
||||||
source_dist_matcher(source_tree, &pyproject_toml, settings, show_warnings)?;
|
source_dist_matcher(source_tree, &pyproject_toml, settings)?;
|
||||||
|
|
||||||
let mut files_visited = 0;
|
let mut files_visited = 0;
|
||||||
for entry in WalkDir::new(source_tree)
|
for entry in WalkDir::new(source_tree)
|
||||||
|
|
@ -299,10 +297,6 @@ impl TarGzWriter {
|
||||||
impl DirectoryWriter for TarGzWriter {
|
impl DirectoryWriter for TarGzWriter {
|
||||||
fn write_bytes(&mut self, path: &str, bytes: &[u8]) -> Result<(), Error> {
|
fn write_bytes(&mut self, path: &str, bytes: &[u8]) -> Result<(), Error> {
|
||||||
let mut header = Header::new_gnu();
|
let mut header = Header::new_gnu();
|
||||||
// Work around bug in Python's std tar module
|
|
||||||
// https://github.com/python/cpython/issues/141707
|
|
||||||
// https://github.com/astral-sh/uv/pull/17043#issuecomment-3636841022
|
|
||||||
header.set_entry_type(EntryType::Regular);
|
|
||||||
header.set_size(bytes.len() as u64);
|
header.set_size(bytes.len() as u64);
|
||||||
// Reasonable default to avoid 0o000 permissions, the user's umask will be applied on
|
// Reasonable default to avoid 0o000 permissions, the user's umask will be applied on
|
||||||
// unpacking.
|
// unpacking.
|
||||||
|
|
@ -316,10 +310,6 @@ impl DirectoryWriter for TarGzWriter {
|
||||||
fn write_file(&mut self, path: &str, file: &Path) -> Result<(), Error> {
|
fn write_file(&mut self, path: &str, file: &Path) -> Result<(), Error> {
|
||||||
let metadata = fs_err::metadata(file)?;
|
let metadata = fs_err::metadata(file)?;
|
||||||
let mut header = Header::new_gnu();
|
let mut header = Header::new_gnu();
|
||||||
// Work around bug in Python's std tar module
|
|
||||||
// https://github.com/python/cpython/issues/141707
|
|
||||||
// https://github.com/astral-sh/uv/pull/17043#issuecomment-3636841022
|
|
||||||
header.set_entry_type(EntryType::Regular);
|
|
||||||
// Preserve the executable bit, especially for scripts
|
// Preserve the executable bit, especially for scripts
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
let executable_bit = {
|
let executable_bit = {
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,9 @@ pub fn build_wheel(
|
||||||
wheel_dir: &Path,
|
wheel_dir: &Path,
|
||||||
metadata_directory: Option<&Path>,
|
metadata_directory: Option<&Path>,
|
||||||
uv_version: &str,
|
uv_version: &str,
|
||||||
show_warnings: bool,
|
|
||||||
) -> Result<WheelFilename, Error> {
|
) -> Result<WheelFilename, Error> {
|
||||||
let pyproject_toml = PyProjectToml::parse(&source_tree.join("pyproject.toml"))?;
|
let contents = fs_err::read_to_string(source_tree.join("pyproject.toml"))?;
|
||||||
|
let pyproject_toml = PyProjectToml::parse(&contents)?;
|
||||||
for warning in pyproject_toml.check_build_system(uv_version) {
|
for warning in pyproject_toml.check_build_system(uv_version) {
|
||||||
warn_user_once!("{warning}");
|
warn_user_once!("{warning}");
|
||||||
}
|
}
|
||||||
|
|
@ -58,7 +58,6 @@ pub fn build_wheel(
|
||||||
&filename,
|
&filename,
|
||||||
uv_version,
|
uv_version,
|
||||||
wheel_writer,
|
wheel_writer,
|
||||||
show_warnings,
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(filename)
|
Ok(filename)
|
||||||
|
|
@ -68,9 +67,9 @@ pub fn build_wheel(
|
||||||
pub fn list_wheel(
|
pub fn list_wheel(
|
||||||
source_tree: &Path,
|
source_tree: &Path,
|
||||||
uv_version: &str,
|
uv_version: &str,
|
||||||
show_warnings: bool,
|
|
||||||
) -> Result<(WheelFilename, FileList), Error> {
|
) -> Result<(WheelFilename, FileList), Error> {
|
||||||
let pyproject_toml = PyProjectToml::parse(&source_tree.join("pyproject.toml"))?;
|
let contents = fs_err::read_to_string(source_tree.join("pyproject.toml"))?;
|
||||||
|
let pyproject_toml = PyProjectToml::parse(&contents)?;
|
||||||
for warning in pyproject_toml.check_build_system(uv_version) {
|
for warning in pyproject_toml.check_build_system(uv_version) {
|
||||||
warn_user_once!("{warning}");
|
warn_user_once!("{warning}");
|
||||||
}
|
}
|
||||||
|
|
@ -88,14 +87,7 @@ pub fn list_wheel(
|
||||||
|
|
||||||
let mut files = FileList::new();
|
let mut files = FileList::new();
|
||||||
let writer = ListWriter::new(&mut files);
|
let writer = ListWriter::new(&mut files);
|
||||||
write_wheel(
|
write_wheel(source_tree, &pyproject_toml, &filename, uv_version, writer)?;
|
||||||
source_tree,
|
|
||||||
&pyproject_toml,
|
|
||||||
&filename,
|
|
||||||
uv_version,
|
|
||||||
writer,
|
|
||||||
show_warnings,
|
|
||||||
)?;
|
|
||||||
Ok((filename, files))
|
Ok((filename, files))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -105,7 +97,6 @@ fn write_wheel(
|
||||||
filename: &WheelFilename,
|
filename: &WheelFilename,
|
||||||
uv_version: &str,
|
uv_version: &str,
|
||||||
mut wheel_writer: impl DirectoryWriter,
|
mut wheel_writer: impl DirectoryWriter,
|
||||||
show_warnings: bool,
|
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let settings = pyproject_toml
|
let settings = pyproject_toml
|
||||||
.settings()
|
.settings()
|
||||||
|
|
@ -141,7 +132,6 @@ fn write_wheel(
|
||||||
&settings.module_root,
|
&settings.module_root,
|
||||||
settings.module_name.as_ref(),
|
settings.module_name.as_ref(),
|
||||||
settings.namespace,
|
settings.namespace,
|
||||||
show_warnings,
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let mut files_visited = 0;
|
let mut files_visited = 0;
|
||||||
|
|
@ -269,9 +259,9 @@ pub fn build_editable(
|
||||||
wheel_dir: &Path,
|
wheel_dir: &Path,
|
||||||
metadata_directory: Option<&Path>,
|
metadata_directory: Option<&Path>,
|
||||||
uv_version: &str,
|
uv_version: &str,
|
||||||
show_warnings: bool,
|
|
||||||
) -> Result<WheelFilename, Error> {
|
) -> Result<WheelFilename, Error> {
|
||||||
let pyproject_toml = PyProjectToml::parse(&source_tree.join("pyproject.toml"))?;
|
let contents = fs_err::read_to_string(source_tree.join("pyproject.toml"))?;
|
||||||
|
let pyproject_toml = PyProjectToml::parse(&contents)?;
|
||||||
for warning in pyproject_toml.check_build_system(uv_version) {
|
for warning in pyproject_toml.check_build_system(uv_version) {
|
||||||
warn_user_once!("{warning}");
|
warn_user_once!("{warning}");
|
||||||
}
|
}
|
||||||
|
|
@ -305,7 +295,6 @@ pub fn build_editable(
|
||||||
&settings.module_root,
|
&settings.module_root,
|
||||||
settings.module_name.as_ref(),
|
settings.module_name.as_ref(),
|
||||||
settings.namespace,
|
settings.namespace,
|
||||||
show_warnings,
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
wheel_writer.write_bytes(
|
wheel_writer.write_bytes(
|
||||||
|
|
@ -332,7 +321,8 @@ pub fn metadata(
|
||||||
metadata_directory: &Path,
|
metadata_directory: &Path,
|
||||||
uv_version: &str,
|
uv_version: &str,
|
||||||
) -> Result<String, Error> {
|
) -> Result<String, Error> {
|
||||||
let pyproject_toml = PyProjectToml::parse(&source_tree.join("pyproject.toml"))?;
|
let contents = fs_err::read_to_string(source_tree.join("pyproject.toml"))?;
|
||||||
|
let pyproject_toml = PyProjectToml::parse(&contents)?;
|
||||||
for warning in pyproject_toml.check_build_system(uv_version) {
|
for warning in pyproject_toml.check_build_system(uv_version) {
|
||||||
warn_user_once!("{warning}");
|
warn_user_once!("{warning}");
|
||||||
}
|
}
|
||||||
|
|
@ -840,7 +830,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_prepare_metadata() {
|
fn test_prepare_metadata() {
|
||||||
let metadata_dir = TempDir::new().unwrap();
|
let metadata_dir = TempDir::new().unwrap();
|
||||||
let built_by_uv = Path::new("../../test/packages/built-by-uv");
|
let built_by_uv = Path::new("../../scripts/packages/built-by-uv");
|
||||||
metadata(built_by_uv, metadata_dir.path(), "1.0.0+test").unwrap();
|
metadata(built_by_uv, metadata_dir.path(), "1.0.0+test").unwrap();
|
||||||
|
|
||||||
let mut files: Vec<_> = WalkDir::new(metadata_dir.path())
|
let mut files: Vec<_> = WalkDir::new(metadata_dir.path())
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-build-frontend"
|
name = "uv-build-frontend"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
description = "This is an internal component crate of uv"
|
description = "This is an internal component crate of uv"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
@ -16,7 +16,6 @@ doctest = false
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
uv-auth = { workspace = true }
|
|
||||||
uv-cache-key = { workspace = true }
|
uv-cache-key = { workspace = true }
|
||||||
uv-configuration = { workspace = true }
|
uv-configuration = { workspace = true }
|
||||||
uv-distribution = { workspace = true }
|
uv-distribution = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@
|
||||||
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
||||||
is unstable and will have frequent breaking changes.
|
is unstable and will have frequent breaking changes.
|
||||||
|
|
||||||
This version (0.0.8) is a component of [uv 0.9.18](https://crates.io/crates/uv/0.9.18). The source
|
|
||||||
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-build-frontend).
|
|
||||||
|
|
||||||
See uv's
|
See uv's
|
||||||
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
||||||
for details on versioning.
|
for details on versioning.
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ use tokio::io::AsyncBufReadExt;
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
use tokio::sync::{Mutex, Semaphore};
|
use tokio::sync::{Mutex, Semaphore};
|
||||||
use tracing::{Instrument, debug, info_span, instrument, warn};
|
use tracing::{Instrument, debug, info_span, instrument, warn};
|
||||||
use uv_auth::CredentialsCache;
|
|
||||||
use uv_cache_key::cache_digest;
|
use uv_cache_key::cache_digest;
|
||||||
use uv_configuration::{BuildKind, BuildOutput, SourceStrategy};
|
use uv_configuration::{BuildKind, BuildOutput, SourceStrategy};
|
||||||
use uv_distribution::BuildRequires;
|
use uv_distribution::BuildRequires;
|
||||||
|
|
@ -36,7 +36,7 @@ use uv_distribution_types::{
|
||||||
ConfigSettings, ExtraBuildRequirement, ExtraBuildRequires, IndexLocations, Requirement,
|
ConfigSettings, ExtraBuildRequirement, ExtraBuildRequires, IndexLocations, Requirement,
|
||||||
Resolution,
|
Resolution,
|
||||||
};
|
};
|
||||||
use uv_fs::{LockedFile, LockedFileMode};
|
use uv_fs::LockedFile;
|
||||||
use uv_fs::{PythonExt, Simplified};
|
use uv_fs::{PythonExt, Simplified};
|
||||||
use uv_normalize::PackageName;
|
use uv_normalize::PackageName;
|
||||||
use uv_pep440::Version;
|
use uv_pep440::Version;
|
||||||
|
|
@ -292,7 +292,6 @@ impl SourceBuild {
|
||||||
mut environment_variables: FxHashMap<OsString, OsString>,
|
mut environment_variables: FxHashMap<OsString, OsString>,
|
||||||
level: BuildOutput,
|
level: BuildOutput,
|
||||||
concurrent_builds: usize,
|
concurrent_builds: usize,
|
||||||
credentials_cache: &CredentialsCache,
|
|
||||||
preview: Preview,
|
preview: Preview,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let temp_dir = build_context.cache().venv_dir()?;
|
let temp_dir = build_context.cache().venv_dir()?;
|
||||||
|
|
@ -311,7 +310,6 @@ impl SourceBuild {
|
||||||
locations,
|
locations,
|
||||||
source_strategy,
|
source_strategy,
|
||||||
workspace_cache,
|
workspace_cache,
|
||||||
credentials_cache,
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| *err)?;
|
.map_err(|err| *err)?;
|
||||||
|
|
@ -454,7 +452,6 @@ impl SourceBuild {
|
||||||
&environment_variables,
|
&environment_variables,
|
||||||
&modified_path,
|
&modified_path,
|
||||||
&temp_dir,
|
&temp_dir,
|
||||||
credentials_cache,
|
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
@ -493,16 +490,12 @@ impl SourceBuild {
|
||||||
"uv-setuptools-{}.lock",
|
"uv-setuptools-{}.lock",
|
||||||
cache_digest(&canonical_source_path)
|
cache_digest(&canonical_source_path)
|
||||||
));
|
));
|
||||||
source_tree_lock = LockedFile::acquire(
|
source_tree_lock = LockedFile::acquire(lock_path, self.source_tree.to_string_lossy())
|
||||||
lock_path,
|
.await
|
||||||
LockedFileMode::Exclusive,
|
.inspect_err(|err| {
|
||||||
self.source_tree.to_string_lossy(),
|
warn!("Failed to acquire build lock: {err}");
|
||||||
)
|
})
|
||||||
.await
|
.ok();
|
||||||
.inspect_err(|err| {
|
|
||||||
warn!("Failed to acquire build lock: {err}");
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
}
|
}
|
||||||
Ok(source_tree_lock)
|
Ok(source_tree_lock)
|
||||||
}
|
}
|
||||||
|
|
@ -563,7 +556,6 @@ impl SourceBuild {
|
||||||
locations: &IndexLocations,
|
locations: &IndexLocations,
|
||||||
source_strategy: SourceStrategy,
|
source_strategy: SourceStrategy,
|
||||||
workspace_cache: &WorkspaceCache,
|
workspace_cache: &WorkspaceCache,
|
||||||
credentials_cache: &CredentialsCache,
|
|
||||||
) -> Result<(Pep517Backend, Option<Project>), Box<Error>> {
|
) -> Result<(Pep517Backend, Option<Project>), Box<Error>> {
|
||||||
match fs::read_to_string(source_tree.join("pyproject.toml")) {
|
match fs::read_to_string(source_tree.join("pyproject.toml")) {
|
||||||
Ok(toml) => {
|
Ok(toml) => {
|
||||||
|
|
@ -592,7 +584,6 @@ impl SourceBuild {
|
||||||
locations,
|
locations,
|
||||||
source_strategy,
|
source_strategy,
|
||||||
workspace_cache,
|
workspace_cache,
|
||||||
credentials_cache,
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(Error::Lowering)?;
|
.map_err(Error::Lowering)?;
|
||||||
|
|
@ -965,7 +956,6 @@ async fn create_pep517_build_environment(
|
||||||
environment_variables: &FxHashMap<OsString, OsString>,
|
environment_variables: &FxHashMap<OsString, OsString>,
|
||||||
modified_path: &OsString,
|
modified_path: &OsString,
|
||||||
temp_dir: &TempDir,
|
temp_dir: &TempDir,
|
||||||
credentials_cache: &CredentialsCache,
|
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Write the hook output to a file so that we can read it back reliably.
|
// Write the hook output to a file so that we can read it back reliably.
|
||||||
let outfile = temp_dir
|
let outfile = temp_dir
|
||||||
|
|
@ -1060,7 +1050,6 @@ async fn create_pep517_build_environment(
|
||||||
locations,
|
locations,
|
||||||
source_strategy,
|
source_strategy,
|
||||||
workspace_cache,
|
workspace_cache,
|
||||||
credentials_cache,
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(Error::Lowering)?;
|
.map_err(Error::Lowering)?;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-build"
|
name = "uv-build"
|
||||||
version = "0.9.18"
|
version = "0.9.14"
|
||||||
description = "A Python build backend"
|
description = "A Python build backend"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[project]
|
[project]
|
||||||
name = "uv-build"
|
name = "uv-build"
|
||||||
version = "0.9.18"
|
version = "0.9.14"
|
||||||
description = "The uv build backend"
|
description = "The uv build backend"
|
||||||
authors = [{ name = "Astral Software Inc.", email = "hey@astral.sh" }]
|
authors = [{ name = "Astral Software Inc.", email = "hey@astral.sh" }]
|
||||||
requires-python = ">=3.8"
|
requires-python = ">=3.8"
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,6 @@ fn main() -> Result<()> {
|
||||||
&env::current_dir()?,
|
&env::current_dir()?,
|
||||||
&sdist_directory,
|
&sdist_directory,
|
||||||
uv_version::version(),
|
uv_version::version(),
|
||||||
false,
|
|
||||||
)?;
|
)?;
|
||||||
// Tell the build frontend about the name of the artifact we built
|
// Tell the build frontend about the name of the artifact we built
|
||||||
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
||||||
|
|
@ -57,7 +56,6 @@ fn main() -> Result<()> {
|
||||||
&wheel_directory,
|
&wheel_directory,
|
||||||
metadata_directory.as_deref(),
|
metadata_directory.as_deref(),
|
||||||
uv_version::version(),
|
uv_version::version(),
|
||||||
false,
|
|
||||||
)?;
|
)?;
|
||||||
// Tell the build frontend about the name of the artifact we built
|
// Tell the build frontend about the name of the artifact we built
|
||||||
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
||||||
|
|
@ -70,7 +68,6 @@ fn main() -> Result<()> {
|
||||||
&wheel_directory,
|
&wheel_directory,
|
||||||
metadata_directory.as_deref(),
|
metadata_directory.as_deref(),
|
||||||
uv_version::version(),
|
uv_version::version(),
|
||||||
false,
|
|
||||||
)?;
|
)?;
|
||||||
// Tell the build frontend about the name of the artifact we built
|
// Tell the build frontend about the name of the artifact we built
|
||||||
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-cache-info"
|
name = "uv-cache-info"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
description = "This is an internal component crate of uv"
|
description = "This is an internal component crate of uv"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@
|
||||||
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
||||||
is unstable and will have frequent breaking changes.
|
is unstable and will have frequent breaking changes.
|
||||||
|
|
||||||
This version (0.0.8) is a component of [uv 0.9.18](https://crates.io/crates/uv/0.9.18). The source
|
|
||||||
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-cache-info).
|
|
||||||
|
|
||||||
See uv's
|
See uv's
|
||||||
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
||||||
for details on versioning.
|
for details on versioning.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-cache-key"
|
name = "uv-cache-key"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
description = "This is an internal component crate of uv"
|
description = "This is an internal component crate of uv"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@
|
||||||
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
||||||
is unstable and will have frequent breaking changes.
|
is unstable and will have frequent breaking changes.
|
||||||
|
|
||||||
This version (0.0.8) is a component of [uv 0.9.18](https://crates.io/crates/uv/0.9.18). The source
|
|
||||||
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-cache-key).
|
|
||||||
|
|
||||||
See uv's
|
See uv's
|
||||||
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
||||||
for details on versioning.
|
for details on versioning.
|
||||||
|
|
|
||||||
|
|
@ -139,18 +139,8 @@ impl std::fmt::Display for CanonicalUrl {
|
||||||
/// `https://github.com/pypa/package.git#subdirectory=pkg_b` would map to different
|
/// `https://github.com/pypa/package.git#subdirectory=pkg_b` would map to different
|
||||||
/// [`CanonicalUrl`] values, but the same [`RepositoryUrl`], since they map to the same
|
/// [`CanonicalUrl`] values, but the same [`RepositoryUrl`], since they map to the same
|
||||||
/// resource.
|
/// resource.
|
||||||
///
|
|
||||||
/// The additional information it holds should only be used to discriminate between
|
|
||||||
/// sources that hold the exact same commit in their canonical representation,
|
|
||||||
/// but may differ in the contents such as when Git LFS is enabled.
|
|
||||||
///
|
|
||||||
/// A different cache key will be computed when Git LFS is enabled.
|
|
||||||
/// When Git LFS is `false` or `None`, the cache key remains unchanged.
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
|
||||||
pub struct RepositoryUrl {
|
pub struct RepositoryUrl(DisplaySafeUrl);
|
||||||
repo_url: DisplaySafeUrl,
|
|
||||||
with_lfs: Option<bool>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RepositoryUrl {
|
impl RepositoryUrl {
|
||||||
pub fn new(url: &DisplaySafeUrl) -> Self {
|
pub fn new(url: &DisplaySafeUrl) -> Self {
|
||||||
|
|
@ -171,31 +161,19 @@ impl RepositoryUrl {
|
||||||
url.set_fragment(None);
|
url.set_fragment(None);
|
||||||
url.set_query(None);
|
url.set_query(None);
|
||||||
|
|
||||||
Self {
|
Self(url)
|
||||||
repo_url: url,
|
|
||||||
with_lfs: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(url: &str) -> Result<Self, DisplaySafeUrlError> {
|
pub fn parse(url: &str) -> Result<Self, DisplaySafeUrlError> {
|
||||||
Ok(Self::new(&DisplaySafeUrl::parse(url)?))
|
Ok(Self::new(&DisplaySafeUrl::parse(url)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn with_lfs(mut self, lfs: Option<bool>) -> Self {
|
|
||||||
self.with_lfs = lfs;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CacheKey for RepositoryUrl {
|
impl CacheKey for RepositoryUrl {
|
||||||
fn cache_key(&self, state: &mut CacheKeyHasher) {
|
fn cache_key(&self, state: &mut CacheKeyHasher) {
|
||||||
// `as_str` gives the serialisation of a url (which has a spec) and so insulates against
|
// `as_str` gives the serialisation of a url (which has a spec) and so insulates against
|
||||||
// possible changes in how the URL crate does hashing.
|
// possible changes in how the URL crate does hashing.
|
||||||
self.repo_url.as_str().cache_key(state);
|
self.0.as_str().cache_key(state);
|
||||||
if let Some(true) = self.with_lfs {
|
|
||||||
1u8.cache_key(state);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -203,10 +181,7 @@ impl Hash for RepositoryUrl {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
// `as_str` gives the serialisation of a url (which has a spec) and so insulates against
|
// `as_str` gives the serialisation of a url (which has a spec) and so insulates against
|
||||||
// possible changes in how the URL crate does hashing.
|
// possible changes in how the URL crate does hashing.
|
||||||
self.repo_url.as_str().hash(state);
|
self.0.as_str().hash(state);
|
||||||
if let Some(true) = self.with_lfs {
|
|
||||||
1u8.hash(state);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,13 +189,13 @@ impl Deref for RepositoryUrl {
|
||||||
type Target = Url;
|
type Target = Url;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.repo_url
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for RepositoryUrl {
|
impl std::fmt::Display for RepositoryUrl {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
std::fmt::Display::fmt(&self.repo_url, f)
|
std::fmt::Display::fmt(&self.0, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -308,14 +283,6 @@ mod tests {
|
||||||
)?,
|
)?,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Two URLs should _not_ be considered equal if they differ in Git LFS enablement.
|
|
||||||
assert_ne!(
|
|
||||||
CanonicalUrl::parse(
|
|
||||||
"git+https://github.com/pypa/sample-namespace-packages.git#lfs=true"
|
|
||||||
)?,
|
|
||||||
CanonicalUrl::parse("git+https://github.com/pypa/sample-namespace-packages.git")?,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Two URLs should _not_ be considered equal if they request different commit tags.
|
// Two URLs should _not_ be considered equal if they request different commit tags.
|
||||||
assert_ne!(
|
assert_ne!(
|
||||||
CanonicalUrl::parse(
|
CanonicalUrl::parse(
|
||||||
|
|
@ -411,76 +378,6 @@ mod tests {
|
||||||
)?,
|
)?,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Two URLs should be considered equal if they map to the same repository, even if they
|
|
||||||
// differ in Git LFS enablement.
|
|
||||||
assert_eq!(
|
|
||||||
RepositoryUrl::parse(
|
|
||||||
"git+https://github.com/pypa/sample-namespace-packages.git#lfs=true"
|
|
||||||
)?,
|
|
||||||
RepositoryUrl::parse("git+https://github.com/pypa/sample-namespace-packages.git")?,
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn repository_url_with_lfs() -> Result<(), DisplaySafeUrlError> {
|
|
||||||
let mut hasher = CacheKeyHasher::new();
|
|
||||||
RepositoryUrl::parse("https://example.com/pypa/sample-namespace-packages.git@2.0.0")?
|
|
||||||
.cache_key(&mut hasher);
|
|
||||||
let repo_url_basic = hasher.finish();
|
|
||||||
|
|
||||||
let mut hasher = CacheKeyHasher::new();
|
|
||||||
RepositoryUrl::parse(
|
|
||||||
"https://user:foo@example.com/pypa/sample-namespace-packages.git@2.0.0#foo=bar",
|
|
||||||
)?
|
|
||||||
.cache_key(&mut hasher);
|
|
||||||
let repo_url_with_fragments = hasher.finish();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
repo_url_basic, repo_url_with_fragments,
|
|
||||||
"repository urls should have the exact cache keys as fragments are removed",
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut hasher = CacheKeyHasher::new();
|
|
||||||
RepositoryUrl::parse(
|
|
||||||
"https://user:foo@example.com/pypa/sample-namespace-packages.git@2.0.0#foo=bar",
|
|
||||||
)?
|
|
||||||
.with_lfs(None)
|
|
||||||
.cache_key(&mut hasher);
|
|
||||||
let git_url_with_fragments = hasher.finish();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
repo_url_with_fragments, git_url_with_fragments,
|
|
||||||
"both structs should have the exact cache keys as fragments are still removed",
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut hasher = CacheKeyHasher::new();
|
|
||||||
RepositoryUrl::parse(
|
|
||||||
"https://user:foo@example.com/pypa/sample-namespace-packages.git@2.0.0#foo=bar",
|
|
||||||
)?
|
|
||||||
.with_lfs(Some(false))
|
|
||||||
.cache_key(&mut hasher);
|
|
||||||
let git_url_with_fragments_and_lfs_false = hasher.finish();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
git_url_with_fragments, git_url_with_fragments_and_lfs_false,
|
|
||||||
"both structs should have the exact cache keys as lfs false should not influence them",
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut hasher = CacheKeyHasher::new();
|
|
||||||
RepositoryUrl::parse(
|
|
||||||
"https://user:foo@example.com/pypa/sample-namespace-packages.git@2.0.0#foo=bar",
|
|
||||||
)?
|
|
||||||
.with_lfs(Some(true))
|
|
||||||
.cache_key(&mut hasher);
|
|
||||||
let git_url_with_fragments_and_lfs_true = hasher.finish();
|
|
||||||
|
|
||||||
assert_ne!(
|
|
||||||
git_url_with_fragments, git_url_with_fragments_and_lfs_true,
|
|
||||||
"both structs should have different cache keys as one has Git LFS enabled",
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-cache"
|
name = "uv-cache"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
description = "This is an internal component crate of uv"
|
description = "This is an internal component crate of uv"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
@ -34,6 +34,5 @@ rustc-hash = { workspace = true }
|
||||||
same-file = { workspace = true }
|
same-file = { workspace = true }
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
tempfile = { workspace = true }
|
tempfile = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
walkdir = { workspace = true }
|
walkdir = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@
|
||||||
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
||||||
is unstable and will have frequent breaking changes.
|
is unstable and will have frequent breaking changes.
|
||||||
|
|
||||||
This version (0.0.8) is a component of [uv 0.9.18](https://crates.io/crates/uv/0.9.18). The source
|
|
||||||
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-cache).
|
|
||||||
|
|
||||||
See uv's
|
See uv's
|
||||||
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
||||||
for details on versioning.
|
for details on versioning.
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use std::path::{Path, PathBuf};
|
||||||
use uv_static::EnvVars;
|
use uv_static::EnvVars;
|
||||||
|
|
||||||
use crate::Cache;
|
use crate::Cache;
|
||||||
use clap::{Parser, ValueHint};
|
use clap::Parser;
|
||||||
use tracing::{debug, warn};
|
use tracing::{debug, warn};
|
||||||
|
|
||||||
#[derive(Parser, Debug, Clone)]
|
#[derive(Parser, Debug, Clone)]
|
||||||
|
|
@ -27,7 +27,7 @@ pub struct CacheArgs {
|
||||||
/// `%LOCALAPPDATA%\uv\cache` on Windows.
|
/// `%LOCALAPPDATA%\uv\cache` on Windows.
|
||||||
///
|
///
|
||||||
/// To view the location of the cache directory, run `uv cache dir`.
|
/// To view the location of the cache directory, run `uv cache dir`.
|
||||||
#[arg(global = true, long, env = EnvVars::UV_CACHE_DIR, value_hint = ValueHint::DirPath)]
|
#[arg(global = true, long, env = EnvVars::UV_CACHE_DIR)]
|
||||||
pub cache_dir: Option<PathBuf>,
|
pub cache_dir: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ use rustc_hash::FxHashMap;
|
||||||
use tracing::{debug, trace, warn};
|
use tracing::{debug, trace, warn};
|
||||||
|
|
||||||
use uv_cache_info::Timestamp;
|
use uv_cache_info::Timestamp;
|
||||||
use uv_fs::{LockedFile, LockedFileError, LockedFileMode, Simplified, cachedir, directories};
|
use uv_fs::{LockedFile, Simplified, cachedir, directories};
|
||||||
use uv_normalize::PackageName;
|
use uv_normalize::PackageName;
|
||||||
use uv_pypi_types::ResolutionMetadata;
|
use uv_pypi_types::ResolutionMetadata;
|
||||||
|
|
||||||
|
|
@ -35,17 +35,6 @@ mod wheel;
|
||||||
/// Must be kept in-sync with the version in [`CacheBucket::to_str`].
|
/// Must be kept in-sync with the version in [`CacheBucket::to_str`].
|
||||||
pub const ARCHIVE_VERSION: u8 = 0;
|
pub const ARCHIVE_VERSION: u8 = 0;
|
||||||
|
|
||||||
/// Error locking a cache entry or shard
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
|
||||||
pub enum Error {
|
|
||||||
#[error(transparent)]
|
|
||||||
Io(#[from] io::Error),
|
|
||||||
#[error("Could not make the path absolute")]
|
|
||||||
Absolute(#[source] io::Error),
|
|
||||||
#[error("Could not acquire lock")]
|
|
||||||
Acquire(#[from] LockedFileError),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A [`CacheEntry`] which may or may not exist yet.
|
/// A [`CacheEntry`] which may or may not exist yet.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CacheEntry(PathBuf);
|
pub struct CacheEntry(PathBuf);
|
||||||
|
|
@ -91,14 +80,9 @@ impl CacheEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Acquire the [`CacheEntry`] as an exclusive lock.
|
/// Acquire the [`CacheEntry`] as an exclusive lock.
|
||||||
pub async fn lock(&self) -> Result<LockedFile, Error> {
|
pub async fn lock(&self) -> Result<LockedFile, io::Error> {
|
||||||
fs_err::create_dir_all(self.dir())?;
|
fs_err::create_dir_all(self.dir())?;
|
||||||
Ok(LockedFile::acquire(
|
LockedFile::acquire(self.path(), self.path().display()).await
|
||||||
self.path(),
|
|
||||||
LockedFileMode::Exclusive,
|
|
||||||
self.path().display(),
|
|
||||||
)
|
|
||||||
.await?)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -125,14 +109,9 @@ impl CacheShard {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Acquire the cache entry as an exclusive lock.
|
/// Acquire the cache entry as an exclusive lock.
|
||||||
pub async fn lock(&self) -> Result<LockedFile, Error> {
|
pub async fn lock(&self) -> Result<LockedFile, io::Error> {
|
||||||
fs_err::create_dir_all(self.as_ref())?;
|
fs_err::create_dir_all(self.as_ref())?;
|
||||||
Ok(LockedFile::acquire(
|
LockedFile::acquire(self.join(".lock"), self.display()).await
|
||||||
self.join(".lock"),
|
|
||||||
LockedFileMode::Exclusive,
|
|
||||||
self.display(),
|
|
||||||
)
|
|
||||||
.await?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the [`CacheShard`] as a [`PathBuf`].
|
/// Return the [`CacheShard`] as a [`PathBuf`].
|
||||||
|
|
@ -203,7 +182,7 @@ impl Cache {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Acquire a lock that allows removing entries from the cache.
|
/// Acquire a lock that allows removing entries from the cache.
|
||||||
pub async fn with_exclusive_lock(self) -> Result<Self, LockedFileError> {
|
pub fn with_exclusive_lock(self) -> Result<Self, io::Error> {
|
||||||
let Self {
|
let Self {
|
||||||
root,
|
root,
|
||||||
refresh,
|
refresh,
|
||||||
|
|
@ -219,12 +198,8 @@ impl Cache {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let lock_file = LockedFile::acquire(
|
let lock_file =
|
||||||
root.join(".lock"),
|
LockedFile::acquire_blocking(root.join(".lock"), root.simplified_display())?;
|
||||||
LockedFileMode::Exclusive,
|
|
||||||
root.simplified_display(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
root,
|
root,
|
||||||
|
|
@ -245,11 +220,7 @@ impl Cache {
|
||||||
lock_file,
|
lock_file,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
match LockedFile::acquire_no_wait(
|
match LockedFile::acquire_no_wait(root.join(".lock"), root.simplified_display()) {
|
||||||
root.join(".lock"),
|
|
||||||
LockedFileMode::Exclusive,
|
|
||||||
root.simplified_display(),
|
|
||||||
) {
|
|
||||||
Some(lock_file) => Ok(Self {
|
Some(lock_file) => Ok(Self {
|
||||||
root,
|
root,
|
||||||
refresh,
|
refresh,
|
||||||
|
|
@ -401,8 +372,10 @@ impl Cache {
|
||||||
self.temp_dir.is_some()
|
self.temp_dir.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Populate the cache scaffold.
|
/// Initialize the [`Cache`].
|
||||||
fn create_base_files(root: &PathBuf) -> io::Result<()> {
|
pub fn init(self) -> Result<Self, io::Error> {
|
||||||
|
let root = &self.root;
|
||||||
|
|
||||||
// Create the cache directory, if it doesn't exist.
|
// Create the cache directory, if it doesn't exist.
|
||||||
fs_err::create_dir_all(root)?;
|
fs_err::create_dir_all(root)?;
|
||||||
|
|
||||||
|
|
@ -448,66 +421,29 @@ impl Cache {
|
||||||
.join(".git"),
|
.join(".git"),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initialize the [`Cache`].
|
|
||||||
pub async fn init(self) -> Result<Self, Error> {
|
|
||||||
let root = &self.root;
|
|
||||||
|
|
||||||
Self::create_base_files(root)?;
|
|
||||||
|
|
||||||
// Block cache removal operations from interfering.
|
// Block cache removal operations from interfering.
|
||||||
let lock_file = match LockedFile::acquire(
|
let lock_file = match LockedFile::acquire_shared_blocking(
|
||||||
root.join(".lock"),
|
root.join(".lock"),
|
||||||
LockedFileMode::Shared,
|
|
||||||
root.simplified_display(),
|
root.simplified_display(),
|
||||||
)
|
) {
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(lock_file) => Some(Arc::new(lock_file)),
|
Ok(lock_file) => Some(Arc::new(lock_file)),
|
||||||
Err(err)
|
Err(err) if err.kind() == io::ErrorKind::Unsupported => {
|
||||||
if err
|
|
||||||
.as_io_error()
|
|
||||||
.is_some_and(|err| err.kind() == io::ErrorKind::Unsupported) =>
|
|
||||||
{
|
|
||||||
warn!(
|
warn!(
|
||||||
"Shared locking is not supported by the current platform or filesystem, \
|
"Shared locking is not supported by the current platform or filesystem, \
|
||||||
reduced parallel process safety with `uv cache clean` and `uv cache prune`."
|
reduced parallel process safety with `uv cache clean` and `uv cache prune`."
|
||||||
);
|
);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Err(err) => return Err(err.into()),
|
Err(err) => return Err(err),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
root: std::path::absolute(root).map_err(Error::Absolute)?,
|
root: std::path::absolute(root)?,
|
||||||
lock_file,
|
lock_file,
|
||||||
..self
|
..self
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize the [`Cache`], assuming that there are no other uv processes running.
|
|
||||||
pub fn init_no_wait(self) -> Result<Option<Self>, Error> {
|
|
||||||
let root = &self.root;
|
|
||||||
|
|
||||||
Self::create_base_files(root)?;
|
|
||||||
|
|
||||||
// Block cache removal operations from interfering.
|
|
||||||
let Some(lock_file) = LockedFile::acquire_no_wait(
|
|
||||||
root.join(".lock"),
|
|
||||||
LockedFileMode::Shared,
|
|
||||||
root.simplified_display(),
|
|
||||||
) else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
Ok(Some(Self {
|
|
||||||
root: std::path::absolute(root).map_err(Error::Absolute)?,
|
|
||||||
lock_file: Some(Arc::new(lock_file)),
|
|
||||||
..self
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clear the cache, removing all entries.
|
/// Clear the cache, removing all entries.
|
||||||
pub fn clear(self, reporter: Box<dyn CleanReporter>) -> Result<Removal, io::Error> {
|
pub fn clear(self, reporter: Box<dyn CleanReporter>) -> Result<Removal, io::Error> {
|
||||||
// Remove everything but `.lock`, Windows does not allow removal of a locked file
|
// Remove everything but `.lock`, Windows does not allow removal of a locked file
|
||||||
|
|
@ -542,7 +478,7 @@ impl Cache {
|
||||||
/// Remove a package from the cache.
|
/// Remove a package from the cache.
|
||||||
///
|
///
|
||||||
/// Returns the number of entries removed from the cache.
|
/// Returns the number of entries removed from the cache.
|
||||||
pub fn remove(&self, name: &PackageName) -> io::Result<Removal> {
|
pub fn remove(&self, name: &PackageName) -> Result<Removal, io::Error> {
|
||||||
// Collect the set of referenced archives.
|
// Collect the set of referenced archives.
|
||||||
let references = self.find_archive_references()?;
|
let references = self.find_archive_references()?;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ pub enum WheelCache<'a> {
|
||||||
Path(&'a DisplaySafeUrl),
|
Path(&'a DisplaySafeUrl),
|
||||||
/// An editable dependency, which we key by URL.
|
/// An editable dependency, which we key by URL.
|
||||||
Editable(&'a DisplaySafeUrl),
|
Editable(&'a DisplaySafeUrl),
|
||||||
/// A Git dependency, which we key by URL (including LFS state), SHA.
|
/// A Git dependency, which we key by URL and SHA.
|
||||||
///
|
///
|
||||||
/// Note that this variant only exists for source distributions; wheels can't be delivered
|
/// Note that this variant only exists for source distributions; wheels can't be delivered
|
||||||
/// through Git.
|
/// through Git.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-cli"
|
name = "uv-cli"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
description = "This is an internal component crate of uv"
|
description = "This is an internal component crate of uv"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@
|
||||||
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
||||||
is unstable and will have frequent breaking changes.
|
is unstable and will have frequent breaking changes.
|
||||||
|
|
||||||
This version (0.0.8) is a component of [uv 0.9.18](https://crates.io/crates/uv/0.9.18). The source
|
|
||||||
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-cli).
|
|
||||||
|
|
||||||
See uv's
|
See uv's
|
||||||
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
||||||
for details on versioning.
|
for details on versioning.
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -366,7 +366,6 @@ pub fn resolver_options(
|
||||||
exclude_newer_package.unwrap_or_default(),
|
exclude_newer_package.unwrap_or_default(),
|
||||||
),
|
),
|
||||||
link_mode,
|
link_mode,
|
||||||
torch_backend: None,
|
|
||||||
no_build: flag(no_build, build, "build"),
|
no_build: flag(no_build, build, "build"),
|
||||||
no_build_package: Some(no_build_package),
|
no_build_package: Some(no_build_package),
|
||||||
no_binary: flag(no_binary, binary, "binary"),
|
no_binary: flag(no_binary, binary, "binary"),
|
||||||
|
|
@ -496,6 +495,5 @@ pub fn resolver_installer_options(
|
||||||
Some(no_binary_package)
|
Some(no_binary_package)
|
||||||
},
|
},
|
||||||
no_sources: if no_sources { Some(true) } else { None },
|
no_sources: if no_sources { Some(true) } else { None },
|
||||||
torch_backend: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-client"
|
name = "uv-client"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
description = "This is an internal component crate of uv"
|
description = "This is an internal component crate of uv"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@
|
||||||
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
||||||
is unstable and will have frequent breaking changes.
|
is unstable and will have frequent breaking changes.
|
||||||
|
|
||||||
This version (0.0.8) is a component of [uv 0.9.18](https://crates.io/crates/uv/0.9.18). The source
|
|
||||||
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-client).
|
|
||||||
|
|
||||||
See uv's
|
See uv's
|
||||||
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
||||||
for details on versioning.
|
for details on versioning.
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ use tracing::{debug, trace};
|
||||||
use url::ParseError;
|
use url::ParseError;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use uv_auth::{AuthMiddleware, Credentials, CredentialsCache, Indexes, PyxTokenStore};
|
use uv_auth::{AuthMiddleware, Credentials, Indexes, PyxTokenStore};
|
||||||
use uv_configuration::{KeyringProviderType, TrustedHost};
|
use uv_configuration::{KeyringProviderType, TrustedHost};
|
||||||
use uv_fs::Simplified;
|
use uv_fs::Simplified;
|
||||||
use uv_pep508::MarkerEnvironment;
|
use uv_pep508::MarkerEnvironment;
|
||||||
|
|
@ -50,7 +50,7 @@ pub const DEFAULT_RETRIES: u32 = 3;
|
||||||
/// Maximum number of redirects to follow before giving up.
|
/// Maximum number of redirects to follow before giving up.
|
||||||
///
|
///
|
||||||
/// This is the default used by [`reqwest`].
|
/// This is the default used by [`reqwest`].
|
||||||
pub const DEFAULT_MAX_REDIRECTS: u32 = 10;
|
const DEFAULT_MAX_REDIRECTS: u32 = 10;
|
||||||
|
|
||||||
/// Selectively skip parts or the entire auth middleware.
|
/// Selectively skip parts or the entire auth middleware.
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
|
|
@ -78,8 +78,6 @@ pub struct BaseClientBuilder<'a> {
|
||||||
markers: Option<&'a MarkerEnvironment>,
|
markers: Option<&'a MarkerEnvironment>,
|
||||||
platform: Option<&'a Platform>,
|
platform: Option<&'a Platform>,
|
||||||
auth_integration: AuthIntegration,
|
auth_integration: AuthIntegration,
|
||||||
/// Global authentication cache for a uv invocation to share credentials across uv clients.
|
|
||||||
credentials_cache: Arc<CredentialsCache>,
|
|
||||||
indexes: Indexes,
|
indexes: Indexes,
|
||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
extra_middleware: Option<ExtraMiddleware>,
|
extra_middleware: Option<ExtraMiddleware>,
|
||||||
|
|
@ -104,8 +102,6 @@ pub enum RedirectPolicy {
|
||||||
BypassMiddleware,
|
BypassMiddleware,
|
||||||
/// Handle redirects manually, re-triggering our custom middleware for each request.
|
/// Handle redirects manually, re-triggering our custom middleware for each request.
|
||||||
RetriggerMiddleware,
|
RetriggerMiddleware,
|
||||||
/// No redirect for non-cloneable (e.g., streaming) requests with custom redirect logic.
|
|
||||||
NoRedirect,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RedirectPolicy {
|
impl RedirectPolicy {
|
||||||
|
|
@ -113,7 +109,6 @@ impl RedirectPolicy {
|
||||||
match self {
|
match self {
|
||||||
Self::BypassMiddleware => reqwest::redirect::Policy::default(),
|
Self::BypassMiddleware => reqwest::redirect::Policy::default(),
|
||||||
Self::RetriggerMiddleware => reqwest::redirect::Policy::none(),
|
Self::RetriggerMiddleware => reqwest::redirect::Policy::none(),
|
||||||
Self::NoRedirect => reqwest::redirect::Policy::none(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -143,7 +138,6 @@ impl Default for BaseClientBuilder<'_> {
|
||||||
markers: None,
|
markers: None,
|
||||||
platform: None,
|
platform: None,
|
||||||
auth_integration: AuthIntegration::default(),
|
auth_integration: AuthIntegration::default(),
|
||||||
credentials_cache: Arc::new(CredentialsCache::default()),
|
|
||||||
indexes: Indexes::new(),
|
indexes: Indexes::new(),
|
||||||
timeout: Duration::from_secs(30),
|
timeout: Duration::from_secs(30),
|
||||||
extra_middleware: None,
|
extra_middleware: None,
|
||||||
|
|
@ -156,7 +150,7 @@ impl Default for BaseClientBuilder<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> BaseClientBuilder<'a> {
|
impl BaseClientBuilder<'_> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
connectivity: Connectivity,
|
connectivity: Connectivity,
|
||||||
native_tls: bool,
|
native_tls: bool,
|
||||||
|
|
@ -175,7 +169,9 @@ impl<'a> BaseClientBuilder<'a> {
|
||||||
..Self::default()
|
..Self::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> BaseClientBuilder<'a> {
|
||||||
/// Use a custom reqwest client instead of creating a new one.
|
/// Use a custom reqwest client instead of creating a new one.
|
||||||
///
|
///
|
||||||
/// This allows you to provide your own reqwest client with custom configuration.
|
/// This allows you to provide your own reqwest client with custom configuration.
|
||||||
|
|
@ -289,20 +285,6 @@ impl<'a> BaseClientBuilder<'a> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn credentials_cache(&self) -> &CredentialsCache {
|
|
||||||
&self.credentials_cache
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See [`CredentialsCache::store_credentials_from_url`].
|
|
||||||
pub fn store_credentials_from_url(&self, url: &DisplaySafeUrl) -> bool {
|
|
||||||
self.credentials_cache.store_credentials_from_url(url)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See [`CredentialsCache::store_credentials`].
|
|
||||||
pub fn store_credentials(&self, url: &DisplaySafeUrl, credentials: Credentials) {
|
|
||||||
self.credentials_cache.store_credentials(url, credentials);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_native_tls(&self) -> bool {
|
pub fn is_native_tls(&self) -> bool {
|
||||||
self.native_tls
|
self.native_tls
|
||||||
}
|
}
|
||||||
|
|
@ -351,7 +333,6 @@ impl<'a> BaseClientBuilder<'a> {
|
||||||
dangerous_client,
|
dangerous_client,
|
||||||
raw_dangerous_client,
|
raw_dangerous_client,
|
||||||
timeout,
|
timeout,
|
||||||
credentials_cache: self.credentials_cache.clone(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -378,7 +359,6 @@ impl<'a> BaseClientBuilder<'a> {
|
||||||
raw_client: existing.raw_client.clone(),
|
raw_client: existing.raw_client.clone(),
|
||||||
raw_dangerous_client: existing.raw_dangerous_client.clone(),
|
raw_dangerous_client: existing.raw_dangerous_client.clone(),
|
||||||
timeout: existing.timeout,
|
timeout: existing.timeout,
|
||||||
credentials_cache: existing.credentials_cache.clone(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -583,7 +563,6 @@ impl<'a> BaseClientBuilder<'a> {
|
||||||
match self.auth_integration {
|
match self.auth_integration {
|
||||||
AuthIntegration::Default => {
|
AuthIntegration::Default => {
|
||||||
let mut auth_middleware = AuthMiddleware::new()
|
let mut auth_middleware = AuthMiddleware::new()
|
||||||
.with_cache_arc(self.credentials_cache.clone())
|
|
||||||
.with_base_client(base_client)
|
.with_base_client(base_client)
|
||||||
.with_indexes(self.indexes.clone())
|
.with_indexes(self.indexes.clone())
|
||||||
.with_keyring(self.keyring.to_provider())
|
.with_keyring(self.keyring.to_provider())
|
||||||
|
|
@ -595,7 +574,6 @@ impl<'a> BaseClientBuilder<'a> {
|
||||||
}
|
}
|
||||||
AuthIntegration::OnlyAuthenticated => {
|
AuthIntegration::OnlyAuthenticated => {
|
||||||
let mut auth_middleware = AuthMiddleware::new()
|
let mut auth_middleware = AuthMiddleware::new()
|
||||||
.with_cache_arc(self.credentials_cache.clone())
|
|
||||||
.with_base_client(base_client)
|
.with_base_client(base_client)
|
||||||
.with_indexes(self.indexes.clone())
|
.with_indexes(self.indexes.clone())
|
||||||
.with_keyring(self.keyring.to_provider())
|
.with_keyring(self.keyring.to_provider())
|
||||||
|
|
@ -639,8 +617,6 @@ pub struct BaseClient {
|
||||||
allow_insecure_host: Vec<TrustedHost>,
|
allow_insecure_host: Vec<TrustedHost>,
|
||||||
/// The number of retries to attempt on transient errors.
|
/// The number of retries to attempt on transient errors.
|
||||||
retries: u32,
|
retries: u32,
|
||||||
/// Global authentication cache for a uv invocation to share credentials across uv clients.
|
|
||||||
credentials_cache: Arc<CredentialsCache>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
|
@ -692,10 +668,6 @@ impl BaseClient {
|
||||||
}
|
}
|
||||||
builder.build_with_max_retries(self.retries)
|
builder.build_with_max_retries(self.retries)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn credentials_cache(&self) -> &CredentialsCache {
|
|
||||||
&self.credentials_cache
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper around [`ClientWithMiddleware`] that manages redirects.
|
/// Wrapper around [`ClientWithMiddleware`] that manages redirects.
|
||||||
|
|
@ -732,7 +704,6 @@ impl RedirectClientWithMiddleware {
|
||||||
match self.redirect_policy {
|
match self.redirect_policy {
|
||||||
RedirectPolicy::BypassMiddleware => self.client.execute(req).await,
|
RedirectPolicy::BypassMiddleware => self.client.execute(req).await,
|
||||||
RedirectPolicy::RetriggerMiddleware => self.execute_with_redirect_handling(req).await,
|
RedirectPolicy::RetriggerMiddleware => self.execute_with_redirect_handling(req).await,
|
||||||
RedirectPolicy::NoRedirect => self.client.execute(req).await,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ use std::fmt::{Display, Formatter};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use uv_cache::Error as CacheError;
|
|
||||||
use uv_distribution_filename::{WheelFilename, WheelFilenameError};
|
use uv_distribution_filename::{WheelFilename, WheelFilenameError};
|
||||||
use uv_normalize::PackageName;
|
use uv_normalize::PackageName;
|
||||||
use uv_redacted::DisplaySafeUrl;
|
use uv_redacted::DisplaySafeUrl;
|
||||||
|
|
@ -338,9 +337,6 @@ pub enum ErrorKind {
|
||||||
#[error("Failed to write to the client cache")]
|
#[error("Failed to write to the client cache")]
|
||||||
CacheWrite(#[source] std::io::Error),
|
CacheWrite(#[source] std::io::Error),
|
||||||
|
|
||||||
#[error("Failed to acquire lock on the client cache")]
|
|
||||||
CacheLock(#[source] CacheError),
|
|
||||||
|
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Io(std::io::Error),
|
Io(std::io::Error),
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
pub use base_client::{
|
pub use base_client::{
|
||||||
AuthIntegration, BaseClient, BaseClientBuilder, DEFAULT_MAX_REDIRECTS, DEFAULT_RETRIES,
|
AuthIntegration, BaseClient, BaseClientBuilder, DEFAULT_RETRIES, ExtraMiddleware,
|
||||||
ExtraMiddleware, RedirectClientWithMiddleware, RedirectPolicy, RequestBuilder,
|
RedirectClientWithMiddleware, RequestBuilder, RetryParsingError, UvRetryableStrategy,
|
||||||
RetryParsingError, UvRetryableStrategy, is_transient_network_error,
|
is_transient_network_error,
|
||||||
};
|
};
|
||||||
pub use cached_client::{CacheControl, CachedClient, CachedClientError, DataWithCachePolicy};
|
pub use cached_client::{CacheControl, CachedClient, CachedClientError, DataWithCachePolicy};
|
||||||
pub use error::{Error, ErrorKind, WrappedReqwestError};
|
pub use error::{Error, ErrorKind, WrappedReqwestError};
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ use tokio::sync::{Mutex, Semaphore};
|
||||||
use tracing::{Instrument, debug, info_span, instrument, trace, warn};
|
use tracing::{Instrument, debug, info_span, instrument, trace, warn};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use uv_auth::{CredentialsCache, Indexes, PyxTokenStore};
|
use uv_auth::{Indexes, PyxTokenStore};
|
||||||
use uv_cache::{Cache, CacheBucket, CacheEntry, WheelCache};
|
use uv_cache::{Cache, CacheBucket, CacheEntry, WheelCache};
|
||||||
use uv_configuration::IndexStrategy;
|
use uv_configuration::IndexStrategy;
|
||||||
use uv_configuration::KeyringProviderType;
|
use uv_configuration::KeyringProviderType;
|
||||||
|
|
@ -148,30 +148,8 @@ impl<'a> RegistryClientBuilder<'a> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add all authenticated sources to the cache.
|
pub fn build(self) -> RegistryClient {
|
||||||
pub fn cache_index_credentials(&mut self) {
|
self.index_locations.cache_index_credentials();
|
||||||
for index in self.index_locations.known_indexes() {
|
|
||||||
if let Some(credentials) = index.credentials() {
|
|
||||||
trace!(
|
|
||||||
"Read credentials for index {}",
|
|
||||||
index
|
|
||||||
.name
|
|
||||||
.as_ref()
|
|
||||||
.map(ToString::to_string)
|
|
||||||
.unwrap_or_else(|| index.url.to_string())
|
|
||||||
);
|
|
||||||
if let Some(root_url) = index.root_url() {
|
|
||||||
self.base_client_builder
|
|
||||||
.store_credentials(&root_url, credentials.clone());
|
|
||||||
}
|
|
||||||
self.base_client_builder
|
|
||||||
.store_credentials(index.raw_url(), credentials);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build(mut self) -> RegistryClient {
|
|
||||||
self.cache_index_credentials();
|
|
||||||
let index_urls = self.index_locations.index_urls();
|
let index_urls = self.index_locations.index_urls();
|
||||||
|
|
||||||
// Build a base client
|
// Build a base client
|
||||||
|
|
@ -202,8 +180,8 @@ impl<'a> RegistryClientBuilder<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Share the underlying client between two different middleware configurations.
|
/// Share the underlying client between two different middleware configurations.
|
||||||
pub fn wrap_existing(mut self, existing: &BaseClient) -> RegistryClient {
|
pub fn wrap_existing(self, existing: &BaseClient) -> RegistryClient {
|
||||||
self.cache_index_credentials();
|
self.index_locations.cache_index_credentials();
|
||||||
let index_urls = self.index_locations.index_urls();
|
let index_urls = self.index_locations.index_urls();
|
||||||
|
|
||||||
// Wrap in any relevant middleware and handle connectivity.
|
// Wrap in any relevant middleware and handle connectivity.
|
||||||
|
|
@ -291,10 +269,6 @@ impl RegistryClient {
|
||||||
self.timeout
|
self.timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn credentials_cache(&self) -> &CredentialsCache {
|
|
||||||
self.client.uncached().credentials_cache()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the appropriate index URLs for the given [`PackageName`].
|
/// Return the appropriate index URLs for the given [`PackageName`].
|
||||||
fn index_urls_for(
|
fn index_urls_for(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -539,7 +513,7 @@ impl RegistryClient {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let _lock = {
|
let _lock = {
|
||||||
let lock_entry = cache_entry.with_file(format!("{package_name}.lock"));
|
let lock_entry = cache_entry.with_file(format!("{package_name}.lock"));
|
||||||
lock_entry.lock().await.map_err(ErrorKind::CacheLock)?
|
lock_entry.lock().await.map_err(ErrorKind::CacheWrite)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = if matches!(index, IndexUrl::Path(_)) {
|
let result = if matches!(index, IndexUrl::Path(_)) {
|
||||||
|
|
@ -1031,7 +1005,7 @@ impl RegistryClient {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let _lock = {
|
let _lock = {
|
||||||
let lock_entry = cache_entry.with_file(format!("{}.lock", filename.stem()));
|
let lock_entry = cache_entry.with_file(format!("{}.lock", filename.stem()));
|
||||||
lock_entry.lock().await.map_err(ErrorKind::CacheLock)?
|
lock_entry.lock().await.map_err(ErrorKind::CacheWrite)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let response_callback = async |response: Response| {
|
let response_callback = async |response: Response| {
|
||||||
|
|
@ -1115,7 +1089,7 @@ impl RegistryClient {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let _lock = {
|
let _lock = {
|
||||||
let lock_entry = cache_entry.with_file(format!("{}.lock", filename.stem()));
|
let lock_entry = cache_entry.with_file(format!("{}.lock", filename.stem()));
|
||||||
lock_entry.lock().await.map_err(ErrorKind::CacheLock)?
|
lock_entry.lock().await.map_err(ErrorKind::CacheWrite)?
|
||||||
};
|
};
|
||||||
|
|
||||||
// Attempt to fetch via a range request.
|
// Attempt to fetch via a range request.
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use uv_redacted::DisplaySafeUrl;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn remote_metadata_with_and_without_cache() -> Result<()> {
|
async fn remote_metadata_with_and_without_cache() -> Result<()> {
|
||||||
let cache = Cache::temp()?.init().await?;
|
let cache = Cache::temp()?.init()?;
|
||||||
let client = RegistryClientBuilder::new(BaseClientBuilder::default(), cache).build();
|
let client = RegistryClientBuilder::new(BaseClientBuilder::default(), cache).build();
|
||||||
|
|
||||||
// The first run is without cache (the tempdir is empty), the second has the cache from the
|
// The first run is without cache (the tempdir is empty), the second has the cache from the
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ async fn ssl_env_vars() -> Result<()> {
|
||||||
}
|
}
|
||||||
let (server_task, addr) = start_https_user_agent_server(&standalone_server_cert).await?;
|
let (server_task, addr) = start_https_user_agent_server(&standalone_server_cert).await?;
|
||||||
let url = DisplaySafeUrl::from_str(&format!("https://{addr}"))?;
|
let url = DisplaySafeUrl::from_str(&format!("https://{addr}"))?;
|
||||||
let cache = Cache::temp()?.init().await?;
|
let cache = Cache::temp()?.init()?;
|
||||||
let client = RegistryClientBuilder::new(BaseClientBuilder::default(), cache).build();
|
let client = RegistryClientBuilder::new(BaseClientBuilder::default(), cache).build();
|
||||||
let res = client
|
let res = client
|
||||||
.cached_client()
|
.cached_client()
|
||||||
|
|
@ -142,7 +142,7 @@ async fn ssl_env_vars() -> Result<()> {
|
||||||
}
|
}
|
||||||
let (server_task, addr) = start_https_user_agent_server(&standalone_server_cert).await?;
|
let (server_task, addr) = start_https_user_agent_server(&standalone_server_cert).await?;
|
||||||
let url = DisplaySafeUrl::from_str(&format!("https://{addr}"))?;
|
let url = DisplaySafeUrl::from_str(&format!("https://{addr}"))?;
|
||||||
let cache = Cache::temp()?.init().await?;
|
let cache = Cache::temp()?.init()?;
|
||||||
let client = RegistryClientBuilder::new(BaseClientBuilder::default(), cache).build();
|
let client = RegistryClientBuilder::new(BaseClientBuilder::default(), cache).build();
|
||||||
let res = client
|
let res = client
|
||||||
.cached_client()
|
.cached_client()
|
||||||
|
|
@ -171,7 +171,7 @@ async fn ssl_env_vars() -> Result<()> {
|
||||||
}
|
}
|
||||||
let (server_task, addr) = start_https_user_agent_server(&standalone_server_cert).await?;
|
let (server_task, addr) = start_https_user_agent_server(&standalone_server_cert).await?;
|
||||||
let url = DisplaySafeUrl::from_str(&format!("https://{addr}"))?;
|
let url = DisplaySafeUrl::from_str(&format!("https://{addr}"))?;
|
||||||
let cache = Cache::temp()?.init().await?;
|
let cache = Cache::temp()?.init()?;
|
||||||
let client = RegistryClientBuilder::new(BaseClientBuilder::default(), cache).build();
|
let client = RegistryClientBuilder::new(BaseClientBuilder::default(), cache).build();
|
||||||
let res = client
|
let res = client
|
||||||
.cached_client()
|
.cached_client()
|
||||||
|
|
@ -194,7 +194,7 @@ async fn ssl_env_vars() -> Result<()> {
|
||||||
}
|
}
|
||||||
let (server_task, addr) = start_https_user_agent_server(&standalone_server_cert).await?;
|
let (server_task, addr) = start_https_user_agent_server(&standalone_server_cert).await?;
|
||||||
let url = DisplaySafeUrl::from_str(&format!("https://{addr}"))?;
|
let url = DisplaySafeUrl::from_str(&format!("https://{addr}"))?;
|
||||||
let cache = Cache::temp()?.init().await?;
|
let cache = Cache::temp()?.init()?;
|
||||||
let client = RegistryClientBuilder::new(BaseClientBuilder::default(), cache).build();
|
let client = RegistryClientBuilder::new(BaseClientBuilder::default(), cache).build();
|
||||||
let res = client
|
let res = client
|
||||||
.cached_client()
|
.cached_client()
|
||||||
|
|
@ -259,7 +259,7 @@ async fn ssl_env_vars() -> Result<()> {
|
||||||
}
|
}
|
||||||
let (server_task, addr) = start_https_mtls_user_agent_server(&ca_cert, &server_cert).await?;
|
let (server_task, addr) = start_https_mtls_user_agent_server(&ca_cert, &server_cert).await?;
|
||||||
let url = DisplaySafeUrl::from_str(&format!("https://{addr}"))?;
|
let url = DisplaySafeUrl::from_str(&format!("https://{addr}"))?;
|
||||||
let cache = Cache::temp()?.init().await?;
|
let cache = Cache::temp()?.init()?;
|
||||||
let client = RegistryClientBuilder::new(BaseClientBuilder::default(), cache).build();
|
let client = RegistryClientBuilder::new(BaseClientBuilder::default(), cache).build();
|
||||||
let res = client
|
let res = client
|
||||||
.cached_client()
|
.cached_client()
|
||||||
|
|
@ -283,7 +283,7 @@ async fn ssl_env_vars() -> Result<()> {
|
||||||
}
|
}
|
||||||
let (server_task, addr) = start_https_mtls_user_agent_server(&ca_cert, &server_cert).await?;
|
let (server_task, addr) = start_https_mtls_user_agent_server(&ca_cert, &server_cert).await?;
|
||||||
let url = DisplaySafeUrl::from_str(&format!("https://{addr}"))?;
|
let url = DisplaySafeUrl::from_str(&format!("https://{addr}"))?;
|
||||||
let cache = Cache::temp()?.init().await?;
|
let cache = Cache::temp()?.init()?;
|
||||||
let client = RegistryClientBuilder::new(BaseClientBuilder::default(), cache).build();
|
let client = RegistryClientBuilder::new(BaseClientBuilder::default(), cache).build();
|
||||||
let res = client
|
let res = client
|
||||||
.cached_client()
|
.cached_client()
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ async fn test_user_agent_has_version() -> Result<()> {
|
||||||
let (server_task, addr) = start_http_user_agent_server().await?;
|
let (server_task, addr) = start_http_user_agent_server().await?;
|
||||||
|
|
||||||
// Initialize uv-client
|
// Initialize uv-client
|
||||||
let cache = Cache::temp()?.init().await?;
|
let cache = Cache::temp()?.init()?;
|
||||||
let client = RegistryClientBuilder::new(BaseClientBuilder::default(), cache).build();
|
let client = RegistryClientBuilder::new(BaseClientBuilder::default(), cache).build();
|
||||||
|
|
||||||
// Send request to our dummy server
|
// Send request to our dummy server
|
||||||
|
|
@ -75,7 +75,7 @@ async fn test_user_agent_has_subcommand() -> Result<()> {
|
||||||
let (server_task, addr) = start_http_user_agent_server().await?;
|
let (server_task, addr) = start_http_user_agent_server().await?;
|
||||||
|
|
||||||
// Initialize uv-client
|
// Initialize uv-client
|
||||||
let cache = Cache::temp()?.init().await?;
|
let cache = Cache::temp()?.init()?;
|
||||||
let client = RegistryClientBuilder::new(
|
let client = RegistryClientBuilder::new(
|
||||||
BaseClientBuilder::default().subcommand(vec!["foo".to_owned(), "bar".to_owned()]),
|
BaseClientBuilder::default().subcommand(vec!["foo".to_owned(), "bar".to_owned()]),
|
||||||
cache,
|
cache,
|
||||||
|
|
@ -152,7 +152,7 @@ async fn test_user_agent_has_linehaul() -> Result<()> {
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Initialize uv-client
|
// Initialize uv-client
|
||||||
let cache = Cache::temp()?.init().await?;
|
let cache = Cache::temp()?.init()?;
|
||||||
let mut builder =
|
let mut builder =
|
||||||
RegistryClientBuilder::new(BaseClientBuilder::default(), cache).markers(&markers);
|
RegistryClientBuilder::new(BaseClientBuilder::default(), cache).markers(&markers);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-configuration"
|
name = "uv-configuration"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
description = "This is an internal component crate of uv"
|
description = "This is an internal component crate of uv"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@
|
||||||
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
||||||
is unstable and will have frequent breaking changes.
|
is unstable and will have frequent breaking changes.
|
||||||
|
|
||||||
This version (0.0.8) is a component of [uv 0.9.18](https://crates.io/crates/uv/0.9.18). The source
|
|
||||||
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-configuration).
|
|
||||||
|
|
||||||
See uv's
|
See uv's
|
||||||
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
||||||
for details on versioning.
|
for details on versioning.
|
||||||
|
|
|
||||||
|
|
@ -94,32 +94,3 @@ wheels/
|
||||||
# Virtual environments
|
# Virtual environments
|
||||||
.venv
|
.venv
|
||||||
";
|
";
|
||||||
|
|
||||||
/// Setting for Git LFS (Large File Storage) support.
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
|
||||||
pub enum GitLfsSetting {
|
|
||||||
/// Git LFS is disabled (default).
|
|
||||||
#[default]
|
|
||||||
Disabled,
|
|
||||||
/// Git LFS is enabled. Tracks whether it came from an environment variable.
|
|
||||||
Enabled { from_env: bool },
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GitLfsSetting {
|
|
||||||
pub fn new(from_arg: Option<bool>, from_env: Option<bool>) -> Self {
|
|
||||||
match (from_arg, from_env) {
|
|
||||||
(Some(true), _) => Self::Enabled { from_env: false },
|
|
||||||
(_, Some(true)) => Self::Enabled { from_env: true },
|
|
||||||
_ => Self::Disabled,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<GitLfsSetting> for Option<bool> {
|
|
||||||
fn from(setting: GitLfsSetting) -> Self {
|
|
||||||
match setting {
|
|
||||||
GitLfsSetting::Enabled { .. } => Some(true),
|
|
||||||
GitLfsSetting::Disabled => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-console"
|
name = "uv-console"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
description = "This is an internal component crate of uv"
|
description = "This is an internal component crate of uv"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@
|
||||||
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
||||||
is unstable and will have frequent breaking changes.
|
is unstable and will have frequent breaking changes.
|
||||||
|
|
||||||
This version (0.0.8) is a component of [uv 0.9.18](https://crates.io/crates/uv/0.9.18). The source
|
|
||||||
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-console).
|
|
||||||
|
|
||||||
See uv's
|
See uv's
|
||||||
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
||||||
for details on versioning.
|
for details on versioning.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-dev"
|
name = "uv-dev"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
description = "This is an internal component crate of uv"
|
description = "This is an internal component crate of uv"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
|
|
@ -79,4 +79,4 @@ performance-memory-allocator = ["dep:uv-performance-memory-allocator"]
|
||||||
render = ["poloto", "resvg", "tagu"]
|
render = ["poloto", "resvg", "tagu"]
|
||||||
|
|
||||||
[package.metadata.cargo-shear]
|
[package.metadata.cargo-shear]
|
||||||
ignored = ["uv-performance-memory-allocator"]
|
ignored = ["flate2", "uv-extract", "uv-performance-memory-allocator"]
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@
|
||||||
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
||||||
is unstable and will have frequent breaking changes.
|
is unstable and will have frequent breaking changes.
|
||||||
|
|
||||||
This version (0.0.8) is a component of [uv 0.9.18](https://crates.io/crates/uv/0.9.18). The source
|
|
||||||
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-dev).
|
|
||||||
|
|
||||||
See uv's
|
See uv's
|
||||||
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
||||||
for details on versioning.
|
for details on versioning.
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ pub(crate) struct CompileArgs {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn compile(args: CompileArgs) -> anyhow::Result<()> {
|
pub(crate) async fn compile(args: CompileArgs) -> anyhow::Result<()> {
|
||||||
let cache = Cache::try_from(args.cache_args)?.init().await?;
|
let cache = Cache::try_from(args.cache_args)?.init()?;
|
||||||
|
|
||||||
let interpreter = if let Some(python) = args.python {
|
let interpreter = if let Some(python) = args.python {
|
||||||
python
|
python
|
||||||
|
|
|
||||||
|
|
@ -342,3 +342,31 @@ fn emit_possible_options(opt: &clap::Arg, output: &mut String) {
|
||||||
output.push_str(&markdown::to_html(&value));
|
output.push_str(&markdown::to_html(&value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use uv_static::EnvVars;
|
||||||
|
|
||||||
|
use crate::generate_all::Mode;
|
||||||
|
|
||||||
|
use super::{Args, main};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_generate_cli_reference() -> Result<()> {
|
||||||
|
// Skip this test in CI to avoid redundancy with the dedicated CI job
|
||||||
|
if env::var_os(EnvVars::CI).is_some() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mode = if env::var(EnvVars::UV_UPDATE_SCHEMA).as_deref() == Ok("1") {
|
||||||
|
Mode::Write
|
||||||
|
} else {
|
||||||
|
Mode::Check
|
||||||
|
};
|
||||||
|
main(&Args { mode })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -106,3 +106,31 @@ fn render(var: &str, doc: &str, added_in: Option<&str>) -> String {
|
||||||
format!("### `{var}`\n\n{doc}\n\n")
|
format!("### `{var}`\n\n{doc}\n\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use uv_static::EnvVars;
|
||||||
|
|
||||||
|
use crate::generate_all::Mode;
|
||||||
|
|
||||||
|
use super::{Args, main};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_generate_env_vars_reference() -> Result<()> {
|
||||||
|
// Skip this test in CI to avoid redundancy with the dedicated CI job
|
||||||
|
if env::var_os(EnvVars::CI).is_some() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mode = if env::var(EnvVars::UV_UPDATE_SCHEMA).as_deref() == Ok("1") {
|
||||||
|
Mode::Write
|
||||||
|
} else {
|
||||||
|
Mode::Check
|
||||||
|
};
|
||||||
|
main(&Args { mode })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -387,3 +387,31 @@ impl Visit for CollectOptionsVisitor {
|
||||||
self.fields.push((name.to_owned(), field));
|
self.fields.push((name.to_owned(), field));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use uv_static::EnvVars;
|
||||||
|
|
||||||
|
use crate::generate_all::Mode;
|
||||||
|
|
||||||
|
use super::{Args, main};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_generate_options_reference() -> Result<()> {
|
||||||
|
// Skip this test in CI to avoid redundancy with the dedicated CI job
|
||||||
|
if env::var_os(EnvVars::CI).is_some() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mode = if env::var(EnvVars::UV_UPDATE_SCHEMA).as_deref() == Ok("1") {
|
||||||
|
Mode::Write
|
||||||
|
} else {
|
||||||
|
Mode::Check
|
||||||
|
};
|
||||||
|
main(&Args { mode })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use crate::ROOT_DIR;
|
||||||
use crate::generate_all::Mode;
|
use crate::generate_all::Mode;
|
||||||
|
|
||||||
/// Contains current supported targets
|
/// Contains current supported targets
|
||||||
const TARGETS_YML_URL: &str = "https://raw.githubusercontent.com/astral-sh/python-build-standalone/refs/tags/20251209/cpython-unix/targets.yml";
|
const TARGETS_YML_URL: &str = "https://raw.githubusercontent.com/astral-sh/python-build-standalone/refs/tags/20251120/cpython-unix/targets.yml";
|
||||||
|
|
||||||
#[derive(clap::Args)]
|
#[derive(clap::Args)]
|
||||||
pub(crate) struct Args {
|
pub(crate) struct Args {
|
||||||
|
|
@ -130,7 +130,7 @@ async fn generate() -> Result<String> {
|
||||||
output.push_str("//! DO NOT EDIT\n");
|
output.push_str("//! DO NOT EDIT\n");
|
||||||
output.push_str("//!\n");
|
output.push_str("//!\n");
|
||||||
output.push_str("//! Generated with `cargo run dev generate-sysconfig-metadata`\n");
|
output.push_str("//! Generated with `cargo run dev generate-sysconfig-metadata`\n");
|
||||||
output.push_str("//! Targets from <https://github.com/astral-sh/python-build-standalone/blob/20251209/cpython-unix/targets.yml>\n");
|
output.push_str("//! Targets from <https://github.com/astral-sh/python-build-standalone/blob/20251120/cpython-unix/targets.yml>\n");
|
||||||
output.push_str("//!\n");
|
output.push_str("//!\n");
|
||||||
|
|
||||||
// Disable clippy/fmt
|
// Disable clippy/fmt
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ pub(crate) async fn list_packages(
|
||||||
args: ListPackagesArgs,
|
args: ListPackagesArgs,
|
||||||
environment: EnvironmentOptions,
|
environment: EnvironmentOptions,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let cache = Cache::try_from(args.cache_args)?.init().await?;
|
let cache = Cache::try_from(args.cache_args)?.init()?;
|
||||||
let client = RegistryClientBuilder::new(
|
let client = RegistryClientBuilder::new(
|
||||||
BaseClientBuilder::default().timeout(environment.http_timeout),
|
BaseClientBuilder::default().timeout(environment.http_timeout),
|
||||||
cache,
|
cache,
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ pub(crate) async fn validate_zip(
|
||||||
args: ValidateZipArgs,
|
args: ValidateZipArgs,
|
||||||
environment: EnvironmentOptions,
|
environment: EnvironmentOptions,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let cache = Cache::try_from(args.cache_args)?.init().await?;
|
let cache = Cache::try_from(args.cache_args)?.init()?;
|
||||||
let client = RegistryClientBuilder::new(
|
let client = RegistryClientBuilder::new(
|
||||||
BaseClientBuilder::default().timeout(environment.http_timeout),
|
BaseClientBuilder::default().timeout(environment.http_timeout),
|
||||||
cache,
|
cache,
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ pub(crate) async fn wheel_metadata(
|
||||||
args: WheelMetadataArgs,
|
args: WheelMetadataArgs,
|
||||||
environment: EnvironmentOptions,
|
environment: EnvironmentOptions,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let cache = Cache::try_from(args.cache_args)?.init().await?;
|
let cache = Cache::try_from(args.cache_args)?.init()?;
|
||||||
let client = RegistryClientBuilder::new(
|
let client = RegistryClientBuilder::new(
|
||||||
BaseClientBuilder::default().timeout(environment.http_timeout),
|
BaseClientBuilder::default().timeout(environment.http_timeout),
|
||||||
cache,
|
cache,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-dirs"
|
name = "uv-dirs"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
description = "This is an internal component crate of uv"
|
description = "This is an internal component crate of uv"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@
|
||||||
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
||||||
is unstable and will have frequent breaking changes.
|
is unstable and will have frequent breaking changes.
|
||||||
|
|
||||||
This version (0.0.8) is a component of [uv 0.9.18](https://crates.io/crates/uv/0.9.18). The source
|
|
||||||
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-dirs).
|
|
||||||
|
|
||||||
See uv's
|
See uv's
|
||||||
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
||||||
for details on versioning.
|
for details on versioning.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-dispatch"
|
name = "uv-dispatch"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
description = "This is an internal component crate of uv"
|
description = "This is an internal component crate of uv"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@
|
||||||
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
||||||
is unstable and will have frequent breaking changes.
|
is unstable and will have frequent breaking changes.
|
||||||
|
|
||||||
This version (0.0.8) is a component of [uv 0.9.18](https://crates.io/crates/uv/0.9.18). The source
|
|
||||||
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-dispatch).
|
|
||||||
|
|
||||||
See uv's
|
See uv's
|
||||||
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
||||||
for details on versioning.
|
for details on versioning.
|
||||||
|
|
|
||||||
|
|
@ -492,7 +492,6 @@ impl BuildContext for BuildDispatch<'_> {
|
||||||
environment_variables,
|
environment_variables,
|
||||||
build_output,
|
build_output,
|
||||||
self.concurrency.builds,
|
self.concurrency.builds,
|
||||||
self.client.credentials_cache(),
|
|
||||||
self.preview,
|
self.preview,
|
||||||
)
|
)
|
||||||
.boxed_local()
|
.boxed_local()
|
||||||
|
|
@ -505,7 +504,6 @@ impl BuildContext for BuildDispatch<'_> {
|
||||||
source: &'data Path,
|
source: &'data Path,
|
||||||
subdirectory: Option<&'data Path>,
|
subdirectory: Option<&'data Path>,
|
||||||
output_dir: &'data Path,
|
output_dir: &'data Path,
|
||||||
sources: SourceStrategy,
|
|
||||||
build_kind: BuildKind,
|
build_kind: BuildKind,
|
||||||
version_id: Option<&'data str>,
|
version_id: Option<&'data str>,
|
||||||
) -> Result<Option<DistFilename>, BuildDispatchError> {
|
) -> Result<Option<DistFilename>, BuildDispatchError> {
|
||||||
|
|
@ -534,7 +532,6 @@ impl BuildContext for BuildDispatch<'_> {
|
||||||
&output_dir,
|
&output_dir,
|
||||||
None,
|
None,
|
||||||
uv_version::version(),
|
uv_version::version(),
|
||||||
sources == SourceStrategy::Enabled,
|
|
||||||
)?;
|
)?;
|
||||||
DistFilename::WheelFilename(wheel)
|
DistFilename::WheelFilename(wheel)
|
||||||
}
|
}
|
||||||
|
|
@ -543,7 +540,6 @@ impl BuildContext for BuildDispatch<'_> {
|
||||||
&source_tree,
|
&source_tree,
|
||||||
&output_dir,
|
&output_dir,
|
||||||
uv_version::version(),
|
uv_version::version(),
|
||||||
sources == SourceStrategy::Enabled,
|
|
||||||
)?;
|
)?;
|
||||||
DistFilename::SourceDistFilename(source_dist)
|
DistFilename::SourceDistFilename(source_dist)
|
||||||
}
|
}
|
||||||
|
|
@ -553,7 +549,6 @@ impl BuildContext for BuildDispatch<'_> {
|
||||||
&output_dir,
|
&output_dir,
|
||||||
None,
|
None,
|
||||||
uv_version::version(),
|
uv_version::version(),
|
||||||
sources == SourceStrategy::Enabled,
|
|
||||||
)?;
|
)?;
|
||||||
DistFilename::WheelFilename(wheel)
|
DistFilename::WheelFilename(wheel)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-distribution-filename"
|
name = "uv-distribution-filename"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
description = "This is an internal component crate of uv"
|
description = "This is an internal component crate of uv"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@
|
||||||
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
||||||
is unstable and will have frequent breaking changes.
|
is unstable and will have frequent breaking changes.
|
||||||
|
|
||||||
This version (0.0.8) is a component of [uv 0.9.18](https://crates.io/crates/uv/0.9.18). The source
|
|
||||||
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-distribution-filename).
|
|
||||||
|
|
||||||
See uv's
|
See uv's
|
||||||
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
||||||
for details on versioning.
|
for details on versioning.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-distribution-types"
|
name = "uv-distribution-types"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
description = "This is an internal component crate of uv"
|
description = "This is an internal component crate of uv"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@
|
||||||
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
||||||
is unstable and will have frequent breaking changes.
|
is unstable and will have frequent breaking changes.
|
||||||
|
|
||||||
This version (0.0.8) is a component of [uv 0.9.18](https://crates.io/crates/uv/0.9.18). The source
|
|
||||||
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-distribution-types).
|
|
||||||
|
|
||||||
See uv's
|
See uv's
|
||||||
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
||||||
for details on versioning.
|
for details on versioning.
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ use std::sync::{Arc, LazyLock, RwLock};
|
||||||
use itertools::Either;
|
use itertools::Either;
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
use tracing::trace;
|
||||||
use url::{ParseError, Url};
|
use url::{ParseError, Url};
|
||||||
use uv_auth::RealmRef;
|
use uv_auth::RealmRef;
|
||||||
use uv_cache_key::CanonicalUrl;
|
use uv_cache_key::CanonicalUrl;
|
||||||
|
|
@ -439,6 +440,26 @@ impl<'a> IndexLocations {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add all authenticated sources to the cache.
|
||||||
|
pub fn cache_index_credentials(&self) {
|
||||||
|
for index in self.known_indexes() {
|
||||||
|
if let Some(credentials) = index.credentials() {
|
||||||
|
trace!(
|
||||||
|
"Read credentials for index {}",
|
||||||
|
index
|
||||||
|
.name
|
||||||
|
.as_ref()
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.unwrap_or_else(|| index.url.to_string())
|
||||||
|
);
|
||||||
|
if let Some(root_url) = index.root_url() {
|
||||||
|
uv_auth::store_credentials(&root_url, credentials.clone());
|
||||||
|
}
|
||||||
|
uv_auth::store_credentials(index.raw_url(), credentials);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the Simple API cache control header for an [`IndexUrl`], if configured.
|
/// Return the Simple API cache control header for an [`IndexUrl`], if configured.
|
||||||
pub fn simple_api_cache_control_for(&self, url: &IndexUrl) -> Option<&str> {
|
pub fn simple_api_cache_control_for(&self, url: &IndexUrl) -> Option<&str> {
|
||||||
for index in &self.indexes {
|
for index in &self.indexes {
|
||||||
|
|
|
||||||
|
|
@ -159,9 +159,9 @@ pub enum InstalledVersion<'a> {
|
||||||
Url(&'a DisplaySafeUrl, &'a Version),
|
Url(&'a DisplaySafeUrl, &'a Version),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> InstalledVersion<'a> {
|
impl InstalledVersion<'_> {
|
||||||
/// If it is a URL, return its value.
|
/// If it is a URL, return its value.
|
||||||
pub fn url(&self) -> Option<&'a DisplaySafeUrl> {
|
pub fn url(&self) -> Option<&DisplaySafeUrl> {
|
||||||
match self {
|
match self {
|
||||||
Self::Version(_) => None,
|
Self::Version(_) => None,
|
||||||
Self::Url(url, _) => Some(url),
|
Self::Url(url, _) => Some(url),
|
||||||
|
|
@ -169,7 +169,7 @@ impl<'a> InstalledVersion<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If it is a version, return its value.
|
/// If it is a version, return its value.
|
||||||
pub fn version(&self) -> &'a Version {
|
pub fn version(&self) -> &Version {
|
||||||
match self {
|
match self {
|
||||||
Self::Version(version) => version,
|
Self::Version(version) => version,
|
||||||
Self::Url(_, version) => version,
|
Self::Url(_, version) => version,
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use thiserror::Error;
|
||||||
use uv_cache_key::{CacheKey, CacheKeyHasher};
|
use uv_cache_key::{CacheKey, CacheKeyHasher};
|
||||||
use uv_distribution_filename::DistExtension;
|
use uv_distribution_filename::DistExtension;
|
||||||
use uv_fs::{CWD, PortablePath, PortablePathBuf, relative_to};
|
use uv_fs::{CWD, PortablePath, PortablePathBuf, relative_to};
|
||||||
use uv_git_types::{GitLfs, GitOid, GitReference, GitUrl, GitUrlParseError, OidParseError};
|
use uv_git_types::{GitOid, GitReference, GitUrl, GitUrlParseError, OidParseError};
|
||||||
use uv_normalize::{ExtraName, GroupName, PackageName};
|
use uv_normalize::{ExtraName, GroupName, PackageName};
|
||||||
use uv_pep440::VersionSpecifiers;
|
use uv_pep440::VersionSpecifiers;
|
||||||
use uv_pep508::{
|
use uv_pep508::{
|
||||||
|
|
@ -350,13 +350,6 @@ impl Display for Requirement {
|
||||||
if let Some(subdirectory) = subdirectory {
|
if let Some(subdirectory) = subdirectory {
|
||||||
writeln!(f, "#subdirectory={}", subdirectory.display())?;
|
writeln!(f, "#subdirectory={}", subdirectory.display())?;
|
||||||
}
|
}
|
||||||
if git.lfs().enabled() {
|
|
||||||
writeln!(
|
|
||||||
f,
|
|
||||||
"{}lfs=true",
|
|
||||||
if subdirectory.is_some() { "&" } else { "#" }
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
RequirementSource::Path { url, .. } => {
|
RequirementSource::Path { url, .. } => {
|
||||||
write!(f, " @ {url}")?;
|
write!(f, " @ {url}")?;
|
||||||
|
|
@ -443,9 +436,6 @@ impl CacheKey for Requirement {
|
||||||
} else {
|
} else {
|
||||||
0u8.cache_key(state);
|
0u8.cache_key(state);
|
||||||
}
|
}
|
||||||
if git.lfs().enabled() {
|
|
||||||
1u8.cache_key(state);
|
|
||||||
}
|
|
||||||
url.cache_key(state);
|
url.cache_key(state);
|
||||||
}
|
}
|
||||||
RequirementSource::Path {
|
RequirementSource::Path {
|
||||||
|
|
@ -775,13 +765,6 @@ impl Display for RequirementSource {
|
||||||
if let Some(subdirectory) = subdirectory {
|
if let Some(subdirectory) = subdirectory {
|
||||||
writeln!(f, "#subdirectory={}", subdirectory.display())?;
|
writeln!(f, "#subdirectory={}", subdirectory.display())?;
|
||||||
}
|
}
|
||||||
if git.lfs().enabled() {
|
|
||||||
writeln!(
|
|
||||||
f,
|
|
||||||
"{}lfs=true",
|
|
||||||
if subdirectory.is_some() { "&" } else { "#" }
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Self::Path { url, .. } => {
|
Self::Path { url, .. } => {
|
||||||
write!(f, "{url}")?;
|
write!(f, "{url}")?;
|
||||||
|
|
@ -873,11 +856,6 @@ impl From<RequirementSource> for RequirementSourceWire {
|
||||||
.append_pair("subdirectory", &subdirectory);
|
.append_pair("subdirectory", &subdirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Persist lfs=true in the distribution metadata only when explicitly enabled.
|
|
||||||
if git.lfs().enabled() {
|
|
||||||
url.query_pairs_mut().append_pair("lfs", "true");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put the requested reference in the query.
|
// Put the requested reference in the query.
|
||||||
match git.reference() {
|
match git.reference() {
|
||||||
GitReference::Branch(branch) => {
|
GitReference::Branch(branch) => {
|
||||||
|
|
@ -954,7 +932,6 @@ impl TryFrom<RequirementSourceWire> for RequirementSource {
|
||||||
|
|
||||||
let mut reference = GitReference::DefaultBranch;
|
let mut reference = GitReference::DefaultBranch;
|
||||||
let mut subdirectory: Option<PortablePathBuf> = None;
|
let mut subdirectory: Option<PortablePathBuf> = None;
|
||||||
let mut lfs = GitLfs::Disabled;
|
|
||||||
for (key, val) in repository.query_pairs() {
|
for (key, val) in repository.query_pairs() {
|
||||||
match &*key {
|
match &*key {
|
||||||
"tag" => reference = GitReference::Tag(val.into_owned()),
|
"tag" => reference = GitReference::Tag(val.into_owned()),
|
||||||
|
|
@ -963,7 +940,6 @@ impl TryFrom<RequirementSourceWire> for RequirementSource {
|
||||||
"subdirectory" => {
|
"subdirectory" => {
|
||||||
subdirectory = Some(PortablePathBuf::from(val.as_ref()));
|
subdirectory = Some(PortablePathBuf::from(val.as_ref()));
|
||||||
}
|
}
|
||||||
"lfs" => lfs = GitLfs::from(val.eq_ignore_ascii_case("true")),
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -983,22 +959,13 @@ impl TryFrom<RequirementSourceWire> for RequirementSource {
|
||||||
let path = format!("{}@{}", url.path(), rev);
|
let path = format!("{}@{}", url.path(), rev);
|
||||||
url.set_path(&path);
|
url.set_path(&path);
|
||||||
}
|
}
|
||||||
let mut frags: Vec<String> = Vec::new();
|
|
||||||
if let Some(subdirectory) = subdirectory.as_ref() {
|
if let Some(subdirectory) = subdirectory.as_ref() {
|
||||||
frags.push(format!("subdirectory={subdirectory}"));
|
url.set_fragment(Some(&format!("subdirectory={subdirectory}")));
|
||||||
}
|
}
|
||||||
// Preserve that we're using Git LFS in the Verbatim Url representations
|
|
||||||
if lfs.enabled() {
|
|
||||||
frags.push("lfs=true".to_string());
|
|
||||||
}
|
|
||||||
if !frags.is_empty() {
|
|
||||||
url.set_fragment(Some(&frags.join("&")));
|
|
||||||
}
|
|
||||||
|
|
||||||
let url = VerbatimUrl::from_url(url);
|
let url = VerbatimUrl::from_url(url);
|
||||||
|
|
||||||
Ok(Self::Git {
|
Ok(Self::Git {
|
||||||
git: GitUrl::from_fields(repository, reference, precise, lfs)?,
|
git: GitUrl::from_fields(repository, reference, precise)?,
|
||||||
subdirectory: subdirectory.map(Box::<Path>::from),
|
subdirectory: subdirectory.map(Box::<Path>::from),
|
||||||
url,
|
url,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
use uv_git_types::{GitLfs, GitReference};
|
use uv_git_types::GitReference;
|
||||||
use uv_normalize::ExtraName;
|
use uv_normalize::ExtraName;
|
||||||
use uv_pep508::{MarkerEnvironment, MarkerTree, UnnamedRequirement};
|
use uv_pep508::{MarkerEnvironment, MarkerTree, UnnamedRequirement};
|
||||||
use uv_pypi_types::{Hashes, ParsedUrl};
|
use uv_pypi_types::{Hashes, ParsedUrl};
|
||||||
|
|
@ -75,7 +75,6 @@ impl UnresolvedRequirement {
|
||||||
rev: Option<&str>,
|
rev: Option<&str>,
|
||||||
tag: Option<&str>,
|
tag: Option<&str>,
|
||||||
branch: Option<&str>,
|
branch: Option<&str>,
|
||||||
lfs: Option<bool>,
|
|
||||||
marker: Option<MarkerTree>,
|
marker: Option<MarkerTree>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
#[allow(clippy::manual_map)]
|
#[allow(clippy::manual_map)]
|
||||||
|
|
@ -108,11 +107,6 @@ impl UnresolvedRequirement {
|
||||||
} else {
|
} else {
|
||||||
git
|
git
|
||||||
};
|
};
|
||||||
let git = if let Some(lfs) = lfs {
|
|
||||||
git.with_lfs(GitLfs::from(lfs))
|
|
||||||
} else {
|
|
||||||
git
|
|
||||||
};
|
|
||||||
RequirementSource::Git {
|
RequirementSource::Git {
|
||||||
git,
|
git,
|
||||||
subdirectory,
|
subdirectory,
|
||||||
|
|
@ -135,9 +129,6 @@ impl UnresolvedRequirement {
|
||||||
if let Some(git_reference) = git_reference {
|
if let Some(git_reference) = git_reference {
|
||||||
git.url = git.url.with_reference(git_reference);
|
git.url = git.url.with_reference(git_reference);
|
||||||
}
|
}
|
||||||
if let Some(lfs) = lfs {
|
|
||||||
git.url = git.url.with_lfs(GitLfs::from(lfs));
|
|
||||||
}
|
|
||||||
VerbatimParsedUrl {
|
VerbatimParsedUrl {
|
||||||
parsed_url: ParsedUrl::Git(git),
|
parsed_url: ParsedUrl::Git(git),
|
||||||
verbatim: requirement.url.verbatim,
|
verbatim: requirement.url.verbatim,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-distribution"
|
name = "uv-distribution"
|
||||||
version = "0.0.8"
|
version = "0.0.4"
|
||||||
description = "This is an internal component crate of uv"
|
description = "This is an internal component crate of uv"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
@ -24,7 +24,6 @@ uv-configuration = { workspace = true }
|
||||||
uv-distribution-filename = { workspace = true }
|
uv-distribution-filename = { workspace = true }
|
||||||
uv-distribution-types = { workspace = true }
|
uv-distribution-types = { workspace = true }
|
||||||
uv-extract = { workspace = true }
|
uv-extract = { workspace = true }
|
||||||
uv-flags = { workspace = true }
|
|
||||||
uv-fs = { workspace = true, features = ["tokio"] }
|
uv-fs = { workspace = true, features = ["tokio"] }
|
||||||
uv-git = { workspace = true }
|
uv-git = { workspace = true }
|
||||||
uv-git-types = { workspace = true }
|
uv-git-types = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@
|
||||||
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
This crate is an internal component of [uv](https://crates.io/crates/uv). The Rust API exposed here
|
||||||
is unstable and will have frequent breaking changes.
|
is unstable and will have frequent breaking changes.
|
||||||
|
|
||||||
This version (0.0.8) is a component of [uv 0.9.18](https://crates.io/crates/uv/0.9.18). The source
|
|
||||||
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-distribution).
|
|
||||||
|
|
||||||
See uv's
|
See uv's
|
||||||
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
||||||
for details on versioning.
|
for details on versioning.
|
||||||
|
|
|
||||||
|
|
@ -385,27 +385,6 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
|
||||||
.boxed_local()
|
.boxed_local()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// Check that the wheel is compatible with its install target.
|
|
||||||
//
|
|
||||||
// When building a build dependency for a cross-install, the build dependency needs
|
|
||||||
// to install and run on the host instead of the target. In this case the `tags` are already
|
|
||||||
// for the host instead of the target, so this check passes.
|
|
||||||
if !built_wheel.filename.is_compatible(tags) {
|
|
||||||
return if tags.is_cross() {
|
|
||||||
Err(Error::BuiltWheelIncompatibleTargetPlatform {
|
|
||||||
filename: built_wheel.filename,
|
|
||||||
python_platform: tags.python_platform().clone(),
|
|
||||||
python_version: tags.python_version(),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Err(Error::BuiltWheelIncompatibleHostPlatform {
|
|
||||||
filename: built_wheel.filename,
|
|
||||||
python_platform: tags.python_platform().clone(),
|
|
||||||
python_version: tags.python_version(),
|
|
||||||
})
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Acquire the advisory lock.
|
// Acquire the advisory lock.
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let _lock = {
|
let _lock = {
|
||||||
|
|
@ -416,7 +395,7 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
|
||||||
built_wheel.target.file_name().unwrap().to_str().unwrap()
|
built_wheel.target.file_name().unwrap().to_str().unwrap()
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
lock_entry.lock().await.map_err(Error::CacheLock)?
|
lock_entry.lock().await.map_err(Error::CacheWrite)?
|
||||||
};
|
};
|
||||||
|
|
||||||
// If the wheel was unzipped previously, respect it. Source distributions are
|
// If the wheel was unzipped previously, respect it. Source distributions are
|
||||||
|
|
@ -575,11 +554,7 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
|
||||||
pyproject_toml: &PyProjectToml,
|
pyproject_toml: &PyProjectToml,
|
||||||
) -> Result<Option<RequiresDist>, Error> {
|
) -> Result<Option<RequiresDist>, Error> {
|
||||||
self.builder
|
self.builder
|
||||||
.source_tree_requires_dist(
|
.source_tree_requires_dist(path, pyproject_toml)
|
||||||
path,
|
|
||||||
pyproject_toml,
|
|
||||||
self.client.unmanaged.credentials_cache(),
|
|
||||||
)
|
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -599,7 +574,7 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let _lock = {
|
let _lock = {
|
||||||
let lock_entry = wheel_entry.with_file(format!("{}.lock", filename.stem()));
|
let lock_entry = wheel_entry.with_file(format!("{}.lock", filename.stem()));
|
||||||
lock_entry.lock().await.map_err(Error::CacheLock)?
|
lock_entry.lock().await.map_err(Error::CacheWrite)?
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create an entry for the HTTP cache.
|
// Create an entry for the HTTP cache.
|
||||||
|
|
@ -770,7 +745,7 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let _lock = {
|
let _lock = {
|
||||||
let lock_entry = wheel_entry.with_file(format!("{}.lock", filename.stem()));
|
let lock_entry = wheel_entry.with_file(format!("{}.lock", filename.stem()));
|
||||||
lock_entry.lock().await.map_err(Error::CacheLock)?
|
lock_entry.lock().await.map_err(Error::CacheWrite)?
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create an entry for the HTTP cache.
|
// Create an entry for the HTTP cache.
|
||||||
|
|
@ -972,7 +947,7 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let _lock = {
|
let _lock = {
|
||||||
let lock_entry = wheel_entry.with_file(format!("{}.lock", filename.stem()));
|
let lock_entry = wheel_entry.with_file(format!("{}.lock", filename.stem()));
|
||||||
lock_entry.lock().await.map_err(Error::CacheLock)?
|
lock_entry.lock().await.map_err(Error::CacheWrite)?
|
||||||
};
|
};
|
||||||
|
|
||||||
// Determine the last-modified time of the wheel.
|
// Determine the last-modified time of the wheel.
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,12 @@ use tokio::task::JoinError;
|
||||||
use zip::result::ZipError;
|
use zip::result::ZipError;
|
||||||
|
|
||||||
use crate::metadata::MetadataError;
|
use crate::metadata::MetadataError;
|
||||||
use uv_cache::Error as CacheError;
|
|
||||||
use uv_client::WrappedReqwestError;
|
use uv_client::WrappedReqwestError;
|
||||||
use uv_distribution_filename::{WheelFilename, WheelFilenameError};
|
use uv_distribution_filename::WheelFilenameError;
|
||||||
use uv_distribution_types::{InstalledDist, InstalledDistError, IsBuildBackendError};
|
use uv_distribution_types::{InstalledDist, InstalledDistError, IsBuildBackendError};
|
||||||
use uv_fs::Simplified;
|
use uv_fs::Simplified;
|
||||||
use uv_git::GitError;
|
|
||||||
use uv_normalize::PackageName;
|
use uv_normalize::PackageName;
|
||||||
use uv_pep440::{Version, VersionSpecifiers};
|
use uv_pep440::{Version, VersionSpecifiers};
|
||||||
use uv_platform_tags::Platform;
|
|
||||||
use uv_pypi_types::{HashAlgorithm, HashDigest};
|
use uv_pypi_types::{HashAlgorithm, HashDigest};
|
||||||
use uv_redacted::DisplaySafeUrl;
|
use uv_redacted::DisplaySafeUrl;
|
||||||
use uv_types::AnyErrorBuild;
|
use uv_types::AnyErrorBuild;
|
||||||
|
|
@ -42,8 +39,6 @@ pub enum Error {
|
||||||
CacheRead(#[source] std::io::Error),
|
CacheRead(#[source] std::io::Error),
|
||||||
#[error("Failed to write to the distribution cache")]
|
#[error("Failed to write to the distribution cache")]
|
||||||
CacheWrite(#[source] std::io::Error),
|
CacheWrite(#[source] std::io::Error),
|
||||||
#[error("Failed to acquire lock on the distribution cache")]
|
|
||||||
CacheLock(#[source] CacheError),
|
|
||||||
#[error("Failed to deserialize cache entry")]
|
#[error("Failed to deserialize cache entry")]
|
||||||
CacheDecode(#[from] rmp_serde::decode::Error),
|
CacheDecode(#[from] rmp_serde::decode::Error),
|
||||||
#[error("Failed to serialize cache entry")]
|
#[error("Failed to serialize cache entry")]
|
||||||
|
|
@ -79,35 +74,6 @@ pub enum Error {
|
||||||
filename: Version,
|
filename: Version,
|
||||||
metadata: Version,
|
metadata: Version,
|
||||||
},
|
},
|
||||||
/// This shouldn't happen, it's a bug in the build backend.
|
|
||||||
#[error(
|
|
||||||
"The built wheel `{}` is not compatible with the current Python {}.{} on {} {}",
|
|
||||||
filename,
|
|
||||||
python_version.0,
|
|
||||||
python_version.1,
|
|
||||||
python_platform.os(),
|
|
||||||
python_platform.arch(),
|
|
||||||
)]
|
|
||||||
BuiltWheelIncompatibleHostPlatform {
|
|
||||||
filename: WheelFilename,
|
|
||||||
python_platform: Platform,
|
|
||||||
python_version: (u8, u8),
|
|
||||||
},
|
|
||||||
/// This may happen when trying to cross-install native dependencies without their build backend
|
|
||||||
/// being aware that the target is a cross-install.
|
|
||||||
#[error(
|
|
||||||
"The built wheel `{}` is not compatible with the target Python {}.{} on {} {}. Consider using `--no-build` to disable building wheels.",
|
|
||||||
filename,
|
|
||||||
python_version.0,
|
|
||||||
python_version.1,
|
|
||||||
python_platform.os(),
|
|
||||||
python_platform.arch(),
|
|
||||||
)]
|
|
||||||
BuiltWheelIncompatibleTargetPlatform {
|
|
||||||
filename: WheelFilename,
|
|
||||||
python_platform: Platform,
|
|
||||||
python_version: (u8, u8),
|
|
||||||
},
|
|
||||||
#[error("Failed to parse metadata from built wheel")]
|
#[error("Failed to parse metadata from built wheel")]
|
||||||
Metadata(#[from] uv_pypi_types::MetadataError),
|
Metadata(#[from] uv_pypi_types::MetadataError),
|
||||||
#[error("Failed to read metadata: `{}`", _0.user_display())]
|
#[error("Failed to read metadata: `{}`", _0.user_display())]
|
||||||
|
|
@ -122,8 +88,6 @@ pub enum Error {
|
||||||
MissingPkgInfo,
|
MissingPkgInfo,
|
||||||
#[error("The source distribution `{}` has no subdirectory `{}`", _0, _1.display())]
|
#[error("The source distribution `{}` has no subdirectory `{}`", _0, _1.display())]
|
||||||
MissingSubdirectory(DisplaySafeUrl, PathBuf),
|
MissingSubdirectory(DisplaySafeUrl, PathBuf),
|
||||||
#[error("The source distribution `{0}` is missing Git LFS artifacts.")]
|
|
||||||
MissingGitLfsArtifacts(DisplaySafeUrl, #[source] GitError),
|
|
||||||
#[error("Failed to extract static metadata from `PKG-INFO`")]
|
#[error("Failed to extract static metadata from `PKG-INFO`")]
|
||||||
PkgInfo(#[source] uv_pypi_types::MetadataError),
|
PkgInfo(#[source] uv_pypi_types::MetadataError),
|
||||||
#[error("Failed to extract metadata from `requires.txt`")]
|
#[error("Failed to extract metadata from `requires.txt`")]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use uv_auth::CredentialsCache;
|
|
||||||
use uv_configuration::SourceStrategy;
|
use uv_configuration::SourceStrategy;
|
||||||
use uv_distribution_types::{
|
use uv_distribution_types::{
|
||||||
ExtraBuildRequirement, ExtraBuildRequires, IndexLocations, Requirement,
|
ExtraBuildRequirement, ExtraBuildRequires, IndexLocations, Requirement,
|
||||||
|
|
@ -42,7 +42,6 @@ impl BuildRequires {
|
||||||
locations: &IndexLocations,
|
locations: &IndexLocations,
|
||||||
sources: SourceStrategy,
|
sources: SourceStrategy,
|
||||||
cache: &WorkspaceCache,
|
cache: &WorkspaceCache,
|
||||||
credentials_cache: &CredentialsCache,
|
|
||||||
) -> Result<Self, MetadataError> {
|
) -> Result<Self, MetadataError> {
|
||||||
let discovery = match sources {
|
let discovery = match sources {
|
||||||
SourceStrategy::Enabled => DiscoveryOptions::default(),
|
SourceStrategy::Enabled => DiscoveryOptions::default(),
|
||||||
|
|
@ -57,13 +56,7 @@ impl BuildRequires {
|
||||||
return Ok(Self::from_metadata23(metadata));
|
return Ok(Self::from_metadata23(metadata));
|
||||||
};
|
};
|
||||||
|
|
||||||
Self::from_project_workspace(
|
Self::from_project_workspace(metadata, &project_workspace, locations, sources)
|
||||||
metadata,
|
|
||||||
&project_workspace,
|
|
||||||
locations,
|
|
||||||
sources,
|
|
||||||
credentials_cache,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lower the `build-system.requires` field from a `pyproject.toml` file.
|
/// Lower the `build-system.requires` field from a `pyproject.toml` file.
|
||||||
|
|
@ -72,7 +65,6 @@ impl BuildRequires {
|
||||||
project_workspace: &ProjectWorkspace,
|
project_workspace: &ProjectWorkspace,
|
||||||
locations: &IndexLocations,
|
locations: &IndexLocations,
|
||||||
source_strategy: SourceStrategy,
|
source_strategy: SourceStrategy,
|
||||||
credentials_cache: &CredentialsCache,
|
|
||||||
) -> Result<Self, MetadataError> {
|
) -> Result<Self, MetadataError> {
|
||||||
// Collect any `tool.uv.index` entries.
|
// Collect any `tool.uv.index` entries.
|
||||||
let empty = vec![];
|
let empty = vec![];
|
||||||
|
|
@ -122,7 +114,6 @@ impl BuildRequires {
|
||||||
locations,
|
locations,
|
||||||
project_workspace.workspace(),
|
project_workspace.workspace(),
|
||||||
None,
|
None,
|
||||||
credentials_cache,
|
|
||||||
)
|
)
|
||||||
.map(move |requirement| match requirement {
|
.map(move |requirement| match requirement {
|
||||||
Ok(requirement) => Ok(requirement.into_inner()),
|
Ok(requirement) => Ok(requirement.into_inner()),
|
||||||
|
|
@ -148,7 +139,6 @@ impl BuildRequires {
|
||||||
workspace: &Workspace,
|
workspace: &Workspace,
|
||||||
locations: &IndexLocations,
|
locations: &IndexLocations,
|
||||||
source_strategy: SourceStrategy,
|
source_strategy: SourceStrategy,
|
||||||
credentials_cache: &CredentialsCache,
|
|
||||||
) -> Result<Self, MetadataError> {
|
) -> Result<Self, MetadataError> {
|
||||||
// Collect any `tool.uv.index` entries.
|
// Collect any `tool.uv.index` entries.
|
||||||
let empty = vec![];
|
let empty = vec![];
|
||||||
|
|
@ -196,7 +186,6 @@ impl BuildRequires {
|
||||||
locations,
|
locations,
|
||||||
workspace,
|
workspace,
|
||||||
None,
|
None,
|
||||||
credentials_cache,
|
|
||||||
)
|
)
|
||||||
.map(move |requirement| match requirement {
|
.map(move |requirement| match requirement {
|
||||||
Ok(requirement) => Ok(requirement.into_inner()),
|
Ok(requirement) => Ok(requirement.into_inner()),
|
||||||
|
|
@ -236,7 +225,6 @@ impl LoweredExtraBuildDependencies {
|
||||||
workspace: &Workspace,
|
workspace: &Workspace,
|
||||||
index_locations: &IndexLocations,
|
index_locations: &IndexLocations,
|
||||||
source_strategy: SourceStrategy,
|
source_strategy: SourceStrategy,
|
||||||
credentials_cache: &CredentialsCache,
|
|
||||||
) -> Result<Self, MetadataError> {
|
) -> Result<Self, MetadataError> {
|
||||||
match source_strategy {
|
match source_strategy {
|
||||||
SourceStrategy::Enabled => {
|
SourceStrategy::Enabled => {
|
||||||
|
|
@ -283,7 +271,6 @@ impl LoweredExtraBuildDependencies {
|
||||||
index_locations,
|
index_locations,
|
||||||
workspace,
|
workspace,
|
||||||
None,
|
None,
|
||||||
credentials_cache,
|
|
||||||
)
|
)
|
||||||
.map(move |requirement| {
|
.map(move |requirement| {
|
||||||
match requirement {
|
match requirement {
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue