Determine if spec file patches are actually applied and striplevel

There's a little more to patch handling in spec files than "patchX:"
fields - the patch actually has to be applied in the %prep section as
well, though this can take one of several forms (%autosetup / %autopatch
which apply all patches, individual %patchX directives, or even direct
application (rare). There's also the matter of the striplevel (-p option
to the patch command). Add fields to record whether or not a patch is
applied and the striplevel.

Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
This commit is contained in:
Paul Eggleton 2019-04-04 00:18:46 +13:00
parent 4196ed7945
commit 4abd0174fa
5 changed files with 101 additions and 4 deletions

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.16 on 2019-04-03 12:20
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('layerindex', '0036_layerbranch_local_path'),
]
operations = [
migrations.AddField(
model_name='patch',
name='applied',
field=models.BooleanField(default=True),
),
]

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.16 on 2019-04-03 12:22
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('layerindex', '0037_patch_applied'),
]
operations = [
migrations.AddField(
model_name='patch',
name='striplevel',
field=models.IntegerField(default=1),
),
]

View File

@ -563,6 +563,8 @@ class Patch(models.Model):
status = models.CharField(max_length=1, choices=PATCH_STATUS_CHOICES, default='U') status = models.CharField(max_length=1, choices=PATCH_STATUS_CHOICES, default='U')
status_extra = models.CharField(max_length=255, blank=True) status_extra = models.CharField(max_length=255, blank=True)
apply_order = models.IntegerField(blank=True, null=True) apply_order = models.IntegerField(blank=True, null=True)
applied = models.BooleanField(default=True)
striplevel = models.IntegerField(default=1)
class Meta: class Meta:
verbose_name_plural = 'Patches' verbose_name_plural = 'Patches'

View File

@ -49,6 +49,8 @@ def update_recipe_file(path, recipe, repodir, raiseexceptions=False):
# yes, yes, I know this is all crude as hell, but it gets the job done. # yes, yes, I know this is all crude as hell, but it gets the job done.
# At the end of the day we are scraping the spec file, we aren't trying to build it # At the end of the day we are scraping the spec file, we aren't trying to build it
pnum_re = re.compile('-p[\s]*([0-9]+)')
try: try:
logger.debug('Updating recipe %s' % path) logger.debug('Updating recipe %s' % path)
recipe.pn = os.path.splitext(recipe.filename)[0] recipe.pn = os.path.splitext(recipe.filename)[0]
@ -191,13 +193,23 @@ def update_recipe_file(path, recipe, repodir, raiseexceptions=False):
else: else:
return res return res
applypatches = {}
autopatch = None
conds = [] conds = []
reading = True reading = True
inprep = False
applyextra = []
for line in f: for line in f:
if line.startswith('%package'): if line.startswith('%build'):
# Assume it's OK to stop when we hit the first package # Assume it's OK to stop when we hit %build
break break
if line.startswith(('%gometa', '%gocraftmeta')): if line.startswith('%autopatch') or line.startswith('%autosetup'):
pnum = pnum_re.search(line)
if pnum:
autopatch = pnum.groups()[0]
else:
autopatch = -1
elif line.startswith(('%gometa', '%gocraftmeta')):
goipath = globaldefs.get('goipath', '') goipath = globaldefs.get('goipath', '')
if not goipath: if not goipath:
goipath = globaldefs.get('gobaseipath', '') goipath = globaldefs.get('gobaseipath', '')
@ -241,6 +253,22 @@ def update_recipe_file(path, recipe, repodir, raiseexceptions=False):
if name in defines: if name in defines:
del defines[name] del defines[name]
continue continue
elif line.startswith('%patch'):
patchsplit = line.split()
if '-P' in line:
# Old style
patchid = re.search('-P[\s]*([0-9]+)', line)
if patchid:
patchid = patchid.groups()[0]
else:
# FIXME not sure if this is correct...
patchid = 0
else:
patchid = int(patchsplit[0][6:])
applypatches[patchid] = ' '.join(patchsplit[1:])
elif line.startswith('%prep'):
inprep = True
continue
elif line.strip() == '%description': elif line.strip() == '%description':
indesc = True indesc = True
continue continue
@ -253,6 +281,11 @@ def update_recipe_file(path, recipe, repodir, raiseexceptions=False):
elif not line.startswith('#'): elif not line.startswith('#'):
desc.append(line) desc.append(line)
continue continue
if inprep:
if line.startswith(('%build', '%install')):
inprep = False
elif 'git apply' in line:
applyextra.append(line)
if ':' in line and not line.startswith('%'): if ':' in line and not line.startswith('%'):
key, value = line.split(':', 1) key, value = line.split(':', 1)
@ -289,6 +322,23 @@ def update_recipe_file(path, recipe, repodir, raiseexceptions=False):
for index, patchfn in patches: for index, patchfn in patches:
patchpath = os.path.join(os.path.relpath(os.path.dirname(path), repodir), patchfn) patchpath = os.path.join(os.path.relpath(os.path.dirname(path), repodir), patchfn)
patch, _ = Patch.objects.get_or_create(recipe=recipe, path=patchpath) patch, _ = Patch.objects.get_or_create(recipe=recipe, path=patchpath)
if autopatch is not None:
patch.striplevel = int(autopatch)
elif index in applypatches:
pnum = pnum_re.search(applypatches[index])
if pnum:
patch.striplevel = int(pnum.groups()[0])
else:
patch.striplevel = -1
else:
for line in applyextra:
if patchfn in line:
patch.striplevel = 1
break
else:
# Not being applied
logger.debug('Not applying %s %s' % (index, patchfn))
patch.applied = False
patch.src_path = patchfn patch.src_path = patchfn
patch.apply_order = index patch.apply_order = index
patch.save() patch.save()
@ -515,6 +565,10 @@ def try_specfile(args):
print('sources:') print('sources:')
for src in recipe.source_set.all(): for src in recipe.source_set.all():
print(' * %s' % src.url) print(' * %s' % src.url)
if recipe.patch_set.exists():
print('patches:')
for patch in recipe.patch_set.all():
print(' * %s' % patch.src_path)
raise DryRunRollbackException() raise DryRunRollbackException()
except DryRunRollbackException: except DryRunRollbackException:

View File

@ -189,7 +189,7 @@
<tbody> <tbody>
{% for patch in rcp.patch_set.all %} {% for patch in rcp.patch_set.all %}
<tr> <tr>
<td><a href="{{ patch.vcs_web_url }}">{{ patch.src_path }}</a></td> <td><a href="{{ patch.vcs_web_url }}">{{ patch.src_path }}</a>{% if not patch.applied %} <i class="glyphicon glyphicon-ban-circle not-applied" aria-hidden="true"></i>{% endif %}</td>
{% block patch_status %} {% block patch_status %}
{% if not rcp.layerbranch.branch.comparison %} {% if not rcp.layerbranch.branch.comparison %}
<td>{{ patch.get_status_display }} {{ patch.status_extra | urlize }}</td> <td>{{ patch.get_status_display }} {{ patch.status_extra | urlize }}</td>
@ -222,6 +222,7 @@
$('[data-toggle="tooltip"]').tooltip(); $('[data-toggle="tooltip"]').tooltip();
$('#id_cover_status').change(enable_value_field) $('#id_cover_status').change(enable_value_field)
enable_value_field() enable_value_field()
$('.not-applied').tooltip({title:"Not being applied"});
}); });
enable_value_field = function() { enable_value_field = function() {
cover_status = $('#id_cover_status').val() cover_status = $('#id_cover_status').val()