git-gui: Make sure we get errors from git-update-index
[git-gui/git-gui-i18n.git] / lib / index.tcl
blob28ca03901226b6738ccefd678185d77726b3eae6
1 # git-gui index (add/remove) support
2 # Copyright (C) 2006, 2007 Shawn Pearce
4 proc _delete_indexlock {} {
5 if {[catch {file delete -- [gitdir index.lock]} err]} {
6 error_popup [strcat [mc "Unable to unlock the index."] "\n\n$err"]
10 proc _close_updateindex {fd after} {
11 fconfigure $fd -blocking 1
12 if {[catch {close $fd} err]} {
13 set w .indexfried
14 toplevel $w
15 wm title $w [strcat "[appname] ([reponame]): " [mc "Index Error"]]
16 wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
17 pack [label $w.msg \
18 -justify left \
19 -anchor w \
20 -text [strcat \
21 [mc "Updating the Git index failed. A rescan will be automatically started to resynchronize git-gui."] \
22 "\n\n$err"] \
23 ] -anchor w
25 frame $w.buttons
26 button $w.buttons.continue \
27 -text [mc "Continue"] \
28 -command [list destroy $w]
29 pack $w.buttons.continue -side right -padx 5
30 button $w.buttons.unlock \
31 -text [mc "Unlock Index"] \
32 -command "destroy $w; _delete_indexlock"
33 pack $w.buttons.unlock -side right
34 pack $w.buttons -side bottom -fill x -pady 10 -padx 10
36 wm protocol $w WM_DELETE_WINDOW update
37 bind $w.buttons.continue <Visibility> "
38 grab $w
39 focus $w.buttons.continue
41 tkwait window $w
43 $::main_status stop
44 unlock_index
45 rescan $after 0
46 return
49 unlock_index
50 uplevel #0 $after
53 proc update_indexinfo {msg pathList after} {
54 global update_index_cp
56 if {![lock_index update]} return
58 set update_index_cp 0
59 set pathList [lsort $pathList]
60 set totalCnt [llength $pathList]
61 set batch [expr {int($totalCnt * .01) + 1}]
62 if {$batch > 25} {set batch 25}
64 ui_status [format \
65 "%s... %i/%i files (%.2f%%)" \
66 $msg \
67 $update_index_cp \
68 $totalCnt \
69 0.0]
70 set fd [git_write update-index -z --index-info]
71 fconfigure $fd \
72 -blocking 0 \
73 -buffering full \
74 -buffersize 512 \
75 -encoding binary \
76 -translation binary
77 fileevent $fd writable [list \
78 write_update_indexinfo \
79 $fd \
80 $pathList \
81 $totalCnt \
82 $batch \
83 $msg \
84 $after \
88 proc write_update_indexinfo {fd pathList totalCnt batch msg after} {
89 global update_index_cp
90 global file_states current_diff_path
92 if {$update_index_cp >= $totalCnt} {
93 _close_updateindex $fd $after
94 return
97 for {set i $batch} \
98 {$update_index_cp < $totalCnt && $i > 0} \
99 {incr i -1} {
100 set path [lindex $pathList $update_index_cp]
101 incr update_index_cp
103 set s $file_states($path)
104 switch -glob -- [lindex $s 0] {
105 A? {set new _O}
106 M? {set new _M}
107 D_ {set new _D}
108 D? {set new _?}
109 ?? {continue}
111 set info [lindex $s 2]
112 if {$info eq {}} continue
114 puts -nonewline $fd "$info\t[encoding convertto $path]\0"
115 display_file $path $new
118 ui_status [format \
119 "%s... %i/%i files (%.2f%%)" \
120 $msg \
121 $update_index_cp \
122 $totalCnt \
123 [expr {100.0 * $update_index_cp / $totalCnt}]]
126 proc update_index {msg pathList after} {
127 global update_index_cp
129 if {![lock_index update]} return
131 set update_index_cp 0
132 set pathList [lsort $pathList]
133 set totalCnt [llength $pathList]
134 set batch [expr {int($totalCnt * .01) + 1}]
135 if {$batch > 25} {set batch 25}
137 ui_status [format \
138 "%s... %i/%i files (%.2f%%)" \
139 $msg \
140 $update_index_cp \
141 $totalCnt \
142 0.0]
143 set fd [git_write update-index --add --remove -z --stdin]
144 fconfigure $fd \
145 -blocking 0 \
146 -buffering full \
147 -buffersize 512 \
148 -encoding binary \
149 -translation binary
150 fileevent $fd writable [list \
151 write_update_index \
152 $fd \
153 $pathList \
154 $totalCnt \
155 $batch \
156 $msg \
157 $after \
161 proc write_update_index {fd pathList totalCnt batch msg after} {
162 global update_index_cp
163 global file_states current_diff_path
165 if {$update_index_cp >= $totalCnt} {
166 _close_updateindex $fd $after
167 return
170 for {set i $batch} \
171 {$update_index_cp < $totalCnt && $i > 0} \
172 {incr i -1} {
173 set path [lindex $pathList $update_index_cp]
174 incr update_index_cp
176 switch -glob -- [lindex $file_states($path) 0] {
177 AD {set new __}
178 ?D {set new D_}
179 _O -
180 AM {set new A_}
181 U? {
182 if {[file exists $path]} {
183 set new M_
184 } else {
185 set new D_
188 ?M {set new M_}
189 ?? {continue}
191 puts -nonewline $fd "[encoding convertto $path]\0"
192 display_file $path $new
195 ui_status [format \
196 "%s... %i/%i files (%.2f%%)" \
197 $msg \
198 $update_index_cp \
199 $totalCnt \
200 [expr {100.0 * $update_index_cp / $totalCnt}]]
203 proc checkout_index {msg pathList after} {
204 global update_index_cp
206 if {![lock_index update]} return
208 set update_index_cp 0
209 set pathList [lsort $pathList]
210 set totalCnt [llength $pathList]
211 set batch [expr {int($totalCnt * .01) + 1}]
212 if {$batch > 25} {set batch 25}
214 ui_status [format \
215 "%s... %i/%i files (%.2f%%)" \
216 $msg \
217 $update_index_cp \
218 $totalCnt \
219 0.0]
220 set fd [git_write checkout-index \
221 --index \
222 --quiet \
223 --force \
224 -z \
225 --stdin \
227 fconfigure $fd \
228 -blocking 0 \
229 -buffering full \
230 -buffersize 512 \
231 -encoding binary \
232 -translation binary
233 fileevent $fd writable [list \
234 write_checkout_index \
235 $fd \
236 $pathList \
237 $totalCnt \
238 $batch \
239 $msg \
240 $after \
244 proc write_checkout_index {fd pathList totalCnt batch msg after} {
245 global update_index_cp
246 global file_states current_diff_path
248 if {$update_index_cp >= $totalCnt} {
249 _close_updateindex $fd $after
250 return
253 for {set i $batch} \
254 {$update_index_cp < $totalCnt && $i > 0} \
255 {incr i -1} {
256 set path [lindex $pathList $update_index_cp]
257 incr update_index_cp
258 switch -glob -- [lindex $file_states($path) 0] {
259 U? {continue}
260 ?M -
261 ?D {
262 puts -nonewline $fd "[encoding convertto $path]\0"
263 display_file $path ?_
268 ui_status [format \
269 "%s... %i/%i files (%.2f%%)" \
270 $msg \
271 $update_index_cp \
272 $totalCnt \
273 [expr {100.0 * $update_index_cp / $totalCnt}]]
276 proc unstage_helper {txt paths} {
277 global file_states current_diff_path
279 if {![lock_index begin-update]} return
281 set pathList [list]
282 set after {}
283 foreach path $paths {
284 switch -glob -- [lindex $file_states($path) 0] {
285 A? -
286 M? -
287 D? {
288 lappend pathList $path
289 if {$path eq $current_diff_path} {
290 set after {reshow_diff;}
295 if {$pathList eq {}} {
296 unlock_index
297 } else {
298 update_indexinfo \
299 $txt \
300 $pathList \
301 [concat $after [list ui_ready]]
305 proc do_unstage_selection {} {
306 global current_diff_path selected_paths
308 if {[array size selected_paths] > 0} {
309 unstage_helper \
310 {Unstaging selected files from commit} \
311 [array names selected_paths]
312 } elseif {$current_diff_path ne {}} {
313 unstage_helper \
314 "Unstaging [short_path $current_diff_path] from commit" \
315 [list $current_diff_path]
319 proc add_helper {txt paths} {
320 global file_states current_diff_path
322 if {![lock_index begin-update]} return
324 set pathList [list]
325 set after {}
326 foreach path $paths {
327 switch -glob -- [lindex $file_states($path) 0] {
328 _O -
329 ?M -
330 ?D -
331 U? {
332 lappend pathList $path
333 if {$path eq $current_diff_path} {
334 set after {reshow_diff;}
339 if {$pathList eq {}} {
340 unlock_index
341 } else {
342 update_index \
343 $txt \
344 $pathList \
345 [concat $after {ui_status {Ready to commit.}}]
349 proc do_add_selection {} {
350 global current_diff_path selected_paths
352 if {[array size selected_paths] > 0} {
353 add_helper \
354 {Adding selected files} \
355 [array names selected_paths]
356 } elseif {$current_diff_path ne {}} {
357 add_helper \
358 "Adding [short_path $current_diff_path]" \
359 [list $current_diff_path]
363 proc do_add_all {} {
364 global file_states
366 set paths [list]
367 foreach path [array names file_states] {
368 switch -glob -- [lindex $file_states($path) 0] {
369 U? {continue}
370 ?M -
371 ?D {lappend paths $path}
374 add_helper {Adding all changed files} $paths
377 proc revert_helper {txt paths} {
378 global file_states current_diff_path
380 if {![lock_index begin-update]} return
382 set pathList [list]
383 set after {}
384 foreach path $paths {
385 switch -glob -- [lindex $file_states($path) 0] {
386 U? {continue}
387 ?M -
388 ?D {
389 lappend pathList $path
390 if {$path eq $current_diff_path} {
391 set after {reshow_diff;}
397 set n [llength $pathList]
398 if {$n == 0} {
399 unlock_index
400 return
401 } elseif {$n == 1} {
402 set s "[short_path [lindex $pathList]]"
403 } else {
404 set s "these $n files"
407 set reply [tk_dialog \
408 .confirm_revert \
409 "[appname] ([reponame])" \
410 "Revert changes in $s?
412 Any unstaged changes will be permanently lost by the revert." \
413 question \
415 {Do Nothing} \
416 {Revert Changes} \
418 if {$reply == 1} {
419 checkout_index \
420 $txt \
421 $pathList \
422 [concat $after [list ui_ready]]
423 } else {
424 unlock_index
428 proc do_revert_selection {} {
429 global current_diff_path selected_paths
431 if {[array size selected_paths] > 0} {
432 revert_helper \
433 {Reverting selected files} \
434 [array names selected_paths]
435 } elseif {$current_diff_path ne {}} {
436 revert_helper \
437 "Reverting [short_path $current_diff_path]" \
438 [list $current_diff_path]
442 proc do_select_commit_type {} {
443 global commit_type selected_commit_type
445 if {$selected_commit_type eq {new}
446 && [string match amend* $commit_type]} {
447 create_new_commit
448 } elseif {$selected_commit_type eq {amend}
449 && ![string match amend* $commit_type]} {
450 load_last_commit
452 # The amend request was rejected...
454 if {![string match amend* $commit_type]} {
455 set selected_commit_type new