summaryrefslogtreecommitdiffstats
path: root/scripts/lib/devtool/upgrade.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/lib/devtool/upgrade.py')
-rw-r--r--scripts/lib/devtool/upgrade.py246
1 files changed, 150 insertions, 96 deletions
diff --git a/scripts/lib/devtool/upgrade.py b/scripts/lib/devtool/upgrade.py
index 826a3f955f..d9aca6e2db 100644
--- a/scripts/lib/devtool/upgrade.py
+++ b/scripts/lib/devtool/upgrade.py
@@ -32,9 +32,11 @@ def _run(cmd, cwd=''):
32 32
33def _get_srctree(tmpdir): 33def _get_srctree(tmpdir):
34 srctree = tmpdir 34 srctree = tmpdir
35 dirs = scriptutils.filter_src_subdirs(tmpdir) 35 dirs = os.listdir(tmpdir)
36 if len(dirs) == 1: 36 if len(dirs) == 1:
37 srctree = os.path.join(tmpdir, dirs[0]) 37 srctree = os.path.join(tmpdir, dirs[0])
38 else:
39 raise DevtoolError("Cannot determine where the source tree is after unpacking in {}: {}".format(tmpdir,dirs))
38 return srctree 40 return srctree
39 41
40def _copy_source_code(orig, dest): 42def _copy_source_code(orig, dest):
@@ -74,21 +76,21 @@ def _rename_recipe_dirs(oldpv, newpv, path):
74 bb.utils.rename(os.path.join(path, oldfile), 76 bb.utils.rename(os.path.join(path, oldfile),
75 os.path.join(path, newfile)) 77 os.path.join(path, newfile))
76 78
77def _rename_recipe_file(oldrecipe, bpn, oldpv, newpv, path): 79def _rename_recipe_file(oldrecipe, pn, oldpv, newpv, path):
78 oldrecipe = os.path.basename(oldrecipe) 80 oldrecipe = os.path.basename(oldrecipe)
79 if oldrecipe.endswith('_%s.bb' % oldpv): 81 if oldrecipe.endswith('_%s.bb' % oldpv):
80 newrecipe = '%s_%s.bb' % (bpn, newpv) 82 newrecipe = '%s_%s.bb' % (pn, newpv)
81 if oldrecipe != newrecipe: 83 if oldrecipe != newrecipe:
82 shutil.move(os.path.join(path, oldrecipe), os.path.join(path, newrecipe)) 84 shutil.move(os.path.join(path, oldrecipe), os.path.join(path, newrecipe))
83 else: 85 else:
84 newrecipe = oldrecipe 86 newrecipe = oldrecipe
85 return os.path.join(path, newrecipe) 87 return os.path.join(path, newrecipe)
86 88
87def _rename_recipe_files(oldrecipe, bpn, oldpv, newpv, path): 89def _rename_recipe_files(oldrecipe, pn, oldpv, newpv, path):
88 _rename_recipe_dirs(oldpv, newpv, path) 90 _rename_recipe_dirs(oldpv, newpv, path)
89 return _rename_recipe_file(oldrecipe, bpn, oldpv, newpv, path) 91 return _rename_recipe_file(oldrecipe, pn, oldpv, newpv, path)
90 92
91def _write_append(rc, srctree, same_dir, no_same_dir, rev, copied, workspace, d): 93def _write_append(rc, srctreebase, srctree, same_dir, no_same_dir, revs, copied, workspace, d):
92 """Writes an append file""" 94 """Writes an append file"""
93 if not os.path.exists(rc): 95 if not os.path.exists(rc):
94 raise DevtoolError("bbappend not created because %s does not exist" % rc) 96 raise DevtoolError("bbappend not created because %s does not exist" % rc)
@@ -104,6 +106,11 @@ def _write_append(rc, srctree, same_dir, no_same_dir, rev, copied, workspace, d)
104 af = os.path.join(appendpath, '%s.bbappend' % brf) 106 af = os.path.join(appendpath, '%s.bbappend' % brf)
105 with open(af, 'w') as f: 107 with open(af, 'w') as f:
106 f.write('FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n\n') 108 f.write('FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n\n')
109 # Local files can be modified/tracked in separate subdir under srctree
110 # Mostly useful for packages with S != WORKDIR
111 f.write('FILESPATH:prepend := "%s:"\n' %
112 os.path.join(srctreebase, 'oe-local-files'))
113 f.write('# srctreebase: %s\n' % srctreebase)
107 f.write('inherit externalsrc\n') 114 f.write('inherit externalsrc\n')
108 f.write(('# NOTE: We use pn- overrides here to avoid affecting' 115 f.write(('# NOTE: We use pn- overrides here to avoid affecting'
109 'multiple variants in the case where the recipe uses BBCLASSEXTEND\n')) 116 'multiple variants in the case where the recipe uses BBCLASSEXTEND\n'))
@@ -112,27 +119,24 @@ def _write_append(rc, srctree, same_dir, no_same_dir, rev, copied, workspace, d)
112 if b_is_s: 119 if b_is_s:
113 f.write('EXTERNALSRC_BUILD:pn-%s = "%s"\n' % (pn, srctree)) 120 f.write('EXTERNALSRC_BUILD:pn-%s = "%s"\n' % (pn, srctree))
114 f.write('\n') 121 f.write('\n')
115 if rev: 122 if revs:
116 f.write('# initial_rev: %s\n' % rev) 123 for name, rev in revs.items():
124 f.write('# initial_rev %s: %s\n' % (name, rev))
117 if copied: 125 if copied:
118 f.write('# original_path: %s\n' % os.path.dirname(d.getVar('FILE'))) 126 f.write('# original_path: %s\n' % os.path.dirname(d.getVar('FILE')))
119 f.write('# original_files: %s\n' % ' '.join(copied)) 127 f.write('# original_files: %s\n' % ' '.join(copied))
120 return af 128 return af
121 129
122def _cleanup_on_error(rf, srctree): 130def _cleanup_on_error(rd, srctree):
123 rfp = os.path.split(rf)[0] # recipe folder 131 if os.path.exists(rd):
124 rfpp = os.path.split(rfp)[0] # recipes folder 132 shutil.rmtree(rd)
125 if os.path.exists(rfp):
126 shutil.rmtree(rfp)
127 if not len(os.listdir(rfpp)):
128 os.rmdir(rfpp)
129 srctree = os.path.abspath(srctree) 133 srctree = os.path.abspath(srctree)
130 if os.path.exists(srctree): 134 if os.path.exists(srctree):
131 shutil.rmtree(srctree) 135 shutil.rmtree(srctree)
132 136
133def _upgrade_error(e, rf, srctree, keep_failure=False, extramsg=None): 137def _upgrade_error(e, rd, srctree, keep_failure=False, extramsg=None):
134 if rf and not keep_failure: 138 if not keep_failure:
135 _cleanup_on_error(rf, srctree) 139 _cleanup_on_error(rd, srctree)
136 logger.error(e) 140 logger.error(e)
137 if extramsg: 141 if extramsg:
138 logger.error(extramsg) 142 logger.error(extramsg)
@@ -165,6 +169,7 @@ def _get_uri(rd):
165 169
166def _extract_new_source(newpv, srctree, no_patch, srcrev, srcbranch, branch, keep_temp, tinfoil, rd): 170def _extract_new_source(newpv, srctree, no_patch, srcrev, srcbranch, branch, keep_temp, tinfoil, rd):
167 """Extract sources of a recipe with a new version""" 171 """Extract sources of a recipe with a new version"""
172 import oe.patch
168 173
169 def __run(cmd): 174 def __run(cmd):
170 """Simple wrapper which calls _run with srctree as cwd""" 175 """Simple wrapper which calls _run with srctree as cwd"""
@@ -179,12 +184,16 @@ def _extract_new_source(newpv, srctree, no_patch, srcrev, srcbranch, branch, kee
179 uri, rev = _get_uri(crd) 184 uri, rev = _get_uri(crd)
180 if srcrev: 185 if srcrev:
181 rev = srcrev 186 rev = srcrev
187 paths = [srctree]
182 if uri.startswith('git://') or uri.startswith('gitsm://'): 188 if uri.startswith('git://') or uri.startswith('gitsm://'):
183 __run('git fetch') 189 __run('git fetch')
184 __run('git checkout %s' % rev) 190 __run('git checkout %s' % rev)
185 __run('git tag -f devtool-base-new') 191 __run('git tag -f --no-sign devtool-base-new')
186 md5 = None 192 __run('git submodule update --recursive')
187 sha256 = None 193 __run('git submodule foreach \'git tag -f --no-sign devtool-base-new\'')
194 (stdout, _) = __run('git submodule --quiet foreach \'echo $sm_path\'')
195 paths += [os.path.join(srctree, p) for p in stdout.splitlines()]
196 checksums = {}
188 _, _, _, _, _, params = bb.fetch2.decodeurl(uri) 197 _, _, _, _, _, params = bb.fetch2.decodeurl(uri)
189 srcsubdir_rel = params.get('destsuffix', 'git') 198 srcsubdir_rel = params.get('destsuffix', 'git')
190 if not srcbranch: 199 if not srcbranch:
@@ -192,14 +201,15 @@ def _extract_new_source(newpv, srctree, no_patch, srcrev, srcbranch, branch, kee
192 get_branch = [x.strip() for x in check_branch.splitlines()] 201 get_branch = [x.strip() for x in check_branch.splitlines()]
193 # Remove HEAD reference point and drop remote prefix 202 # Remove HEAD reference point and drop remote prefix
194 get_branch = [x.split('/', 1)[1] for x in get_branch if not x.startswith('origin/HEAD')] 203 get_branch = [x.split('/', 1)[1] for x in get_branch if not x.startswith('origin/HEAD')]
195 if 'master' in get_branch: 204 if len(get_branch) == 1:
196 # If it is master, we do not need to append 'branch=master' as this is default. 205 # If srcrev is on only ONE branch, then use that branch
197 # Even with the case where get_branch has multiple objects, if 'master' is one
198 # of them, we should default take from 'master'
199 srcbranch = ''
200 elif len(get_branch) == 1:
201 # If 'master' isn't in get_branch and get_branch contains only ONE object, then store result into 'srcbranch'
202 srcbranch = get_branch[0] 206 srcbranch = get_branch[0]
207 elif 'main' in get_branch:
208 # If srcrev is on multiple branches, then choose 'main' if it is one of them
209 srcbranch = 'main'
210 elif 'master' in get_branch:
211 # Otherwise choose 'master' if it is one of the branches
212 srcbranch = 'master'
203 else: 213 else:
204 # If get_branch contains more than one objects, then display error and exit. 214 # If get_branch contains more than one objects, then display error and exit.
205 mbrch = '\n ' + '\n '.join(get_branch) 215 mbrch = '\n ' + '\n '.join(get_branch)
@@ -216,9 +226,6 @@ def _extract_new_source(newpv, srctree, no_patch, srcrev, srcbranch, branch, kee
216 if ftmpdir and keep_temp: 226 if ftmpdir and keep_temp:
217 logger.info('Fetch temp directory is %s' % ftmpdir) 227 logger.info('Fetch temp directory is %s' % ftmpdir)
218 228
219 md5 = checksums['md5sum']
220 sha256 = checksums['sha256sum']
221
222 tmpsrctree = _get_srctree(tmpdir) 229 tmpsrctree = _get_srctree(tmpdir)
223 srctree = os.path.abspath(srctree) 230 srctree = os.path.abspath(srctree)
224 srcsubdir_rel = os.path.relpath(tmpsrctree, tmpdir) 231 srcsubdir_rel = os.path.relpath(tmpsrctree, tmpdir)
@@ -250,31 +257,52 @@ def _extract_new_source(newpv, srctree, no_patch, srcrev, srcbranch, branch, kee
250 useroptions = [] 257 useroptions = []
251 oe.patch.GitApplyTree.gitCommandUserOptions(useroptions, d=rd) 258 oe.patch.GitApplyTree.gitCommandUserOptions(useroptions, d=rd)
252 __run('git %s commit -q -m "Commit of upstream changes at version %s" --allow-empty' % (' '.join(useroptions), newpv)) 259 __run('git %s commit -q -m "Commit of upstream changes at version %s" --allow-empty' % (' '.join(useroptions), newpv))
253 __run('git tag -f devtool-base-%s' % newpv) 260 __run('git tag -f --no-sign devtool-base-%s' % newpv)
254 261
255 (stdout, _) = __run('git rev-parse HEAD') 262 revs = {}
256 rev = stdout.rstrip() 263 for path in paths:
264 (stdout, _) = _run('git rev-parse HEAD', cwd=path)
265 revs[os.path.relpath(path, srctree)] = stdout.rstrip()
257 266
258 if no_patch: 267 if no_patch:
259 patches = oe.recipeutils.get_recipe_patches(crd) 268 patches = oe.recipeutils.get_recipe_patches(crd)
260 if patches: 269 if patches:
261 logger.warning('By user choice, the following patches will NOT be applied to the new source tree:\n %s' % '\n '.join([os.path.basename(patch) for patch in patches])) 270 logger.warning('By user choice, the following patches will NOT be applied to the new source tree:\n %s' % '\n '.join([os.path.basename(patch) for patch in patches]))
262 else: 271 else:
263 __run('git checkout devtool-patched -b %s' % branch) 272 for path in paths:
264 (stdout, _) = __run('git branch --list devtool-override-*') 273 _run('git checkout devtool-patched -b %s' % branch, cwd=path)
265 branches_to_rebase = [branch] + stdout.split() 274 (stdout, _) = _run('git branch --list devtool-override-*', cwd=path)
266 for b in branches_to_rebase: 275 branches_to_rebase = [branch] + stdout.split()
267 logger.info("Rebasing {} onto {}".format(b, rev)) 276 target_branch = revs[os.path.relpath(path, srctree)]
268 __run('git checkout %s' % b) 277
269 try: 278 # There is a bug (or feature?) in git rebase where if a commit with
270 __run('git rebase %s' % rev) 279 # a note is fully rebased away by being part of an old commit, the
271 except bb.process.ExecutionError as e: 280 # note is still attached to the old commit. Avoid this by making
272 if 'conflict' in e.stdout: 281 # sure all old devtool related commits have a note attached to them
273 logger.warning('Command \'%s\' failed:\n%s\n\nYou will need to resolve conflicts in order to complete the upgrade.' % (e.command, e.stdout.rstrip())) 282 # (this assumes git config notes.rewriteMode is set to ignore).
274 __run('git rebase --abort') 283 (stdout, _) = __run('git rev-list devtool-base..%s' % target_branch)
275 else: 284 for rev in stdout.splitlines():
276 logger.warning('Command \'%s\' failed:\n%s' % (e.command, e.stdout)) 285 if not oe.patch.GitApplyTree.getNotes(path, rev):
277 __run('git checkout %s' % branch) 286 oe.patch.GitApplyTree.addNote(path, rev, "dummy")
287
288 for b in branches_to_rebase:
289 logger.info("Rebasing {} onto {}".format(b, target_branch))
290 _run('git checkout %s' % b, cwd=path)
291 try:
292 _run('git rebase %s' % target_branch, cwd=path)
293 except bb.process.ExecutionError as e:
294 if 'conflict' in e.stdout:
295 logger.warning('Command \'%s\' failed:\n%s\n\nYou will need to resolve conflicts in order to complete the upgrade.' % (e.command, e.stdout.rstrip()))
296 _run('git rebase --abort', cwd=path)
297 else:
298 logger.warning('Command \'%s\' failed:\n%s' % (e.command, e.stdout))
299
300 # Remove any dummy notes added above.
301 (stdout, _) = __run('git rev-list devtool-base..%s' % target_branch)
302 for rev in stdout.splitlines():
303 oe.patch.GitApplyTree.removeNote(path, rev, "dummy")
304
305 _run('git checkout %s' % branch, cwd=path)
278 306
279 if tmpsrctree: 307 if tmpsrctree:
280 if keep_temp: 308 if keep_temp:
@@ -284,7 +312,7 @@ def _extract_new_source(newpv, srctree, no_patch, srcrev, srcbranch, branch, kee
284 if tmpdir != tmpsrctree: 312 if tmpdir != tmpsrctree:
285 shutil.rmtree(tmpdir) 313 shutil.rmtree(tmpdir)
286 314
287 return (rev, md5, sha256, srcbranch, srcsubdir_rel) 315 return (revs, checksums, srcbranch, srcsubdir_rel)
288 316
289def _add_license_diff_to_recipe(path, diff): 317def _add_license_diff_to_recipe(path, diff):
290 notice_text = """# FIXME: the LIC_FILES_CHKSUM values have been updated by 'devtool upgrade'. 318 notice_text = """# FIXME: the LIC_FILES_CHKSUM values have been updated by 'devtool upgrade'.
@@ -305,22 +333,22 @@ def _add_license_diff_to_recipe(path, diff):
305 f.write("\n#\n\n".encode()) 333 f.write("\n#\n\n".encode())
306 f.write(orig_content) 334 f.write(orig_content)
307 335
308def _create_new_recipe(newpv, md5, sha256, srcrev, srcbranch, srcsubdir_old, srcsubdir_new, workspace, tinfoil, rd, license_diff, new_licenses, srctree, keep_failure): 336def _create_new_recipe(newpv, checksums, srcrev, srcbranch, srcsubdir_old, srcsubdir_new, workspace, tinfoil, rd, license_diff, new_licenses, srctree, keep_failure):
309 """Creates the new recipe under workspace""" 337 """Creates the new recipe under workspace"""
310 338
311 bpn = rd.getVar('BPN') 339 pn = rd.getVar('PN')
312 path = os.path.join(workspace, 'recipes', bpn) 340 path = os.path.join(workspace, 'recipes', pn)
313 bb.utils.mkdirhier(path) 341 bb.utils.mkdirhier(path)
314 copied, _ = oe.recipeutils.copy_recipe_files(rd, path, all_variants=True) 342 copied, _ = oe.recipeutils.copy_recipe_files(rd, path, all_variants=True)
315 if not copied: 343 if not copied:
316 raise DevtoolError('Internal error - no files were copied for recipe %s' % bpn) 344 raise DevtoolError('Internal error - no files were copied for recipe %s' % pn)
317 logger.debug('Copied %s to %s' % (copied, path)) 345 logger.debug('Copied %s to %s' % (copied, path))
318 346
319 oldpv = rd.getVar('PV') 347 oldpv = rd.getVar('PV')
320 if not newpv: 348 if not newpv:
321 newpv = oldpv 349 newpv = oldpv
322 origpath = rd.getVar('FILE') 350 origpath = rd.getVar('FILE')
323 fullpath = _rename_recipe_files(origpath, bpn, oldpv, newpv, path) 351 fullpath = _rename_recipe_files(origpath, pn, oldpv, newpv, path)
324 logger.debug('Upgraded %s => %s' % (origpath, fullpath)) 352 logger.debug('Upgraded %s => %s' % (origpath, fullpath))
325 353
326 newvalues = {} 354 newvalues = {}
@@ -336,7 +364,10 @@ def _create_new_recipe(newpv, md5, sha256, srcrev, srcbranch, srcsubdir_old, src
336 replacing = True 364 replacing = True
337 new_src_uri = [] 365 new_src_uri = []
338 for entry in src_uri: 366 for entry in src_uri:
339 scheme, network, path, user, passwd, params = bb.fetch2.decodeurl(entry) 367 try:
368 scheme, network, path, user, passwd, params = bb.fetch2.decodeurl(entry)
369 except bb.fetch2.MalformedUrl as e:
370 raise DevtoolError("Could not decode SRC_URI: {}".format(e))
340 if replacing and scheme in ['git', 'gitsm']: 371 if replacing and scheme in ['git', 'gitsm']:
341 branch = params.get('branch', 'master') 372 branch = params.get('branch', 'master')
342 if rd.expand(branch) != srcbranch: 373 if rd.expand(branch) != srcbranch:
@@ -374,30 +405,39 @@ def _create_new_recipe(newpv, md5, sha256, srcrev, srcbranch, srcsubdir_old, src
374 addnames.append(params['name']) 405 addnames.append(params['name'])
375 # Find what's been set in the original recipe 406 # Find what's been set in the original recipe
376 oldnames = [] 407 oldnames = []
408 oldsums = []
377 noname = False 409 noname = False
378 for varflag in rd.getVarFlags('SRC_URI'): 410 for varflag in rd.getVarFlags('SRC_URI'):
379 if varflag.endswith(('.md5sum', '.sha256sum')): 411 for checksum in checksums:
380 name = varflag.rsplit('.', 1)[0] 412 if varflag.endswith('.' + checksum):
381 if name not in oldnames: 413 name = varflag.rsplit('.', 1)[0]
382 oldnames.append(name) 414 if name not in oldnames:
383 elif varflag in ['md5sum', 'sha256sum']: 415 oldnames.append(name)
384 noname = True 416 oldsums.append(checksum)
417 elif varflag == checksum:
418 noname = True
419 oldsums.append(checksum)
385 # Even if SRC_URI has named entries it doesn't have to actually use the name 420 # Even if SRC_URI has named entries it doesn't have to actually use the name
386 if noname and addnames and addnames[0] not in oldnames: 421 if noname and addnames and addnames[0] not in oldnames:
387 addnames = [] 422 addnames = []
388 # Drop any old names (the name actually might include ${PV}) 423 # Drop any old names (the name actually might include ${PV})
389 for name in oldnames: 424 for name in oldnames:
390 if name not in newnames: 425 if name not in newnames:
391 newvalues['SRC_URI[%s.md5sum]' % name] = None 426 for checksum in oldsums:
392 newvalues['SRC_URI[%s.sha256sum]' % name] = None 427 newvalues['SRC_URI[%s.%s]' % (name, checksum)] = None
393 428
394 if sha256: 429 nameprefix = '%s.' % addnames[0] if addnames else ''
395 if addnames: 430
396 nameprefix = '%s.' % addnames[0] 431 # md5sum is deprecated, remove any traces of it. If it was the only old
397 else: 432 # checksum, then replace it with the default checksums.
398 nameprefix = '' 433 if 'md5sum' in oldsums:
399 newvalues['SRC_URI[%smd5sum]' % nameprefix] = None 434 newvalues['SRC_URI[%smd5sum]' % nameprefix] = None
400 newvalues['SRC_URI[%ssha256sum]' % nameprefix] = sha256 435 oldsums.remove('md5sum')
436 if not oldsums:
437 oldsums = ["%ssum" % s for s in bb.fetch2.SHOWN_CHECKSUM_LIST]
438
439 for checksum in oldsums:
440 newvalues['SRC_URI[%s%s]' % (nameprefix, checksum)] = checksums[checksum]
401 441
402 if srcsubdir_new != srcsubdir_old: 442 if srcsubdir_new != srcsubdir_old:
403 s_subdir_old = os.path.relpath(os.path.abspath(rd.getVar('S')), rd.getVar('WORKDIR')) 443 s_subdir_old = os.path.relpath(os.path.abspath(rd.getVar('S')), rd.getVar('WORKDIR'))
@@ -422,10 +462,11 @@ def _create_new_recipe(newpv, md5, sha256, srcrev, srcbranch, srcsubdir_old, src
422 newvalues["LIC_FILES_CHKSUM"] = newlicchksum 462 newvalues["LIC_FILES_CHKSUM"] = newlicchksum
423 _add_license_diff_to_recipe(fullpath, license_diff) 463 _add_license_diff_to_recipe(fullpath, license_diff)
424 464
465 tinfoil.modified_files()
425 try: 466 try:
426 rd = tinfoil.parse_recipe_file(fullpath, False) 467 rd = tinfoil.parse_recipe_file(fullpath, False)
427 except bb.tinfoil.TinfoilCommandFailed as e: 468 except bb.tinfoil.TinfoilCommandFailed as e:
428 _upgrade_error(e, fullpath, srctree, keep_failure, 'Parsing of upgraded recipe failed') 469 _upgrade_error(e, os.path.dirname(fullpath), srctree, keep_failure, 'Parsing of upgraded recipe failed')
429 oe.recipeutils.patch_recipe(rd, fullpath, newvalues) 470 oe.recipeutils.patch_recipe(rd, fullpath, newvalues)
430 471
431 return fullpath, copied 472 return fullpath, copied
@@ -434,7 +475,7 @@ def _create_new_recipe(newpv, md5, sha256, srcrev, srcbranch, srcsubdir_old, src
434def _check_git_config(): 475def _check_git_config():
435 def getconfig(name): 476 def getconfig(name):
436 try: 477 try:
437 value = bb.process.run('git config --global %s' % name)[0].strip() 478 value = bb.process.run('git config %s' % name)[0].strip()
438 except bb.process.ExecutionError as e: 479 except bb.process.ExecutionError as e:
439 if e.exitcode == 1: 480 if e.exitcode == 1:
440 value = None 481 value = None
@@ -494,6 +535,15 @@ def _generate_license_diff(old_licenses, new_licenses):
494 diff = diff + line 535 diff = diff + line
495 return diff 536 return diff
496 537
538def _run_recipe_upgrade_extra_tasks(pn, rd, tinfoil):
539 tasks = []
540 for task in (rd.getVar('RECIPE_UPGRADE_EXTRA_TASKS') or '').split():
541 logger.info('Running extra recipe upgrade task: %s' % task)
542 res = tinfoil.build_targets(pn, task, handle_events=True)
543
544 if not res:
545 raise DevtoolError('Running extra recipe upgrade task %s for %s failed' % (task, pn))
546
497def upgrade(args, config, basepath, workspace): 547def upgrade(args, config, basepath, workspace):
498 """Entry point for the devtool 'upgrade' subcommand""" 548 """Entry point for the devtool 'upgrade' subcommand"""
499 549
@@ -521,14 +571,7 @@ def upgrade(args, config, basepath, workspace):
521 else: 571 else:
522 srctree = standard.get_default_srctree(config, pn) 572 srctree = standard.get_default_srctree(config, pn)
523 573
524 # Check that recipe isn't using a shared workdir 574 srctree_s = standard.get_real_srctree(srctree, rd.getVar('S'), rd.getVar('UNPACKDIR'))
525 s = os.path.abspath(rd.getVar('S'))
526 workdir = os.path.abspath(rd.getVar('WORKDIR'))
527 srctree_s = srctree
528 if s.startswith(workdir) and s != workdir and os.path.dirname(s) != workdir:
529 # Handle if S is set to a subdirectory of the source
530 srcsubdir = os.path.relpath(s, workdir).split(os.sep, 1)[1]
531 srctree_s = os.path.join(srctree, srcsubdir)
532 575
533 # try to automatically discover latest version and revision if not provided on command line 576 # try to automatically discover latest version and revision if not provided on command line
534 if not args.version and not args.srcrev: 577 if not args.version and not args.srcrev:
@@ -561,22 +604,23 @@ def upgrade(args, config, basepath, workspace):
561 rev1, srcsubdir1 = standard._extract_source(srctree, False, 'devtool-orig', False, config, basepath, workspace, args.fixed_setup, rd, tinfoil, no_overrides=args.no_overrides) 604 rev1, srcsubdir1 = standard._extract_source(srctree, False, 'devtool-orig', False, config, basepath, workspace, args.fixed_setup, rd, tinfoil, no_overrides=args.no_overrides)
562 old_licenses = _extract_licenses(srctree_s, (rd.getVar('LIC_FILES_CHKSUM') or "")) 605 old_licenses = _extract_licenses(srctree_s, (rd.getVar('LIC_FILES_CHKSUM') or ""))
563 logger.info('Extracting upgraded version source...') 606 logger.info('Extracting upgraded version source...')
564 rev2, md5, sha256, srcbranch, srcsubdir2 = _extract_new_source(args.version, srctree, args.no_patch, 607 rev2, checksums, srcbranch, srcsubdir2 = _extract_new_source(args.version, srctree, args.no_patch,
565 args.srcrev, args.srcbranch, args.branch, args.keep_temp, 608 args.srcrev, args.srcbranch, args.branch, args.keep_temp,
566 tinfoil, rd) 609 tinfoil, rd)
567 new_licenses = _extract_licenses(srctree_s, (rd.getVar('LIC_FILES_CHKSUM') or "")) 610 new_licenses = _extract_licenses(srctree_s, (rd.getVar('LIC_FILES_CHKSUM') or ""))
568 license_diff = _generate_license_diff(old_licenses, new_licenses) 611 license_diff = _generate_license_diff(old_licenses, new_licenses)
569 rf, copied = _create_new_recipe(args.version, md5, sha256, args.srcrev, srcbranch, srcsubdir1, srcsubdir2, config.workspace_path, tinfoil, rd, license_diff, new_licenses, srctree, args.keep_failure) 612 rf, copied = _create_new_recipe(args.version, checksums, args.srcrev, srcbranch, srcsubdir1, srcsubdir2, config.workspace_path, tinfoil, rd, license_diff, new_licenses, srctree, args.keep_failure)
570 except bb.process.CmdError as e: 613 except (bb.process.CmdError, DevtoolError) as e:
571 _upgrade_error(e, rf, srctree, args.keep_failure) 614 recipedir = os.path.join(config.workspace_path, 'recipes', rd.getVar('PN'))
572 except DevtoolError as e: 615 _upgrade_error(e, recipedir, srctree, args.keep_failure)
573 _upgrade_error(e, rf, srctree, args.keep_failure)
574 standard._add_md5(config, pn, os.path.dirname(rf)) 616 standard._add_md5(config, pn, os.path.dirname(rf))
575 617
576 af = _write_append(rf, srctree_s, args.same_dir, args.no_same_dir, rev2, 618 af = _write_append(rf, srctree, srctree_s, args.same_dir, args.no_same_dir, rev2,
577 copied, config.workspace_path, rd) 619 copied, config.workspace_path, rd)
578 standard._add_md5(config, pn, af) 620 standard._add_md5(config, pn, af)
579 621
622 _run_recipe_upgrade_extra_tasks(pn, rd, tinfoil)
623
580 update_unlockedsigs(basepath, workspace, args.fixed_setup, [pn]) 624 update_unlockedsigs(basepath, workspace, args.fixed_setup, [pn])
581 625
582 logger.info('Upgraded source extracted to %s' % srctree) 626 logger.info('Upgraded source extracted to %s' % srctree)
@@ -611,18 +655,28 @@ def latest_version(args, config, basepath, workspace):
611 return 0 655 return 0
612 656
613def check_upgrade_status(args, config, basepath, workspace): 657def check_upgrade_status(args, config, basepath, workspace):
658 def _print_status(recipe):
659 print("{:25} {:15} {:15} {} {} {}".format( recipe['pn'],
660 recipe['cur_ver'],
661 recipe['status'] if recipe['status'] != 'UPDATE' else (recipe['next_ver'] if not recipe['next_ver'].endswith("new-commits-available") else "new commits"),
662 recipe['maintainer'],
663 recipe['revision'] if recipe['revision'] != 'N/A' else "",
664 "cannot be updated due to: %s" %(recipe['no_upgrade_reason']) if recipe['no_upgrade_reason'] else ""))
614 if not args.recipe: 665 if not args.recipe:
615 logger.info("Checking the upstream status for all recipes may take a few minutes") 666 logger.info("Checking the upstream status for all recipes may take a few minutes")
616 results = oe.recipeutils.get_recipe_upgrade_status(args.recipe) 667 results = oe.recipeutils.get_recipe_upgrade_status(args.recipe)
617 for result in results: 668 for recipegroup in results:
618 # pn, update_status, current, latest, maintainer, latest_commit, no_update_reason 669 upgrades = [r for r in recipegroup if r['status'] != 'MATCH']
619 if args.all or result[1] != 'MATCH': 670 currents = [r for r in recipegroup if r['status'] == 'MATCH']
620 logger.info("{:25} {:15} {:15} {} {} {}".format( result[0], 671 if len(upgrades) > 1:
621 result[2], 672 print("These recipes need to be upgraded together {")
622 result[1] if result[1] != 'UPDATE' else (result[3] if not result[3].endswith("new-commits-available") else "new commits"), 673 for r in sorted(upgrades, key=lambda r:r['pn']):
623 result[4], 674 _print_status(r)
624 result[5] if result[5] != 'N/A' else "", 675 if len(upgrades) > 1:
625 "cannot be updated due to: %s" %(result[6]) if result[6] else "")) 676 print("}")
677 for r in currents:
678 if args.all:
679 _print_status(r)
626 680
627def register_commands(subparsers, context): 681def register_commands(subparsers, context):
628 """Register devtool subcommands from this plugin""" 682 """Register devtool subcommands from this plugin"""