difftool: print list of valid tools with '--tool-help'
authorTim Henigan <tim.henigan@gmail.com>
Thu, 29 Mar 2012 13:39:18 +0000 (09:39 -0400)
committerJunio C Hamano <gitster@pobox.com>
Mon, 23 Apr 2012 19:00:42 +0000 (12:00 -0700)
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>
Documentation/git-difftool.txt
git-difftool.perl
t/t7800-difftool.sh

index aba5e76c52761af456db7f2c00786a9b5a1d97fa..31fc2e3aed613acd8cb6e4a56ae66c378fb07a0d 100644 (file)
@@ -36,11 +36,9 @@ OPTIONS
 
 -t <tool>::
 --tool=<tool>::
-       Use the diff tool specified by <tool>.
-       Valid diff tools are:
-       araxis, bc3, deltawalker, diffuse, emerge, ecmerge, gvimdiff,
-       kdiff3, kompare, meld, opendiff, p4merge, tkdiff, vimdiff and
-       xxdiff.
+       Use the diff tool specified by <tool>.  Valid values include
+       emerge, kompare, meld, and vimdiff. Run `git difftool --tool-help`
+       for the list of valid <tool> settings.
 +
 If a diff tool is not specified, 'git difftool'
 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
 being compared. `$BASE` is provided for compatibility
 with custom merge tool commands and has the same value as `$MERGED`.
 
+--tool-help::
+       Print a list of diff tools that may be used with `--tool`.
+
 -x <command>::
 --extcmd=<command>::
        Specify a custom command for viewing diffs.
index 850ebbe5718b3b13404ff8c7e30de6df011b14cd..ae1e0525d89181f8adbe288b62e107b8dadb8ca1 100755 (executable)
@@ -15,12 +15,14 @@ use strict;
 use warnings;
 use File::Basename qw(dirname);
 use File::Copy;
+use File::Find;
 use File::stat;
 use File::Path qw(mkpath);
 use File::Temp qw(tempdir);
 use Getopt::Long qw(:config pass_through);
 use Git;
 
+my @tools;
 my @working_tree;
 my $rc;
 my $repo = Git->repository();
@@ -30,7 +32,7 @@ sub usage
 {
        my $exitcode = shift;
        print << 'USAGE';
-usage: git difftool [-t|--tool=<tool>]
+usage: git difftool [-t|--tool=<tool>] [--tool-help]
                     [-x|--extcmd=<cmd>]
                     [-g|--gui] [--no-gui]
                     [--prompt] [-y|--no-prompt]
@@ -62,6 +64,51 @@ sub find_worktree
 
 my $workdir = find_worktree();
 
+sub filter_tool_scripts
+{
+       if (-d $_) {
+               if ($_ ne ".") {
+                       # Ignore files in subdirectories
+                       $File::Find::prune = 1;
+               }
+       } else {
+               if ((-f $_) && ($_ ne "defaults")) {
+                       push(@tools, $_);
+               }
+       }
+}
+
+sub print_tool_help
+{
+       my ($cmd, @found, @notfound);
+       my $gitpath = Git::exec_path();
+
+       find(\&filter_tool_scripts, "$gitpath/mergetools");
+
+       foreach my $tool (@tools) {
+               $cmd  = "TOOL_MODE=diff";
+               $cmd .= ' && . "$(git --exec-path)/git-mergetool--lib"';
+               $cmd .= " && get_merge_tool_path $tool >/dev/null 2>&1";
+               $cmd .= " && can_diff >/dev/null 2>&1";
+               if (system('sh', '-c', $cmd) == 0) {
+                       push(@found, $tool);
+               } else {
+                       push(@notfound, $tool);
+               }
+       }
+
+       print "'git difftool --tool=<tool>' may be set to one of the following:\n";
+       print "\t$_\n" for (sort(@found));
+
+       print "\nThe following tools are valid, but not currently available:\n";
+       print "\t$_\n" for (sort(@notfound));
+
+       print "\nNOTE: Some of the tools listed above only work in a windowed\n";
+       print "environment. If run in a terminal-only session, they will fail.\n";
+
+       exit(0);
+}
+
 sub setup_dir_diff
 {
        # Run the diff; exit immediately if no diff found
@@ -230,18 +277,22 @@ sub write_to_file
 
 # parse command-line options. all unrecognized options and arguments
 # are passed through to the 'git diff' command.
-my ($difftool_cmd, $dirdiff, $extcmd, $gui, $help, $prompt);
+my ($difftool_cmd, $dirdiff, $extcmd, $gui, $help, $prompt, $tool_help);
 GetOptions('g|gui!' => \$gui,
        'd|dir-diff' => \$dirdiff,
        'h' => \$help,
        'prompt!' => \$prompt,
        'y' => sub { $prompt = 0; },
        't|tool:s' => \$difftool_cmd,
+       'tool-help' => \$tool_help,
        'x|extcmd:s' => \$extcmd);
 
 if (defined($help)) {
        usage(0);
 }
+if (defined($tool_help)) {
+       print_tool_help();
+}
 if (defined($difftool_cmd)) {
        if (length($difftool_cmd) > 0) {
                $ENV{GIT_DIFF_TOOL} = $difftool_cmd;
index 478c1bef375c0529a338b07e6e71669fa34bb7f2..bbe71e5f73a0b1a95c8afc4365a8b7c93bfcf40d 100755 (executable)
@@ -319,6 +319,11 @@ test_expect_success PERL 'say no to the second file' '
        echo "$diff" | stdin_doesnot_contain br2
 '
 
+test_expect_success PERL 'difftool --tool-help' '
+       tool_help=$(git difftool --tool-help) &&
+       echo "$tool_help" | stdin_contains tool
+'
+
 test_expect_success PERL 'setup change in subdirectory' '
        git checkout master &&
        mkdir sub &&