git-gui: Perform our own magic shbang detection on Windows
authorShawn O. Pearce <spearce@spearce.org>
Mon, 9 Jul 2007 06:47:33 +0000 (02:47 -0400)
committerShawn O. Pearce <spearce@spearce.org>
Mon, 9 Jul 2007 06:47:33 +0000 (02:47 -0400)
If we cannot locate a .exe for a git tool that we want to run than
it may just be a Bourne shell script as these are popular in Git.
In such a case the first line of the file will say "#!/bin/sh" so
a UNIX kernel knows what program to start to parse and run that.
But Windows doesn't support shbang lines, and neither does the Tcl
that comes with Cygwin.

We can pass control off to the git wrapper as that is a real Cygwin
program and can therefore start the Bourne shell script, but that is
at least two fork+exec calls to get the program running.  One to do
the fork+exec of the git wrapper and another to start the Bourne shell
script.  If the program is run multiple times it is rather expensive
as the magic shbang detection won't be cached across executions.

On MinGW/MSYS we don't have the luxury of such magic detection.  The
MSYS team has taught some of this magic to the git wrapper, but again
its slower than it needs to be as the git wrapper must still go and
run the Bourne shell after it is called.

We now attempt to guess the shbang line on Windows by reading the
first line of the file and building our own command line path from
it.  Currently we support Bourne shell (sh), Perl and Python.  That
is the entire set of shbang lines that appear in git.git today.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
git-gui.sh

index a3ac5daf14c3e57229d3d1dbea5bdee3c368fdb5..7e6952c2bc0d31e8028f80573b846af90be9dc6f 100755 (executable)
@@ -302,19 +302,31 @@ proc _git_cmd {name} {
                set p [gitexec git-$name$::_search_exe]
                if {[file exists $p]} {
                        set v [list $p]
-               } elseif {[is_Cygwin]} {
-                       # On Cygwin git is a proper Cygwin program and knows
-                       # how to properly restart the Cygwin environment and
-                       # spawn its non-.exe support program.
+               } elseif {[is_Windows] && [file exists [gitexec git-$name]]} {
+                       # Try to determine what sort of magic will make
+                       # git-$name go and do its thing, because native
+                       # Tcl on Windows doesn't know it.
                        #
-                       set v [list $::_git $name]
-               } elseif {[is_Windows]
-                       && $::_sh ne {}
-                       && [file exists [gitexec git-$name]]} {
-                       # Assume this is a UNIX shell script.  We can
-                       # probably execute it through a Bourne shell.
-                       #
-                       set v [list $::_sh [gitexec git-$name]]
+                       set p [gitexec git-$name]
+                       set f [open $p r]
+                       set s [gets $f]
+                       close $f
+
+                       switch -glob -- $s {
+                       #!*sh     { set i sh     }
+                       #!*perl   { set i perl   }
+                       #!*python { set i python }
+                       default   { error "git-$name is not supported: $s" }
+                       }
+
+                       upvar #0 _$i interp
+                       if {![info exists interp]} {
+                               set interp [_which $i]
+                       }
+                       if {$interp eq {}} {
+                               error "git-$name requires $i (not in PATH)"
+                       }
+                       set v [list $interp $p]
                } else {
                        # Assume it is builtin to git somehow and we
                        # aren't actually able to see a file for it.
@@ -506,7 +518,6 @@ if {$_git eq {}} {
        exit 1
 }
 set _nice [_which nice]
-set _sh   [_which sh]
 
 ######################################################################
 ##