Commit | Line | Data |
---|---|---|
aa252f19 SP |
1 | # git-gui remote branch deleting support |
2 | # Copyright (C) 2007 Shawn Pearce | |
3 | ||
4 | class remote_branch_delete { | |
5 | ||
6 | field w | |
7 | field head_m | |
8 | ||
9 | field urltype {url} | |
10 | field remote {} | |
11 | field url {} | |
12 | ||
13 | field checktype {head} | |
14 | field check_head {} | |
15 | ||
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 | |
24 | ||
25 | constructor dialog {} { | |
c80d7be5 | 26 | global all_remotes M1B use_ttk NS |
aa252f19 | 27 | |
c80d7be5 | 28 | make_dialog top w |
3c1c2a00 | 29 | wm title $top [append "[appname] ([reponame]): " [mc "Delete Branch Remotely"]] |
aa252f19 SP |
30 | if {$top ne {.}} { |
31 | wm geometry $top "+[winfo rootx .]+[winfo rooty .]" | |
32 | } | |
33 | ||
c80d7be5 PT |
34 | ${NS}::label $w.header -text [mc "Delete Branch Remotely"] \ |
35 | -font font_uibold -anchor center | |
aa252f19 SP |
36 | pack $w.header -side top -fill x |
37 | ||
c80d7be5 PT |
38 | ${NS}::frame $w.buttons |
39 | ${NS}::button $w.buttons.delete -text [mc Delete] \ | |
aa252f19 SP |
40 | -default active \ |
41 | -command [cb _delete] | |
42 | pack $w.buttons.delete -side right | |
c80d7be5 | 43 | ${NS}::button $w.buttons.cancel -text [mc "Cancel"] \ |
aa252f19 SP |
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 | |
47 | ||
c80d7be5 | 48 | ${NS}::labelframe $w.dest -text [mc "From Repository"] |
aa252f19 | 49 | if {$all_remotes ne {}} { |
c80d7be5 | 50 | ${NS}::radiobutton $w.dest.remote_r \ |
1ac17950 | 51 | -text [mc "Remote:"] \ |
aa252f19 SP |
52 | -value remote \ |
53 | -variable @urltype | |
c80d7be5 PT |
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 | |
59 | } | |
aa252f19 SP |
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] | |
65 | } | |
66 | set urltype remote | |
67 | trace add variable @remote write [cb _write_remote] | |
68 | } else { | |
69 | set urltype url | |
70 | } | |
c80d7be5 | 71 | ${NS}::radiobutton $w.dest.url_r \ |
4259568d | 72 | -text [mc "Arbitrary Location:"] \ |
aa252f19 SP |
73 | -value url \ |
74 | -variable @urltype | |
c80d7be5 | 75 | ${NS}::entry $w.dest.url_t \ |
aa252f19 SP |
76 | -width 50 \ |
77 | -textvariable @url \ | |
78 | -validate key \ | |
79 | -validatecommand { | |
80 | if {%d == 1 && [regexp {\s} %S]} {return 0} | |
81 | return 1 | |
82 | } | |
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 | |
87 | ||
c80d7be5 PT |
88 | ${NS}::labelframe $w.heads -text [mc "Branches"] |
89 | slistbox $w.heads.l \ | |
aa252f19 SP |
90 | -height 10 \ |
91 | -width 70 \ | |
92 | -listvariable @head_list \ | |
c80d7be5 | 93 | -selectmode extended |
aa252f19 | 94 | |
c80d7be5 PT |
95 | ${NS}::frame $w.heads.footer |
96 | ${NS}::label $w.heads.footer.status \ | |
aa252f19 SP |
97 | -textvariable @status \ |
98 | -anchor w \ | |
99 | -justify left | |
c80d7be5 | 100 | ${NS}::button $w.heads.footer.rescan \ |
1ac17950 | 101 | -text [mc "Rescan"] \ |
aa252f19 | 102 | -command [cb _rescan] |
1eb96a25 | 103 | pack $w.heads.footer.status -side left -fill x |
aa252f19 SP |
104 | pack $w.heads.footer.rescan -side right |
105 | ||
1eb96a25 | 106 | pack $w.heads.footer -side bottom -fill x |
aa252f19 SP |
107 | pack $w.heads.l -side left -fill both -expand 1 |
108 | pack $w.heads -fill both -expand 1 -pady 5 -padx 5 | |
109 | ||
c80d7be5 PT |
110 | ${NS}::labelframe $w.validate -text [mc "Delete Only If"] |
111 | ${NS}::radiobutton $w.validate.head_r \ | |
1ac17950 | 112 | -text [mc "Merged Into:"] \ |
aa252f19 SP |
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 | |
c80d7be5 | 119 | ${NS}::radiobutton $w.validate.always_r \ |
1ac17950 | 120 | -text [mc "Always (Do not perform merge checks)"] \ |
aa252f19 SP |
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 | |
126 | ||
127 | trace add variable @urltype write [cb _write_urltype] | |
128 | _rescan $this | |
129 | ||
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] | |
aa252f19 SP |
135 | return $w |
136 | } | |
137 | ||
138 | method _delete {} { | |
139 | switch $urltype { | |
140 | remote {set uri $remote} | |
141 | url {set uri $url} | |
142 | } | |
143 | ||
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 \ | |
1ac17950 | 153 | -message [mc "A branch is required for 'Merged Into'."] |
aa252f19 SP |
154 | return |
155 | } | |
156 | set crev $full_cache("$cache\nrefs/heads/$check_head") | |
157 | } | |
158 | ||
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 | |
165 | ||
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 {} | |
173 | } | |
174 | if {$obj ne $m} { | |
175 | lappend not_merged [lindex $head_list $i] | |
176 | continue | |
177 | } | |
178 | } | |
179 | ||
180 | lappend push_cmd :$ref | |
181 | set have_selection 1 | |
182 | } | |
183 | ||
184 | if {$not_merged ne {}} { | |
c8c4854b | 185 | set msg [mc "The following branches are not completely merged into %s: |
aa252f19 | 186 | |
c8c4854b | 187 | - %s" $check_head [join $not_merged "\n - "]] |
aa252f19 SP |
188 | |
189 | if {$need_fetch} { | |
1ac17950 | 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] |
aa252f19 SP |
191 | } |
192 | ||
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 | |
200 | } | |
201 | ||
202 | if {!$have_selection} { | |
203 | tk_messageBox \ | |
204 | -icon error \ | |
205 | -type ok \ | |
206 | -title [wm title $w] \ | |
207 | -parent $w \ | |
1ac17950 | 208 | -message [mc "Please select one or more branches to delete."] |
aa252f19 SP |
209 | return |
210 | } | |
211 | ||
2112be76 HV |
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 | |
220 | } | |
aa252f19 SP |
221 | } |
222 | ||
223 | destroy $w | |
224 | ||
225 | set cons [console::new \ | |
226 | "push $uri" \ | |
1ac17950 | 227 | [mc "Deleting branches from %s" $uri]] |
aa252f19 SP |
228 | console::exec $cons $push_cmd |
229 | } | |
230 | ||
231 | method _rescan {{force 1}} { | |
232 | switch $urltype { | |
233 | remote {set uri $remote} | |
234 | url {set uri $url} | |
235 | } | |
236 | ||
237 | if {$force} { | |
238 | unset -nocomplain cached($urltype:$uri) | |
239 | } | |
240 | ||
241 | if {$idle_id ne {}} { | |
242 | after cancel $idle_id | |
243 | set idle_id {} | |
244 | } | |
245 | ||
246 | _load $this $urltype:$uri $uri | |
247 | } | |
248 | ||
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 } | |
252 | ||
253 | method _write_head_list {args} { | |
9d04278a | 254 | global current_branch _last_merged_branch |
c0d15329 | 255 | |
aa252f19 SP |
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 | |
262 | } | |
263 | if {[lsearch -exact -sorted $head_list $check_head] < 0} { | |
c0d15329 HV |
264 | if {[lsearch -exact -sorted $head_list $current_branch] < 0} { |
265 | set check_head {} | |
266 | } else { | |
267 | set check_head $current_branch | |
268 | } | |
aa252f19 | 269 | } |
9d04278a HV |
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 | |
276 | } | |
aa252f19 SP |
277 | } |
278 | ||
279 | method _write_urltype {args} { | |
280 | if {$urltype eq {url}} { | |
281 | if {$idle_id ne {}} { | |
282 | after cancel $idle_id | |
283 | } | |
284 | _load $this none: {} | |
285 | set idle_id [after 1000 [cb _rescan 0]] | |
286 | } else { | |
287 | _rescan $this 0 | |
288 | } | |
289 | } | |
290 | ||
291 | method _load {cache uri} { | |
292 | if {$active_ls ne {}} { | |
293 | catch {close $active_ls} | |
294 | } | |
295 | ||
296 | if {$uri eq {}} { | |
297 | $w.heads.l conf -state disabled | |
298 | set head_list [list] | |
299 | set full_list [list] | |
1ac17950 | 300 | set status [mc "No repository selected."] |
aa252f19 SP |
301 | return |
302 | } | |
303 | ||
304 | if {[catch {set x $cached($cache)}]} { | |
1ac17950 | 305 | set status [mc "Scanning %s..." $uri] |
aa252f19 SP |
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] | |
0b812616 | 311 | set active_ls [git_read ls-remote $uri] |
aa252f19 SP |
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 | |
322 | } | |
323 | } | |
324 | ||
325 | method _read {cache fd} { | |
326 | if {$fd ne $active_ls} { | |
327 | catch {close $fd} | |
328 | return | |
329 | } | |
330 | ||
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 | |
340 | } | |
341 | } | |
342 | } | |
343 | ||
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 | |
353 | } | |
354 | } | |
355 | } ifdeleted { | |
356 | catch {close $fd} | |
357 | } | |
358 | ||
359 | } |