mercurial/simplemerge.py
changeset 43077 687b865b95ad
parent 43076 2372284d9457
child 43486 3b581ad59459
equal deleted inserted replaced
43076:2372284d9457 43077:687b865b95ad
    91     def merge_lines(
    91     def merge_lines(
    92         self,
    92         self,
    93         name_a=None,
    93         name_a=None,
    94         name_b=None,
    94         name_b=None,
    95         name_base=None,
    95         name_base=None,
    96         start_marker='<<<<<<<',
    96         start_marker=b'<<<<<<<',
    97         mid_marker='=======',
    97         mid_marker=b'=======',
    98         end_marker='>>>>>>>',
    98         end_marker=b'>>>>>>>',
    99         base_marker=None,
    99         base_marker=None,
   100         localorother=None,
   100         localorother=None,
   101         minimize=False,
   101         minimize=False,
   102     ):
   102     ):
   103         """Return merge in cvs-like form.
   103         """Return merge in cvs-like form.
   104         """
   104         """
   105         self.conflicts = False
   105         self.conflicts = False
   106         newline = '\n'
   106         newline = b'\n'
   107         if len(self.a) > 0:
   107         if len(self.a) > 0:
   108             if self.a[0].endswith('\r\n'):
   108             if self.a[0].endswith(b'\r\n'):
   109                 newline = '\r\n'
   109                 newline = b'\r\n'
   110             elif self.a[0].endswith('\r'):
   110             elif self.a[0].endswith(b'\r'):
   111                 newline = '\r'
   111                 newline = b'\r'
   112         if name_a and start_marker:
   112         if name_a and start_marker:
   113             start_marker = start_marker + ' ' + name_a
   113             start_marker = start_marker + b' ' + name_a
   114         if name_b and end_marker:
   114         if name_b and end_marker:
   115             end_marker = end_marker + ' ' + name_b
   115             end_marker = end_marker + b' ' + name_b
   116         if name_base and base_marker:
   116         if name_base and base_marker:
   117             base_marker = base_marker + ' ' + name_base
   117             base_marker = base_marker + b' ' + name_base
   118         merge_regions = self.merge_regions()
   118         merge_regions = self.merge_regions()
   119         if minimize:
   119         if minimize:
   120             merge_regions = self.minimize(merge_regions)
   120             merge_regions = self.minimize(merge_regions)
   121         for t in merge_regions:
   121         for t in merge_regions:
   122             what = t[0]
   122             what = t[0]
   123             if what == 'unchanged':
   123             if what == b'unchanged':
   124                 for i in range(t[1], t[2]):
   124                 for i in range(t[1], t[2]):
   125                     yield self.base[i]
   125                     yield self.base[i]
   126             elif what == 'a' or what == 'same':
   126             elif what == b'a' or what == b'same':
   127                 for i in range(t[1], t[2]):
   127                 for i in range(t[1], t[2]):
   128                     yield self.a[i]
   128                     yield self.a[i]
   129             elif what == 'b':
   129             elif what == b'b':
   130                 for i in range(t[1], t[2]):
   130                 for i in range(t[1], t[2]):
   131                     yield self.b[i]
   131                     yield self.b[i]
   132             elif what == 'conflict':
   132             elif what == b'conflict':
   133                 if localorother == 'local':
   133                 if localorother == b'local':
   134                     for i in range(t[3], t[4]):
   134                     for i in range(t[3], t[4]):
   135                         yield self.a[i]
   135                         yield self.a[i]
   136                 elif localorother == 'other':
   136                 elif localorother == b'other':
   137                     for i in range(t[5], t[6]):
   137                     for i in range(t[5], t[6]):
   138                         yield self.b[i]
   138                         yield self.b[i]
   139                 else:
   139                 else:
   140                     self.conflicts = True
   140                     self.conflicts = True
   141                     if start_marker is not None:
   141                     if start_marker is not None:
   173         'conflict', base_lines, a_lines, b_lines
   173         'conflict', base_lines, a_lines, b_lines
   174              Lines from base were changed to either a or b and conflict.
   174              Lines from base were changed to either a or b and conflict.
   175         """
   175         """
   176         for t in self.merge_regions():
   176         for t in self.merge_regions():
   177             what = t[0]
   177             what = t[0]
   178             if what == 'unchanged':
   178             if what == b'unchanged':
   179                 yield what, self.base[t[1] : t[2]]
   179                 yield what, self.base[t[1] : t[2]]
   180             elif what == 'a' or what == 'same':
   180             elif what == b'a' or what == b'same':
   181                 yield what, self.a[t[1] : t[2]]
   181                 yield what, self.a[t[1] : t[2]]
   182             elif what == 'b':
   182             elif what == b'b':
   183                 yield what, self.b[t[1] : t[2]]
   183                 yield what, self.b[t[1] : t[2]]
   184             elif what == 'conflict':
   184             elif what == b'conflict':
   185                 yield (
   185                 yield (
   186                     what,
   186                     what,
   187                     self.base[t[1] : t[2]],
   187                     self.base[t[1] : t[2]],
   188                     self.a[t[3] : t[4]],
   188                     self.a[t[3] : t[4]],
   189                     self.b[t[5] : t[6]],
   189                     self.b[t[5] : t[6]],
   251                     self.b, ib, bmatch, self.base, iz, zmatch
   251                     self.b, ib, bmatch, self.base, iz, zmatch
   252                 )
   252                 )
   253                 same = compare_range(self.a, ia, amatch, self.b, ib, bmatch)
   253                 same = compare_range(self.a, ia, amatch, self.b, ib, bmatch)
   254 
   254 
   255                 if same:
   255                 if same:
   256                     yield 'same', ia, amatch
   256                     yield b'same', ia, amatch
   257                 elif equal_a and not equal_b:
   257                 elif equal_a and not equal_b:
   258                     yield 'b', ib, bmatch
   258                     yield b'b', ib, bmatch
   259                 elif equal_b and not equal_a:
   259                 elif equal_b and not equal_a:
   260                     yield 'a', ia, amatch
   260                     yield b'a', ia, amatch
   261                 elif not equal_a and not equal_b:
   261                 elif not equal_a and not equal_b:
   262                     yield 'conflict', iz, zmatch, ia, amatch, ib, bmatch
   262                     yield b'conflict', iz, zmatch, ia, amatch, ib, bmatch
   263                 else:
   263                 else:
   264                     raise AssertionError("can't handle a=b=base but unmatched")
   264                     raise AssertionError(b"can't handle a=b=base but unmatched")
   265 
   265 
   266                 ia = amatch
   266                 ia = amatch
   267                 ib = bmatch
   267                 ib = bmatch
   268             iz = zmatch
   268             iz = zmatch
   269 
   269 
   273             if matchlen > 0:
   273             if matchlen > 0:
   274                 assert ia == amatch
   274                 assert ia == amatch
   275                 assert ib == bmatch
   275                 assert ib == bmatch
   276                 assert iz == zmatch
   276                 assert iz == zmatch
   277 
   277 
   278                 yield 'unchanged', zmatch, zend
   278                 yield b'unchanged', zmatch, zend
   279                 iz = zend
   279                 iz = zend
   280                 ia = aend
   280                 ia = aend
   281                 ib = bend
   281                 ib = bend
   282 
   282 
   283     def minimize(self, merge_regions):
   283     def minimize(self, merge_regions):
   286         Lines where both A and B have made the same changes at the beginning
   286         Lines where both A and B have made the same changes at the beginning
   287         or the end of each merge region are eliminated from the conflict
   287         or the end of each merge region are eliminated from the conflict
   288         region and are instead considered the same.
   288         region and are instead considered the same.
   289         """
   289         """
   290         for region in merge_regions:
   290         for region in merge_regions:
   291             if region[0] != "conflict":
   291             if region[0] != b"conflict":
   292                 yield region
   292                 yield region
   293                 continue
   293                 continue
   294             issue, z1, z2, a1, a2, b1, b2 = region
   294             issue, z1, z2, a1, a2, b1, b2 = region
   295             alen = a2 - a1
   295             alen = a2 - a1
   296             blen = b2 - b1
   296             blen = b2 - b1
   312             ):
   312             ):
   313                 ii += 1
   313                 ii += 1
   314             endmatches = ii
   314             endmatches = ii
   315 
   315 
   316             if startmatches > 0:
   316             if startmatches > 0:
   317                 yield 'same', a1, a1 + startmatches
   317                 yield b'same', a1, a1 + startmatches
   318 
   318 
   319             yield (
   319             yield (
   320                 'conflict',
   320                 b'conflict',
   321                 z1,
   321                 z1,
   322                 z2,
   322                 z2,
   323                 a1 + startmatches,
   323                 a1 + startmatches,
   324                 a2 - endmatches,
   324                 a2 - endmatches,
   325                 b1 + startmatches,
   325                 b1 + startmatches,
   326                 b2 - endmatches,
   326                 b2 - endmatches,
   327             )
   327             )
   328 
   328 
   329             if endmatches > 0:
   329             if endmatches > 0:
   330                 yield 'same', a2 - endmatches, a2
   330                 yield b'same', a2 - endmatches, a2
   331 
   331 
   332     def find_sync_regions(self):
   332     def find_sync_regions(self):
   333         """Return a list of sync regions, where both descendants match the base.
   333         """Return a list of sync regions, where both descendants match the base.
   334 
   334 
   335         Generates a list of (base1, base2, a1, a2, b1, b2).  There is
   335         Generates a list of (base1, base2, a1, a2, b1, b2).  There is
   418 
   418 
   419 def _verifytext(text, path, ui, opts):
   419 def _verifytext(text, path, ui, opts):
   420     """verifies that text is non-binary (unless opts[text] is passed,
   420     """verifies that text is non-binary (unless opts[text] is passed,
   421     then we just warn)"""
   421     then we just warn)"""
   422     if stringutil.binary(text):
   422     if stringutil.binary(text):
   423         msg = _("%s looks like a binary file.") % path
   423         msg = _(b"%s looks like a binary file.") % path
   424         if not opts.get('quiet'):
   424         if not opts.get(b'quiet'):
   425             ui.warn(_('warning: %s\n') % msg)
   425             ui.warn(_(b'warning: %s\n') % msg)
   426         if not opts.get('text'):
   426         if not opts.get(b'text'):
   427             raise error.Abort(msg)
   427             raise error.Abort(msg)
   428     return text
   428     return text
   429 
   429 
   430 
   430 
   431 def _picklabels(defaults, overrides):
   431 def _picklabels(defaults, overrides):
   432     if len(overrides) > 3:
   432     if len(overrides) > 3:
   433         raise error.Abort(_("can only specify three labels."))
   433         raise error.Abort(_(b"can only specify three labels."))
   434     result = defaults[:]
   434     result = defaults[:]
   435     for i, override in enumerate(overrides):
   435     for i, override in enumerate(overrides):
   436         result[i] = override
   436         result[i] = override
   437     return result
   437     return result
   438 
   438 
   452         # Maintain that behavior today for BC, though perhaps in the future
   452         # Maintain that behavior today for BC, though perhaps in the future
   453         # it'd be worth considering whether merging encoded data (what the
   453         # it'd be worth considering whether merging encoded data (what the
   454         # repository usually sees) might be more useful.
   454         # repository usually sees) might be more useful.
   455         return _verifytext(ctx.decodeddata(), ctx.path(), ui, opts)
   455         return _verifytext(ctx.decodeddata(), ctx.path(), ui, opts)
   456 
   456 
   457     mode = opts.get('mode', 'merge')
   457     mode = opts.get(b'mode', b'merge')
   458     name_a, name_b, name_base = None, None, None
   458     name_a, name_b, name_base = None, None, None
   459     if mode != 'union':
   459     if mode != b'union':
   460         name_a, name_b, name_base = _picklabels(
   460         name_a, name_b, name_base = _picklabels(
   461             [localctx.path(), otherctx.path(), None], opts.get('label', [])
   461             [localctx.path(), otherctx.path(), None], opts.get(b'label', [])
   462         )
   462         )
   463 
   463 
   464     try:
   464     try:
   465         localtext = readctx(localctx)
   465         localtext = readctx(localctx)
   466         basetext = readctx(basectx)
   466         basetext = readctx(basectx)
   468     except error.Abort:
   468     except error.Abort:
   469         return 1
   469         return 1
   470 
   470 
   471     m3 = Merge3Text(basetext, localtext, othertext)
   471     m3 = Merge3Text(basetext, localtext, othertext)
   472     extrakwargs = {
   472     extrakwargs = {
   473         "localorother": opts.get("localorother", None),
   473         b"localorother": opts.get(b"localorother", None),
   474         'minimize': True,
   474         b'minimize': True,
   475     }
   475     }
   476     if mode == 'union':
   476     if mode == b'union':
   477         extrakwargs['start_marker'] = None
   477         extrakwargs[b'start_marker'] = None
   478         extrakwargs['mid_marker'] = None
   478         extrakwargs[b'mid_marker'] = None
   479         extrakwargs['end_marker'] = None
   479         extrakwargs[b'end_marker'] = None
   480     elif name_base is not None:
   480     elif name_base is not None:
   481         extrakwargs['base_marker'] = '|||||||'
   481         extrakwargs[b'base_marker'] = b'|||||||'
   482         extrakwargs['name_base'] = name_base
   482         extrakwargs[b'name_base'] = name_base
   483         extrakwargs['minimize'] = False
   483         extrakwargs[b'minimize'] = False
   484 
   484 
   485     mergedtext = ""
   485     mergedtext = b""
   486     for line in m3.merge_lines(
   486     for line in m3.merge_lines(
   487         name_a=name_a, name_b=name_b, **pycompat.strkwargs(extrakwargs)
   487         name_a=name_a, name_b=name_b, **pycompat.strkwargs(extrakwargs)
   488     ):
   488     ):
   489         if opts.get('print'):
   489         if opts.get(b'print'):
   490             ui.fout.write(line)
   490             ui.fout.write(line)
   491         else:
   491         else:
   492             mergedtext += line
   492             mergedtext += line
   493 
   493 
   494     if not opts.get('print'):
   494     if not opts.get(b'print'):
   495         localctx.write(mergedtext, localctx.flags())
   495         localctx.write(mergedtext, localctx.flags())
   496 
   496 
   497     if m3.conflicts and not mode == 'union':
   497     if m3.conflicts and not mode == b'union':
   498         return 1
   498         return 1