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