Commit only at end
[trackgit.git] / patch.py
blob949553d9dfc0dbc6f569ebdab88203ba1be4e0af
1 import re
2 import sys
3 import os.path
5 import db
6 import dbcache
7 from git import git
9 _boundary_line_regex = re.compile(r'^---')
10 _diff_head_regex = re.compile(r'^diff --git a/(.*) b/(.*)$')
11 _index_line_regex = re.compile(r'^index ([a-f0-9]{7,})\.\.([a-f0-9]{7,}) ')
12 _all_zeros_regex = re.compile(r'^0+$')
14 class PatchError(Exception):
15 pass
17 class Patch(object):
19 def __init__(self, data):
20 self.blobs_pre = set()
21 self.blobs_post = set()
22 self.missing_files = False
23 self.data = data
24 self.notes = None
25 self._parse(data)
27 def _parse(self, data):
28 boundary_seen = False
29 diff_seen = False
30 filename = None
31 notes = []
32 for line in data.splitlines(True):
33 if _boundary_line_regex.match(line):
34 boundary_seen = True
35 continue
36 m = _diff_head_regex.match(line)
37 if m:
38 diff_seen = True
39 # at least the 'pre' filename should exist
40 filename = m.group(1)
41 continue
42 if diff_seen:
43 m = _index_line_regex.match(line)
44 if m:
45 if not _all_zeros_regex.match(m.group(1)):
46 self.blobs_pre.add(m.group(1))
47 self._check_file(filename)
48 self.blobs_post.add(m.group(2))
49 continue
50 if boundary_seen:
51 notes.append(line)
52 if diff_seen:
53 self.notes = ''.join(notes)
55 def _check_file(self, name):
56 if os.path.basename(name) not in dbcache.file_cache:
57 self.missing_files = True
58 print 'patch for missing file "%s"' % name
60 def apply(self):
61 output, ret = git('am', input=self.data)
62 if ret != 0:
63 # clean up
64 git('am', '--abort')
65 git('reset', '--hard')
66 raise PatchError()
67 return output