mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-03 10:33:49 +00:00
Add forks to lockfile, don't read them yet (#5480)
Add the forks to the lockfile, without using them yet, which we'll add in the next PR. Please review commit-by-commit Part of https://github.com/astral-sh/uv/issues/5180#issuecomment-2247696198
This commit is contained in:
parent
228a803fde
commit
dedd913603
24 changed files with 533 additions and 76 deletions
|
@ -131,7 +131,7 @@ pub struct NoSolutionError {
|
|||
impl NoSolutionError {
|
||||
pub fn header(&self) -> String {
|
||||
match &self.markers {
|
||||
ResolverMarkers::Universal | ResolverMarkers::SpecificEnvironment(_) => {
|
||||
ResolverMarkers::Universal { .. } | ResolverMarkers::SpecificEnvironment(_) => {
|
||||
"No solution found when resolving dependencies:".to_string()
|
||||
}
|
||||
ResolverMarkers::Fork(markers) => {
|
||||
|
|
|
@ -40,7 +40,8 @@ impl ForkUrls {
|
|||
];
|
||||
conflicting_url.sort();
|
||||
return match fork_markers {
|
||||
ResolverMarkers::Universal | ResolverMarkers::SpecificEnvironment(_) => {
|
||||
ResolverMarkers::Universal { .. }
|
||||
| ResolverMarkers::SpecificEnvironment(_) => {
|
||||
Err(ResolveError::ConflictingUrlsUniversal(
|
||||
package_name.clone(),
|
||||
conflicting_url,
|
||||
|
|
|
@ -20,10 +20,10 @@ use cache_key::RepositoryUrl;
|
|||
use distribution_filename::WheelFilename;
|
||||
use distribution_types::{
|
||||
BuiltDist, DirectUrlBuiltDist, DirectUrlSourceDist, DirectorySourceDist, Dist,
|
||||
DistributionMetadata, FileLocation, GitSourceDist, HashComparison, IndexUrl, PathBuiltDist,
|
||||
PathSourceDist, PrioritizedDist, RegistryBuiltDist, RegistryBuiltWheel, RegistrySourceDist,
|
||||
RemoteSource, Resolution, ResolvedDist, SourceDistCompatibility, ToUrlError, UrlString,
|
||||
VersionId, WheelCompatibility,
|
||||
DistributionMetadata, FileLocation, GitSourceDist, HashComparison, IndexUrl, Name,
|
||||
PathBuiltDist, PathSourceDist, PrioritizedDist, RegistryBuiltDist, RegistryBuiltWheel,
|
||||
RegistrySourceDist, RemoteSource, Resolution, ResolvedDist, SourceDistCompatibility,
|
||||
ToUrlError, UrlString, VersionId, WheelCompatibility,
|
||||
};
|
||||
use pep440_rs::{Version, VersionSpecifier};
|
||||
use pep508_rs::{
|
||||
|
@ -53,7 +53,10 @@ const VERSION: u32 = 1;
|
|||
#[serde(try_from = "LockWire")]
|
||||
pub struct Lock {
|
||||
version: u32,
|
||||
distributions: Vec<Distribution>,
|
||||
/// If this lockfile was built from a forking resolution with non-identical forks, store the
|
||||
/// forks in the lockfile so we can recreate them in subsequent resolutions.
|
||||
#[serde(rename = "environment-markers")]
|
||||
fork_markers: Option<BTreeSet<MarkerTree>>,
|
||||
/// The range of supported Python versions.
|
||||
requires_python: Option<RequiresPython>,
|
||||
/// The [`ResolutionMode`] used to generate this lock.
|
||||
|
@ -62,6 +65,8 @@ pub struct Lock {
|
|||
prerelease_mode: PreReleaseMode,
|
||||
/// The [`ExcludeNewer`] used to generate this lock.
|
||||
exclude_newer: Option<ExcludeNewer>,
|
||||
/// The actual locked version and their metadata.
|
||||
distributions: Vec<Distribution>,
|
||||
/// A map from distribution ID to index in `distributions`.
|
||||
///
|
||||
/// This can be used to quickly lookup the full distribution for any ID
|
||||
|
@ -87,7 +92,12 @@ impl Lock {
|
|||
continue;
|
||||
};
|
||||
if dist.is_base() {
|
||||
let mut locked_dist = Distribution::from_annotated_dist(dist)?;
|
||||
let fork_markers = graph
|
||||
.fork_markers(dist.name(), &dist.version, dist.dist.version_or_url().url())
|
||||
.cloned();
|
||||
let mut locked_dist = Distribution::from_annotated_dist(dist, fork_markers)?;
|
||||
|
||||
// Add all dependencies
|
||||
for edge in graph.petgraph.edges(node_index) {
|
||||
let ResolutionGraphNode::Dist(dependency_dist) = &graph.petgraph[edge.target()]
|
||||
else {
|
||||
|
@ -159,6 +169,7 @@ impl Lock {
|
|||
options.resolution_mode,
|
||||
options.prerelease_mode,
|
||||
options.exclude_newer,
|
||||
graph.fork_markers.clone(),
|
||||
)?;
|
||||
Ok(lock)
|
||||
}
|
||||
|
@ -171,6 +182,7 @@ impl Lock {
|
|||
resolution_mode: ResolutionMode,
|
||||
prerelease_mode: PreReleaseMode,
|
||||
exclude_newer: Option<ExcludeNewer>,
|
||||
fork_markers: Option<BTreeSet<MarkerTree>>,
|
||||
) -> Result<Self, LockError> {
|
||||
// Put all dependencies for each distribution in a canonical order and
|
||||
// check for duplicates.
|
||||
|
@ -324,11 +336,12 @@ impl Lock {
|
|||
}
|
||||
Ok(Self {
|
||||
version,
|
||||
distributions,
|
||||
fork_markers,
|
||||
requires_python,
|
||||
resolution_mode,
|
||||
prerelease_mode,
|
||||
exclude_newer,
|
||||
distributions,
|
||||
by_id,
|
||||
})
|
||||
}
|
||||
|
@ -363,6 +376,12 @@ impl Lock {
|
|||
self.exclude_newer
|
||||
}
|
||||
|
||||
/// If this lockfile was built from a forking resolution with non-identical forks, return the
|
||||
/// markers of those forks, otherwise `None`.
|
||||
pub fn fork_markers(&self) -> &Option<BTreeSet<MarkerTree>> {
|
||||
&self.fork_markers
|
||||
}
|
||||
|
||||
/// Convert the [`Lock`] to a [`Resolution`] using the given marker environment, tags, and root.
|
||||
pub fn to_resolution(
|
||||
&self,
|
||||
|
@ -451,6 +470,11 @@ impl Lock {
|
|||
if let Some(ref requires_python) = self.requires_python {
|
||||
doc.insert("requires-python", value(requires_python.to_string()));
|
||||
}
|
||||
if let Some(ref fork_markers) = self.fork_markers {
|
||||
let fork_markers =
|
||||
each_element_on_its_line_array(fork_markers.iter().map(ToString::to_string));
|
||||
doc.insert("environment-markers", value(fork_markers));
|
||||
}
|
||||
|
||||
// Write the settings that were used to generate the resolution.
|
||||
// This enables us to invalidate the lockfile if the user changes
|
||||
|
@ -571,31 +595,36 @@ impl Lock {
|
|||
#[serde(rename_all = "kebab-case")]
|
||||
struct LockWire {
|
||||
version: u32,
|
||||
#[serde(rename = "distribution", default)]
|
||||
distributions: Vec<DistributionWire>,
|
||||
#[serde(default)]
|
||||
requires_python: Option<RequiresPython>,
|
||||
/// If this lockfile was built from a forking resolution with non-identical forks, store the
|
||||
/// forks in the lockfile so we can recreate them in subsequent resolutions.
|
||||
#[serde(rename = "environment-markers")]
|
||||
fork_markers: Option<BTreeSet<MarkerTree>>,
|
||||
#[serde(default)]
|
||||
resolution_mode: ResolutionMode,
|
||||
#[serde(default)]
|
||||
prerelease_mode: PreReleaseMode,
|
||||
#[serde(default)]
|
||||
exclude_newer: Option<ExcludeNewer>,
|
||||
#[serde(rename = "distribution", default)]
|
||||
distributions: Vec<DistributionWire>,
|
||||
}
|
||||
|
||||
impl From<Lock> for LockWire {
|
||||
fn from(lock: Lock) -> LockWire {
|
||||
LockWire {
|
||||
version: lock.version,
|
||||
requires_python: lock.requires_python,
|
||||
fork_markers: lock.fork_markers,
|
||||
resolution_mode: lock.resolution_mode,
|
||||
prerelease_mode: lock.prerelease_mode,
|
||||
exclude_newer: lock.exclude_newer,
|
||||
distributions: lock
|
||||
.distributions
|
||||
.into_iter()
|
||||
.map(DistributionWire::from)
|
||||
.collect(),
|
||||
requires_python: lock.requires_python,
|
||||
resolution_mode: lock.resolution_mode,
|
||||
prerelease_mode: lock.prerelease_mode,
|
||||
exclude_newer: lock.exclude_newer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -633,6 +662,7 @@ impl TryFrom<LockWire> for Lock {
|
|||
wire.resolution_mode,
|
||||
wire.prerelease_mode,
|
||||
wire.exclude_newer,
|
||||
wire.fork_markers,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -642,13 +672,22 @@ pub struct Distribution {
|
|||
pub(crate) id: DistributionId,
|
||||
sdist: Option<SourceDist>,
|
||||
wheels: Vec<Wheel>,
|
||||
/// If there are multiple distributions for the same package name, we add the markers of the
|
||||
/// fork(s) that contained this distribution, so we can set the correct preferences in the next
|
||||
/// resolution.
|
||||
///
|
||||
/// Named `environment-markers` in `uv.lock`.
|
||||
fork_markers: Option<BTreeSet<MarkerTree>>,
|
||||
dependencies: Vec<Dependency>,
|
||||
optional_dependencies: BTreeMap<ExtraName, Vec<Dependency>>,
|
||||
dev_dependencies: BTreeMap<GroupName, Vec<Dependency>>,
|
||||
}
|
||||
|
||||
impl Distribution {
|
||||
fn from_annotated_dist(annotated_dist: &AnnotatedDist) -> Result<Self, LockError> {
|
||||
fn from_annotated_dist(
|
||||
annotated_dist: &AnnotatedDist,
|
||||
fork_markers: Option<BTreeSet<MarkerTree>>,
|
||||
) -> Result<Self, LockError> {
|
||||
let id = DistributionId::from_annotated_dist(annotated_dist);
|
||||
let sdist = SourceDist::from_annotated_dist(&id, annotated_dist)?;
|
||||
let wheels = Wheel::from_annotated_dist(annotated_dist)?;
|
||||
|
@ -656,6 +695,7 @@ impl Distribution {
|
|||
id,
|
||||
sdist,
|
||||
wheels,
|
||||
fork_markers,
|
||||
dependencies: vec![],
|
||||
optional_dependencies: BTreeMap::default(),
|
||||
dev_dependencies: BTreeMap::default(),
|
||||
|
@ -1005,6 +1045,12 @@ impl Distribution {
|
|||
|
||||
self.id.to_toml(None, &mut table);
|
||||
|
||||
if let Some(ref fork_markers) = self.fork_markers {
|
||||
let wheels =
|
||||
each_element_on_its_line_array(fork_markers.iter().map(ToString::to_string));
|
||||
table.insert("environment-markers", value(wheels));
|
||||
}
|
||||
|
||||
if !self.dependencies.is_empty() {
|
||||
let deps = each_element_on_its_line_array(
|
||||
self.dependencies
|
||||
|
@ -1145,6 +1191,8 @@ struct DistributionWire {
|
|||
sdist: Option<SourceDist>,
|
||||
#[serde(default)]
|
||||
wheels: Vec<Wheel>,
|
||||
#[serde(default, rename = "environment-markers")]
|
||||
fork_markers: BTreeSet<MarkerTree>,
|
||||
#[serde(default)]
|
||||
dependencies: Vec<DependencyWire>,
|
||||
#[serde(default)]
|
||||
|
@ -1167,6 +1215,7 @@ impl DistributionWire {
|
|||
id: self.id,
|
||||
sdist: self.sdist,
|
||||
wheels: self.wheels,
|
||||
fork_markers: (!self.fork_markers.is_empty()).then_some(self.fork_markers),
|
||||
dependencies: unwire_deps(self.dependencies)?,
|
||||
optional_dependencies: self
|
||||
.optional_dependencies
|
||||
|
@ -1191,6 +1240,7 @@ impl From<Distribution> for DistributionWire {
|
|||
id: dist.id,
|
||||
sdist: dist.sdist,
|
||||
wheels: dist.wheels,
|
||||
fork_markers: dist.fork_markers.unwrap_or_default(),
|
||||
dependencies: wire_deps(dist.dependencies),
|
||||
optional_dependencies: dist
|
||||
.optional_dependencies
|
||||
|
@ -2546,12 +2596,13 @@ impl std::fmt::Display for HashParseError {
|
|||
/// { name = "sniffio" },
|
||||
/// ]
|
||||
/// ```
|
||||
fn each_element_on_its_line_array(elements: impl Iterator<Item = InlineTable>) -> Array {
|
||||
fn each_element_on_its_line_array(elements: impl Iterator<Item = impl Into<Value>>) -> Array {
|
||||
let mut array = elements
|
||||
.map(|mut inline_table| {
|
||||
.map(|item| {
|
||||
let mut value = item.into();
|
||||
// Each dependency is on its own line and indented.
|
||||
inline_table.decor_mut().set_prefix("\n ");
|
||||
inline_table
|
||||
value.decor_mut().set_prefix("\n ");
|
||||
value
|
||||
})
|
||||
.collect::<Array>();
|
||||
// With a trailing comma, inserting another entry doesn't change the preceding line,
|
||||
|
|
|
@ -13,7 +13,9 @@ use uv_normalize::PackageName;
|
|||
use crate::resolution::{RequirementsTxtDist, ResolutionGraphNode};
|
||||
use crate::{marker, ResolutionGraph, ResolverMarkers};
|
||||
|
||||
static UNIVERSAL_MARKERS: ResolverMarkers = ResolverMarkers::Universal;
|
||||
static UNIVERSAL_MARKERS: ResolverMarkers = ResolverMarkers::Universal {
|
||||
fork_preferences: None,
|
||||
};
|
||||
|
||||
/// A [`std::fmt::Display`] implementation for the resolution graph.
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::collections::BTreeSet;
|
||||
|
||||
use indexmap::IndexSet;
|
||||
use petgraph::{
|
||||
graph::{Graph, NodeIndex},
|
||||
|
@ -10,7 +12,7 @@ use distribution_types::{
|
|||
VersionOrUrlRef,
|
||||
};
|
||||
use pep440_rs::{Version, VersionSpecifier};
|
||||
use pep508_rs::{MarkerEnvironment, MarkerTree};
|
||||
use pep508_rs::{MarkerEnvironment, MarkerTree, VerbatimUrl};
|
||||
use pypi_types::{HashDigest, ParsedUrlError, Requirement, VerbatimParsedUrl, Yanked};
|
||||
use uv_configuration::{Constraints, Overrides};
|
||||
use uv_distribution::Metadata;
|
||||
|
@ -25,9 +27,12 @@ use crate::resolution::AnnotatedDist;
|
|||
use crate::resolver::{Resolution, ResolutionDependencyEdge, ResolutionPackage};
|
||||
use crate::{
|
||||
InMemoryIndex, MetadataResponse, Options, PythonRequirement, RequiresPython, ResolveError,
|
||||
VersionsResponse,
|
||||
ResolverMarkers, VersionsResponse,
|
||||
};
|
||||
|
||||
pub(crate) type MarkersForDistribution =
|
||||
FxHashMap<(Version, Option<VerbatimUrl>), BTreeSet<MarkerTree>>;
|
||||
|
||||
/// A complete resolution graph in which every node represents a pinned package and every edge
|
||||
/// represents a dependency between two pinned packages.
|
||||
#[derive(Debug)]
|
||||
|
@ -36,6 +41,9 @@ pub struct ResolutionGraph {
|
|||
pub(crate) petgraph: Graph<ResolutionGraphNode, Option<MarkerTree>, Directed>,
|
||||
/// The range of supported Python versions.
|
||||
pub(crate) requires_python: Option<RequiresPython>,
|
||||
/// If the resolution had non-identical forks, store the forks in the lockfile so we can
|
||||
/// recreate them in subsequent resolutions.
|
||||
pub(crate) fork_markers: Option<BTreeSet<MarkerTree>>,
|
||||
/// Any diagnostics that were encountered while building the graph.
|
||||
pub(crate) diagnostics: Vec<ResolutionDiagnostic>,
|
||||
/// The requirements that were used to build the graph.
|
||||
|
@ -46,6 +54,9 @@ pub struct ResolutionGraph {
|
|||
pub(crate) overrides: Overrides,
|
||||
/// The options that were used to build the graph.
|
||||
pub(crate) options: Options,
|
||||
/// If there are multiple options for a package, track which fork they belong to so we
|
||||
/// can write that to the lockfile and later get the correct preference per fork back.
|
||||
pub(crate) package_markers: FxHashMap<PackageName, MarkersForDistribution>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -86,10 +97,28 @@ impl ResolutionGraph {
|
|||
// Add the root node.
|
||||
let root_index = petgraph.add_node(ResolutionGraphNode::Root);
|
||||
|
||||
let mut package_markers: FxHashMap<PackageName, MarkersForDistribution> =
|
||||
FxHashMap::default();
|
||||
|
||||
let mut seen = FxHashSet::default();
|
||||
for resolution in resolutions {
|
||||
// Add every package to the graph.
|
||||
for (package, version) in &resolution.nodes {
|
||||
if package.is_base() {
|
||||
// For packages with diverging versions, store which version comes from which
|
||||
// fork.
|
||||
if let Some(markers) = resolution.markers.fork_markers() {
|
||||
let entry = package_markers
|
||||
.entry(package.name.clone())
|
||||
.or_default()
|
||||
.entry((version.clone(), package.url.clone().map(|url| url.verbatim)))
|
||||
.or_default();
|
||||
if !entry.contains(markers) {
|
||||
entry.insert(markers.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !seen.insert((package, version)) {
|
||||
// Insert each node only once.
|
||||
continue;
|
||||
|
@ -138,14 +167,38 @@ impl ResolutionGraph {
|
|||
}
|
||||
}
|
||||
|
||||
let fork_markers = if let [resolution] = resolutions {
|
||||
match resolution.markers {
|
||||
ResolverMarkers::Universal { .. } | ResolverMarkers::SpecificEnvironment(_) => None,
|
||||
ResolverMarkers::Fork(_) => {
|
||||
panic!("A single fork must be universal");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Some(
|
||||
resolutions
|
||||
.iter()
|
||||
.map(|resolution| {
|
||||
resolution
|
||||
.markers
|
||||
.fork_markers()
|
||||
.expect("A non-forking resolution exists in forking mode")
|
||||
.clone()
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
petgraph,
|
||||
requires_python,
|
||||
package_markers,
|
||||
diagnostics,
|
||||
requirements: requirements.to_vec(),
|
||||
constraints: constraints.clone(),
|
||||
overrides: overrides.clone(),
|
||||
options,
|
||||
fork_markers,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -549,6 +602,22 @@ impl ResolutionGraph {
|
|||
}
|
||||
Ok(MarkerTree::And(conjuncts))
|
||||
}
|
||||
|
||||
/// If there are multiple distributions for the same package name, return the markers of the
|
||||
/// fork(s) that contained this distribution, otherwise return `None`.
|
||||
pub fn fork_markers(
|
||||
&self,
|
||||
package_name: &PackageName,
|
||||
version: &Version,
|
||||
url: Option<&VerbatimUrl>,
|
||||
) -> Option<&BTreeSet<MarkerTree>> {
|
||||
let package_markers = &self.package_markers.get(package_name)?;
|
||||
if package_markers.len() == 1 {
|
||||
None
|
||||
} else {
|
||||
Some(&package_markers[&(version.clone(), url.cloned())])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ResolutionGraph> for distribution_types::Resolution {
|
||||
|
|
|
@ -78,7 +78,7 @@ impl<T> ForkMap<T> {
|
|||
.collect(),
|
||||
|
||||
// If we haven't forked yet, all values are potentially compatible.
|
||||
ResolverMarkers::Universal => values.iter().map(|entry| &entry.value).collect(),
|
||||
ResolverMarkers::Universal { .. } => values.iter().map(|entry| &entry.value).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -403,7 +403,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
|
|||
.clone());
|
||||
existing_resolution.markers = normalize(new_markers, None)
|
||||
.map(ResolverMarkers::Fork)
|
||||
.unwrap_or(ResolverMarkers::Universal);
|
||||
.unwrap_or(ResolverMarkers::universal(None));
|
||||
continue 'FORK;
|
||||
}
|
||||
|
||||
|
@ -1155,7 +1155,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
|
|||
Dependencies::Available(deps) => ForkedDependencies::Unforked(deps),
|
||||
Dependencies::Unavailable(err) => ForkedDependencies::Unavailable(err),
|
||||
}),
|
||||
ResolverMarkers::Universal | ResolverMarkers::Fork(_) => Ok(result?.fork()),
|
||||
ResolverMarkers::Universal { .. } | ResolverMarkers::Fork(_) => Ok(result?.fork()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1770,7 +1770,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
|
|||
&self.exclusions,
|
||||
// We don't have access to the fork state when prefetching, so assume that
|
||||
// pre-release versions are allowed.
|
||||
&ResolverMarkers::Universal,
|
||||
&ResolverMarkers::universal(None),
|
||||
) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
@ -2479,6 +2479,12 @@ impl Resolution {
|
|||
}
|
||||
}
|
||||
|
||||
impl ResolutionPackage {
|
||||
pub(crate) fn is_base(&self) -> bool {
|
||||
self.extra.is_none() && self.dev.is_none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch the metadata for an item
|
||||
#[derive(Debug)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use pep508_rs::{MarkerEnvironment, MarkerTree};
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
use pep508_rs::{MarkerEnvironment, MarkerTree};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
/// Whether we're solving for a specific environment, universally or for a specific fork.
|
||||
pub enum ResolverMarkers {
|
||||
|
@ -8,16 +10,29 @@ pub enum ResolverMarkers {
|
|||
SpecificEnvironment(MarkerEnvironment),
|
||||
/// We're doing a universal resolution for all environments (a python version
|
||||
/// constraint is expressed separately).
|
||||
Universal,
|
||||
Universal {
|
||||
/// Start the resolution with these forks.
|
||||
fork_preferences: Option<BTreeSet<MarkerTree>>,
|
||||
},
|
||||
/// We're in a fork of the universal resolution solving only for specific markers.
|
||||
Fork(MarkerTree),
|
||||
}
|
||||
|
||||
impl ResolverMarkers {
|
||||
/// Set the resolver to perform a resolution for a specific environment.
|
||||
pub fn specific_environment(markers: MarkerEnvironment) -> Self {
|
||||
Self::SpecificEnvironment(markers)
|
||||
}
|
||||
|
||||
/// Set the resolver to perform a universal resolution.
|
||||
pub fn universal(fork_preferences: Option<BTreeSet<MarkerTree>>) -> Self {
|
||||
Self::Universal { fork_preferences }
|
||||
}
|
||||
|
||||
/// Add the markers of an initial or subsequent fork to the current markers.
|
||||
pub(crate) fn and(self, other: MarkerTree) -> MarkerTree {
|
||||
match self {
|
||||
ResolverMarkers::Universal => other,
|
||||
ResolverMarkers::Universal { .. } => other,
|
||||
ResolverMarkers::Fork(mut current) => {
|
||||
current.and(other);
|
||||
current
|
||||
|
@ -31,14 +46,15 @@ impl ResolverMarkers {
|
|||
/// If solving for a specific environment, return this environment.
|
||||
pub fn marker_environment(&self) -> Option<&MarkerEnvironment> {
|
||||
match self {
|
||||
ResolverMarkers::Universal | ResolverMarkers::Fork(_) => None,
|
||||
ResolverMarkers::Universal { .. } | ResolverMarkers::Fork(_) => None,
|
||||
ResolverMarkers::SpecificEnvironment(env) => Some(env),
|
||||
}
|
||||
}
|
||||
|
||||
/// If solving a fork, return that fork's markers.
|
||||
pub fn fork_markers(&self) -> Option<&MarkerTree> {
|
||||
match self {
|
||||
ResolverMarkers::SpecificEnvironment(_) | ResolverMarkers::Universal => None,
|
||||
ResolverMarkers::SpecificEnvironment(_) | ResolverMarkers::Universal { .. } => None,
|
||||
ResolverMarkers::Fork(markers) => Some(markers),
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +63,7 @@ impl ResolverMarkers {
|
|||
impl Display for ResolverMarkers {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ResolverMarkers::Universal => f.write_str("universal"),
|
||||
ResolverMarkers::Universal { .. } => f.write_str("universal"),
|
||||
ResolverMarkers::SpecificEnvironment(_) => f.write_str("specific environment"),
|
||||
ResolverMarkers::Fork(markers) => {
|
||||
write!(f, "({markers})")
|
||||
|
|
|
@ -5,6 +5,11 @@ expression: result
|
|||
Ok(
|
||||
Lock {
|
||||
version: 1,
|
||||
fork_markers: None,
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
distributions: [
|
||||
Distribution {
|
||||
id: DistributionId {
|
||||
|
@ -56,15 +61,12 @@ Ok(
|
|||
},
|
||||
},
|
||||
],
|
||||
fork_markers: None,
|
||||
dependencies: [],
|
||||
optional_dependencies: {},
|
||||
dev_dependencies: {},
|
||||
},
|
||||
],
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
by_id: {
|
||||
DistributionId {
|
||||
name: PackageName(
|
||||
|
|
|
@ -5,6 +5,11 @@ expression: result
|
|||
Ok(
|
||||
Lock {
|
||||
version: 1,
|
||||
fork_markers: None,
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
distributions: [
|
||||
Distribution {
|
||||
id: DistributionId {
|
||||
|
@ -63,15 +68,12 @@ Ok(
|
|||
},
|
||||
},
|
||||
],
|
||||
fork_markers: None,
|
||||
dependencies: [],
|
||||
optional_dependencies: {},
|
||||
dev_dependencies: {},
|
||||
},
|
||||
],
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
by_id: {
|
||||
DistributionId {
|
||||
name: PackageName(
|
||||
|
|
|
@ -5,6 +5,11 @@ expression: result
|
|||
Ok(
|
||||
Lock {
|
||||
version: 1,
|
||||
fork_markers: None,
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
distributions: [
|
||||
Distribution {
|
||||
id: DistributionId {
|
||||
|
@ -49,15 +54,12 @@ Ok(
|
|||
},
|
||||
},
|
||||
],
|
||||
fork_markers: None,
|
||||
dependencies: [],
|
||||
optional_dependencies: {},
|
||||
dev_dependencies: {},
|
||||
},
|
||||
],
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
by_id: {
|
||||
DistributionId {
|
||||
name: PackageName(
|
||||
|
|
|
@ -5,6 +5,11 @@ expression: result
|
|||
Ok(
|
||||
Lock {
|
||||
version: 1,
|
||||
fork_markers: None,
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
distributions: [
|
||||
Distribution {
|
||||
id: DistributionId {
|
||||
|
@ -51,6 +56,7 @@ Ok(
|
|||
},
|
||||
),
|
||||
wheels: [],
|
||||
fork_markers: None,
|
||||
dependencies: [],
|
||||
optional_dependencies: {},
|
||||
dev_dependencies: {},
|
||||
|
@ -100,6 +106,7 @@ Ok(
|
|||
},
|
||||
),
|
||||
wheels: [],
|
||||
fork_markers: None,
|
||||
dependencies: [
|
||||
Dependency {
|
||||
distribution_id: DistributionId {
|
||||
|
@ -133,10 +140,6 @@ Ok(
|
|||
dev_dependencies: {},
|
||||
},
|
||||
],
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
by_id: {
|
||||
DistributionId {
|
||||
name: PackageName(
|
||||
|
|
|
@ -5,6 +5,11 @@ expression: result
|
|||
Ok(
|
||||
Lock {
|
||||
version: 1,
|
||||
fork_markers: None,
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
distributions: [
|
||||
Distribution {
|
||||
id: DistributionId {
|
||||
|
@ -51,6 +56,7 @@ Ok(
|
|||
},
|
||||
),
|
||||
wheels: [],
|
||||
fork_markers: None,
|
||||
dependencies: [],
|
||||
optional_dependencies: {},
|
||||
dev_dependencies: {},
|
||||
|
@ -100,6 +106,7 @@ Ok(
|
|||
},
|
||||
),
|
||||
wheels: [],
|
||||
fork_markers: None,
|
||||
dependencies: [
|
||||
Dependency {
|
||||
distribution_id: DistributionId {
|
||||
|
@ -133,10 +140,6 @@ Ok(
|
|||
dev_dependencies: {},
|
||||
},
|
||||
],
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
by_id: {
|
||||
DistributionId {
|
||||
name: PackageName(
|
||||
|
|
|
@ -5,6 +5,11 @@ expression: result
|
|||
Ok(
|
||||
Lock {
|
||||
version: 1,
|
||||
fork_markers: None,
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
distributions: [
|
||||
Distribution {
|
||||
id: DistributionId {
|
||||
|
@ -51,6 +56,7 @@ Ok(
|
|||
},
|
||||
),
|
||||
wheels: [],
|
||||
fork_markers: None,
|
||||
dependencies: [],
|
||||
optional_dependencies: {},
|
||||
dev_dependencies: {},
|
||||
|
@ -100,6 +106,7 @@ Ok(
|
|||
},
|
||||
),
|
||||
wheels: [],
|
||||
fork_markers: None,
|
||||
dependencies: [
|
||||
Dependency {
|
||||
distribution_id: DistributionId {
|
||||
|
@ -133,10 +140,6 @@ Ok(
|
|||
dev_dependencies: {},
|
||||
},
|
||||
],
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
by_id: {
|
||||
DistributionId {
|
||||
name: PackageName(
|
||||
|
|
|
@ -5,6 +5,11 @@ expression: result
|
|||
Ok(
|
||||
Lock {
|
||||
version: 1,
|
||||
fork_markers: None,
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
distributions: [
|
||||
Distribution {
|
||||
id: DistributionId {
|
||||
|
@ -37,15 +42,12 @@ Ok(
|
|||
},
|
||||
sdist: None,
|
||||
wheels: [],
|
||||
fork_markers: None,
|
||||
dependencies: [],
|
||||
optional_dependencies: {},
|
||||
dev_dependencies: {},
|
||||
},
|
||||
],
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
by_id: {
|
||||
DistributionId {
|
||||
name: PackageName(
|
||||
|
|
|
@ -5,6 +5,11 @@ expression: result
|
|||
Ok(
|
||||
Lock {
|
||||
version: 1,
|
||||
fork_markers: None,
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
distributions: [
|
||||
Distribution {
|
||||
id: DistributionId {
|
||||
|
@ -35,15 +40,12 @@ Ok(
|
|||
},
|
||||
sdist: None,
|
||||
wheels: [],
|
||||
fork_markers: None,
|
||||
dependencies: [],
|
||||
optional_dependencies: {},
|
||||
dev_dependencies: {},
|
||||
},
|
||||
],
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
by_id: {
|
||||
DistributionId {
|
||||
name: PackageName(
|
||||
|
|
|
@ -5,6 +5,11 @@ expression: result
|
|||
Ok(
|
||||
Lock {
|
||||
version: 1,
|
||||
fork_markers: None,
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
distributions: [
|
||||
Distribution {
|
||||
id: DistributionId {
|
||||
|
@ -18,15 +23,12 @@ Ok(
|
|||
},
|
||||
sdist: None,
|
||||
wheels: [],
|
||||
fork_markers: None,
|
||||
dependencies: [],
|
||||
optional_dependencies: {},
|
||||
dev_dependencies: {},
|
||||
},
|
||||
],
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
by_id: {
|
||||
DistributionId {
|
||||
name: PackageName(
|
||||
|
|
|
@ -5,6 +5,11 @@ expression: result
|
|||
Ok(
|
||||
Lock {
|
||||
version: 1,
|
||||
fork_markers: None,
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
distributions: [
|
||||
Distribution {
|
||||
id: DistributionId {
|
||||
|
@ -18,15 +23,12 @@ Ok(
|
|||
},
|
||||
sdist: None,
|
||||
wheels: [],
|
||||
fork_markers: None,
|
||||
dependencies: [],
|
||||
optional_dependencies: {},
|
||||
dev_dependencies: {},
|
||||
},
|
||||
],
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
by_id: {
|
||||
DistributionId {
|
||||
name: PackageName(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue