62 RECORD_UNSUPPORTED_ADVISORY = b'x' |
62 RECORD_UNSUPPORTED_ADVISORY = b'x' |
63 |
63 |
64 MERGE_DRIVER_STATE_UNMARKED = b'u' |
64 MERGE_DRIVER_STATE_UNMARKED = b'u' |
65 MERGE_DRIVER_STATE_MARKED = b'm' |
65 MERGE_DRIVER_STATE_MARKED = b'm' |
66 MERGE_DRIVER_STATE_SUCCESS = b's' |
66 MERGE_DRIVER_STATE_SUCCESS = b's' |
|
67 |
|
68 MERGE_RECORD_UNRESOLVED = b'u' |
|
69 MERGE_RECORD_RESOLVED = b'r' |
|
70 MERGE_RECORD_UNRESOLVED_PATH = b'pu' |
|
71 MERGE_RECORD_RESOLVED_PATH = b'pr' |
|
72 MERGE_RECORD_DRIVER_RESOLVED = b'd' |
67 |
73 |
68 class mergestate(object): |
74 class mergestate(object): |
69 '''track 3-way merge state of individual files |
75 '''track 3-way merge state of individual files |
70 |
76 |
71 The merge state is stored on disk when needed. Two files are used: one with |
77 The merge state is stored on disk when needed. Two files are used: one with |
389 # is written as the contents of the record. The record type depends on |
395 # is written as the contents of the record. The record type depends on |
390 # the type of state that is stored, and capital-letter records are used |
396 # the type of state that is stored, and capital-letter records are used |
391 # to prevent older versions of Mercurial that do not support the feature |
397 # to prevent older versions of Mercurial that do not support the feature |
392 # from loading them. |
398 # from loading them. |
393 for filename, v in self._state.iteritems(): |
399 for filename, v in self._state.iteritems(): |
394 if v[0] == 'd': |
400 if v[0] == MERGE_RECORD_DRIVER_RESOLVED: |
395 # Driver-resolved merge. These are stored in 'D' records. |
401 # Driver-resolved merge. These are stored in 'D' records. |
396 records.append((RECORD_MERGE_DRIVER_MERGE, |
402 records.append((RECORD_MERGE_DRIVER_MERGE, |
397 '\0'.join([filename] + v))) |
403 '\0'.join([filename] + v))) |
398 elif v[0] in ('pu', 'pr'): |
404 elif v[0] in (MERGE_RECORD_UNRESOLVED_PATH, |
|
405 MERGE_RECORD_RESOLVED_PATH): |
399 # Path conflicts. These are stored in 'P' records. The current |
406 # Path conflicts. These are stored in 'P' records. The current |
400 # resolution state ('pu' or 'pr') is stored within the record. |
407 # resolution state ('pu' or 'pr') is stored within the record. |
401 records.append((RECORD_PATH_CONFLICT, |
408 records.append((RECORD_PATH_CONFLICT, |
402 '\0'.join([filename] + v))) |
409 '\0'.join([filename] + v))) |
403 elif v[1] == nullhex or v[6] == nullhex: |
410 elif v[1] == nullhex or v[6] == nullhex: |
465 if fcl.isabsent(): |
472 if fcl.isabsent(): |
466 hash = nullhex |
473 hash = nullhex |
467 else: |
474 else: |
468 hash = hex(hashlib.sha1(fcl.path()).digest()) |
475 hash = hex(hashlib.sha1(fcl.path()).digest()) |
469 self._repo.vfs.write('merge/' + hash, fcl.data()) |
476 self._repo.vfs.write('merge/' + hash, fcl.data()) |
470 self._state[fd] = ['u', hash, fcl.path(), |
477 self._state[fd] = [MERGE_RECORD_UNRESOLVED, hash, fcl.path(), |
471 fca.path(), hex(fca.filenode()), |
478 fca.path(), hex(fca.filenode()), |
472 fco.path(), hex(fco.filenode()), |
479 fco.path(), hex(fco.filenode()), |
473 fcl.flags()] |
480 fcl.flags()] |
474 self._stateextras[fd] = {'ancestorlinknode': hex(fca.node())} |
481 self._stateextras[fd] = {'ancestorlinknode': hex(fca.node())} |
475 self._dirty = True |
482 self._dirty = True |
478 """add a new conflicting path to the merge state |
485 """add a new conflicting path to the merge state |
479 path: the path that conflicts |
486 path: the path that conflicts |
480 frename: the filename the conflicting file was renamed to |
487 frename: the filename the conflicting file was renamed to |
481 forigin: origin of the file ('l' or 'r' for local/remote) |
488 forigin: origin of the file ('l' or 'r' for local/remote) |
482 """ |
489 """ |
483 self._state[path] = ['pu', frename, forigin] |
490 self._state[path] = [MERGE_RECORD_UNRESOLVED_PATH, frename, forigin] |
484 self._dirty = True |
491 self._dirty = True |
485 |
492 |
486 def __contains__(self, dfile): |
493 def __contains__(self, dfile): |
487 return dfile in self._state |
494 return dfile in self._state |
488 |
495 |
504 |
511 |
505 def unresolved(self): |
512 def unresolved(self): |
506 """Obtain the paths of unresolved files.""" |
513 """Obtain the paths of unresolved files.""" |
507 |
514 |
508 for f, entry in self._state.iteritems(): |
515 for f, entry in self._state.iteritems(): |
509 if entry[0] in ('u', 'pu'): |
516 if entry[0] in (MERGE_RECORD_UNRESOLVED, |
|
517 MERGE_RECORD_UNRESOLVED_PATH): |
510 yield f |
518 yield f |
511 |
519 |
512 def driverresolved(self): |
520 def driverresolved(self): |
513 """Obtain the paths of driver-resolved files.""" |
521 """Obtain the paths of driver-resolved files.""" |
514 |
522 |
515 for f, entry in self._state.items(): |
523 for f, entry in self._state.items(): |
516 if entry[0] == 'd': |
524 if entry[0] == MERGE_RECORD_DRIVER_RESOLVED: |
517 yield f |
525 yield f |
518 |
526 |
519 def extras(self, filename): |
527 def extras(self, filename): |
520 return self._stateextras.setdefault(filename, {}) |
528 return self._stateextras.setdefault(filename, {}) |
521 |
529 |
522 def _resolve(self, preresolve, dfile, wctx): |
530 def _resolve(self, preresolve, dfile, wctx): |
523 """rerun merge process for file path `dfile`""" |
531 """rerun merge process for file path `dfile`""" |
524 if self[dfile] in 'rd': |
532 if self[dfile] in (MERGE_RECORD_RESOLVED, |
|
533 MERGE_RECORD_DRIVER_RESOLVED): |
525 return True, 0 |
534 return True, 0 |
526 stateentry = self._state[dfile] |
535 stateentry = self._state[dfile] |
527 state, hash, lfile, afile, anode, ofile, onode, flags = stateentry |
536 state, hash, lfile, afile, anode, ofile, onode, flags = stateentry |
528 octx = self._repo[self._other] |
537 octx = self._repo[self._other] |
529 extras = self.extras(dfile) |
538 extras = self.extras(dfile) |