Add source distribution support to pip-compile (#323)

## Summary

This is a first-pass at adding source distribution support to the
installer.

The previous installation flow was:

1. Come up with a plan.
1. Find a distribution (specific file) for every package that we'll need
to download.
1. Download those distributions.
1. Unzip them (since we assumed they were all wheels).
1. Install them into the virtual environment.

Now, Step (3) downloads both wheels and source distributions, and we
insert a step between Steps (3) and (4) to build any source
distributions into zipped wheels.

There are a bunch of TODOs, the most important (IMO) is that we
basically have two implementations of downloading and building, between
the stuff in `puffin_installer` and `puffin_resolver` (namely in
`crates/puffin-resolver/src/distribution`). I didn't attempt to clean
that up here -- it's already a problem, and it's related to the overall
problem we need to solve around unified caching and resource management.

Closes #243.
This commit is contained in:
Charlie Marsh 2023-11-06 05:22:36 -08:00 committed by GitHub
parent b79a15b458
commit 6d672b8951
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 745 additions and 79 deletions

View file

@ -8,14 +8,14 @@ use std::pin::Pin;
use anyhow::Context;
use anyhow::Result;
use itertools::Itertools;
use itertools::{Either, Itertools};
use tracing::{debug, instrument};
use pep508_rs::Requirement;
use platform_tags::Tags;
use puffin_build::SourceDistributionBuilder;
use puffin_client::RegistryClient;
use puffin_installer::{Downloader, Installer, PartitionedRequirements, Unzipper};
use puffin_installer::{Builder, Downloader, Installer, PartitionedRequirements, Unzipper};
use puffin_interpreter::{InterpreterInfo, Virtualenv};
use puffin_resolver::{DistributionFinder, Manifest, PreReleaseMode, ResolutionMode, Resolver};
use puffin_traits::BuildContext;
@ -144,6 +144,33 @@ impl BuildContext for BuildDispatch {
.context("Failed to download build dependencies")?
};
let (wheels, sdists): (Vec<_>, Vec<_>) =
downloads
.into_iter()
.partition_map(|download| match download {
puffin_installer::Download::Wheel(wheel) => Either::Left(wheel),
puffin_installer::Download::SourceDistribution(sdist) => {
Either::Right(sdist)
}
});
// Build any missing source distributions.
let sdists = if sdists.is_empty() {
vec![]
} else {
debug!(
"Building source distributions{}: {}",
if sdists.len() == 1 { "" } else { "s" },
sdists.iter().map(ToString::to_string).join(", ")
);
Builder::new(self)
.build(sdists)
.await
.context("Failed to build source distributions")?
};
let downloads = wheels.into_iter().chain(sdists).collect::<Vec<_>>();
// Unzip any downloaded distributions.
let unzips = if downloads.is_empty() {
vec![]