From 765b7bad50eae5b79d13a3f4988dc440c3d9787f Mon Sep 17 00:00:00 2001 From: Paul Eggleton Date: Fri, 19 Dec 2014 11:41:49 +0000 Subject: lib/oe/patch: add support for extracting patches from git tree When patches from a recipe have been written out to a git tree, we also want to be able to do the reverse so we can update the patches next to the recipe. This is implemented by adding a comment to each commit message (using git hooks) which we can extract later on. Signed-off-by: Paul Eggleton Signed-off-by: Richard Purdie --- meta/lib/oe/patch.py | 112 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 82 insertions(+), 30 deletions(-) diff --git a/meta/lib/oe/patch.py b/meta/lib/oe/patch.py index 522778140c..b838be80be 100644 --- a/meta/lib/oe/patch.py +++ b/meta/lib/oe/patch.py @@ -199,6 +199,8 @@ class PatchTree(PatchSet): self.Pop(all=True) class GitApplyTree(PatchTree): + patch_line_prefix = '%% original patch' + def __init__(self, dir, d): PatchTree.__init__(self, dir, d) @@ -256,10 +258,6 @@ class GitApplyTree(PatchTree): if author_re.match(authorval): author = authorval outlines.append(line) - # Add a pointer to the original patch file name - if outlines and outlines[-1].strip(): - outlines.append('\n') - outlines.append('(from original patch: %s)\n' % os.path.basename(patchfile)) # Write out commit message to a file with tempfile.NamedTemporaryFile('w', delete=False) as tf: tmpfile = tf.name @@ -274,7 +272,35 @@ class GitApplyTree(PatchTree): cmd.append('--date="%s"' % date) return (tmpfile, cmd) + @staticmethod + def extractPatches(tree, startcommit, outdir): + import tempfile + import shutil + tempdir = tempfile.mkdtemp(prefix='oepatch') + try: + shellcmd = ["git", "format-patch", startcommit, "-o", tempdir] + out = runcmd(["sh", "-c", " ".join(shellcmd)], tree) + if out: + for srcfile in out.split(): + patchlines = [] + outfile = None + with open(srcfile, 'r') as f: + for line in f: + if line.startswith(GitApplyTree.patch_line_prefix): + outfile = line.split()[-1].strip() + continue + patchlines.append(line) + if not outfile: + outfile = os.path.basename(srcfile) + with open(os.path.join(outdir, outfile), 'w') as of: + for line in patchlines: + of.write(line) + finally: + shutil.rmtree(tempdir) + def _applypatch(self, patch, force = False, reverse = False, run = True): + import shutil + def _applypatchhelper(shellcmd, patch, force = False, reverse = False, run = True): if reverse: shellcmd.append('-R') @@ -286,36 +312,62 @@ class GitApplyTree(PatchTree): return runcmd(["sh", "-c", " ".join(shellcmd)], self.dir) + # Add hooks which add a pointer to the original patch file name in the commit message + commithook = os.path.join(self.dir, '.git', 'hooks', 'commit-msg') + commithook_backup = commithook + '.devtool-orig' + applyhook = os.path.join(self.dir, '.git', 'hooks', 'applypatch-msg') + applyhook_backup = applyhook + '.devtool-orig' + if os.path.exists(commithook): + shutil.move(commithook, commithook_backup) + if os.path.exists(applyhook): + shutil.move(applyhook, applyhook_backup) + with open(commithook, 'w') as f: + # NOTE: the formatting here is significant; if you change it you'll also need to + # change other places which read it back + f.write('echo >> $1\n') + f.write('echo "%s: $PATCHFILE" >> $1\n' % GitApplyTree.patch_line_prefix) + os.chmod(commithook, 0755) + shutil.copy2(commithook, applyhook) try: - shellcmd = ["git", "--work-tree=.", "am", "-3", "--keep-cr", "-p%s" % patch['strippath']] - return _applypatchhelper(shellcmd, patch, force, reverse, run) - except CmdError: - # Need to abort the git am, or we'll still be within it at the end - try: - shellcmd = ["git", "--work-tree=.", "am", "--abort"] - runcmd(["sh", "-c", " ".join(shellcmd)], self.dir) - except CmdError: - pass - # Fall back to git apply - shellcmd = ["git", "--git-dir=.", "apply", "-p%s" % patch['strippath']] + patchfilevar = 'PATCHFILE="%s"' % os.path.basename(patch['file']) try: - output = _applypatchhelper(shellcmd, patch, force, reverse, run) + shellcmd = [patchfilevar, "git", "--work-tree=.", "am", "-3", "--keep-cr", "-p%s" % patch['strippath']] + return _applypatchhelper(shellcmd, patch, force, reverse, run) except CmdError: - # Fall back to patch - output = PatchTree._applypatch(self, patch, force, reverse, run) - # Add all files - shellcmd = ["git", "add", "-f", "."] - output += runcmd(["sh", "-c", " ".join(shellcmd)], self.dir) - # Exclude the patches directory - shellcmd = ["git", "reset", "HEAD", self.patchdir] - output += runcmd(["sh", "-c", " ".join(shellcmd)], self.dir) - # Commit the result - (tmpfile, shellcmd) = self.prepareCommit(patch['file']) - try: + # Need to abort the git am, or we'll still be within it at the end + try: + shellcmd = ["git", "--work-tree=.", "am", "--abort"] + runcmd(["sh", "-c", " ".join(shellcmd)], self.dir) + except CmdError: + pass + # Fall back to git apply + shellcmd = ["git", "--git-dir=.", "apply", "-p%s" % patch['strippath']] + try: + output = _applypatchhelper(shellcmd, patch, force, reverse, run) + except CmdError: + # Fall back to patch + output = PatchTree._applypatch(self, patch, force, reverse, run) + # Add all files + shellcmd = ["git", "add", "-f", "."] + output += runcmd(["sh", "-c", " ".join(shellcmd)], self.dir) + # Exclude the patches directory + shellcmd = ["git", "reset", "HEAD", self.patchdir] output += runcmd(["sh", "-c", " ".join(shellcmd)], self.dir) - finally: - os.remove(tmpfile) - return output + # Commit the result + (tmpfile, shellcmd) = self.prepareCommit(patch['file']) + try: + shellcmd.insert(0, patchfilevar) + output += runcmd(["sh", "-c", " ".join(shellcmd)], self.dir) + finally: + os.remove(tmpfile) + return output + finally: + os.remove(commithook) + os.remove(applyhook) + if os.path.exists(commithook_backup): + shutil.move(commithook_backup, commithook) + if os.path.exists(applyhook_backup): + shutil.move(applyhook_backup, applyhook) class QuiltTree(PatchSet): -- cgit 1.2.3-korg