X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=git-gui.sh;h=2127557f9d595020765dbf318051375be8c7e390;hb=301dfaa9daeb64c66d616efe50fac29d542c9414;hp=b2c9a9c6a06581d232b891f3dca578398d0546bb;hpb=51530d1722b0a4cccc630043fc4b46d075bf8558;p=git.git diff --git a/git-gui.sh b/git-gui.sh index b2c9a9c6a..2127557f9 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -117,6 +117,7 @@ set _gitdir {} set _gitexec {} set _reponame {} set _iscygwin {} +set _search_path {} proc appname {} { global _appname @@ -128,7 +129,7 @@ proc gitdir {args} { if {$args eq {}} { return $_gitdir } - return [eval [concat [list file join $_gitdir] $args]] + return [eval [list file join $_gitdir] $args] } proc gitexec {args} { @@ -137,11 +138,19 @@ proc gitexec {args} { if {[catch {set _gitexec [git --exec-path]} err]} { error "Git not installed?\n\n$err" } + if {[is_Cygwin]} { + set _gitexec [exec cygpath \ + --windows \ + --absolute \ + $_gitexec] + } else { + set _gitexec [file normalize $_gitexec] + } } if {$args eq {}} { return $_gitexec } - return [eval [concat [list file join $_gitexec] $args]] + return [eval [list file join $_gitexec] $args] } proc reponame {} { @@ -237,7 +246,7 @@ proc load_config {include_global} { array unset global_config if {$include_global} { catch { - set fd_rc [open "| git config --global --list" r] + set fd_rc [git_read config --global --list] while {[gets $fd_rc line] >= 0} { if {[regexp {^([^=]+)=(.*)$} $line line name value]} { if {[is_many_config $name]} { @@ -253,7 +262,7 @@ proc load_config {include_global} { array unset repo_config catch { - set fd_rc [open "| git config --list" r] + set fd_rc [git_read config --list] while {[gets $fd_rc line] >= 0} { if {[regexp {^([^=]+)=(.*)$} $line line name value]} { if {[is_many_config $name]} { @@ -280,8 +289,199 @@ proc load_config {include_global} { ## ## handy utils +proc _git_cmd {name} { + global _git_cmd_path + + if {[catch {set v $_git_cmd_path($name)}]} { + switch -- $name { + version - + --version - + --exec-path { return [list $::_git $name] } + } + + set p [gitexec git-$name$::_search_exe] + if {[file exists $p]} { + set v [list $p] + } 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 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. + # + set v [list $::_git $name] + } + set _git_cmd_path($name) $v + } + return $v +} + +proc _which {what} { + global env _search_exe _search_path + + if {$_search_path eq {}} { + if {[is_Cygwin]} { + set _search_path [split [exec cygpath \ + --windows \ + --path \ + --absolute \ + $env(PATH)] {;}] + set _search_exe .exe + } elseif {[is_Windows]} { + set _search_path [split $env(PATH) {;}] + set _search_exe .exe + } else { + set _search_path [split $env(PATH) :] + set _search_exe {} + } + } + + foreach p $_search_path { + set p [file join $p $what$_search_exe] + if {[file exists $p]} { + return [file normalize $p] + } + } + return {} +} + +proc _lappend_nice {cmd_var} { + global _nice + upvar $cmd_var cmd + + if {![info exists _nice]} { + set _nice [_which nice] + } + if {$_nice ne {}} { + lappend cmd $_nice + } +} + proc git {args} { - return [eval exec git $args] + set opt [list exec] + + while {1} { + switch -- [lindex $args 0] { + --nice { + _lappend_nice opt + } + + default { + break + } + + } + + set args [lrange $args 1 end] + } + + set cmdp [_git_cmd [lindex $args 0]] + set args [lrange $args 1 end] + + return [eval $opt $cmdp $args] +} + +proc _open_stdout_stderr {cmd} { + if {[catch { + set fd [open $cmd r] + } err]} { + if { [lindex $cmd end] eq {2>@1} + && $err eq {can not find channel named "1"} + } { + # Older versions of Tcl 8.4 don't have this 2>@1 IO + # redirect operator. Fallback to |& cat for those. + # The command was not actually started, so its safe + # to try to start it a second time. + # + set fd [open [concat \ + [lrange $cmd 0 end-1] \ + [list |& cat] \ + ] r] + } else { + error $err + } + } + fconfigure $fd -eofchar {} + return $fd +} + +proc git_read {args} { + set opt [list |] + + while {1} { + switch -- [lindex $args 0] { + --nice { + _lappend_nice opt + } + + --stderr { + lappend args 2>@1 + } + + default { + break + } + + } + + set args [lrange $args 1 end] + } + + set cmdp [_git_cmd [lindex $args 0]] + set args [lrange $args 1 end] + + return [_open_stdout_stderr [concat $opt $cmdp $args]] +} + +proc git_write {args} { + set opt [list |] + + while {1} { + switch -- [lindex $args 0] { + --nice { + _lappend_nice opt + } + + default { + break + } + + } + + set args [lrange $args 1 end] + } + + set cmdp [_git_cmd [lindex $args 0]] + set args [lrange $args 1 end] + + return [open [concat $opt $cmdp $args] w] +} + +proc sq {value} { + regsub -all ' $value "'\\''" value + return "'$value'" } proc load_current_branch {} { @@ -318,6 +518,17 @@ proc tk_optionMenu {w varName args} { return $m } +###################################################################### +## +## find git + +set _git [_which git] +if {$_git eq {}} { + catch {wm withdraw .} + error_popup "Cannot find git in PATH." + exit 1 +} + ###################################################################### ## ## version check @@ -336,8 +547,34 @@ if {![regsub {^git version } $_git_version {} _git_version]} { error_popup "Cannot parse Git version string:\n\n$_git_version" exit 1 } + +set _real_git_version $_git_version +regsub -- {-dirty$} $_git_version {} _git_version regsub {\.[0-9]+\.g[0-9a-f]+$} $_git_version {} _git_version regsub {\.rc[0-9]+$} $_git_version {} _git_version +regsub {\.GIT$} $_git_version {} _git_version + +if {![regexp {^[1-9]+(\.[0-9]+)+$} $_git_version]} { + catch {wm withdraw .} + if {[tk_messageBox \ + -icon warning \ + -type yesno \ + -default no \ + -title "[appname]: warning" \ + -message "Git version cannot be determined. + +$_git claims it is version '$_real_git_version'. + +[appname] requires at least Git 1.5.0 or later. + +Assume '$_real_git_version' is version 1.5.0? +"] eq {yes}} { + set _git_version 1.5.0 + } else { + exit 1 + } +} +unset _real_git_version proc git-version {args} { global _git_version @@ -566,12 +803,12 @@ proc rescan {after {honor_trustmtime 1}} { } else { set rescan_active 1 ui_status {Refreshing file status...} - set cmd [list git update-index] - lappend cmd -q - lappend cmd --unmerged - lappend cmd --ignore-missing - lappend cmd --refresh - set fd_rf [open "| $cmd" r] + set fd_rf [git_read update-index \ + -q \ + --unmerged \ + --ignore-missing \ + --refresh \ + ] fconfigure $fd_rf -blocking 0 -translation binary fileevent $fd_rf readable \ [list rescan_stage2 $fd_rf $after] @@ -587,8 +824,7 @@ proc rescan_stage2 {fd after} { close $fd } - set ls_others [list | git ls-files --others -z \ - --exclude-per-directory=.gitignore] + set ls_others [list --exclude-per-directory=.gitignore] set info_exclude [gitdir info exclude] if {[file readable $info_exclude]} { lappend ls_others "--exclude-from=$info_exclude" @@ -600,9 +836,9 @@ proc rescan_stage2 {fd after} { set rescan_active 3 ui_status {Scanning for modified files ...} - set fd_di [open "| git diff-index --cached -z [PARENT]" r] - set fd_df [open "| git diff-files -z" r] - set fd_lo [open $ls_others r] + set fd_di [git_read diff-index --cached -z [PARENT]] + set fd_df [git_read diff-files -z] + set fd_lo [eval git_read ls-files --others -z $ls_others] fconfigure $fd_di -blocking 0 -translation binary -encoding binary fconfigure $fd_df -blocking 0 -translation binary -encoding binary @@ -620,6 +856,7 @@ proc load_message {file} { if {[catch {set fd [open $f r]}]} { return 0 } + fconfigure $fd -eofchar {} set content [string trim [read $fd]] close $fd regsub -all -line {[ \r\t]+$} $content {} content @@ -1118,24 +1355,16 @@ proc incr_font_size {font {amt 1}} { set starting_gitk_msg {Starting gitk... please wait...} proc do_gitk {revs} { - global env starting_gitk_msg - # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. # - set cmd [list [info nameofexecutable]] - set exe [gitexec gitk] - lappend cmd $exe - if {$revs ne {}} { - append cmd { } - append cmd $revs - } - + set exe [file join [file dirname $::_git] gitk] + set cmd [list [info nameofexecutable] $exe] if {! [file exists $exe]} { error_popup "Unable to start gitk:\n\n$exe does not exist" } else { - eval exec $cmd & - ui_status $starting_gitk_msg + eval exec $cmd $revs & + ui_status $::starting_gitk_msg after 10000 { ui_ready $starting_gitk_msg } @@ -2355,12 +2584,21 @@ if {[is_enabled transport]} { # -- Only suggest a gc run if we are going to stay running. # if {[is_enabled multicommit]} { - set object_limit 2000 - if {[is_Windows]} {set object_limit 200} - regexp {^([0-9]+) objects,} [git count-objects] _junk objects_current + set object_limit 8 + if {[is_Windows]} { + set object_limit 1 + } + set objects_current [llength [glob \ + -directory [gitdir objects 42] \ + -nocomplain \ + -tails \ + -- \ + *]] if {$objects_current >= $object_limit} { + set objects_current [expr {$objects_current * 256}] + set object_limit [expr {$object_limit * 256}] if {[ask_popup \ - "This repository currently has $objects_current loose objects. + "This repository currently has approximately $objects_current loose objects. To maintain optimal performance it is strongly recommended that you compress the database when more than $object_limit loose objects exist. @@ -2368,8 +2606,11 @@ Compress the database now?"] eq yes} { do_gc } } - unset object_limit _junk objects_current + unset object_limit objects_current } lock_index begin-read +if {![winfo ismapped .]} { + wm deiconify . +} after 1 do_rescan