difftool: print list of valid tools with '--tool-help'

Since bc7a96a (mergetool--lib: Refactor tools into separate files, 2011-08-18), it is possible to add a new diff tool by creating a simple script in the '$(git --exec-path)/mergetools' directory. Updating the difftool help text is still a manual process, and the documentation can easily go out of sync. This commit teaches difftool the '--tool-help' option, which: - Reads the list of valid tools from 'mergetools/*' - Determines which of them are actually installed - Determines which are capable of diffing (i.e. not just a merge tool) - Prints the resulting list for the user Signed-off-by: Tim Henigan <tim.henigan@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Tim Henigan committed Mar 29, 2012 at 09:39 UTC bf73fc212a159210398b6d46ed5e9101c650e7db
3 files changed +64 -7
Documentation/git-difftool.txt
+6 -5
@@ -36,11 +36,9 @@ OPTIONS
36
37 -t <tool>::
38 --tool=<tool>::
39 - Use the diff tool specified by <tool>.
40 - Valid diff tools are:
41 - araxis, bc3, deltawalker, diffuse, emerge, ecmerge, gvimdiff,
42 - kdiff3, kompare, meld, opendiff, p4merge, tkdiff, vimdiff and
43 - xxdiff.
39 + Use the diff tool specified by <tool>. Valid values include
40 + emerge, kompare, meld, and vimdiff. Run `git difftool --tool-help`
41 + for the list of valid <tool> settings.
42 +
43 If a diff tool is not specified, 'git difftool'
44 will use the configuration variable `diff.tool`. If the
@@ -68,6 +66,9 @@ of the diff post-image. `$MERGED` is the name of the file which is
66 being compared. `$BASE` is provided for compatibility
67 with custom merge tool commands and has the same value as `$MERGED`.
68
69 +--tool-help::
70 + Print a list of diff tools that may be used with `--tool`.
71 +
72 -x <command>::
73 --extcmd=<command>::
74 Specify a custom command for viewing diffs.
git-difftool.perl
+53 -2
@@ -15,12 +15,14 @@ use strict;
15 use warnings;
16 use File::Basename qw(dirname);
17 use File::Copy;
18 +use File::Find;
19 use File::stat;
20 use File::Path qw(mkpath);
21 use File::Temp qw(tempdir);
22 use Getopt::Long qw(:config pass_through);
23 use Git;
24
25 +my @tools;
26 my @working_tree;
27 my $rc;
28 my $repo = Git->repository();
@@ -30,7 +32,7 @@ sub usage
32 {
33 my $exitcode = shift;
34 print << 'USAGE';
33 -usage: git difftool [-t|--tool=<tool>]
35 +usage: git difftool [-t|--tool=<tool>] [--tool-help]
36 [-x|--extcmd=<cmd>]
37 [-g|--gui] [--no-gui]
38 [--prompt] [-y|--no-prompt]
@@ -62,6 +64,51 @@ sub find_worktree
64
65 my $workdir = find_worktree();
66
67 +sub filter_tool_scripts
68 +{
69 + if (-d $_) {
70 + if ($_ ne ".") {
71 + # Ignore files in subdirectories
72 + $File::Find::prune = 1;
73 + }
74 + } else {
75 + if ((-f $_) && ($_ ne "defaults")) {
76 + push(@tools, $_);
77 + }
78 + }
79 +}
80 +
81 +sub print_tool_help
82 +{
83 + my ($cmd, @found, @notfound);
84 + my $gitpath = Git::exec_path();
85 +
86 + find(\&filter_tool_scripts, "$gitpath/mergetools");
87 +
88 + foreach my $tool (@tools) {
89 + $cmd = "TOOL_MODE=diff";
90 + $cmd .= ' && . "$(git --exec-path)/git-mergetool--lib"';
91 + $cmd .= " && get_merge_tool_path $tool >/dev/null 2>&1";
92 + $cmd .= " && can_diff >/dev/null 2>&1";
93 + if (system('sh', '-c', $cmd) == 0) {
94 + push(@found, $tool);
95 + } else {
96 + push(@notfound, $tool);
97 + }
98 + }
99 +
100 + print "'git difftool --tool=<tool>' may be set to one of the following:\n";
101 + print "\t$_\n" for (sort(@found));
102 +
103 + print "\nThe following tools are valid, but not currently available:\n";
104 + print "\t$_\n" for (sort(@notfound));
105 +
106 + print "\nNOTE: Some of the tools listed above only work in a windowed\n";
107 + print "environment. If run in a terminal-only session, they will fail.\n";
108 +
109 + exit(0);
110 +}
111 +
112 sub setup_dir_diff
113 {
114 # Run the diff; exit immediately if no diff found
@@ -230,18 +277,22 @@ sub write_to_file
277
278 # parse command-line options. all unrecognized options and arguments
279 # are passed through to the 'git diff' command.
233 -my ($difftool_cmd, $dirdiff, $extcmd, $gui, $help, $prompt);
280 +my ($difftool_cmd, $dirdiff, $extcmd, $gui, $help, $prompt, $tool_help);
281 GetOptions('g|gui!' => \$gui,
282 'd|dir-diff' => \$dirdiff,
283 'h' => \$help,
284 'prompt!' => \$prompt,
285 'y' => sub { $prompt = 0; },
286 't|tool:s' => \$difftool_cmd,
287 + 'tool-help' => \$tool_help,
288 'x|extcmd:s' => \$extcmd);
289
290 if (defined($help)) {
291 usage(0);
292 }
293 +if (defined($tool_help)) {
294 + print_tool_help();
295 +}
296 if (defined($difftool_cmd)) {
297 if (length($difftool_cmd) > 0) {
298 $ENV{GIT_DIFF_TOOL} = $difftool_cmd;
t/t7800-difftool.sh
+5
@@ -319,6 +319,11 @@ test_expect_success PERL 'say no to the second file' '
319 echo "$diff" | stdin_doesnot_contain br2
320 '
321
322 +test_expect_success PERL 'difftool --tool-help' '
323 + tool_help=$(git difftool --tool-help) &&
324 + echo "$tool_help" | stdin_contains tool
325 +'
326 +
327 test_expect_success PERL 'setup change in subdirectory' '
328 git checkout master &&
329 mkdir sub &&