git-gui: Honor the standard commit-msg hook
[gitweb.git] / lib / commit.tcl
index 1c0586c409b1700f250270a87f178f621989c32b..73e18bf9825d7ce7c5dfab4a1a35082333864bd0 100644 (file)
@@ -192,6 +192,24 @@ A good commit message has the following format:
                return
        }
 
+       # -- Build the message file.
+       #
+       set msg_p [gitdir GITGUI_EDITMSG]
+       set msg_wt [open $msg_p w]
+       fconfigure $msg_wt -translation lf
+       if {[catch {set enc $repo_config(i18n.commitencoding)}]} {
+               set enc utf-8
+       }
+       set use_enc [tcl_encoding $enc]
+       if {$use_enc ne {}} {
+               fconfigure $msg_wt -encoding $use_enc
+       } else {
+               puts stderr [mc "warning: Tcl does not support encoding '%s'." $enc]
+               fconfigure $msg_wt -encoding utf-8
+       }
+       puts $msg_wt $msg
+       close $msg_wt
+
        # -- Run the pre-commit hook.
        #
        set pchook [gitdir hooks pre-commit]
@@ -207,7 +225,7 @@ A good commit message has the following format:
        } elseif {[file executable $pchook]} {
                set pchook [list $pchook |& cat]
        } else {
-               commit_writetree $curHEAD $msg
+               commit_commitmsg $curHEAD $msg_p
                return
        }
 
@@ -216,21 +234,22 @@ A good commit message has the following format:
        set fd_ph [open "| $pchook" r]
        fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
        fileevent $fd_ph readable \
-               [list commit_prehook_wait $fd_ph $curHEAD $msg]
+               [list commit_prehook_wait $fd_ph $curHEAD $msg_p]
 }
 
-proc commit_prehook_wait {fd_ph curHEAD msg} {
+proc commit_prehook_wait {fd_ph curHEAD msg_p} {
        global pch_error
 
        append pch_error [read $fd_ph]
        fconfigure $fd_ph -blocking 1
        if {[eof $fd_ph]} {
                if {[catch {close $fd_ph}]} {
+                       catch {file delete $msg_p}
                        ui_status {Commit declined by pre-commit hook.}
                        hook_failed_popup pre-commit $pch_error
                        unlock_index
                } else {
-                       commit_writetree $curHEAD $msg
+                       commit_commitmsg $curHEAD $msg_p
                }
                set pch_error {}
                return
@@ -238,14 +257,64 @@ proc commit_prehook_wait {fd_ph curHEAD msg} {
        fconfigure $fd_ph -blocking 0
 }
 
-proc commit_writetree {curHEAD msg} {
+proc commit_commitmsg {curHEAD msg_p} {
+       global pch_error
+
+       # -- Run the commit-msg hook.
+       #
+       set pchook [gitdir hooks commit-msg]
+
+       # On Cygwin [file executable] might lie so we need to ask
+       # the shell if the hook is executable.  Yes that's annoying.
+       #
+       if {[is_Cygwin] && [file isfile $pchook]} {
+               set pchook [list sh -c [concat \
+                       "if test -x \"$pchook\";" \
+                       "then exec \"$pchook\" \"$msg_p\" 2>&1;" \
+                       "fi"]]
+       } elseif {[file executable $pchook]} {
+               set pchook [list $pchook $msg_p |& cat]
+       } else {
+               commit_writetree $curHEAD $msg_p
+               return
+       }
+
+       ui_status {Calling commit-msg hook...}
+       set pch_error {}
+       set fd_ph [open "| $pchook" r]
+       fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
+       fileevent $fd_ph readable \
+               [list commit_commitmsg_wait $fd_ph $curHEAD $msg_p]
+}
+
+proc commit_commitmsg_wait {fd_ph curHEAD msg_p} {
+       global pch_error
+
+       append pch_error [read $fd_ph]
+       fconfigure $fd_ph -blocking 1
+       if {[eof $fd_ph]} {
+               if {[catch {close $fd_ph}]} {
+                       catch {file delete $msg_p}
+                       ui_status {Commit declined by commit-msg hook.}
+                       hook_failed_popup commit-msg $pch_error
+                       unlock_index
+               } else {
+                       commit_writetree $curHEAD $msg_p
+               }
+               set pch_error {}
+               return
+       }
+       fconfigure $fd_ph -blocking 0
+}
+
+proc commit_writetree {curHEAD msg_p} {
        ui_status {Committing changes...}
        set fd_wt [git_read write-tree]
        fileevent $fd_wt readable \
-               [list commit_committree $fd_wt $curHEAD $msg]
+               [list commit_committree $fd_wt $curHEAD $msg_p]
 }
 
-proc commit_committree {fd_wt curHEAD msg} {
+proc commit_committree {fd_wt curHEAD msg_p} {
        global HEAD PARENT MERGE_HEAD commit_type
        global current_branch
        global ui_comm selected_commit_type
@@ -254,6 +323,7 @@ proc commit_committree {fd_wt curHEAD msg} {
 
        gets $fd_wt tree_id
        if {[catch {close $fd_wt} err]} {
+               catch {file delete $msg_p}
                error_popup [strcat [mc "write-tree failed:"] "\n\n$err"]
                ui_status {Commit failed.}
                unlock_index
@@ -276,6 +346,7 @@ proc commit_committree {fd_wt curHEAD msg} {
                }
 
                if {$tree_id eq $old_tree} {
+                       catch {file delete $msg_p}
                        info_popup [mc "No changes to commit.
 
 No files were modified by this commit and it was not a merge commit.
@@ -288,24 +359,6 @@ A rescan will be automatically started now.
                }
        }
 
-       # -- Build the message.
-       #
-       set msg_p [gitdir COMMIT_EDITMSG]
-       set msg_wt [open $msg_p w]
-       fconfigure $msg_wt -translation lf
-       if {[catch {set enc $repo_config(i18n.commitencoding)}]} {
-               set enc utf-8
-       }
-       set use_enc [tcl_encoding $enc]
-       if {$use_enc ne {}} {
-               fconfigure $msg_wt -encoding $use_enc
-       } else {
-               puts stderr [mc "warning: Tcl does not support encoding '%s'." $enc]
-               fconfigure $msg_wt -encoding utf-8
-       }
-       puts $msg_wt $msg
-       close $msg_wt
-
        # -- Create the commit.
        #
        set cmd [list commit-tree $tree_id]
@@ -314,6 +367,7 @@ A rescan will be automatically started now.
        }
        lappend cmd <$msg_p
        if {[catch {set cmt_id [eval git $cmd]} err]} {
+               catch {file delete $msg_p}
                error_popup [strcat [mc "commit-tree failed:"] "\n\n$err"]
                ui_status {Commit failed.}
                unlock_index
@@ -326,16 +380,14 @@ A rescan will be automatically started now.
        if {$commit_type ne {normal}} {
                append reflogm " ($commit_type)"
        }
-       set i [string first "\n" $msg]
-       if {$i >= 0} {
-               set subject [string range $msg 0 [expr {$i - 1}]]
-       } else {
-               set subject $msg
-       }
+       set msg_fd [open $msg_p r]
+       gets $msg_fd subject
+       close $msg_fd
        append reflogm {: } $subject
        if {[catch {
                        git update-ref -m $reflogm HEAD $cmt_id $curHEAD
                } err]} {
+               catch {file delete $msg_p}
                error_popup [strcat [mc "update-ref failed:"] "\n\n$err"]
                ui_status {Commit failed.}
                unlock_index