From 15a5fa8bb2d0b5697a06dc8e80f353f26b654cd6 Mon Sep 17 00:00:00 2001 From: Olav Vitters Date: Thu, 10 Jul 2014 02:57:47 +0200 Subject: add ability to convert patches into %autopatch --- mgagnome | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 79 insertions(+), 11 deletions(-) diff --git a/mgagnome b/mgagnome index 1b8ebd9..032715f 100755 --- a/mgagnome +++ b/mgagnome @@ -362,9 +362,12 @@ class SpecFile(object): @property def version(self): - return subprocess.check_output(["rpm", "--specfile", self.path, "--queryformat", "%{VERSION}\n"]).splitlines()[0] + return subprocess.check_output(["rpm", "--define", "_topdir %s" % os.path.join(self.cwd, ".."), "--specfile", self.path, "--queryformat", "%{VERSION}\n"]).splitlines()[0] def _sources_and_patches(self, flag=None): + os.chdir(self.cwd) + rpm.delMacro("_topdir" ) + rpm.addMacro("_topdir", os.path.join(self.cwd, '..')) ts = rpm.ts() spec = ts.parseSpec(self.path) srclist = spec.sources if isinstance(spec.sources, (list, tuple)) \ @@ -452,11 +455,7 @@ class SpecFile(object): data = data.lstrip() self._changes.append('SILENT remove variable definition(s) %s' % ", ".join(converted_defines)) - # Make use of %apply_patches - patches = self.patches - if patches and not self.uses_apply_patches: - print "WARNING: Patches, no %%apply_patches for %s" % self.module - print self.module, patches + made_changes, data = self._clean_spec_patches(f, made_changes, data) # Overwrite file with new version number if made_changes: @@ -464,8 +463,78 @@ class SpecFile(object): return made_changes + def _clean_spec_patches(self, f, made_changes, data): + re_patch_header = re.compile('^\Patch(?P[0-9]*):[ \t]*(?P[^\n]+)\n', re.MULTILINE + re.IGNORECASE) + re_patch_any = re.compile(r'^[ \t]*\%patch(?P[0-9]*)', re.MULTILINE) + re_patch_valid = re.compile(r'^[ \t+]*\%patch(?P[0-9]*)(?:[ \t]+-p(?P[0-9]+))?(?:[ \t]+-b[ \t]+\S+)$\n?', re.MULTILINE) + re_prep_patches = re.compile(r'^\%setup[^\n]+$(?:' + re_patch_valid.pattern + r'|^#[^%\n]+\n|\s)+\n\%build', re.MULTILINE) + + give_patchnr = lambda mo: (mo.group('nr') if len(mo.group('nr')) == 1 else mo.group('nr').lstrip('0')) if mo.group('nr') else "0" + + # Make use of %apply_patches + patches = self.patches + if not patches: + return made_changes, data + + if self.uses_apply_patches: + return made_changes, data + +# print "WARNING: Patches, no %%apply_patches for %s" % self.module +# print self.module, patches +# print re_patch_header.findall(data) +# print re_patch_valid.findall(data) + + mo2 = re_prep_patches.search(data) + patch_nrs_header = set([give_patchnr(mo) for mo in re_patch_header.finditer(data)]) + patch_nrs_any = set([give_patchnr(mo) for mo in re_patch_any.finditer(data)]) + patch_nrs_valid = set([give_patchnr(mo) for mo in re_patch_valid.finditer(mo2.group(0))]) if mo2 else set() + + if not patch_nrs_header: + # XXX -- werird, self.patches should've returned 0 already + return made_changes, data + + if not (patch_nrs_header == patch_nrs_any == patch_nrs_valid): + print >>sys.stderr, "NOTICE: Unable to automatically convert patches into %autopatch" + return made_changes, data + + patch_flags = set([mo.group('strip') for mo in re_patch_valid.finditer(mo2.group(0))]) + + if len(patch_flags) != 1: + print >>sys.stderr, "NOTICE: Unable to automatically convert patches into as different -p / strip levels used" + return made_changes, data + + # Whoot, we can convert!! + change_to = "%%autopatch -p%s\n" % list(patch_flags)[0] + prep, n1 = re_patch_valid.subn(change_to.replace('\\', '\\\\'), mo2.group(0), count=1) + prep, n2 = re_patch_valid.subn('', prep) + if len(patch_nrs_valid) <> n1 + n2: + print >>sys.stderr, "WARNING: Couldn't replace patches?!? Likely error in program logic" + return made_changes, data + + # First check if patches currently apply + if not self.check_and_update_patches(check_only=True): + return made_changes, data + + try: + change_to = data.replace(mo2.group(0), prep, 1) + write_file(self.path, change_to) + + # Validate patches still apply + if self.check_and_update_patches(check_only=True): + pass + data = change_to + self._changes.append('SILENT use autopatch') + made_changes = True + finally: + if not made_changes: + write_file(self.path, data) + + return made_changes, data + @property def buildrequires(self): + rpm.delMacro("_topdir" ) + rpm.addMacro("_topdir", os.path.join(self.cwd, '..')) ts = rpm.ts() spec = ts.parseSpec(self.path) @@ -518,7 +587,7 @@ class SpecFile(object): subprocess.check_call(['mgarepo', 'sync'], cwd=self.cwd) return True - def check_and_update_patches(self): + def check_and_update_patches(self, check_only=False): """Check if patches still apply Remove any merged patches""" @@ -534,13 +603,14 @@ class SpecFile(object): # Check patches still apply subprocess.check_call(['bm', '-p', '--nodeps'], cwd=self.cwd) except subprocess.CalledProcessError: - logfile = os.path.join(os.path.dirname(self.path), 'log.%s' % os.path.splitext(os.path.basename(self.path))[0]) + logfile = os.path.join(self.cwd, 'log.%s' % os.path.splitext(os.path.basename(self.path))[0]) failed_patch = None cmd = None cmd_output = [] # Determine the last command that failed if os.path.exists(logfile): + print logfile with open(logfile, "r") as f: for line in line_input(f): if line.startswith('+ '): @@ -551,7 +621,7 @@ class SpecFile(object): cmd_parsed = shlex.split(cmd) if cmd else [] - if uses_apply_patches and patches and cmd_parsed: + if not check_only and uses_apply_patches and patches and cmd_parsed: if os.path.basename(cmd_parsed[0]) == 'patch' and os.path.exists(cmd_parsed[-1]): failed_patch = os.path.basename(cmd_parsed[-1]) @@ -604,8 +674,6 @@ class SpecFile(object): # XXX - doesn't handle buildrequires with version numbers :-( made_changes = False - re_patch = re.compile(r'^\%patch(?P[0-9]*)(?:[ \t]+-p(P[0-9]+))?(?:[ \t]+-b[ \t]+\S+)?\n', re.MULTILINE) - with open(self.path, "rw") as f: data = f.read() data_before=data -- cgit v1.2.1