Skip to content

Commit 31ad5d2

Browse files
authored
feat: install uv (#198)
1 parent 06c08b1 commit 31ad5d2

File tree

2 files changed

+109
-0
lines changed

2 files changed

+109
-0
lines changed

README.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,59 @@ export VIRTUAL_ENV="${PWD}/.venv"
153153
PATH_add "${PWD}/.venv/bin"
154154
```
155155

156+
if using uv:
157+
158+
`[reporoot]/devenv/sync.py`
159+
```py
160+
from devenv.lib import uv
161+
162+
def main(context: dict[str, str]) -> int:
163+
reporoot = context["reporoot"]
164+
cfg = config.get_repo(reporoot)
165+
166+
uv.install(
167+
cfg["uv"]["version"],
168+
cfg["uv"][constants.SYSTEM_MACHINE],
169+
cfg["uv"][f"{constants.SYSTEM_MACHINE}_sha256"],
170+
reporoot,
171+
)
172+
173+
# reporoot/.venv is the default venv location
174+
print(f"syncing .venv ...")
175+
proc.run(("uv", "sync", "--frozen", "--quiet"))
176+
177+
return 0
178+
```
179+
180+
`[reporoot]/devenv/config.ini`
181+
```ini
182+
[uv]
183+
darwin_arm64 = https://github.com/astral-sh/uv/releases/download/0.7.21/uv-aarch64-apple-darwin.tar.gz
184+
darwin_arm64_sha256 = c73af7a4e0bcea9b5b593a0c7e5c025ee78d8be3f7cd60bfeadc8614a16c92ef
185+
darwin_x86_64 = https://github.com/astral-sh/uv/releases/download/0.7.21/uv-x86_64-apple-darwin.tar.gz
186+
darwin_x86_64_sha256 = f8a9b4f4a80a44653344d36b53e148134176e8f7cc99f8e823676a57c884595e
187+
linux_arm64 = https://github.com/astral-sh/uv/releases/download/0.7.21/uv-aarch64-unknown-linux-gnu.tar.gz
188+
linux_arm64_sha256 = 1dae18211605b9d00767d913da5108aea50200a88372bf8a2e1f56abdbe509f0
189+
linux_x86_64 = https://github.com/astral-sh/uv/releases/download/0.7.21/uv-x86_64-unknown-linux-gnu.tar.gz
190+
linux_x86_64_sha256 = ca3e8898adfce5fcc891d393a079013fa4bd0d9636cef11aded8a7485bcba312
191+
# used for autoupdate
192+
version = 0.7.21
193+
```
194+
195+
`[reporoot]/.python-version`
196+
```
197+
3.13.3
198+
```
199+
200+
`[reporoot]/pyproject.toml`
201+
```
202+
[project]
203+
name = "foo"
204+
version = "0.0.0"
205+
```
206+
207+
or classic pip:
208+
156209
`[reporoot]/devenv/sync.py`
157210
```py
158211
from devenv.lib import config, venv

devenv/lib/uv.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
from __future__ import annotations
2+
3+
import os
4+
import shutil
5+
import tempfile
6+
7+
from devenv.lib import archive
8+
from devenv.lib import fs
9+
from devenv.lib import proc
10+
11+
12+
def _install(url: str, sha256: str, into: str) -> None:
13+
with tempfile.TemporaryDirectory(dir=into) as tmpd:
14+
archive_file = archive.download(url, sha256, dest=f"{tmpd}/download")
15+
archive.unpack(archive_file, tmpd, perform_strip1=True)
16+
17+
# the archive was atomically placed into tmpd so
18+
# these are on the same fs and can be atomically moved too
19+
os.replace(f"{tmpd}/uv", f"{into}/uv")
20+
os.replace(f"{tmpd}/uvx", f"{into}/uvx")
21+
22+
23+
def uninstall(binroot: str) -> None:
24+
for fp in (f"{binroot}/uv", f"{binroot}/uvx"):
25+
try:
26+
os.remove(fp)
27+
except FileNotFoundError:
28+
# it's better to do this than to guard with
29+
# os.path.exists(fp) because if it's an invalid or circular
30+
# symlink the result'll be False!
31+
pass
32+
33+
34+
def _version(binpath: str) -> str:
35+
stdout = proc.run((binpath, "--version"), stdout=True)
36+
# uv 0.7.21 (77c771c7f 2025-07-14)
37+
return stdout.split()[1]
38+
39+
40+
def install(version: str, url: str, sha256: str, reporoot: str) -> None:
41+
binroot = fs.ensure_binroot(reporoot)
42+
binpath = f"{binroot}/uv"
43+
44+
if shutil.which("uv", path=binroot) == binpath:
45+
installed_version = _version(binpath)
46+
if version == installed_version:
47+
return
48+
print(f"installed uv {installed_version} is unexpected!")
49+
50+
print(f"installing uv {version}...")
51+
uninstall(binroot)
52+
_install(url, sha256, binroot)
53+
54+
installed_version = _version(binpath)
55+
if version != installed_version:
56+
raise SystemExit("Failed to install uv {version}!")

0 commit comments

Comments
 (0)