Mercurial > public > mercurial-scm > hg
comparison mercurial/merge.py @ 20652:2a4871c2511d
merge: adds documentation to the mergestate class
Document most the new function involved in the new serialisation process (and a
few others).
author | Pierre-Yves David <pierre-yves.david@fb.com> |
---|---|
date | Wed, 05 Mar 2014 10:49:43 -0800 |
parents | c1a52dd56eb4 |
children | 89059c450c56 |
comparison
equal
deleted
inserted
replaced
20651:c1a52dd56eb4 | 20652:2a4871c2511d |
---|---|
60 self._other = other | 60 self._other = other |
61 shutil.rmtree(self._repo.join("merge"), True) | 61 shutil.rmtree(self._repo.join("merge"), True) |
62 self._dirty = False | 62 self._dirty = False |
63 | 63 |
64 def _read(self): | 64 def _read(self): |
65 """Analyse each record content to restore a serialized state from disk | |
66 | |
67 This function process "record" entry produced by the de-serialization | |
68 of on disk file. | |
69 """ | |
65 self._state = {} | 70 self._state = {} |
66 records = self._readrecords() | 71 records = self._readrecords() |
67 for rtype, record in records: | 72 for rtype, record in records: |
68 if rtype == 'L': | 73 if rtype == 'L': |
69 self._local = bin(record) | 74 self._local = bin(record) |
76 raise util.Abort(_('unsupported merge state record:' | 81 raise util.Abort(_('unsupported merge state record:' |
77 % rtype)) | 82 % rtype)) |
78 self._dirty = False | 83 self._dirty = False |
79 | 84 |
80 def _readrecords(self): | 85 def _readrecords(self): |
86 """Read merge state from disk and return a list of record (TYPE, data) | |
87 | |
88 We read data from both V1 and Ve files decide which on to use. | |
89 | |
90 V1 have been used by version prior to 2.9.1 and contains less data than | |
91 v2. We read both version and check if no data in v2 contradict one in | |
92 v1. If there is not contradiction we can safely assume that both v1 | |
93 and v2 were written at the same time and use the extract data in v2. If | |
94 there is contradiction we ignore v2 content as we assume an old version | |
95 of Mercurial have over written the mergstate file and left an old v2 | |
96 file around. | |
97 | |
98 returns list of record [(TYPE, data), ...]""" | |
81 v1records = self._readrecordsv1() | 99 v1records = self._readrecordsv1() |
82 v2records = self._readrecordsv2() | 100 v2records = self._readrecordsv2() |
83 oldv2 = set() # old format version of v2 record | 101 oldv2 = set() # old format version of v2 record |
84 for rec in v2records: | 102 for rec in v2records: |
85 if rec[0] == 'L': | 103 if rec[0] == 'L': |
105 return v1records | 123 return v1records |
106 else: | 124 else: |
107 return v2records | 125 return v2records |
108 | 126 |
109 def _readrecordsv1(self): | 127 def _readrecordsv1(self): |
128 """read on disk merge state for version 1 file | |
129 | |
130 returns list of record [(TYPE, data), ...] | |
131 | |
132 Note: the "F" data from this file are one entry short | |
133 (no "other file node" entry) | |
134 """ | |
110 records = [] | 135 records = [] |
111 try: | 136 try: |
112 f = self._repo.opener(self.statepathv1) | 137 f = self._repo.opener(self.statepathv1) |
113 for i, l in enumerate(f): | 138 for i, l in enumerate(f): |
114 if i == 0: | 139 if i == 0: |
120 if err.errno != errno.ENOENT: | 145 if err.errno != errno.ENOENT: |
121 raise | 146 raise |
122 return records | 147 return records |
123 | 148 |
124 def _readrecordsv2(self): | 149 def _readrecordsv2(self): |
150 """read on disk merge state for version 2 file | |
151 | |
152 returns list of record [(TYPE, data), ...] | |
153 """ | |
125 records = [] | 154 records = [] |
126 try: | 155 try: |
127 f = self._repo.opener(self.statepathv2) | 156 f = self._repo.opener(self.statepathv2) |
128 data = f.read() | 157 data = f.read() |
129 off = 0 | 158 off = 0 |
141 if err.errno != errno.ENOENT: | 170 if err.errno != errno.ENOENT: |
142 raise | 171 raise |
143 return records | 172 return records |
144 | 173 |
145 def commit(self): | 174 def commit(self): |
175 """Write current state on disk (if necessary)""" | |
146 if self._dirty: | 176 if self._dirty: |
147 records = [] | 177 records = [] |
148 records.append(("L", hex(self._local))) | 178 records.append(("L", hex(self._local))) |
149 records.append(("O", hex(self._other))) | 179 records.append(("O", hex(self._other))) |
150 for d, v in self._state.iteritems(): | 180 for d, v in self._state.iteritems(): |
151 records.append(("F", "\0".join([d] + v))) | 181 records.append(("F", "\0".join([d] + v))) |
152 self._writerecords(records) | 182 self._writerecords(records) |
153 self._dirty = False | 183 self._dirty = False |
154 | 184 |
155 def _writerecords(self, records): | 185 def _writerecords(self, records): |
186 """Write current state on disk (both v1 and v2)""" | |
156 self._writerecordsv1(records) | 187 self._writerecordsv1(records) |
157 self._writerecordsv2(records) | 188 self._writerecordsv2(records) |
158 | 189 |
159 def _writerecordsv1(self, records): | 190 def _writerecordsv1(self, records): |
191 """Write current state on disk in a version 1 file""" | |
160 f = self._repo.opener(self.statepathv1, "w") | 192 f = self._repo.opener(self.statepathv1, "w") |
161 irecords = iter(records) | 193 irecords = iter(records) |
162 lrecords = irecords.next() | 194 lrecords = irecords.next() |
163 assert lrecords[0] == 'L' | 195 assert lrecords[0] == 'L' |
164 f.write(hex(self._local) + "\n") | 196 f.write(hex(self._local) + "\n") |
166 if rtype == "F": | 198 if rtype == "F": |
167 f.write("%s\n" % _droponode(data)) | 199 f.write("%s\n" % _droponode(data)) |
168 f.close() | 200 f.close() |
169 | 201 |
170 def _writerecordsv2(self, records): | 202 def _writerecordsv2(self, records): |
203 """Write current state on disk in a version 2 file""" | |
171 f = self._repo.opener(self.statepathv2, "w") | 204 f = self._repo.opener(self.statepathv2, "w") |
172 for key, data in records: | 205 for key, data in records: |
173 assert len(key) == 1 | 206 assert len(key) == 1 |
174 format = ">sI%is" % len(data) | 207 format = ">sI%is" % len(data) |
175 f.write(_pack(format, key, len(data), data)) | 208 f.write(_pack(format, key, len(data), data)) |
176 f.close() | 209 f.close() |
177 | 210 |
178 def add(self, fcl, fco, fca, fd): | 211 def add(self, fcl, fco, fca, fd): |
212 """add a new (potentially?) conflicting file the merge state | |
213 fcl: file context for local, | |
214 fco: file context for remote, | |
215 fca: file context for ancestors, | |
216 fd: file path of the resulting merge. | |
217 | |
218 note: also write the local version to the `.hg/merge` directory. | |
219 """ | |
179 hash = util.sha1(fcl.path()).hexdigest() | 220 hash = util.sha1(fcl.path()).hexdigest() |
180 self._repo.opener.write("merge/" + hash, fcl.data()) | 221 self._repo.opener.write("merge/" + hash, fcl.data()) |
181 self._state[fd] = ['u', hash, fcl.path(), | 222 self._state[fd] = ['u', hash, fcl.path(), |
182 fca.path(), hex(fca.filenode()), | 223 fca.path(), hex(fca.filenode()), |
183 fco.path(), hex(fco.filenode()), | 224 fco.path(), hex(fco.filenode()), |
202 def mark(self, dfile, state): | 243 def mark(self, dfile, state): |
203 self._state[dfile][0] = state | 244 self._state[dfile][0] = state |
204 self._dirty = True | 245 self._dirty = True |
205 | 246 |
206 def resolve(self, dfile, wctx): | 247 def resolve(self, dfile, wctx): |
248 """rerun merge process for file path `dfile`""" | |
207 if self[dfile] == 'r': | 249 if self[dfile] == 'r': |
208 return 0 | 250 return 0 |
209 stateentry = self._state[dfile] | 251 stateentry = self._state[dfile] |
210 state, hash, lfile, afile, anode, ofile, onode, flags = stateentry | 252 state, hash, lfile, afile, anode, ofile, onode, flags = stateentry |
211 octx = self._repo[self._other] | 253 octx = self._repo[self._other] |