@@ -1147,6 +1147,12 @@ class Bootstrap(object):
1147
1147
distribution = None
1148
1148
1149
1149
recipe_depends = []
1150
+
1151
+ can_be_chosen_automatically = True
1152
+ '''Determines whether the bootstrap can be chosen as one that
1153
+ satisfies user requirements. If False, it will not be returned
1154
+ from Bootstrap.get_bootstrap_from_recipes.
1155
+ '''
1150
1156
1151
1157
# Other things a Bootstrap might need to track (maybe separately):
1152
1158
# ndk_main.c
@@ -1221,6 +1227,39 @@ def list_bootstraps(cls):
1221
1227
if isdir (filen ):
1222
1228
yield name
1223
1229
1230
+ @classmethod
1231
+ def get_bootstrap_from_recipes (cls , recipes , ctx ):
1232
+ '''Returns a bootstrap whose recipe requirements do not conflict with
1233
+ the given recipes.'''
1234
+ info ('Trying to find a bootstrap that matches the given recipes.' )
1235
+ bootstraps = [cls .get_bootstrap (name , ctx ) for name in cls .list_bootstraps ()]
1236
+ acceptable_bootstraps = []
1237
+ for bs in bootstraps :
1238
+ ok = True
1239
+ if not bs .can_be_chosen_automatically :
1240
+ ok = False
1241
+ for recipe in bs .recipe_depends :
1242
+ recipe = Recipe .get_recipe (recipe , ctx )
1243
+ if any ([conflict in recipes for conflict in recipe .conflicts ]):
1244
+ ok = False
1245
+ break
1246
+ for recipe in recipes :
1247
+ recipe = Recipe .get_recipe (recipe , ctx )
1248
+ if any ([conflict in bs .recipe_depends for conflict in recipe .conflicts ]):
1249
+ ok = False
1250
+ break
1251
+ if ok :
1252
+ acceptable_bootstraps .append (bs )
1253
+ info ('Found {} acceptable bootstraps: {}' .format (
1254
+ len (acceptable_bootstraps ), [bs .name for bs in acceptable_bootstraps ]))
1255
+ if acceptable_bootstraps :
1256
+ info ('Using the first of these: {}' .format (acceptable_bootstraps [0 ].name ))
1257
+ return acceptable_bootstraps [0 ]
1258
+ return None
1259
+
1260
+
1261
+
1262
+
1224
1263
@classmethod
1225
1264
def get_bootstrap (cls , name , ctx ):
1226
1265
'''Returns an instance of a bootstrap with the given name.
@@ -1230,6 +1269,8 @@ def get_bootstrap(cls, name, ctx):
1230
1269
'''
1231
1270
# AND: This method will need to check user dirs, and access
1232
1271
# bootstraps in a slightly different way
1272
+ if name is None :
1273
+ return None
1233
1274
if not hasattr (cls , 'bootstraps' ):
1234
1275
cls .bootstraps = {}
1235
1276
if name in cls .bootstraps :
@@ -1946,54 +1987,9 @@ def get_recipe_env(self, arch):
1946
1987
return env
1947
1988
1948
1989
1949
- def build_recipes (names , ctx ):
1990
+ def build_recipes (build_order , python_modules , ctx ):
1950
1991
# Put recipes in correct build order
1951
- graph = Graph ()
1952
- recipes_to_load = set (names )
1953
1992
bs = ctx .bootstrap
1954
- if bs is not None and bs .recipe_depends :
1955
- info_notify ('Bootstrap requires recipes {}' .format (bs .recipe_depends ))
1956
- recipes_to_load = recipes_to_load .union (set (bs .recipe_depends ))
1957
- recipes_to_load = list (recipes_to_load )
1958
- recipe_loaded = []
1959
- python_modules = []
1960
- while recipes_to_load :
1961
- name = recipes_to_load .pop (0 )
1962
- if name in recipe_loaded or isinstance (name , (list , tuple )):
1963
- continue
1964
- try :
1965
- recipe = Recipe .get_recipe (name , ctx )
1966
- except ImportError :
1967
- info ('No recipe named {}; will attempt to install with pip' .format (name ))
1968
- python_modules .append (name )
1969
- continue
1970
- graph .add (name , name )
1971
- info ('Loaded recipe {} (depends on {}{})' .format (
1972
- name , recipe .depends ,
1973
- ', conflicts {}' .format (recipe .conflicts ) if recipe .conflicts else '' ))
1974
- for depend in recipe .depends :
1975
- graph .add (name , depend )
1976
- recipes_to_load += recipe .depends
1977
- for conflict in recipe .conflicts :
1978
- if graph .conflicts (conflict ):
1979
- warning (
1980
- ('{} conflicts with {}, but both have been '
1981
- 'included or pulled into the requirements.' .format (recipe .name , conflict )))
1982
- warning ('Due to this conflict the build cannot continue, exiting.' )
1983
- exit (1 )
1984
- recipe_loaded .append (name )
1985
- graph .remove_remaining_conflicts (ctx )
1986
- if len (graph .graphs ) > 1 :
1987
- info ('Found multiple valid recipe sets:' )
1988
- for g in graph .graphs :
1989
- info (' {}' .format (g .keys ()))
1990
- info_notify ('Using the first of these: {}' .format (graph .graphs [0 ].keys ()))
1991
- elif len (graph .graphs ) == 0 :
1992
- warning ('Didn\' t find any valid dependency graphs, exiting.' )
1993
- exit (1 )
1994
- else :
1995
- info ('Found a single valid recipe set (this is good)' )
1996
- build_order = list (graph .find_order (0 ))
1997
1993
info_notify ("Recipe build order is {}" .format (build_order ))
1998
1994
if python_modules :
1999
1995
info_notify (('The requirements ({}) were not found as recipes, they will be '
@@ -2192,11 +2188,15 @@ def build_dist_from_args(ctx, dist, args_list):
2192
2188
parser = argparse .ArgumentParser (
2193
2189
description = 'Create a newAndroid project' )
2194
2190
parser .add_argument ('--bootstrap' , help = ('The name of the bootstrap type, \' pygame\' '
2195
- 'or \' sdl2\' ' ),
2196
- default = 'sdl2' )
2191
+ 'or \' sdl2\' , or leave empty to let a '
2192
+ 'bootstrap be chosen automatically from your '
2193
+ 'requirements.' ),
2194
+ default = None )
2197
2195
args , unknown = parser .parse_known_args (args_list )
2198
2196
2199
2197
bs = Bootstrap .get_bootstrap (args .bootstrap , ctx )
2198
+ build_order , python_modules , bs = get_recipe_order_and_bootstrap (ctx , dist .recipes , bs )
2199
+
2200
2200
info ('The selected bootstrap is {}' .format (bs .name ))
2201
2201
info_main ('# Creating dist with {} bootstrap' .format (bs .name ))
2202
2202
bs .distribution = dist
@@ -2207,8 +2207,7 @@ def build_dist_from_args(ctx, dist, args_list):
2207
2207
ctx .prepare_bootstrap (bs )
2208
2208
ctx .prepare_dist (ctx .dist_name )
2209
2209
2210
- recipes = dist .recipes
2211
- build_recipes (recipes , ctx )
2210
+ build_recipes (build_order , python_modules , ctx )
2212
2211
2213
2212
ctx .bootstrap .run_distribute ()
2214
2213
@@ -2217,6 +2216,105 @@ def build_dist_from_args(ctx, dist, args_list):
2217
2216
2218
2217
return unknown
2219
2218
2219
+ def get_recipe_order_and_bootstrap (ctx , names , bs = None ):
2220
+ '''Takes a list of recipe names and (optionally) a bootstrap. Then
2221
+ works out the dependency graph (including bootstrap recipes if
2222
+ necessary). Finally, if no bootstrap was initially selected,
2223
+ chooses one that supports all the recipes.
2224
+ '''
2225
+ graph = Graph ()
2226
+ recipes_to_load = set (names )
2227
+ if bs is not None and bs .recipe_depends :
2228
+ info_notify ('Bootstrap requires recipes {}' .format (bs .recipe_depends ))
2229
+ recipes_to_load = recipes_to_load .union (set (bs .recipe_depends ))
2230
+ recipes_to_load = list (recipes_to_load )
2231
+ recipe_loaded = []
2232
+ python_modules = []
2233
+ while recipes_to_load :
2234
+ name = recipes_to_load .pop (0 )
2235
+ if name in recipe_loaded or isinstance (name , (list , tuple )):
2236
+ continue
2237
+ try :
2238
+ recipe = Recipe .get_recipe (name , ctx )
2239
+ except ImportError :
2240
+ info ('No recipe named {}; will attempt to install with pip' .format (name ))
2241
+ python_modules .append (name )
2242
+ continue
2243
+ graph .add (name , name )
2244
+ info ('Loaded recipe {} (depends on {}{})' .format (
2245
+ name , recipe .depends ,
2246
+ ', conflicts {}' .format (recipe .conflicts ) if recipe .conflicts else '' ))
2247
+ for depend in recipe .depends :
2248
+ graph .add (name , depend )
2249
+ recipes_to_load += recipe .depends
2250
+ for conflict in recipe .conflicts :
2251
+ if graph .conflicts (conflict ):
2252
+ warning (
2253
+ ('{} conflicts with {}, but both have been '
2254
+ 'included or pulled into the requirements.' .format (recipe .name , conflict )))
2255
+ warning ('Due to this conflict the build cannot continue, exiting.' )
2256
+ exit (1 )
2257
+ recipe_loaded .append (name )
2258
+ graph .remove_remaining_conflicts (ctx )
2259
+ if len (graph .graphs ) > 1 :
2260
+ info ('Found multiple valid recipe sets:' )
2261
+ for g in graph .graphs :
2262
+ info (' {}' .format (g .keys ()))
2263
+ info_notify ('Using the first of these: {}' .format (graph .graphs [0 ].keys ()))
2264
+ elif len (graph .graphs ) == 0 :
2265
+ warning ('Didn\' t find any valid dependency graphs, exiting.' )
2266
+ exit (1 )
2267
+ else :
2268
+ info ('Found a single valid recipe set (this is good)' )
2269
+
2270
+ build_order = list (graph .find_order (0 ))
2271
+ if bs is None : # It would be better to check against possible
2272
+ # orders other than the first one, but in practice
2273
+ # there will rarely be clashes, and the user can
2274
+ # specify more parameters if necessary to resolve
2275
+ # them.
2276
+ bs = Bootstrap .get_bootstrap_from_recipes (build_order , ctx )
2277
+ if bs is None :
2278
+ info ('Could not find a bootstrap compatible with the required recipes.' )
2279
+ info ('If you think such a combination should exist, try '
2280
+ 'specifying the bootstrap manually with --bootstrap.' )
2281
+ exit (1 )
2282
+ info ('{} bootstrap appears compatible with the required recipes.' .format (bs .name ))
2283
+ info ('Checking this...' )
2284
+ recipes_to_load = bs .recipe_depends
2285
+ # This code repeats the code from earlier! Should move to a function:
2286
+ while recipes_to_load :
2287
+ name = recipes_to_load .pop (0 )
2288
+ if name in recipe_loaded or isinstance (name , (list , tuple )):
2289
+ continue
2290
+ try :
2291
+ recipe = Recipe .get_recipe (name , ctx )
2292
+ except ImportError :
2293
+ info ('No recipe named {}; will attempt to install with pip' .format (name ))
2294
+ python_modules .append (name )
2295
+ continue
2296
+ graph .add (name , name )
2297
+ info ('Loaded recipe {} (depends on {}{})' .format (
2298
+ name , recipe .depends ,
2299
+ ', conflicts {}' .format (recipe .conflicts ) if recipe .conflicts else '' ))
2300
+ for depend in recipe .depends :
2301
+ graph .add (name , depend )
2302
+ recipes_to_load += recipe .depends
2303
+ for conflict in recipe .conflicts :
2304
+ if graph .conflicts (conflict ):
2305
+ warning (
2306
+ ('{} conflicts with {}, but both have been '
2307
+ 'included or pulled into the requirements.' .format (recipe .name , conflict )))
2308
+ warning ('Due to this conflict the build cannot continue, exiting.' )
2309
+ exit (1 )
2310
+ recipe_loaded .append (name )
2311
+ graph .remove_remaining_conflicts (ctx )
2312
+ build_order = list (graph .find_order (0 ))
2313
+ return build_order , python_modules , bs
2314
+
2315
+ # Do a final check that the new bs doesn't pull in any conflicts
2316
+
2317
+
2220
2318
2221
2319
def split_argument_list (l ):
2222
2320
if not len (l ):
0 commit comments