mirror of https://github.com/astral-sh/uv
Respect dependency group markers in `uv export` (#8659)
## Summary Closes https://github.com/astral-sh/uv/issues/8658.
This commit is contained in:
parent
9fa4fea8f2
commit
bf14b6a282
|
|
@ -22,18 +22,12 @@ use crate::graph_ops::marker_reachability;
|
|||
use crate::lock::{Package, PackageId, Source};
|
||||
use crate::{Lock, LockError};
|
||||
|
||||
type LockGraph<'lock> = Graph<&'lock Package, Edge, Directed>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
struct Node<'lock> {
|
||||
package: &'lock Package,
|
||||
marker: MarkerTree,
|
||||
}
|
||||
type LockGraph<'lock> = Graph<Node<'lock>, Edge, Directed>;
|
||||
|
||||
/// An export of a [`Lock`] that renders in `requirements.txt` format.
|
||||
#[derive(Debug)]
|
||||
pub struct RequirementsTxtExport<'lock> {
|
||||
nodes: Vec<Node<'lock>>,
|
||||
nodes: Vec<Requirement<'lock>>,
|
||||
hashes: bool,
|
||||
editable: EditableMode,
|
||||
}
|
||||
|
|
@ -55,45 +49,62 @@ impl<'lock> RequirementsTxtExport<'lock> {
|
|||
let mut queue: VecDeque<(&Package, Option<&ExtraName>)> = VecDeque::new();
|
||||
let mut seen = FxHashSet::default();
|
||||
|
||||
let root = petgraph.add_node(Node::Root);
|
||||
|
||||
// Add the workspace package to the queue.
|
||||
let root = lock
|
||||
let dist = lock
|
||||
.find_by_name(root_name)
|
||||
.expect("found too many packages matching root")
|
||||
.expect("could not find root");
|
||||
|
||||
if dev.prod() {
|
||||
// Add the base package.
|
||||
queue.push_back((root, None));
|
||||
// Add the workspace package to the graph.
|
||||
if let Entry::Vacant(entry) = inverse.entry(&dist.id) {
|
||||
entry.insert(petgraph.add_node(Node::Package(dist)));
|
||||
}
|
||||
|
||||
// Add any extras.
|
||||
// Add an edge from the root.
|
||||
let index = inverse[&dist.id];
|
||||
petgraph.add_edge(root, index, MarkerTree::TRUE);
|
||||
|
||||
// Push its dependencies on the queue.
|
||||
queue.push_back((dist, None));
|
||||
match extras {
|
||||
ExtrasSpecification::None => {}
|
||||
ExtrasSpecification::All => {
|
||||
for extra in root.optional_dependencies.keys() {
|
||||
queue.push_back((root, Some(extra)));
|
||||
for extra in dist.optional_dependencies.keys() {
|
||||
queue.push_back((dist, Some(extra)));
|
||||
}
|
||||
}
|
||||
ExtrasSpecification::Some(extras) => {
|
||||
for extra in extras {
|
||||
queue.push_back((root, Some(extra)));
|
||||
queue.push_back((dist, Some(extra)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the root package to the graph.
|
||||
inverse.insert(&root.id, petgraph.add_node(root));
|
||||
}
|
||||
|
||||
// Add any dev dependencies.
|
||||
// Add any development dependencies.
|
||||
for group in dev.iter() {
|
||||
for dep in root.dependency_groups.get(group).into_iter().flatten() {
|
||||
for dep in dist.dependency_groups.get(group).into_iter().flatten() {
|
||||
let dep_dist = lock.find_by_id(&dep.package_id);
|
||||
|
||||
// Add the dependency to the graph.
|
||||
if let Entry::Vacant(entry) = inverse.entry(&dep.package_id) {
|
||||
entry.insert(petgraph.add_node(dep_dist));
|
||||
entry.insert(petgraph.add_node(Node::Package(dep_dist)));
|
||||
}
|
||||
|
||||
// Add an edge from the root. Development dependencies may be installed without
|
||||
// installing the workspace package itself (which can never have markers on it
|
||||
// anyway), so they're directly connected to the root.
|
||||
let dep_index = inverse[&dep.package_id];
|
||||
petgraph.add_edge(
|
||||
root,
|
||||
dep_index,
|
||||
dep.simplified_marker.as_simplified_marker_tree().clone(),
|
||||
);
|
||||
|
||||
// Push its dependencies on the queue.
|
||||
if seen.insert((&dep.package_id, None)) {
|
||||
queue.push_back((dep_dist, None));
|
||||
}
|
||||
|
|
@ -126,7 +137,7 @@ impl<'lock> RequirementsTxtExport<'lock> {
|
|||
|
||||
// Add the dependency to the graph.
|
||||
if let Entry::Vacant(entry) = inverse.entry(&dep.package_id) {
|
||||
entry.insert(petgraph.add_node(dep_dist));
|
||||
entry.insert(petgraph.add_node(Node::Package(dep_dist)));
|
||||
}
|
||||
|
||||
// Add the edge.
|
||||
|
|
@ -152,12 +163,16 @@ impl<'lock> RequirementsTxtExport<'lock> {
|
|||
let mut reachability = marker_reachability(&petgraph, &[]);
|
||||
|
||||
// Collect all packages.
|
||||
let mut nodes: Vec<Node> = petgraph
|
||||
let mut nodes = petgraph
|
||||
.node_references()
|
||||
.filter_map(|(index, node)| match node {
|
||||
Node::Root => None,
|
||||
Node::Package(package) => Some((index, package)),
|
||||
})
|
||||
.filter(|(_index, package)| {
|
||||
install_options.include_package(&package.id.name, Some(root_name), lock.members())
|
||||
})
|
||||
.map(|(index, package)| Node {
|
||||
.map(|(index, package)| Requirement {
|
||||
package,
|
||||
marker: reachability.remove(&index).unwrap_or_default(),
|
||||
})
|
||||
|
|
@ -165,7 +180,7 @@ impl<'lock> RequirementsTxtExport<'lock> {
|
|||
|
||||
// Sort the nodes, such that unnamed URLs (editables) appear at the top.
|
||||
nodes.sort_unstable_by(|a, b| {
|
||||
NodeComparator::from(a.package).cmp(&NodeComparator::from(b.package))
|
||||
RequirementComparator::from(a.package).cmp(&RequirementComparator::from(b.package))
|
||||
});
|
||||
|
||||
Ok(Self {
|
||||
|
|
@ -179,7 +194,7 @@ impl<'lock> RequirementsTxtExport<'lock> {
|
|||
impl std::fmt::Display for RequirementsTxtExport<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
// Write out each package.
|
||||
for Node { package, marker } in &self.nodes {
|
||||
for Requirement { package, marker } in &self.nodes {
|
||||
match &package.id.source {
|
||||
Source::Registry(_) => {
|
||||
write!(f, "{}=={}", package.id.name, package.id.version)?;
|
||||
|
|
@ -261,17 +276,31 @@ impl std::fmt::Display for RequirementsTxtExport<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A node in the [`LockGraph`].
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
enum Node<'lock> {
|
||||
Root,
|
||||
Package(&'lock Package),
|
||||
}
|
||||
|
||||
/// The edges of the [`LockGraph`].
|
||||
type Edge = MarkerTree;
|
||||
|
||||
/// A flat requirement, with its associated marker.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
struct Requirement<'lock> {
|
||||
package: &'lock Package,
|
||||
marker: MarkerTree,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
enum NodeComparator<'lock> {
|
||||
enum RequirementComparator<'lock> {
|
||||
Editable(&'lock Path),
|
||||
Path(&'lock Path),
|
||||
Package(&'lock PackageId),
|
||||
}
|
||||
|
||||
impl<'lock> From<&'lock Package> for NodeComparator<'lock> {
|
||||
impl<'lock> From<&'lock Package> for RequirementComparator<'lock> {
|
||||
fn from(value: &'lock Package) -> Self {
|
||||
match &value.id.source {
|
||||
Source::Path(path) | Source::Directory(path) => Self::Path(path),
|
||||
|
|
|
|||
|
|
@ -1027,7 +1027,7 @@ fn export_group() -> Result<()> {
|
|||
requires-python = ">=3.12"
|
||||
dependencies = ["typing-extensions"]
|
||||
[dependency-groups]
|
||||
foo = ["anyio"]
|
||||
foo = ["anyio ; sys_platform == 'darwin'"]
|
||||
bar = ["iniconfig"]
|
||||
dev = ["sniffio"]
|
||||
"#,
|
||||
|
|
@ -1072,10 +1072,10 @@ fn export_group() -> Result<()> {
|
|||
----- stdout -----
|
||||
# This file was autogenerated by uv via the following command:
|
||||
# uv export --cache-dir [CACHE_DIR] --group foo
|
||||
anyio==4.3.0 \
|
||||
anyio==4.3.0 ; sys_platform == 'darwin' \
|
||||
--hash=sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6 \
|
||||
--hash=sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8
|
||||
idna==3.6 \
|
||||
idna==3.6 ; sys_platform == 'darwin' \
|
||||
--hash=sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca \
|
||||
--hash=sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f
|
||||
sniffio==1.3.1 \
|
||||
|
|
@ -1095,10 +1095,10 @@ fn export_group() -> Result<()> {
|
|||
----- stdout -----
|
||||
# This file was autogenerated by uv via the following command:
|
||||
# uv export --cache-dir [CACHE_DIR] --group foo --group bar
|
||||
anyio==4.3.0 \
|
||||
anyio==4.3.0 ; sys_platform == 'darwin' \
|
||||
--hash=sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6 \
|
||||
--hash=sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8
|
||||
idna==3.6 \
|
||||
idna==3.6 ; sys_platform == 'darwin' \
|
||||
--hash=sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca \
|
||||
--hash=sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f
|
||||
iniconfig==2.0.0 \
|
||||
|
|
|
|||
Loading…
Reference in New Issue