Remove special-casing for editable requirements (#3869)

## Summary

There are a few behavior changes in here:

- We now enforce `--require-hashes` for editables, like pip. So if you
use `--require-hashes` with an editable requirement, we'll reject it. I
could change this if it seems off.
- We now treat source tree requirements, editable or not (e.g., both `-e
./black` and `./black`) as if `--refresh` is always enabled. This
doesn't mean that we _always_ rebuild them; but if you pass
`--reinstall`, then yes, we always rebuild them. I think this is an
improvement and is close to how editables work today.

Closes #3844.

Closes #2695.
This commit is contained in:
Charlie Marsh 2024-05-28 11:49:34 -04:00 committed by GitHub
parent 063a0a4384
commit 1fc6a59707
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
64 changed files with 583 additions and 1813 deletions

View file

@ -1,44 +0,0 @@
use rustc_hash::FxHashMap;
use distribution_types::{LocalEditable, Requirements};
use pypi_types::Metadata23;
use uv_normalize::PackageName;
/// A built editable for which we know its dependencies and other static metadata.
#[derive(Debug, Clone)]
pub struct BuiltEditableMetadata {
pub built: LocalEditable,
pub metadata: Metadata23,
pub requirements: Requirements,
}
/// A set of editable packages, indexed by package name.
#[derive(Debug, Default, Clone)]
pub(crate) struct Editables(FxHashMap<PackageName, BuiltEditableMetadata>);
impl Editables {
/// Create a new set of editables from a set of requirements.
pub(crate) fn from_requirements(requirements: Vec<BuiltEditableMetadata>) -> Self {
Self(
requirements
.into_iter()
.map(|editable| (editable.metadata.name.clone(), editable))
.collect(),
)
}
/// Get the editable for a package.
pub(crate) fn get(&self, name: &PackageName) -> Option<&BuiltEditableMetadata> {
self.0.get(name)
}
/// Returns `true` if the given package is editable.
pub(crate) fn contains(&self, name: &PackageName) -> bool {
self.0.contains_key(name)
}
/// Iterate over all editables.
pub(crate) fn iter(&self) -> impl Iterator<Item = &BuiltEditableMetadata> {
self.0.values()
}
}

View file

@ -1,5 +1,4 @@
pub use dependency_mode::DependencyMode;
pub use editables::BuiltEditableMetadata;
pub use error::ResolveError;
pub use exclude_newer::ExcludeNewer;
pub use exclusions::Exclusions;
@ -25,7 +24,6 @@ mod candidate_selector;
mod dependency_mode;
mod dependency_provider;
mod editables;
mod error;
mod exclude_newer;
mod exclusions;

View file

@ -6,7 +6,6 @@ use uv_configuration::{Constraints, Overrides};
use uv_normalize::PackageName;
use uv_types::RequestedRequirements;
use crate::editables::BuiltEditableMetadata;
use crate::{preferences::Preference, DependencyMode, Exclusions};
/// A manifest of requirements, constraints, and preferences.
@ -31,12 +30,6 @@ pub struct Manifest {
/// The name of the project.
pub(crate) project: Option<PackageName>,
/// The editable requirements for the project, which are built in advance.
///
/// The requirements of the editables should be included in resolution as if they were
/// direct requirements in their own right.
pub(crate) editables: Vec<BuiltEditableMetadata>,
/// The installed packages to exclude from consideration during resolution.
///
/// These typically represent packages that are being upgraded or reinstalled
@ -59,7 +52,6 @@ impl Manifest {
overrides: Overrides,
preferences: Vec<Preference>,
project: Option<PackageName>,
editables: Vec<BuiltEditableMetadata>,
exclusions: Exclusions,
lookaheads: Vec<RequestedRequirements>,
) -> Self {
@ -69,7 +61,6 @@ impl Manifest {
overrides,
preferences,
project,
editables,
exclusions,
lookaheads,
}
@ -82,7 +73,6 @@ impl Manifest {
overrides: Overrides::default(),
preferences: Vec::new(),
project: None,
editables: Vec::new(),
exclusions: Exclusions::default(),
lookaheads: Vec::new(),
}
@ -113,13 +103,6 @@ impl Manifest {
requirement.evaluate_markers(markers, lookahead.extras())
})
})
.chain(self.editables.iter().flat_map(move |editable| {
self.overrides
.apply(&editable.requirements.dependencies)
.filter(move |requirement| {
requirement.evaluate_markers(markers, &editable.built.extras)
})
}))
.chain(
self.overrides
.apply(&self.requirements)
@ -175,13 +158,6 @@ impl Manifest {
requirement.evaluate_markers(markers, lookahead.extras())
})
})
.chain(self.editables.iter().flat_map(move |editable| {
self.overrides
.apply(&editable.requirements.dependencies)
.filter(move |requirement| {
requirement.evaluate_markers(markers, &editable.built.extras)
})
}))
.chain(
self.overrides
.apply(&self.requirements)
@ -213,6 +189,6 @@ impl Manifest {
/// Returns the number of input requirements.
pub fn num_requirements(&self) -> usize {
self.requirements.len() + self.editables.len()
self.requirements.len()
}
}

View file

@ -49,11 +49,6 @@ impl PubGrubDependencies {
Ok(Self(dependencies))
}
/// Add a [`PubGrubPackage`] and [`PubGrubVersion`] range into the dependencies.
pub(crate) fn push(&mut self, package: PubGrubPackage, version: Range<Version>) {
self.0.push((package, version));
}
/// Iterate over the dependencies.
pub(crate) fn iter(&self) -> impl Iterator<Item = &(PubGrubPackage, Range<Version>)> {
self.0.iter()

View file

@ -1,4 +1,4 @@
pub(crate) use crate::pubgrub::dependencies::{PubGrubDependencies, PubGrubRequirement};
pub(crate) use crate::pubgrub::dependencies::PubGrubDependencies;
pub(crate) use crate::pubgrub::distribution::PubGrubDistribution;
pub(crate) use crate::pubgrub::package::{PubGrubPackage, PubGrubPackageInner, PubGrubPython};
pub(crate) use crate::pubgrub::priority::{PubGrubPriorities, PubGrubPriority};

View file

@ -1,15 +1,12 @@
use std::borrow::Cow;
use std::collections::BTreeSet;
use owo_colors::OwoColorize;
use petgraph::visit::EdgeRef;
use petgraph::Direction;
use distribution_types::{IndexUrl, LocalEditable, Name, SourceAnnotations, Verbatim};
use pypi_types::HashDigest;
use distribution_types::{Name, SourceAnnotations};
use uv_normalize::PackageName;
use crate::resolution::AnnotatedDist;
use crate::ResolutionGraph;
/// A [`std::fmt::Display`] implementation for the resolution graph.
@ -77,48 +74,6 @@ impl<'a> DisplayResolutionGraph<'a> {
}
}
#[derive(Debug)]
enum Node<'a> {
/// A node linked to an editable distribution.
Editable(&'a LocalEditable),
/// A node linked to a non-editable distribution.
Distribution(&'a AnnotatedDist),
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
enum NodeKey<'a> {
/// A node linked to an editable distribution, sorted by verbatim representation.
Editable(Cow<'a, str>),
/// A node linked to a non-editable distribution, sorted by package name.
Distribution(&'a PackageName),
}
impl<'a> Node<'a> {
/// Return a comparable key for the node.
fn key(&self) -> NodeKey<'a> {
match self {
Node::Editable(editable) => NodeKey::Editable(editable.verbatim()),
Node::Distribution(annotated) => NodeKey::Distribution(annotated.name()),
}
}
/// Return the [`IndexUrl`] of the distribution, if any.
fn index(&self) -> Option<&IndexUrl> {
match self {
Node::Editable(_) => None,
Node::Distribution(annotated) => annotated.dist.index(),
}
}
/// Return the hashes of the distribution.
fn hashes(&self) -> &[HashDigest] {
match self {
Node::Editable(_) => &[],
Node::Distribution(annotated) => &annotated.hashes,
}
}
}
/// Write the graph in the `{name}=={version}` format of requirements.txt that pip uses.
impl std::fmt::Display for DisplayResolutionGraph<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@ -134,32 +89,22 @@ impl std::fmt::Display for DisplayResolutionGraph<'_> {
return None;
}
let node = if let Some(editable) = self.resolution.editables.get(name) {
Node::Editable(&editable.built)
} else {
Node::Distribution(dist)
};
Some((index, node))
Some((index, dist))
})
.collect::<Vec<_>>();
// Sort the nodes by name, but with editable packages first.
nodes.sort_unstable_by_key(|(index, node)| (node.key(), *index));
nodes.sort_unstable_by_key(|(index, node)| (node.to_comparator(), *index));
// Print out the dependency graph.
for (index, node) in nodes {
// Display the node itself.
let mut line = match node {
Node::Editable(editable) => format!("-e {}", editable.verbatim()),
Node::Distribution(dist) => {
dist.to_requirements_txt(self.include_extras).to_string()
}
};
let mut line = node.to_requirements_txt(self.include_extras).to_string();
// Display the distribution hashes, if any.
let mut has_hashes = false;
if self.show_hashes {
for hash in node.hashes() {
for hash in &node.hashes {
has_hashes = true;
line.push_str(" \\\n");
line.push_str(" --hash=");
@ -184,12 +129,7 @@ impl std::fmt::Display for DisplayResolutionGraph<'_> {
// Include all external sources (e.g., requirements files).
let default = BTreeSet::default();
let source = match node {
Node::Editable(editable) => {
self.sources.get_editable(&editable.url).unwrap_or(&default)
}
Node::Distribution(dist) => self.sources.get(dist.name()).unwrap_or(&default),
};
let source = self.sources.get(node.name()).unwrap_or(&default);
match self.annotation_style {
AnnotationStyle::Line => match edges.as_slice() {
@ -261,7 +201,7 @@ impl std::fmt::Display for DisplayResolutionGraph<'_> {
// If enabled, include indexes to indicate which index was used for each package (e.g.,
// `# from https://pypi.org/simple`).
if self.include_index_annotation {
if let Some(index) = node.index() {
if let Some(index) = node.dist.index() {
let url = index.redacted();
writeln!(f, "{}", format!(" # from {url}").green())?;
}

View file

@ -16,7 +16,6 @@ use pypi_types::{ParsedUrlError, Yanked};
use uv_normalize::PackageName;
use crate::dependency_provider::UvDependencyProvider;
use crate::editables::Editables;
use crate::pins::FilePins;
use crate::preferences::Preferences;
use crate::pubgrub::{PubGrubDistribution, PubGrubPackageInner};
@ -34,8 +33,6 @@ use crate::{
pub struct ResolutionGraph {
/// The underlying graph.
pub(crate) petgraph: petgraph::graph::Graph<AnnotatedDist, Range<Version>, petgraph::Directed>,
/// The set of editable requirements in this resolution.
pub(crate) editables: Editables,
/// Any diagnostics that were encountered while building the graph.
pub(crate) diagnostics: Vec<ResolutionDiagnostic>,
}
@ -50,7 +47,6 @@ impl ResolutionGraph {
distributions: &FxOnceMap<VersionId, Arc<MetadataResponse>>,
state: &State<UvDependencyProvider>,
preferences: &Preferences,
editables: Editables,
) -> anyhow::Result<Self, ResolveError> {
// Collect and validate the extras.
let mut extras = FxHashMap::default();
@ -102,50 +98,34 @@ impl ResolutionGraph {
marker: None,
url: Some(url),
} => {
if let Some(editable) = editables.get(name) {
if editable.metadata.provides_extras.contains(extra) {
extras
.entry(name.clone())
.or_insert_with(Vec::new)
.push(extra.clone());
} else {
let dist = Dist::from_editable(name.clone(), editable.built.clone())?;
let dist = PubGrubDistribution::from_url(name, url);
diagnostics.push(ResolutionDiagnostic::MissingExtra {
dist: dist.into(),
extra: extra.clone(),
});
}
let response = distributions.get(&dist.version_id()).unwrap_or_else(|| {
panic!(
"Every package should have metadata: {:?}",
dist.version_id()
)
});
let MetadataResponse::Found(archive) = &*response else {
panic!(
"Every package should have metadata: {:?}",
dist.version_id()
)
};
if archive.metadata.provides_extras.contains(extra) {
extras
.entry(name.clone())
.or_insert_with(Vec::new)
.push(extra.clone());
} else {
let dist = PubGrubDistribution::from_url(name, url);
let dist = Dist::from_url(name.clone(), url_to_precise(url.clone()))?;
let response = distributions.get(&dist.version_id()).unwrap_or_else(|| {
panic!(
"Every package should have metadata: {:?}",
dist.version_id()
)
diagnostics.push(ResolutionDiagnostic::MissingExtra {
dist: dist.into(),
extra: extra.clone(),
});
let MetadataResponse::Found(archive) = &*response else {
panic!(
"Every package should have metadata: {:?}",
dist.version_id()
)
};
if archive.metadata.provides_extras.contains(extra) {
extras
.entry(name.clone())
.or_insert_with(Vec::new)
.push(extra.clone());
} else {
let dist = Dist::from_url(name.clone(), url_to_precise(url.clone()))?;
diagnostics.push(ResolutionDiagnostic::MissingExtra {
dist: dist.into(),
extra: extra.clone(),
});
}
}
}
_ => {}
@ -254,75 +234,60 @@ impl ResolutionGraph {
url: Some(url),
} => {
// Create the distribution.
if let Some(editable) = editables.get(name) {
let dist = Dist::from_editable(name.clone(), editable.built.clone())?;
// Add the distribution to the graph.
let index = petgraph.add_node(AnnotatedDist {
dist: dist.into(),
extras: editable.built.extras.clone(),
hashes: vec![],
metadata: editable.metadata.clone(),
});
inverse.insert(name, index);
} else {
let dist = Dist::from_url(name.clone(), url_to_precise(url.clone()))?;
let dist = Dist::from_url(name.clone(), url_to_precise(url.clone()))?;
// Extract the hashes, preserving those that were already present in the
// lockfile if necessary.
let hashes = if let Some(digests) = preferences
.match_hashes(name, version)
.filter(|digests| !digests.is_empty())
{
digests.to_vec()
} else if let Some(metadata_response) =
distributions.get(&dist.version_id())
{
if let MetadataResponse::Found(ref archive) = *metadata_response {
let mut digests = archive.hashes.clone();
digests.sort_unstable();
digests
} else {
vec![]
}
// Extract the hashes, preserving those that were already present in the
// lockfile if necessary.
let hashes = if let Some(digests) = preferences
.match_hashes(name, version)
.filter(|digests| !digests.is_empty())
{
digests.to_vec()
} else if let Some(metadata_response) = distributions.get(&dist.version_id()) {
if let MetadataResponse::Found(ref archive) = *metadata_response {
let mut digests = archive.hashes.clone();
digests.sort_unstable();
digests
} else {
vec![]
};
// Extract the metadata.
let metadata = {
let dist = PubGrubDistribution::from_url(name, url);
let response =
distributions.get(&dist.version_id()).unwrap_or_else(|| {
panic!(
"Every package should have metadata: {:?}",
dist.version_id()
)
});
let MetadataResponse::Found(archive) = &*response else {
panic!(
"Every package should have metadata: {:?}",
dist.version_id()
)
};
archive.metadata.clone()
};
// Extract the extras.
let extras = extras.get(name).cloned().unwrap_or_default();
// Add the distribution to the graph.
let index = petgraph.add_node(AnnotatedDist {
dist: dist.into(),
extras,
hashes,
metadata,
});
inverse.insert(name, index);
}
} else {
vec![]
};
// Extract the metadata.
let metadata = {
let dist = PubGrubDistribution::from_url(name, url);
let response = distributions.get(&dist.version_id()).unwrap_or_else(|| {
panic!(
"Every package should have metadata: {:?}",
dist.version_id()
)
});
let MetadataResponse::Found(archive) = &*response else {
panic!(
"Every package should have metadata: {:?}",
dist.version_id()
)
};
archive.metadata.clone()
};
// Extract the extras.
let extras = extras.get(name).cloned().unwrap_or_default();
// Add the distribution to the graph.
let index = petgraph.add_node(AnnotatedDist {
dist: dist.into(),
extras,
hashes,
metadata,
});
inverse.insert(name, index);
}
_ => {}
};
@ -380,7 +345,6 @@ impl ResolutionGraph {
Ok(Self {
petgraph,
editables,
diagnostics,
})
}
@ -523,13 +487,7 @@ impl ResolutionGraph {
}
// Ensure that we consider markers from direct dependencies.
let direct_reqs = manifest.requirements.iter().chain(
manifest
.editables
.iter()
.flat_map(|editable| &editable.requirements.dependencies),
);
for direct_req in manifest.apply(direct_reqs) {
for direct_req in manifest.apply(manifest.requirements.iter()) {
let Some(ref marker_tree) = direct_req.marker else {
continue;
};

View file

@ -34,6 +34,14 @@ impl AnnotatedDist {
/// unnamed requirement for relative paths, which can't be represented with PEP 508 (but are
/// supported in `requirements.txt`).
pub(crate) fn to_requirements_txt(&self, include_extras: bool) -> Cow<str> {
// If the URL is editable, write it as an editable requirement.
if self.dist.is_editable() {
if let VersionOrUrlRef::Url(url) = self.dist.version_or_url() {
let given = url.verbatim();
return Cow::Owned(format!("-e {given}"));
}
}
// If the URL is not _definitively_ an absolute `file://` URL, write it as a relative path.
if self.dist.is_local() {
if let VersionOrUrlRef::Url(url) = self.dist.version_or_url() {
@ -94,6 +102,22 @@ impl AnnotatedDist {
))
}
}
pub(crate) fn to_comparator(&self) -> RequirementsTxtComparator {
if self.dist.is_editable() {
if let VersionOrUrlRef::Url(url) = self.dist.version_or_url() {
return RequirementsTxtComparator::Url(url.verbatim());
}
}
RequirementsTxtComparator::Name(self.name())
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) enum RequirementsTxtComparator<'a> {
Url(Cow<'a, str>),
Name(&'a PackageName),
}
impl Name for AnnotatedDist {

View file

@ -37,14 +37,13 @@ use uv_types::{BuildContext, HashStrategy, InstalledPackagesProvider};
use crate::candidate_selector::{CandidateDist, CandidateSelector};
use crate::dependency_provider::UvDependencyProvider;
use crate::editables::Editables;
use crate::error::ResolveError;
use crate::manifest::Manifest;
use crate::pins::FilePins;
use crate::preferences::Preferences;
use crate::pubgrub::{
PubGrubDependencies, PubGrubDistribution, PubGrubPackage, PubGrubPackageInner,
PubGrubPriorities, PubGrubPython, PubGrubRequirement, PubGrubSpecifier,
PubGrubPriorities, PubGrubPython, PubGrubSpecifier,
};
use crate::python_requirement::PythonRequirement;
use crate::resolution::ResolutionGraph;
@ -85,7 +84,6 @@ struct ResolverState<InstalledPackages: InstalledPackagesProvider> {
overrides: Overrides,
preferences: Preferences,
exclusions: Exclusions,
editables: Editables,
urls: Urls,
locals: Locals,
dependency_mode: DependencyMode,
@ -192,7 +190,6 @@ impl<Provider: ResolverProvider, InstalledPackages: InstalledPackagesProvider>
overrides: manifest.overrides,
preferences: Preferences::from_iter(manifest.preferences, markers),
exclusions: manifest.exclusions,
editables: Editables::from_requirements(manifest.editables),
hasher: hasher.clone(),
markers: markers.cloned(),
python_requirement: python_requirement.clone(),
@ -343,7 +340,6 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
self.index.distributions(),
&state.pubgrub,
&self.preferences,
self.editables.clone(),
);
};
state.next = highest_priority_pkg;
@ -560,11 +556,6 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
return Err(ResolveError::UnhashedPackage(name.clone()));
}
// If the package is an editable, we don't need to fetch metadata.
if self.editables.contains(name) {
return Ok(());
}
// Emit a request to fetch the metadata for this distribution.
let dist = Dist::from_url(name.clone(), url.clone())?;
if self.index.distributions().register(dist.version_id()) {
@ -649,31 +640,6 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
url.verbatim
);
// If the dist is an editable, return the version from the editable metadata.
if let Some(editable) = self.editables.get(name) {
let version = &editable.metadata.version;
// The version is incompatible with the requirement.
if !range.contains(version) {
return Ok(None);
}
// The version is incompatible due to its Python requirement.
if let Some(requires_python) = editable.metadata.requires_python.as_ref() {
let target = self.python_requirement.target();
if !requires_python.contains(target) {
return Ok(Some(ResolverVersion::Unavailable(
version.clone(),
UnavailableVersion::IncompatibleDist(IncompatibleDist::Source(
IncompatibleSource::RequiresPython(requires_python.clone()),
)),
)));
}
}
return Ok(Some(ResolverVersion::Available(version.clone())));
}
let dist = PubGrubDistribution::from_url(name, url);
let response = self
.index
@ -853,7 +819,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
self.markers.as_ref(),
);
let mut dependencies = match dependencies {
let dependencies = match dependencies {
Ok(dependencies) => dependencies,
Err(err) => {
return Ok(Dependencies::Unavailable(
@ -872,54 +838,6 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
self.visit_package(package, request_sink)?;
}
// Add a dependency on each editable.
for editable in self.editables.iter() {
let package = PubGrubPackage::from_package(
editable.metadata.name.clone(),
None,
None,
&self.urls,
);
let version = Range::singleton(editable.metadata.version.clone());
// Update the package priorities.
priorities.insert(&package, &version);
// Add the editable as a direct dependency.
dependencies.push(package, version);
// Add a dependency on each extra.
for extra in &editable.built.extras {
dependencies.push(
PubGrubPackage::from_package(
editable.metadata.name.clone(),
Some(extra.clone()),
None,
&self.urls,
),
Range::singleton(editable.metadata.version.clone()),
);
}
// Add any constraints.
for constraint in self
.constraints
.get(&editable.metadata.name)
.into_iter()
.flatten()
{
if constraint.evaluate_markers(self.markers.as_ref(), &[]) {
let PubGrubRequirement { package, version } =
PubGrubRequirement::from_constraint(
constraint,
&self.urls,
&self.locals,
)?;
dependencies.push(package, version);
}
}
}
Ok(Dependencies::Available(dependencies.into()))
}
@ -935,57 +853,22 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
if self.dependency_mode.is_direct() {
// If an extra is provided, wait for the metadata to be available, since it's
// still required for generating the lock file.
if !self.editables.contains(name) {
// Determine the distribution to lookup.
let dist = match url {
Some(url) => PubGrubDistribution::from_url(name, url),
None => PubGrubDistribution::from_registry(name, version),
};
let version_id = dist.version_id();
// Wait for the metadata to be available.
self.index
.distributions()
.wait_blocking(&version_id)
.ok_or(ResolveError::Unregistered)?;
}
let dist = match url {
Some(url) => PubGrubDistribution::from_url(name, url),
None => PubGrubDistribution::from_registry(name, version),
};
let version_id = dist.version_id();
// Wait for the metadata to be available.
self.index
.distributions()
.wait_blocking(&version_id)
.ok_or(ResolveError::Unregistered)?;
return Ok(Dependencies::Available(Vec::default()));
}
// Determine if the distribution is editable.
if let Some(editable) = self.editables.get(name) {
let requirements: Vec<_> = editable
.metadata
.requires_dist
.iter()
.cloned()
.map(Requirement::from)
.collect();
let dependencies = PubGrubDependencies::from_requirements(
&requirements,
&self.constraints,
&self.overrides,
Some(name),
extra.as_ref(),
&self.urls,
&self.locals,
self.markers.as_ref(),
)?;
for (dep_package, dep_version) in dependencies.iter() {
debug!("Adding transitive dependency for {package}=={version}: {dep_package}{dep_version}");
// Update the package priorities.
priorities.insert(dep_package, dep_version);
// Emit a request to fetch the metadata for this package.
self.visit_package(dep_package, request_sink)?;
}
return Ok(Dependencies::Available(dependencies.into()));
}
// Determine the distribution to lookup.
let dist = match url {
Some(url) => PubGrubDistribution::from_url(name, url),
@ -1232,6 +1115,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
ResolveError::FetchAndBuild(Box::new(source_dist), err)
}
})?;
Ok(Some(Response::Dist { dist, metadata }))
}
@ -1320,6 +1204,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
ResolveError::FetchAndBuild(Box::new(source_dist), err)
}
})?;
Response::Dist { dist, metadata }
}
ResolvedDist::Installed(dist) => {

View file

@ -22,36 +22,6 @@ impl Urls {
) -> Result<Self, ResolveError> {
let mut urls: FxHashMap<PackageName, VerbatimParsedUrl> = FxHashMap::default();
// Add the editables themselves to the list of required URLs.
for editable in &manifest.editables {
let editable_url = VerbatimParsedUrl {
parsed_url: ParsedUrl::Path(ParsedPathUrl {
url: editable.built.url.to_url(),
path: editable.built.path.clone(),
editable: true,
}),
verbatim: editable.built.url.clone(),
};
if let Some(previous) =
urls.insert(editable.metadata.name.clone(), editable_url.clone())
{
if !is_equal(&previous.verbatim, &editable_url.verbatim) {
if is_same_reference(&previous.verbatim, &editable_url.verbatim) {
debug!(
"Allowing {} as a variant of {}",
editable_url.verbatim, previous.verbatim
);
} else {
return Err(ResolveError::ConflictingUrlsDirect(
editable.metadata.name.clone(),
previous.verbatim.verbatim().to_string(),
editable_url.verbatim.verbatim().to_string(),
));
}
}
}
}
// Add all direct requirements and constraints. If there are any conflicts, return an error.
for requirement in manifest.requirements(markers, dependencies) {
match &requirement.source {