##// END OF EJS Templates
merge: define conflict marker labels in filemerge()...
Durham Goode -
r21273:20b8090d default
parent child Browse files
Show More
@@ -1,378 +1,378 b''
1 # filemerge.py - file-level merge handling for Mercurial
1 # filemerge.py - file-level merge handling for Mercurial
2 #
2 #
3 # Copyright 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
4 #
4 #
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 from node import short
8 from node import short
9 from i18n import _
9 from i18n import _
10 import util, simplemerge, match, error
10 import util, simplemerge, match, error
11 import os, tempfile, re, filecmp
11 import os, tempfile, re, filecmp
12
12
13 def _toolstr(ui, tool, part, default=""):
13 def _toolstr(ui, tool, part, default=""):
14 return ui.config("merge-tools", tool + "." + part, default)
14 return ui.config("merge-tools", tool + "." + part, default)
15
15
16 def _toolbool(ui, tool, part, default=False):
16 def _toolbool(ui, tool, part, default=False):
17 return ui.configbool("merge-tools", tool + "." + part, default)
17 return ui.configbool("merge-tools", tool + "." + part, default)
18
18
19 def _toollist(ui, tool, part, default=[]):
19 def _toollist(ui, tool, part, default=[]):
20 return ui.configlist("merge-tools", tool + "." + part, default)
20 return ui.configlist("merge-tools", tool + "." + part, default)
21
21
22 internals = {}
22 internals = {}
23
23
24 def internaltool(name, trymerge, onfailure=None):
24 def internaltool(name, trymerge, onfailure=None):
25 '''return a decorator for populating internal merge tool table'''
25 '''return a decorator for populating internal merge tool table'''
26 def decorator(func):
26 def decorator(func):
27 fullname = 'internal:' + name
27 fullname = 'internal:' + name
28 func.__doc__ = "``%s``\n" % fullname + func.__doc__.strip()
28 func.__doc__ = "``%s``\n" % fullname + func.__doc__.strip()
29 internals[fullname] = func
29 internals[fullname] = func
30 func.trymerge = trymerge
30 func.trymerge = trymerge
31 func.onfailure = onfailure
31 func.onfailure = onfailure
32 return func
32 return func
33 return decorator
33 return decorator
34
34
35 def _findtool(ui, tool):
35 def _findtool(ui, tool):
36 if tool in internals:
36 if tool in internals:
37 return tool
37 return tool
38 for kn in ("regkey", "regkeyalt"):
38 for kn in ("regkey", "regkeyalt"):
39 k = _toolstr(ui, tool, kn)
39 k = _toolstr(ui, tool, kn)
40 if not k:
40 if not k:
41 continue
41 continue
42 p = util.lookupreg(k, _toolstr(ui, tool, "regname"))
42 p = util.lookupreg(k, _toolstr(ui, tool, "regname"))
43 if p:
43 if p:
44 p = util.findexe(p + _toolstr(ui, tool, "regappend"))
44 p = util.findexe(p + _toolstr(ui, tool, "regappend"))
45 if p:
45 if p:
46 return p
46 return p
47 exe = _toolstr(ui, tool, "executable", tool)
47 exe = _toolstr(ui, tool, "executable", tool)
48 return util.findexe(util.expandpath(exe))
48 return util.findexe(util.expandpath(exe))
49
49
50 def _picktool(repo, ui, path, binary, symlink):
50 def _picktool(repo, ui, path, binary, symlink):
51 def check(tool, pat, symlink, binary):
51 def check(tool, pat, symlink, binary):
52 tmsg = tool
52 tmsg = tool
53 if pat:
53 if pat:
54 tmsg += " specified for " + pat
54 tmsg += " specified for " + pat
55 if not _findtool(ui, tool):
55 if not _findtool(ui, tool):
56 if pat: # explicitly requested tool deserves a warning
56 if pat: # explicitly requested tool deserves a warning
57 ui.warn(_("couldn't find merge tool %s\n") % tmsg)
57 ui.warn(_("couldn't find merge tool %s\n") % tmsg)
58 else: # configured but non-existing tools are more silent
58 else: # configured but non-existing tools are more silent
59 ui.note(_("couldn't find merge tool %s\n") % tmsg)
59 ui.note(_("couldn't find merge tool %s\n") % tmsg)
60 elif symlink and not _toolbool(ui, tool, "symlink"):
60 elif symlink and not _toolbool(ui, tool, "symlink"):
61 ui.warn(_("tool %s can't handle symlinks\n") % tmsg)
61 ui.warn(_("tool %s can't handle symlinks\n") % tmsg)
62 elif binary and not _toolbool(ui, tool, "binary"):
62 elif binary and not _toolbool(ui, tool, "binary"):
63 ui.warn(_("tool %s can't handle binary\n") % tmsg)
63 ui.warn(_("tool %s can't handle binary\n") % tmsg)
64 elif not util.gui() and _toolbool(ui, tool, "gui"):
64 elif not util.gui() and _toolbool(ui, tool, "gui"):
65 ui.warn(_("tool %s requires a GUI\n") % tmsg)
65 ui.warn(_("tool %s requires a GUI\n") % tmsg)
66 else:
66 else:
67 return True
67 return True
68 return False
68 return False
69
69
70 # forcemerge comes from command line arguments, highest priority
70 # forcemerge comes from command line arguments, highest priority
71 force = ui.config('ui', 'forcemerge')
71 force = ui.config('ui', 'forcemerge')
72 if force:
72 if force:
73 toolpath = _findtool(ui, force)
73 toolpath = _findtool(ui, force)
74 if toolpath:
74 if toolpath:
75 return (force, util.shellquote(toolpath))
75 return (force, util.shellquote(toolpath))
76 else:
76 else:
77 # mimic HGMERGE if given tool not found
77 # mimic HGMERGE if given tool not found
78 return (force, force)
78 return (force, force)
79
79
80 # HGMERGE takes next precedence
80 # HGMERGE takes next precedence
81 hgmerge = os.environ.get("HGMERGE")
81 hgmerge = os.environ.get("HGMERGE")
82 if hgmerge:
82 if hgmerge:
83 return (hgmerge, hgmerge)
83 return (hgmerge, hgmerge)
84
84
85 # then patterns
85 # then patterns
86 for pat, tool in ui.configitems("merge-patterns"):
86 for pat, tool in ui.configitems("merge-patterns"):
87 mf = match.match(repo.root, '', [pat])
87 mf = match.match(repo.root, '', [pat])
88 if mf(path) and check(tool, pat, symlink, False):
88 if mf(path) and check(tool, pat, symlink, False):
89 toolpath = _findtool(ui, tool)
89 toolpath = _findtool(ui, tool)
90 return (tool, util.shellquote(toolpath))
90 return (tool, util.shellquote(toolpath))
91
91
92 # then merge tools
92 # then merge tools
93 tools = {}
93 tools = {}
94 for k, v in ui.configitems("merge-tools"):
94 for k, v in ui.configitems("merge-tools"):
95 t = k.split('.')[0]
95 t = k.split('.')[0]
96 if t not in tools:
96 if t not in tools:
97 tools[t] = int(_toolstr(ui, t, "priority", "0"))
97 tools[t] = int(_toolstr(ui, t, "priority", "0"))
98 names = tools.keys()
98 names = tools.keys()
99 tools = sorted([(-p, t) for t, p in tools.items()])
99 tools = sorted([(-p, t) for t, p in tools.items()])
100 uimerge = ui.config("ui", "merge")
100 uimerge = ui.config("ui", "merge")
101 if uimerge:
101 if uimerge:
102 if uimerge not in names:
102 if uimerge not in names:
103 return (uimerge, uimerge)
103 return (uimerge, uimerge)
104 tools.insert(0, (None, uimerge)) # highest priority
104 tools.insert(0, (None, uimerge)) # highest priority
105 tools.append((None, "hgmerge")) # the old default, if found
105 tools.append((None, "hgmerge")) # the old default, if found
106 for p, t in tools:
106 for p, t in tools:
107 if check(t, None, symlink, binary):
107 if check(t, None, symlink, binary):
108 toolpath = _findtool(ui, t)
108 toolpath = _findtool(ui, t)
109 return (t, util.shellquote(toolpath))
109 return (t, util.shellquote(toolpath))
110
110
111 # internal merge or prompt as last resort
111 # internal merge or prompt as last resort
112 if symlink or binary:
112 if symlink or binary:
113 return "internal:prompt", None
113 return "internal:prompt", None
114 return "internal:merge", None
114 return "internal:merge", None
115
115
116 def _eoltype(data):
116 def _eoltype(data):
117 "Guess the EOL type of a file"
117 "Guess the EOL type of a file"
118 if '\0' in data: # binary
118 if '\0' in data: # binary
119 return None
119 return None
120 if '\r\n' in data: # Windows
120 if '\r\n' in data: # Windows
121 return '\r\n'
121 return '\r\n'
122 if '\r' in data: # Old Mac
122 if '\r' in data: # Old Mac
123 return '\r'
123 return '\r'
124 if '\n' in data: # UNIX
124 if '\n' in data: # UNIX
125 return '\n'
125 return '\n'
126 return None # unknown
126 return None # unknown
127
127
128 def _matcheol(file, origfile):
128 def _matcheol(file, origfile):
129 "Convert EOL markers in a file to match origfile"
129 "Convert EOL markers in a file to match origfile"
130 tostyle = _eoltype(util.readfile(origfile))
130 tostyle = _eoltype(util.readfile(origfile))
131 if tostyle:
131 if tostyle:
132 data = util.readfile(file)
132 data = util.readfile(file)
133 style = _eoltype(data)
133 style = _eoltype(data)
134 if style:
134 if style:
135 newdata = data.replace(style, tostyle)
135 newdata = data.replace(style, tostyle)
136 if newdata != data:
136 if newdata != data:
137 util.writefile(file, newdata)
137 util.writefile(file, newdata)
138
138
139 @internaltool('prompt', False)
139 @internaltool('prompt', False)
140 def _iprompt(repo, mynode, orig, fcd, fco, fca, toolconf):
140 def _iprompt(repo, mynode, orig, fcd, fco, fca, toolconf):
141 """Asks the user which of the local or the other version to keep as
141 """Asks the user which of the local or the other version to keep as
142 the merged version."""
142 the merged version."""
143 ui = repo.ui
143 ui = repo.ui
144 fd = fcd.path()
144 fd = fcd.path()
145
145
146 if ui.promptchoice(_(" no tool found to merge %s\n"
146 if ui.promptchoice(_(" no tool found to merge %s\n"
147 "keep (l)ocal or take (o)ther?"
147 "keep (l)ocal or take (o)ther?"
148 "$$ &Local $$ &Other") % fd, 0):
148 "$$ &Local $$ &Other") % fd, 0):
149 return _iother(repo, mynode, orig, fcd, fco, fca, toolconf)
149 return _iother(repo, mynode, orig, fcd, fco, fca, toolconf)
150 else:
150 else:
151 return _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf)
151 return _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf)
152
152
153 @internaltool('local', False)
153 @internaltool('local', False)
154 def _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf):
154 def _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf):
155 """Uses the local version of files as the merged version."""
155 """Uses the local version of files as the merged version."""
156 return 0
156 return 0
157
157
158 @internaltool('other', False)
158 @internaltool('other', False)
159 def _iother(repo, mynode, orig, fcd, fco, fca, toolconf):
159 def _iother(repo, mynode, orig, fcd, fco, fca, toolconf):
160 """Uses the other version of files as the merged version."""
160 """Uses the other version of files as the merged version."""
161 repo.wwrite(fcd.path(), fco.data(), fco.flags())
161 repo.wwrite(fcd.path(), fco.data(), fco.flags())
162 return 0
162 return 0
163
163
164 @internaltool('fail', False)
164 @internaltool('fail', False)
165 def _ifail(repo, mynode, orig, fcd, fco, fca, toolconf):
165 def _ifail(repo, mynode, orig, fcd, fco, fca, toolconf):
166 """
166 """
167 Rather than attempting to merge files that were modified on both
167 Rather than attempting to merge files that were modified on both
168 branches, it marks them as unresolved. The resolve command must be
168 branches, it marks them as unresolved. The resolve command must be
169 used to resolve these conflicts."""
169 used to resolve these conflicts."""
170 return 1
170 return 1
171
171
172 def _premerge(repo, toolconf, files):
172 def _premerge(repo, toolconf, files, labels=None):
173 tool, toolpath, binary, symlink = toolconf
173 tool, toolpath, binary, symlink = toolconf
174 if symlink:
174 if symlink:
175 return 1
175 return 1
176 a, b, c, back = files
176 a, b, c, back = files
177
177
178 ui = repo.ui
178 ui = repo.ui
179
179
180 # do we attempt to simplemerge first?
180 # do we attempt to simplemerge first?
181 try:
181 try:
182 premerge = _toolbool(ui, tool, "premerge", not binary)
182 premerge = _toolbool(ui, tool, "premerge", not binary)
183 except error.ConfigError:
183 except error.ConfigError:
184 premerge = _toolstr(ui, tool, "premerge").lower()
184 premerge = _toolstr(ui, tool, "premerge").lower()
185 valid = 'keep'.split()
185 valid = 'keep'.split()
186 if premerge not in valid:
186 if premerge not in valid:
187 _valid = ', '.join(["'" + v + "'" for v in valid])
187 _valid = ', '.join(["'" + v + "'" for v in valid])
188 raise error.ConfigError(_("%s.premerge not valid "
188 raise error.ConfigError(_("%s.premerge not valid "
189 "('%s' is neither boolean nor %s)") %
189 "('%s' is neither boolean nor %s)") %
190 (tool, premerge, _valid))
190 (tool, premerge, _valid))
191
191
192 if premerge:
192 if premerge:
193 r = simplemerge.simplemerge(ui, a, b, c, quiet=True)
193 r = simplemerge.simplemerge(ui, a, b, c, quiet=True, label=labels)
194 if not r:
194 if not r:
195 ui.debug(" premerge successful\n")
195 ui.debug(" premerge successful\n")
196 return 0
196 return 0
197 if premerge != 'keep':
197 if premerge != 'keep':
198 util.copyfile(back, a) # restore from backup and try again
198 util.copyfile(back, a) # restore from backup and try again
199 return 1 # continue merging
199 return 1 # continue merging
200
200
201 @internaltool('merge', True,
201 @internaltool('merge', True,
202 _("merging %s incomplete! "
202 _("merging %s incomplete! "
203 "(edit conflicts, then use 'hg resolve --mark')\n"))
203 "(edit conflicts, then use 'hg resolve --mark')\n"))
204 def _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files):
204 def _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
205 """
205 """
206 Uses the internal non-interactive simple merge algorithm for merging
206 Uses the internal non-interactive simple merge algorithm for merging
207 files. It will fail if there are any conflicts and leave markers in
207 files. It will fail if there are any conflicts and leave markers in
208 the partially merged file."""
208 the partially merged file."""
209 tool, toolpath, binary, symlink = toolconf
209 tool, toolpath, binary, symlink = toolconf
210 if symlink:
210 if symlink:
211 repo.ui.warn(_('warning: internal:merge cannot merge symlinks '
211 repo.ui.warn(_('warning: internal:merge cannot merge symlinks '
212 'for %s\n') % fcd.path())
212 'for %s\n') % fcd.path())
213 return False, 1
213 return False, 1
214
214 r = _premerge(repo, toolconf, files, labels=labels)
215 r = _premerge(repo, toolconf, files)
216 if r:
215 if r:
217 a, b, c, back = files
216 a, b, c, back = files
218
217
219 ui = repo.ui
218 ui = repo.ui
220
219
221 r = simplemerge.simplemerge(ui, a, b, c, label=['local', 'other'])
220 r = simplemerge.simplemerge(ui, a, b, c, label=labels)
222 return True, r
221 return True, r
223 return False, 0
222 return False, 0
224
223
225 @internaltool('dump', True)
224 @internaltool('dump', True)
226 def _idump(repo, mynode, orig, fcd, fco, fca, toolconf, files):
225 def _idump(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
227 """
226 """
228 Creates three versions of the files to merge, containing the
227 Creates three versions of the files to merge, containing the
229 contents of local, other and base. These files can then be used to
228 contents of local, other and base. These files can then be used to
230 perform a merge manually. If the file to be merged is named
229 perform a merge manually. If the file to be merged is named
231 ``a.txt``, these files will accordingly be named ``a.txt.local``,
230 ``a.txt``, these files will accordingly be named ``a.txt.local``,
232 ``a.txt.other`` and ``a.txt.base`` and they will be placed in the
231 ``a.txt.other`` and ``a.txt.base`` and they will be placed in the
233 same directory as ``a.txt``."""
232 same directory as ``a.txt``."""
234 r = _premerge(repo, toolconf, files)
233 r = _premerge(repo, toolconf, files, labels=labels)
235 if r:
234 if r:
236 a, b, c, back = files
235 a, b, c, back = files
237
236
238 fd = fcd.path()
237 fd = fcd.path()
239
238
240 util.copyfile(a, a + ".local")
239 util.copyfile(a, a + ".local")
241 repo.wwrite(fd + ".other", fco.data(), fco.flags())
240 repo.wwrite(fd + ".other", fco.data(), fco.flags())
242 repo.wwrite(fd + ".base", fca.data(), fca.flags())
241 repo.wwrite(fd + ".base", fca.data(), fca.flags())
243 return False, r
242 return False, r
244
243
245 def _xmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files):
244 def _xmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
246 r = _premerge(repo, toolconf, files)
245 r = _premerge(repo, toolconf, files, labels=labels)
247 if r:
246 if r:
248 tool, toolpath, binary, symlink = toolconf
247 tool, toolpath, binary, symlink = toolconf
249 a, b, c, back = files
248 a, b, c, back = files
250 out = ""
249 out = ""
251 env = {'HG_FILE': fcd.path(),
250 env = {'HG_FILE': fcd.path(),
252 'HG_MY_NODE': short(mynode),
251 'HG_MY_NODE': short(mynode),
253 'HG_OTHER_NODE': str(fco.changectx()),
252 'HG_OTHER_NODE': str(fco.changectx()),
254 'HG_BASE_NODE': str(fca.changectx()),
253 'HG_BASE_NODE': str(fca.changectx()),
255 'HG_MY_ISLINK': 'l' in fcd.flags(),
254 'HG_MY_ISLINK': 'l' in fcd.flags(),
256 'HG_OTHER_ISLINK': 'l' in fco.flags(),
255 'HG_OTHER_ISLINK': 'l' in fco.flags(),
257 'HG_BASE_ISLINK': 'l' in fca.flags(),
256 'HG_BASE_ISLINK': 'l' in fca.flags(),
258 }
257 }
259
258
260 ui = repo.ui
259 ui = repo.ui
261
260
262 args = _toolstr(ui, tool, "args", '$local $base $other')
261 args = _toolstr(ui, tool, "args", '$local $base $other')
263 if "$output" in args:
262 if "$output" in args:
264 out, a = a, back # read input from backup, write to original
263 out, a = a, back # read input from backup, write to original
265 replace = {'local': a, 'base': b, 'other': c, 'output': out}
264 replace = {'local': a, 'base': b, 'other': c, 'output': out}
266 args = util.interpolate(r'\$', replace, args,
265 args = util.interpolate(r'\$', replace, args,
267 lambda s: util.shellquote(util.localpath(s)))
266 lambda s: util.shellquote(util.localpath(s)))
268 r = util.system(toolpath + ' ' + args, cwd=repo.root, environ=env,
267 r = util.system(toolpath + ' ' + args, cwd=repo.root, environ=env,
269 out=ui.fout)
268 out=ui.fout)
270 return True, r
269 return True, r
271 return False, 0
270 return False, 0
272
271
273 def filemerge(repo, mynode, orig, fcd, fco, fca):
272 def filemerge(repo, mynode, orig, fcd, fco, fca):
274 """perform a 3-way merge in the working directory
273 """perform a 3-way merge in the working directory
275
274
276 mynode = parent node before merge
275 mynode = parent node before merge
277 orig = original local filename before merge
276 orig = original local filename before merge
278 fco = other file context
277 fco = other file context
279 fca = ancestor file context
278 fca = ancestor file context
280 fcd = local file context for current/destination file
279 fcd = local file context for current/destination file
281 """
280 """
282
281
283 def temp(prefix, ctx):
282 def temp(prefix, ctx):
284 pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
283 pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
285 (fd, name) = tempfile.mkstemp(prefix=pre)
284 (fd, name) = tempfile.mkstemp(prefix=pre)
286 data = repo.wwritedata(ctx.path(), ctx.data())
285 data = repo.wwritedata(ctx.path(), ctx.data())
287 f = os.fdopen(fd, "wb")
286 f = os.fdopen(fd, "wb")
288 f.write(data)
287 f.write(data)
289 f.close()
288 f.close()
290 return name
289 return name
291
290
292 if not fco.cmp(fcd): # files identical?
291 if not fco.cmp(fcd): # files identical?
293 return None
292 return None
294
293
295 ui = repo.ui
294 ui = repo.ui
296 fd = fcd.path()
295 fd = fcd.path()
297 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary()
296 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary()
298 symlink = 'l' in fcd.flags() + fco.flags()
297 symlink = 'l' in fcd.flags() + fco.flags()
299 tool, toolpath = _picktool(repo, ui, fd, binary, symlink)
298 tool, toolpath = _picktool(repo, ui, fd, binary, symlink)
300 ui.debug("picked tool '%s' for %s (binary %s symlink %s)\n" %
299 ui.debug("picked tool '%s' for %s (binary %s symlink %s)\n" %
301 (tool, fd, binary, symlink))
300 (tool, fd, binary, symlink))
302
301
303 if tool in internals:
302 if tool in internals:
304 func = internals[tool]
303 func = internals[tool]
305 trymerge = func.trymerge
304 trymerge = func.trymerge
306 onfailure = func.onfailure
305 onfailure = func.onfailure
307 else:
306 else:
308 func = _xmerge
307 func = _xmerge
309 trymerge = True
308 trymerge = True
310 onfailure = _("merging %s failed!\n")
309 onfailure = _("merging %s failed!\n")
311
310
312 toolconf = tool, toolpath, binary, symlink
311 toolconf = tool, toolpath, binary, symlink
313
312
314 if not trymerge:
313 if not trymerge:
315 return func(repo, mynode, orig, fcd, fco, fca, toolconf)
314 return func(repo, mynode, orig, fcd, fco, fca, toolconf)
316
315
317 a = repo.wjoin(fd)
316 a = repo.wjoin(fd)
318 b = temp("base", fca)
317 b = temp("base", fca)
319 c = temp("other", fco)
318 c = temp("other", fco)
320 back = a + ".orig"
319 back = a + ".orig"
321 util.copyfile(a, back)
320 util.copyfile(a, back)
322
321
323 if orig != fco.path():
322 if orig != fco.path():
324 ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))
323 ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))
325 else:
324 else:
326 ui.status(_("merging %s\n") % fd)
325 ui.status(_("merging %s\n") % fd)
327
326
328 ui.debug("my %s other %s ancestor %s\n" % (fcd, fco, fca))
327 ui.debug("my %s other %s ancestor %s\n" % (fcd, fco, fca))
329
328
329 labels = ['local', 'other']
330 needcheck, r = func(repo, mynode, orig, fcd, fco, fca, toolconf,
330 needcheck, r = func(repo, mynode, orig, fcd, fco, fca, toolconf,
331 (a, b, c, back))
331 (a, b, c, back), labels=labels)
332 if not needcheck:
332 if not needcheck:
333 if r:
333 if r:
334 if onfailure:
334 if onfailure:
335 ui.warn(onfailure % fd)
335 ui.warn(onfailure % fd)
336 else:
336 else:
337 util.unlink(back)
337 util.unlink(back)
338
338
339 util.unlink(b)
339 util.unlink(b)
340 util.unlink(c)
340 util.unlink(c)
341 return r
341 return r
342
342
343 if not r and (_toolbool(ui, tool, "checkconflicts") or
343 if not r and (_toolbool(ui, tool, "checkconflicts") or
344 'conflicts' in _toollist(ui, tool, "check")):
344 'conflicts' in _toollist(ui, tool, "check")):
345 if re.search("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcd.data(),
345 if re.search("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcd.data(),
346 re.MULTILINE):
346 re.MULTILINE):
347 r = 1
347 r = 1
348
348
349 checked = False
349 checked = False
350 if 'prompt' in _toollist(ui, tool, "check"):
350 if 'prompt' in _toollist(ui, tool, "check"):
351 checked = True
351 checked = True
352 if ui.promptchoice(_("was merge of '%s' successful (yn)?"
352 if ui.promptchoice(_("was merge of '%s' successful (yn)?"
353 "$$ &Yes $$ &No") % fd, 1):
353 "$$ &Yes $$ &No") % fd, 1):
354 r = 1
354 r = 1
355
355
356 if not r and not checked and (_toolbool(ui, tool, "checkchanged") or
356 if not r and not checked and (_toolbool(ui, tool, "checkchanged") or
357 'changed' in _toollist(ui, tool, "check")):
357 'changed' in _toollist(ui, tool, "check")):
358 if filecmp.cmp(a, back):
358 if filecmp.cmp(a, back):
359 if ui.promptchoice(_(" output file %s appears unchanged\n"
359 if ui.promptchoice(_(" output file %s appears unchanged\n"
360 "was merge successful (yn)?"
360 "was merge successful (yn)?"
361 "$$ &Yes $$ &No") % fd, 1):
361 "$$ &Yes $$ &No") % fd, 1):
362 r = 1
362 r = 1
363
363
364 if _toolbool(ui, tool, "fixeol"):
364 if _toolbool(ui, tool, "fixeol"):
365 _matcheol(a, back)
365 _matcheol(a, back)
366
366
367 if r:
367 if r:
368 if onfailure:
368 if onfailure:
369 ui.warn(onfailure % fd)
369 ui.warn(onfailure % fd)
370 else:
370 else:
371 util.unlink(back)
371 util.unlink(back)
372
372
373 util.unlink(b)
373 util.unlink(b)
374 util.unlink(c)
374 util.unlink(c)
375 return r
375 return r
376
376
377 # tell hggettext to extract docstrings from these functions:
377 # tell hggettext to extract docstrings from these functions:
378 i18nfunctions = internals.values()
378 i18nfunctions = internals.values()
General Comments 0
You need to be logged in to leave comments. Login now