dir.h: move struct exclude declaration to top level
[git.git] / git-gui / lib / remote_branch_delete.tcl
blobfcc06d03a1dfc4919f762d70e2809f29dab77390
1 # git-gui remote branch deleting support
2 # Copyright (C) 2007 Shawn Pearce
4 class remote_branch_delete {
6 field w
7 field head_m
9 field urltype {url}
10 field remote {}
11 field url {}
13 field checktype {head}
14 field check_head {}
16 field status {}
17 field idle_id {}
18 field full_list {}
19 field head_list {}
20 field active_ls {}
21 field head_cache
22 field full_cache
23 field cached
25 constructor dialog {} {
26 global all_remotes M1B use_ttk NS
28 make_dialog top w
29 wm title $top [append "[appname] ([reponame]): " [mc "Delete Branch Remotely"]]
30 if {$top ne {.}} {
31 wm geometry $top "+[winfo rootx .]+[winfo rooty .]"
34 ${NS}::label $w.header -text [mc "Delete Branch Remotely"] \
35 -font font_uibold -anchor center
36 pack $w.header -side top -fill x
38 ${NS}::frame $w.buttons
39 ${NS}::button $w.buttons.delete -text [mc Delete] \
40 -default active \
41 -command [cb _delete]
42 pack $w.buttons.delete -side right
43 ${NS}::button $w.buttons.cancel -text [mc "Cancel"] \
44 -command [list destroy $w]
45 pack $w.buttons.cancel -side right -padx 5
46 pack $w.buttons -side bottom -fill x -pady 10 -padx 10
48 ${NS}::labelframe $w.dest -text [mc "From Repository"]
49 if {$all_remotes ne {}} {
50 ${NS}::radiobutton $w.dest.remote_r \
51 -text [mc "Remote:"] \
52 -value remote \
53 -variable @urltype
54 if {$use_ttk} {
55 ttk::combobox $w.dest.remote_m -textvariable @remote \
56 -values $all_remotes -state readonly
57 } else {
58 eval tk_optionMenu $w.dest.remote_m @remote $all_remotes
60 grid $w.dest.remote_r $w.dest.remote_m -sticky w
61 if {[lsearch -sorted -exact $all_remotes origin] != -1} {
62 set remote origin
63 } else {
64 set remote [lindex $all_remotes 0]
66 set urltype remote
67 trace add variable @remote write [cb _write_remote]
68 } else {
69 set urltype url
71 ${NS}::radiobutton $w.dest.url_r \
72 -text [mc "Arbitrary Location:"] \
73 -value url \
74 -variable @urltype
75 ${NS}::entry $w.dest.url_t \
76 -width 50 \
77 -textvariable @url \
78 -validate key \
79 -validatecommand {
80 if {%d == 1 && [regexp {\s} %S]} {return 0}
81 return 1
83 trace add variable @url write [cb _write_url]
84 grid $w.dest.url_r $w.dest.url_t -sticky we -padx {0 5}
85 grid columnconfigure $w.dest 1 -weight 1
86 pack $w.dest -anchor nw -fill x -pady 5 -padx 5
88 ${NS}::labelframe $w.heads -text [mc "Branches"]
89 slistbox $w.heads.l \
90 -height 10 \
91 -width 70 \
92 -listvariable @head_list \
93 -selectmode extended
95 ${NS}::frame $w.heads.footer
96 ${NS}::label $w.heads.footer.status \
97 -textvariable @status \
98 -anchor w \
99 -justify left
100 ${NS}::button $w.heads.footer.rescan \
101 -text [mc "Rescan"] \
102 -command [cb _rescan]
103 pack $w.heads.footer.status -side left -fill x
104 pack $w.heads.footer.rescan -side right
106 pack $w.heads.footer -side bottom -fill x
107 pack $w.heads.l -side left -fill both -expand 1
108 pack $w.heads -fill both -expand 1 -pady 5 -padx 5
110 ${NS}::labelframe $w.validate -text [mc "Delete Only If"]
111 ${NS}::radiobutton $w.validate.head_r \
112 -text [mc "Merged Into:"] \
113 -value head \
114 -variable @checktype
115 set head_m [tk_optionMenu $w.validate.head_m @check_head {}]
116 trace add variable @head_list write [cb _write_head_list]
117 trace add variable @check_head write [cb _write_check_head]
118 grid $w.validate.head_r $w.validate.head_m -sticky w
119 ${NS}::radiobutton $w.validate.always_r \
120 -text [mc "Always (Do not perform merge checks)"] \
121 -value always \
122 -variable @checktype
123 grid $w.validate.always_r -columnspan 2 -sticky w
124 grid columnconfigure $w.validate 1 -weight 1
125 pack $w.validate -anchor nw -fill x -pady 5 -padx 5
127 trace add variable @urltype write [cb _write_urltype]
128 _rescan $this
130 bind $w <Key-F5> [cb _rescan]
131 bind $w <$M1B-Key-r> [cb _rescan]
132 bind $w <$M1B-Key-R> [cb _rescan]
133 bind $w <Key-Return> [cb _delete]
134 bind $w <Key-Escape> [list destroy $w]
135 return $w
138 method _delete {} {
139 switch $urltype {
140 remote {set uri $remote}
141 url {set uri $url}
144 set cache $urltype:$uri
145 set crev {}
146 if {$checktype eq {head}} {
147 if {$check_head eq {}} {
148 tk_messageBox \
149 -icon error \
150 -type ok \
151 -title [wm title $w] \
152 -parent $w \
153 -message [mc "A branch is required for 'Merged Into'."]
154 return
156 set crev $full_cache("$cache\nrefs/heads/$check_head")
159 set not_merged [list]
160 set need_fetch 0
161 set have_selection 0
162 set push_cmd [list git push]
163 lappend push_cmd -v
164 lappend push_cmd $uri
166 foreach i [$w.heads.l curselection] {
167 set ref [lindex $full_list $i]
168 if {$crev ne {}} {
169 set obj $full_cache("$cache\n$ref")
170 if {[catch {set m [git merge-base $obj $crev]}]} {
171 set need_fetch 1
172 set m {}
174 if {$obj ne $m} {
175 lappend not_merged [lindex $head_list $i]
176 continue
180 lappend push_cmd :$ref
181 set have_selection 1
184 if {$not_merged ne {}} {
185 set msg [mc "The following branches are not completely merged into %s:
187 - %s" $check_head [join $not_merged "\n - "]]
189 if {$need_fetch} {
190 append msg "\n\n" [mc "One or more of the merge tests failed because you have not fetched the necessary commits. Try fetching from %s first." $uri]
193 tk_messageBox \
194 -icon info \
195 -type ok \
196 -title [wm title $w] \
197 -parent $w \
198 -message $msg
199 if {!$have_selection} return
202 if {!$have_selection} {
203 tk_messageBox \
204 -icon error \
205 -type ok \
206 -title [wm title $w] \
207 -parent $w \
208 -message [mc "Please select one or more branches to delete."]
209 return
212 if {$checktype ne {head}} {
213 if {[tk_messageBox \
214 -icon warning \
215 -type yesno \
216 -title [wm title $w] \
217 -parent $w \
218 -message [mc "Recovering deleted branches is difficult.\n\nDelete the selected branches?"]] ne yes} {
219 return
223 destroy $w
225 set cons [console::new \
226 "push $uri" \
227 [mc "Deleting branches from %s" $uri]]
228 console::exec $cons $push_cmd
231 method _rescan {{force 1}} {
232 switch $urltype {
233 remote {set uri $remote}
234 url {set uri $url}
237 if {$force} {
238 unset -nocomplain cached($urltype:$uri)
241 if {$idle_id ne {}} {
242 after cancel $idle_id
243 set idle_id {}
246 _load $this $urltype:$uri $uri
249 method _write_remote {args} { set urltype remote }
250 method _write_url {args} { set urltype url }
251 method _write_check_head {args} { set checktype head }
253 method _write_head_list {args} {
254 global current_branch _last_merged_branch
256 $head_m delete 0 end
257 foreach abr $head_list {
258 $head_m insert end radiobutton \
259 -label $abr \
260 -value $abr \
261 -variable @check_head
263 if {[lsearch -exact -sorted $head_list $check_head] < 0} {
264 if {[lsearch -exact -sorted $head_list $current_branch] < 0} {
265 set check_head {}
266 } else {
267 set check_head $current_branch
270 set lmb [lsearch -exact -sorted $head_list $_last_merged_branch]
271 if {$lmb >= 0} {
272 $w.heads.l conf -state normal
273 $w.heads.l select set $lmb
274 $w.heads.l yview $lmb
275 $w.heads.l conf -state disabled
279 method _write_urltype {args} {
280 if {$urltype eq {url}} {
281 if {$idle_id ne {}} {
282 after cancel $idle_id
284 _load $this none: {}
285 set idle_id [after 1000 [cb _rescan 0]]
286 } else {
287 _rescan $this 0
291 method _load {cache uri} {
292 if {$active_ls ne {}} {
293 catch {close $active_ls}
296 if {$uri eq {}} {
297 $w.heads.l conf -state disabled
298 set head_list [list]
299 set full_list [list]
300 set status [mc "No repository selected."]
301 return
304 if {[catch {set x $cached($cache)}]} {
305 set status [mc "Scanning %s..." $uri]
306 $w.heads.l conf -state disabled
307 set head_list [list]
308 set full_list [list]
309 set head_cache($cache) [list]
310 set full_cache($cache) [list]
311 set active_ls [git_read ls-remote $uri]
312 fconfigure $active_ls \
313 -blocking 0 \
314 -translation lf \
315 -encoding utf-8
316 fileevent $active_ls readable [cb _read $cache $active_ls]
317 } else {
318 set status {}
319 set full_list $full_cache($cache)
320 set head_list $head_cache($cache)
321 $w.heads.l conf -state normal
325 method _read {cache fd} {
326 if {$fd ne $active_ls} {
327 catch {close $fd}
328 return
331 while {[gets $fd line] >= 0} {
332 if {[string match {*^{}} $line]} continue
333 if {[regexp {^([0-9a-f]{40}) (.*)$} $line _junk obj ref]} {
334 if {[regsub ^refs/heads/ $ref {} abr]} {
335 lappend head_list $abr
336 lappend head_cache($cache) $abr
337 lappend full_list $ref
338 lappend full_cache($cache) $ref
339 set full_cache("$cache\n$ref") $obj
344 if {[eof $fd]} {
345 if {[catch {close $fd} err]} {
346 set status $err
347 set head_list [list]
348 set full_list [list]
349 } else {
350 set status {}
351 set cached($cache) 1
352 $w.heads.l conf -state normal
355 } ifdeleted {
356 catch {close $fd}