@@ -129,7 +129,7 @@ def conflicts(self, name):
129129 except OSError :
130130 conflicts = []
131131
132- if any ([c in self for c in recipe . conflicts ]):
132+ if any ([c in self for c in conflicts ]):
133133 return True
134134 return False
135135
@@ -151,6 +151,8 @@ def recursively_collect_orders(name, ctx, orders=[]):
151151 # via pip with no extra dependencies
152152 dependencies = []
153153
154+ # TODO: Also check recipe conflicts
155+
154156 new_orders = []
155157 # for each existing recipe order, see if we can add the new recipe name
156158 for order in orders :
@@ -174,24 +176,72 @@ def recursively_collect_orders(name, ctx, orders=[]):
174176 return new_orders
175177
176178
179+ def find_order (graph ):
180+ '''
181+ Do a topological sort on the dependency graph dict.
182+ '''
183+ while graph :
184+ # Find all items without a parent
185+ leftmost = [l for l , s in graph .items () if not s ]
186+ if not leftmost :
187+ raise ValueError ('Dependency cycle detected! %s' % graph )
188+ # If there is more than one, sort them for predictable order
189+ leftmost .sort ()
190+ for result in leftmost :
191+ # Yield and remove them from the graph
192+ yield result
193+ graph .pop (result )
194+ for bset in graph .values ():
195+ bset .discard (result )
196+
197+
177198def new_get_recipe_order_and_bootstrap (ctx , names , bs = None ):
178199 recipes_to_load = set (names )
179- # if bs is not None and bs.recipe_depends:
180- # recipes_to_load = recipes_to_load.union(set(bs.recipe_depends))
181-
182- possible_orders = [RecipeOrder (ctx )]
200+ if bs is not None and bs .recipe_depends :
201+ recipes_to_load = recipes_to_load .union (set (bs .recipe_depends ))
183202
184- # get all possible recipe orders
185- for name in names :
186- possible_orders = recursively_collect_orders (name , ctx , orders = possible_orders )
203+ possible_orders = []
204+
205+ # get all possible recipe sets if names includes alternative
206+ # dependencies
207+ names = [([name ] if not isinstance (name , (list , tuple )) else name )
208+ for name in names ]
209+ for name_set in product (* names ):
210+ new_possible_orders = [RecipeOrder (ctx )]
211+ for name in name_set :
212+ new_possible_orders = recursively_collect_orders (
213+ name , ctx , orders = new_possible_orders )
214+ possible_orders .extend (new_possible_orders )
215+
216+ # turn each order graph into a linear list if possible
217+ orders = []
218+ for possible_order in possible_orders :
219+ try :
220+ order = find_order (possible_order )
221+ except ValueError : # a circular dependency was found
222+ info ('Circular dependency found in graph {}' .format (possible_order ))
223+ continue
224+ orders .append (list (order ))
187225
188226 # prefer python2 and SDL2 if available
189- possible_orders = sorted (possible_orders ,
190- key = lambda order : - ('python2' in order ) - ('sdl2' in order ))
227+ orders = sorted (orders ,
228+ key = lambda order : - ('python2' in order ) - ('sdl2' in order ))
191229
230+ # It would be better to check against possible orders other
231+ # than the first one, but in practice clashes will be rare,
232+ # and can be resolved by specifying more parameters
233+ order = orders [0 ]
192234
235+ print ('pre-bs order is' , order )
236+
237+ if bs is None :
238+ bs = Bootstrap .get_bootstrap_from_recipes (order , ctx )
239+ orders , bs = new_get_recipe_order_and_bootstrap (ctx , order , bs = bs )
240+ order = orders [0 ]
193241
194- return possible_orders
242+ return order , bs
243+
244+
195245
196246
197247def get_recipe_order_and_bootstrap (ctx , names , bs = None ):
@@ -210,7 +260,6 @@ def get_recipe_order_and_bootstrap(ctx, names, bs=None):
210260 python_modules = []
211261 print ('recipes_to_load' , recipes_to_load )
212262 while recipes_to_load :
213- info ('Current recipes to load: {}' .format (', ' .join (map (str , recipes_to_load ))))
214263 name = recipes_to_load .pop (0 )
215264 if name in recipe_loaded or isinstance (name , (list , tuple )):
216265 continue
0 commit comments