diff options
Diffstat (limited to 'meta/lib/oe/patch.py')
| -rw-r--r-- | meta/lib/oe/patch.py | 109 |
1 files changed, 70 insertions, 39 deletions
diff --git a/meta/lib/oe/patch.py b/meta/lib/oe/patch.py index 3ded5f3601..60a0cc8291 100644 --- a/meta/lib/oe/patch.py +++ b/meta/lib/oe/patch.py | |||
| @@ -294,8 +294,9 @@ class PatchTree(PatchSet): | |||
| 294 | self.Pop(all=True) | 294 | self.Pop(all=True) |
| 295 | 295 | ||
| 296 | class GitApplyTree(PatchTree): | 296 | class GitApplyTree(PatchTree): |
| 297 | patch_line_prefix = '%% original patch' | 297 | notes_ref = "refs/notes/devtool" |
| 298 | ignore_commit_prefix = '%% ignore' | 298 | original_patch = 'original patch' |
| 299 | ignore_commit = 'ignore' | ||
| 299 | 300 | ||
| 300 | def __init__(self, dir, d): | 301 | def __init__(self, dir, d): |
| 301 | PatchTree.__init__(self, dir, d) | 302 | PatchTree.__init__(self, dir, d) |
| @@ -452,7 +453,7 @@ class GitApplyTree(PatchTree): | |||
| 452 | # Prepare git command | 453 | # Prepare git command |
| 453 | cmd = ["git"] | 454 | cmd = ["git"] |
| 454 | GitApplyTree.gitCommandUserOptions(cmd, commituser, commitemail) | 455 | GitApplyTree.gitCommandUserOptions(cmd, commituser, commitemail) |
| 455 | cmd += ["commit", "-F", tmpfile] | 456 | cmd += ["commit", "-F", tmpfile, "--no-verify"] |
| 456 | # git doesn't like plain email addresses as authors | 457 | # git doesn't like plain email addresses as authors |
| 457 | if author and '<' in author: | 458 | if author and '<' in author: |
| 458 | cmd.append('--author="%s"' % author) | 459 | cmd.append('--author="%s"' % author) |
| @@ -461,14 +462,52 @@ class GitApplyTree(PatchTree): | |||
| 461 | return (tmpfile, cmd) | 462 | return (tmpfile, cmd) |
| 462 | 463 | ||
| 463 | @staticmethod | 464 | @staticmethod |
| 465 | def addNote(repo, ref, key, value=None): | ||
| 466 | note = key + (": %s" % value if value else "") | ||
| 467 | notes_ref = GitApplyTree.notes_ref | ||
| 468 | runcmd(["git", "config", "notes.rewriteMode", "ignore"], repo) | ||
| 469 | runcmd(["git", "config", "notes.displayRef", notes_ref, notes_ref], repo) | ||
| 470 | runcmd(["git", "config", "notes.rewriteRef", notes_ref, notes_ref], repo) | ||
| 471 | runcmd(["git", "notes", "--ref", notes_ref, "append", "-m", note, ref], repo) | ||
| 472 | |||
| 473 | @staticmethod | ||
| 474 | def removeNote(repo, ref, key): | ||
| 475 | notes = GitApplyTree.getNotes(repo, ref) | ||
| 476 | notes = {k: v for k, v in notes.items() if k != key and not k.startswith(key + ":")} | ||
| 477 | runcmd(["git", "notes", "--ref", GitApplyTree.notes_ref, "remove", "--ignore-missing", ref], repo) | ||
| 478 | for note, value in notes.items(): | ||
| 479 | GitApplyTree.addNote(repo, ref, note, value) | ||
| 480 | |||
| 481 | @staticmethod | ||
| 482 | def getNotes(repo, ref): | ||
| 483 | import re | ||
| 484 | |||
| 485 | note = None | ||
| 486 | try: | ||
| 487 | note = runcmd(["git", "notes", "--ref", GitApplyTree.notes_ref, "show", ref], repo) | ||
| 488 | prefix = "" | ||
| 489 | except CmdError: | ||
| 490 | note = runcmd(['git', 'show', '-s', '--format=%B', ref], repo) | ||
| 491 | prefix = "%% " | ||
| 492 | |||
| 493 | note_re = re.compile(r'^%s(.*?)(?::\s*(.*))?$' % prefix) | ||
| 494 | notes = dict() | ||
| 495 | for line in note.splitlines(): | ||
| 496 | m = note_re.match(line) | ||
| 497 | if m: | ||
| 498 | notes[m.group(1)] = m.group(2) | ||
| 499 | |||
| 500 | return notes | ||
| 501 | |||
| 502 | @staticmethod | ||
| 464 | def commitIgnored(subject, dir=None, files=None, d=None): | 503 | def commitIgnored(subject, dir=None, files=None, d=None): |
| 465 | if files: | 504 | if files: |
| 466 | runcmd(['git', 'add'] + files, dir) | 505 | runcmd(['git', 'add'] + files, dir) |
| 467 | message = "%s\n\n%s" % (subject, GitApplyTree.ignore_commit_prefix) | ||
| 468 | cmd = ["git"] | 506 | cmd = ["git"] |
| 469 | GitApplyTree.gitCommandUserOptions(cmd, d=d) | 507 | GitApplyTree.gitCommandUserOptions(cmd, d=d) |
| 470 | cmd += ["commit", "-m", message, "--no-verify"] | 508 | cmd += ["commit", "-m", subject, "--no-verify"] |
| 471 | runcmd(cmd, dir) | 509 | runcmd(cmd, dir) |
| 510 | GitApplyTree.addNote(dir, "HEAD", GitApplyTree.ignore_commit) | ||
| 472 | 511 | ||
| 473 | @staticmethod | 512 | @staticmethod |
| 474 | def extractPatches(tree, startcommits, outdir, paths=None): | 513 | def extractPatches(tree, startcommits, outdir, paths=None): |
| @@ -484,18 +523,20 @@ class GitApplyTree(PatchTree): | |||
| 484 | out = runcmd(["sh", "-c", " ".join(shellcmd)], os.path.join(tree, name)) | 523 | out = runcmd(["sh", "-c", " ".join(shellcmd)], os.path.join(tree, name)) |
| 485 | if out: | 524 | if out: |
| 486 | for srcfile in out.split(): | 525 | for srcfile in out.split(): |
| 487 | outfile = os.path.basename(srcfile) | 526 | # This loop, which is used to remove any line that |
| 527 | # starts with "%% original patch", is kept for backwards | ||
| 528 | # compatibility. If/when that compatibility is dropped, | ||
| 529 | # it can be replaced with code to just read the first | ||
| 530 | # line of the patch file to get the SHA-1, and the code | ||
| 531 | # below that writes the modified patch file can be | ||
| 532 | # replaced with a simple file move. | ||
| 488 | for encoding in ['utf-8', 'latin-1']: | 533 | for encoding in ['utf-8', 'latin-1']: |
| 489 | patchlines = [] | 534 | patchlines = [] |
| 490 | try: | 535 | try: |
| 491 | with open(srcfile, 'r', encoding=encoding, newline='') as f: | 536 | with open(srcfile, 'r', encoding=encoding, newline='') as f: |
| 492 | for line in f: | 537 | for line in f: |
| 493 | if line.startswith(GitApplyTree.patch_line_prefix): | 538 | if line.startswith("%% " + GitApplyTree.original_patch): |
| 494 | outfile = line.split()[-1].strip() | ||
| 495 | continue | 539 | continue |
| 496 | if line.startswith(GitApplyTree.ignore_commit_prefix): | ||
| 497 | outfile = None | ||
| 498 | break | ||
| 499 | patchlines.append(line) | 540 | patchlines.append(line) |
| 500 | except UnicodeDecodeError: | 541 | except UnicodeDecodeError: |
| 501 | continue | 542 | continue |
| @@ -503,11 +544,16 @@ class GitApplyTree(PatchTree): | |||
| 503 | else: | 544 | else: |
| 504 | raise PatchError('Unable to find a character encoding to decode %s' % srcfile) | 545 | raise PatchError('Unable to find a character encoding to decode %s' % srcfile) |
| 505 | 546 | ||
| 506 | if outfile: | 547 | sha1 = patchlines[0].split()[1] |
| 507 | bb.utils.mkdirhier(os.path.join(outdir, name)) | 548 | notes = GitApplyTree.getNotes(os.path.join(tree, name), sha1) |
| 508 | with open(os.path.join(outdir, name, outfile), 'w') as of: | 549 | if GitApplyTree.ignore_commit in notes: |
| 509 | for line in patchlines: | 550 | continue |
| 510 | of.write(line) | 551 | outfile = notes.get(GitApplyTree.original_patch, os.path.basename(srcfile)) |
| 552 | |||
| 553 | bb.utils.mkdirhier(os.path.join(outdir, name)) | ||
| 554 | with open(os.path.join(outdir, name, outfile), 'w') as of: | ||
| 555 | for line in patchlines: | ||
| 556 | of.write(line) | ||
| 511 | finally: | 557 | finally: |
| 512 | shutil.rmtree(tempdir) | 558 | shutil.rmtree(tempdir) |
| 513 | 559 | ||
| @@ -555,28 +601,11 @@ class GitApplyTree(PatchTree): | |||
| 555 | 601 | ||
| 556 | return runcmd(["sh", "-c", " ".join(shellcmd)], self.dir) | 602 | return runcmd(["sh", "-c", " ".join(shellcmd)], self.dir) |
| 557 | 603 | ||
| 558 | # Add hooks which add a pointer to the original patch file name in the commit message | ||
| 559 | reporoot = (runcmd("git rev-parse --show-toplevel".split(), self.dir) or '').strip() | 604 | reporoot = (runcmd("git rev-parse --show-toplevel".split(), self.dir) or '').strip() |
| 560 | if not reporoot: | 605 | if not reporoot: |
| 561 | raise Exception("Cannot get repository root for directory %s" % self.dir) | 606 | raise Exception("Cannot get repository root for directory %s" % self.dir) |
| 562 | gitdir = (runcmd("git rev-parse --absolute-git-dir".split(), self.dir) or '').strip() | 607 | |
| 563 | if not gitdir: | 608 | patch_applied = True |
| 564 | raise Exception("Cannot get gitdir for directory %s" % self.dir) | ||
| 565 | hooks_dir = os.path.join(gitdir, 'hooks') | ||
| 566 | hooks_dir_backup = hooks_dir + '.devtool-orig' | ||
| 567 | if os.path.lexists(hooks_dir_backup): | ||
| 568 | raise Exception("Git hooks backup directory already exists: %s" % hooks_dir_backup) | ||
| 569 | if os.path.lexists(hooks_dir): | ||
| 570 | shutil.move(hooks_dir, hooks_dir_backup) | ||
| 571 | os.mkdir(hooks_dir) | ||
| 572 | commithook = os.path.join(hooks_dir, 'commit-msg') | ||
| 573 | applyhook = os.path.join(hooks_dir, 'applypatch-msg') | ||
| 574 | with open(commithook, 'w') as f: | ||
| 575 | # NOTE: the formatting here is significant; if you change it you'll also need to | ||
| 576 | # change other places which read it back | ||
| 577 | f.write('echo "\n%s: $PATCHFILE" >> $1' % GitApplyTree.patch_line_prefix) | ||
| 578 | os.chmod(commithook, 0o755) | ||
| 579 | shutil.copy2(commithook, applyhook) | ||
| 580 | try: | 609 | try: |
| 581 | patchfilevar = 'PATCHFILE="%s"' % os.path.basename(patch['file']) | 610 | patchfilevar = 'PATCHFILE="%s"' % os.path.basename(patch['file']) |
| 582 | if self._need_dirty_check(): | 611 | if self._need_dirty_check(): |
| @@ -587,7 +616,7 @@ class GitApplyTree(PatchTree): | |||
| 587 | pass | 616 | pass |
| 588 | else: | 617 | else: |
| 589 | if output: | 618 | if output: |
| 590 | # The tree is dirty, not need to try to apply patches with git anymore | 619 | # The tree is dirty, no need to try to apply patches with git anymore |
| 591 | # since they fail, fallback directly to patch | 620 | # since they fail, fallback directly to patch |
| 592 | output = PatchTree._applypatch(self, patch, force, reverse, run) | 621 | output = PatchTree._applypatch(self, patch, force, reverse, run) |
| 593 | output += self._commitpatch(patch, patchfilevar) | 622 | output += self._commitpatch(patch, patchfilevar) |
| @@ -620,10 +649,12 @@ class GitApplyTree(PatchTree): | |||
| 620 | output = PatchTree._applypatch(self, patch, force, reverse, run) | 649 | output = PatchTree._applypatch(self, patch, force, reverse, run) |
| 621 | output += self._commitpatch(patch, patchfilevar) | 650 | output += self._commitpatch(patch, patchfilevar) |
| 622 | return output | 651 | return output |
| 652 | except: | ||
| 653 | patch_applied = False | ||
| 654 | raise | ||
| 623 | finally: | 655 | finally: |
| 624 | shutil.rmtree(hooks_dir) | 656 | if patch_applied: |
| 625 | if os.path.lexists(hooks_dir_backup): | 657 | GitApplyTree.addNote(self.dir, "HEAD", GitApplyTree.original_patch, os.path.basename(patch['file'])) |
| 626 | shutil.move(hooks_dir_backup, hooks_dir) | ||
| 627 | 658 | ||
| 628 | 659 | ||
| 629 | class QuiltTree(PatchSet): | 660 | class QuiltTree(PatchSet): |
