3
3
import json
4
4
5
5
from pythonforandroid import __version__
6
- from pythonforandroid .logger import (info , info_notify , warning , Err_Style , Err_Fore )
6
+ from pythonforandroid .logger import (
7
+ info , debug , info_notify , warning , Err_Style , Err_Fore
8
+ )
7
9
from pythonforandroid .util import current_directory , BuildInterruptingException
10
+ from pythonforandroid .recipe import Recipe
8
11
from shutil import rmtree
9
12
10
13
@@ -30,7 +33,11 @@ class Distribution(object):
30
33
archs = []
31
34
'''The arch targets that the dist is built for.'''
32
35
33
- recipes = []
36
+ recipes = {}
37
+ '''A dictionary which holds recipes information. Each key is the name of
38
+ the recipe, and the value is recipe's version'''
39
+
40
+ recipes_to_rebuild = set ()
34
41
35
42
description = '' # A long description
36
43
@@ -88,6 +95,8 @@ def get_distribution(cls, ctx, name=None, recipes=[],
88
95
89
96
req_archs = [arch .arch for arch in ctx .archs ]
90
97
98
+ recipes_with_version = cls .get_recipes_with_version (ctx , recipes )
99
+
91
100
# 0) Check if a dist with that name already exists
92
101
if name is not None and name :
93
102
possible_dists = [d for d in possible_dists if d .name == name ]
@@ -106,10 +115,38 @@ def get_distribution(cls, ctx, name=None, recipes=[],
106
115
]
107
116
):
108
117
continue
109
- for recipe in recipes :
110
- if recipe not in dist .recipes :
118
+ checked_dist_recipes = set ()
119
+ for recipe_name , recipe_version in recipes_with_version .items ():
120
+ if recipe_name not in dist .recipes .keys ():
111
121
break
122
+ debug ('Checking version for {} recipe: {} VS {}' .format (
123
+ recipe_name , dist .recipes [recipe_name ], recipe_version )
124
+ )
125
+ if dist .recipes [recipe_name ] != recipe_version :
126
+ warning (
127
+ 'Recipe {} has a newer version, '
128
+ 'adding it to recipes_to_rebuild' .format (recipe_name )
129
+ )
130
+ dist .recipes_to_rebuild .add (recipe_name )
131
+ checked_dist_recipes .add (recipe_name )
112
132
else :
133
+ # Check that the dist recipes has not changed (without
134
+ # considering the ones we already computed above)
135
+ for recipe_name , recipe_version in dist .recipes .items ():
136
+ if recipe_name in dist .recipes_to_rebuild :
137
+ continue
138
+ try :
139
+ test_recipe = Recipe .get_recipe (recipe_name , ctx )
140
+ except ValueError :
141
+ # we don't have a recipe so skipping it
142
+ continue
143
+ if test_recipe .version != recipe_version :
144
+ warning (
145
+ 'Recipe {} has a newer version,'
146
+ ' adding to rebuild' .format (recipe_name )
147
+ )
148
+ dist .recipes_to_rebuild .add (recipe_name )
149
+
113
150
_possible_dists .append (dist )
114
151
possible_dists = _possible_dists
115
152
@@ -125,16 +162,25 @@ def get_distribution(cls, ctx, name=None, recipes=[],
125
162
for dist in possible_dists :
126
163
if force_build :
127
164
continue
128
- if (set (dist .recipes ) == set (recipes ) or
129
- (set (recipes ).issubset (set (dist .recipes )) and
130
- not require_perfect_match )):
165
+ if set (dist .recipes .keys ()) == set (recipes ) or (
166
+ set (recipes ).issubset (set (dist .recipes .keys ()))
167
+ and not require_perfect_match
168
+ ):
131
169
info_notify ('{} has compatible recipes, using this one'
132
170
.format (dist .name ))
133
171
if dist .p4a_version != __version__ :
134
172
# We build this dist with a different version of p4a, so
135
173
# we mark it as a dist that requires a clean build environ
136
174
# (to avoid old cached builds issues)
137
175
dist .needs_clean_build = True
176
+ elif dist .recipes_to_rebuild :
177
+ dist .needs_build = True
178
+ info_notify (
179
+ 'Some of the recipes has new versions,'
180
+ ' we will update them:\n \t - {}' .format (
181
+ '\n \t - ' .join (dist .recipes_to_rebuild )
182
+ )
183
+ )
138
184
return dist
139
185
140
186
assert len (possible_dists ) < 2
@@ -180,7 +226,7 @@ def get_distribution(cls, ctx, name=None, recipes=[],
180
226
181
227
dist .name = name
182
228
dist .dist_dir = join (ctx .dist_dir , dist .name )
183
- dist .recipes = recipes
229
+ dist .recipes = recipes_with_version
184
230
dist .archs = req_archs
185
231
dist .ndk_api = ctx .ndk_api
186
232
dist .android_api = ctx .android_api
@@ -232,38 +278,70 @@ def get_distributions(cls, ctx, extra_dist_dirs=[]):
232
278
dists .append (dist )
233
279
return dists
234
280
281
+ @classmethod
282
+ def get_recipes_with_version (cls , ctx , recipes_names ):
283
+ recipes_with_version = {}
284
+ for name in recipes_names :
285
+ try :
286
+ version = Recipe .get_recipe (name , ctx ).version
287
+ except ValueError :
288
+ # we don't have a recipe (it's a pure python module, and we
289
+ # don't know the version, so we set it to None)
290
+ version = None
291
+ recipes_with_version [name ] = version
292
+ return recipes_with_version
293
+
235
294
def save_info (self , dirn ):
236
295
'''
237
296
Save information about the distribution in its dist_dir.
238
297
'''
239
298
with current_directory (dirn ):
240
299
info ('Saving distribution info' )
300
+ # Add version to recipes, so we can detect
301
+ # any change and rebuild them if necessary
302
+ recipes_with_version = self .get_recipes_with_version (
303
+ self .ctx , self .ctx .recipe_build_order + self .ctx .python_modules
304
+ )
305
+ py_version = self .ctx .python_recipe .major_minor_version_string
241
306
with open ('dist_info.json' , 'w' ) as fileh :
242
- json .dump ({'dist_name' : self .ctx .dist_name ,
243
- 'bootstrap' : self .ctx .bootstrap .name ,
244
- 'archs' : [arch .arch for arch in self .ctx .archs ],
245
- 'ndk_api' : self .ctx .ndk_api ,
246
- 'android_api' : self .ctx .android_api ,
247
- 'use_setup_py' : self .ctx .use_setup_py ,
248
- 'recipes' : self .ctx .recipe_build_order + self .ctx .python_modules ,
249
- 'hostpython' : self .ctx .hostpython ,
250
- 'python_version' : self .ctx .python_recipe .major_minor_version_string ,
251
- 'p4a_version' : __version__ },
252
- fileh )
307
+ json .dump (
308
+ {
309
+ 'dist_name' : self .ctx .dist_name ,
310
+ 'bootstrap' : self .ctx .bootstrap .name ,
311
+ 'archs' : [arch .arch for arch in self .ctx .archs ],
312
+ 'ndk_api' : self .ctx .ndk_api ,
313
+ 'android_api' : self .ctx .android_api ,
314
+ 'use_setup_py' : self .ctx .use_setup_py ,
315
+ 'recipes' : recipes_with_version ,
316
+ 'hostpython' : self .ctx .hostpython ,
317
+ 'python_version' : py_version ,
318
+ 'p4a_version' : __version__ ,
319
+ },
320
+ fileh ,
321
+ indent = 4 ,
322
+ sort_keys = True ,
323
+ )
253
324
254
325
255
326
def pretty_log_dists (dists , log_func = info ):
256
327
infos = []
257
328
for dist in dists :
258
329
ndk_api = 'unknown' if dist .ndk_api is None else dist .ndk_api
259
- infos .append ('{Fore.GREEN}{Style.BRIGHT}{name}{Style.RESET_ALL}: min API {ndk_api}, '
260
- 'includes recipes ({Fore.GREEN}{recipes}'
261
- '{Style.RESET_ALL}), built for archs ({Fore.BLUE}'
262
- '{archs}{Style.RESET_ALL})' .format (
263
- ndk_api = ndk_api ,
264
- name = dist .name , recipes = ', ' .join (dist .recipes ),
265
- archs = ', ' .join (dist .archs ) if dist .archs else 'UNKNOWN' ,
266
- Fore = Err_Fore , Style = Err_Style ))
330
+ infos .append (
331
+ '{Fore.GREEN}{Style.BRIGHT}{name}{Style.RESET_ALL}: '
332
+ 'min API {ndk_api}, '
333
+ 'includes recipes ({Fore.GREEN}{recipes}{Style.RESET_ALL}), '
334
+ 'recipes to rebuild({Fore.GREEN}{to_rebuild}{Style.RESET_ALL}), '
335
+ 'built for archs ({Fore.BLUE}{archs}{Style.RESET_ALL})' .format (
336
+ ndk_api = ndk_api ,
337
+ name = dist .name ,
338
+ recipes = ", " .join ("{}" .format (k ) for k in dist .recipes .keys ()),
339
+ to_rebuild = ", " .join (dist .recipes_to_rebuild ),
340
+ archs = ', ' .join (dist .archs ) if dist .archs else 'UNKNOWN' ,
341
+ Fore = Err_Fore ,
342
+ Style = Err_Style ,
343
+ )
344
+ )
267
345
268
346
for line in infos :
269
347
log_func ('\t ' + line )
0 commit comments