Show More
@@ -5,15 +5,41 b'' | |||||
5 | # This software may be used and distributed according to the terms of the |
|
5 | # This software may be used and distributed according to the terms of the | |
6 | # GNU General Public License version 2 or any later version. |
|
6 | # GNU General Public License version 2 or any later version. | |
7 |
|
7 | |||
|
8 | import struct | |||
|
9 | ||||
8 | from node import nullid, nullrev, hex, bin |
|
10 | from node import nullid, nullrev, hex, bin | |
9 | from i18n import _ |
|
11 | from i18n import _ | |
10 | from mercurial import obsolete |
|
12 | from mercurial import obsolete | |
11 | import error, util, filemerge, copies, subrepo, worker, dicthelpers |
|
13 | import error, util, filemerge, copies, subrepo, worker, dicthelpers | |
12 | import errno, os, shutil |
|
14 | import errno, os, shutil | |
13 |
|
15 | |||
|
16 | _pack = struct.pack | |||
|
17 | _unpack = struct.unpack | |||
|
18 | ||||
14 | class mergestate(object): |
|
19 | class mergestate(object): | |
15 |
'''track 3-way merge state of individual files |
|
20 | '''track 3-way merge state of individual files | |
16 | statepath = "merge/state" |
|
21 | ||
|
22 | it is stored on disk when needed. Two file are used, one with an old | |||
|
23 | format, one with a new format. Both contains similar data, but the new | |||
|
24 | format can store new kind of field. | |||
|
25 | ||||
|
26 | Current new format is a list of arbitrary record of the form: | |||
|
27 | ||||
|
28 | [type][length][content] | |||
|
29 | ||||
|
30 | Type is a single character, length is a 4 bytes integer, content is an | |||
|
31 | arbitrary suites of bytes of lenght `length`. | |||
|
32 | ||||
|
33 | Type should be a letter. Capital letter are mandatory record, Mercurial | |||
|
34 | should abort if they are unknown. lower case record can be safely ignored. | |||
|
35 | ||||
|
36 | Currently known record: | |||
|
37 | ||||
|
38 | L: the node of the "local" part of the merge (hexified version) | |||
|
39 | F: a file to be merged entry | |||
|
40 | ''' | |||
|
41 | statepathv1 = "merge/state" | |||
|
42 | statepathv2 = "merge/state2" | |||
17 | def __init__(self, repo): |
|
43 | def __init__(self, repo): | |
18 | self._repo = repo |
|
44 | self._repo = repo | |
19 | self._dirty = False |
|
45 | self._dirty = False | |
@@ -38,9 +64,19 b' class mergestate(object):' | |||||
38 | % rtype)) |
|
64 | % rtype)) | |
39 | self._dirty = False |
|
65 | self._dirty = False | |
40 | def _readrecords(self): |
|
66 | def _readrecords(self): | |
|
67 | v1records = self._readrecordsv1() | |||
|
68 | v2records = self._readrecordsv2() | |||
|
69 | allv2 = set(v2records) | |||
|
70 | for rev in v1records: | |||
|
71 | if rev not in allv2: | |||
|
72 | # v1 file is newer than v2 file, use it | |||
|
73 | return v1records | |||
|
74 | else: | |||
|
75 | return v2records | |||
|
76 | def _readrecordsv1(self): | |||
41 | records = [] |
|
77 | records = [] | |
42 | try: |
|
78 | try: | |
43 | f = self._repo.opener(self.statepath) |
|
79 | f = self._repo.opener(self.statepathv1) | |
44 | for i, l in enumerate(f): |
|
80 | for i, l in enumerate(f): | |
45 | if i == 0: |
|
81 | if i == 0: | |
46 | records.append(('L', l[:-1])) |
|
82 | records.append(('L', l[:-1])) | |
@@ -51,6 +87,26 b' class mergestate(object):' | |||||
51 | if err.errno != errno.ENOENT: |
|
87 | if err.errno != errno.ENOENT: | |
52 | raise |
|
88 | raise | |
53 | return records |
|
89 | return records | |
|
90 | def _readrecordsv2(self): | |||
|
91 | records = [] | |||
|
92 | try: | |||
|
93 | f = self._repo.opener(self.statepathv2) | |||
|
94 | data = f.read() | |||
|
95 | off = 0 | |||
|
96 | end = len(data) | |||
|
97 | while off < end: | |||
|
98 | rtype = data[off] | |||
|
99 | off += 1 | |||
|
100 | lenght = _unpack('>I', data[off:(off + 4)])[0] | |||
|
101 | off += 4 | |||
|
102 | record = data[off:(off + lenght)] | |||
|
103 | off += lenght | |||
|
104 | records.append((rtype, record)) | |||
|
105 | f.close() | |||
|
106 | except IOError, err: | |||
|
107 | if err.errno != errno.ENOENT: | |||
|
108 | raise | |||
|
109 | return records | |||
54 | def commit(self): |
|
110 | def commit(self): | |
55 | if self._dirty: |
|
111 | if self._dirty: | |
56 | records = [] |
|
112 | records = [] | |
@@ -60,7 +116,10 b' class mergestate(object):' | |||||
60 | self._writerecords(records) |
|
116 | self._writerecords(records) | |
61 | self._dirty = False |
|
117 | self._dirty = False | |
62 | def _writerecords(self, records): |
|
118 | def _writerecords(self, records): | |
63 | f = self._repo.opener(self.statepath, "w") |
|
119 | self._writerecordsv1(records) | |
|
120 | self._writerecordsv2(records) | |||
|
121 | def _writerecordsv1(self, records): | |||
|
122 | f = self._repo.opener(self.statepathv1, "w") | |||
64 | irecords = iter(records) |
|
123 | irecords = iter(records) | |
65 | lrecords = irecords.next() |
|
124 | lrecords = irecords.next() | |
66 | assert lrecords[0] == 'L' |
|
125 | assert lrecords[0] == 'L' | |
@@ -69,6 +128,13 b' class mergestate(object):' | |||||
69 | if rtype == "F": |
|
128 | if rtype == "F": | |
70 | f.write("%s\n" % data) |
|
129 | f.write("%s\n" % data) | |
71 | f.close() |
|
130 | f.close() | |
|
131 | def _writerecordsv2(self, records): | |||
|
132 | f = self._repo.opener(self.statepathv2, "w") | |||
|
133 | for key, data in records: | |||
|
134 | assert len(key) == 1 | |||
|
135 | format = ">sI%is" % len(data) | |||
|
136 | f.write(_pack(format, key, len(data), data)) | |||
|
137 | f.close() | |||
72 | def add(self, fcl, fco, fca, fd): |
|
138 | def add(self, fcl, fco, fca, fd): | |
73 | hash = util.sha1(fcl.path()).hexdigest() |
|
139 | hash = util.sha1(fcl.path()).hexdigest() | |
74 | self._repo.opener.write("merge/" + hash, fcl.data()) |
|
140 | self._repo.opener.write("merge/" + hash, fcl.data()) |
General Comments 0
You need to be logged in to leave comments.
Login now