Add support for URL requirements in --generate-hashes (#2952)

## Summary

This PR enables hash generation for URL requirements when the user
provides `--generate-hashes` to `pip compile`. While we include the
hashes from the registry already, today, we omit hashes for URLs.

To power hash generation, we introduce a `HashPolicy` abstraction:

```rust
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HashPolicy<'a> {
    /// No hash policy is specified.
    None,
    /// Hashes should be generated (specifically, a SHA-256 hash), but not validated.
    Generate,
    /// Hashes should be validated against a pre-defined list of hashes. If necessary, hashes should
    /// be generated so as to ensure that the archive is valid.
    Validate(&'a [HashDigest]),
}
```

All of the methods on the distribution database now accept this policy,
instead of accepting `&'a [HashDigest]`.

Closes #2378.
This commit is contained in:
Charlie Marsh 2024-04-10 16:02:45 -04:00 committed by GitHub
parent 8513d603b4
commit 006379c50c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 546 additions and 495 deletions

View file

@ -21,7 +21,7 @@ use uv_configuration::{BuildKind, ConfigSettings, NoBinary, NoBuild, Reinstall,
use uv_installer::{Downloader, Installer, Plan, Planner, SitePackages};
use uv_interpreter::{Interpreter, PythonEnvironment};
use uv_resolver::{FlatIndex, InMemoryIndex, Manifest, Options, Resolver};
use uv_types::{BuildContext, BuildIsolation, EmptyInstalledPackages, InFlight, RequiredHashes};
use uv_types::{BuildContext, BuildIsolation, EmptyInstalledPackages, HashStrategy, InFlight};
/// The main implementation of [`BuildContext`], used by the CLI, see [`BuildContext`]
/// documentation.
@ -134,7 +134,6 @@ impl<'a> BuildContext for BuildDispatch<'a> {
async fn resolve<'data>(&'data self, requirements: &'data [Requirement]) -> Result<Resolution> {
let markers = self.interpreter.markers();
let tags = self.interpreter.tags()?;
let hashes = RequiredHashes::default();
let resolver = Resolver::new(
Manifest::simple(requirements.to_vec()),
self.options,
@ -144,7 +143,7 @@ impl<'a> BuildContext for BuildDispatch<'a> {
self.client,
self.flat_index,
self.index,
&hashes,
&HashStrategy::None,
self,
&EmptyInstalledPackages,
)?;
@ -178,9 +177,6 @@ impl<'a> BuildContext for BuildDispatch<'a> {
venv.root().display(),
);
// Don't enforce hashes for build dependencies.
let hashes = RequiredHashes::default();
// Determine the current environment markers.
let tags = self.interpreter.tags()?;
@ -197,7 +193,7 @@ impl<'a> BuildContext for BuildDispatch<'a> {
site_packages,
&Reinstall::None,
&NoBinary::None,
&RequiredHashes::default(),
&HashStrategy::None,
self.index_locations,
self.cache(),
venv,
@ -226,7 +222,8 @@ impl<'a> BuildContext for BuildDispatch<'a> {
vec![]
} else {
// TODO(konstin): Check that there is no endless recursion.
let downloader = Downloader::new(self.cache, tags, &hashes, self.client, self);
let downloader =
Downloader::new(self.cache, tags, &HashStrategy::None, self.client, self);
debug!(
"Downloading and building requirement{} for build: {}",
if remote.len() == 1 { "" } else { "s" },