3 # GUI interface for common LilyPond git repository commands
4 # Copyright 2009--2010 by Johannes Schindelin and Carl Sorensen
9 # set to 1 to set up for translation, to 0 for other
12 # location of lilypond git
13 set lily_dir $env(HOME)/lilypond-git
15 if {$translator == 1} {
17 "LilyPond Translator's Git Interface version $version"
18 set updateButtonText "1. Update translation"
19 set initializeButtonText "1. Get translation"
20 set originHead "lilypond/translation"
24 "LilyPond Contributor's Git Interface version $version"
25 set updateButtonText "1. Update source"
26 set initializeButtonText "1. Get source"
27 set originHead "master"
32 ## Submits the user data collected using the git config command
34 proc submituserdata {} {
35 exec git config --global user.name "$::username"
36 exec git config --global user.email "$::useremail"
41 ## Request name and email from user
43 proc requestuserdata {} {
46 wm geometry .b -300-300
47 wm title .b "Contributor details"
48 grid [frame .b.c ] -column 0 -row 0 -sticky nwes
49 grid columnconfigure . 0 -weight 1; grid rowconfigure . 0 -weight 1
51 grid [entry .b.c.username -width 20 -textvariable username] -column 2 -row 2 -sticky we
52 grid [entry .b.c.useremail -width 20 -textvariable useremail] -column 2 -row 3 -sticky we
53 grid [button .b.c.submituserdata -text "Submit" -command submituserdata] -column 2 -row 4
55 grid [label .b.c.explbl -text "Please enter your name and email for future commits:"] -column 1 -row 1 -columnspan 3 -sticky we
56 grid [label .b.c.nmlbl -text "Name:"] -column 1 -row 2 -sticky w
57 grid [label .b.c.emlbl -text "Email:"] -column 1 -row 3 -sticky w
59 foreach w [winfo children .b.c] {grid configure $w -padx 5 -pady 5}
61 bind .b <Return> {submituserdata}
64 ## Checks the user's global .gitconfig for name and email and executes requestuserdata if either is not found
66 if {![file exists "$env(HOME)/.gitconfig"]} {set fileholder [open "$env(HOME)/.gitconfig" a+]} else {
67 set fileholder [open "$env(HOME)/.gitconfig" r]}
69 set usercheck [split [read $fileholder] "\n"]
71 if {![regexp "name" $usercheck] || ![regexp "email" $usercheck]} then {
76 ## Entry limit routine from jeff at hobbs org, downloaded from
77 ## http://www.purl.org/net/hobbs/tcl/tclet/entrylimit.html
79 ## For those who aren't using Tk4 with these, make a bell noop:
80 if [string match {} [info commands bell]] { proc bell args {} }
82 proc forceLen {len name el op} {
83 global $name ${name}_len
84 if [string comp $el {}] {
85 set old ${name}_len\($el)
87 } else { set old ${name}_len }
88 if {[string length [set $name]] > $len} {
95 ## Here is a wish example to use the routines. Remember that with
96 ## write traces, a valid value must be set for each variable both
97 ## before AND after the trace is established.
101 ## 1) textvariable specification
103 ## 4) variable reinit
106 trace variable commit_header w {forceLen 50}
110 ## End of entry limit code
115 if {[file exists $lily_dir]} {
119 set abort_dir "./aborted_edits"
121 proc write_to_output {s} {
122 .output.text insert insert $s
126 proc write_file_to_output {f} {
129 fconfigure $f -blocking true
130 if {[catch {close $f} err]} {
131 tk_messageBox -type ok -message \
132 "Command returned an error: $err\n\nCheck output text for details"
136 write_to_output [read $f 24]
141 global lily_dir git_command
142 set git_command [linsert $args 0 "|git" "--git-dir=$lily_dir/.git"]
143 set git_command "$git_command 2>@1"
144 .output.text insert end "$git_command\n"
145 set git [open $git_command r]
146 fconfigure $git -blocking false
147 fileevent $git readable [list write_file_to_output $git]
153 set p [open [linsert $args 0 "|git" --git-dir=$lily_dir/.git config] r]
154 set result [regsub "\n\$" [read $p] ""]
155 if {[catch {close $p} err]} {
156 tk_messageBox -type ok -message "config failed: $err"
161 proc config_quiet {args} {
163 set p [open [linsert $args 0 "|git" --git-dir=$lily_dir/.git config] r]
164 set result [regsub "\n\$" [read $p] ""]
165 if {[catch {close $p} err]} {
171 proc update_lilypond_rebase {} {
176 global commit_message
177 global commit_canceled
178 set commit_canceled 0
180 tkwait visibility .commitMessage
181 tkwait window .commitMessage
182 if {$commit_canceled != 1} {
183 if {$commit_message == ""} {
184 tk_messageBox -message "You must enter a commit message!" \
187 git commit -a -m $commit_message
188 git rebase --whitespace=fix HEAD^
189 set commit_message ""
194 proc commit_amend {} {
195 git commit -a --amend -C HEAD
196 git rebase --whitespace=fix HEAD^
199 proc update_lilypond_norebase {} {
203 proc update_lilypond_with_rebase {} {
205 update_lilypond $rebase
208 proc update_lilypond {rebase} {
212 . config -cursor watch
213 if {![file exists $lily_dir]} {
214 write_to_output "Cloning LilyPond (this can take some time) ...\n"
218 git config core.bare false
219 git remote add -t $originHead \
220 origin git://git.sv.gnu.org/lilypond.git
221 if {$translator == 1} {
226 git reset --hard origin/$originHead
227 git config branch.$originHead.remote origin
228 git config branch.$originHead.merge refs/heads/$originHead
229 .buttons.commitFrame.commit configure -state normal
230 .buttons.commitFrame.amend configure -state normal
231 .buttons.update configure -text buttonUpdateText
232 .buttons.patch configure -state normal
233 .buttons.panic configure -state normal
236 write_to_output "Updating LilyPond...\n"
239 git rebase origin/$originHead
241 git merge origin/$originHead
244 write_to_output "Done.\n"
248 proc patch_from_origin {} {
250 make_patch_from_origin $rebase
251 if {![llength [glob -nocomplain 0*.patch]]} {
252 tk_messageBox -type ok -message \
253 "No patches created; did you make a local commit?"
257 proc make_patch_from_origin {rebase} {
260 . config -cursor watch
261 update_lilypond $rebase
262 write_to_output "Creating patch...\n"
263 git format-patch origin/$originHead
264 write_to_output "Done.\n"
268 proc abort_changes {} {
271 set answer [tk_messageBox -type okcancel \
272 -message "This will copy all changed files to $abort_dir and reset the repository." \
276 write_to_output "abort_dir: $abort_dir \n"
277 if {![file exists $abort_dir]} {
278 set return_code [exec mkdir $abort_dir]
280 set return_code [catch {exec git diff origin/$originHead} gitdiff]
281 set return_code [regexp {diff --git a/(\S*)} $gitdiff match modified_file]
282 while {$return_code != 0} {
283 write_to_output "Copying $modified_file to $abort_dir.\n"
284 set return_code [catch {exec cp $modified_file $abort_dir} result]
285 set return_code [regsub {diff --git a/(\S*)} $gitdiff "" gitdiff]
286 set return_code [regexp {diff --git a/(\S*)} $gitdiff match modified_file]
288 set return_code [git reset --hard origin/$originHead]
289 write_to_output "Repository reset. \n"
294 proc toggle_rebase {} {
298 global updateButtonText
299 global initializeButtonText
300 if {[file exists $lily_dir]} {
301 config --bool branch.$originHead.rebase $rebase
302 .buttons.update configure -text $updateButtonText
304 .buttons.update configure -text $initializeButtonText
308 proc clear_rebase {} {
320 proc commitMessageOK {} {
321 global commit_message
323 set commit_body [.commitMessage.bottomFrame.commit_body get 1.0 end]
324 set commit_message "$commit_header\n\n$commit_body"
325 destroy .commitMessage
328 proc commitMessageCancel {} {
329 global commit_message
330 global commit_canceled
331 set commit_message ""
332 set commit_canceled 1
333 destroy .commitMessage
337 # Commit message input window
338 proc get_commit_message {} {
341 toplevel .commitMessage
342 frame .commitMessage.topFrame
343 label .commitMessage.topFrame.label \
344 -text "Enter commit message header:\n(50 chars max = width of box)"
345 entry .commitMessage.topFrame.commit_header \
346 -width 50 -relief solid -border 2 -textvariable commit_header
347 pack .commitMessage.topFrame.label -side left
348 pack .commitMessage.topFrame.commit_header -side left
350 frame .commitMessage.bottomFrame
351 text .commitMessage.bottomFrame.commit_body \
352 -width 75 -height 10 -relief solid -border 2 -wrap none
354 frame .commitMessage.bottomFrame.leftFrame
355 label .commitMessage.bottomFrame.leftFrame.label \
356 -text "Enter commit message body:\n(No limit -- Full description)"
357 button .commitMessage.bottomFrame.leftFrame.ok \
358 -text OK -default active -command commitMessageOK
359 button .commitMessage.bottomFrame.leftFrame.cancel -text Cancel -default active \
360 -command commitMessageCancel
361 wm withdraw .commitMessage
362 wm title .commitMessage "Git Commit Message"
364 pack .commitMessage.bottomFrame.leftFrame.label
365 pack .commitMessage.bottomFrame.leftFrame.ok
366 pack .commitMessage.bottomFrame.leftFrame.cancel
368 pack .commitMessage.bottomFrame.leftFrame -side left
369 pack .commitMessage.bottomFrame.commit_body -side left
371 pack .commitMessage.topFrame
372 pack .commitMessage.bottomFrame
374 wm transient .commitMessage .
375 wm deiconify .commitMessage
381 wm title . $windowTitle
387 frame .buttons.commitFrame
388 button .buttons.commitFrame.commit -text "2a. New local commit" -command commit
389 button .buttons.commitFrame.amend -text "2b. Amend previous commit" -command commit_amend
390 pack .buttons.commitFrame.commit -fill x
391 pack .buttons.commitFrame.amend -fill x
393 button .buttons.update -text $updateButtonText \
394 -command update_lilypond_with_rebase
395 button .buttons.patch -text "3. Make patch set" \
396 -command patch_from_origin
398 button .buttons.panic -text "Abort changes -- Reset to origin" \
399 -command abort_changes -fg Blue -bg Red
400 label .buttons.spacer -text " "
401 if {![file exists $lily_dir]} {
402 .buttons.update configure \
403 -text $initializeButtonText
404 .buttons.commitFrame.commit configure -state disabled
405 .buttons.commitFrame.amend configure -state disabled
406 .buttons.patch configure -state disabled
407 .buttons.panic configure -state disabled
412 pack .buttons.update -side left
413 pack .buttons.commitFrame -side left
414 pack .buttons.patch -side left
415 pack .buttons.spacer -side left
416 pack .buttons.panic -side right
422 label .output.label -text "Command output:"
423 text .output.text -width 80 -height 15 \
424 -xscrollcommand [list .output.horizontal set] \
425 -yscrollcommand [list .output.vertical set] \
426 -relief solid -border 2
427 scrollbar .output.horizontal -orient h -command [list .output.text xview]
428 scrollbar .output.vertical -orient v -command [list .output.text yview]
429 pack .output.label -side left
430 pack .output.horizontal -side bottom -fill x
431 pack .output.vertical -side right -fill y
432 pack .output.text -expand true -anchor nw -fill both
437 #grid .buttons -row 2 -column 1
438 #grid .output -row 3 -column 1 -sticky "w"