1
2
3
4
5
6
7
8
9
10
11
12 package org.eclipse.jgit.internal.diffmergetool;
13
14 import java.io.File;
15 import java.io.IOException;
16 import java.util.Collections;
17 import java.util.LinkedHashSet;
18 import java.util.Map;
19 import java.util.Map.Entry;
20 import java.util.Optional;
21 import java.util.Set;
22 import java.util.TreeMap;
23
24 import org.eclipse.jgit.internal.JGitText;
25 import org.eclipse.jgit.lib.Repository;
26 import org.eclipse.jgit.lib.StoredConfig;
27 import org.eclipse.jgit.lib.internal.BooleanTriState;
28 import org.eclipse.jgit.treewalk.TreeWalk;
29 import org.eclipse.jgit.util.FS;
30 import org.eclipse.jgit.util.FS.ExecutionResult;
31 import org.eclipse.jgit.util.StringUtils;
32
33
34
35
36 public class DiffTools {
37
38 private final FS fs;
39
40 private final File gitDir;
41
42 private final File workTree;
43
44 private final DiffToolConfig config;
45
46 private final Repository repo;
47
48 private final Map<String, ExternalDiffTool> predefinedTools;
49
50 private final Map<String, ExternalDiffTool> userDefinedTools;
51
52
53
54
55
56
57
58 public DiffTools(Repository repo) {
59 this(repo, repo.getConfig());
60 }
61
62
63
64
65
66
67
68 public DiffTools(StoredConfig config) {
69 this(null, config);
70 }
71
72 private DiffTools(Repository repo, StoredConfig config) {
73 this.repo = repo;
74 this.config = config.get(DiffToolConfig.KEY);
75 this.gitDir = repo == null ? null : repo.getDirectory();
76 this.fs = repo == null ? FS.DETECTED : repo.getFS();
77 this.workTree = repo == null ? null : repo.getWorkTree();
78 predefinedTools = setupPredefinedTools();
79 userDefinedTools = setupUserDefinedTools(predefinedTools);
80 }
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110 public Optional<ExecutionResult> compare(FileElement localFile,
111 FileElement remoteFile, Optional<String> toolName,
112 BooleanTriState prompt, boolean gui, BooleanTriState trustExitCode,
113 PromptContinueHandler promptHandler,
114 InformNoToolHandler noToolHandler) throws ToolException {
115
116 String toolNameToUse;
117
118 if (toolName == null) {
119 throw new ToolException(JGitText.get().diffToolNullError);
120 }
121
122 if (toolName.isPresent()) {
123 toolNameToUse = toolName.get();
124 } else {
125 toolNameToUse = getDefaultToolName(gui);
126 }
127
128 if (StringUtils.isEmptyOrNull(toolNameToUse)) {
129 throw new ToolException(JGitText.get().diffToolNotGivenError);
130 }
131
132 boolean doPrompt;
133 if (prompt != BooleanTriState.UNSET) {
134 doPrompt = prompt == BooleanTriState.TRUE;
135 } else {
136 doPrompt = isInteractive();
137 }
138
139 if (doPrompt) {
140 if (!promptHandler.prompt(toolNameToUse)) {
141 return Optional.empty();
142 }
143 }
144
145 boolean trust;
146 if (trustExitCode != BooleanTriState.UNSET) {
147 trust = trustExitCode == BooleanTriState.TRUE;
148 } else {
149 trust = config.isTrustExitCode();
150 }
151
152 ExternalDiffTool tool = getTool(toolNameToUse);
153 if (tool == null) {
154 throw new ToolException(
155 "External diff tool is not defined: " + toolNameToUse);
156 }
157
158 return Optional.of(
159 compare(localFile, remoteFile, tool, trust));
160 }
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176 public ExecutionResult compare(FileElement localFile,
177 FileElement remoteFile, ExternalDiffTool tool,
178 boolean trustExitCode) throws ToolException {
179 try {
180 if (tool == null) {
181 throw new ToolException(JGitText
182 .get().diffToolNotSpecifiedInGitAttributesError);
183 }
184
185 String command = ExternalToolUtils.prepareCommand(tool.getCommand(),
186 localFile, remoteFile, null, null);
187
188 Map<String, String> env = ExternalToolUtils.prepareEnvironment(
189 gitDir, localFile, remoteFile, null, null);
190
191 CommandExecutor cmdExec = new CommandExecutor(fs, trustExitCode);
192 return cmdExec.run(command, workTree, env);
193 } catch (IOException | InterruptedException e) {
194 throw new ToolException(e);
195 } finally {
196 localFile.cleanTemporaries();
197 remoteFile.cleanTemporaries();
198 }
199 }
200
201
202
203
204
205
206 public Set<String> getUserDefinedToolNames() {
207 return userDefinedTools.keySet();
208 }
209
210
211
212
213
214
215 public Set<String> getPredefinedToolNames() {
216 return predefinedTools.keySet();
217 }
218
219
220
221
222
223
224
225 public Set<String> getAllToolNames() {
226 String defaultName = getDefaultToolName(false);
227 if (defaultName == null) {
228 defaultName = getFirstAvailableTool();
229 }
230 return ExternalToolUtils.createSortedToolSet(defaultName,
231 getUserDefinedToolNames(), getPredefinedToolNames());
232 }
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248 public Optional<String> getExternalToolFromAttributes(final String path)
249 throws ToolException {
250 return ExternalToolUtils.getExternalToolFromAttributes(repo, path,
251 ExternalToolUtils.KEY_DIFF_TOOL);
252 }
253
254
255
256
257
258
259 public Set<String> getPredefinedAvailableTools() {
260 Map<String, ExternalDiffTool> defTools = getPredefinedTools(true);
261 Set<String> availableTools = new LinkedHashSet<>();
262 for (Entry<String, ExternalDiffTool> elem : defTools.entrySet()) {
263 if (elem.getValue().isAvailable()) {
264 availableTools.add(elem.getKey());
265 }
266 }
267 return availableTools;
268 }
269
270
271
272
273
274
275 public Map<String, ExternalDiffTool> getUserDefinedTools() {
276 return Collections.unmodifiableMap(userDefinedTools);
277 }
278
279
280
281
282
283
284
285
286
287
288
289
290 public Map<String, ExternalDiffTool> getPredefinedTools(
291 boolean checkAvailability) {
292 if (checkAvailability) {
293 for (ExternalDiffTool tool : predefinedTools.values()) {
294 PreDefinedDiffTool predefTool = (PreDefinedDiffTool) tool;
295 predefTool.setAvailable(ExternalToolUtils.isToolAvailable(fs,
296 gitDir, workTree, predefTool.getPath()));
297 }
298 }
299 return Collections.unmodifiableMap(predefinedTools);
300 }
301
302
303
304
305
306
307 public String getFirstAvailableTool() {
308 for (ExternalDiffTool tool : predefinedTools.values()) {
309 if (ExternalToolUtils.isToolAvailable(fs, gitDir, workTree,
310 tool.getPath())) {
311 return tool.getName();
312 }
313 }
314 return null;
315 }
316
317
318
319
320
321
322
323
324 public String getDefaultToolName(boolean gui) {
325 String guiToolName;
326 if (gui) {
327 guiToolName = config.getDefaultGuiToolName();
328 if (guiToolName != null) {
329 return guiToolName;
330 }
331 }
332 return config.getDefaultToolName();
333 }
334
335
336
337
338
339
340 public boolean isInteractive() {
341 return config.isPrompt();
342 }
343
344 private ExternalDiffTool getTool(final String name) {
345 ExternalDiffTool tool = userDefinedTools.get(name);
346 if (tool == null) {
347 tool = predefinedTools.get(name);
348 }
349 return tool;
350 }
351
352 private static Map<String, ExternalDiffTool> setupPredefinedTools() {
353 Map<String, ExternalDiffTool> tools = new TreeMap<>();
354 for (CommandLineDiffTool tool : CommandLineDiffTool.values()) {
355 tools.put(tool.name(), new PreDefinedDiffTool(tool));
356 }
357 return tools;
358 }
359
360 private Map<String, ExternalDiffTool> setupUserDefinedTools(
361 Map<String, ExternalDiffTool> predefTools) {
362 Map<String, ExternalDiffTool> tools = new TreeMap<>();
363 Map<String, ExternalDiffTool> userTools = config.getTools();
364 for (String name : userTools.keySet()) {
365 ExternalDiffTool userTool = userTools.get(name);
366
367 if (userTool.getCommand() != null) {
368 tools.put(name, userTool);
369 } else if (userTool.getPath() != null) {
370
371
372 PreDefinedDiffTool predefTool = (PreDefinedDiffTool) predefTools
373 .get(name);
374 if (predefTool != null) {
375 predefTool.setPath(userTool.getPath());
376 }
377 }
378 }
379 return tools;
380 }
381
382 }