Git fork
at reftables-rust 331 lines 7.3 kB view raw
1# git-gui remote management 2# Copyright (C) 2006, 2007 Shawn Pearce 3 4set some_heads_tracking 0; # assume not 5 6proc is_tracking_branch {name} { 7 global tracking_branches 8 foreach spec $tracking_branches { 9 set t [lindex $spec 0] 10 if {$t eq $name || [string match $t $name]} { 11 return 1 12 } 13 } 14 return 0 15} 16 17proc all_tracking_branches {} { 18 global tracking_branches 19 20 set all [list] 21 set pat [list] 22 set cmd [list] 23 24 foreach spec $tracking_branches { 25 set dst [lindex $spec 0] 26 if {[string range $dst end-1 end] eq {/*}} { 27 lappend pat $spec 28 lappend cmd [string range $dst 0 end-2] 29 } else { 30 lappend all $spec 31 } 32 } 33 34 if {$pat ne {}} { 35 set fd [git_read [concat for-each-ref --format=%(refname) $cmd]] 36 while {[gets $fd n] > 0} { 37 foreach spec $pat { 38 set dst [string range [lindex $spec 0] 0 end-2] 39 set len [string length $dst] 40 if {[string equal -length $len $dst $n]} { 41 set src [string range [lindex $spec 2] 0 end-2] 42 set spec [list \ 43 $n \ 44 [lindex $spec 1] \ 45 $src[string range $n $len end] \ 46 ] 47 lappend all $spec 48 } 49 } 50 } 51 close $fd 52 } 53 54 return [lsort -index 0 -unique $all] 55} 56 57proc load_all_remotes {} { 58 global repo_config 59 global all_remotes tracking_branches some_heads_tracking 60 global remote_url 61 62 set some_heads_tracking 0 63 set all_remotes [list] 64 set trck [list] 65 66 set rh_str refs/heads/ 67 set rh_len [string length $rh_str] 68 set rm_dir [gitdir remotes] 69 if {[file isdirectory $rm_dir]} { 70 set all_remotes [glob \ 71 -types f \ 72 -tails \ 73 -nocomplain \ 74 -directory $rm_dir *] 75 76 foreach name $all_remotes { 77 catch { 78 set fd [safe_open_file [file join $rm_dir $name] r] 79 while {[gets $fd line] >= 0} { 80 if {[regexp {^URL:[ ]*(.+)$} $line line url]} { 81 set remote_url($name) $url 82 continue 83 } 84 if {![regexp {^Pull:[ ]*([^:]+):(.+)$} \ 85 $line line src dst]} continue 86 if {[string index $src 0] eq {+}} { 87 set src [string range $src 1 end] 88 } 89 if {![string equal -length 5 refs/ $src]} { 90 set src $rh_str$src 91 } 92 if {![string equal -length 5 refs/ $dst]} { 93 set dst $rh_str$dst 94 } 95 if {[string equal -length $rh_len $rh_str $dst]} { 96 set some_heads_tracking 1 97 } 98 lappend trck [list $dst $name $src] 99 } 100 close $fd 101 } 102 } 103 } 104 105 foreach line [array names repo_config remote.*.url] { 106 if {![regexp ^remote\.(.*)\.url\$ $line line name]} continue 107 lappend all_remotes $name 108 set remote_url($name) $repo_config(remote.$name.url) 109 110 if {[catch {set fl $repo_config(remote.$name.fetch)}]} { 111 set fl {} 112 } 113 foreach line $fl { 114 if {![regexp {^([^:]+):(.+)$} $line line src dst]} continue 115 if {[string index $src 0] eq {+}} { 116 set src [string range $src 1 end] 117 } 118 if {![string equal -length 5 refs/ $src]} { 119 set src $rh_str$src 120 } 121 if {![string equal -length 5 refs/ $dst]} { 122 set dst $rh_str$dst 123 } 124 if {[string equal -length $rh_len $rh_str $dst]} { 125 set some_heads_tracking 1 126 } 127 lappend trck [list $dst $name $src] 128 } 129 } 130 131 set tracking_branches [lsort -index 0 -unique $trck] 132 set all_remotes [lsort -unique $all_remotes] 133} 134 135proc add_fetch_entry {r} { 136 global repo_config 137 set remote_m .mbar.remote 138 set fetch_m $remote_m.fetch 139 set prune_m $remote_m.prune 140 set remove_m $remote_m.remove 141 set enable 0 142 if {![catch {set a $repo_config(remote.$r.url)}]} { 143 if {![catch {set a $repo_config(remote.$r.fetch)}]} { 144 set enable 1 145 } 146 } else { 147 catch { 148 set fd [safe_open_file [gitdir remotes $r] r] 149 while {[gets $fd n] >= 0} { 150 if {[regexp {^Pull:[ \t]*([^:]+):} $n]} { 151 set enable 1 152 break 153 } 154 } 155 close $fd 156 } 157 } 158 159 if {$enable} { 160 make_sure_remote_submenues_exist $remote_m 161 162 $fetch_m add command \ 163 -label $r \ 164 -command [list fetch_from $r] 165 $prune_m add command \ 166 -label $r \ 167 -command [list prune_from $r] 168 $remove_m add command \ 169 -label $r \ 170 -command [list remove_remote $r] 171 } 172} 173 174proc add_push_entry {r} { 175 global repo_config 176 set remote_m .mbar.remote 177 set push_m $remote_m.push 178 set enable 0 179 if {![catch {set a $repo_config(remote.$r.url)}]} { 180 if {![catch {set a $repo_config(remote.$r.push)}]} { 181 set enable 1 182 } 183 } else { 184 catch { 185 set fd [safe_open_file [gitdir remotes $r] r] 186 while {[gets $fd n] >= 0} { 187 if {[regexp {^Push:[ \t]*([^:]+):} $n]} { 188 set enable 1 189 break 190 } 191 } 192 close $fd 193 } 194 } 195 196 if {$enable} { 197 if {![winfo exists $push_m]} { 198 menu $push_m 199 $remote_m insert 0 cascade \ 200 -label [mc "Push to"] \ 201 -menu $push_m 202 } 203 204 $push_m add command \ 205 -label $r \ 206 -command [list push_to $r] 207 } 208} 209 210proc make_sure_remote_submenues_exist {remote_m} { 211 set fetch_m $remote_m.fetch 212 set prune_m $remote_m.prune 213 set remove_m $remote_m.remove 214 215 if {![winfo exists $fetch_m]} { 216 menu $remove_m 217 $remote_m insert 0 cascade \ 218 -label [mc "Remove Remote"] \ 219 -menu $remove_m 220 221 menu $prune_m 222 $remote_m insert 0 cascade \ 223 -label [mc "Prune from"] \ 224 -menu $prune_m 225 226 menu $fetch_m 227 $remote_m insert 0 cascade \ 228 -label [mc "Fetch from"] \ 229 -menu $fetch_m 230 } 231} 232 233proc update_all_remotes_menu_entry {} { 234 global all_remotes 235 236 set have_remote 0 237 foreach r $all_remotes { 238 incr have_remote 239 } 240 241 set remote_m .mbar.remote 242 set fetch_m $remote_m.fetch 243 set prune_m $remote_m.prune 244 if {$have_remote > 1} { 245 make_sure_remote_submenues_exist $remote_m 246 if {[$fetch_m type end] eq "command" \ 247 && [$fetch_m entrycget end -label] ne [mc "All"]} { 248 249 $fetch_m insert end separator 250 $fetch_m insert end command \ 251 -label [mc "All"] \ 252 -command fetch_from_all 253 254 $prune_m insert end separator 255 $prune_m insert end command \ 256 -label [mc "All"] \ 257 -command prune_from_all 258 } 259 } else { 260 if {[winfo exists $fetch_m]} { 261 if {[$fetch_m type end] eq "command" \ 262 && [$fetch_m entrycget end -label] eq [mc "All"]} { 263 264 delete_from_menu $fetch_m end 265 delete_from_menu $fetch_m end 266 267 delete_from_menu $prune_m end 268 delete_from_menu $prune_m end 269 } 270 } 271 } 272} 273 274proc populate_remotes_menu {} { 275 global all_remotes 276 277 foreach r $all_remotes { 278 add_fetch_entry $r 279 add_push_entry $r 280 } 281 282 update_all_remotes_menu_entry 283} 284 285proc add_single_remote {name location} { 286 global all_remotes repo_config 287 lappend all_remotes $name 288 289 git remote add $name $location 290 291 # XXX: Better re-read the config so that we will never get out 292 # of sync with git remote implementation? 293 set repo_config(remote.$name.url) $location 294 set repo_config(remote.$name.fetch) "+refs/heads/*:refs/remotes/$name/*" 295 296 add_fetch_entry $name 297 add_push_entry $name 298 299 update_all_remotes_menu_entry 300} 301 302proc delete_from_menu {menu name} { 303 if {[winfo exists $menu]} { 304 $menu delete $name 305 } 306} 307 308proc remove_remote {name} { 309 global all_remotes repo_config 310 311 git remote rm $name 312 313 catch { 314 # Missing values are ok 315 unset repo_config(remote.$name.url) 316 unset repo_config(remote.$name.fetch) 317 unset repo_config(remote.$name.push) 318 } 319 320 set i [lsearch -exact $all_remotes $name] 321 set all_remotes [lreplace $all_remotes $i $i] 322 323 set remote_m .mbar.remote 324 delete_from_menu $remote_m.fetch $name 325 delete_from_menu $remote_m.prune $name 326 delete_from_menu $remote_m.remove $name 327 # Not all remotes are in the push menu 328 catch { delete_from_menu $remote_m.push $name } 329 330 update_all_remotes_menu_entry 331}