lib/oe/recipeutils: refactor patch_recipe_file() to use edit_metadata()

Use bb.utils.edit_metadata() to replace some of the logic in this
function; this avoids us effectively having two implementations of the
same thing. In the process fix the following issues:

* Insert values before any leading comments for the next variable
  instead of after them
* Insert overridden variables (e.g. RDEPENDS_${PN}) in the correct place
* Properly handle replacing varflag settings (e.g. SRC_URI[md5sum])

(From OE-Core rev: 0f81b83fc5fd908efa7f6b837137830ca65f6ed6)

Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
Signed-off-by: Ross Burton <ross.burton@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Paul Eggleton 2015-05-18 12:04:55 +01:00 committed by Richard Purdie
parent 0b850cb231
commit 1fbd76093d
2 changed files with 94 additions and 90 deletions

View File

@ -19,9 +19,9 @@ from collections import OrderedDict, defaultdict
# Help us to find places to insert values
recipe_progression = ['SUMMARY', 'DESCRIPTION', 'HOMEPAGE', 'BUGTRACKER', 'SECTION', 'LICENSE', 'LIC_FILES_CHKSUM', 'PROVIDES', 'DEPENDS', 'PR', 'PV', 'SRCREV', 'SRC_URI', 'S', 'do_fetch', 'do_unpack', 'do_patch', 'EXTRA_OECONF', 'do_configure', 'EXTRA_OEMAKE', 'do_compile', 'do_install', 'do_populate_sysroot', 'INITSCRIPT', 'USERADD', 'GROUPADD', 'PACKAGES', 'FILES', 'RDEPENDS', 'RRECOMMENDS', 'RSUGGESTS', 'RPROVIDES', 'RREPLACES', 'RCONFLICTS', 'ALLOW_EMPTY', 'do_package', 'do_deploy']
recipe_progression = ['SUMMARY', 'DESCRIPTION', 'HOMEPAGE', 'BUGTRACKER', 'SECTION', 'LICENSE', 'LIC_FILES_CHKSUM', 'PROVIDES', 'DEPENDS', 'PR', 'PV', 'SRCREV', 'SRC_URI', 'S', 'do_fetch()', 'do_unpack()', 'do_patch()', 'EXTRA_OECONF', 'do_configure()', 'EXTRA_OEMAKE', 'do_compile()', 'do_install()', 'do_populate_sysroot()', 'INITSCRIPT', 'USERADD', 'GROUPADD', 'PACKAGES', 'FILES', 'RDEPENDS', 'RRECOMMENDS', 'RSUGGESTS', 'RPROVIDES', 'RREPLACES', 'RCONFLICTS', 'ALLOW_EMPTY', 'do_package()', 'do_deploy()']
# Variables that sometimes are a bit long but shouldn't be wrapped
nowrap_vars = ['SUMMARY', 'HOMEPAGE', 'BUGTRACKER']
nowrap_vars = ['SUMMARY', 'HOMEPAGE', 'BUGTRACKER', 'SRC_URI[md5sum]', 'SRC_URI[sha256sum]']
list_vars = ['SRC_URI', 'LIC_FILES_CHKSUM']
meta_vars = ['SUMMARY', 'DESCRIPTION', 'HOMEPAGE', 'BUGTRACKER', 'SECTION']
@ -164,85 +164,111 @@ def patch_recipe_file(fn, values, patch=False, relpath=''):
Note that some manual inspection/intervention may be required
since this cannot handle all situations.
"""
import bb.utils
recipe_progression_res = []
recipe_progression_restrs = []
for item in recipe_progression:
if item.endswith('()'):
key = item[:-2]
else:
key = item
restr = '%s(_[a-zA-Z0-9-_$(){}]+|\[[^\]]*\])?' % key
if item.endswith('()'):
recipe_progression_restrs.append(restr + '()')
else:
recipe_progression_restrs.append(restr)
recipe_progression_res.append(re.compile('^%s$' % restr))
def get_recipe_pos(variable):
for i, p in enumerate(recipe_progression_res):
if p.match(variable):
return i
return -1
remainingnames = {}
for k in values.keys():
remainingnames[k] = recipe_progression.index(k) if k in recipe_progression else -1
remainingnames[k] = get_recipe_pos(k)
remainingnames = OrderedDict(sorted(remainingnames.iteritems(), key=lambda x: x[1]))
with tempfile.NamedTemporaryFile('w', delete=False) as tf:
def outputvalue(name):
rawtext = '%s = "%s"\n' % (name, values[name])
if name in nowrap_vars:
tf.write(rawtext)
elif name in list_vars:
splitvalue = split_var_value(values[name], assignment=False)
if len(splitvalue) > 1:
linesplit = ' \\\n' + (' ' * (len(name) + 4))
tf.write('%s = "%s%s"\n' % (name, linesplit.join(splitvalue), linesplit))
else:
tf.write(rawtext)
modifying = False
def outputvalue(name, lines, rewindcomments=False):
if values[name] is None:
return
rawtext = '%s = "%s"\n' % (name, values[name])
addlines = []
if name in nowrap_vars:
addlines.append(rawtext)
elif name in list_vars:
splitvalue = split_var_value(values[name], assignment=False)
if len(splitvalue) > 1:
linesplit = ' \\\n' + (' ' * (len(name) + 4))
addlines.append('%s = "%s%s"\n' % (name, linesplit.join(splitvalue), linesplit))
else:
wrapped = textwrap.wrap(rawtext)
for wrapline in wrapped[:-1]:
tf.write('%s \\\n' % wrapline)
tf.write('%s\n' % wrapped[-1])
addlines.append(rawtext)
else:
wrapped = textwrap.wrap(rawtext)
for wrapline in wrapped[:-1]:
addlines.append('%s \\\n' % wrapline)
addlines.append('%s\n' % wrapped[-1])
if rewindcomments:
# Ensure we insert the lines before any leading comments
# (that we'd want to ensure remain leading the next value)
for i, ln in reversed(list(enumerate(lines))):
if ln[0] != '#':
lines[i+1:i+1] = addlines
break
else:
lines.extend(addlines)
else:
lines.extend(addlines)
tfn = tf.name
with open(fn, 'r') as f:
# First runthrough - find existing names (so we know not to insert based on recipe_progression)
# Second runthrough - make the changes
existingnames = []
for runthrough in [1, 2]:
currname = None
for line in f:
if not currname:
insert = False
for k in remainingnames.keys():
for p in recipe_progression:
if re.match('^%s(_prepend|_append)*[ ?:=(]' % p, line):
if remainingnames[k] > -1 and recipe_progression.index(p) > remainingnames[k] and runthrough > 1 and not k in existingnames:
outputvalue(k)
del remainingnames[k]
break
for k in remainingnames.keys():
if re.match('^%s[ ?:=]' % k, line):
currname = k
if runthrough == 1:
existingnames.append(k)
else:
del remainingnames[k]
break
if currname and runthrough > 1:
outputvalue(currname)
existingnames = []
def patch_recipe_varfunc(varname, origvalue, op, newlines):
if modifying:
# Insert anything that should come before this variable
pos = get_recipe_pos(varname)
for k in remainingnames.keys()[:]:
if remainingnames[k] > -1 and pos >= remainingnames[k] and not k in existingnames:
outputvalue(k, newlines, rewindcomments=True)
del remainingnames[k]
# Now change this variable, if it needs to be changed
if varname in existingnames:
outputvalue(varname, newlines)
del remainingnames[varname]
return None, None, 0, True
else:
if varname in values:
existingnames.append(varname)
return origvalue, None, 0, True
if currname:
sline = line.rstrip()
if not sline.endswith('\\'):
currname = None
continue
if runthrough > 1:
tf.write(line)
f.seek(0)
if remainingnames:
tf.write('\n')
for k in remainingnames.keys():
outputvalue(k)
# First run - establish which values we want to set are already in the file
varlist = [re.escape(item) for item in values.keys()]
with open(fn, 'r') as f:
changed, fromlines = bb.utils.edit_metadata(f, varlist, patch_recipe_varfunc)
# Second run - actually set everything
modifying = True
varlist.extend(recipe_progression_restrs)
changed, tolines = bb.utils.edit_metadata(fromlines, varlist, patch_recipe_varfunc, match_overrides=True)
if remainingnames:
if tolines[-1].strip() != '':
tolines.append('\n')
for k in remainingnames.keys():
outputvalue(k, tolines)
with open(tfn, 'U') as f:
tolines = f.readlines()
if patch:
with open(fn, 'U') as f:
fromlines = f.readlines()
relfn = os.path.relpath(fn, relpath)
diff = difflib.unified_diff(fromlines, tolines, 'a/%s' % relfn, 'b/%s' % relfn)
os.remove(tfn)
return diff
else:
with open(fn, 'w') as f:
f.writelines(tolines)
os.remove(tfn)
return None
def localise_file_vars(fn, varfiles, varlist):
"""Given a list of variables and variable history (fetched with get_var_files())
find where each variable should be set/changed. This handles for example where a

View File

@ -62,26 +62,6 @@ def _get_checksums(rf):
checksums[cs] = m.group(1)
return checksums
def _replace_checksums(rf, md5, sha256):
if not md5 and not sha256:
return
checksums = {'md5sum':md5, 'sha256sum':sha256}
with open(rf + ".tmp", "w+") as tmprf:
with open(rf) as f:
for line in f:
m = None
for cs in checksums.keys():
m = re.match("^SRC_URI\[%s\].*=.*\"(.*)\"" % cs, line)
if m:
if checksums[cs]:
oldcheck = m.group(1)
newcheck = checksums[cs]
line = line.replace(oldcheck, newcheck)
break
tmprf.write(line)
os.rename(rf + ".tmp", rf)
def _remove_patch_dirs(recipefolder):
for root, dirs, files in os.walk(recipefolder):
for d in dirs:
@ -297,16 +277,14 @@ def _create_new_recipe(newpv, md5, sha256, srcrev, srcbranch, workspace, tinfoil
if changed:
newvalues['SRC_URI'] = ' '.join(new_src_uri)
if md5 and sha256:
newvalues['SRC_URI[md5sum]'] = md5
newvalues['SRC_URI[sha256sum]'] = sha256
if newvalues:
rd = oe.recipeutils.parse_recipe(fullpath, None, tinfoil.config_data)
oe.recipeutils.patch_recipe(rd, fullpath, newvalues)
if md5 and sha256:
# Unfortunately, oe.recipeutils.patch_recipe cannot update flags.
# once the latter feature is implemented, we should call patch_recipe
# instead of the following function
_replace_checksums(fullpath, md5, sha256)
return fullpath
def upgrade(args, config, basepath, workspace):