118 if p: |
118 if p: |
119 return p |
119 return p |
120 exe = _toolstr(ui, tool, "executable", tool) |
120 exe = _toolstr(ui, tool, "executable", tool) |
121 return util.findexe(util.expandpath(exe)) |
121 return util.findexe(util.expandpath(exe)) |
122 |
122 |
123 def _picktool(repo, ui, path, binary, symlink): |
123 def _picktool(repo, ui, path, binary, symlink, changedelete): |
124 def check(tool, pat, symlink, binary): |
124 def supportscd(tool): |
|
125 return tool in internals and internals[tool].mergetype == nomerge |
|
126 |
|
127 def check(tool, pat, symlink, binary, changedelete): |
125 tmsg = tool |
128 tmsg = tool |
126 if pat: |
129 if pat: |
127 tmsg += " specified for " + pat |
130 tmsg += " specified for " + pat |
128 if not _findtool(ui, tool): |
131 if not _findtool(ui, tool): |
129 if pat: # explicitly requested tool deserves a warning |
132 if pat: # explicitly requested tool deserves a warning |
132 ui.note(_("couldn't find merge tool %s\n") % tmsg) |
135 ui.note(_("couldn't find merge tool %s\n") % tmsg) |
133 elif symlink and not _toolbool(ui, tool, "symlink"): |
136 elif symlink and not _toolbool(ui, tool, "symlink"): |
134 ui.warn(_("tool %s can't handle symlinks\n") % tmsg) |
137 ui.warn(_("tool %s can't handle symlinks\n") % tmsg) |
135 elif binary and not _toolbool(ui, tool, "binary"): |
138 elif binary and not _toolbool(ui, tool, "binary"): |
136 ui.warn(_("tool %s can't handle binary\n") % tmsg) |
139 ui.warn(_("tool %s can't handle binary\n") % tmsg) |
|
140 elif changedelete and not supportscd(tool): |
|
141 # the nomerge tools are the only tools that support change/delete |
|
142 # conflicts |
|
143 pass |
137 elif not util.gui() and _toolbool(ui, tool, "gui"): |
144 elif not util.gui() and _toolbool(ui, tool, "gui"): |
138 ui.warn(_("tool %s requires a GUI\n") % tmsg) |
145 ui.warn(_("tool %s requires a GUI\n") % tmsg) |
139 else: |
146 else: |
140 return True |
147 return True |
141 return False |
148 return False |
143 # internal config: ui.forcemerge |
150 # internal config: ui.forcemerge |
144 # forcemerge comes from command line arguments, highest priority |
151 # forcemerge comes from command line arguments, highest priority |
145 force = ui.config('ui', 'forcemerge') |
152 force = ui.config('ui', 'forcemerge') |
146 if force: |
153 if force: |
147 toolpath = _findtool(ui, force) |
154 toolpath = _findtool(ui, force) |
148 if toolpath: |
155 if changedelete and not supportscd(toolpath): |
149 return (force, util.shellquote(toolpath)) |
156 return ":prompt", None |
150 else: |
157 else: |
151 # mimic HGMERGE if given tool not found |
158 if toolpath: |
152 return (force, force) |
159 return (force, util.shellquote(toolpath)) |
|
160 else: |
|
161 # mimic HGMERGE if given tool not found |
|
162 return (force, force) |
153 |
163 |
154 # HGMERGE takes next precedence |
164 # HGMERGE takes next precedence |
155 hgmerge = os.environ.get("HGMERGE") |
165 hgmerge = os.environ.get("HGMERGE") |
156 if hgmerge: |
166 if hgmerge: |
157 return (hgmerge, hgmerge) |
167 if changedelete and not supportscd(hgmerge): |
|
168 return ":prompt", None |
|
169 else: |
|
170 return (hgmerge, hgmerge) |
158 |
171 |
159 # then patterns |
172 # then patterns |
160 for pat, tool in ui.configitems("merge-patterns"): |
173 for pat, tool in ui.configitems("merge-patterns"): |
161 mf = match.match(repo.root, '', [pat]) |
174 mf = match.match(repo.root, '', [pat]) |
162 if mf(path) and check(tool, pat, symlink, False): |
175 if mf(path) and check(tool, pat, symlink, False, changedelete): |
163 toolpath = _findtool(ui, tool) |
176 toolpath = _findtool(ui, tool) |
164 return (tool, util.shellquote(toolpath)) |
177 return (tool, util.shellquote(toolpath)) |
165 |
178 |
166 # then merge tools |
179 # then merge tools |
167 tools = {} |
180 tools = {} |
174 disabled.add(t) |
187 disabled.add(t) |
175 names = tools.keys() |
188 names = tools.keys() |
176 tools = sorted([(-p, t) for t, p in tools.items() if t not in disabled]) |
189 tools = sorted([(-p, t) for t, p in tools.items() if t not in disabled]) |
177 uimerge = ui.config("ui", "merge") |
190 uimerge = ui.config("ui", "merge") |
178 if uimerge: |
191 if uimerge: |
179 if uimerge not in names: |
192 # external tools defined in uimerge won't be able to handle |
|
193 # change/delete conflicts |
|
194 if uimerge not in names and not changedelete: |
180 return (uimerge, uimerge) |
195 return (uimerge, uimerge) |
181 tools.insert(0, (None, uimerge)) # highest priority |
196 tools.insert(0, (None, uimerge)) # highest priority |
182 tools.append((None, "hgmerge")) # the old default, if found |
197 tools.append((None, "hgmerge")) # the old default, if found |
183 for p, t in tools: |
198 for p, t in tools: |
184 if check(t, None, symlink, binary): |
199 if check(t, None, symlink, binary, changedelete): |
185 toolpath = _findtool(ui, t) |
200 toolpath = _findtool(ui, t) |
186 return (t, util.shellquote(toolpath)) |
201 return (t, util.shellquote(toolpath)) |
187 |
202 |
188 # internal merge or prompt as last resort |
203 # internal merge or prompt as last resort |
189 if symlink or binary: |
204 if symlink or binary or changedelete: |
190 return ":prompt", None |
205 return ":prompt", None |
191 return ":merge", None |
206 return ":merge", None |
192 |
207 |
193 def _eoltype(data): |
208 def _eoltype(data): |
194 "Guess the EOL type of a file" |
209 "Guess the EOL type of a file" |
533 |
548 |
534 ui = repo.ui |
549 ui = repo.ui |
535 fd = fcd.path() |
550 fd = fcd.path() |
536 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary() |
551 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary() |
537 symlink = 'l' in fcd.flags() + fco.flags() |
552 symlink = 'l' in fcd.flags() + fco.flags() |
538 tool, toolpath = _picktool(repo, ui, fd, binary, symlink) |
553 changedelete = fcd.isabsent() or fco.isabsent() |
|
554 tool, toolpath = _picktool(repo, ui, fd, binary, symlink, changedelete) |
539 if tool in internals and tool.startswith('internal:'): |
555 if tool in internals and tool.startswith('internal:'): |
540 # normalize to new-style names (':merge' etc) |
556 # normalize to new-style names (':merge' etc) |
541 tool = tool[len('internal'):] |
557 tool = tool[len('internal'):] |
542 ui.debug("picked tool '%s' for %s (binary %s symlink %s)\n" % |
558 ui.debug("picked tool '%s' for %s (binary %s symlink %s)\n" % |
543 (tool, fd, binary, symlink)) |
559 (tool, fd, binary, symlink)) |