Commit Graph

7321 Commits

Author SHA1 Message Date
konsti de9e85978b
Fix tempdir rename (#94)
This fixes two bugs on linux:

`/tmp` and `$HOME` are technically on two different partitions on my
machine, which means that rename-as-atomic-dir-write doesn't work. The
solution is to create the temp dir in the target directory.

zip files may contain directory entries, we can't create files for them
but need to create directories. We could skip them though because iirc
they are not in the RECORD so they won't be uninstalled.
2023-10-12 18:47:38 +00:00
konsti 530edb6e39
Add output file option to compile (#93)
`pip-compile` has the same option. I need this esp. since piping doesn't
work as we write to stdout.
2023-10-12 20:42:06 +02:00
konsti 6a7954cdd0
Add `-p` base python option to venv command (#92)
This is the same option that `virtualenv` offers, except that we only
support absolute paths atm and not e.g. `-p 3.10` (which we need to
eventually).
2023-10-12 20:41:52 +02:00
Charlie Marsh a622345fbc
Replace mocked server with 'real' integration tests (#91)
We can always restore these from history, but right now, it feels a lot
more productive to just hit PyPI directly for our integration tests,
since we don't have to spend time figuring out mocks.
2023-10-12 17:34:48 +00:00
Charlie Marsh 496cb7b2ef
Migrate to `requirements_txt.rs` (#90)
Remove the parser I wrote in favor of Konsti's which is much more
complete. The only change vs. the version in `poc-monotrail` is that I
changed the tests to use insta rather than manually storing and
comparing against JSON snapshots.

Closes https://github.com/astral-sh/puffin/issues/89.
2023-10-12 17:09:00 +00:00
Charlie Marsh 906a482499
Separate unzip into its own install phase (#87) 2023-10-11 15:18:23 +00:00
Charlie Marsh 85162d1111
Parallelize wheel installations with Rayon (#84)
It looks like using _either_ async Rust with a `JoinSet` _or_
parallelizing a fixed threadpool with Rayon provide about a ~5% speed-up
over our current serial approach:

```console
❯ hyperfine --runs 30 --warmup 5 --prepare "./target/release/puffin venv .venv" \
  "./target/release/rayon sync ./scripts/benchmarks/requirements-large.txt" \
  "./target/release/async sync ./scripts/benchmarks/requirements-large.txt" \
  "./target/release/main sync ./scripts/benchmarks/requirements-large.txt"
Benchmark 1: ./target/release/rayon sync ./scripts/benchmarks/requirements-large.txt
  Time (mean ± σ):     295.7 ms ±  16.9 ms    [User: 28.6 ms, System: 263.3 ms]
  Range (min … max):   249.2 ms … 315.9 ms    30 runs

Benchmark 2: ./target/release/async sync ./scripts/benchmarks/requirements-large.txt
  Time (mean ± σ):     296.2 ms ±  20.2 ms    [User: 36.1 ms, System: 340.1 ms]
  Range (min … max):   258.0 ms … 359.4 ms    30 runs

Benchmark 3: ./target/release/main sync ./scripts/benchmarks/requirements-large.txt
  Time (mean ± σ):     306.6 ms ±  19.5 ms    [User: 25.3 ms, System: 220.5 ms]
  Range (min … max):   269.6 ms … 332.2 ms    30 runs

Summary
  './target/release/rayon sync ./scripts/benchmarks/requirements-large.txt' ran
    1.00 ± 0.09 times faster than './target/release/async sync ./scripts/benchmarks/requirements-large.txt'
    1.04 ± 0.09 times faster than './target/release/main sync ./scripts/benchmarks/requirements-large.txt'
```

It's much easier to just parallelize with Rayon and avoid async in the
underlying wheel code, so this PR takes that approach for now.
2023-10-10 23:46:30 -04:00
Charlie Marsh ed68d31e03
Add a basic test for the resolver (#86)
Mocks out the PyPI client using some checked-in fixtures. The test is
very basic, and I'm not very happy with all the ceremony around the
mocks and such, but it's an interesting experiment at least.
2023-10-11 03:30:53 +00:00
Charlie Marsh c1fb698eae
Add a separate dist-info name struct (#85) 2023-10-10 23:21:18 +00:00
Charlie Marsh d0764bdc23
Add `puffin venv` command to create virtual environments (#83)
Closes https://github.com/astral-sh/puffin/issues/58.
2023-10-10 13:46:25 -04:00
Charlie Marsh a0294a510c
Rework `puffin sync` output to summarize (#81)
This also moves away from using `tracing` for user-facing logging,
instead introducing a new `Printer` abstraction.

Closes #66.
2023-10-10 03:29:09 +00:00
Charlie Marsh 2d4a8c361b
Change puffin-cli binary to puffin (#80) 2023-10-09 17:19:33 -04:00
Charlie Marsh f03c605bde
Add a script to benchmark uninstalls (#78) 2023-10-09 16:59:15 -04:00
Charlie Marsh ba2b200fce
Enable release builds via `cargo-dist` (#79) 2023-10-09 20:48:55 +00:00
Charlie Marsh b90140e1bc
Add support for wheel uninstalls (#77)
Closes #36.
2023-10-09 14:14:33 -04:00
Charlie Marsh 239b5893d8
Fix version satisfier for unpinned dependencies (#74) 2023-10-09 11:48:39 -04:00
Charlie Marsh 485b1dceb6
Use a single requirements iterator in `sync` (#71) 2023-10-09 03:29:38 +00:00
Charlie Marsh ba72950546
Avoid passing cached wheels to the resolver step (#70)
When we go to install a locked `requirements.txt`, if a wheel is already
available in the local cache, and matches the version specifiers, we can
just use it directly without fetching the package metadata. This speeds
up the no-op case by about 33%.

Closes https://github.com/astral-sh/puffin/issues/48.
2023-10-08 22:17:19 -04:00
Charlie Marsh 75cb7a0178
Add benchmark scripts (#69)
Moving these out of the README and into proper scripts.
2023-10-08 23:37:38 +00:00
Charlie Marsh 5b71cfdd0b
Remove Monotrail-specific code from `install-wheel-rs` (#68)
I think this isn't necessary to support in this generic crate. If we
choose to adopt Monotrail-style concepts, we'll likely need to rework
them anyway.
2023-10-08 18:28:57 -04:00
Charlie Marsh adbee4fb32
Use recursive `clonefile` calls on macOS (#67)
It turns out that on macOS, you can pass `clonefile` a directory to
recursively copy an entire directory. This speeds up wheel installation
dramatically, by about 3x.
2023-10-08 21:44:02 +00:00
Charlie Marsh 1c942ab8fe
Tweak tracing output for sync command (#64) 2023-10-08 20:09:15 +00:00
Charlie Marsh a53f697f62
Use `tracing` for user-facing output (#63)
The setup is now as follows:

- All user-facing logging goes through `tracing` at an `info` leve.
(This excludes messages that go to `stdout`, like the compiled
`requirements.txt` file.)
- We have `--quiet` and `--verbose` command-line flags to set the
tracing filter and format defaults. So if you use `--verbose`, we
include timestamps and targets, and filter at `puffin=debug` level.
- However, we always respect `RUST_LOG`. So you can override the
_filter_ via `RUST_LOG`.

For example: the standard setup filters to `puffin=info`, and doesn't
show timestamps or targets:

<img width="1235" alt="Screen Shot 2023-10-08 at 3 41 22 PM"
src="https://github.com/astral-sh/puffin/assets/1309177/54ca4db6-c66a-439e-bfa3-b86dee136e45">

If you run with `--verbose`, you get debug logging, but confined to our
crates:

<img width="1235" alt="Screen Shot 2023-10-08 at 3 41 57 PM"
src="https://github.com/astral-sh/puffin/assets/1309177/c5c1af11-7f7a-4038-a173-d9eca4c3630b">

If you want verbose logging with _all_ crates, you can add
`RUST_LOG=debug`:

<img width="1235" alt="Screen Shot 2023-10-08 at 3 42 39 PM"
src="https://github.com/astral-sh/puffin/assets/1309177/0b5191f4-4db0-4db9-86ba-6f9fa521bcb6">

I think this is a reasonable setup, though we can see how it feels and
refine over time.

Closes https://github.com/astral-sh/puffin/issues/57.
2023-10-08 15:46:06 -04:00
Charlie Marsh 0ca17a1cf2
Use local copy of `gourgeist` (#62)
This PR gets `gourgeist` passing our local CI and integrated into the
broader workspace.

There's some duplicate between concepts in `gourgeist` (like the
`InterpreterInfo`) and structs we have elsewhere, but we can tackle
those later.
2023-10-08 18:45:08 +00:00
Charlie Marsh 7caf5f42b8
Copy over `gourgeist` crate (#61)
This PR copies over the `gourgeist` crate at commit
`e64c17a263dac6933702dc8d155425c053fe885a` with no modifications.

It won't pass CI, but modifications will intentionally be confined to
later PRs.
2023-10-08 14:37:09 -04:00
Charlie Marsh d1ed41170b
Cache environment marker lookups (#55)
Closes https://github.com/astral-sh/puffin/issues/53.
2023-10-08 05:31:19 +00:00
Charlie Marsh 5eef6e9636
Store cached wheels by dist-info-like name (#52)
Closes https://github.com/astral-sh/puffin/issues/50.
2023-10-08 04:28:04 +00:00
Charlie Marsh fd5aef2c75
Avoid error when repeatedly clearing cache (#51)
Also avoid failing to clear the cache when it contains non-directories
(e.g., I had a `.DS_Store` after looking at it in Finder).
2023-10-08 04:16:48 +00:00
Charlie Marsh 2a846e76b7
Store unzipped wheels in a cache (#49)
This PR massively speeds up the case in which you need to install wheels
that already exist in the global cache.

The new strategy is as follows:

- Download the wheel into the content-addressed cache.
- Unzip the wheel into the cache, but ignore content-addressing. It
turns out that writing to `cacache` for every file in the zip added a
ton of overhead, and I don't see any actual advantages to doing so.
Instead, we just unzip the contents into a directory at, e.g.,
`~/.cache/puffin/django-4.1.5`.
- (The unzip itself is now parallelized with Rayon.)
- When installing the wheel, we now support unzipping from a directory
instead of a zip archive. This required duplicating and tweaking a few
functions.
- When installing the wheel, we now use reflinks (or copy-on-write
links). These have a few fantastic properties: (1) they're extremely
cheap to create (on macOS, they are allegedly faster than hard links);
(2) they minimize disk space, since we avoid copying files entirely in
the vast majority of cases; and (3) if the user then edits a file
locally, the cache doesn't get polluted. Orogene, Bun, and soon pnpm all
use reflinks.

Puffin is now ~15x faster than `pip` for the common case of installing
cached data into a fresh environment.

Closes https://github.com/astral-sh/puffin/issues/21.

Closes https://github.com/astral-sh/puffin/issues/39.
2023-10-08 04:04:48 +00:00
Charlie Marsh a46887d34b
Add motivation to README (#47) 2023-10-07 23:39:56 +00:00
Charlie Marsh 92160e37df
Surface error when unable to find package (#45) 2023-10-07 19:43:12 +00:00
Charlie Marsh 9be02d1590
Skip already-installed dependencies during `sync` command (#43)
Closes https://github.com/astral-sh/puffin/issues/35.
2023-10-07 19:26:45 +00:00
Charlie Marsh bc1736feff
Add a `freeze` command to list installed dependencies (#42)
A pre-requisite for https://github.com/astral-sh/puffin/issues/35.
2023-10-07 18:46:09 +00:00
Charlie Marsh f3015ffc1f
Add a `clean` command to clear the cache (#41) 2023-10-07 15:19:03 +00:00
Charlie Marsh f14b1f0c95
Update benchmark command in README (#40) 2023-10-07 14:32:25 +00:00
Charlie Marsh 162952bf64
Add a content-addressed cache for wheels (#38)
Closes https://github.com/astral-sh/puffin/issues/4.
2023-10-07 14:24:52 +00:00
Charlie Marsh 6c31631913
Fetch from `data-dist-info-metadata` when available (#37)
As specified in https://peps.python.org/pep-0658/#specification.
2023-10-07 13:05:29 +00:00
Charlie Marsh ae28552b3a
Use local copy of `install-wheel-rs` (#34)
This PR modifies the `install-wheel-rs` (and a few other crates) to get
everything playing nicely. Specifically, CI should pass, and all these
crates now use workspace dependencies between one another.

As part of this change, I split out the wheel name parsing into its own
`wheel-filename` crate, and the compatibility tag parsing into its own
`platform-tags` crate.
2023-10-07 01:43:55 +00:00
Charlie Marsh e824fe6d2b
Copy over `install-wheel-rs` crate (#33)
This PR copies over the `install-wheel-rs` crate at commit
`10730ea1a84c58af6b35fb74c89ed0578ab042b6` with no modifications.

It won't pass CI, but modifications will intentionally be confined to
later PRs.
2023-10-06 21:38:38 -04:00
Charlie Marsh c8477991a9
Use local versions of PEP 440 and PEP 508 crates (#32)
This PR modifies the PEP 440 and PEP 508 crates to pass CI, primarily by
fixing all lint violations.

We're also now using these crates in the workspace via `path`.
(Previously, we were still fetching them from Cargo.)
2023-10-07 00:16:44 +00:00
Charlie Marsh 4fcdb3c045
Copy over `pep508-rs` crate (#31)
This PR copies over the `pep440-rs` crate at commit
`82aa5d4dcbe676b121dc931b0afa09a82de8e3d7` with no modifications.

It won't pass CI, but modifications will intentionally be confined to
later PRs.
2023-10-06 20:12:19 -04:00
Charlie Marsh f03398bee3
Copy over `pep440-rs` crate (#30)
This PR copies over the `pep440-rs` crate at commit
`a8303b01ffef6fccfdce562a887f6b110d482ef3` with no modifications.

It won't pass CI, but modifications will intentionally be confined to
later PRs.
2023-10-06 20:11:52 -04:00
Charlie Marsh 1e6a217503
Check in `Cargo.lock` (#29) 2023-10-06 20:59:17 +00:00
Charlie Marsh 36d0124e60
Do wheel downloads concurrently (#28) 2023-10-06 20:51:31 +00:00
Charlie Marsh dd26cfa0cc
Migrate to `tokio` (#27)
Closes https://github.com/astral-sh/puffin/issues/26.
2023-10-06 20:31:03 +00:00
Charlie Marsh ca6aa207ff
Move to workspace dependencies (#25) 2023-10-06 19:49:41 +00:00
Charlie Marsh dab70a661a
Change `install` to `sync` (with sync semantics) (#24)
For better separate at this stage (and following `pip-tools`), it's now
`puffin sync`, and it assumes `--no-deps`.
2023-10-06 19:42:58 +00:00
Charlie Marsh ff8e24a621
Move `puffin-installer` to its own crate (#23) 2023-10-06 19:31:21 +00:00
Charlie Marsh f395c9c98c Update README 2023-10-06 01:03:07 -04:00
Charlie Marsh 28721cf5fc Avoid caching wheel fetches 2023-10-06 00:50:30 -04:00