annotate mercurial/filemerge.py @ 16093:7e30f5f2285f

merge: refactor unknown file conflict checking Previously, we would do a full working directory walk including unknown files to perform a merge. In many cases, this was painful because unknown files greatly outnumbered tracked files and generally had no useful effect on the merge. Here we instead wait until we find a file in the destination that's not tracked locally and detect if it exists and is not ignored. This is usually cheaper but can be -more- expensive in the case where we're adding a huge number of files. On the other hand, the cost of statting the new files should be dwarfed by the cost of eventually writing them. In this version, case collisions are detected implicitly by os.path.exists and wctx[f] lookup.
author Matt Mackall <mpm@selenic.com>
date Thu, 09 Feb 2012 16:50:19 -0600
parents e86dd8dfdea0
children 83925d3a4559 b605448eb254
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
1 # filemerge.py - file-level merge handling for Mercurial
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
2 #
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
3 # Copyright 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
4 #
8225
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 8209
diff changeset
5 # This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 9709
diff changeset
6 # GNU General Public License version 2 or any later version.
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
7
7873
4a4c7f6a5912 cleanup: drop unused imports
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7397
diff changeset
8 from node import short
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
9 from i18n import _
11146
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
10 import util, simplemerge, match, error
8312
b87a50b7125c separate import lines from mercurial and general python modules
Simon Heimberg <simohe@besonet.ch>
parents: 8269
diff changeset
11 import os, tempfile, re, filecmp
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
12
6013
bb441d77df99 filemerge: handle missing regappend
Matt Mackall <mpm@selenic.com>
parents: 6007
diff changeset
13 def _toolstr(ui, tool, part, default=""):
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
14 return ui.config("merge-tools", tool + "." + part, default)
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
15
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
16 def _toolbool(ui, tool, part, default=False):
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
17 return ui.configbool("merge-tools", tool + "." + part, default)
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
18
11148
a912f26777d3 merge: introduce tool.check parameter
David Champion <dgc@uchicago.edu>
parents: 11146
diff changeset
19 def _toollist(ui, tool, part, default=[]):
a912f26777d3 merge: introduce tool.check parameter
David Champion <dgc@uchicago.edu>
parents: 11146
diff changeset
20 return ui.configlist("merge-tools", tool + "." + part, default)
a912f26777d3 merge: introduce tool.check parameter
David Champion <dgc@uchicago.edu>
parents: 11146
diff changeset
21
8831
91e26fb24fb1 filemerge: add internal:dump
Matt Mackall <mpm@selenic.com>
parents: 8830
diff changeset
22 _internal = ['internal:' + s
91e26fb24fb1 filemerge: add internal:dump
Matt Mackall <mpm@selenic.com>
parents: 8830
diff changeset
23 for s in 'fail local other merge prompt dump'.split()]
8830
a9850eda2973 filemerge: add internal:prompt target
Matt Mackall <mpm@selenic.com>
parents: 8615
diff changeset
24
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
25 def _findtool(ui, tool):
8830
a9850eda2973 filemerge: add internal:prompt target
Matt Mackall <mpm@selenic.com>
parents: 8615
diff changeset
26 if tool in _internal:
6522
2b181fb3a70a use internal merge tool when specified for a merge-pattern in hgrc
Dov Feldstern <dfeldstern@fastimap.com>
parents: 6212
diff changeset
27 return tool
13565
984175605311 filemerge: introduce a 'regkeyalt' merge tool variable
Steve Borho <steve@borho.org>
parents: 12788
diff changeset
28 for kn in ("regkey", "regkeyalt"):
984175605311 filemerge: introduce a 'regkeyalt' merge tool variable
Steve Borho <steve@borho.org>
parents: 12788
diff changeset
29 k = _toolstr(ui, tool, kn)
984175605311 filemerge: introduce a 'regkeyalt' merge tool variable
Steve Borho <steve@borho.org>
parents: 12788
diff changeset
30 if not k:
984175605311 filemerge: introduce a 'regkeyalt' merge tool variable
Steve Borho <steve@borho.org>
parents: 12788
diff changeset
31 continue
14230
d51630301241 rename util.lookup_reg to lookupreg
Adrian Buehlmann <adrian@cadifra.com>
parents: 14168
diff changeset
32 p = util.lookupreg(k, _toolstr(ui, tool, "regname"))
6006
3c9dbb743d20 merge: add registry look up bits to tool search
Matt Mackall <mpm@selenic.com>
parents: 6005
diff changeset
33 if p:
14271
4030630fb59c rename util.find_exe to findexe
Adrian Buehlmann <adrian@cadifra.com>
parents: 14230
diff changeset
34 p = util.findexe(p + _toolstr(ui, tool, "regappend"))
6006
3c9dbb743d20 merge: add registry look up bits to tool search
Matt Mackall <mpm@selenic.com>
parents: 6005
diff changeset
35 if p:
3c9dbb743d20 merge: add registry look up bits to tool search
Matt Mackall <mpm@selenic.com>
parents: 6005
diff changeset
36 return p
15264
157d93c41c10 merge: expand environment variables and ~/ in tool.executable
Greg Ward <greg@gerg.ca>
parents: 14749
diff changeset
37 exe = _toolstr(ui, tool, "executable", tool)
157d93c41c10 merge: expand environment variables and ~/ in tool.executable
Greg Ward <greg@gerg.ca>
parents: 14749
diff changeset
38 return util.findexe(util.expandpath(exe))
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
39
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
40 def _picktool(repo, ui, path, binary, symlink):
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
41 def check(tool, pat, symlink, binary):
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
42 tmsg = tool
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
43 if pat:
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
44 tmsg += " specified for " + pat
7397
4c92d8971809 More verbose logging when filemerge searches for merge-tool
Mads Kiilerich <mads@kiilerich.com>
parents: 6762
diff changeset
45 if not _findtool(ui, tool):
4c92d8971809 More verbose logging when filemerge searches for merge-tool
Mads Kiilerich <mads@kiilerich.com>
parents: 6762
diff changeset
46 if pat: # explicitly requested tool deserves a warning
4c92d8971809 More verbose logging when filemerge searches for merge-tool
Mads Kiilerich <mads@kiilerich.com>
parents: 6762
diff changeset
47 ui.warn(_("couldn't find merge tool %s\n") % tmsg)
4c92d8971809 More verbose logging when filemerge searches for merge-tool
Mads Kiilerich <mads@kiilerich.com>
parents: 6762
diff changeset
48 else: # configured but non-existing tools are more silent
4c92d8971809 More verbose logging when filemerge searches for merge-tool
Mads Kiilerich <mads@kiilerich.com>
parents: 6762
diff changeset
49 ui.note(_("couldn't find merge tool %s\n") % tmsg)
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
50 elif symlink and not _toolbool(ui, tool, "symlink"):
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
51 ui.warn(_("tool %s can't handle symlinks\n") % tmsg)
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
52 elif binary and not _toolbool(ui, tool, "binary"):
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
53 ui.warn(_("tool %s can't handle binary\n") % tmsg)
6007
090b1a665901 filemerge: add config item for GUI tools
Matt Mackall <mpm@selenic.com>
parents: 6006
diff changeset
54 elif not util.gui() and _toolbool(ui, tool, "gui"):
090b1a665901 filemerge: add config item for GUI tools
Matt Mackall <mpm@selenic.com>
parents: 6006
diff changeset
55 ui.warn(_("tool %s requires a GUI\n") % tmsg)
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
56 else:
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
57 return True
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
58 return False
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
59
12788
de793925862e merge: implement --tool arguments using new ui.forcemerge configurable
Steve Borho <steve@borho.org>
parents: 12047
diff changeset
60 # forcemerge comes from command line arguments, highest priority
de793925862e merge: implement --tool arguments using new ui.forcemerge configurable
Steve Borho <steve@borho.org>
parents: 12047
diff changeset
61 force = ui.config('ui', 'forcemerge')
de793925862e merge: implement --tool arguments using new ui.forcemerge configurable
Steve Borho <steve@borho.org>
parents: 12047
diff changeset
62 if force:
de793925862e merge: implement --tool arguments using new ui.forcemerge configurable
Steve Borho <steve@borho.org>
parents: 12047
diff changeset
63 toolpath = _findtool(ui, force)
de793925862e merge: implement --tool arguments using new ui.forcemerge configurable
Steve Borho <steve@borho.org>
parents: 12047
diff changeset
64 if toolpath:
de793925862e merge: implement --tool arguments using new ui.forcemerge configurable
Steve Borho <steve@borho.org>
parents: 12047
diff changeset
65 return (force, '"' + toolpath + '"')
de793925862e merge: implement --tool arguments using new ui.forcemerge configurable
Steve Borho <steve@borho.org>
parents: 12047
diff changeset
66 else:
de793925862e merge: implement --tool arguments using new ui.forcemerge configurable
Steve Borho <steve@borho.org>
parents: 12047
diff changeset
67 # mimic HGMERGE if given tool not found
de793925862e merge: implement --tool arguments using new ui.forcemerge configurable
Steve Borho <steve@borho.org>
parents: 12047
diff changeset
68 return (force, force)
de793925862e merge: implement --tool arguments using new ui.forcemerge configurable
Steve Borho <steve@borho.org>
parents: 12047
diff changeset
69
de793925862e merge: implement --tool arguments using new ui.forcemerge configurable
Steve Borho <steve@borho.org>
parents: 12047
diff changeset
70 # HGMERGE takes next precedence
6025
f2335246e5c7 filemerge: wrap quotes around tool path
Steve Borho <steve@borho.org>
parents: 6016
diff changeset
71 hgmerge = os.environ.get("HGMERGE")
f2335246e5c7 filemerge: wrap quotes around tool path
Steve Borho <steve@borho.org>
parents: 6016
diff changeset
72 if hgmerge:
f2335246e5c7 filemerge: wrap quotes around tool path
Steve Borho <steve@borho.org>
parents: 6016
diff changeset
73 return (hgmerge, hgmerge)
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
74
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
75 # then patterns
6016
288ec2f6faa2 filemerge: fix pattern matching
dhruva <dhruvakm@gmail.com>
parents: 6015
diff changeset
76 for pat, tool in ui.configitems("merge-patterns"):
8567
fea40a677d43 match: add some default args
Matt Mackall <mpm@selenic.com>
parents: 8566
diff changeset
77 mf = match.match(repo.root, '', [pat])
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
78 if mf(path) and check(tool, pat, symlink, False):
10339
23e608f42f2c fix spaces/identation issues
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
79 toolpath = _findtool(ui, tool)
23e608f42f2c fix spaces/identation issues
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
80 return (tool, '"' + toolpath + '"')
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
81
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
82 # then merge tools
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
83 tools = {}
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
84 for k, v in ui.configitems("merge-tools"):
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
85 t = k.split('.')[0]
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
86 if t not in tools:
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
87 tools[t] = int(_toolstr(ui, t, "priority", "0"))
6076
0ee885fea464 filemerge: more backwards compatible behavior for ui.merge
Steve Borho <steve@borho.org>
parents: 6075
diff changeset
88 names = tools.keys()
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
89 tools = sorted([(-p, t) for t, p in tools.items()])
6076
0ee885fea464 filemerge: more backwards compatible behavior for ui.merge
Steve Borho <steve@borho.org>
parents: 6075
diff changeset
90 uimerge = ui.config("ui", "merge")
0ee885fea464 filemerge: more backwards compatible behavior for ui.merge
Steve Borho <steve@borho.org>
parents: 6075
diff changeset
91 if uimerge:
0ee885fea464 filemerge: more backwards compatible behavior for ui.merge
Steve Borho <steve@borho.org>
parents: 6075
diff changeset
92 if uimerge not in names:
0ee885fea464 filemerge: more backwards compatible behavior for ui.merge
Steve Borho <steve@borho.org>
parents: 6075
diff changeset
93 return (uimerge, uimerge)
0ee885fea464 filemerge: more backwards compatible behavior for ui.merge
Steve Borho <steve@borho.org>
parents: 6075
diff changeset
94 tools.insert(0, (None, uimerge)) # highest priority
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
95 tools.append((None, "hgmerge")) # the old default, if found
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
96 for p, t in tools:
7397
4c92d8971809 More verbose logging when filemerge searches for merge-tool
Mads Kiilerich <mads@kiilerich.com>
parents: 6762
diff changeset
97 if check(t, None, symlink, binary):
4c92d8971809 More verbose logging when filemerge searches for merge-tool
Mads Kiilerich <mads@kiilerich.com>
parents: 6762
diff changeset
98 toolpath = _findtool(ui, t)
6025
f2335246e5c7 filemerge: wrap quotes around tool path
Steve Borho <steve@borho.org>
parents: 6016
diff changeset
99 return (t, '"' + toolpath + '"')
f2335246e5c7 filemerge: wrap quotes around tool path
Steve Borho <steve@borho.org>
parents: 6016
diff changeset
100 # internal merge as last resort
f2335246e5c7 filemerge: wrap quotes around tool path
Steve Borho <steve@borho.org>
parents: 6016
diff changeset
101 return (not (symlink or binary) and "internal:merge" or None, None)
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
102
6005
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
103 def _eoltype(data):
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
104 "Guess the EOL type of a file"
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
105 if '\0' in data: # binary
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
106 return None
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
107 if '\r\n' in data: # Windows
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
108 return '\r\n'
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
109 if '\r' in data: # Old Mac
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
110 return '\r'
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
111 if '\n' in data: # UNIX
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
112 return '\n'
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
113 return None # unknown
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
114
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
115 def _matcheol(file, origfile):
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
116 "Convert EOL markers in a file to match origfile"
14168
135e244776f0 prevent transient leaks of file handle by using new helper functions
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13565
diff changeset
117 tostyle = _eoltype(util.readfile(origfile))
6005
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
118 if tostyle:
14168
135e244776f0 prevent transient leaks of file handle by using new helper functions
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13565
diff changeset
119 data = util.readfile(file)
6005
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
120 style = _eoltype(data)
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
121 if style:
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
122 newdata = data.replace(style, tostyle)
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
123 if newdata != data:
14168
135e244776f0 prevent transient leaks of file handle by using new helper functions
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13565
diff changeset
124 util.writefile(file, newdata)
6005
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
125
6512
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
126 def filemerge(repo, mynode, orig, fcd, fco, fca):
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
127 """perform a 3-way merge in the working directory
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
128
6512
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
129 mynode = parent node before merge
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
130 orig = original local filename before merge
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
131 fco = other file context
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
132 fca = ancestor file context
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
133 fcd = local file context for current/destination file
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
134 """
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
135
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
136 def temp(prefix, ctx):
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
137 pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
138 (fd, name) = tempfile.mkstemp(prefix=pre)
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
139 data = repo.wwritedata(ctx.path(), ctx.data())
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
140 f = os.fdopen(fd, "wb")
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
141 f.write(data)
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
142 f.close()
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
143 return name
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
144
11702
eb07fbc21e9c filectx: use cmp(self, fctx) instead of cmp(self, text)
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 11149
diff changeset
145 if not fco.cmp(fcd): # files identical?
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
146 return None
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
147
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
148 ui = repo.ui
6512
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
149 fd = fcd.path()
15738
e86dd8dfdea0 context: add isbinary function
Laurens Holst <laurens.hg@grauw.nl>
parents: 15501
diff changeset
150 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary()
6744
d3691d31fc9c context: remove islink and isexec methods
Matt Mackall <mpm@selenic.com>
parents: 6743
diff changeset
151 symlink = 'l' in fcd.flags() + fco.flags()
6512
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
152 tool, toolpath = _picktool(repo, ui, fd, binary, symlink)
9467
4c041f1ee1b4 do not attempt to translate ui.debug output
Martin Geisler <mg@lazybytes.net>
parents: 9049
diff changeset
153 ui.debug("picked tool '%s' for %s (binary %s symlink %s)\n" %
6512
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
154 (tool, fd, binary, symlink))
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
155
8830
a9850eda2973 filemerge: add internal:prompt target
Matt Mackall <mpm@selenic.com>
parents: 8615
diff changeset
156 if not tool or tool == 'internal:prompt':
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
157 tool = "internal:local"
9048
86b4a9b0ddda ui: extract choice from prompt
Simon Heimberg <simohe@besonet.ch>
parents: 8861
diff changeset
158 if ui.promptchoice(_(" no tool found to merge %s\n"
9049
38b5d5e0efab filemerge, subrepo: correct indention
Martin Geisler <mg@lazybytes.net>
parents: 9048
diff changeset
159 "keep (l)ocal or take (o)ther?") % fd,
38b5d5e0efab filemerge, subrepo: correct indention
Martin Geisler <mg@lazybytes.net>
parents: 9048
diff changeset
160 (_("&Local"), _("&Other")), 0):
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
161 tool = "internal:other"
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
162 if tool == "internal:local":
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
163 return 0
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
164 if tool == "internal:other":
6743
86e8187b721a simplify flag handling
Matt Mackall <mpm@selenic.com>
parents: 6533
diff changeset
165 repo.wwrite(fd, fco.data(), fco.flags())
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
166 return 0
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
167 if tool == "internal:fail":
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
168 return 1
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
169
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
170 # do the actual merge
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
171 a = repo.wjoin(fd)
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
172 b = temp("base", fca)
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
173 c = temp("other", fco)
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
174 out = ""
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
175 back = a + ".orig"
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
176 util.copyfile(a, back)
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
177
6512
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
178 if orig != fco.path():
8615
94ca38e63576 use ui instead of repo.ui when the former is in scope
Martin Geisler <mg@lazybytes.net>
parents: 8567
diff changeset
179 ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
180 else:
8615
94ca38e63576 use ui instead of repo.ui when the former is in scope
Martin Geisler <mg@lazybytes.net>
parents: 8567
diff changeset
181 ui.status(_("merging %s\n") % fd)
6512
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
182
9467
4c041f1ee1b4 do not attempt to translate ui.debug output
Martin Geisler <mg@lazybytes.net>
parents: 9049
diff changeset
183 ui.debug("my %s other %s ancestor %s\n" % (fcd, fco, fca))
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
184
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
185 # do we attempt to simplemerge first?
11146
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
186 try:
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
187 premerge = _toolbool(ui, tool, "premerge", not (binary or symlink))
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
188 except error.ConfigError:
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
189 premerge = _toolstr(ui, tool, "premerge").lower()
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
190 valid = 'keep'.split()
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
191 if premerge not in valid:
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
192 _valid = ', '.join(["'" + v + "'" for v in valid])
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
193 raise error.ConfigError(_("%s.premerge not valid "
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
194 "('%s' is neither boolean nor %s)") %
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
195 (tool, premerge, _valid))
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
196
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
197 if premerge:
8269
bb9f13974d8e simplemerge: use ui.warn() for warnings
Steve Borho <steve@borho.org>
parents: 8259
diff changeset
198 r = simplemerge.simplemerge(ui, a, b, c, quiet=True)
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
199 if not r:
9467
4c041f1ee1b4 do not attempt to translate ui.debug output
Martin Geisler <mg@lazybytes.net>
parents: 9049
diff changeset
200 ui.debug(" premerge successful\n")
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
201 os.unlink(back)
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
202 os.unlink(b)
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
203 os.unlink(c)
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
204 return 0
11146
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
205 if premerge != 'keep':
523330d567cf merge: tool.premerge=keep will leave premerge markers in $local
David Champion <dgc@uchicago.edu>
parents: 10944
diff changeset
206 util.copyfile(back, a) # restore from backup and try again
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
207
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
208 env = dict(HG_FILE=fd,
6512
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
209 HG_MY_NODE=short(mynode),
368a4ec603cc merge: introduce mergestate
Matt Mackall <mpm@selenic.com>
parents: 6212
diff changeset
210 HG_OTHER_NODE=str(fco.changectx()),
9709
5858117a0077 merge: supply base node to merge tools in the environment
Sune Foldager <cryo@cyanite.org>
parents: 9467
diff changeset
211 HG_BASE_NODE=str(fca.changectx()),
6744
d3691d31fc9c context: remove islink and isexec methods
Matt Mackall <mpm@selenic.com>
parents: 6743
diff changeset
212 HG_MY_ISLINK='l' in fcd.flags(),
d3691d31fc9c context: remove islink and isexec methods
Matt Mackall <mpm@selenic.com>
parents: 6743
diff changeset
213 HG_OTHER_ISLINK='l' in fco.flags(),
d3691d31fc9c context: remove islink and isexec methods
Matt Mackall <mpm@selenic.com>
parents: 6743
diff changeset
214 HG_BASE_ISLINK='l' in fca.flags())
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
215
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
216 if tool == "internal:merge":
8269
bb9f13974d8e simplemerge: use ui.warn() for warnings
Steve Borho <steve@borho.org>
parents: 8259
diff changeset
217 r = simplemerge.simplemerge(ui, a, b, c, label=['local', 'other'])
8831
91e26fb24fb1 filemerge: add internal:dump
Matt Mackall <mpm@selenic.com>
parents: 8830
diff changeset
218 elif tool == 'internal:dump':
91e26fb24fb1 filemerge: add internal:dump
Matt Mackall <mpm@selenic.com>
parents: 8830
diff changeset
219 a = repo.wjoin(fd)
91e26fb24fb1 filemerge: add internal:dump
Matt Mackall <mpm@selenic.com>
parents: 8830
diff changeset
220 util.copyfile(a, a + ".local")
8861
90f74b31ed4f filemerge: fix internal:dump
Matt Mackall <mpm@selenic.com>
parents: 8831
diff changeset
221 repo.wwrite(fd + ".other", fco.data(), fco.flags())
90f74b31ed4f filemerge: fix internal:dump
Matt Mackall <mpm@selenic.com>
parents: 8831
diff changeset
222 repo.wwrite(fd + ".base", fca.data(), fca.flags())
8831
91e26fb24fb1 filemerge: add internal:dump
Matt Mackall <mpm@selenic.com>
parents: 8830
diff changeset
223 return 1 # unresolved
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
224 else:
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
225 args = _toolstr(ui, tool, "args", '$local $base $other')
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
226 if "$output" in args:
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
227 out, a = a, back # read input from backup, write to original
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
228 replace = dict(local=a, base=b, other=c, output=out)
11988
8380ed691df8 util: add an interpolate() function to for replacing multiple values
Steve Losh <steve@stevelosh.com>
parents: 11702
diff changeset
229 args = util.interpolate(r'\$', replace, args,
8380ed691df8 util: add an interpolate() function to for replacing multiple values
Steve Losh <steve@stevelosh.com>
parents: 11702
diff changeset
230 lambda s: '"%s"' % util.localpath(s))
14749
e3be7dc9a5e1 filemerge: use ui out descriptor when calling util.system
Idan Kamara <idankk86@gmail.com>
parents: 14271
diff changeset
231 r = util.system(toolpath + ' ' + args, cwd=repo.root, environ=env,
e3be7dc9a5e1 filemerge: use ui out descriptor when calling util.system
Idan Kamara <idankk86@gmail.com>
parents: 14271
diff changeset
232 out=ui.fout)
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
233
11148
a912f26777d3 merge: introduce tool.check parameter
David Champion <dgc@uchicago.edu>
parents: 11146
diff changeset
234 if not r and (_toolbool(ui, tool, "checkconflicts") or
a912f26777d3 merge: introduce tool.check parameter
David Champion <dgc@uchicago.edu>
parents: 11146
diff changeset
235 'conflicts' in _toollist(ui, tool, "check")):
12046
8e7960feb139 Fix merge-tools.checkconflicts
Thomas Arendsen Hein <thomas@intevation.de>
parents: 12008
diff changeset
236 if re.search("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcd.data(),
8e7960feb139 Fix merge-tools.checkconflicts
Thomas Arendsen Hein <thomas@intevation.de>
parents: 12008
diff changeset
237 re.MULTILINE):
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
238 r = 1
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
239
11149
d3c1eddfdbcf merge: tool.check = prompt will force an interactive merge check
David Champion <dgc@uchicago.edu>
parents: 11148
diff changeset
240 checked = False
d3c1eddfdbcf merge: tool.check = prompt will force an interactive merge check
David Champion <dgc@uchicago.edu>
parents: 11148
diff changeset
241 if 'prompt' in _toollist(ui, tool, "check"):
d3c1eddfdbcf merge: tool.check = prompt will force an interactive merge check
David Champion <dgc@uchicago.edu>
parents: 11148
diff changeset
242 checked = True
d3c1eddfdbcf merge: tool.check = prompt will force an interactive merge check
David Champion <dgc@uchicago.edu>
parents: 11148
diff changeset
243 if ui.promptchoice(_("was merge of '%s' successful (yn)?") % fd,
d3c1eddfdbcf merge: tool.check = prompt will force an interactive merge check
David Champion <dgc@uchicago.edu>
parents: 11148
diff changeset
244 (_("&Yes"), _("&No")), 1):
d3c1eddfdbcf merge: tool.check = prompt will force an interactive merge check
David Champion <dgc@uchicago.edu>
parents: 11148
diff changeset
245 r = 1
d3c1eddfdbcf merge: tool.check = prompt will force an interactive merge check
David Champion <dgc@uchicago.edu>
parents: 11148
diff changeset
246
d3c1eddfdbcf merge: tool.check = prompt will force an interactive merge check
David Champion <dgc@uchicago.edu>
parents: 11148
diff changeset
247 if not r and not checked and (_toolbool(ui, tool, "checkchanged") or
d3c1eddfdbcf merge: tool.check = prompt will force an interactive merge check
David Champion <dgc@uchicago.edu>
parents: 11148
diff changeset
248 'changed' in _toollist(ui, tool, "check")):
6075
63e0e57ab157 filemerge: add 'checkchanged' merge tool property
Steve Borho <steve@borho.org>
parents: 6025
diff changeset
249 if filecmp.cmp(repo.wjoin(fd), back):
9048
86b4a9b0ddda ui: extract choice from prompt
Simon Heimberg <simohe@besonet.ch>
parents: 8861
diff changeset
250 if ui.promptchoice(_(" output file %s appears unchanged\n"
9049
38b5d5e0efab filemerge, subrepo: correct indention
Martin Geisler <mg@lazybytes.net>
parents: 9048
diff changeset
251 "was merge successful (yn)?") % fd,
38b5d5e0efab filemerge, subrepo: correct indention
Martin Geisler <mg@lazybytes.net>
parents: 9048
diff changeset
252 (_("&Yes"), _("&No")), 1):
6075
63e0e57ab157 filemerge: add 'checkchanged' merge tool property
Steve Borho <steve@borho.org>
parents: 6025
diff changeset
253 r = 1
63e0e57ab157 filemerge: add 'checkchanged' merge tool property
Steve Borho <steve@borho.org>
parents: 6025
diff changeset
254
6005
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
255 if _toolbool(ui, tool, "fixeol"):
6015
26ef792f834e filemerge: fix path to working file when fixeol is enabled
Lee Cantey <lcantey@gmail.com>
parents: 6013
diff changeset
256 _matcheol(repo.wjoin(fd), back)
6005
3c33032d8906 merge: add support for tool EOL fixups
Matt Mackall <mpm@selenic.com>
parents: 6004
diff changeset
257
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
258 if r:
15501
2371f4aea665 merge: give a special message for internal:merge failure (issue3105)
Matt Mackall <mpm@selenic.com>
parents: 15264
diff changeset
259 if tool == "internal:merge":
2371f4aea665 merge: give a special message for internal:merge failure (issue3105)
Matt Mackall <mpm@selenic.com>
parents: 15264
diff changeset
260 ui.warn(_("merging %s incomplete! "
2371f4aea665 merge: give a special message for internal:merge failure (issue3105)
Matt Mackall <mpm@selenic.com>
parents: 15264
diff changeset
261 "(edit conflicts, then use 'hg resolve --mark')\n") % fd)
2371f4aea665 merge: give a special message for internal:merge failure (issue3105)
Matt Mackall <mpm@selenic.com>
parents: 15264
diff changeset
262 else:
2371f4aea665 merge: give a special message for internal:merge failure (issue3105)
Matt Mackall <mpm@selenic.com>
parents: 15264
diff changeset
263 ui.warn(_("merging %s failed!\n") % fd)
6004
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
264 else:
5af5f0f9d724 merge: allow smarter tool configuration
Matt Mackall <mpm@selenic.com>
parents: 6003
diff changeset
265 os.unlink(back)
6003
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
266
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
267 os.unlink(b)
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
268 os.unlink(c)
7855b88ba838 filemerge: pull file-merging code into its own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
269 return r