359 lines
		
	
	
	
		
			8.3 KiB
		
	
	
	
		
			Tcl
		
	
	
	
	
	
			
		
		
	
	
			359 lines
		
	
	
	
		
			8.3 KiB
		
	
	
	
		
			Tcl
		
	
	
	
	
	
# git-gui remote branch deleting support
 | 
						|
# Copyright (C) 2007 Shawn Pearce
 | 
						|
 | 
						|
class remote_branch_delete {
 | 
						|
 | 
						|
field w
 | 
						|
field head_m
 | 
						|
 | 
						|
field urltype   {url}
 | 
						|
field remote    {}
 | 
						|
field url       {}
 | 
						|
 | 
						|
field checktype  {head}
 | 
						|
field check_head {}
 | 
						|
 | 
						|
field status    {}
 | 
						|
field idle_id   {}
 | 
						|
field full_list {}
 | 
						|
field head_list {}
 | 
						|
field active_ls {}
 | 
						|
field head_cache
 | 
						|
field full_cache
 | 
						|
field cached
 | 
						|
 | 
						|
constructor dialog {} {
 | 
						|
	global all_remotes M1B use_ttk NS
 | 
						|
 | 
						|
	make_dialog top w
 | 
						|
	wm title $top [mc "%s (%s): Delete Branch Remotely" [appname] [reponame]]
 | 
						|
	if {$top ne {.}} {
 | 
						|
		wm geometry $top "+[winfo rootx .]+[winfo rooty .]"
 | 
						|
	}
 | 
						|
 | 
						|
	${NS}::label $w.header -text [mc "Delete Branch Remotely"] \
 | 
						|
		-font font_uibold -anchor center
 | 
						|
	pack $w.header -side top -fill x
 | 
						|
 | 
						|
	${NS}::frame $w.buttons
 | 
						|
	${NS}::button $w.buttons.delete -text [mc Delete] \
 | 
						|
		-default active \
 | 
						|
		-command [cb _delete]
 | 
						|
	pack $w.buttons.delete -side right
 | 
						|
	${NS}::button $w.buttons.cancel -text [mc "Cancel"] \
 | 
						|
		-command [list destroy $w]
 | 
						|
	pack $w.buttons.cancel -side right -padx 5
 | 
						|
	pack $w.buttons -side bottom -fill x -pady 10 -padx 10
 | 
						|
 | 
						|
	${NS}::labelframe $w.dest -text [mc "From Repository"]
 | 
						|
	if {$all_remotes ne {}} {
 | 
						|
		${NS}::radiobutton $w.dest.remote_r \
 | 
						|
			-text [mc "Remote:"] \
 | 
						|
			-value remote \
 | 
						|
			-variable @urltype
 | 
						|
		if {$use_ttk} {
 | 
						|
			ttk::combobox $w.dest.remote_m -textvariable @remote \
 | 
						|
				-values $all_remotes -state readonly
 | 
						|
		} else {
 | 
						|
			eval tk_optionMenu $w.dest.remote_m @remote $all_remotes
 | 
						|
		}
 | 
						|
		grid $w.dest.remote_r $w.dest.remote_m -sticky w
 | 
						|
		if {[lsearch -sorted -exact $all_remotes origin] != -1} {
 | 
						|
			set remote origin
 | 
						|
		} else {
 | 
						|
			set remote [lindex $all_remotes 0]
 | 
						|
		}
 | 
						|
		set urltype remote
 | 
						|
		trace add variable @remote write [cb _write_remote]
 | 
						|
	} else {
 | 
						|
		set urltype url
 | 
						|
	}
 | 
						|
	${NS}::radiobutton $w.dest.url_r \
 | 
						|
		-text [mc "Arbitrary Location:"] \
 | 
						|
		-value url \
 | 
						|
		-variable @urltype
 | 
						|
	${NS}::entry $w.dest.url_t \
 | 
						|
		-width 50 \
 | 
						|
		-textvariable @url \
 | 
						|
		-validate key \
 | 
						|
		-validatecommand {
 | 
						|
			if {%d == 1 && [regexp {\s} %S]} {return 0}
 | 
						|
			return 1
 | 
						|
		}
 | 
						|
	trace add variable @url write [cb _write_url]
 | 
						|
	grid $w.dest.url_r $w.dest.url_t -sticky we -padx {0 5}
 | 
						|
	grid columnconfigure $w.dest 1 -weight 1
 | 
						|
	pack $w.dest -anchor nw -fill x -pady 5 -padx 5
 | 
						|
 | 
						|
	${NS}::labelframe $w.heads -text [mc "Branches"]
 | 
						|
	slistbox $w.heads.l \
 | 
						|
		-height 10 \
 | 
						|
		-width 70 \
 | 
						|
		-listvariable @head_list \
 | 
						|
		-selectmode extended
 | 
						|
 | 
						|
	${NS}::frame $w.heads.footer
 | 
						|
	${NS}::label $w.heads.footer.status \
 | 
						|
		-textvariable @status \
 | 
						|
		-anchor w \
 | 
						|
		-justify left
 | 
						|
	${NS}::button $w.heads.footer.rescan \
 | 
						|
		-text [mc "Rescan"] \
 | 
						|
		-command [cb _rescan]
 | 
						|
	pack $w.heads.footer.status -side left -fill x
 | 
						|
	pack $w.heads.footer.rescan -side right
 | 
						|
 | 
						|
	pack $w.heads.footer -side bottom -fill x
 | 
						|
	pack $w.heads.l -side left -fill both -expand 1
 | 
						|
	pack $w.heads -fill both -expand 1 -pady 5 -padx 5
 | 
						|
 | 
						|
	${NS}::labelframe $w.validate -text [mc "Delete Only If"]
 | 
						|
	${NS}::radiobutton $w.validate.head_r \
 | 
						|
		-text [mc "Merged Into:"] \
 | 
						|
		-value head \
 | 
						|
		-variable @checktype
 | 
						|
	set head_m [tk_optionMenu $w.validate.head_m @check_head {}]
 | 
						|
	trace add variable @head_list write [cb _write_head_list]
 | 
						|
	trace add variable @check_head write [cb _write_check_head]
 | 
						|
	grid $w.validate.head_r $w.validate.head_m -sticky w
 | 
						|
	${NS}::radiobutton $w.validate.always_r \
 | 
						|
		-text [mc "Always (Do not perform merge checks)"] \
 | 
						|
		-value always \
 | 
						|
		-variable @checktype
 | 
						|
	grid $w.validate.always_r -columnspan 2 -sticky w
 | 
						|
	grid columnconfigure $w.validate 1 -weight 1
 | 
						|
	pack $w.validate -anchor nw -fill x -pady 5 -padx 5
 | 
						|
 | 
						|
	trace add variable @urltype write [cb _write_urltype]
 | 
						|
	_rescan $this
 | 
						|
 | 
						|
	bind $w <Key-F5>     [cb _rescan]
 | 
						|
	bind $w <$M1B-Key-r> [cb _rescan]
 | 
						|
	bind $w <$M1B-Key-R> [cb _rescan]
 | 
						|
	bind $w <Key-Return> [cb _delete]
 | 
						|
	bind $w <Key-Escape> [list destroy $w]
 | 
						|
	return $w
 | 
						|
}
 | 
						|
 | 
						|
method _delete {} {
 | 
						|
	switch $urltype {
 | 
						|
	remote {set uri $remote}
 | 
						|
	url    {set uri $url}
 | 
						|
	}
 | 
						|
 | 
						|
	set cache $urltype:$uri
 | 
						|
	set crev {}
 | 
						|
	if {$checktype eq {head}} {
 | 
						|
		if {$check_head eq {}} {
 | 
						|
			tk_messageBox \
 | 
						|
				-icon error \
 | 
						|
				-type ok \
 | 
						|
				-title [wm title $w] \
 | 
						|
				-parent $w \
 | 
						|
				-message [mc "A branch is required for 'Merged Into'."]
 | 
						|
			return
 | 
						|
		}
 | 
						|
		set crev $full_cache("$cache\nrefs/heads/$check_head")
 | 
						|
	}
 | 
						|
 | 
						|
	set not_merged [list]
 | 
						|
	set need_fetch 0
 | 
						|
	set have_selection 0
 | 
						|
	set push_cmd [list git push]
 | 
						|
	lappend push_cmd -v
 | 
						|
	lappend push_cmd $uri
 | 
						|
 | 
						|
	foreach i [$w.heads.l curselection] {
 | 
						|
		set ref [lindex $full_list $i]
 | 
						|
		if {$crev ne {}} {
 | 
						|
			set obj $full_cache("$cache\n$ref")
 | 
						|
			if {[catch {set m [git merge-base $obj $crev]}]} {
 | 
						|
				set need_fetch 1
 | 
						|
				set m {}
 | 
						|
			}
 | 
						|
			if {$obj ne $m} {
 | 
						|
				lappend not_merged [lindex $head_list $i]
 | 
						|
				continue
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		lappend push_cmd :$ref
 | 
						|
		set have_selection 1
 | 
						|
	}
 | 
						|
 | 
						|
	if {$not_merged ne {}} {
 | 
						|
		set msg [mc "The following branches are not completely merged into %s:
 | 
						|
 | 
						|
 - %s" $check_head [join $not_merged "\n - "]]
 | 
						|
 | 
						|
		if {$need_fetch} {
 | 
						|
			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]
 | 
						|
		}
 | 
						|
 | 
						|
		tk_messageBox \
 | 
						|
			-icon info \
 | 
						|
			-type ok \
 | 
						|
			-title [wm title $w] \
 | 
						|
			-parent $w \
 | 
						|
			-message $msg
 | 
						|
		if {!$have_selection} return
 | 
						|
	}
 | 
						|
 | 
						|
	if {!$have_selection} {
 | 
						|
		tk_messageBox \
 | 
						|
			-icon error \
 | 
						|
			-type ok \
 | 
						|
			-title [wm title $w] \
 | 
						|
			-parent $w \
 | 
						|
			-message [mc "Please select one or more branches to delete."]
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	if {$checktype ne {head}} {
 | 
						|
		if {[tk_messageBox \
 | 
						|
			-icon warning \
 | 
						|
			-type yesno \
 | 
						|
			-title [wm title $w] \
 | 
						|
			-parent $w \
 | 
						|
			-message [mc "Recovering deleted branches is difficult.\n\nDelete the selected branches?"]] ne yes} {
 | 
						|
			return
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	destroy $w
 | 
						|
 | 
						|
	set cons [console::new \
 | 
						|
		"push $uri" \
 | 
						|
		[mc "Deleting branches from %s" $uri]]
 | 
						|
	console::exec $cons $push_cmd
 | 
						|
}
 | 
						|
 | 
						|
method _rescan {{force 1}} {
 | 
						|
	switch $urltype {
 | 
						|
	remote {set uri $remote}
 | 
						|
	url    {set uri $url}
 | 
						|
	}
 | 
						|
 | 
						|
	if {$force} {
 | 
						|
		unset -nocomplain cached($urltype:$uri)
 | 
						|
	}
 | 
						|
 | 
						|
	if {$idle_id ne {}} {
 | 
						|
		after cancel $idle_id
 | 
						|
		set idle_id {}
 | 
						|
	}
 | 
						|
 | 
						|
	_load $this $urltype:$uri $uri
 | 
						|
}
 | 
						|
 | 
						|
method _write_remote     {args} { set urltype remote }
 | 
						|
method _write_url        {args} { set urltype url    }
 | 
						|
method _write_check_head {args} { set checktype head }
 | 
						|
 | 
						|
method _write_head_list {args} {
 | 
						|
	global current_branch _last_merged_branch
 | 
						|
 | 
						|
	$head_m delete 0 end
 | 
						|
	foreach abr $head_list {
 | 
						|
		$head_m insert end radiobutton \
 | 
						|
			-label $abr \
 | 
						|
			-value $abr \
 | 
						|
			-variable @check_head
 | 
						|
	}
 | 
						|
	if {[lsearch -exact -sorted $head_list $check_head] < 0} {
 | 
						|
		if {[lsearch -exact -sorted $head_list $current_branch] < 0} {
 | 
						|
			set check_head {}
 | 
						|
		} else {
 | 
						|
			set check_head $current_branch
 | 
						|
		}
 | 
						|
	}
 | 
						|
	set lmb [lsearch -exact -sorted $head_list $_last_merged_branch]
 | 
						|
	if {$lmb >= 0} {
 | 
						|
		$w.heads.l conf -state normal
 | 
						|
		$w.heads.l select set $lmb
 | 
						|
		$w.heads.l yview $lmb
 | 
						|
		$w.heads.l conf -state disabled
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
method _write_urltype {args} {
 | 
						|
	if {$urltype eq {url}} {
 | 
						|
		if {$idle_id ne {}} {
 | 
						|
			after cancel $idle_id
 | 
						|
		}
 | 
						|
		_load $this none: {}
 | 
						|
		set idle_id [after 1000 [cb _rescan 0]]
 | 
						|
	} else {
 | 
						|
		_rescan $this 0
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
method _load {cache uri} {
 | 
						|
	if {$active_ls ne {}} {
 | 
						|
		catch {close $active_ls}
 | 
						|
	}
 | 
						|
 | 
						|
	if {$uri eq {}} {
 | 
						|
		$w.heads.l conf -state disabled
 | 
						|
		set head_list [list]
 | 
						|
		set full_list [list]
 | 
						|
		set status [mc "No repository selected."]
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	if {[catch {set x $cached($cache)}]} {
 | 
						|
		set status [mc "Scanning %s..." $uri]
 | 
						|
		$w.heads.l conf -state disabled
 | 
						|
		set head_list [list]
 | 
						|
		set full_list [list]
 | 
						|
		set head_cache($cache) [list]
 | 
						|
		set full_cache($cache) [list]
 | 
						|
		set active_ls [git_read ls-remote $uri]
 | 
						|
		fconfigure $active_ls \
 | 
						|
			-blocking 0 \
 | 
						|
			-translation lf \
 | 
						|
			-encoding utf-8
 | 
						|
		fileevent $active_ls readable [cb _read $cache $active_ls]
 | 
						|
	} else {
 | 
						|
		set status {}
 | 
						|
		set full_list $full_cache($cache)
 | 
						|
		set head_list $head_cache($cache)
 | 
						|
		$w.heads.l conf -state normal
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
method _read {cache fd} {
 | 
						|
	if {$fd ne $active_ls} {
 | 
						|
		catch {close $fd}
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	while {[gets $fd line] >= 0} {
 | 
						|
		if {[string match {*^{}} $line]} continue
 | 
						|
		if {[regexp {^([0-9a-f]{40})	(.*)$} $line _junk obj ref]} {
 | 
						|
			if {[regsub ^refs/heads/ $ref {} abr]} {
 | 
						|
				lappend head_list $abr
 | 
						|
				lappend head_cache($cache) $abr
 | 
						|
				lappend full_list $ref
 | 
						|
				lappend full_cache($cache) $ref
 | 
						|
				set full_cache("$cache\n$ref") $obj
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if {[eof $fd]} {
 | 
						|
		if {[catch {close $fd} err]} {
 | 
						|
			set status $err
 | 
						|
			set head_list [list]
 | 
						|
			set full_list [list]
 | 
						|
		} else {
 | 
						|
			set status {}
 | 
						|
			set cached($cache) 1
 | 
						|
			$w.heads.l conf -state normal
 | 
						|
		}
 | 
						|
	}
 | 
						|
} ifdeleted {
 | 
						|
	catch {close $fd}
 | 
						|
}
 | 
						|
 | 
						|
}
 |