mirror of https://github.com/astral-sh/uv
Compare commits
43 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
9949f0801f | |
|
|
c1d3c9bdb2 | |
|
|
1ddb646a74 | |
|
|
994b108af2 | |
|
|
e2a775d727 | |
|
|
44d1a302c8 | |
|
|
a25d4f953f | |
|
|
9f422e7515 | |
|
|
9360ca7778 | |
|
|
6fa8204efe | |
|
|
6578e0521b | |
|
|
0a83bf7dd5 | |
|
|
e603761862 | |
|
|
4f6f56b070 | |
|
|
66f7093ad2 | |
|
|
60df92f9aa | |
|
|
0cee76417f | |
|
|
af348c2a88 | |
|
|
b58f543e5e | |
|
|
13e7ad62cb | |
|
|
94c97b6434 | |
|
|
af95677b9b | |
|
|
a5d50a20d2 | |
|
|
a768a9d111 | |
|
|
d20948bec2 | |
|
|
a2d64aa224 | |
|
|
c43315f4eb | |
|
|
e77ee15204 | |
|
|
ed37f3b432 | |
|
|
3e80b10272 | |
|
|
7ad441a0bd | |
|
|
5a55bbe883 | |
|
|
6ad80c5150 | |
|
|
38ae414682 | |
|
|
6de869cc88 | |
|
|
59d73fdddf | |
|
|
4c1571fb76 | |
|
|
ebdffaf728 | |
|
|
3bb7f67c71 | |
|
|
caac4814df | |
|
|
a550743bed | |
|
|
94f1f02d85 | |
|
|
36806f8e66 |
|
|
@ -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-alpine,python3.14-alpine
|
- python:3.14-alpine3.23,python3.14-alpine3.23,python3.14-alpine
|
||||||
- python:3.13-alpine,python3.13-alpine
|
- python:3.13-alpine3.23,python3.13-alpine3.23,python3.13-alpine
|
||||||
- python:3.12-alpine,python3.12-alpine
|
- python:3.12-alpine3.23,python3.12-alpine3.23,python3.12-alpine
|
||||||
- python:3.11-alpine,python3.11-alpine
|
- python:3.11-alpine3.23,python3.11-alpine3.23,python3.11-alpine
|
||||||
- python:3.10-alpine,python3.10-alpine
|
- python:3.10-alpine3.23,python3.10-alpine3.23,python3.10-alpine
|
||||||
- python:3.9-alpine,python3.9-alpine
|
- python:3.9-alpine3.22,python3.9-alpine3.22,python3.9-alpine
|
||||||
- python:3.8-alpine,python3.8-alpine
|
- python:3.8-alpine3.20,python3.8-alpine3.20,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
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: "Install cargo shear"
|
- name: "Install cargo shear"
|
||||||
uses: taiki-e/install-action@a416ddeedbd372e614cc1386e8b642692f66865e # v2.57.1
|
uses: taiki-e/install-action@d850aa816998e5cf15f67a78c7b933f2a5033f8a # v2.63.3
|
||||||
with:
|
with:
|
||||||
tool: cargo-shear
|
tool: cargo-shear
|
||||||
- run: cargo shear
|
- run: cargo shear
|
||||||
|
|
@ -289,6 +289,7 @@ 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
|
||||||
|
|
@ -330,6 +331,7 @@ 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,git-lfs,performance,crates-io,native-auth,apple-native \
|
||||||
--workspace \
|
--workspace \
|
||||||
|
|
@ -385,6 +387,7 @@ 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 \
|
||||||
|
|
@ -561,15 +564,15 @@ jobs:
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
||||||
|
|
||||||
- name: "Build"
|
- name: "Build"
|
||||||
run: cargo build
|
run: cargo build --profile no-debug
|
||||||
|
|
||||||
- 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/debug/uv
|
./target/no-debug/uv
|
||||||
./target/debug/uvx
|
./target/no-debug/uvx
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
build-binary-linux-aarch64:
|
build-binary-linux-aarch64:
|
||||||
|
|
@ -588,15 +591,15 @@ jobs:
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
||||||
|
|
||||||
- name: "Build"
|
- name: "Build"
|
||||||
run: cargo build
|
run: cargo build --profile no-debug
|
||||||
|
|
||||||
- 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/debug/uv
|
./target/no-debug/uv
|
||||||
./target/debug/uvx
|
./target/no-debug/uvx
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
build-binary-linux-musl:
|
build-binary-linux-musl:
|
||||||
|
|
@ -620,15 +623,15 @@ jobs:
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
||||||
|
|
||||||
- name: "Build"
|
- name: "Build"
|
||||||
run: cargo build --target x86_64-unknown-linux-musl --bin uv --bin uvx
|
run: cargo build --profile no-debug --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/debug/uv
|
./target/x86_64-unknown-linux-musl/no-debug/uv
|
||||||
./target/x86_64-unknown-linux-musl/debug/uvx
|
./target/x86_64-unknown-linux-musl/no-debug/uvx
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
build-binary-macos-aarch64:
|
build-binary-macos-aarch64:
|
||||||
|
|
@ -646,15 +649,15 @@ jobs:
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
||||||
- name: "Build"
|
- name: "Build"
|
||||||
run: cargo build --bin uv --bin uvx
|
run: cargo build --profile no-debug --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/debug/uv
|
./target/no-debug/uv
|
||||||
./target/debug/uvx
|
./target/no-debug/uvx
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
build-binary-macos-x86_64:
|
build-binary-macos-x86_64:
|
||||||
|
|
@ -672,15 +675,15 @@ jobs:
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
||||||
- name: "Build"
|
- name: "Build"
|
||||||
run: cargo build --bin uv --bin uvx
|
run: cargo build --profile no-debug --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/debug/uv
|
./target/no-debug/uv
|
||||||
./target/debug/uvx
|
./target/no-debug/uvx
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
build-binary-windows-x86_64:
|
build-binary-windows-x86_64:
|
||||||
|
|
@ -708,15 +711,15 @@ jobs:
|
||||||
|
|
||||||
- name: "Build"
|
- name: "Build"
|
||||||
working-directory: ${{ env.UV_WORKSPACE }}
|
working-directory: ${{ env.UV_WORKSPACE }}
|
||||||
run: cargo build --bin uv --bin uvx
|
run: cargo build --profile no-debug --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/debug/uv.exe
|
${{ env.UV_WORKSPACE }}/target/no-debug/uv.exe
|
||||||
${{ env.UV_WORKSPACE }}/target/debug/uvx.exe
|
${{ env.UV_WORKSPACE }}/target/no-debug/uvx.exe
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
build-binary-windows-aarch64:
|
build-binary-windows-aarch64:
|
||||||
|
|
@ -748,15 +751,15 @@ jobs:
|
||||||
|
|
||||||
- name: "Build"
|
- name: "Build"
|
||||||
working-directory: ${{ env.UV_WORKSPACE }}
|
working-directory: ${{ env.UV_WORKSPACE }}
|
||||||
run: cargo build --target aarch64-pc-windows-msvc
|
run: cargo build --profile no-debug --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/debug/uv.exe
|
${{ env.UV_WORKSPACE }}/target/aarch64-pc-windows-msvc/no-debug/uv.exe
|
||||||
${{ env.UV_WORKSPACE }}/target/aarch64-pc-windows-msvc/debug/uvx.exe
|
${{ env.UV_WORKSPACE }}/target/aarch64-pc-windows-msvc/no-debug/uvx.exe
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
build-binary-msrv:
|
build-binary-msrv:
|
||||||
|
|
@ -781,10 +784,10 @@ jobs:
|
||||||
- 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@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
||||||
- run: cargo +${MSRV} build
|
- run: cargo +${MSRV} build --profile no-debug
|
||||||
env:
|
env:
|
||||||
MSRV: ${{ steps.msrv.outputs.value }}
|
MSRV: ${{ steps.msrv.outputs.value }}
|
||||||
- run: ./target/debug/uv --version
|
- run: ./target/no-debug/uv --version
|
||||||
|
|
||||||
build-binary-freebsd:
|
build-binary-freebsd:
|
||||||
needs: determine_changes
|
needs: determine_changes
|
||||||
|
|
@ -805,7 +808,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
|
cross build --target x86_64-unknown-freebsd --profile no-debug
|
||||||
|
|
||||||
- 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
|
||||||
|
|
@ -819,8 +822,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/debug
|
target/x86_64-unknown-freebsd/no-debug
|
||||||
target/x86_64-unknown-freebsd/debug/uv
|
target/x86_64-unknown-freebsd/no-debug/uv
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
rsync -r -e "ssh" \
|
rsync -r -e "ssh" \
|
||||||
|
|
@ -830,7 +833,7 @@ jobs:
|
||||||
--exclude "*" \
|
--exclude "*" \
|
||||||
. firecracker:
|
. firecracker:
|
||||||
run-in-vm: |
|
run-in-vm: |
|
||||||
mv target/x86_64-unknown-freebsd/debug/uv uv
|
mv target/x86_64-unknown-freebsd/no-debug/uv uv
|
||||||
chmod +x uv
|
chmod +x uv
|
||||||
./uv --version
|
./uv --version
|
||||||
|
|
||||||
|
|
|
||||||
37
CHANGELOG.md
37
CHANGELOG.md
|
|
@ -3,6 +3,43 @@
|
||||||
<!-- 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
|
## 0.9.17
|
||||||
|
|
||||||
Released on 2025-12-09.
|
Released on 2025-12-09.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,125 @@
|
||||||
|
# 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
|
||||||
|
|
@ -102,6 +102,15 @@ 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
|
||||||
|
|
|
||||||
|
|
@ -227,9 +227,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "astral-reqwest-retry"
|
name = "astral-reqwest-retry"
|
||||||
version = "0.7.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cb7549bd00f62f73f2e7e76f3f77ccdabb31873f4f02f758ed88ad739d522867"
|
checksum = "78ab210f6cdf8fd3254d47e5ee27ce60ed34a428ff71b4ae9477b1c84b49498c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"astral-reqwest-middleware",
|
"astral-reqwest-middleware",
|
||||||
|
|
@ -1038,6 +1038,15 @@ 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"
|
||||||
|
|
@ -1255,6 +1264,16 @@ 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"
|
||||||
|
|
@ -3443,9 +3462,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon"
|
name = "rayon"
|
||||||
version = "1.10.0"
|
version = "1.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
"rayon-core",
|
"rayon-core",
|
||||||
|
|
@ -3453,9 +3472,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon-core"
|
name = "rayon-core"
|
||||||
version = "1.12.1"
|
version = "1.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
|
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-deque",
|
"crossbeam-deque",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
|
|
@ -3734,11 +3753,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "retry-policies"
|
name = "retry-policies"
|
||||||
version = "0.4.0"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5875471e6cab2871bc150ecb8c727db5113c9338cc3354dc5ee3425b6aa40a1c"
|
checksum = "46a4bd6027df676bcb752d3724db0ea3c0c5fc1dd0376fec51ac7dcaf9cc69be"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand 0.8.5",
|
"rand 0.9.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -4378,9 +4397,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spdx"
|
name = "spdx"
|
||||||
version = "0.12.0"
|
version = "0.13.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "41cf87c0efffc158b9dde4d6e0567a43e4383adc4c949e687a2039732db2f23a"
|
checksum = "35107b1c818f4e9cb9e6c4444ca560ba03b4ee1288dcecc6d7830c2023a7609e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"smallvec",
|
"smallvec",
|
||||||
]
|
]
|
||||||
|
|
@ -5387,7 +5406,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv"
|
name = "uv"
|
||||||
version = "0.9.17"
|
version = "0.9.18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
|
@ -5402,6 +5421,7 @@ dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"console 0.16.1",
|
"console 0.16.1",
|
||||||
"ctrlc",
|
"ctrlc",
|
||||||
|
"diskus",
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
"dunce",
|
"dunce",
|
||||||
"embed-manifest",
|
"embed-manifest",
|
||||||
|
|
@ -5409,7 +5429,6 @@ dependencies = [
|
||||||
"flate2",
|
"flate2",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
"futures",
|
"futures",
|
||||||
"h2",
|
|
||||||
"http",
|
"http",
|
||||||
"ignore",
|
"ignore",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
|
@ -5506,7 +5525,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-auth"
|
name = "uv-auth"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arcstr",
|
"arcstr",
|
||||||
|
|
@ -5549,7 +5568,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-bench"
|
name = "uv-bench"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"codspeed-criterion-compat",
|
"codspeed-criterion-compat",
|
||||||
|
|
@ -5576,7 +5595,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-bin-install"
|
name = "uv-bin-install"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"astral-reqwest-middleware",
|
"astral-reqwest-middleware",
|
||||||
"astral-reqwest-retry",
|
"astral-reqwest-retry",
|
||||||
|
|
@ -5587,13 +5606,11 @@ dependencies = [
|
||||||
"thiserror 2.0.17",
|
"thiserror 2.0.17",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tracing",
|
|
||||||
"url",
|
"url",
|
||||||
"uv-cache",
|
"uv-cache",
|
||||||
"uv-client",
|
"uv-client",
|
||||||
"uv-distribution-filename",
|
"uv-distribution-filename",
|
||||||
"uv-extract",
|
"uv-extract",
|
||||||
"uv-fs",
|
|
||||||
"uv-pep440",
|
"uv-pep440",
|
||||||
"uv-platform",
|
"uv-platform",
|
||||||
"uv-redacted",
|
"uv-redacted",
|
||||||
|
|
@ -5601,7 +5618,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-build"
|
name = "uv-build"
|
||||||
version = "0.9.17"
|
version = "0.9.18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
|
@ -5613,7 +5630,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-build-backend"
|
name = "uv-build-backend"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"astral-version-ranges",
|
"astral-version-ranges",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
|
|
@ -5629,7 +5646,7 @@ dependencies = [
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"sha2",
|
"sha2",
|
||||||
"spdx 0.12.0",
|
"spdx 0.13.2",
|
||||||
"tar",
|
"tar",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"thiserror 2.0.17",
|
"thiserror 2.0.17",
|
||||||
|
|
@ -5653,7 +5670,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-build-frontend"
|
name = "uv-build-frontend"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
|
|
@ -5691,7 +5708,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-cache"
|
name = "uv-cache"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
|
|
@ -5701,6 +5718,7 @@ 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",
|
||||||
|
|
@ -5716,7 +5734,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-cache-info"
|
name = "uv-cache-info"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
|
|
@ -5733,7 +5751,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-cache-key"
|
name = "uv-cache-key"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hex",
|
"hex",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
|
@ -5745,7 +5763,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-cli"
|
name = "uv-cli"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
|
@ -5777,7 +5795,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-client"
|
name = "uv-client"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"astral-reqwest-middleware",
|
"astral-reqwest-middleware",
|
||||||
|
|
@ -5840,7 +5858,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-configuration"
|
name = "uv-configuration"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
|
|
@ -5869,14 +5887,14 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-console"
|
name = "uv-console"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console 0.16.1",
|
"console 0.16.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-dev"
|
name = "uv-dev"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
|
@ -5925,7 +5943,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-dirs"
|
name = "uv-dirs"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_fs",
|
"assert_fs",
|
||||||
"etcetera",
|
"etcetera",
|
||||||
|
|
@ -5937,7 +5955,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-dispatch"
|
name = "uv-dispatch"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"futures",
|
"futures",
|
||||||
|
|
@ -5969,7 +5987,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-distribution"
|
name = "uv-distribution"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"astral-reqwest-middleware",
|
"astral-reqwest-middleware",
|
||||||
|
|
@ -6018,7 +6036,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-distribution-filename"
|
name = "uv-distribution-filename"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"insta",
|
"insta",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
|
@ -6035,7 +6053,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-distribution-types"
|
name = "uv-distribution-types"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arcstr",
|
"arcstr",
|
||||||
"astral-version-ranges",
|
"astral-version-ranges",
|
||||||
|
|
@ -6075,7 +6093,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-extract"
|
name = "uv-extract"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"astral-tokio-tar",
|
"astral-tokio-tar",
|
||||||
"astral_async_zip",
|
"astral_async_zip",
|
||||||
|
|
@ -6105,14 +6123,14 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-flags"
|
name = "uv-flags"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.4",
|
"bitflags 2.9.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-fs"
|
name = "uv-fs"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backon",
|
"backon",
|
||||||
"dunce",
|
"dunce",
|
||||||
|
|
@ -6136,7 +6154,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-git"
|
name = "uv-git"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"astral-reqwest-middleware",
|
"astral-reqwest-middleware",
|
||||||
|
|
@ -6162,7 +6180,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-git-types"
|
name = "uv-git-types"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror 2.0.17",
|
"thiserror 2.0.17",
|
||||||
|
|
@ -6174,7 +6192,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-globfilter"
|
name = "uv-globfilter"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
|
|
@ -6191,7 +6209,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-install-wheel"
|
name = "uv-install-wheel"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"assert_fs",
|
"assert_fs",
|
||||||
|
|
@ -6231,7 +6249,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-installer"
|
name = "uv-installer"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-channel",
|
"async-channel",
|
||||||
|
|
@ -6272,7 +6290,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-keyring"
|
name = "uv-keyring"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
|
|
@ -6289,7 +6307,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-logging"
|
name = "uv-logging"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jiff",
|
"jiff",
|
||||||
"owo-colors",
|
"owo-colors",
|
||||||
|
|
@ -6299,7 +6317,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-macros"
|
name = "uv-macros"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -6309,7 +6327,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-metadata"
|
name = "uv-metadata"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"astral_async_zip",
|
"astral_async_zip",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
|
|
@ -6326,7 +6344,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-normalize"
|
name = "uv-normalize"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rkyv",
|
"rkyv",
|
||||||
"schemars",
|
"schemars",
|
||||||
|
|
@ -6336,7 +6354,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-once-map"
|
name = "uv-once-map"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dashmap",
|
"dashmap",
|
||||||
"futures",
|
"futures",
|
||||||
|
|
@ -6345,14 +6363,14 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-options-metadata"
|
name = "uv-options-metadata"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-pep440"
|
name = "uv-pep440"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"astral-version-ranges",
|
"astral-version-ranges",
|
||||||
"indoc",
|
"indoc",
|
||||||
|
|
@ -6366,7 +6384,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-pep508"
|
name = "uv-pep508"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arcstr",
|
"arcstr",
|
||||||
"astral-version-ranges",
|
"astral-version-ranges",
|
||||||
|
|
@ -6395,7 +6413,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-performance-memory-allocator"
|
name = "uv-performance-memory-allocator"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"mimalloc",
|
"mimalloc",
|
||||||
"tikv-jemallocator",
|
"tikv-jemallocator",
|
||||||
|
|
@ -6403,7 +6421,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-platform"
|
name = "uv-platform"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fs-err",
|
"fs-err",
|
||||||
"goblin",
|
"goblin",
|
||||||
|
|
@ -6420,7 +6438,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-platform-tags"
|
name = "uv-platform-tags"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"insta",
|
"insta",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
|
@ -6433,7 +6451,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-preview"
|
name = "uv-preview"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.4",
|
"bitflags 2.9.4",
|
||||||
"thiserror 2.0.17",
|
"thiserror 2.0.17",
|
||||||
|
|
@ -6442,9 +6460,10 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-publish"
|
name = "uv-publish"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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",
|
||||||
|
|
@ -6478,11 +6497,12 @@ 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.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"hashbrown 0.16.1",
|
"hashbrown 0.16.1",
|
||||||
|
|
@ -6514,7 +6534,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-python"
|
name = "uv-python"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"assert_fs",
|
"assert_fs",
|
||||||
|
|
@ -6576,7 +6596,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-redacted"
|
name = "uv-redacted"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ref-cast",
|
"ref-cast",
|
||||||
"schemars",
|
"schemars",
|
||||||
|
|
@ -6587,7 +6607,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-requirements"
|
name = "uv-requirements"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"configparser",
|
"configparser",
|
||||||
|
|
@ -6622,7 +6642,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-requirements-txt"
|
name = "uv-requirements-txt"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"assert_fs",
|
"assert_fs",
|
||||||
|
|
@ -6655,7 +6675,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-resolver"
|
name = "uv-resolver"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arcstr",
|
"arcstr",
|
||||||
"astral-pubgrub",
|
"astral-pubgrub",
|
||||||
|
|
@ -6720,7 +6740,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-scripts"
|
name = "uv-scripts"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fs-err",
|
"fs-err",
|
||||||
"indoc",
|
"indoc",
|
||||||
|
|
@ -6744,7 +6764,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-settings"
|
name = "uv-settings"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
|
|
@ -6779,7 +6799,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-shell"
|
name = "uv-shell"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
|
|
@ -6796,7 +6816,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-small-str"
|
name = "uv-small-str"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arcstr",
|
"arcstr",
|
||||||
"rkyv",
|
"rkyv",
|
||||||
|
|
@ -6806,7 +6826,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-state"
|
name = "uv-state"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fs-err",
|
"fs-err",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
|
|
@ -6815,14 +6835,14 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-static"
|
name = "uv-static"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"uv-macros",
|
"uv-macros",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-tool"
|
name = "uv-tool"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fs-err",
|
"fs-err",
|
||||||
"pathdiff",
|
"pathdiff",
|
||||||
|
|
@ -6851,7 +6871,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-torch"
|
name = "uv-torch"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"either",
|
"either",
|
||||||
|
|
@ -6871,7 +6891,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-trampoline-builder"
|
name = "uv-trampoline-builder"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"assert_cmd",
|
"assert_cmd",
|
||||||
|
|
@ -6888,7 +6908,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-types"
|
name = "uv-types"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
|
|
@ -6910,11 +6930,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-version"
|
name = "uv-version"
|
||||||
version = "0.9.17"
|
version = "0.9.18"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-virtualenv"
|
name = "uv-virtualenv"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console 0.16.1",
|
"console 0.16.1",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
|
|
@ -6936,16 +6956,19 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uv-warnings"
|
name = "uv-warnings"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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.7"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"assert_fs",
|
"assert_fs",
|
||||||
|
|
|
||||||
133
Cargo.toml
133
Cargo.toml
|
|
@ -16,64 +16,64 @@ authors = ["uv"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
uv-auth = { version = "0.0.7", path = "crates/uv-auth" }
|
uv-auth = { version = "0.0.8", path = "crates/uv-auth" }
|
||||||
uv-bin-install = { version = "0.0.7", path = "crates/uv-bin-install" }
|
uv-bin-install = { version = "0.0.8", path = "crates/uv-bin-install" }
|
||||||
uv-build-backend = { version = "0.0.7", path = "crates/uv-build-backend" }
|
uv-build-backend = { version = "0.0.8", path = "crates/uv-build-backend" }
|
||||||
uv-build-frontend = { version = "0.0.7", path = "crates/uv-build-frontend" }
|
uv-build-frontend = { version = "0.0.8", path = "crates/uv-build-frontend" }
|
||||||
uv-cache = { version = "0.0.7", path = "crates/uv-cache" }
|
uv-cache = { version = "0.0.8", path = "crates/uv-cache" }
|
||||||
uv-cache-info = { version = "0.0.7", path = "crates/uv-cache-info" }
|
uv-cache-info = { version = "0.0.8", path = "crates/uv-cache-info" }
|
||||||
uv-cache-key = { version = "0.0.7", path = "crates/uv-cache-key" }
|
uv-cache-key = { version = "0.0.8", path = "crates/uv-cache-key" }
|
||||||
uv-cli = { version = "0.0.7", path = "crates/uv-cli" }
|
uv-cli = { version = "0.0.8", path = "crates/uv-cli" }
|
||||||
uv-client = { version = "0.0.7", path = "crates/uv-client" }
|
uv-client = { version = "0.0.8", path = "crates/uv-client" }
|
||||||
uv-configuration = { version = "0.0.7", path = "crates/uv-configuration" }
|
uv-configuration = { version = "0.0.8", path = "crates/uv-configuration" }
|
||||||
uv-console = { version = "0.0.7", path = "crates/uv-console" }
|
uv-console = { version = "0.0.8", path = "crates/uv-console" }
|
||||||
uv-dirs = { version = "0.0.7", path = "crates/uv-dirs" }
|
uv-dirs = { version = "0.0.8", path = "crates/uv-dirs" }
|
||||||
uv-dispatch = { version = "0.0.7", path = "crates/uv-dispatch" }
|
uv-dispatch = { version = "0.0.8", path = "crates/uv-dispatch" }
|
||||||
uv-distribution = { version = "0.0.7", path = "crates/uv-distribution" }
|
uv-distribution = { version = "0.0.8", path = "crates/uv-distribution" }
|
||||||
uv-distribution-filename = { version = "0.0.7", path = "crates/uv-distribution-filename" }
|
uv-distribution-filename = { version = "0.0.8", path = "crates/uv-distribution-filename" }
|
||||||
uv-distribution-types = { version = "0.0.7", path = "crates/uv-distribution-types" }
|
uv-distribution-types = { version = "0.0.8", path = "crates/uv-distribution-types" }
|
||||||
uv-extract = { version = "0.0.7", path = "crates/uv-extract" }
|
uv-extract = { version = "0.0.8", path = "crates/uv-extract" }
|
||||||
uv-flags = { version = "0.0.7", path = "crates/uv-flags" }
|
uv-flags = { version = "0.0.8", path = "crates/uv-flags" }
|
||||||
uv-fs = { version = "0.0.7", path = "crates/uv-fs", features = ["serde", "tokio"] }
|
uv-fs = { version = "0.0.8", path = "crates/uv-fs", features = ["serde", "tokio"] }
|
||||||
uv-git = { version = "0.0.7", path = "crates/uv-git" }
|
uv-git = { version = "0.0.8", path = "crates/uv-git" }
|
||||||
uv-git-types = { version = "0.0.7", path = "crates/uv-git-types" }
|
uv-git-types = { version = "0.0.8", path = "crates/uv-git-types" }
|
||||||
uv-globfilter = { version = "0.0.7", path = "crates/uv-globfilter" }
|
uv-globfilter = { version = "0.0.8", path = "crates/uv-globfilter" }
|
||||||
uv-install-wheel = { version = "0.0.7", path = "crates/uv-install-wheel", default-features = false }
|
uv-install-wheel = { version = "0.0.8", path = "crates/uv-install-wheel", default-features = false }
|
||||||
uv-installer = { version = "0.0.7", path = "crates/uv-installer" }
|
uv-installer = { version = "0.0.8", path = "crates/uv-installer" }
|
||||||
uv-keyring = { version = "0.0.7", path = "crates/uv-keyring" }
|
uv-keyring = { version = "0.0.8", path = "crates/uv-keyring" }
|
||||||
uv-logging = { version = "0.0.7", path = "crates/uv-logging" }
|
uv-logging = { version = "0.0.8", path = "crates/uv-logging" }
|
||||||
uv-macros = { version = "0.0.7", path = "crates/uv-macros" }
|
uv-macros = { version = "0.0.8", path = "crates/uv-macros" }
|
||||||
uv-metadata = { version = "0.0.7", path = "crates/uv-metadata" }
|
uv-metadata = { version = "0.0.8", path = "crates/uv-metadata" }
|
||||||
uv-normalize = { version = "0.0.7", path = "crates/uv-normalize" }
|
uv-normalize = { version = "0.0.8", path = "crates/uv-normalize" }
|
||||||
uv-once-map = { version = "0.0.7", path = "crates/uv-once-map" }
|
uv-once-map = { version = "0.0.8", path = "crates/uv-once-map" }
|
||||||
uv-options-metadata = { version = "0.0.7", path = "crates/uv-options-metadata" }
|
uv-options-metadata = { version = "0.0.8", path = "crates/uv-options-metadata" }
|
||||||
uv-performance-memory-allocator = { version = "0.0.7", path = "crates/uv-performance-memory-allocator" }
|
uv-performance-memory-allocator = { version = "0.0.8", path = "crates/uv-performance-memory-allocator" }
|
||||||
uv-pep440 = { version = "0.0.7", path = "crates/uv-pep440", features = ["tracing", "rkyv", "version-ranges"] }
|
uv-pep440 = { version = "0.0.8", path = "crates/uv-pep440", features = ["tracing", "rkyv", "version-ranges"] }
|
||||||
uv-pep508 = { version = "0.0.7", path = "crates/uv-pep508", features = ["non-pep508-extensions"] }
|
uv-pep508 = { version = "0.0.8", path = "crates/uv-pep508", features = ["non-pep508-extensions"] }
|
||||||
uv-platform = { version = "0.0.7", path = "crates/uv-platform" }
|
uv-platform = { version = "0.0.8", path = "crates/uv-platform" }
|
||||||
uv-platform-tags = { version = "0.0.7", path = "crates/uv-platform-tags" }
|
uv-platform-tags = { version = "0.0.8", path = "crates/uv-platform-tags" }
|
||||||
uv-preview = { version = "0.0.7", path = "crates/uv-preview" }
|
uv-preview = { version = "0.0.8", path = "crates/uv-preview" }
|
||||||
uv-publish = { version = "0.0.7", path = "crates/uv-publish" }
|
uv-publish = { version = "0.0.8", path = "crates/uv-publish" }
|
||||||
uv-pypi-types = { version = "0.0.7", path = "crates/uv-pypi-types" }
|
uv-pypi-types = { version = "0.0.8", path = "crates/uv-pypi-types" }
|
||||||
uv-python = { version = "0.0.7", path = "crates/uv-python" }
|
uv-python = { version = "0.0.8", path = "crates/uv-python" }
|
||||||
uv-redacted = { version = "0.0.7", path = "crates/uv-redacted" }
|
uv-redacted = { version = "0.0.8", path = "crates/uv-redacted" }
|
||||||
uv-requirements = { version = "0.0.7", path = "crates/uv-requirements" }
|
uv-requirements = { version = "0.0.8", path = "crates/uv-requirements" }
|
||||||
uv-requirements-txt = { version = "0.0.7", path = "crates/uv-requirements-txt" }
|
uv-requirements-txt = { version = "0.0.8", path = "crates/uv-requirements-txt" }
|
||||||
uv-resolver = { version = "0.0.7", path = "crates/uv-resolver" }
|
uv-resolver = { version = "0.0.8", path = "crates/uv-resolver" }
|
||||||
uv-scripts = { version = "0.0.7", path = "crates/uv-scripts" }
|
uv-scripts = { version = "0.0.8", path = "crates/uv-scripts" }
|
||||||
uv-settings = { version = "0.0.7", path = "crates/uv-settings" }
|
uv-settings = { version = "0.0.8", path = "crates/uv-settings" }
|
||||||
uv-shell = { version = "0.0.7", path = "crates/uv-shell" }
|
uv-shell = { version = "0.0.8", path = "crates/uv-shell" }
|
||||||
uv-small-str = { version = "0.0.7", path = "crates/uv-small-str" }
|
uv-small-str = { version = "0.0.8", path = "crates/uv-small-str" }
|
||||||
uv-state = { version = "0.0.7", path = "crates/uv-state" }
|
uv-state = { version = "0.0.8", path = "crates/uv-state" }
|
||||||
uv-static = { version = "0.0.7", path = "crates/uv-static" }
|
uv-static = { version = "0.0.8", path = "crates/uv-static" }
|
||||||
uv-tool = { version = "0.0.7", path = "crates/uv-tool" }
|
uv-tool = { version = "0.0.8", path = "crates/uv-tool" }
|
||||||
uv-torch = { version = "0.0.7", path = "crates/uv-torch" }
|
uv-torch = { version = "0.0.8", path = "crates/uv-torch" }
|
||||||
uv-trampoline-builder = { version = "0.0.7", path = "crates/uv-trampoline-builder" }
|
uv-trampoline-builder = { version = "0.0.8", path = "crates/uv-trampoline-builder" }
|
||||||
uv-types = { version = "0.0.7", path = "crates/uv-types" }
|
uv-types = { version = "0.0.8", path = "crates/uv-types" }
|
||||||
uv-version = { version = "0.9.17", path = "crates/uv-version" }
|
uv-version = { version = "0.9.18", path = "crates/uv-version" }
|
||||||
uv-virtualenv = { version = "0.0.7", path = "crates/uv-virtualenv" }
|
uv-virtualenv = { version = "0.0.8", path = "crates/uv-virtualenv" }
|
||||||
uv-warnings = { version = "0.0.7", path = "crates/uv-warnings" }
|
uv-warnings = { version = "0.0.8", path = "crates/uv-warnings" }
|
||||||
uv-workspace = { version = "0.0.7", path = "crates/uv-workspace" }
|
uv-workspace = { version = "0.0.8", path = "crates/uv-workspace" }
|
||||||
|
|
||||||
ambient-id = { version = "0.0.7", default-features = false, features = ["astral-reqwest-middleware"] }
|
ambient-id = { version = "0.0.7", default-features = false, features = ["astral-reqwest-middleware"] }
|
||||||
anstream = { version = "0.6.15" }
|
anstream = { version = "0.6.15" }
|
||||||
|
|
@ -103,6 +103,7 @@ 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" }
|
||||||
|
|
@ -152,7 +153,7 @@ regex-automata = { version = "0.4.8", default-features = false, features = ["dfa
|
||||||
reqsign = { version = "0.18.0", features = ["aws", "default-context"], default-features = false }
|
reqsign = { version = "0.18.0", features = ["aws", "default-context"], default-features = false }
|
||||||
reqwest = { version = "0.12.22", default-features = false, features = ["json", "gzip", "deflate", "zstd", "stream", "system-proxy", "rustls-tls", "rustls-tls-native-roots", "socks", "multipart", "http2", "blocking"] }
|
reqwest = { version = "0.12.22", default-features = false, features = ["json", "gzip", "deflate", "zstd", "stream", "system-proxy", "rustls-tls", "rustls-tls-native-roots", "socks", "multipart", "http2", "blocking"] }
|
||||||
reqwest-middleware = { version = "0.4.2", package = "astral-reqwest-middleware", features = ["multipart"] }
|
reqwest-middleware = { version = "0.4.2", package = "astral-reqwest-middleware", features = ["multipart"] }
|
||||||
reqwest-retry = { version = "0.7.0", package = "astral-reqwest-retry" }
|
reqwest-retry = { version = "0.8.0", package = "astral-reqwest-retry" }
|
||||||
rkyv = { version = "0.8.8", features = ["bytecheck"] }
|
rkyv = { version = "0.8.8", features = ["bytecheck"] }
|
||||||
rmp-serde = { version = "1.3.0" }
|
rmp-serde = { version = "1.3.0" }
|
||||||
rust-netrc = { version = "0.1.2" }
|
rust-netrc = { version = "0.1.2" }
|
||||||
|
|
@ -169,7 +170,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.12.0" }
|
spdx = { version = "0.13.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" }
|
||||||
|
|
@ -224,9 +225,6 @@ 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"
|
||||||
|
|
@ -312,12 +310,21 @@ 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"
|
||||||
|
|
|
||||||
36
README.md
36
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).
|
[Ruff](https://github.com/astral-sh/ruff) and [ty](https://github.com/astral-sh/ty).
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|
@ -192,14 +192,12 @@ uv installs Python and allows quickly switching between versions.
|
||||||
Install multiple Python versions:
|
Install multiple Python versions:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ uv python install 3.10 3.11 3.12
|
$ uv python install 3.12 3.13 3.14
|
||||||
Searching for Python versions matching: Python 3.10
|
Installed 3 versions in 972ms
|
||||||
Searching for Python versions matching: Python 3.11
|
+ cpython-3.12.12-macos-aarch64-none (python3.12)
|
||||||
Searching for Python versions matching: Python 3.12
|
+ cpython-3.13.9-macos-aarch64-none (python3.13)
|
||||||
Installed 3 versions in 3.42s
|
+ cpython-3.14.0-macos-aarch64-none (python3.14)
|
||||||
+ 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:
|
||||||
|
|
@ -270,19 +268,12 @@ 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
|
||||||
you get involved in the project. See the
|
you get involved in the project. See the
|
||||||
[contributing guide](https://github.com/astral-sh/uv/blob/main/CONTRIBUTING.md) to get started.
|
[contributing guide](https://github.com/astral-sh/uv?tab=contributing-ov-file#contributing) to get
|
||||||
|
started.
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
|
|
@ -294,6 +285,15 @@ 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,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-auth"
|
name = "uv-auth"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-auth).
|
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)
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,15 @@ 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
|
||||||
|
|
@ -150,6 +159,8 @@ 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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -172,6 +183,7 @@ impl AuthMiddleware {
|
||||||
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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -678,14 +690,27 @@ impl AuthMiddleware {
|
||||||
return Some(credentials);
|
return Some(credentials);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(credentials) = S3EndpointProvider::credentials_for(url, self.preview)
|
if S3EndpointProvider::is_s3_endpoint(url, self.preview) {
|
||||||
.map(Authentication::from)
|
let mut s3_state = self.s3_credential_state.lock().await;
|
||||||
.map(Arc::new)
|
|
||||||
{
|
// If the S3 credential state is uninitialized, initialize it.
|
||||||
|
let credentials = match &*s3_state {
|
||||||
|
S3CredentialState::Uninitialized => {
|
||||||
|
trace!("Initializing S3 credentials for {url}");
|
||||||
|
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}");
|
debug!("Found S3 credentials for {url}");
|
||||||
self.cache().fetches.done(key, Some(credentials.clone()));
|
self.cache().fetches.done(key, Some(credentials.clone()));
|
||||||
return Some(credentials);
|
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.
|
||||||
if let Some(base_client) = self.base_client.as_ref() {
|
if let Some(base_client) = self.base_client.as_ref() {
|
||||||
|
|
|
||||||
|
|
@ -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 the credentials for the S3 endpoint, if available.
|
/// Returns `true` if the URL matches the configured S3 endpoint.
|
||||||
pub(crate) fn credentials_for(url: &Url, preview: Preview) -> Option<DefaultSigner> {
|
pub(crate) fn is_s3_endpoint(url: &Url, preview: Preview) -> bool {
|
||||||
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,6 +79,17 @@ 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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,
|
// TODO(charlie): Can `reqsign` infer the region for us? Profiles, for example,
|
||||||
// often have a region set already.
|
// often have a region set already.
|
||||||
let region = std::env::var(EnvVars::AWS_REGION)
|
let region = std::env::var(EnvVars::AWS_REGION)
|
||||||
|
|
@ -88,10 +99,6 @@ impl S3EndpointProvider {
|
||||||
.map(Cow::Owned)
|
.map(Cow::Owned)
|
||||||
.unwrap_or_else(|_| Cow::Borrowed("us-east-1"))
|
.unwrap_or_else(|_| Cow::Borrowed("us-east-1"))
|
||||||
});
|
});
|
||||||
let signer = reqsign::aws::default_signer("s3", ®ion);
|
reqsign::aws::default_signer("s3", ®ion)
|
||||||
return Some(signer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-bench"
|
name = "uv-bench"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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
|
||||||
|
|
||||||
[dependencies]
|
[dev-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, optional = true }
|
uv-extract = { workspace = 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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-bench).
|
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)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-bin-install"
|
name = "uv-bin-install"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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 }
|
||||||
|
|
@ -20,7 +20,6 @@ uv-cache = { workspace = true }
|
||||||
uv-client = { workspace = true }
|
uv-client = { workspace = true }
|
||||||
uv-distribution-filename = { workspace = true }
|
uv-distribution-filename = { workspace = true }
|
||||||
uv-extract = { workspace = true }
|
uv-extract = { workspace = true }
|
||||||
uv-fs = { 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 }
|
||||||
|
|
@ -34,5 +33,4 @@ tempfile = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
tokio-util = { workspace = true }
|
tokio-util = { workspace = true }
|
||||||
tracing = { workspace = true }
|
|
||||||
url = { workspace = true }
|
url = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-bin-install).
|
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)
|
||||||
|
|
|
||||||
|
|
@ -6,23 +6,19 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
use std::time::{Duration, SystemTime};
|
|
||||||
|
|
||||||
use futures::TryStreamExt;
|
use futures::TryStreamExt;
|
||||||
use reqwest_retry::RetryPolicy;
|
|
||||||
use reqwest_retry::policies::ExponentialBackoff;
|
use reqwest_retry::policies::ExponentialBackoff;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::io::{AsyncRead, ReadBuf};
|
use tokio::io::{AsyncRead, ReadBuf};
|
||||||
use tokio_util::compat::FuturesAsyncReadCompatExt;
|
use tokio_util::compat::FuturesAsyncReadCompatExt;
|
||||||
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};
|
use uv_cache::{Cache, CacheBucket, CacheEntry, Error as CacheError};
|
||||||
use uv_client::{BaseClient, is_transient_network_error};
|
use uv_client::{BaseClient, RetryState};
|
||||||
use uv_extract::{Error as ExtractError, stream};
|
use uv_extract::{Error as ExtractError, stream};
|
||||||
use uv_fs::LockedFileError;
|
|
||||||
use uv_pep440::Version;
|
use uv_pep440::Version;
|
||||||
use uv_platform::Platform;
|
use uv_platform::Platform;
|
||||||
use uv_redacted::DisplaySafeUrl;
|
use uv_redacted::DisplaySafeUrl;
|
||||||
|
|
@ -137,12 +133,12 @@ pub enum Error {
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
|
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
LockedFile(#[from] LockedFileError),
|
Cache(#[from] CacheError),
|
||||||
|
|
||||||
#[error("Failed to detect platform")]
|
#[error("Failed to detect platform")]
|
||||||
Platform(#[from] uv_platform::Error),
|
Platform(#[from] uv_platform::Error),
|
||||||
|
|
||||||
#[error("Attempt failed after {retries} {subject}", subject = if *retries > 1 { "retries" } else { "retry" })]
|
#[error("Request failed after {retries} {subject}", subject = if *retries > 1 { "retries" } else { "retry" })]
|
||||||
RetriedError {
|
RetriedError {
|
||||||
#[source]
|
#[source]
|
||||||
err: Box<Error>,
|
err: Box<Error>,
|
||||||
|
|
@ -151,13 +147,15 @@ pub enum Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
/// Return the number of attempts that were made to complete this request before this error was
|
/// Return the number of retries that were made to complete this request before this error was
|
||||||
/// returned. Note that e.g. 3 retries equates to 4 attempts.
|
/// returned.
|
||||||
fn attempts(&self) -> u32 {
|
///
|
||||||
|
/// Note that e.g. 3 retries equates to 4 attempts.
|
||||||
|
fn retries(&self) -> u32 {
|
||||||
if let Self::RetriedError { retries, .. } = self {
|
if let Self::RetriedError { retries, .. } = self {
|
||||||
return retries + 1;
|
return *retries;
|
||||||
}
|
}
|
||||||
1
|
0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -243,9 +241,7 @@ async fn download_and_unpack_with_retry(
|
||||||
download_url: &Url,
|
download_url: &Url,
|
||||||
cache_entry: &CacheEntry,
|
cache_entry: &CacheEntry,
|
||||||
) -> Result<PathBuf, Error> {
|
) -> Result<PathBuf, Error> {
|
||||||
let mut total_attempts = 0;
|
let mut retry_state = RetryState::start(*retry_policy, download_url.clone());
|
||||||
let mut retried_here = false;
|
|
||||||
let start_time = SystemTime::now();
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let result = download_and_unpack(
|
let result = download_and_unpack(
|
||||||
|
|
@ -261,40 +257,23 @@ async fn download_and_unpack_with_retry(
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let result = match result {
|
match result {
|
||||||
Ok(path) => Ok(path),
|
Ok(path) => return Ok(path),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
total_attempts += err.attempts();
|
if let Some(backoff) = retry_state.should_retry(&err, err.retries()) {
|
||||||
let past_retries = total_attempts - 1;
|
retry_state.sleep_backoff(backoff).await;
|
||||||
|
|
||||||
if is_transient_network_error(&err) {
|
|
||||||
let retry_decision = retry_policy.should_retry(start_time, past_retries);
|
|
||||||
if let reqwest_retry::RetryDecision::Retry { execute_after } = retry_decision {
|
|
||||||
debug!(
|
|
||||||
"Transient failure while installing {} {}; retrying...",
|
|
||||||
binary.name(),
|
|
||||||
version
|
|
||||||
);
|
|
||||||
let duration = execute_after
|
|
||||||
.duration_since(SystemTime::now())
|
|
||||||
.unwrap_or_else(|_| Duration::default());
|
|
||||||
tokio::time::sleep(duration).await;
|
|
||||||
retried_here = true;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
return if retry_state.total_retries() > 0 {
|
||||||
|
|
||||||
if retried_here {
|
|
||||||
Err(Error::RetriedError {
|
Err(Error::RetriedError {
|
||||||
err: Box::new(err),
|
err: Box::new(err),
|
||||||
retries: past_retries,
|
retries: retry_state.total_retries(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(err)
|
Err(err)
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
return result;
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-build-backend"
|
name = "uv-build-backend"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-build-backend).
|
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)
|
||||||
|
|
|
||||||
|
|
@ -662,7 +662,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())),
|
||||||
@"871d1f859140721b67cbeaca074e7a2740c88c38028d0509eba87d1285f1da9e"
|
@"bb74bff575b135bb39e5c9bce56349441fb0923bb8857e32a5eaf34ec1843967"
|
||||||
);
|
);
|
||||||
// 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"
|
||||||
|
|
|
||||||
|
|
@ -299,6 +299,10 @@ 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.
|
||||||
|
|
@ -312,6 +316,10 @@ 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 = {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-build-frontend"
|
name = "uv-build-frontend"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-build-frontend).
|
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)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-build"
|
name = "uv-build"
|
||||||
version = "0.9.17"
|
version = "0.9.18"
|
||||||
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.17"
|
version = "0.9.18"
|
||||||
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"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-cache-info"
|
name = "uv-cache-info"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-cache-info).
|
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)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-cache-key"
|
name = "uv-cache-key"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-cache-key).
|
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)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-cache"
|
name = "uv-cache"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,5 +34,6 @@ 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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-cache).
|
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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
use clap::{Parser, ValueHint};
|
||||||
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)]
|
#[arg(global = true, long, env = EnvVars::UV_CACHE_DIR, value_hint = ValueHint::DirPath)]
|
||||||
pub cache_dir: Option<PathBuf>,
|
pub cache_dir: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,17 @@ 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);
|
||||||
|
|
@ -80,14 +91,14 @@ impl CacheEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Acquire the [`CacheEntry`] as an exclusive lock.
|
/// Acquire the [`CacheEntry`] as an exclusive lock.
|
||||||
pub async fn lock(&self) -> Result<LockedFile, LockedFileError> {
|
pub async fn lock(&self) -> Result<LockedFile, Error> {
|
||||||
fs_err::create_dir_all(self.dir())?;
|
fs_err::create_dir_all(self.dir())?;
|
||||||
LockedFile::acquire(
|
Ok(LockedFile::acquire(
|
||||||
self.path(),
|
self.path(),
|
||||||
LockedFileMode::Exclusive,
|
LockedFileMode::Exclusive,
|
||||||
self.path().display(),
|
self.path().display(),
|
||||||
)
|
)
|
||||||
.await
|
.await?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -114,14 +125,14 @@ 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, LockedFileError> {
|
pub async fn lock(&self) -> Result<LockedFile, Error> {
|
||||||
fs_err::create_dir_all(self.as_ref())?;
|
fs_err::create_dir_all(self.as_ref())?;
|
||||||
LockedFile::acquire(
|
Ok(LockedFile::acquire(
|
||||||
self.join(".lock"),
|
self.join(".lock"),
|
||||||
LockedFileMode::Exclusive,
|
LockedFileMode::Exclusive,
|
||||||
self.display(),
|
self.display(),
|
||||||
)
|
)
|
||||||
.await
|
.await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the [`CacheShard`] as a [`PathBuf`].
|
/// Return the [`CacheShard`] as a [`PathBuf`].
|
||||||
|
|
@ -391,7 +402,7 @@ impl Cache {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Populate the cache scaffold.
|
/// Populate the cache scaffold.
|
||||||
fn create_base_files(root: &PathBuf) -> Result<(), io::Error> {
|
fn create_base_files(root: &PathBuf) -> io::Result<()> {
|
||||||
// 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)?;
|
||||||
|
|
||||||
|
|
@ -441,7 +452,7 @@ impl Cache {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize the [`Cache`].
|
/// Initialize the [`Cache`].
|
||||||
pub async fn init(self) -> Result<Self, LockedFileError> {
|
pub async fn init(self) -> Result<Self, Error> {
|
||||||
let root = &self.root;
|
let root = &self.root;
|
||||||
|
|
||||||
Self::create_base_files(root)?;
|
Self::create_base_files(root)?;
|
||||||
|
|
@ -466,18 +477,18 @@ impl Cache {
|
||||||
);
|
);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err.into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
root: std::path::absolute(root)?,
|
root: std::path::absolute(root).map_err(Error::Absolute)?,
|
||||||
lock_file,
|
lock_file,
|
||||||
..self
|
..self
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize the [`Cache`], assuming that there are no other uv processes running.
|
/// Initialize the [`Cache`], assuming that there are no other uv processes running.
|
||||||
pub fn init_no_wait(self) -> Result<Option<Self>, io::Error> {
|
pub fn init_no_wait(self) -> Result<Option<Self>, Error> {
|
||||||
let root = &self.root;
|
let root = &self.root;
|
||||||
|
|
||||||
Self::create_base_files(root)?;
|
Self::create_base_files(root)?;
|
||||||
|
|
@ -491,7 +502,7 @@ impl Cache {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
Ok(Some(Self {
|
Ok(Some(Self {
|
||||||
root: std::path::absolute(root)?,
|
root: std::path::absolute(root).map_err(Error::Absolute)?,
|
||||||
lock_file: Some(Arc::new(lock_file)),
|
lock_file: Some(Arc::new(lock_file)),
|
||||||
..self
|
..self
|
||||||
}))
|
}))
|
||||||
|
|
@ -531,7 +542,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) -> Result<Removal, io::Error> {
|
pub fn remove(&self, name: &PackageName) -> io::Result<Removal> {
|
||||||
// Collect the set of referenced archives.
|
// Collect the set of referenced archives.
|
||||||
let references = self.find_archive_references()?;
|
let references = self.find_archive_references()?;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-cli"
|
name = "uv-cli"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-cli).
|
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)
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -366,6 +366,7 @@ 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"),
|
||||||
|
|
@ -495,5 +496,6 @@ 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.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-client).
|
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)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use std::fmt::Write;
|
||||||
use std::num::ParseIntError;
|
use std::num::ParseIntError;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::{Duration, SystemTime};
|
||||||
use std::{env, io, iter};
|
use std::{env, io, iter};
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
|
|
@ -20,8 +20,8 @@ use reqwest::{Client, ClientBuilder, IntoUrl, Proxy, Request, Response, multipar
|
||||||
use reqwest_middleware::{ClientWithMiddleware, Middleware};
|
use reqwest_middleware::{ClientWithMiddleware, Middleware};
|
||||||
use reqwest_retry::policies::ExponentialBackoff;
|
use reqwest_retry::policies::ExponentialBackoff;
|
||||||
use reqwest_retry::{
|
use reqwest_retry::{
|
||||||
DefaultRetryableStrategy, RetryTransientMiddleware, Retryable, RetryableStrategy,
|
RetryPolicy, RetryTransientMiddleware, Retryable, RetryableStrategy, default_on_request_error,
|
||||||
default_on_request_error,
|
default_on_request_success,
|
||||||
};
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tracing::{debug, trace};
|
use tracing::{debug, trace};
|
||||||
|
|
@ -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`].
|
||||||
const DEFAULT_MAX_REDIRECTS: u32 = 10;
|
pub 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)]
|
||||||
|
|
@ -104,6 +104,8 @@ 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 {
|
||||||
|
|
@ -111,6 +113,7 @@ 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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -729,6 +732,7 @@ 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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1015,21 +1019,15 @@ impl<'a> RequestBuilder<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extends [`DefaultRetryableStrategy`], to log transient request failures and additional retry cases.
|
/// An extension over [`DefaultRetryableStrategy`] that logs transient request failures and
|
||||||
|
/// adds additional retry cases.
|
||||||
pub struct UvRetryableStrategy;
|
pub struct UvRetryableStrategy;
|
||||||
|
|
||||||
impl RetryableStrategy for UvRetryableStrategy {
|
impl RetryableStrategy for UvRetryableStrategy {
|
||||||
fn handle(&self, res: &Result<Response, reqwest_middleware::Error>) -> Option<Retryable> {
|
fn handle(&self, res: &Result<Response, reqwest_middleware::Error>) -> Option<Retryable> {
|
||||||
// Use the default strategy and check for additional transient error cases.
|
let retryable = match res {
|
||||||
let retryable = match DefaultRetryableStrategy.handle(res) {
|
Ok(success) => default_on_request_success(success),
|
||||||
None | Some(Retryable::Fatal)
|
Err(err) => retryable_on_request_failure(err),
|
||||||
if res
|
|
||||||
.as_ref()
|
|
||||||
.is_err_and(|err| is_transient_network_error(err)) =>
|
|
||||||
{
|
|
||||||
Some(Retryable::Transient)
|
|
||||||
}
|
|
||||||
default => default,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Log on transient errors
|
// Log on transient errors
|
||||||
|
|
@ -1055,11 +1053,13 @@ impl RetryableStrategy for UvRetryableStrategy {
|
||||||
|
|
||||||
/// Whether the error looks like a network error that should be retried.
|
/// Whether the error looks like a network error that should be retried.
|
||||||
///
|
///
|
||||||
/// There are two cases that the default retry strategy is missing:
|
/// This is an extension over [`reqwest_middleware::default_on_request_failure`], which is missing
|
||||||
|
/// a number of cases:
|
||||||
/// * Inside the reqwest or reqwest-middleware error is an `io::Error` such as a broken pipe
|
/// * Inside the reqwest or reqwest-middleware error is an `io::Error` such as a broken pipe
|
||||||
/// * When streaming a response, a reqwest error may be hidden several layers behind errors
|
/// * When streaming a response, a reqwest error may be hidden several layers behind errors
|
||||||
/// of different crates processing the stream, including `io::Error` layers.
|
/// of different crates processing the stream, including `io::Error` layers
|
||||||
pub fn is_transient_network_error(err: &(dyn Error + 'static)) -> bool {
|
/// * Any `h2` error
|
||||||
|
fn retryable_on_request_failure(err: &(dyn Error + 'static)) -> Option<Retryable> {
|
||||||
// First, try to show a nice trace log
|
// First, try to show a nice trace log
|
||||||
if let Some((Some(status), Some(url))) = find_source::<WrappedReqwestError>(&err)
|
if let Some((Some(status), Some(url))) = find_source::<WrappedReqwestError>(&err)
|
||||||
.map(|request_err| (request_err.status(), request_err.url()))
|
.map(|request_err| (request_err.status(), request_err.url()))
|
||||||
|
|
@ -1074,29 +1074,32 @@ pub fn is_transient_network_error(err: &(dyn Error + 'static)) -> bool {
|
||||||
// crates
|
// crates
|
||||||
let mut current_source = Some(err);
|
let mut current_source = Some(err);
|
||||||
while let Some(source) = current_source {
|
while let Some(source) = current_source {
|
||||||
if let Some(reqwest_err) = source.downcast_ref::<WrappedReqwestError>() {
|
// Handle different kinds of reqwest error nesting not accessible by downcast.
|
||||||
has_known_error = true;
|
let reqwest_err = if let Some(reqwest_err) = source.downcast_ref::<reqwest::Error>() {
|
||||||
if let reqwest_middleware::Error::Reqwest(reqwest_err) = &**reqwest_err {
|
Some(reqwest_err)
|
||||||
if default_on_request_error(reqwest_err) == Some(Retryable::Transient) {
|
} else if let Some(reqwest_err) = source
|
||||||
trace!("Retrying nested reqwest middleware error");
|
.downcast_ref::<WrappedReqwestError>()
|
||||||
return true;
|
.and_then(|err| err.inner())
|
||||||
}
|
{
|
||||||
if is_retryable_status_error(reqwest_err) {
|
Some(reqwest_err)
|
||||||
trace!("Retrying nested reqwest middleware status code error");
|
} else if let Some(reqwest_middleware::Error::Reqwest(reqwest_err)) =
|
||||||
return true;
|
source.downcast_ref::<reqwest_middleware::Error>()
|
||||||
}
|
{
|
||||||
}
|
Some(reqwest_err)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
trace!("Cannot retry nested reqwest middleware error");
|
if let Some(reqwest_err) = reqwest_err {
|
||||||
} else if let Some(reqwest_err) = source.downcast_ref::<reqwest::Error>() {
|
|
||||||
has_known_error = true;
|
has_known_error = true;
|
||||||
|
// Ignore the default retry strategy returning fatal.
|
||||||
if default_on_request_error(reqwest_err) == Some(Retryable::Transient) {
|
if default_on_request_error(reqwest_err) == Some(Retryable::Transient) {
|
||||||
trace!("Retrying nested reqwest error");
|
trace!("Retrying nested reqwest error");
|
||||||
return true;
|
return Some(Retryable::Transient);
|
||||||
}
|
}
|
||||||
if is_retryable_status_error(reqwest_err) {
|
if is_retryable_status_error(reqwest_err) {
|
||||||
trace!("Retrying nested reqwest status code error");
|
trace!("Retrying nested reqwest status code error");
|
||||||
return true;
|
return Some(Retryable::Transient);
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("Cannot retry nested reqwest error");
|
trace!("Cannot retry nested reqwest error");
|
||||||
|
|
@ -1104,7 +1107,7 @@ pub fn is_transient_network_error(err: &(dyn Error + 'static)) -> bool {
|
||||||
// All h2 errors look like errors that should be retried
|
// All h2 errors look like errors that should be retried
|
||||||
// https://github.com/astral-sh/uv/issues/15916
|
// https://github.com/astral-sh/uv/issues/15916
|
||||||
trace!("Retrying nested h2 error");
|
trace!("Retrying nested h2 error");
|
||||||
return true;
|
return Some(Retryable::Transient);
|
||||||
} else if let Some(io_err) = source.downcast_ref::<io::Error>() {
|
} else if let Some(io_err) = source.downcast_ref::<io::Error>() {
|
||||||
has_known_error = true;
|
has_known_error = true;
|
||||||
let retryable_io_err_kinds = [
|
let retryable_io_err_kinds = [
|
||||||
|
|
@ -1121,7 +1124,7 @@ pub fn is_transient_network_error(err: &(dyn Error + 'static)) -> bool {
|
||||||
];
|
];
|
||||||
if retryable_io_err_kinds.contains(&io_err.kind()) {
|
if retryable_io_err_kinds.contains(&io_err.kind()) {
|
||||||
trace!("Retrying error: `{}`", io_err.kind());
|
trace!("Retrying error: `{}`", io_err.kind());
|
||||||
return true;
|
return Some(Retryable::Transient);
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!(
|
trace!(
|
||||||
|
|
@ -1136,7 +1139,81 @@ pub fn is_transient_network_error(err: &(dyn Error + 'static)) -> bool {
|
||||||
if !has_known_error {
|
if !has_known_error {
|
||||||
trace!("Cannot retry error: Neither an IO error nor a reqwest error");
|
trace!("Cannot retry error: Neither an IO error nor a reqwest error");
|
||||||
}
|
}
|
||||||
false
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Per-request retry state and policy.
|
||||||
|
pub struct RetryState {
|
||||||
|
retry_policy: ExponentialBackoff,
|
||||||
|
start_time: SystemTime,
|
||||||
|
total_retries: u32,
|
||||||
|
url: DisplaySafeUrl,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RetryState {
|
||||||
|
/// Initialize the [`RetryState`] and start the backoff timer.
|
||||||
|
pub fn start(retry_policy: ExponentialBackoff, url: impl Into<DisplaySafeUrl>) -> Self {
|
||||||
|
Self {
|
||||||
|
retry_policy,
|
||||||
|
start_time: SystemTime::now(),
|
||||||
|
total_retries: 0,
|
||||||
|
url: url.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The number of retries across all requests.
|
||||||
|
///
|
||||||
|
/// After a failed retryable request, this equals the maximum number of retries.
|
||||||
|
pub fn total_retries(&self) -> u32 {
|
||||||
|
self.total_retries
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines whether request should be retried.
|
||||||
|
///
|
||||||
|
/// Takes the number of retries from nested layers associated with the specific `err` type as
|
||||||
|
/// `error_retries`.
|
||||||
|
///
|
||||||
|
/// Returns the backoff duration if the request should be retried.
|
||||||
|
#[must_use]
|
||||||
|
pub fn should_retry(
|
||||||
|
&mut self,
|
||||||
|
err: &(dyn Error + 'static),
|
||||||
|
error_retries: u32,
|
||||||
|
) -> Option<Duration> {
|
||||||
|
// If the middleware performed any retries, consider them in our budget.
|
||||||
|
self.total_retries += error_retries;
|
||||||
|
match retryable_on_request_failure(err) {
|
||||||
|
Some(Retryable::Transient) => {
|
||||||
|
let retry_decision = self
|
||||||
|
.retry_policy
|
||||||
|
.should_retry(self.start_time, self.total_retries);
|
||||||
|
if let reqwest_retry::RetryDecision::Retry { execute_after } = retry_decision {
|
||||||
|
let duration = execute_after
|
||||||
|
.duration_since(SystemTime::now())
|
||||||
|
.unwrap_or_else(|_| Duration::default());
|
||||||
|
|
||||||
|
self.total_retries += 1;
|
||||||
|
return Some(duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Some(Retryable::Fatal) | None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wait before retrying the request.
|
||||||
|
pub async fn sleep_backoff(&self, duration: Duration) {
|
||||||
|
debug!(
|
||||||
|
"Transient failure while handling response from {}; retrying after {:.1}s...",
|
||||||
|
self.url,
|
||||||
|
duration.as_secs_f32(),
|
||||||
|
);
|
||||||
|
// TODO(konsti): Should we show a spinner plus a message in the CLI while
|
||||||
|
// waiting?
|
||||||
|
tokio::time::sleep(duration).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether the error is a status code error that is retryable.
|
/// Whether the error is a status code error that is retryable.
|
||||||
|
|
@ -1381,7 +1458,7 @@ mod tests {
|
||||||
let middleware_client = ClientWithMiddleware::default();
|
let middleware_client = ClientWithMiddleware::default();
|
||||||
let mut retried = Vec::new();
|
let mut retried = Vec::new();
|
||||||
for status in 100..599 {
|
for status in 100..599 {
|
||||||
// Test all standard status codes and and example for a non-RFC code used in the wild.
|
// Test all standard status codes and an example for a non-RFC code used in the wild.
|
||||||
if StatusCode::from_u16(status)?.canonical_reason().is_none() && status != 420 {
|
if StatusCode::from_u16(status)?.canonical_reason().is_none() && status != 420 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -1397,7 +1474,7 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let middleware_retry =
|
let middleware_retry =
|
||||||
DefaultRetryableStrategy.handle(&response) == Some(Retryable::Transient);
|
UvRetryableStrategy.handle(&response) == Some(Retryable::Transient);
|
||||||
|
|
||||||
let response = client
|
let response = client
|
||||||
.get(format!("{}/{}", server.uri(), status))
|
.get(format!("{}/{}", server.uri(), status))
|
||||||
|
|
@ -1406,7 +1483,7 @@ mod tests {
|
||||||
|
|
||||||
let uv_retry = match response.error_for_status() {
|
let uv_retry = match response.error_for_status() {
|
||||||
Ok(_) => false,
|
Ok(_) => false,
|
||||||
Err(err) => is_transient_network_error(&err),
|
Err(err) => retryable_on_request_failure(&err) == Some(Retryable::Transient),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ensure we're retrying the same status code as the reqwest_retry crate. We may choose
|
// Ensure we're retrying the same status code as the reqwest_retry crate. We may choose
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
use std::time::{Duration, SystemTime};
|
|
||||||
use std::{borrow::Cow, path::Path};
|
use std::{borrow::Cow, path::Path};
|
||||||
|
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use reqwest::{Request, Response};
|
use reqwest::{Request, Response};
|
||||||
use reqwest_retry::RetryPolicy;
|
|
||||||
use rkyv::util::AlignedVec;
|
use rkyv::util::AlignedVec;
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
@ -14,7 +12,7 @@ use uv_fs::write_atomic;
|
||||||
use uv_redacted::DisplaySafeUrl;
|
use uv_redacted::DisplaySafeUrl;
|
||||||
|
|
||||||
use crate::BaseClient;
|
use crate::BaseClient;
|
||||||
use crate::base_client::is_transient_network_error;
|
use crate::base_client::RetryState;
|
||||||
use crate::error::ProblemDetails;
|
use crate::error::ProblemDetails;
|
||||||
use crate::{
|
use crate::{
|
||||||
Error, ErrorKind,
|
Error, ErrorKind,
|
||||||
|
|
@ -119,51 +117,35 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dispatch type: Either a cached client error or a (user specified) error from the callback
|
/// Dispatch type: Either a cached client error or a (user specified) error from the callback.
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum CachedClientError<CallbackError: std::error::Error + 'static> {
|
pub enum CachedClientError<CallbackError: std::error::Error + 'static> {
|
||||||
Client {
|
/// The client tracks retries internally.
|
||||||
retries: Option<u32>,
|
Client(Error),
|
||||||
err: Error,
|
/// Track retries before a callback explicitly, as we can't attach them to the callback error
|
||||||
},
|
/// type.
|
||||||
Callback {
|
Callback { retries: u32, err: CallbackError },
|
||||||
retries: Option<u32>,
|
|
||||||
err: CallbackError,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CallbackError: std::error::Error + 'static> CachedClientError<CallbackError> {
|
impl<CallbackError: std::error::Error + 'static> CachedClientError<CallbackError> {
|
||||||
/// Attach the number of retries to the error context.
|
/// Attach the combined number of retries to the error context, discarding the previous count.
|
||||||
///
|
|
||||||
/// Adds to existing errors if any, in case different layers retried.
|
|
||||||
fn with_retries(self, retries: u32) -> Self {
|
fn with_retries(self, retries: u32) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::Client {
|
Self::Client(err) => Self::Client(err.with_retries(retries)),
|
||||||
retries: existing_retries,
|
Self::Callback { retries: _, err } => Self::Callback { retries, err },
|
||||||
err,
|
|
||||||
} => Self::Client {
|
|
||||||
retries: Some(existing_retries.unwrap_or_default() + retries),
|
|
||||||
err,
|
|
||||||
},
|
|
||||||
Self::Callback {
|
|
||||||
retries: existing_retries,
|
|
||||||
err,
|
|
||||||
} => Self::Callback {
|
|
||||||
retries: Some(existing_retries.unwrap_or_default() + retries),
|
|
||||||
err,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn retries(&self) -> Option<u32> {
|
fn retries(&self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
Self::Client { retries, .. } => *retries,
|
Self::Client(err) => err.retries(),
|
||||||
Self::Callback { retries, .. } => *retries,
|
Self::Callback { retries, .. } => *retries,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error(&self) -> &(dyn std::error::Error + 'static) {
|
fn error(&self) -> &(dyn std::error::Error + 'static) {
|
||||||
match self {
|
match self {
|
||||||
Self::Client { err, .. } => err,
|
Self::Client(err) => err,
|
||||||
Self::Callback { err, .. } => err,
|
Self::Callback { err, .. } => err,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -171,10 +153,7 @@ impl<CallbackError: std::error::Error + 'static> CachedClientError<CallbackError
|
||||||
|
|
||||||
impl<CallbackError: std::error::Error + 'static> From<Error> for CachedClientError<CallbackError> {
|
impl<CallbackError: std::error::Error + 'static> From<Error> for CachedClientError<CallbackError> {
|
||||||
fn from(error: Error) -> Self {
|
fn from(error: Error) -> Self {
|
||||||
Self::Client {
|
Self::Client(error)
|
||||||
retries: None,
|
|
||||||
err: error,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,10 +161,7 @@ impl<CallbackError: std::error::Error + 'static> From<ErrorKind>
|
||||||
for CachedClientError<CallbackError>
|
for CachedClientError<CallbackError>
|
||||||
{
|
{
|
||||||
fn from(error: ErrorKind) -> Self {
|
fn from(error: ErrorKind) -> Self {
|
||||||
Self::Client {
|
Self::Client(error.into())
|
||||||
retries: None,
|
|
||||||
err: error.into(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -193,16 +169,10 @@ impl<E: Into<Self> + std::error::Error + 'static> From<CachedClientError<E>> for
|
||||||
/// Attach retry error context, if there were retries.
|
/// Attach retry error context, if there were retries.
|
||||||
fn from(error: CachedClientError<E>) -> Self {
|
fn from(error: CachedClientError<E>) -> Self {
|
||||||
match error {
|
match error {
|
||||||
CachedClientError::Client {
|
CachedClientError::Client(error) => error,
|
||||||
retries: Some(retries),
|
CachedClientError::Callback { retries, err } => {
|
||||||
err,
|
Self::new(err.into().into_kind(), retries)
|
||||||
} => Self::new(err.into_kind(), retries),
|
}
|
||||||
CachedClientError::Client { retries: None, err } => err,
|
|
||||||
CachedClientError::Callback {
|
|
||||||
retries: Some(retries),
|
|
||||||
err,
|
|
||||||
} => Self::new(err.into().into_kind(), retries),
|
|
||||||
CachedClientError::Callback { retries: None, err } => err.into(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -450,10 +420,16 @@ impl CachedClient {
|
||||||
response_callback: Callback,
|
response_callback: Callback,
|
||||||
) -> Result<Payload::Target, CachedClientError<CallBackError>> {
|
) -> Result<Payload::Target, CachedClientError<CallBackError>> {
|
||||||
let new_cache = info_span!("new_cache", file = %cache_entry.path().display());
|
let new_cache = info_span!("new_cache", file = %cache_entry.path().display());
|
||||||
|
// Capture retries from the retry middleware
|
||||||
|
let retries = response
|
||||||
|
.extensions()
|
||||||
|
.get::<reqwest_retry::RetryCount>()
|
||||||
|
.map(|retries| retries.value())
|
||||||
|
.unwrap_or_default();
|
||||||
let data = response_callback(response)
|
let data = response_callback(response)
|
||||||
.boxed_local()
|
.boxed_local()
|
||||||
.await
|
.await
|
||||||
.map_err(|err| CachedClientError::Callback { retries: None, err })?;
|
.map_err(|err| CachedClientError::Callback { retries, err })?;
|
||||||
let Some(cache_policy) = cache_policy else {
|
let Some(cache_policy) = cache_policy else {
|
||||||
return Ok(data.into_target());
|
return Ok(data.into_target());
|
||||||
};
|
};
|
||||||
|
|
@ -662,16 +638,10 @@ impl CachedClient {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
return Err(CachedClientError::<Error>::Client {
|
return Err(Error::new(
|
||||||
retries: retry_count,
|
ErrorKind::from_reqwest_with_problem_details(url, status_error, problem_details),
|
||||||
err: ErrorKind::from_reqwest_with_problem_details(
|
retry_count.unwrap_or_default(),
|
||||||
url,
|
));
|
||||||
status_error,
|
|
||||||
problem_details,
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
}
|
|
||||||
.into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let cache_policy = cache_policy_builder.build(&response);
|
let cache_policy = cache_policy_builder.build(&response);
|
||||||
|
|
@ -720,49 +690,23 @@ impl CachedClient {
|
||||||
cache_control: CacheControl<'_>,
|
cache_control: CacheControl<'_>,
|
||||||
response_callback: Callback,
|
response_callback: Callback,
|
||||||
) -> Result<Payload::Target, CachedClientError<CallBackError>> {
|
) -> Result<Payload::Target, CachedClientError<CallBackError>> {
|
||||||
let mut past_retries = 0;
|
let mut retry_state = RetryState::start(self.uncached().retry_policy(), req.url().clone());
|
||||||
let start_time = SystemTime::now();
|
|
||||||
let retry_policy = self.uncached().retry_policy();
|
|
||||||
loop {
|
loop {
|
||||||
let fresh_req = req.try_clone().expect("HTTP request must be cloneable");
|
let fresh_req = req.try_clone().expect("HTTP request must be cloneable");
|
||||||
let result = self
|
let result = self
|
||||||
.get_cacheable(fresh_req, cache_entry, cache_control, &response_callback)
|
.get_cacheable(fresh_req, cache_entry, cache_control, &response_callback)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
// Check if the middleware already performed retries
|
match result {
|
||||||
let middleware_retries = match &result {
|
Ok(ok) => return Ok(ok),
|
||||||
Err(err) => err.retries().unwrap_or_default(),
|
Err(err) => {
|
||||||
Ok(_) => 0,
|
if let Some(backoff) = retry_state.should_retry(err.error(), err.retries()) {
|
||||||
};
|
retry_state.sleep_backoff(backoff).await;
|
||||||
|
|
||||||
if result
|
|
||||||
.as_ref()
|
|
||||||
.is_err_and(|err| is_transient_network_error(err.error()))
|
|
||||||
{
|
|
||||||
// If middleware already retried, consider that in our retry budget
|
|
||||||
let total_retries = past_retries + middleware_retries;
|
|
||||||
let retry_decision = retry_policy.should_retry(start_time, total_retries);
|
|
||||||
if let reqwest_retry::RetryDecision::Retry { execute_after } = retry_decision {
|
|
||||||
let duration = execute_after
|
|
||||||
.duration_since(SystemTime::now())
|
|
||||||
.unwrap_or_else(|_| Duration::default());
|
|
||||||
|
|
||||||
debug!(
|
|
||||||
"Transient failure while handling response from {}; retrying after {:.1}s...",
|
|
||||||
req.url(),
|
|
||||||
duration.as_secs_f32(),
|
|
||||||
);
|
|
||||||
tokio::time::sleep(duration).await;
|
|
||||||
past_retries += 1;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
return Err(err.with_retries(retry_state.total_retries()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if past_retries > 0 {
|
|
||||||
return result.map_err(|err| err.with_retries(past_retries));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -780,48 +724,23 @@ impl CachedClient {
|
||||||
cache_control: CacheControl<'_>,
|
cache_control: CacheControl<'_>,
|
||||||
response_callback: Callback,
|
response_callback: Callback,
|
||||||
) -> Result<Payload, CachedClientError<CallBackError>> {
|
) -> Result<Payload, CachedClientError<CallBackError>> {
|
||||||
let mut past_retries = 0;
|
let mut retry_state = RetryState::start(self.uncached().retry_policy(), req.url().clone());
|
||||||
let start_time = SystemTime::now();
|
|
||||||
let retry_policy = self.uncached().retry_policy();
|
|
||||||
loop {
|
loop {
|
||||||
let fresh_req = req.try_clone().expect("HTTP request must be cloneable");
|
let fresh_req = req.try_clone().expect("HTTP request must be cloneable");
|
||||||
let result = self
|
let result = self
|
||||||
.skip_cache(fresh_req, cache_entry, cache_control, &response_callback)
|
.skip_cache(fresh_req, cache_entry, cache_control, &response_callback)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
// Check if the middleware already performed retries
|
match result {
|
||||||
let middleware_retries = match &result {
|
Ok(ok) => return Ok(ok),
|
||||||
Err(err) => err.retries().unwrap_or_default(),
|
Err(err) => {
|
||||||
_ => 0,
|
if let Some(backoff) = retry_state.should_retry(err.error(), err.retries()) {
|
||||||
};
|
retry_state.sleep_backoff(backoff).await;
|
||||||
|
|
||||||
if result
|
|
||||||
.as_ref()
|
|
||||||
.err()
|
|
||||||
.is_some_and(|err| is_transient_network_error(err.error()))
|
|
||||||
{
|
|
||||||
let total_retries = past_retries + middleware_retries;
|
|
||||||
let retry_decision = retry_policy.should_retry(start_time, total_retries);
|
|
||||||
if let reqwest_retry::RetryDecision::Retry { execute_after } = retry_decision {
|
|
||||||
let duration = execute_after
|
|
||||||
.duration_since(SystemTime::now())
|
|
||||||
.unwrap_or_else(|_| Duration::default());
|
|
||||||
debug!(
|
|
||||||
"Transient failure while handling response from {}; retrying after {}s...",
|
|
||||||
req.url(),
|
|
||||||
duration.as_secs(),
|
|
||||||
);
|
|
||||||
tokio::time::sleep(duration).await;
|
|
||||||
past_retries += 1;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
return Err(err.with_retries(retry_state.total_retries()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if past_retries > 0 {
|
|
||||||
return result.map_err(|err| err.with_retries(past_retries));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ 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_fs::LockedFileError;
|
|
||||||
use uv_normalize::PackageName;
|
use uv_normalize::PackageName;
|
||||||
use uv_redacted::DisplaySafeUrl;
|
use uv_redacted::DisplaySafeUrl;
|
||||||
|
|
||||||
|
|
@ -123,6 +123,11 @@ impl Error {
|
||||||
&self.kind
|
&self.kind
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn with_retries(mut self, retries: u32) -> Self {
|
||||||
|
self.retries = retries;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new error from a JSON parsing error.
|
/// Create a new error from a JSON parsing error.
|
||||||
pub(crate) fn from_json_err(err: serde_json::Error, url: DisplaySafeUrl) -> Self {
|
pub(crate) fn from_json_err(err: serde_json::Error, url: DisplaySafeUrl) -> Self {
|
||||||
ErrorKind::BadJson { source: err, url }.into()
|
ErrorKind::BadJson { source: err, url }.into()
|
||||||
|
|
@ -339,7 +344,7 @@ pub enum ErrorKind {
|
||||||
CacheWrite(#[source] std::io::Error),
|
CacheWrite(#[source] std::io::Error),
|
||||||
|
|
||||||
#[error("Failed to acquire lock on the client cache")]
|
#[error("Failed to acquire lock on the client cache")]
|
||||||
CacheLock(#[source] LockedFileError),
|
CacheLock(#[source] CacheError),
|
||||||
|
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Io(std::io::Error),
|
Io(std::io::Error),
|
||||||
|
|
@ -425,13 +430,33 @@ impl WrappedReqwestError {
|
||||||
problem_details: Option<ProblemDetails>,
|
problem_details: Option<ProblemDetails>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
error,
|
error: Self::filter_retries_from_error(error),
|
||||||
problem_details: problem_details.map(Box::new),
|
problem_details: problem_details.map(Box::new),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Drop `RetryError::WithRetries` to avoid reporting the number of retries twice.
|
||||||
|
///
|
||||||
|
/// We attach the number of errors outside by adding the retry counts from the retry middleware
|
||||||
|
/// and from uv's outer retry loop for streaming bodies. Stripping the inner count from the
|
||||||
|
/// error context avoids showing two numbers.
|
||||||
|
fn filter_retries_from_error(error: reqwest_middleware::Error) -> reqwest_middleware::Error {
|
||||||
|
match error {
|
||||||
|
reqwest_middleware::Error::Middleware(error) => {
|
||||||
|
match error.downcast::<reqwest_retry::RetryError>() {
|
||||||
|
Ok(
|
||||||
|
reqwest_retry::RetryError::WithRetries { err, .. }
|
||||||
|
| reqwest_retry::RetryError::Error(err),
|
||||||
|
) => err,
|
||||||
|
Err(error) => reqwest_middleware::Error::Middleware(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error @ reqwest_middleware::Error::Reqwest(_) => error,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the inner [`reqwest::Error`] from the error chain, if it exists.
|
/// Return the inner [`reqwest::Error`] from the error chain, if it exists.
|
||||||
fn inner(&self) -> Option<&reqwest::Error> {
|
pub fn inner(&self) -> Option<&reqwest::Error> {
|
||||||
match &self.error {
|
match &self.error {
|
||||||
reqwest_middleware::Error::Reqwest(err) => Some(err),
|
reqwest_middleware::Error::Reqwest(err) => Some(err),
|
||||||
reqwest_middleware::Error::Middleware(err) => err.chain().find_map(|err| {
|
reqwest_middleware::Error::Middleware(err) => err.chain().find_map(|err| {
|
||||||
|
|
@ -495,6 +520,7 @@ impl WrappedReqwestError {
|
||||||
impl From<reqwest::Error> for WrappedReqwestError {
|
impl From<reqwest::Error> for WrappedReqwestError {
|
||||||
fn from(error: reqwest::Error) -> Self {
|
fn from(error: reqwest::Error) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
// No need to filter retries as this error does not have retries.
|
||||||
error: error.into(),
|
error: error.into(),
|
||||||
problem_details: None,
|
problem_details: None,
|
||||||
}
|
}
|
||||||
|
|
@ -504,7 +530,7 @@ impl From<reqwest::Error> for WrappedReqwestError {
|
||||||
impl From<reqwest_middleware::Error> for WrappedReqwestError {
|
impl From<reqwest_middleware::Error> for WrappedReqwestError {
|
||||||
fn from(error: reqwest_middleware::Error) -> Self {
|
fn from(error: reqwest_middleware::Error) -> Self {
|
||||||
Self {
|
Self {
|
||||||
error,
|
error: Self::filter_retries_from_error(error),
|
||||||
problem_details: None,
|
problem_details: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -246,7 +246,7 @@ impl<'a> FlatIndexClient<'a> {
|
||||||
.collect();
|
.collect();
|
||||||
Ok(FlatIndexEntries::from_entries(files))
|
Ok(FlatIndexEntries::from_entries(files))
|
||||||
}
|
}
|
||||||
Err(CachedClientError::Client { err, .. }) if err.is_offline() => {
|
Err(CachedClientError::Client(err)) if err.is_offline() => {
|
||||||
Ok(FlatIndexEntries::offline())
|
Ok(FlatIndexEntries::offline())
|
||||||
}
|
}
|
||||||
Err(err) => Err(err.into()),
|
Err(err) => Err(err.into()),
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
pub use base_client::{
|
pub use base_client::{
|
||||||
AuthIntegration, BaseClient, BaseClientBuilder, DEFAULT_RETRIES, ExtraMiddleware,
|
AuthIntegration, BaseClient, BaseClientBuilder, DEFAULT_MAX_REDIRECTS, DEFAULT_RETRIES,
|
||||||
RedirectClientWithMiddleware, RequestBuilder, RetryParsingError, UvRetryableStrategy,
|
ExtraMiddleware, RedirectClientWithMiddleware, RedirectPolicy, RequestBuilder,
|
||||||
is_transient_network_error,
|
RetryParsingError, RetryState, UvRetryableStrategy,
|
||||||
};
|
};
|
||||||
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};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-configuration"
|
name = "uv-configuration"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-configuration).
|
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)
|
||||||
|
|
|
||||||
|
|
@ -94,3 +94,32 @@ 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.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-console).
|
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)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-dev"
|
name = "uv-dev"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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 = ["flate2", "uv-extract", "uv-performance-memory-allocator"]
|
ignored = ["uv-performance-memory-allocator"]
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-dev).
|
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)
|
||||||
|
|
|
||||||
|
|
@ -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/20251217/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/20251217/cpython-unix/targets.yml>\n");
|
||||||
output.push_str("//!\n");
|
output.push_str("//!\n");
|
||||||
|
|
||||||
// Disable clippy/fmt
|
// Disable clippy/fmt
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-dirs"
|
name = "uv-dirs"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-dirs).
|
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)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-dispatch"
|
name = "uv-dispatch"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-dispatch).
|
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)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-distribution-filename"
|
name = "uv-distribution-filename"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-distribution-filename).
|
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)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-distribution-types"
|
name = "uv-distribution-types"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-distribution-types).
|
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)
|
||||||
|
|
|
||||||
|
|
@ -32,15 +32,18 @@ impl IndexCacheControl {
|
||||||
|
|
||||||
/// Return the default files cache control headers for the given index URL, if applicable.
|
/// Return the default files cache control headers for the given index URL, if applicable.
|
||||||
pub fn artifact_cache_control(url: &Url) -> Option<&'static str> {
|
pub fn artifact_cache_control(url: &Url) -> Option<&'static str> {
|
||||||
if url
|
let dominated_by_pytorch_or_nvidia = url.host_str().is_some_and(|host| {
|
||||||
.host_str()
|
host.eq_ignore_ascii_case("download.pytorch.org")
|
||||||
.is_some_and(|host| host.ends_with("pytorch.org"))
|
|| host.eq_ignore_ascii_case("pypi.nvidia.com")
|
||||||
{
|
});
|
||||||
|
if dominated_by_pytorch_or_nvidia {
|
||||||
// Some wheels in the PyTorch registry were accidentally uploaded with `no-cache,no-store,must-revalidate`.
|
// Some wheels in the PyTorch registry were accidentally uploaded with `no-cache,no-store,must-revalidate`.
|
||||||
// The PyTorch team plans to correct this in the future, but in the meantime we override
|
// The PyTorch team plans to correct this in the future, but in the meantime we override
|
||||||
// the cache control headers to allow caching of static files.
|
// the cache control headers to allow caching of static files.
|
||||||
//
|
//
|
||||||
// See: https://github.com/pytorch/pytorch/pull/149218
|
// See: https://github.com/pytorch/pytorch/pull/149218
|
||||||
|
//
|
||||||
|
// The same issue applies to files hosted on `pypi.nvidia.com`.
|
||||||
Some("max-age=365000000, immutable, public")
|
Some("max-age=365000000, immutable, public")
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
||||||
|
|
@ -875,4 +875,43 @@ mod tests {
|
||||||
Some("max-age=3600")
|
Some("max-age=3600")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_nvidia_default_cache_control() {
|
||||||
|
// Test that NVIDIA indexes get default cache control from the getter methods
|
||||||
|
let indexes = vec![Index {
|
||||||
|
name: Some(IndexName::from_str("nvidia").unwrap()),
|
||||||
|
url: IndexUrl::from_str("https://pypi.nvidia.com").unwrap(),
|
||||||
|
cache_control: None, // No explicit cache control
|
||||||
|
explicit: false,
|
||||||
|
default: false,
|
||||||
|
origin: None,
|
||||||
|
format: IndexFormat::Simple,
|
||||||
|
publish_url: None,
|
||||||
|
authenticate: uv_auth::AuthPolicy::default(),
|
||||||
|
ignore_error_codes: None,
|
||||||
|
}];
|
||||||
|
|
||||||
|
let index_urls = IndexUrls::from_indexes(indexes.clone());
|
||||||
|
let index_locations = IndexLocations::new(indexes, Vec::new(), false);
|
||||||
|
|
||||||
|
let nvidia_url = IndexUrl::from_str("https://pypi.nvidia.com").unwrap();
|
||||||
|
|
||||||
|
// IndexUrls should return the default for NVIDIA
|
||||||
|
assert_eq!(index_urls.simple_api_cache_control_for(&nvidia_url), None);
|
||||||
|
assert_eq!(
|
||||||
|
index_urls.artifact_cache_control_for(&nvidia_url),
|
||||||
|
Some("max-age=365000000, immutable, public")
|
||||||
|
);
|
||||||
|
|
||||||
|
// IndexLocations should also return the default for NVIDIA
|
||||||
|
assert_eq!(
|
||||||
|
index_locations.simple_api_cache_control_for(&nvidia_url),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
index_locations.artifact_cache_control_for(&nvidia_url),
|
||||||
|
Some("max-age=365000000, immutable, public")
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -159,9 +159,9 @@ pub enum InstalledVersion<'a> {
|
||||||
Url(&'a DisplaySafeUrl, &'a Version),
|
Url(&'a DisplaySafeUrl, &'a Version),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InstalledVersion<'_> {
|
impl<'a> InstalledVersion<'a> {
|
||||||
/// If it is a URL, return its value.
|
/// If it is a URL, return its value.
|
||||||
pub fn url(&self) -> Option<&DisplaySafeUrl> {
|
pub fn url(&self) -> Option<&'a 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 InstalledVersion<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If it is a version, return its value.
|
/// If it is a version, return its value.
|
||||||
pub fn version(&self) -> &Version {
|
pub fn version(&self) -> &'a Version {
|
||||||
match self {
|
match self {
|
||||||
Self::Version(version) => version,
|
Self::Version(version) => version,
|
||||||
Self::Url(_, version) => version,
|
Self::Url(_, version) => version,
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ impl IndexStatusCodeStrategy {
|
||||||
pub fn from_index_url(url: &Url) -> Self {
|
pub fn from_index_url(url: &Url) -> Self {
|
||||||
if url
|
if url
|
||||||
.host_str()
|
.host_str()
|
||||||
.is_some_and(|host| host.ends_with("pytorch.org"))
|
.is_some_and(|host| host.eq_ignore_ascii_case("download.pytorch.org"))
|
||||||
{
|
{
|
||||||
// The PyTorch registry returns a 403 when a package is not found, so
|
// The PyTorch registry returns a 403 when a package is not found, so
|
||||||
// we ignore them when deciding whether to search other indexes.
|
// we ignore them when deciding whether to search other indexes.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-distribution"
|
name = "uv-distribution"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-distribution).
|
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)
|
||||||
|
|
|
||||||
|
|
@ -721,7 +721,7 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
|
||||||
.await
|
.await
|
||||||
.map_err(|err| match err {
|
.map_err(|err| match err {
|
||||||
CachedClientError::Callback { err, .. } => err,
|
CachedClientError::Callback { err, .. } => err,
|
||||||
CachedClientError::Client { err, .. } => Error::Client(err),
|
CachedClientError::Client(err) => Error::Client(err),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// If the archive is missing the required hashes, or has since been removed, force a refresh.
|
// If the archive is missing the required hashes, or has since been removed, force a refresh.
|
||||||
|
|
@ -745,7 +745,7 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
|
||||||
.await
|
.await
|
||||||
.map_err(|err| match err {
|
.map_err(|err| match err {
|
||||||
CachedClientError::Callback { err, .. } => err,
|
CachedClientError::Callback { err, .. } => err,
|
||||||
CachedClientError::Client { err, .. } => Error::Client(err),
|
CachedClientError::Client(err) => Error::Client(err),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.await?
|
.await?
|
||||||
|
|
@ -926,7 +926,7 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
|
||||||
.await
|
.await
|
||||||
.map_err(|err| match err {
|
.map_err(|err| match err {
|
||||||
CachedClientError::Callback { err, .. } => err,
|
CachedClientError::Callback { err, .. } => err,
|
||||||
CachedClientError::Client { err, .. } => Error::Client(err),
|
CachedClientError::Client(err) => Error::Client(err),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// If the archive is missing the required hashes, or has since been removed, force a refresh.
|
// If the archive is missing the required hashes, or has since been removed, force a refresh.
|
||||||
|
|
@ -950,7 +950,7 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
|
||||||
.await
|
.await
|
||||||
.map_err(|err| match err {
|
.map_err(|err| match err {
|
||||||
CachedClientError::Callback { err, .. } => err,
|
CachedClientError::Callback { err, .. } => err,
|
||||||
CachedClientError::Client { err, .. } => Error::Client(err),
|
CachedClientError::Client(err) => Error::Client(err),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.await?
|
.await?
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,11 @@ 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::{WheelFilename, WheelFilenameError};
|
||||||
use uv_distribution_types::{InstalledDist, InstalledDistError, IsBuildBackendError};
|
use uv_distribution_types::{InstalledDist, InstalledDistError, IsBuildBackendError};
|
||||||
use uv_fs::{LockedFileError, Simplified};
|
use uv_fs::Simplified;
|
||||||
use uv_git::GitError;
|
use uv_git::GitError;
|
||||||
use uv_normalize::PackageName;
|
use uv_normalize::PackageName;
|
||||||
use uv_pep440::{Version, VersionSpecifiers};
|
use uv_pep440::{Version, VersionSpecifiers};
|
||||||
|
|
@ -42,7 +43,7 @@ pub enum 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")]
|
#[error("Failed to acquire lock on the distribution cache")]
|
||||||
CacheLock(#[source] LockedFileError),
|
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")]
|
||||||
|
|
|
||||||
|
|
@ -823,7 +823,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
||||||
.await
|
.await
|
||||||
.map_err(|err| match err {
|
.map_err(|err| match err {
|
||||||
CachedClientError::Callback { err, .. } => err,
|
CachedClientError::Callback { err, .. } => err,
|
||||||
CachedClientError::Client { err, .. } => Error::Client(err),
|
CachedClientError::Client(err) => Error::Client(err),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// If the archive is missing the required hashes, force a refresh.
|
// If the archive is missing the required hashes, force a refresh.
|
||||||
|
|
@ -843,7 +843,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
||||||
.await
|
.await
|
||||||
.map_err(|err| match err {
|
.map_err(|err| match err {
|
||||||
CachedClientError::Callback { err, .. } => err,
|
CachedClientError::Callback { err, .. } => err,
|
||||||
CachedClientError::Client { err, .. } => Error::Client(err),
|
CachedClientError::Client(err) => Error::Client(err),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
|
@ -2280,7 +2280,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
||||||
.await
|
.await
|
||||||
.map_err(|err| match err {
|
.map_err(|err| match err {
|
||||||
CachedClientError::Callback { err, .. } => err,
|
CachedClientError::Callback { err, .. } => err,
|
||||||
CachedClientError::Client { err, .. } => Error::Client(err),
|
CachedClientError::Client(err) => Error::Client(err),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-extract"
|
name = "uv-extract"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-extract).
|
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-extract).
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-flags"
|
name = "uv-flags"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-flags).
|
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-flags).
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-fs"
|
name = "uv-fs"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-fs).
|
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-fs).
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::convert::Into;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
@ -59,10 +60,18 @@ pub enum LockedFileError {
|
||||||
source: io::Error,
|
source: io::Error,
|
||||||
},
|
},
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Io(#[from] io::Error),
|
|
||||||
#[error(transparent)]
|
|
||||||
#[cfg(feature = "tokio")]
|
#[cfg(feature = "tokio")]
|
||||||
JoinError(#[from] tokio::task::JoinError),
|
JoinError(#[from] tokio::task::JoinError),
|
||||||
|
#[error("Could not create temporary file")]
|
||||||
|
CreateTemporary(#[source] io::Error),
|
||||||
|
#[error("Could not persist temporary file `{}`", path.user_display())]
|
||||||
|
PersistTemporary {
|
||||||
|
path: PathBuf,
|
||||||
|
#[source]
|
||||||
|
source: io::Error,
|
||||||
|
},
|
||||||
|
#[error(transparent)]
|
||||||
|
Io(#[from] io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LockedFileError {
|
impl LockedFileError {
|
||||||
|
|
@ -72,6 +81,8 @@ impl LockedFileError {
|
||||||
#[cfg(feature = "tokio")]
|
#[cfg(feature = "tokio")]
|
||||||
Self::JoinError(_) => None,
|
Self::JoinError(_) => None,
|
||||||
Self::Lock { source, .. } => Some(source),
|
Self::Lock { source, .. } => Some(source),
|
||||||
|
Self::CreateTemporary(err) => Some(err),
|
||||||
|
Self::PersistTemporary { source, .. } => Some(source),
|
||||||
Self::Io(err) => Some(err),
|
Self::Io(err) => Some(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -201,7 +212,7 @@ impl LockedFile {
|
||||||
mode: LockedFileMode,
|
mode: LockedFileMode,
|
||||||
resource: impl Display,
|
resource: impl Display,
|
||||||
) -> Result<Self, LockedFileError> {
|
) -> Result<Self, LockedFileError> {
|
||||||
let file = Self::create(path)?;
|
let file = Self::create(&path)?;
|
||||||
let resource = resource.to_string();
|
let resource = resource.to_string();
|
||||||
Self::lock_file(file, mode, &resource).await
|
Self::lock_file(file, mode, &resource).await
|
||||||
}
|
}
|
||||||
|
|
@ -222,10 +233,25 @@ impl LockedFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn create(path: impl AsRef<Path>) -> Result<fs_err::File, std::io::Error> {
|
fn create(path: impl AsRef<Path>) -> Result<fs_err::File, LockedFileError> {
|
||||||
use std::os::unix::fs::PermissionsExt;
|
use rustix::io::Errno;
|
||||||
|
#[allow(clippy::disallowed_types)]
|
||||||
|
use std::{fs::File, os::unix::fs::PermissionsExt};
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
|
|
||||||
|
/// The permissions the lockfile should end up with
|
||||||
|
const DESIRED_MODE: u32 = 0o666;
|
||||||
|
|
||||||
|
#[allow(clippy::disallowed_types)]
|
||||||
|
fn try_set_permissions(file: &File, path: &Path) {
|
||||||
|
if let Err(err) = file.set_permissions(std::fs::Permissions::from_mode(DESIRED_MODE)) {
|
||||||
|
warn!(
|
||||||
|
"Failed to set permissions on temporary file `{path}`: {err}",
|
||||||
|
path = path.user_display()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If path already exists, return it.
|
// If path already exists, return it.
|
||||||
if let Ok(file) = fs_err::OpenOptions::new()
|
if let Ok(file) = fs_err::OpenOptions::new()
|
||||||
.read(true)
|
.read(true)
|
||||||
|
|
@ -238,16 +264,12 @@ impl LockedFile {
|
||||||
// Otherwise, create a temporary file with 666 permissions. We must set
|
// Otherwise, create a temporary file with 666 permissions. We must set
|
||||||
// permissions _after_ creating the file, to override the `umask`.
|
// permissions _after_ creating the file, to override the `umask`.
|
||||||
let file = if let Some(parent) = path.as_ref().parent() {
|
let file = if let Some(parent) = path.as_ref().parent() {
|
||||||
NamedTempFile::new_in(parent)?
|
NamedTempFile::new_in(parent)
|
||||||
} else {
|
} else {
|
||||||
NamedTempFile::new()?
|
NamedTempFile::new()
|
||||||
};
|
|
||||||
if let Err(err) = file
|
|
||||||
.as_file()
|
|
||||||
.set_permissions(std::fs::Permissions::from_mode(0o666))
|
|
||||||
{
|
|
||||||
warn!("Failed to set permissions on temporary file: {err}");
|
|
||||||
}
|
}
|
||||||
|
.map_err(LockedFileError::CreateTemporary)?;
|
||||||
|
try_set_permissions(file.as_file(), file.path());
|
||||||
|
|
||||||
// Try to move the file to path, but if path exists now, just open path
|
// Try to move the file to path, but if path exists now, just open path
|
||||||
match file.persist_noclobber(path.as_ref()) {
|
match file.persist_noclobber(path.as_ref()) {
|
||||||
|
|
@ -258,20 +280,60 @@ impl LockedFile {
|
||||||
.read(true)
|
.read(true)
|
||||||
.write(true)
|
.write(true)
|
||||||
.open(path.as_ref())
|
.open(path.as_ref())
|
||||||
|
.map_err(Into::into)
|
||||||
|
} else if matches!(
|
||||||
|
Errno::from_io_error(&err.error),
|
||||||
|
Some(Errno::NOTSUP | Errno::INVAL)
|
||||||
|
) {
|
||||||
|
// Fallback in case `persist_noclobber`, which uses `renameat2` or
|
||||||
|
// `renameatx_np` under the hood, is not supported by the FS. Linux reports this
|
||||||
|
// with `EINVAL` and MacOS with `ENOTSUP`. For these reasons and many others,
|
||||||
|
// there isn't an ErrorKind we can use here, and in fact on MacOS `ENOTSUP` gets
|
||||||
|
// mapped to `ErrorKind::Other`
|
||||||
|
|
||||||
|
// There is a race here where another process has just created the file, and we
|
||||||
|
// try to open it and get permission errors because the other process hasn't set
|
||||||
|
// the permission bits yet. This will lead to a transient failure, but unlike
|
||||||
|
// alternative approaches it won't ever lead to a situation where two processes
|
||||||
|
// are locking two different files. Also, since `persist_noclobber` is more
|
||||||
|
// likely to not be supported on special filesystems which don't have permission
|
||||||
|
// bits, it's less likely to ever matter.
|
||||||
|
let file = fs_err::OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.open(path.as_ref())?;
|
||||||
|
|
||||||
|
// We don't want to `try_set_permissions` in cases where another user's process
|
||||||
|
// has already created the lockfile and changed its permissions because we might
|
||||||
|
// not have permission to change the permissions which would produce a confusing
|
||||||
|
// warning.
|
||||||
|
if file
|
||||||
|
.metadata()
|
||||||
|
.is_ok_and(|metadata| metadata.permissions().mode() != DESIRED_MODE)
|
||||||
|
{
|
||||||
|
try_set_permissions(file.file(), path.as_ref());
|
||||||
|
}
|
||||||
|
Ok(file)
|
||||||
} else {
|
} else {
|
||||||
Err(err.error)
|
let temp_path = err.file.into_temp_path();
|
||||||
|
Err(LockedFileError::PersistTemporary {
|
||||||
|
path: <tempfile::TempPath as AsRef<Path>>::as_ref(&temp_path).to_path_buf(),
|
||||||
|
source: err.error,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
fn create(path: impl AsRef<Path>) -> std::io::Result<fs_err::File> {
|
fn create(path: impl AsRef<Path>) -> Result<fs_err::File, LockedFileError> {
|
||||||
fs_err::OpenOptions::new()
|
fs_err::OpenOptions::new()
|
||||||
.read(true)
|
.read(true)
|
||||||
.write(true)
|
.write(true)
|
||||||
.create(true)
|
.create(true)
|
||||||
.open(path.as_ref())
|
.open(path.as_ref())
|
||||||
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-git-types"
|
name = "uv-git-types"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-git-types).
|
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-git-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)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-git"
|
name = "uv-git"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-git).
|
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-git).
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-globfilter"
|
name = "uv-globfilter"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
description = "This is an internal component crate of uv"
|
description = "This is an internal component crate of uv"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-install-wheel"
|
name = "uv-install-wheel"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
description = "This is an internal component crate of uv"
|
description = "This is an internal component crate of uv"
|
||||||
keywords = ["wheel", "python"]
|
keywords = ["wheel", "python"]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-install-wheel).
|
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-install-wheel).
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-installer"
|
name = "uv-installer"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-installer).
|
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-installer).
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-keyring"
|
name = "uv-keyring"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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 }
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-logging"
|
name = "uv-logging"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-logging).
|
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-logging).
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-macros"
|
name = "uv-macros"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-macros).
|
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-macros).
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-metadata"
|
name = "uv-metadata"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-metadata).
|
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-metadata).
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-normalize"
|
name = "uv-normalize"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-normalize).
|
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-normalize).
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-once-map"
|
name = "uv-once-map"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-once-map).
|
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-once-map).
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-options-metadata"
|
name = "uv-options-metadata"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
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,8 +5,8 @@
|
||||||
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.7) is a component of [uv 0.9.17](https://crates.io/crates/uv/0.9.17). The source
|
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.17/crates/uv-options-metadata).
|
can be found [here](https://github.com/astral-sh/uv/blob/0.9.18/crates/uv-options-metadata).
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uv-pep440"
|
name = "uv-pep440"
|
||||||
version = "0.0.7"
|
version = "0.0.8"
|
||||||
description = "This is an internal component crate of uv"
|
description = "This is an internal component crate of uv"
|
||||||
license = "Apache-2.0 OR BSD-2-Clause"
|
license = "Apache-2.0 OR BSD-2-Clause"
|
||||||
include = ["/src", "Changelog.md", "License-Apache", "License-BSD", "Readme.md", "pyproject.toml"]
|
include = ["/src", "Changelog.md", "License-Apache", "License-BSD", "Readme.md", "pyproject.toml"]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!-- This file is generated. DO NOT EDIT -->
|
||||||
|
|
||||||
|
# uv-pep440
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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-pep440).
|
||||||
|
|
||||||
|
See uv's
|
||||||
|
[crate versioning policy](https://docs.astral.sh/uv/reference/policies/versioning/#crate-versioning)
|
||||||
|
for details on versioning.
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue