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