##// END OF EJS Templates
filemerge: better handling of failing remove of temporary files...
Mads Kiilerich -
r21100:098a2747 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):
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)
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):
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
215 r = _premerge(repo, toolconf, files)
215 r = _premerge(repo, toolconf, files)
216 if r:
216 if r:
217 a, b, c, back = files
217 a, b, c, back = files
218
218
219 ui = repo.ui
219 ui = repo.ui
220
220
221 r = simplemerge.simplemerge(ui, a, b, c, label=['local', 'other'])
221 r = simplemerge.simplemerge(ui, a, b, c, label=['local', 'other'])
222 return True, r
222 return True, r
223 return False, 0
223 return False, 0
224
224
225 @internaltool('dump', True)
225 @internaltool('dump', True)
226 def _idump(repo, mynode, orig, fcd, fco, fca, toolconf, files):
226 def _idump(repo, mynode, orig, fcd, fco, fca, toolconf, files):
227 """
227 """
228 Creates three versions of the files to merge, containing the
228 Creates three versions of the files to merge, containing the
229 contents of local, other and base. These files can then be used to
229 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
230 perform a merge manually. If the file to be merged is named
231 ``a.txt``, these files will accordingly be named ``a.txt.local``,
231 ``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
232 ``a.txt.other`` and ``a.txt.base`` and they will be placed in the
233 same directory as ``a.txt``."""
233 same directory as ``a.txt``."""
234 r = _premerge(repo, toolconf, files)
234 r = _premerge(repo, toolconf, files)
235 if r:
235 if r:
236 a, b, c, back = files
236 a, b, c, back = files
237
237
238 fd = fcd.path()
238 fd = fcd.path()
239
239
240 util.copyfile(a, a + ".local")
240 util.copyfile(a, a + ".local")
241 repo.wwrite(fd + ".other", fco.data(), fco.flags())
241 repo.wwrite(fd + ".other", fco.data(), fco.flags())
242 repo.wwrite(fd + ".base", fca.data(), fca.flags())
242 repo.wwrite(fd + ".base", fca.data(), fca.flags())
243 return False, r
243 return False, r
244
244
245 def _xmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files):
245 def _xmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files):
246 r = _premerge(repo, toolconf, files)
246 r = _premerge(repo, toolconf, files)
247 if r:
247 if r:
248 tool, toolpath, binary, symlink = toolconf
248 tool, toolpath, binary, symlink = toolconf
249 a, b, c, back = files
249 a, b, c, back = files
250 out = ""
250 out = ""
251 env = {'HG_FILE': fcd.path(),
251 env = {'HG_FILE': fcd.path(),
252 'HG_MY_NODE': short(mynode),
252 'HG_MY_NODE': short(mynode),
253 'HG_OTHER_NODE': str(fco.changectx()),
253 'HG_OTHER_NODE': str(fco.changectx()),
254 'HG_BASE_NODE': str(fca.changectx()),
254 'HG_BASE_NODE': str(fca.changectx()),
255 'HG_MY_ISLINK': 'l' in fcd.flags(),
255 'HG_MY_ISLINK': 'l' in fcd.flags(),
256 'HG_OTHER_ISLINK': 'l' in fco.flags(),
256 'HG_OTHER_ISLINK': 'l' in fco.flags(),
257 'HG_BASE_ISLINK': 'l' in fca.flags(),
257 'HG_BASE_ISLINK': 'l' in fca.flags(),
258 }
258 }
259
259
260 ui = repo.ui
260 ui = repo.ui
261
261
262 args = _toolstr(ui, tool, "args", '$local $base $other')
262 args = _toolstr(ui, tool, "args", '$local $base $other')
263 if "$output" in args:
263 if "$output" in args:
264 out, a = a, back # read input from backup, write to original
264 out, a = a, back # read input from backup, write to original
265 replace = {'local': a, 'base': b, 'other': c, 'output': out}
265 replace = {'local': a, 'base': b, 'other': c, 'output': out}
266 args = util.interpolate(r'\$', replace, args,
266 args = util.interpolate(r'\$', replace, args,
267 lambda s: util.shellquote(util.localpath(s)))
267 lambda s: util.shellquote(util.localpath(s)))
268 r = util.system(toolpath + ' ' + args, cwd=repo.root, environ=env,
268 r = util.system(toolpath + ' ' + args, cwd=repo.root, environ=env,
269 out=ui.fout)
269 out=ui.fout)
270 return True, r
270 return True, r
271 return False, 0
271 return False, 0
272
272
273 def filemerge(repo, mynode, orig, fcd, fco, fca):
273 def filemerge(repo, mynode, orig, fcd, fco, fca):
274 """perform a 3-way merge in the working directory
274 """perform a 3-way merge in the working directory
275
275
276 mynode = parent node before merge
276 mynode = parent node before merge
277 orig = original local filename before merge
277 orig = original local filename before merge
278 fco = other file context
278 fco = other file context
279 fca = ancestor file context
279 fca = ancestor file context
280 fcd = local file context for current/destination file
280 fcd = local file context for current/destination file
281 """
281 """
282
282
283 def temp(prefix, ctx):
283 def temp(prefix, ctx):
284 pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
284 pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
285 (fd, name) = tempfile.mkstemp(prefix=pre)
285 (fd, name) = tempfile.mkstemp(prefix=pre)
286 data = repo.wwritedata(ctx.path(), ctx.data())
286 data = repo.wwritedata(ctx.path(), ctx.data())
287 f = os.fdopen(fd, "wb")
287 f = os.fdopen(fd, "wb")
288 f.write(data)
288 f.write(data)
289 f.close()
289 f.close()
290 return name
290 return name
291
291
292 if not fco.cmp(fcd): # files identical?
292 if not fco.cmp(fcd): # files identical?
293 return None
293 return None
294
294
295 ui = repo.ui
295 ui = repo.ui
296 fd = fcd.path()
296 fd = fcd.path()
297 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary()
297 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary()
298 symlink = 'l' in fcd.flags() + fco.flags()
298 symlink = 'l' in fcd.flags() + fco.flags()
299 tool, toolpath = _picktool(repo, ui, fd, binary, symlink)
299 tool, toolpath = _picktool(repo, ui, fd, binary, symlink)
300 ui.debug("picked tool '%s' for %s (binary %s symlink %s)\n" %
300 ui.debug("picked tool '%s' for %s (binary %s symlink %s)\n" %
301 (tool, fd, binary, symlink))
301 (tool, fd, binary, symlink))
302
302
303 if tool in internals:
303 if tool in internals:
304 func = internals[tool]
304 func = internals[tool]
305 trymerge = func.trymerge
305 trymerge = func.trymerge
306 onfailure = func.onfailure
306 onfailure = func.onfailure
307 else:
307 else:
308 func = _xmerge
308 func = _xmerge
309 trymerge = True
309 trymerge = True
310 onfailure = _("merging %s failed!\n")
310 onfailure = _("merging %s failed!\n")
311
311
312 toolconf = tool, toolpath, binary, symlink
312 toolconf = tool, toolpath, binary, symlink
313
313
314 if not trymerge:
314 if not trymerge:
315 return func(repo, mynode, orig, fcd, fco, fca, toolconf)
315 return func(repo, mynode, orig, fcd, fco, fca, toolconf)
316
316
317 a = repo.wjoin(fd)
317 a = repo.wjoin(fd)
318 b = temp("base", fca)
318 b = temp("base", fca)
319 c = temp("other", fco)
319 c = temp("other", fco)
320 back = a + ".orig"
320 back = a + ".orig"
321 util.copyfile(a, back)
321 util.copyfile(a, back)
322
322
323 if orig != fco.path():
323 if orig != fco.path():
324 ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))
324 ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))
325 else:
325 else:
326 ui.status(_("merging %s\n") % fd)
326 ui.status(_("merging %s\n") % fd)
327
327
328 ui.debug("my %s other %s ancestor %s\n" % (fcd, fco, fca))
328 ui.debug("my %s other %s ancestor %s\n" % (fcd, fco, fca))
329
329
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))
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 os.unlink(back)
337 util.unlink(back)
338
338
339 os.unlink(b)
339 util.unlink(b)
340 os.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 os.unlink(back)
371 util.unlink(back)
372
372
373 os.unlink(b)
373 util.unlink(b)
374 os.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