diff options
| -rw-r--r-- | meta/lib/oe/patch.py | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/meta/lib/oe/patch.py b/meta/lib/oe/patch.py index 788f465bd9..2d56ba404e 100644 --- a/meta/lib/oe/patch.py +++ b/meta/lib/oe/patch.py | |||
| @@ -202,6 +202,78 @@ class GitApplyTree(PatchTree): | |||
| 202 | def __init__(self, dir, d): | 202 | def __init__(self, dir, d): |
| 203 | PatchTree.__init__(self, dir, d) | 203 | PatchTree.__init__(self, dir, d) |
| 204 | 204 | ||
| 205 | @staticmethod | ||
| 206 | def extractPatchHeader(patchfile): | ||
| 207 | """ | ||
| 208 | Extract just the header lines from the top of a patch file | ||
| 209 | """ | ||
| 210 | lines = [] | ||
| 211 | with open(patchfile, 'r') as f: | ||
| 212 | for line in f.readlines(): | ||
| 213 | if line.startswith('Index: ') or line.startswith('diff -') or line.startswith('---'): | ||
| 214 | break | ||
| 215 | lines.append(line) | ||
| 216 | return lines | ||
| 217 | |||
| 218 | @staticmethod | ||
| 219 | def prepareCommit(patchfile): | ||
| 220 | """ | ||
| 221 | Prepare a git commit command line based on the header from a patch file | ||
| 222 | (typically this is useful for patches that cannot be applied with "git am" due to formatting) | ||
| 223 | """ | ||
| 224 | import tempfile | ||
| 225 | import re | ||
| 226 | author_re = re.compile('[\S ]+ <\S+@\S+\.\S+>') | ||
| 227 | # Process patch header and extract useful information | ||
| 228 | lines = GitApplyTree.extractPatchHeader(patchfile) | ||
| 229 | outlines = [] | ||
| 230 | author = None | ||
| 231 | date = None | ||
| 232 | for line in lines: | ||
| 233 | if line.startswith('Subject: '): | ||
| 234 | subject = line.split(':', 1)[1] | ||
| 235 | # Remove any [PATCH][oe-core] etc. | ||
| 236 | subject = re.sub(r'\[.+?\]\s*', '', subject) | ||
| 237 | outlines.insert(0, '%s\n\n' % subject.strip()) | ||
| 238 | continue | ||
| 239 | if line.startswith('From: ') or line.startswith('Author: '): | ||
| 240 | authorval = line.split(':', 1)[1].strip().replace('"', '') | ||
| 241 | # git is fussy about author formatting i.e. it must be Name <email@domain> | ||
| 242 | if author_re.match(authorval): | ||
| 243 | author = authorval | ||
| 244 | continue | ||
| 245 | if line.startswith('Date: '): | ||
| 246 | if date is None: | ||
| 247 | dateval = line.split(':', 1)[1].strip() | ||
| 248 | # Very crude check for date format, since git will blow up if it's not in the right | ||
| 249 | # format. Without e.g. a python-dateutils dependency we can't do a whole lot more | ||
| 250 | if len(dateval) > 12: | ||
| 251 | date = dateval | ||
| 252 | continue | ||
| 253 | if line.startswith('Signed-off-by: '): | ||
| 254 | authorval = line.split(':', 1)[1].strip().replace('"', '') | ||
| 255 | # git is fussy about author formatting i.e. it must be Name <email@domain> | ||
| 256 | if author_re.match(authorval): | ||
| 257 | author = authorval | ||
| 258 | outlines.append(line) | ||
| 259 | # Add a pointer to the original patch file name | ||
| 260 | if outlines and outlines[-1].strip(): | ||
| 261 | outlines.append('\n') | ||
| 262 | outlines.append('(from original patch: %s)\n' % os.path.basename(patchfile)) | ||
| 263 | # Write out commit message to a file | ||
| 264 | with tempfile.NamedTemporaryFile('w', delete=False) as tf: | ||
| 265 | tmpfile = tf.name | ||
| 266 | for line in outlines: | ||
| 267 | tf.write(line) | ||
| 268 | # Prepare git command | ||
| 269 | cmd = ["git", "commit", "-F", tmpfile] | ||
| 270 | # git doesn't like plain email addresses as authors | ||
| 271 | if author and '<' in author: | ||
| 272 | cmd.append('--author="%s"' % author) | ||
| 273 | if date: | ||
| 274 | cmd.append('--date="%s"' % date) | ||
| 275 | return (tmpfile, cmd) | ||
| 276 | |||
| 205 | def _applypatch(self, patch, force = False, reverse = False, run = True): | 277 | def _applypatch(self, patch, force = False, reverse = False, run = True): |
| 206 | def _applypatchhelper(shellcmd, patch, force = False, reverse = False, run = True): | 278 | def _applypatchhelper(shellcmd, patch, force = False, reverse = False, run = True): |
| 207 | if reverse: | 279 | if reverse: |
| @@ -218,11 +290,25 @@ class GitApplyTree(PatchTree): | |||
| 218 | shellcmd = ["git", "--work-tree=.", "am", "-3", "-p%s" % patch['strippath']] | 290 | shellcmd = ["git", "--work-tree=.", "am", "-3", "-p%s" % patch['strippath']] |
| 219 | return _applypatchhelper(shellcmd, patch, force, reverse, run) | 291 | return _applypatchhelper(shellcmd, patch, force, reverse, run) |
| 220 | except CmdError: | 292 | except CmdError: |
| 293 | # Fall back to git apply | ||
| 221 | shellcmd = ["git", "--git-dir=.", "apply", "-p%s" % patch['strippath']] | 294 | shellcmd = ["git", "--git-dir=.", "apply", "-p%s" % patch['strippath']] |
| 222 | try: | 295 | try: |
| 223 | output = _applypatchhelper(shellcmd, patch, force, reverse, run) | 296 | output = _applypatchhelper(shellcmd, patch, force, reverse, run) |
| 224 | except CmdError: | 297 | except CmdError: |
| 298 | # Fall back to patch | ||
| 225 | output = PatchTree._applypatch(self, patch, force, reverse, run) | 299 | output = PatchTree._applypatch(self, patch, force, reverse, run) |
| 300 | # Add all files | ||
| 301 | shellcmd = ["git", "add", "-f", "."] | ||
| 302 | output += runcmd(["sh", "-c", " ".join(shellcmd)], self.dir) | ||
| 303 | # Exclude the patches directory | ||
| 304 | shellcmd = ["git", "reset", "HEAD", self.patchdir] | ||
| 305 | output += runcmd(["sh", "-c", " ".join(shellcmd)], self.dir) | ||
| 306 | # Commit the result | ||
| 307 | (tmpfile, shellcmd) = self.prepareCommit(patch['file']) | ||
| 308 | try: | ||
| 309 | output += runcmd(["sh", "-c", " ".join(shellcmd)], self.dir) | ||
| 310 | finally: | ||
| 311 | os.remove(tmpfile) | ||
| 226 | return output | 312 | return output |
| 227 | 313 | ||
| 228 | 314 | ||
