@@ -22,18 +22,12 @@ use crate::graph_ops::marker_reachability;
2222use crate :: lock:: { Package , PackageId , Source } ;
2323use crate :: { Lock , LockError } ;
2424
25- type LockGraph < ' lock > = Graph < & ' lock Package , Edge , Directed > ;
26-
27- #[ derive( Debug , Clone , PartialEq , Eq ) ]
28- struct Node < ' lock > {
29- package : & ' lock Package ,
30- marker : MarkerTree ,
31- }
25+ type LockGraph < ' lock > = Graph < Node < ' lock > , Edge , Directed > ;
3226
3327/// An export of a [`Lock`] that renders in `requirements.txt` format.
3428#[ derive( Debug ) ]
3529pub struct RequirementsTxtExport < ' lock > {
36- nodes : Vec < Node < ' lock > > ,
30+ nodes : Vec < Requirement < ' lock > > ,
3731 hashes : bool ,
3832 editable : EditableMode ,
3933}
@@ -55,45 +49,62 @@ impl<'lock> RequirementsTxtExport<'lock> {
5549 let mut queue: VecDeque < ( & Package , Option < & ExtraName > ) > = VecDeque :: new ( ) ;
5650 let mut seen = FxHashSet :: default ( ) ;
5751
52+ let root = petgraph. add_node ( Node :: Root ) ;
53+
5854 // Add the workspace package to the queue.
59- let root = lock
55+ let dist = lock
6056 . find_by_name ( root_name)
6157 . expect ( "found too many packages matching root" )
6258 . expect ( "could not find root" ) ;
6359
6460 if dev. prod ( ) {
65- // Add the base package.
66- queue. push_back ( ( root, None ) ) ;
61+ // Add the workspace package to the graph.
62+ if let Entry :: Vacant ( entry) = inverse. entry ( & dist. id ) {
63+ entry. insert ( petgraph. add_node ( Node :: Package ( dist) ) ) ;
64+ }
6765
68- // Add any extras.
66+ // Add an edge from the root.
67+ let index = inverse[ & dist. id ] ;
68+ petgraph. add_edge ( root, index, MarkerTree :: TRUE ) ;
69+
70+ // Push its dependencies on the queue.
71+ queue. push_back ( ( dist, None ) ) ;
6972 match extras {
7073 ExtrasSpecification :: None => { }
7174 ExtrasSpecification :: All => {
72- for extra in root . optional_dependencies . keys ( ) {
73- queue. push_back ( ( root , Some ( extra) ) ) ;
75+ for extra in dist . optional_dependencies . keys ( ) {
76+ queue. push_back ( ( dist , Some ( extra) ) ) ;
7477 }
7578 }
7679 ExtrasSpecification :: Some ( extras) => {
7780 for extra in extras {
78- queue. push_back ( ( root , Some ( extra) ) ) ;
81+ queue. push_back ( ( dist , Some ( extra) ) ) ;
7982 }
8083 }
8184 }
82-
83- // Add the root package to the graph.
84- inverse. insert ( & root. id , petgraph. add_node ( root) ) ;
8585 }
8686
87- // Add any dev dependencies.
87+ // Add any development dependencies.
8888 for group in dev. iter ( ) {
89- for dep in root . dependency_groups . get ( group) . into_iter ( ) . flatten ( ) {
89+ for dep in dist . dependency_groups . get ( group) . into_iter ( ) . flatten ( ) {
9090 let dep_dist = lock. find_by_id ( & dep. package_id ) ;
9191
9292 // Add the dependency to the graph.
9393 if let Entry :: Vacant ( entry) = inverse. entry ( & dep. package_id ) {
94- entry. insert ( petgraph. add_node ( dep_dist) ) ;
94+ entry. insert ( petgraph. add_node ( Node :: Package ( dep_dist) ) ) ;
9595 }
9696
97+ // Add an edge from the root. Development dependencies may be installed without
98+ // installing the workspace package itself (which can never have markers on it
99+ // anyway), so they're directly connected to the root.
100+ let dep_index = inverse[ & dep. package_id ] ;
101+ petgraph. add_edge (
102+ root,
103+ dep_index,
104+ dep. simplified_marker . as_simplified_marker_tree ( ) . clone ( ) ,
105+ ) ;
106+
107+ // Push its dependencies on the queue.
97108 if seen. insert ( ( & dep. package_id , None ) ) {
98109 queue. push_back ( ( dep_dist, None ) ) ;
99110 }
@@ -126,7 +137,7 @@ impl<'lock> RequirementsTxtExport<'lock> {
126137
127138 // Add the dependency to the graph.
128139 if let Entry :: Vacant ( entry) = inverse. entry ( & dep. package_id ) {
129- entry. insert ( petgraph. add_node ( dep_dist) ) ;
140+ entry. insert ( petgraph. add_node ( Node :: Package ( dep_dist) ) ) ;
130141 }
131142
132143 // Add the edge.
@@ -152,20 +163,24 @@ impl<'lock> RequirementsTxtExport<'lock> {
152163 let mut reachability = marker_reachability ( & petgraph, & [ ] ) ;
153164
154165 // Collect all packages.
155- let mut nodes: Vec < Node > = petgraph
166+ let mut nodes = petgraph
156167 . node_references ( )
168+ . filter_map ( |( index, node) | match node {
169+ Node :: Root => None ,
170+ Node :: Package ( package) => Some ( ( index, package) ) ,
171+ } )
157172 . filter ( |( _index, package) | {
158173 install_options. include_package ( & package. id . name , Some ( root_name) , lock. members ( ) )
159174 } )
160- . map ( |( index, package) | Node {
175+ . map ( |( index, package) | Requirement {
161176 package,
162177 marker : reachability. remove ( & index) . unwrap_or_default ( ) ,
163178 } )
164179 . collect :: < Vec < _ > > ( ) ;
165180
166181 // Sort the nodes, such that unnamed URLs (editables) appear at the top.
167182 nodes. sort_unstable_by ( |a, b| {
168- NodeComparator :: from ( a. package ) . cmp ( & NodeComparator :: from ( b. package ) )
183+ RequirementComparator :: from ( a. package ) . cmp ( & RequirementComparator :: from ( b. package ) )
169184 } ) ;
170185
171186 Ok ( Self {
@@ -179,7 +194,7 @@ impl<'lock> RequirementsTxtExport<'lock> {
179194impl std:: fmt:: Display for RequirementsTxtExport < ' _ > {
180195 fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
181196 // Write out each package.
182- for Node { package, marker } in & self . nodes {
197+ for Requirement { package, marker } in & self . nodes {
183198 match & package. id . source {
184199 Source :: Registry ( _) => {
185200 write ! ( f, "{}=={}" , package. id. name, package. id. version) ?;
@@ -261,17 +276,31 @@ impl std::fmt::Display for RequirementsTxtExport<'_> {
261276 }
262277}
263278
279+ /// A node in the [`LockGraph`].
280+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
281+ enum Node < ' lock > {
282+ Root ,
283+ Package ( & ' lock Package ) ,
284+ }
285+
264286/// The edges of the [`LockGraph`].
265287type Edge = MarkerTree ;
266288
289+ /// A flat requirement, with its associated marker.
290+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
291+ struct Requirement < ' lock > {
292+ package : & ' lock Package ,
293+ marker : MarkerTree ,
294+ }
295+
267296#[ derive( Debug , Clone , PartialEq , Eq , PartialOrd , Ord ) ]
268- enum NodeComparator < ' lock > {
297+ enum RequirementComparator < ' lock > {
269298 Editable ( & ' lock Path ) ,
270299 Path ( & ' lock Path ) ,
271300 Package ( & ' lock PackageId ) ,
272301}
273302
274- impl < ' lock > From < & ' lock Package > for NodeComparator < ' lock > {
303+ impl < ' lock > From < & ' lock Package > for RequirementComparator < ' lock > {
275304 fn from ( value : & ' lock Package ) -> Self {
276305 match & value. id . source {
277306 Source :: Path ( path) | Source :: Directory ( path) => Self :: Path ( path) ,
0 commit comments