Show More
@@ -47,6 +47,20 b' def _droponode(data):' | |||
|
47 | 47 | bits = bits[:-2] + bits[-1:] |
|
48 | 48 | return '\0'.join(bits) |
|
49 | 49 | |
|
50 | # Merge state record types. See ``mergestate`` docs for more. | |
|
51 | RECORD_LOCAL = b'L' | |
|
52 | RECORD_OTHER = b'O' | |
|
53 | RECORD_MERGED = b'F' | |
|
54 | RECORD_CHANGEDELETE_CONFLICT = b'C' | |
|
55 | RECORD_MERGE_DRIVER_MERGE = b'D' | |
|
56 | RECORD_PATH_CONFLICT = b'P' | |
|
57 | RECORD_MERGE_DRIVER_STATE = b'm' | |
|
58 | RECORD_FILE_VALUES = b'f' | |
|
59 | RECORD_LABELS = b'l' | |
|
60 | RECORD_OVERRIDE = b't' | |
|
61 | RECORD_UNSUPPORTED_MANDATORY = b'X' | |
|
62 | RECORD_UNSUPPORTED_ADVISORY = b'x' | |
|
63 | ||
|
50 | 64 | class mergestate(object): |
|
51 | 65 | '''track 3-way merge state of individual files |
|
52 | 66 | |
@@ -158,11 +172,11 b' class mergestate(object):' | |||
|
158 | 172 | unsupported = set() |
|
159 | 173 | records = self._readrecords() |
|
160 | 174 | for rtype, record in records: |
|
161 |
if rtype == |
|
|
175 | if rtype == RECORD_LOCAL: | |
|
162 | 176 | self._local = bin(record) |
|
163 |
elif rtype == |
|
|
177 | elif rtype == RECORD_OTHER: | |
|
164 | 178 | self._other = bin(record) |
|
165 |
elif rtype == |
|
|
179 | elif rtype == RECORD_MERGE_DRIVER_STATE: | |
|
166 | 180 | bits = record.split('\0', 1) |
|
167 | 181 | mdstate = bits[1] |
|
168 | 182 | if len(mdstate) != 1 or mdstate not in 'ums': |
@@ -171,10 +185,11 b' class mergestate(object):' | |||
|
171 | 185 | |
|
172 | 186 | self._readmergedriver = bits[0] |
|
173 | 187 | self._mdstate = mdstate |
|
174 | elif rtype in 'FDCP': | |
|
188 | elif rtype in (RECORD_MERGED, RECORD_CHANGEDELETE_CONFLICT, | |
|
189 | RECORD_PATH_CONFLICT, RECORD_MERGE_DRIVER_MERGE): | |
|
175 | 190 | bits = record.split('\0') |
|
176 | 191 | self._state[bits[0]] = bits[1:] |
|
177 |
elif rtype == |
|
|
192 | elif rtype == RECORD_FILE_VALUES: | |
|
178 | 193 | filename, rawextras = record.split('\0', 1) |
|
179 | 194 | extraparts = rawextras.split('\0') |
|
180 | 195 | extras = {} |
@@ -184,7 +199,7 b' class mergestate(object):' | |||
|
184 | 199 | i += 2 |
|
185 | 200 | |
|
186 | 201 | self._stateextras[filename] = extras |
|
187 |
elif rtype == |
|
|
202 | elif rtype == RECORD_LABELS: | |
|
188 | 203 | labels = record.split('\0', 2) |
|
189 | 204 | self._labels = [l for l in labels if len(l) > 0] |
|
190 | 205 | elif not rtype.islower(): |
@@ -218,12 +233,12 b' class mergestate(object):' | |||
|
218 | 233 | # we have to infer the "other" changeset of the merge |
|
219 | 234 | # we cannot do better than that with v1 of the format |
|
220 | 235 | mctx = self._repo[None].parents()[-1] |
|
221 |
v1records.append(( |
|
|
236 | v1records.append((RECORD_OTHER, mctx.hex())) | |
|
222 | 237 | # add place holder "other" file node information |
|
223 | 238 | # nobody is using it yet so we do no need to fetch the data |
|
224 | 239 | # if mctx was wrong `mctx[bits[-2]]` may fails. |
|
225 | 240 | for idx, r in enumerate(v1records): |
|
226 |
if r[0] == |
|
|
241 | if r[0] == RECORD_MERGED: | |
|
227 | 242 | bits = r[1].split('\0') |
|
228 | 243 | bits.insert(-2, '') |
|
229 | 244 | v1records[idx] = (r[0], '\0'.join(bits)) |
@@ -232,11 +247,11 b' class mergestate(object):' | |||
|
232 | 247 | def _v1v2match(self, v1records, v2records): |
|
233 | 248 | oldv2 = set() # old format version of v2 record |
|
234 | 249 | for rec in v2records: |
|
235 |
if rec[0] == |
|
|
250 | if rec[0] == RECORD_LOCAL: | |
|
236 | 251 | oldv2.add(rec) |
|
237 |
elif rec[0] == |
|
|
252 | elif rec[0] == RECORD_MERGED: | |
|
238 | 253 | # drop the onode data (not contained in v1) |
|
239 |
oldv2.add(( |
|
|
254 | oldv2.add((RECORD_MERGED, _droponode(rec[1]))) | |
|
240 | 255 | for rec in v1records: |
|
241 | 256 | if rec not in oldv2: |
|
242 | 257 | return False |
@@ -256,9 +271,9 b' class mergestate(object):' | |||
|
256 | 271 | f = self._repo.vfs(self.statepathv1) |
|
257 | 272 | for i, l in enumerate(f): |
|
258 | 273 | if i == 0: |
|
259 |
records.append(( |
|
|
274 | records.append((RECORD_LOCAL, l[:-1])) | |
|
260 | 275 | else: |
|
261 |
records.append(( |
|
|
276 | records.append((RECORD_MERGED, l[:-1])) | |
|
262 | 277 | f.close() |
|
263 | 278 | except IOError as err: |
|
264 | 279 | if err.errno != errno.ENOENT: |
@@ -296,7 +311,7 b' class mergestate(object):' | |||
|
296 | 311 | off += 4 |
|
297 | 312 | record = data[off:(off + length)] |
|
298 | 313 | off += length |
|
299 |
if rtype == |
|
|
314 | if rtype == RECORD_OVERRIDE: | |
|
300 | 315 | rtype, record = record[0:1], record[1:] |
|
301 | 316 | records.append((rtype, record)) |
|
302 | 317 | f.close() |
@@ -359,10 +374,10 b' class mergestate(object):' | |||
|
359 | 374 | |
|
360 | 375 | def _makerecords(self): |
|
361 | 376 | records = [] |
|
362 |
records.append(( |
|
|
363 |
records.append(( |
|
|
377 | records.append((RECORD_LOCAL, hex(self._local))) | |
|
378 | records.append((RECORD_OTHER, hex(self._other))) | |
|
364 | 379 | if self.mergedriver: |
|
365 |
records.append(( |
|
|
380 | records.append((RECORD_MERGE_DRIVER_STATE, '\0'.join([ | |
|
366 | 381 | self.mergedriver, self._mdstate]))) |
|
367 | 382 | # Write out state items. In all cases, the value of the state map entry |
|
368 | 383 | # is written as the contents of the record. The record type depends on |
@@ -372,27 +387,32 b' class mergestate(object):' | |||
|
372 | 387 | for filename, v in self._state.iteritems(): |
|
373 | 388 | if v[0] == 'd': |
|
374 | 389 | # Driver-resolved merge. These are stored in 'D' records. |
|
375 | records.append(('D', '\0'.join([filename] + v))) | |
|
390 | records.append((RECORD_MERGE_DRIVER_MERGE, | |
|
391 | '\0'.join([filename] + v))) | |
|
376 | 392 | elif v[0] in ('pu', 'pr'): |
|
377 | 393 | # Path conflicts. These are stored in 'P' records. The current |
|
378 | 394 | # resolution state ('pu' or 'pr') is stored within the record. |
|
379 | records.append(('P', '\0'.join([filename] + v))) | |
|
395 | records.append((RECORD_PATH_CONFLICT, | |
|
396 | '\0'.join([filename] + v))) | |
|
380 | 397 | elif v[1] == nullhex or v[6] == nullhex: |
|
381 | 398 | # Change/Delete or Delete/Change conflicts. These are stored in |
|
382 | 399 | # 'C' records. v[1] is the local file, and is nullhex when the |
|
383 | 400 | # file is deleted locally ('dc'). v[6] is the remote file, and |
|
384 | 401 | # is nullhex when the file is deleted remotely ('cd'). |
|
385 | records.append(('C', '\0'.join([filename] + v))) | |
|
402 | records.append((RECORD_CHANGEDELETE_CONFLICT, | |
|
403 | '\0'.join([filename] + v))) | |
|
386 | 404 | else: |
|
387 | 405 | # Normal files. These are stored in 'F' records. |
|
388 |
records.append(( |
|
|
406 | records.append((RECORD_MERGED, | |
|
407 | '\0'.join([filename] + v))) | |
|
389 | 408 | for filename, extras in sorted(self._stateextras.iteritems()): |
|
390 | 409 | rawextras = '\0'.join('%s\0%s' % (k, v) for k, v in |
|
391 | 410 | extras.iteritems()) |
|
392 | records.append(('f', '%s\0%s' % (filename, rawextras))) | |
|
411 | records.append((RECORD_FILE_VALUES, | |
|
412 | '%s\0%s' % (filename, rawextras))) | |
|
393 | 413 | if self._labels is not None: |
|
394 | 414 | labels = '\0'.join(self._labels) |
|
395 |
records.append(( |
|
|
415 | records.append((RECORD_LABELS, labels)) | |
|
396 | 416 | return records |
|
397 | 417 | |
|
398 | 418 | def _writerecords(self, records): |
@@ -405,10 +425,10 b' class mergestate(object):' | |||
|
405 | 425 | f = self._repo.vfs(self.statepathv1, 'wb') |
|
406 | 426 | irecords = iter(records) |
|
407 | 427 | lrecords = next(irecords) |
|
408 |
assert lrecords[0] == |
|
|
428 | assert lrecords[0] == RECORD_LOCAL | |
|
409 | 429 | f.write(hex(self._local) + '\n') |
|
410 | 430 | for rtype, data in irecords: |
|
411 |
if rtype == |
|
|
431 | if rtype == RECORD_MERGED: | |
|
412 | 432 | f.write('%s\n' % _droponode(data)) |
|
413 | 433 | f.close() |
|
414 | 434 | |
@@ -417,12 +437,12 b' class mergestate(object):' | |||
|
417 | 437 | |
|
418 | 438 | See the docstring for _readrecordsv2 for why we use 't'.""" |
|
419 | 439 | # these are the records that all version 2 clients can read |
|
420 | whitelist = 'LOF' | |
|
440 | allowlist = (RECORD_LOCAL, RECORD_OTHER, RECORD_MERGED) | |
|
421 | 441 | f = self._repo.vfs(self.statepathv2, 'wb') |
|
422 | 442 | for key, data in records: |
|
423 | 443 | assert len(key) == 1 |
|
424 |
if key not in w |
|
|
425 |
key, data = |
|
|
444 | if key not in allowlist: | |
|
445 | key, data = RECORD_OVERRIDE, '%s%s' % (key, data) | |
|
426 | 446 | format = '>sI%is' % len(data) |
|
427 | 447 | f.write(_pack(format, key, len(data), data)) |
|
428 | 448 | f.close() |
General Comments 0
You need to be logged in to leave comments.
Login now