X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=scripts%2Fauxiliar%2Flily-git.tcl;h=8a90c48ba6b5592eb3c6f0ec100cd3c4c4061036;hb=47db9a3883d726ca53e2133a3b2298f78dd6a32e;hp=ada1f3bc906efcafb5c94b964d922b423d6d4645;hpb=8502d574eb1ef847f1f8eaee8fee0302d0b8e8b2;p=lilypond.git diff --git a/scripts/auxiliar/lily-git.tcl b/scripts/auxiliar/lily-git.tcl index ada1f3bc90..8a90c48ba6 100755 --- a/scripts/auxiliar/lily-git.tcl +++ b/scripts/auxiliar/lily-git.tcl @@ -1,295 +1,492 @@ #!/usr/bin/wish # GUI interface for common LilyPond git repository commands -# Copyright 2009 by Johannes Schindelin and Carl Sorensen +# Copyright 2009--2015 by Johannes Schindelin and Carl Sorensen # +package require Tk -set version 0.63 +set version 0.66 +proc get_environment_var {var_name default_value} { + global env + if [catch {set return_value $env($var_name)}] { + set return_value $default_value + } + return $return_value +} # set to 1 to set up for translation, to 0 for other set translator 0 +# If you have push access, set to 1, or use LILYPOND_GIT_PUSH +set default_push_access 0 +set push_access [get_environment_var "LILYPOND_GIT_PUSH" $default_push_access] + + +# location of lilypond git +set lily_dir [get_environment_var LILYPOND_GIT $env(HOME)/lilypond-git] + if {$translator == 1} { - set windowTitle \ - "LilyPond Translator's Git Interface version $version" - set updateButtonText "1. Update translation" - set initializeButtonText "1. Get translation" - set originHead "lilypond/translation" - set rebase 0 + set windowTitle \ + "LilyPond Translator's Git Interface version $version" + set updateButtonText "1. Update translation" + set initializeButtonText "1. Get translation" + set originHead "translation" + set pushHead $originHead + set rebase 0 } else { - set windowTitle \ - "LilyPond Contributor's Git Interface version $version" - set updateButtonText "1. Update source" - set initializeButtonText "1. Get source" - set originHead "master" - set rebase 1 + set windowTitle \ + "LilyPond Contributor's Git Interface version $version" + set updateButtonText "1. Update source" + set initializeButtonText "1. Get source" + set originHead "master" + set pushHead "staging" + set defaultBranch "dev/local_working" + set rebase 1 +} + + +## Submits the user data collected using the git config command + +proc submituserdata {} { + exec git config --global user.name "$::username" + exec git config --global user.email "$::useremail" + destroy .b + return 0 +} + +## Request name and email from user + +proc requestuserdata {} { + toplevel .b + grab .b + wm geometry .b -300-300 + wm title .b "Contributor details" + grid [frame .b.c ] -column 0 -row 0 -sticky nwes + grid columnconfigure . 0 -weight 1; grid rowconfigure . 0 -weight 1 + + grid [entry .b.c.username -width 20 -textvariable username] -column 2 -row 2 -sticky we + grid [entry .b.c.useremail -width 20 -textvariable useremail] -column 2 -row 3 -sticky we + grid [button .b.c.submituserdata -text "Submit" -command submituserdata] -column 2 -row 4 + + grid [label .b.c.explbl -text "Please enter your name and email for future commits:"] -column 1 -row 1 -columnspan 3 -sticky we + grid [label .b.c.nmlbl -text "Name:"] -column 1 -row 2 -sticky w + grid [label .b.c.emlbl -text "Email:"] -column 1 -row 3 -sticky w + + foreach w [winfo children .b.c] {grid configure $w -padx 5 -pady 5} + focus .b.c.username + bind .b {submituserdata} +} + +## Checks the user's global .gitconfig for name and email and executes requestuserdata if either is not found + +if {![file exists "$env(HOME)/.gitconfig"]} { + set fileholder [open "$env(HOME)/.gitconfig" a+] +} else { + set fileholder [open "$env(HOME)/.gitconfig" r] } -package require Tk + +set usercheck [split [read $fileholder] "\n"] +close $fileholder +if {![regexp "name" $usercheck] || ![regexp "email" $usercheck]} then { + requestuserdata + tkwait window .b +} + +## Entry limit routine from jeff at hobbs org, downloaded from +## http://www.purl.org/net/hobbs/tcl/tclet/entrylimit.html + +## For those who aren't using Tk4 with these, make a bell noop: +if [string match {} [info commands bell]] { proc bell args {} } + +proc forceLen {len name el op} { + global $name ${name}_len + if [string comp $el {}] { + set old ${name}_len\($el) + set name $name\($el) + } else { + set old ${name}_len + } + if {[string length [set $name]] > $len} { + set $name [set $old] + bell; + return + } + set $old [set $name] +} + +## Here is a wish example to use the routines. Remember that with +## write traces, a valid value must be set for each variable both +## before AND after the trace is established. + +## The order must be: +## 1) variable init +## 1) textvariable specification +## 3) set trace +## 4) variable reinit + +set commit_header {} +trace variable commit_header w {forceLen 50} +set commit_header {} + + +## End of entry limit code + # Helper functions -set lily_dir $env(HOME)/lilypond-git -if {[file exists $lily_dir]} { - cd $lily_dir +proc add_working_branch {} { + global originHead + global workingBranch + git checkout $originHead + git branch -f $workingBranch } + set abort_dir "./aborted_edits" proc write_to_output {s} { - .output.text insert insert $s - .output.text see end + .output.text insert insert $s + .output.text see end } proc write_file_to_output {f} { - if {[eof $f]} { - global git_command - fconfigure $f -blocking true - if {[catch {close $f} err]} { - tk_messageBox -type ok -message \ - "Command returned an error: $err\n\nCheck output text for details" - } - unset git_command - } else { - write_to_output [read $f 24] - } + if {[eof $f]} { + global git_command + fconfigure $f -blocking true + if {[catch {close $f} err]} { + tk_messageBox -type ok -message \ + "Command returned an error: $err\n\nCheck output text for details" + } + unset git_command + } else { + write_to_output [read $f 24] + } } proc git {args} { - global lily_dir git_command - set git_command [linsert $args 0 "|git" "--git-dir=$lily_dir/.git"] - set git_command "$git_command 2>@1" - .output.text insert end "$git_command\n" - set git [open $git_command r] - fconfigure $git -blocking false - fileevent $git readable [list write_file_to_output $git] - vwait git_command + global lily_dir git_command + set git_command [linsert $args 0 "|git" "--git-dir=$lily_dir/.git"] + set git_command "$git_command 2>@1" + .output.text insert end "$git_command\n" + set git [open $git_command r] + fconfigure $git -blocking false + fileevent $git readable [list write_file_to_output $git] + vwait git_command } proc config {args} { - global lily_dir - set p [open [linsert $args 0 "|git" --git-dir=$lily_dir/.git config] r] - set result [regsub "\n\$" [read $p] ""] - if {[catch {close $p} err]} { - tk_messageBox -type ok -message "config failed: $err" - } - return $result + global lily_dir + set p [open [linsert $args 0 "|git" --git-dir=$lily_dir/.git config] r] + set result [regsub "\n\$" [read $p] ""] + if {[catch {close $p} err]} { + tk_messageBox -type ok -message "config failed: $err" + } + return $result } proc config_quiet {args} { - global lily_dir - set p [open [linsert $args 0 "|git" --git-dir=$lily_dir/.git config] r] - set result [regsub "\n\$" [read $p] ""] - if {[catch {close $p} err]} { - set result "" - } - return $result + global lily_dir + set p [open [linsert $args 0 "|git" --git-dir=$lily_dir/.git config] r] + set result [regsub "\n\$" [read $p] ""] + if {[catch {close $p} err]} { + set result "" + } + return $result } proc update_lilypond_rebase {} { - update_lilypond 1 + update_lilypond 1 } proc commit {} { - global commit_message - global commit_canceled - set commit_canceled 0 - get_commit_message - tkwait visibility .commitMessage - tkwait window .commitMessage - if {$commit_canceled != 1} { - if {$commit_message == ""} { - tk_messageBox -message "You must enter a commit message!" \ - -type ok -icon error - } else { - git commit -a -m $commit_message - git rebase --whitespace=fix HEAD^ - set commit_message "2 + global commit_message + global commit_canceled + set commit_canceled 0 + get_commit_message + tkwait visibility .commitMessage + tkwait window .commitMessage + if {$commit_canceled != 1} { + if {$commit_message == ""} { + tk_messageBox -message "You must enter a commit message!" \ + -type ok -icon error + } else { + git commit -a -m $commit_message + git rebase --whitespace=fix HEAD^ + set commit_message "" + } } - } } proc commit_amend {} { - git commit -a --amend -C HEAD - git rebase --whitespace=fix HEAD^ + git commit -a --amend -C HEAD + git rebase --whitespace=fix HEAD^ } proc update_lilypond_norebase {} { - update_lilypond 0 + update_lilypond 0 } proc update_lilypond_with_rebase {} { - global rebase - update_lilypond $rebase + global rebase + update_lilypond $rebase } proc update_lilypond {rebase} { - global lily_dir - global originHead - global translator - . config -cursor watch - if {![file exists $lily_dir]} { - write_to_output "Cloning LilyPond (this can take some time) ...\n" - file mkdir $lily_dir - cd $lily_dir - git init - git config core.bare false - git remote add -t $originHead \ - origin git://git.sv.gnu.org/lilypond.git - if {$translator == 1} { - git fetch - } else { - git fetch --depth 1 - } - git reset --hard origin/$originHead - git config branch.$originHead.remote origin - git config branch.$originHead.merge refs/heads/$originHead - .buttons.commitFrame.commit configure -state normal - .buttons.commitFrame.amend configure -state normal - .buttons.update configure -text buttonUpdateText - .buttons.patch configure -state normal - .buttons.panic configure -state normal - toggle_rebase - } else { - write_to_output "Updating LilyPond...\n" - git fetch origin - if {$rebase} { - git rebase origin/$originHead - } else { - git merge origin/$originHead - } - } - write_to_output "Done.\n" - . config -cursor "" + global lily_dir + global originHead + global pushHead + global translator + global workingBranch + global push_access + . config -cursor watch + if {![file exists $lily_dir]} { + write_to_output "Cloning LilyPond (this can take some time) ...\n" + file mkdir $lily_dir + cd $lily_dir + git init + git config core.bare false + git remote add -t $originHead \ + origin git://git.sv.gnu.org/lilypond.git + git fetch + git reset --hard origin/$originHead + git config branch.$originHead.remote origin + git config branch.$originHead.merge refs/heads/$originHead + git checkout $originHead + if {$workingBranch != ""} { + add_working_branch + git checkout $workingBranch + } + .buttons.commitFrame.commit configure -state normal + .buttons.commitFrame.amend configure -state normal + .buttons.update configure -text buttonUpdateText + .buttons.patch configure -state normal + if {$push_access && !$translator} { + .buttons.push configure -state normal + } + .buttons.panic configure -state normal + toggle_rebase + } else { + write_to_output "Updating LilyPond...\n" + git fetch origin + if {$rebase} { + git rebase origin/$originHead $originHead + git rebase origin/$originHead $workingBranch + } else { + git merge origin/$originHead + } + } + write_to_output "Done.\n" + . config -cursor "" } proc patch_from_origin {} { - global rebase - make_patch_from_origin $rebase - if {![llength [glob -nocomplain 0*.patch]]} { - tk_messageBox -type ok -message \ - "No patches created; did you make a local commit?" - } + global rebase + make_patch_from_origin $rebase + if {![llength [glob -nocomplain 0*.patch]]} { + tk_messageBox -type ok -message \ + "No patches created; did you make a local commit?" + } } proc make_patch_from_origin {rebase} { - global lily_dir - global originHead - . config -cursor watch - update_lilypond $rebase - write_to_output "Creating patch...\n" - git format-patch origin/$originHead - write_to_output "Done.\n" - . config -cursor "" + global lily_dir + global originHead + . config -cursor watch + update_lilypond $rebase + write_to_output "Creating patch...\n" + git format-patch origin/$originHead + write_to_output "Done.\n" + . config -cursor "" +} + + +proc push_patch_to_staging {} { + global workingBranch + global pushHead + global git_log + global push_canceled + global log_text + global originHead + + git rebase $originHead $workingBranch + set staging_sha [exec git rev-parse ] + set head_sha [exec git rev-parse $workingBranch] + set log_error [catch {exec git --no-pager log {--pretty=format:%h : %an -- %s} --graph $originHead..$workingBranch} log_text] + if {$log_error == 0 && $log_text == ""} { + tk_messageBox -type ok -message "No changes in repository. Nothing to push." + } else { + get_git_log + tkwait visibility .gitLogWindow + tkwait window .gitLogWindow + if {$push_canceled == 0} { + git rebase origin/$pushHead $workingBranch~0 + git push origin HEAD:$pushHead + git checkout $workingBranch + } + } } proc abort_changes {} { - global abort_dir - global originHead - set answer [tk_messageBox -type okcancel \ - -message "This will copy all changed files to $abort_dir and reset the repository." \ - -default cancel] - switch -- $answer { - ok { - write_to_output "abort_dir: $abort_dir \n" - if {![file exists $abort_dir]} { - set return_code [exec mkdir $abort_dir] - } - set return_code [catch {exec git diff origin/$originHead} gitdiff] - set return_code [regexp {diff --git a/(\S*)} $gitdiff match modified_file] - while {$return_code != 0} { - write_to_output "Copying $modified_file to $abort_dir.\n" - set return_code [catch {exec cp $modified_file $abort_dir} result] - set return_code [regsub {diff --git a/(\S*)} $gitdiff "" gitdiff] - set return_code [regexp {diff --git a/(\S*)} $gitdiff match modified_file] - } - set return_code [git reset --hard origin/$originHead] - write_to_output "Repository reset. \n" + global abort_dir + global originHead + set answer [tk_messageBox -type okcancel \ + -message "This will copy all changed files to $abort_dir and reset the repository." \ + -default cancel] + switch -- $answer { + ok { + write_to_output "abort_dir: $abort_dir \n" + if {![file exists $abort_dir]} { + set return_code [exec mkdir $abort_dir] + } + set return_code [catch {exec git diff origin/$originHead} gitdiff] + set return_code [regexp {diff --git a/(\S*)} $gitdiff match modified_file] + while {$return_code != 0} { + write_to_output "Copying $modified_file to $abort_dir.\n" + set return_code [catch {exec cp $modified_file $abort_dir} result] + set return_code [regsub {diff --git a/(\S*)} $gitdiff "" gitdiff] + set return_code [regexp {diff --git a/(\S*)} $gitdiff match modified_file] + } + set return_code [git reset --hard origin/$originHead] + write_to_output "Repository reset. \n" + } } - } } proc toggle_rebase {} { - global rebase - global lily_dir - global originHead - global updateButtonText - global initializeButtonText - if {[file exists $lily_dir]} { - config --bool branch.$originHead.rebase $rebase - .buttons.update configure -text $updateButtonText - } else { - .buttons.update configure -text $initializeButtonText - } + global rebase + global lily_dir + global originHead + global updateButtonText + global initializeButtonText + if {[file exists $lily_dir]} { + config --bool branch.$originHead.rebase $rebase + .buttons.update configure -text $updateButtonText + } else { + .buttons.update configure -text $initializeButtonText + } } proc clear_rebase {} { - global rebase - set rebase 0 - toggle_rebase + global rebase + set rebase 0 + toggle_rebase } proc set_rebase {} { - global rebase - set rebase 1 - toggle_rebase + global rebase + set rebase 1 + toggle_rebase } proc commitMessageOK {} { - global commit_message - global commit_header - set commit_body [.commitMessage.bottomFrame.commit_body get 1.0 end] - set commit_message "$commit_header\n\n$commit_body" - destroy .commitMessage + global commit_message + global commit_header + set commit_body [.commitMessage.bottomFrame.commit_body get 1.0 end] + set commit_message "$commit_header\n\n$commit_body" + destroy .commitMessage } proc commitMessageCancel {} { - global commit_message - global commit_canceled - set commit_message "" - set commit_canceled 1 - destroy .commitMessage + global commit_message + global commit_canceled + set commit_message "" + set commit_canceled 1 + destroy .commitMessage +} + +proc pushContinue {} { + global push_canceled + set push_canceled = 0 + destroy .gitLogWindow +} + +proc pushCancel {} { + global push_canceled + set push_canceled 1 + destroy .gitLogWindow +} + + +# git log output window +proc get_git_log {} { + global log_text + toplevel .gitLogWindow + frame .gitLogWindow.messageFrame + + + text .gitLogWindow.messageFrame.message_body \ + -xscrollcommand [list .gitLogWindow.messageFrame.horizontal set] \ + -yscrollcommand [list .gitLogWindow.messageFrame.vertical set] \ + -width 60 -height 10 -relief solid -border 2 -wrap none + scrollbar .gitLogWindow.messageFrame.horizontal -orient h -command [list .gitLogWindow.messageFrame.message_body xview] + scrollbar .gitLogWindow.messageFrame.vertical -orient v -command [list .gitLogWindow.messageFrame.message_body yview] + + frame .gitLogWindow.messageFrame.leftFrame + label .gitLogWindow.messageFrame.leftFrame.label \ + -text "Log of commits in push:" + button .gitLogWindow.messageFrame.leftFrame.ok \ + -text Continue -default active -command pushContinue + button .gitLogWindow.messageFrame.leftFrame.cancel -text Cancel -default active \ + -command pushCancel + wm withdraw .gitLogWindow + wm title .gitLogWindow "Commits to be pushed" + + pack .gitLogWindow.messageFrame.leftFrame.label + pack .gitLogWindow.messageFrame.leftFrame.ok + pack .gitLogWindow.messageFrame.leftFrame.cancel + + pack .gitLogWindow.messageFrame.leftFrame -side left + + pack .gitLogWindow.messageFrame.horizontal -side bottom -fill x + pack .gitLogWindow.messageFrame.vertical -side right -fill y + pack .gitLogWindow.messageFrame.message_body -expand true -anchor nw -fill both + pack .gitLogWindow.messageFrame + + wm transient .gitLogWindow . + wm deiconify .gitLogWindow + .gitLogWindow.messageFrame.message_body insert insert $log_text } # Commit message input window proc get_commit_message {} { - global commit_header - set commit_header "" - toplevel .commitMessage - frame .commitMessage.topFrame - label .commitMessage.topFrame.label \ - -text "Enter commit message header:\n(50 chars max = width of box)" - entry .commitMessage.topFrame.commit_header \ - -width 50 -relief solid -border 2 -textvariable commit_header - pack .commitMessage.topFrame.label -side left - pack .commitMessage.topFrame.commit_header -side left - - frame .commitMessage.bottomFrame - text .commitMessage.bottomFrame.commit_body \ - -width 75 -height 10 -relief solid -border 2 -wrap none - - frame .commitMessage.bottomFrame.leftFrame - label .commitMessage.bottomFrame.leftFrame.label \ - -text "Enter commit message body:\n(No limit -- Full description)" - button .commitMessage.bottomFrame.leftFrame.ok \ - -text OK -default active -command commitMessageOK - button .commitMessage.bottomFrame.leftFrame.cancel -text Cancel -default active \ - -command commitMessageCancel - wm withdraw .commitMessage - wm title .commitMessage "Git Commit Message" - - pack .commitMessage.bottomFrame.leftFrame.label - pack .commitMessage.bottomFrame.leftFrame.ok - pack .commitMessage.bottomFrame.leftFrame.cancel - - pack .commitMessage.bottomFrame.leftFrame -side left - pack .commitMessage.bottomFrame.commit_body -side left - - pack .commitMessage.topFrame - pack .commitMessage.bottomFrame - - wm transient .commitMessage . - wm deiconify .commitMessage + global commit_header + set commit_header "" + toplevel .commitMessage + frame .commitMessage.topFrame + label .commitMessage.topFrame.label \ + -text "Enter commit message header:\n(50 chars max = width of box)" + entry .commitMessage.topFrame.commit_header \ + -width 50 -relief solid -border 2 -textvariable commit_header + pack .commitMessage.topFrame.label -side left + pack .commitMessage.topFrame.commit_header -side left + + frame .commitMessage.bottomFrame + text .commitMessage.bottomFrame.commit_body \ + -width 75 -height 10 -relief solid -border 2 -wrap none + + frame .commitMessage.bottomFrame.leftFrame + label .commitMessage.bottomFrame.leftFrame.label \ + -text "Enter commit message body:\n(No limit -- Full description)" + button .commitMessage.bottomFrame.leftFrame.ok \ + -text OK -default active -command commitMessageOK + button .commitMessage.bottomFrame.leftFrame.cancel -text Cancel -default active \ + -command commitMessageCancel + wm withdraw .commitMessage + wm title .commitMessage "Git Commit Message" + + pack .commitMessage.bottomFrame.leftFrame.label + pack .commitMessage.bottomFrame.leftFrame.ok + pack .commitMessage.bottomFrame.leftFrame.cancel + + pack .commitMessage.bottomFrame.leftFrame -side left + pack .commitMessage.bottomFrame.commit_body -side left + + pack .commitMessage.topFrame + pack .commitMessage.bottomFrame + + wm transient .commitMessage . + wm deiconify .commitMessage } @@ -308,20 +505,27 @@ pack .buttons.commitFrame.commit -fill x pack .buttons.commitFrame.amend -fill x button .buttons.update -text $updateButtonText \ - -command update_lilypond_with_rebase + -command update_lilypond_with_rebase button .buttons.patch -text "3. Make patch set" \ - -command patch_from_origin + -command patch_from_origin +if {$push_access && !$translator} { + button .buttons.push -text "4. Push patch to staging" \ + -command push_patch_to_staging +} toggle_rebase button .buttons.panic -text "Abort changes -- Reset to origin" \ - -command abort_changes -fg Blue -bg Red + -command abort_changes -fg Blue -bg Red label .buttons.spacer -text " " if {![file exists $lily_dir]} { - .buttons.update configure \ - -text $initializeButtonText - .buttons.commitFrame.commit configure -state disabled - .buttons.commitFrame.amend configure -state disabled - .buttons.patch configure -state disabled - .buttons.panic configure -state disabled + .buttons.update configure \ + -text $initializeButtonText + .buttons.commitFrame.commit configure -state disabled + .buttons.commitFrame.amend configure -state disabled + .buttons.patch configure -state disabled + if {$push_access} { + .buttons.push configure -state disabled + } + .buttons.panic configure -state disabled } # Operating buttons @@ -329,6 +533,9 @@ if {![file exists $lily_dir]} { pack .buttons.update -side left pack .buttons.commitFrame -side left pack .buttons.patch -side left +if {$push_access} { + pack .buttons.push -side left +} pack .buttons.spacer -side left pack .buttons.panic -side right @@ -338,9 +545,9 @@ pack .buttons.panic -side right panedwindow .output label .output.label -text "Command output:" text .output.text -width 80 -height 15 \ - -xscrollcommand [list .output.horizontal set] \ - -yscrollcommand [list .output.vertical set] \ - -relief solid -border 2 + -xscrollcommand [list .output.horizontal set] \ + -yscrollcommand [list .output.vertical set] \ + -relief solid -border 2 scrollbar .output.horizontal -orient h -command [list .output.text xview] scrollbar .output.vertical -orient v -command [list .output.text yview] pack .output.label -side left @@ -351,5 +558,19 @@ pack .output.text -expand true -anchor nw -fill both pack .buttons pack .output -#grid .buttons -row 2 -column 1 -#grid .output -row 3 -column 1 -sticky "w" +# set working branch and push branch +set workingBranch [get_environment_var LILYPOND_BRANCH $defaultBranch] + +puts "\nworkingBranch $workingBranch\n" + +if {[file exists $lily_dir]} { + cd $lily_dir + set branchList [exec git branch] + if { $workingBranch != ""} { + if {![regexp $workingBranch $branchList]} { + add_working_branch + } + git checkout $workingBranch + } +} +