11#
2- # Copyright (C) 2024 CEA
2+ # Copyright (C) 2025 CEA
33#
44# This file is part of Rift project.
55#
@@ -54,6 +54,16 @@ def __init__(self, package):
5454 self .subpackages = spec .provides
5555 # Parse buildrequires string in spec file to discard explicit versions
5656 # enforcement.
57+ #
58+ # Note this is currently done this way for the sake of simplicity,
59+ # despite the value that could be provided by these version constraints.
60+ # It could notably be interesting to extract lesser version constraints
61+ # when a dependency is updated to a greater version.
62+ #
63+ # Currently, the automatic rebuilds of recursive reverse dependencies
64+ # eventually fail at some point because of invalid versioning in this
65+ # case but it could be nice to fail faster by detecting mismatching
66+ # versions before the actual builds.
5767 self .build_requires = [
5868 value .group (1 )
5969 for value
@@ -99,24 +109,13 @@ def dump(self):
99109 """Dump graph in its current state with logging message."""
100110 for node in self .nodes :
101111 logging .info ("→ %s" , node .package .name )
112+ logging .info (" provides: %s" , str (node .subpackages ))
102113 logging .info (" requires: %s" , node .build_requires )
103- logging .info (" subpackages: %s" , str (node .subpackages ))
104114 logging .info (
105- " rdeps: %s" , str ([rdep .package .name for rdep in node .rdeps ])
115+ " is required by: %s" ,
116+ str ([rdep .package .name for rdep in node .rdeps ])
106117 )
107118
108- def solve (self , package ):
109- """
110- Return list of recursive build requirements for the provided package.
111- """
112- self .path = [] # Start with empty path
113- for node in self .nodes :
114- if node .package .name == package .name :
115- return self ._solve (node , "User request" )
116-
117- # Package not found in graph, return empty list.
118- return []
119-
120119 def _dep_index (self , new , result ):
121120 """
122121 The new and results arguments are list of build requirements. The result
@@ -148,7 +147,7 @@ def _dep_index(self, new, result):
148147 def _solve (self , node , reason , depth = 0 ):
149148 """
150149 Return list of recursive build requirements for the provided package
151- dependency node. The reason argument is a string to textually justify
150+ dependency node. The " reason" argument is a string to textually justify
152151 the build requirement of the given node. The depth argument is used to
153152 track the depth of recursive path in the dependency graph.
154153 """
@@ -176,18 +175,19 @@ def _solve(self, node, reason, depth=0):
176175 if rdep .package .depends is not None :
177176 reason = f"depends on { node .package .name } "
178177 else :
179- reason = "build requires on " + ", " .join (
178+ reason = "build depends on " + ", " .join (
180179 node .required_subpackages (rdep )
181180 )
182181 # If reverse dependency has already been processed in the processing
183182 # path to the current node, add it to resulting list and stop
184183 # processing to avoid endless loop.
185184 if rdep in self .path [0 :depth ]:
186185 logging .debug (
187- "%s ⥀ Loop detected on node %s at depth %d" ,
186+ "%s ⥀ Loop detected on node %s at depth %d: %s " ,
188187 ' ' * depth ,
189188 rdep .package .name ,
190- depth
189+ depth ,
190+ '→' .join (node .package .name for node in self .path + [rdep ]),
191191 )
192192 result .append (BuildRequirement (rdep .package , [reason ]))
193193 continue
@@ -196,7 +196,7 @@ def _solve(self, node, reason, depth=0):
196196 ' ' * depth ,
197197 rdep .package .name
198198 )
199- # Iterate over all recursively solve build requirements for this
199+ # Iterate over all recursively solved build requirements for this
200200 # reverse dependency.
201201 build_requirements = self ._solve (rdep , reason , depth + 1 )
202202 for idx , build_requirement in enumerate (build_requirements ):
@@ -218,6 +218,28 @@ def _solve(self, node, reason, depth=0):
218218 result .insert (position , build_requirement )
219219 return result
220220
221+ def solve (self , package ):
222+ """
223+ Return list of recursive build requirements for the provided package.
224+ """
225+ self .path = [] # Start with empty path
226+ for node in self .nodes :
227+ if node .package .name == package .name :
228+ return self ._solve (node , "User request" )
229+
230+ # Package not found in graph, return empty list.
231+ return []
232+
233+ def _insert (self , package ):
234+ """Insert package in the graph."""
235+ node = PackageDependencyNode (package )
236+ for _node in self .nodes :
237+ if _node .depends_on (node ):
238+ node .rdeps .append (_node )
239+ if node .depends_on (_node ):
240+ _node .rdeps .append (node )
241+ self .nodes .append (node )
242+
221243 def build (self , packages ):
222244 """Build graph with the provided packages."""
223245 tic = time .perf_counter ()
@@ -227,24 +249,14 @@ def build(self, packages):
227249 try :
228250 package .load ()
229251 except FileNotFoundError as err :
230- logging .warning ("Skipping package %s unable to load: %s" ,
252+ logging .warning ("Skipping package '%s' unable to load: %s" ,
231253 package .name , err )
232254 continue
233255 self ._insert (package )
234256 toc = time .perf_counter ()
235257 logging .debug ("Graph built in %0.4f seconds" , toc - tic )
236258 logging .debug ("Graph size: %d" , len (self .nodes ))
237259
238- def _insert (self , package ):
239- """Insert package in the graph."""
240- node = PackageDependencyNode (package )
241- for _node in self .nodes :
242- if _node .depends_on (node ):
243- node .rdeps .append (_node )
244- if node .depends_on (_node ):
245- _node .rdeps .append (node )
246- self .nodes .append (node )
247-
248260 @classmethod
249261 def from_project (cls , config , staff , modules ):
250262 """
0 commit comments