git-gui: Run the pre-commit hook in the background.
authorShawn O. Pearce <spearce@spearce.org>
Sun, 12 Nov 2006 22:58:08 +0000 (17:58 -0500)
committerShawn O. Pearce <spearce@spearce.org>
Mon, 13 Nov 2006 05:10:38 +0000 (00:10 -0500)
I started to notice on Windows that commits took a lot longer to get
going than on my Mac OS X system.  The real reason is the repositories
that I'm testing with on Windows all enabled the standard pre-commit hook
while my test repository on Mac OS X doesn't have it executable (so its
not running).  So the Windows repositories are spending this
lag time running that hook.

Now we run the pre-commit hook in the background, allowing the UI to
update and tell the user we are busy doing things.

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

diff --git a/git-gui b/git-gui
index 761ce7551f8250fba693ecc8d516cb7f00303e6e..bee17de4ddccb8abd99773dd538cad90d26e54bb 100755 (executable)
--- a/git-gui
+++ b/git-gui
@@ -664,8 +664,8 @@ proc load_last_commit {} {
 
 proc commit_tree {} {
        global tcl_platform HEAD gitdir commit_type file_states
-       global commit_active ui_status_value
-       global ui_comm
+       global commit_active pch_error
+       global ui_status_value ui_comm
 
        if {$commit_active || ![lock_index update]} return
 
@@ -739,33 +739,64 @@ A good commit message has the following format:
                return
        }
 
+       set commit_active 1
+
        # -- Ask the pre-commit hook for the go-ahead.
        #
        set pchook [file join $gitdir hooks pre-commit]
        if {$tcl_platform(platform) == {windows} && [file isfile $pchook]} {
-               set pchook [list sh -c \
-                       "if test -x \"$pchook\"; then exec \"$pchook\"; fi"]
+               set pchook [list sh -c [concat \
+                       "if test -x \"$pchook\";" \
+                       "then exec \"$pchook\" 2>&1;" \
+                       "fi"]]
        } elseif {[file executable $pchook]} {
-               set pchook [list $pchook]
+               set pchook [list $pchook |& cat]
        } else {
                set pchook {}
        }
-       if {$pchook != {} && [catch {eval exec $pchook} err]} {
-               hook_failed_popup pre-commit $err
-               unlock_index
+       if {$pchook != {}} {
+               set ui_status_value {Calling pre-commit hook...}
+               set pch_error {}
+               set fd_ph [open "| $pchook" r]
+               fconfigure $fd_ph -blocking 0 -translation binary
+               fileevent $fd_ph readable \
+                       [list commit_stage1 $fd_ph $curHEAD $msg]
+       } else {
+               commit_stage2 $curHEAD $msg
+       }
+}
+
+proc commit_stage1 {fd_ph curHEAD msg} {
+       global commit_active pch_error ui_status_value
+
+       append pch_error [read $fd_ph]
+       fconfigure $fd_ph -blocking 1
+       if {[eof $fd_ph]} {
+               if {[catch {close $fd_ph}]} {
+                       set ui_status_value {Commit declined by pre-commit hook.}
+                       hook_failed_popup pre-commit $pch_error
+                       unlock_index
+                       set commit_active 0
+                       set pch_error {}
+                       return
+               }
+               commit_stage2 $curHEAD $msg
                return
        }
+       fconfigure $fd_ph -blocking 0
+}
+
+proc commit_stage2 {curHEAD msg} {
+       global ui_status_value
 
        # -- Write the tree in the background.
        #
-       set commit_active 1
        set ui_status_value {Committing changes...}
-
        set fd_wt [open "| git write-tree" r]
-       fileevent $fd_wt readable [list commit_stage2 $fd_wt $curHEAD $msg]
+       fileevent $fd_wt readable [list commit_stage3 $fd_wt $curHEAD $msg]
 }
 
-proc commit_stage2 {fd_wt curHEAD msg} {
+proc commit_stage3 {fd_wt curHEAD msg} {
        global single_commit gitdir HEAD PARENT commit_type
        global commit_active ui_status_value ui_comm
        global file_states