]> git.donarmstrong.com Git - lilypond.git/blob - scripts/auxiliar/lily-git.tcl
Merge branch 'lilypond/translation' of ssh://git.sv.gnu.org/srv/git/lilypond
[lilypond.git] / scripts / auxiliar / lily-git.tcl
1 #!/usr/bin/wish
2
3 # GUI interface for common LilyPond git repository commands
4 # Copyright 2009 by Johannes Schindelin and Carl Sorensen
5 #
6
7 set version 0.64
8
9 # set to 1 to set up for translation, to 0 for other
10 set translator 0
11
12 if {$translator == 1} {
13         set windowTitle \
14           "LilyPond Translator's Git Interface version $version"
15         set updateButtonText "1. Update translation"
16         set initializeButtonText "1. Get translation"
17         set originHead "lilypond/translation"
18         set rebase 0
19 } else {
20         set windowTitle \
21           "LilyPond Contributor's Git Interface version $version"
22         set updateButtonText "1. Update source"
23         set initializeButtonText "1. Get source"
24         set originHead "master"
25         set rebase 1
26 }
27 package require Tk
28
29
30 ##  Entry limit routine from jeff at hobbs org, downloaded from
31 ##  http://www.purl.org/net/hobbs/tcl/tclet/entrylimit.html
32
33 ## For those who aren't using Tk4 with these, make a bell noop:
34 if [string match {} [info commands bell]] { proc bell args {} }
35
36 proc forceLen {len name el op} {
37     global $name ${name}_len
38     if [string comp $el {}] {
39         set old  ${name}_len\($el)
40         set name $name\($el)
41     } else { set old ${name}_len }
42     if {[string length [set $name]] > $len} {
43         set $name [set $old]
44         bell; return
45     }
46     set $old [set $name]
47 }
48
49 ## Here is a wish example to use the routines.  Remember that with
50 ## write traces, a valid value must be set for each variable both
51 ## before AND after the trace is established.
52
53 ## The order must be:
54 ## 1) variable init
55 ## 1) textvariable specification
56 ## 3) set trace
57 ## 4) variable reinit
58
59 set commit_header {}
60 trace variable commit_header w {forceLen 50}
61 set commit_header {}
62
63
64 ## End of entry limit code
65
66
67 # Helper functions
68
69 set lily_dir $env(HOME)/lilypond-git
70 if {[file exists $lily_dir]} {
71         cd $lily_dir
72 }
73
74 set abort_dir "./aborted_edits"
75
76 proc write_to_output {s} {
77         .output.text insert insert $s
78         .output.text see end
79 }
80
81 proc write_file_to_output {f} {
82         if {[eof $f]} {
83                 global git_command
84                 fconfigure $f -blocking true
85                 if {[catch {close $f} err]} {
86                         tk_messageBox -type ok -message \
87                           "Command returned an error: $err\n\nCheck output text for details"
88                 }
89                 unset git_command
90         } else {
91                 write_to_output [read $f 24]
92         }
93 }
94
95 proc git {args} {
96         global lily_dir git_command
97         set git_command [linsert $args 0 "|git" "--git-dir=$lily_dir/.git"]
98         set git_command "$git_command 2>@1"
99         .output.text insert end "$git_command\n"
100         set git [open $git_command r]
101         fconfigure $git -blocking false
102         fileevent $git readable [list write_file_to_output $git]
103         vwait git_command
104 }
105
106 proc config {args} {
107         global lily_dir
108         set p [open [linsert $args 0 "|git" --git-dir=$lily_dir/.git config] r]
109         set result [regsub "\n\$" [read $p] ""]
110         if {[catch {close $p} err]} {
111                 tk_messageBox -type ok -message "config failed: $err"
112         }
113         return $result
114 }
115
116 proc config_quiet {args} {
117         global lily_dir
118         set p [open [linsert $args 0 "|git" --git-dir=$lily_dir/.git config] r]
119         set result [regsub "\n\$" [read $p] ""]
120         if {[catch {close $p} err]} {
121                 set result ""
122         }
123         return $result
124 }
125
126 proc update_lilypond_rebase {} {
127   update_lilypond 1
128 }
129
130 proc commit {} {
131   global commit_message
132   global commit_canceled
133   set commit_canceled 0
134   get_commit_message
135   tkwait visibility .commitMessage
136   tkwait window .commitMessage
137   if {$commit_canceled != 1} {
138     if {$commit_message == ""} {
139       tk_messageBox -message "You must enter a commit message!" \
140       -type ok -icon error
141     } else {
142       git commit -a -m $commit_message
143       git rebase --whitespace=fix HEAD^
144       set commit_message ""
145     }
146   }
147 }
148
149 proc commit_amend {} {
150   git commit -a --amend -C HEAD
151   git rebase --whitespace=fix HEAD^
152 }
153
154 proc update_lilypond_norebase {} {
155   update_lilypond 0
156 }
157
158 proc update_lilypond_with_rebase {} {
159   global rebase
160   update_lilypond $rebase
161 }
162
163 proc update_lilypond {rebase} {
164         global lily_dir
165         global originHead
166         global translator
167         . config -cursor watch
168         if {![file exists $lily_dir]} {
169                 write_to_output "Cloning LilyPond (this can take some time) ...\n"
170                 file mkdir $lily_dir
171                 cd $lily_dir
172                 git init
173                 git config core.bare false
174                 git remote add -t $originHead \
175                         origin git://git.sv.gnu.org/lilypond.git
176                 if {$translator == 1} {
177                   git fetch
178                 } else {
179                   git fetch --depth 1
180                 }
181                 git reset --hard origin/$originHead
182                 git config branch.$originHead.remote origin
183                 git config branch.$originHead.merge refs/heads/$originHead
184                 .buttons.commitFrame.commit configure -state normal
185                 .buttons.commitFrame.amend configure -state normal
186                 .buttons.update configure -text buttonUpdateText
187                 .buttons.patch configure -state normal
188                 .buttons.panic configure -state normal
189                 toggle_rebase
190         } else {
191                 write_to_output "Updating LilyPond...\n"
192                 git fetch origin
193                 if {$rebase} {
194                         git rebase origin/$originHead
195                 } else {
196                         git merge origin/$originHead
197                 }
198         }
199         write_to_output "Done.\n"
200         . config -cursor ""
201 }
202
203 proc patch_from_origin {} {
204   global rebase
205   make_patch_from_origin $rebase
206   if {![llength [glob -nocomplain 0*.patch]]} {
207         tk_messageBox -type ok -message \
208                 "No patches created; did you make a local commit?"
209   }
210 }
211
212 proc make_patch_from_origin {rebase} {
213   global lily_dir
214   global originHead
215   . config -cursor watch
216   update_lilypond $rebase
217   write_to_output "Creating patch...\n"
218   git format-patch origin/$originHead
219   write_to_output "Done.\n"
220   . config -cursor ""
221 }
222
223 proc abort_changes {} {
224   global abort_dir
225   global originHead
226   set answer [tk_messageBox -type okcancel \
227                -message "This will copy all changed files to $abort_dir and reset the repository." \
228                -default cancel]
229   switch -- $answer {
230     ok {
231       write_to_output "abort_dir: $abort_dir \n"
232       if {![file exists $abort_dir]} {
233         set return_code [exec mkdir $abort_dir]
234       }
235       set return_code [catch {exec git diff origin/$originHead} gitdiff]
236       set return_code [regexp {diff --git a/(\S*)} $gitdiff match modified_file]
237       while {$return_code != 0} {
238         write_to_output "Copying $modified_file to $abort_dir.\n"
239         set return_code [catch {exec cp $modified_file $abort_dir} result]
240         set return_code [regsub {diff --git a/(\S*)} $gitdiff "" gitdiff]
241         set return_code [regexp {diff --git a/(\S*)} $gitdiff match modified_file]
242       }
243       set return_code [git reset --hard origin/$originHead]
244       write_to_output "Repository reset. \n"
245     }
246   }
247 }
248
249 proc toggle_rebase {} {
250         global rebase
251         global lily_dir
252         global originHead
253         global updateButtonText
254         global initializeButtonText
255         if {[file exists $lily_dir]} {
256           config --bool branch.$originHead.rebase $rebase
257           .buttons.update configure -text $updateButtonText
258         } else {
259           .buttons.update configure -text $initializeButtonText
260         }
261 }
262
263 proc clear_rebase {} {
264   global rebase
265   set rebase 0
266   toggle_rebase
267 }
268
269 proc set_rebase {} {
270   global rebase
271   set rebase 1
272   toggle_rebase
273 }
274
275 proc commitMessageOK {} {
276   global commit_message
277   global commit_header
278   set commit_body [.commitMessage.bottomFrame.commit_body get 1.0 end]
279   set commit_message "$commit_header\n\n$commit_body"
280   destroy .commitMessage
281 }
282
283 proc commitMessageCancel {} {
284   global commit_message
285   global commit_canceled
286   set commit_message ""
287   set commit_canceled 1
288   destroy .commitMessage
289 }
290
291
292 # Commit message input window
293 proc get_commit_message {} {
294   global commit_header
295   set commit_header ""
296   toplevel .commitMessage
297   frame .commitMessage.topFrame
298   label .commitMessage.topFrame.label \
299       -text "Enter commit message header:\n(50 chars max = width of box)"
300   entry .commitMessage.topFrame.commit_header \
301             -width 50 -relief solid -border 2 -textvariable commit_header
302   pack   .commitMessage.topFrame.label -side left
303   pack   .commitMessage.topFrame.commit_header -side left
304
305   frame  .commitMessage.bottomFrame
306   text   .commitMessage.bottomFrame.commit_body \
307             -width 75  -height 10 -relief solid -border 2 -wrap none
308
309   frame .commitMessage.bottomFrame.leftFrame
310   label .commitMessage.bottomFrame.leftFrame.label \
311       -text "Enter commit message body:\n(No limit -- Full description)"
312   button .commitMessage.bottomFrame.leftFrame.ok \
313            -text OK -default active -command commitMessageOK
314   button .commitMessage.bottomFrame.leftFrame.cancel -text Cancel -default active \
315           -command commitMessageCancel
316   wm withdraw .commitMessage
317   wm title .commitMessage "Git Commit Message"
318
319   pack .commitMessage.bottomFrame.leftFrame.label
320   pack .commitMessage.bottomFrame.leftFrame.ok
321   pack .commitMessage.bottomFrame.leftFrame.cancel
322
323   pack .commitMessage.bottomFrame.leftFrame -side left
324   pack .commitMessage.bottomFrame.commit_body -side left
325
326   pack .commitMessage.topFrame
327   pack .commitMessage.bottomFrame
328
329   wm transient .commitMessage .
330   wm deiconify .commitMessage
331 }
332
333
334 # GUI
335
336 wm title . $windowTitle
337
338 # Buttons
339
340 panedwindow .buttons
341
342 frame  .buttons.commitFrame
343 button .buttons.commitFrame.commit -text "2a. New local commit" -command commit
344 button .buttons.commitFrame.amend -text "2b. Amend previous commit" -command commit_amend
345 pack .buttons.commitFrame.commit -fill x
346 pack .buttons.commitFrame.amend -fill x
347
348 button .buttons.update -text $updateButtonText \
349           -command update_lilypond_with_rebase
350 button .buttons.patch -text "3. Make patch set" \
351           -command patch_from_origin
352 toggle_rebase
353 button .buttons.panic -text "Abort changes -- Reset to origin" \
354           -command abort_changes -fg Blue -bg Red
355 label   .buttons.spacer -text "                         "
356 if {![file exists $lily_dir]} {
357         .buttons.update configure \
358             -text $initializeButtonText
359         .buttons.commitFrame.commit configure -state disabled
360         .buttons.commitFrame.amend configure -state disabled
361         .buttons.patch configure -state disabled
362         .buttons.panic configure -state disabled
363 }
364
365 #  Operating buttons
366
367 pack .buttons.update -side left
368 pack .buttons.commitFrame -side left
369 pack .buttons.patch -side left
370 pack .buttons.spacer -side left
371 pack .buttons.panic -side right
372
373
374 # Output text box
375
376 panedwindow .output
377 label .output.label -text "Command output:"
378 text .output.text -width 80 -height 15 \
379         -xscrollcommand [list .output.horizontal set] \
380         -yscrollcommand [list .output.vertical set] \
381         -relief solid -border 2
382 scrollbar .output.horizontal -orient h -command [list .output.text xview]
383 scrollbar .output.vertical -orient v -command [list .output.text yview]
384 pack .output.label -side left
385 pack .output.horizontal -side bottom -fill x
386 pack .output.vertical -side right -fill y
387 pack .output.text -expand true -anchor nw -fill both
388
389 pack .buttons
390 pack .output
391
392 #grid .buttons -row 2 -column 1
393 #grid .output -row 3 -column 1 -sticky "w"