# Tcl Library for TkRev
#
#
# Current working directory display. Handles all of the functions
# concerned with navigating about the current directory on the main
# window.
#
proc workdir_setup {} {
global cwd
global module_dir
global cvscfg
global cvsglb
global current_tagname
global logclass
global tcl_platform
global incvs insvn inrcs ingit
gen_log:log T "ENTER"
set cwd [pwd]
set pid [pid]
if {[winfo exists .workdir]} {
wm deiconify .workdir
raise .workdir
return
}
# Make a new toplevel and unmap . so that the working directory browser
# the module browser are not in a parent-child relation
toplevel .workdir
wm title .workdir "TkRev Working Directory"
wm iconname .workdir "TkRev Working Directory"
wm iconphoto .workdir -default AppIcon
wm minsize .workdir 430 300
wm protocol .workdir WM_DELETE_WINDOW { .workdir.close invoke }
wm withdraw .
if {[info exists cvscfg(workgeom)]} {
wm geometry .workdir $cvscfg(workgeom)
}
menubar_menus .workdir
workdir_menus .workdir
help_menu .workdir
#
# Top section - where we are, where the module is
#
frame .workdir.top -relief groove -borderwidth 2
pack .workdir.top -side top -fill x
ttk::combobox .workdir.top.tcwd -textvariable cwd
.workdir.top.tcwd configure -values $cvsglb(directory)
bind .workdir.top.tcwd <KeyRelease> {set cwd [validate_dirpath %W $cwd]}
bind .workdir.top.tcwd <Return> {
if {[change_dir "$cwd"]} {%W configure -foreground black}
}
bind .workdir.top.tcwd <<ComboboxSelected>> {
if {[change_dir "$cwd"]} {%W configure -foreground black}
}
button .workdir.top.updir_btn -image updir \
-command {change_dir ..}
label .workdir.top.lmodule -text "Path"
label .workdir.top.tmodule -textvariable module_dir -anchor w -relief groove -bd 2
label .workdir.top.ltagname -text "Tag"
label .workdir.top.ttagname -textvariable current_tagname \
-anchor w -relief groove -bd 2
# Make the Repository Browser button prominent
button .workdir.top.bmodbrowse -image Modules -command modbrowse_run
label .workdir.top.lcvsroot -text "CVSROOT"
label .workdir.top.tcvsroot -textvariable cvscfg(cvsroot) \
-anchor w -relief groove -bd 2
grid columnconf .workdir.top 1 -weight 1
grid rowconf .workdir.top 3 -weight 1
grid .workdir.top.updir_btn -column 0 -row 0 -sticky s
grid .workdir.top.tcwd -column 1 -row 0 -columnspan 2 \
-sticky sew -padx 4 -pady 1
grid .workdir.top.lmodule -column 0 -row 1 -sticky nw
grid .workdir.top.tmodule -column 1 -row 1 -columnspan 2\
-padx 4 -pady 1 -sticky new
grid .workdir.top.bmodbrowse -column 2 -row 2 -rowspan 2 -sticky w
grid .workdir.top.ltagname -column 0 -row 2 -sticky nw
grid .workdir.top.ttagname -column 1 -row 2 -padx 4 -pady 1 -sticky new
grid .workdir.top.lcvsroot -column 0 -row 3 -sticky nw
grid .workdir.top.tcvsroot -column 1 -row 3 -padx 4 -sticky new
# Pack the bottom before the middle so it doesnt disappear if
# the window is resized smaller
frame .workdir.bottom
frame .workdir.bottom.filters -relief raised
pack .workdir.bottom -side bottom -fill x
pack .workdir.bottom.filters -side top -fill x
label .workdir.bottom.filters.showlbl -text "Show:" -anchor w
entry .workdir.bottom.filters.showentry -width 12 \
-textvariable cvscfg(show_file_filter)
label .workdir.bottom.filters.hidelbl -text " Hide:" -anchor w
entry .workdir.bottom.filters.hideentry -width 12 \
-textvariable cvscfg(ignore_file_filter)
label .workdir.bottom.filters.space -text " "
button .workdir.bottom.filters.cleanbutton -text "Clean:" \
-pady 0 -highlightthickness 0 \
-command workdir_cleanup
entry .workdir.bottom.filters.cleanentry -width 12 \
-textvariable cvscfg(clean_these)
label .workdir.bottom.filters.vcshidelbl -text " \[vcs\]ignore"
entry .workdir.bottom.filters.vcshideentry -width 12 -state readonly \
-textvariable cvsglb(vcs_hidden_files)
bind .workdir.bottom.filters.showentry <Return> {setup_dir}
bind .workdir.bottom.filters.hideentry <Return> {setup_dir}
bind .workdir.bottom.filters.cleanentry <Return> {workdir_cleanup}
pack .workdir.bottom.filters.showlbl -side left
pack .workdir.bottom.filters.showentry -side left
pack .workdir.bottom.filters.hidelbl -side left
pack .workdir.bottom.filters.hideentry -side left
pack .workdir.bottom.filters.space -side left
pack .workdir.bottom.filters.cleanbutton -side left -ipadx 2 -ipady 0
pack .workdir.bottom.filters.cleanentry -side left
pack .workdir.bottom.filters.vcshidelbl -side left
pack .workdir.bottom.filters.vcshideentry -side left
frame .workdir.bottom.buttons -relief groove -bd 2
frame .workdir.bottom.buttons.funcs -relief groove -bd 2
frame .workdir.bottom.buttons.dirfuncs -relief groove -bd 2
frame .workdir.bottom.buttons.cvsfuncs -relief groove -bd 2
frame .workdir.bottom.buttons.oddfuncs -relief groove -bd 2
frame .workdir.bottom.buttons.closefm
pack .workdir.bottom.buttons -side top -fill x -expand yes
pack .workdir.bottom.buttons.closefm -side right -expand yes
pack .workdir.bottom.buttons.funcs -side left -expand yes -anchor w
pack .workdir.bottom.buttons.dirfuncs -side left -expand yes -anchor w
pack .workdir.bottom.buttons.cvsfuncs -side left -expand yes -anchor w
pack .workdir.bottom.buttons.oddfuncs -side left -expand yes -anchor w
#
# Action buttons along the bottom of the screen.
#
button .workdir.bottom.buttons.funcs.bedit_files -image Fileedit \
-command { workdir_edit_file [workdir_list_files] }
button .workdir.bottom.buttons.funcs.bview_files -image Fileview \
-command { workdir_view_file [workdir_list_files] }
button .workdir.bottom.buttons.funcs.bdelete_file -image Delete \
-command { workdir_delete_file [workdir_list_files] }
button .workdir.bottom.buttons.funcs.bmkdir -image Dir_new \
-command { file_input_and_do "New Directory" workdir_newdir}
button .workdir.bottom.buttons.dirfuncs.brefresh -image Refresh \
-command { setup_dir }
button .workdir.bottom.buttons.dirfuncs.bcheckdir -image Check \
-command { cvs_check }
button .workdir.bottom.buttons.dirfuncs.patchdiff -image Patches
button .workdir.bottom.buttons.cvsfuncs.blogfile -image Branches \
-command { cvs_branches [workdir_list_files] }
button .workdir.bottom.buttons.cvsfuncs.bannotate -image Annotate \
-command { cvs_annotate $current_tagname [workdir_list_files] }
button .workdir.bottom.buttons.cvsfuncs.bfilelog -image Log \
-command { cvs_log verbose [workdir_list_files] }
button .workdir.bottom.buttons.cvsfuncs.bdiff -image Diff \
-command { comparediff [workdir_list_files] }
button .workdir.bottom.buttons.cvsfuncs.bconflict -image Conflict \
-command { cvs_reconcile_conflict [workdir_list_files] }
button .workdir.bottom.buttons.cvsfuncs.btag -image Tag \
-command { tag_dialog }
button .workdir.bottom.buttons.cvsfuncs.bbranchtag -image Branchtag \
-command { branch_dialog }
button .workdir.bottom.buttons.cvsfuncs.badd_files -image Add \
-command { add_dialog [workdir_list_files] }
button .workdir.bottom.buttons.cvsfuncs.bremove -image Remove \
-command { subtract_dialog [workdir_list_files] }
button .workdir.bottom.buttons.cvsfuncs.bcheckin -image Checkin \
-command cvs_commit_dialog
button .workdir.bottom.buttons.cvsfuncs.bupdate -image Checkout
button .workdir.bottom.buttons.cvsfuncs.bupdateopts -image CheckoutOpts \
-command { cvs_update_options }
button .workdir.bottom.buttons.cvsfuncs.brevert -image Revert \
-command { cvs_revert [workdir_list_files] }
button .workdir.bottom.buttons.cvsfuncs.bjoin -image DirBranches \
-image DirBranches -command cvs_joincanvas
button .workdir.bottom.buttons.oddfuncs.bcvsedit_files -image Edit \
-command { edit_dialog [workdir_list_files] }
button .workdir.bottom.buttons.oddfuncs.bunedit_files -image Unedit \
-command { unedit_dialog [workdir_list_files] }
button .workdir.bottom.buttons.oddfuncs.block -image Lock
button .workdir.bottom.buttons.oddfuncs.bunlock -image UnLock
button .workdir.bottom.buttons.oddfuncs.bpush -image Checkin \
-command { git_push }
button .workdir.bottom.buttons.oddfuncs.bfetch -image Checkout \
-command { git_fetch }
button .workdir.close -text "Close" \
-command {
global cvscfg
set cvscfg(workgeom) [wm geometry .workdir]
destroy .workdir
exit_cleanup 0
}
# These buttons work in any directory
grid .workdir.bottom.buttons.funcs.bdelete_file -column 0 -row 0 -ipadx 4
grid .workdir.bottom.buttons.funcs.bedit_files -column 1 -row 0 -ipadx 4
grid .workdir.bottom.buttons.funcs.bmkdir -column 0 -row 1 -ipadx 4
grid .workdir.bottom.buttons.funcs.bview_files -column 1 -row 1 -ipadx 4
# Directory functions
grid rowconf .workdir.bottom.buttons.dirfuncs 0 -weight 1
grid .workdir.bottom.buttons.dirfuncs.brefresh -column 0 -row 0 -ipadx 4 -ipady 4
grid .workdir.bottom.buttons.dirfuncs.bcheckdir -column 1 -row 0 -ipadx 4 -ipady 4
grid .workdir.bottom.buttons.dirfuncs.patchdiff -column 2 -row 0 -ipadx 4 -ipady 4
# Revcontrol functions
grid .workdir.bottom.buttons.cvsfuncs.blogfile -column 0 -row 0 -ipadx 4
grid .workdir.bottom.buttons.cvsfuncs.bjoin -column 0 -row 1 -ipadx 4
grid .workdir.bottom.buttons.cvsfuncs.bdiff -column 1 -row 0 -ipadx 2
grid .workdir.bottom.buttons.cvsfuncs.bconflict -column 1 -row 1 -ipadx 2
grid .workdir.bottom.buttons.cvsfuncs.bfilelog -column 2 -row 0
grid .workdir.bottom.buttons.cvsfuncs.bannotate -column 2 -row 1
grid .workdir.bottom.buttons.cvsfuncs.bupdate -column 3 -row 0 -ipadx 4
grid .workdir.bottom.buttons.cvsfuncs.bcheckin -column 3 -row 1 -ipadx 4
grid .workdir.bottom.buttons.cvsfuncs.bupdateopts -column 4 -row 0 -ipadx 4
grid .workdir.bottom.buttons.cvsfuncs.brevert -column 4 -row 1 -ipadx 4
grid .workdir.bottom.buttons.cvsfuncs.badd_files -column 5 -row 0
grid .workdir.bottom.buttons.cvsfuncs.bremove -column 5 -row 1
grid .workdir.bottom.buttons.cvsfuncs.btag -column 6 -row 0 -ipadx 4
grid .workdir.bottom.buttons.cvsfuncs.bbranchtag -column 6 -row 1 -ipadx 4
grid .workdir.bottom.buttons.oddfuncs.block -column 0 -row 0
grid .workdir.bottom.buttons.oddfuncs.bunlock -column 0 -row 1
grid .workdir.bottom.buttons.oddfuncs.bcvsedit_files -column 1 -row 0
grid .workdir.bottom.buttons.oddfuncs.bunedit_files -column 1 -row 1
pack .workdir.close -in .workdir.bottom.buttons.closefm \
-side right -fill both -expand yes
set_tooltips .workdir.top.updir_btn \
{"Go up (..)"}
set_tooltips .workdir.bottom.buttons.funcs.bedit_files \
{"Edit the selected files"}
set_tooltips .workdir.bottom.buttons.funcs.bview_files \
{"View the selected files"}
set_tooltips .workdir.bottom.buttons.funcs.bdelete_file \
{"Delete the selected files from the current directory"}
set_tooltips .workdir.bottom.buttons.funcs.bmkdir \
{"Make a new directory"}
set_tooltips .workdir.bottom.buttons.dirfuncs.brefresh \
{"Re-read the current directory"}
set_tooltips .workdir.bottom.buttons.cvsfuncs.bjoin \
{"Directory Branch Diagram and Merge Tool"}
set_tooltips .workdir.bottom.buttons.dirfuncs.bcheckdir \
{"Check the status of the directory"}
set_tooltips .workdir.bottom.buttons.dirfuncs.patchdiff \
{"Show diffs in the changed files"}
set_tooltips .workdir.bottom.buttons.cvsfuncs.blogfile \
{"Graphical Branch Diagram of the selected files"}
set_tooltips .workdir.bottom.buttons.cvsfuncs.bfilelog \
{"Revision log of the selected files"}
set_tooltips .workdir.bottom.buttons.cvsfuncs.bannotate \
{"Revision where each line was modified (annotate/blame)"}
set_tooltips .workdir.bottom.buttons.cvsfuncs.bdiff \
{"Side-by-side comparison of files to the committed version"}
set_tooltips .workdir.bottom.buttons.cvsfuncs.bconflict \
{"Merge Conflicts using TkDiff"}
set_tooltips .workdir.bottom.buttons.cvsfuncs.btag \
{"Tag the selected files"}
set_tooltips .workdir.bottom.buttons.cvsfuncs.bbranchtag \
{"Branch the selected files"}
set_tooltips .workdir.bottom.buttons.cvsfuncs.bupdateopts \
{"Update with options (-A, -r, -f, -d, -kb)"}
set_tooltips .workdir.bottom.buttons.oddfuncs.block \
{"Lock the selected files"}
set_tooltips .workdir.bottom.buttons.oddfuncs.bunlock \
{"Unlock the selected files"}
set_tooltips .workdir.bottom.buttons.oddfuncs.bcvsedit_files \
{"Set the Edit flag on the selected files"}
set_tooltips .workdir.bottom.buttons.oddfuncs.bunedit_files \
{"Unset the Edit flag on the selected files"}
set_tooltips .workdir.bottom.buttons.oddfuncs.bpush \
{"Push to origin"}
set_tooltips .workdir.bottom.buttons.oddfuncs.bfetch \
{"Fetch from origin"}
set_tooltips .workdir.top.bmodbrowse \
{"Open the Repository Browser"}
set_tooltips .workdir.close \
{"Close the Working Directory Browser"}
frame .workdir.main
pack .workdir.main -side bottom -fill both -expand 1 -fill both
update idletasks
if {! [winfo ismapped .workdir]} {
wm deiconify .workdir
}
setup_dir
gen_log:log T "LEAVE"
}
# Returns a list of the selected file names. This is where the arg-list comes
# from for most of the UI buttons and menus.
proc workdir_list_files {} {
global DirList
global cvsglb
set wt .workdir.main.tree
set cvsglb(current_selection) {}
set DirList($wt:selection) {}
set selected_items [$wt selection]
foreach s $selected_items {
set f [$wt set $s filecol]
lappend DirList($wt:selection) "$f"
}
set cvsglb(current_selection) $DirList($wt:selection)
gen_log:log T "LEAVE -- ($cvsglb(current_selection))"
return $cvsglb(current_selection)
}
proc workdir_edit_command {file} {
global cvscfg
gen_log:log T "ENTER ($file)"
if {[info exists cvscfg(editors)]} {
foreach {editor pattern} $cvscfg(editors) {
if {[string match $pattern $file]} {
return "$editor \"$file\""
}
}
}
return "$cvscfg(editor) \"$file\""
}
proc workdir_newdir {file} {
global cvscfg
gen_log:log T "ENTER ($file)"
if [catch {file mkdir $file} err] {
cvsfail "$err" .workdir
return
}
gen_log:log F "mkdir $file"
if {$cvscfg(auto_status)} {
setup_dir
}
gen_log:log T "LEAVE"
}
proc workdir_edit_file {args} {
global cwd
gen_log:log T "ENTER ($args)"
set filelist [join $args]
if {$filelist == ""} {
file_input_and_do "Edit File" workdir_edit_file
return
}
gen_log:log D "$filelist"
foreach file $filelist {
if {[file isdirectory $file]} {
change_dir "$file"
return
}
if {![file exists "$file"]} {
cvsfail "$file does not exist" .workdir
return
}
if {![file isfile "$file"]} {
cvsfail "$file is not a plain file" .workdir
return
}
regsub -all {\$} $file {\$} file
set commandline [workdir_edit_command $file]
set editcmd [exec::new $commandline]
}
gen_log:log T "LEAVE"
}
proc workdir_view_file {args} {
global cwd
gen_log:log T "ENTER ($args)"
set filelist [join $args]
if {$filelist == ""} {
cvsfail "Please select some files to view first!" .workdir
return
}
gen_log:log D "$filelist"
foreach file $filelist {
set filelog ""
if {![file exists $file]} {
cvsfail "$file does not exist" .workdir
return
}
if {![file isfile $file]} {
cvsfail "$file is not a plain file" .workdir
return
}
#regsub -all {\$} $file {\$} file
gen_log:log F "OPEN $file"
set f [open $file]
while { [eof $f] == 0 } {
append filelog [gets $f]
append filelog "\n"
}
view_output::new "$file" $filelog
}
gen_log:log T "LEAVE"
}
# Let the user mark directories they visit often
proc add_bookmark { } {
global incvs inrcs insvn ingit
global bookmarks
gen_log:log T "ENTER"
set dir [pwd]
regsub -all {\$} $dir {\$} dir
gen_log:log D "directory $dir"
foreach mark [array names bookmarks] {
gen_log:log D " $mark \"$bookmarks($mark)\""
}
if {[info exists bookmarks($dir)]} {
.workdir.menubar.goto delete "$dir $bookmarks($dir)"
}
set rtype ""
if {$inrcs} {
set rtype "(RCS)"
} elseif {$incvs} {
set rtype "(CVS)"
} elseif {$insvn} {
set rtype "(SVN)"
} elseif {$ingit} {
set rtype "(GIT)"
}
set bookmarks($dir) $rtype
.workdir.menubar.goto add command -label "$dir $rtype" \
-command "change_dir \"$dir\""
gen_log:log T "LEAVE"
}
# A listbox to choose a bookmark to delete
proc delete_bookmark_dialog { } {
global cvsglb
global colorglb
global bookmarks
gen_log:log T "ENTER"
set maxlbl 0
foreach mark [array names bookmarks] {
gen_log:log D " $mark $bookmarks($mark)"
set len [string length "$mark $bookmarks($mark)"]
if {$len > $maxlbl} {
set maxlbl $len
}
}
set wname .workdir.bookmarkedit
toplevel $wname
grab set $wname
wm title $wname "Delete Bookmarks"
listbox $wname.lbx -selectmode multiple \
-font $colorglb(listboxfont) -width $maxlbl
pack $wname.lbx -ipadx 10 -ipady 10 -expand y -fill both
foreach mark [lsort [array names bookmarks]] {
$wname.lbx insert end "$mark $bookmarks($mark)"
}
frame $wname.buttons
pack $wname.buttons -side top -fill x
button $wname.delete -text "Delete" \
-command "delete_bookmark $wname"
button $wname.close -text "Done" \
-command "
grab release $wname
destroy $wname
exit_cleanup 0"
pack $wname.delete $wname.close -in $wname.buttons \
-side right -ipadx 2 -ipady 2 -padx 4 -pady 4 \
-expand y
gen_log:log T "LEAVE"
}
# Do the actual deletion of the bookmark
proc delete_bookmark {w} {
global bookmarks
gen_log:log T "ENTER ($w)"
set items [$w.lbx curselection]
foreach item $items {
set itemstring [$w.lbx get $item]
#set dir [join [lrange $itemstring 0 end-1]]
regsub {\s+$} $itemstring {} dir
regsub {\s+\([A-Z][A-Z][A-Z]\)$} $dir {} dir
gen_log:log D "$item \"$itemstring\""
gen_log:log D " directory \"$dir\""
unset bookmarks($dir)
$w.lbx delete $item
.workdir.menubar.goto delete $itemstring
}
gen_log:log T "LEAVE"
}
proc auto_setup_dir {command} {
global cvscfg
if {$cvscfg(auto_status)} {
$command\::wait
setup_dir
} else {
after 0 "$command\::wait; $command\::destroy"
}
}
proc setup_dir { } {
#
# Call this when entering a directory. It puts all of the file names
# in the listbox, and reads the directory.
#
global cwd
global env
global module_dir
global incvs insvn inrcs ingit
global cvscfg
global cvsglb
global current_tagname
gen_log:log T "ENTER"
set savyview 0
if { ! [winfo exists .workdir.main] } {
workdir_setup
return
} else {
if {[winfo exists .workdir.main.filecol.list]} {
set savyview [lindex [.workdir.main.filecol.list yview] 0]
}
DirCanvas:deltree .workdir.main.tree
}
set module_dir ""
set current_tagname ""
set cvsglb(vcs_hidden_files) {}
lassign [vcs_detect [pwd]] incvs insvn inrcs ingit
gen_log:log D "incvs=$incvs inrcs=$inrcs insvn=$insvn ingit=$ingit"
.workdir.top.bmodbrowse configure -image Modules
.workdir.top.lmodule configure -text "Path"
.workdir.top.ltagname configure -text "Branch/Tag"
.workdir.top.lcvsroot configure -text "Repository"
.workdir.top.tcvsroot configure -textvariable cvscfg(cvsroot)
set cvsglb(root) $cvscfg(cvsroot)
set cvsglb(vcs) cvs
# Start without revision-control menu
gen_log:log D "CONFIGURE VCS MENUS"
foreach label {"RCS" "CVS" "SVN" "GIT" "Git Tools" "Import"} {
if {! [catch {set vcsmenu_idx [.workdir.menubar index "$label"]}]} {
.workdir.menubar delete $vcsmenu_idx
}
}
set filemenu_idx [.workdir.menubar index "File"]
# Disable report menu items
.workdir.menubar.reports entryconfigure "Check Directory" -state disabled
.workdir.menubar.reports entryconfigure "Status" -state disabled
.workdir.menubar.reports entryconfigure "Log" -state disabled
.workdir.menubar.reports entryconfigure "Info" -state disabled
# Start with the revision-control buttons disabled
.workdir.bottom.filters.vcshidelbl configure -text "VCS hidden:"
.workdir.bottom.buttons.dirfuncs.bcheckdir configure -state disabled
.workdir.bottom.buttons.dirfuncs.patchdiff configure -state disabled
foreach widget [grid slaves .workdir.bottom.buttons.cvsfuncs ] {
$widget configure -state disabled
}
foreach widget [grid slaves .workdir.bottom.buttons.cvsfuncs ] {
$widget configure -state disabled
}
foreach widget [grid slaves .workdir.bottom.buttons.oddfuncs ] {
#$widget configure -state disabled
grid forget $widget
}
# Default for these, only Git is different
.workdir.bottom.buttons.cvsfuncs.bcheckin configure -state disabled \
-image Checkin
.workdir.bottom.buttons.cvsfuncs.bupdate configure -state disabled \
-image Checkout
set_tooltips .workdir.bottom.buttons.cvsfuncs.bjoin \
{"Directory Branch Diagram and Merge Tool"}
set_tooltips .workdir.bottom.buttons.cvsfuncs.badd_files \
{"Add the selected files to the repository"}
set_tooltips .workdir.bottom.buttons.cvsfuncs.bremove \
{"Remove the selected files from the repository"}
set_tooltips .workdir.bottom.buttons.cvsfuncs.bcheckin \
{"Check in (commit) the selected files to the repository"}
set_tooltips .workdir.bottom.buttons.cvsfuncs.bupdate \
{"Update (checkout, patch) the selected files from the repository"}
set_tooltips .workdir.bottom.buttons.cvsfuncs.brevert \
{"Revert the selected files, discarding local edits"}
# Now enable them depending on where we are
if {$inrcs} {
# Top
gen_log:log D "CONFIGURE RCS MENUS"
.workdir.menubar insert [expr {$filemenu_idx + 1}] cascade -label "RCS" \
-menu .workdir.menubar.rcs
.workdir.top.bmodbrowse configure -image Modules -command modbrowse_run
.workdir.top.lcvsroot configure -text "RCS Path"
.workdir.top.tcvsroot configure -textvariable cvscfg(rcsdir)
set cvsglb(root) $cvscfg(rcsdir)
set cvsglb(vcs) rcs
# Buttons
.workdir.bottom.buttons.funcs.bview_files configure \
-command { workdir_view_file [workdir_list_files] }
.workdir.bottom.buttons.dirfuncs.bcheckdir configure -state normal \
-command { rcs_check }
.workdir.bottom.buttons.cvsfuncs.bdiff configure -state normal
.workdir.bottom.buttons.cvsfuncs.blogfile configure -state normal \
-command { rcs_branches [workdir_list_files] }
.workdir.bottom.buttons.cvsfuncs.bfilelog configure -state normal \
-command { rcs_log "verbose" [workdir_list_files] }
.workdir.bottom.buttons.cvsfuncs.bupdate configure -state normal \
-command { rcs_checkout [workdir_list_files] }
.workdir.bottom.buttons.cvsfuncs.bcheckin configure -state normal \
-command { rcs_commit_dialog [workdir_list_files] }
.workdir.bottom.buttons.cvsfuncs.brevert configure -state normal \
-command { rcs_revert [workdir_list_files] }
grid .workdir.bottom.buttons.oddfuncs.block -column 0 -row 0
grid .workdir.bottom.buttons.oddfuncs.bunlock -column 0 -row 1
.workdir.bottom.buttons.oddfuncs.block configure -state normal \
-command { rcs_lock lock [workdir_list_files] }
.workdir.bottom.buttons.oddfuncs.bunlock configure -state normal \
-command { rcs_lock unlock [workdir_list_files] }
# Reports menu for RCS
# Check Directory (log & rdiff)
.workdir.menubar.reports entryconfigure "Check Directory" -state normal \
-command { rcs_check }
.workdir.menubar.reports entryconfigure "Status" -state disabled
# Log (rlog)
.workdir.menubar.reports entryconfigure "Log" -state normal
.workdir.menubar.reports.log_detail entryconfigure "Latest" \
-command { rcs_log "latest" [workdir_list_files] }
.workdir.menubar.reports.log_detail entryconfigure "Summary" \
-command { rcs_log "summary" [workdir_list_files] }
.workdir.menubar.reports.log_detail entryconfigure "Verbose" \
-command { rcs_log "verbose" [workdir_list_files] }
.workdir.menubar.reports entryconfigure "Info" -state disabled
# Options for reports
.workdir.menubar.reports entryconfigure "Report Unknown Files" -state disabled
.workdir.menubar.reports entryconfigure "Report Recursively" -state disabled
} elseif {$insvn} {
# Top
gen_log:log D "CONFIGURE SVN MENUS"
.workdir.menubar insert [expr {$filemenu_idx + 1}] cascade -label "SVN" \
-menu .workdir.menubar.svn
.workdir.top.bmodbrowse configure -image Modules_svn -command modbrowse_run
.workdir.top.lmodule configure -text "Path"
.workdir.top.ltagname configure -text "Tag"
.workdir.top.lcvsroot configure -text "SVN URL"
.workdir.top.tcvsroot configure -textvariable cvscfg(url)
set cvsglb(root) $cvscfg(url)
set cvsglb(vcs) svn
# Buttons
.workdir.bottom.buttons.funcs.bview_files configure \
-command { workdir_view_file [workdir_list_files] }
.workdir.bottom.buttons.dirfuncs.bcheckdir configure -state normal \
-command { svn_check }
.workdir.bottom.buttons.dirfuncs.patchdiff configure -state normal \
-command { svn_patch $cvscfg(url) {} {} {} {} {} 0 {} }
.workdir.bottom.buttons.cvsfuncs.bjoin configure -state normal \
-image DirBranches -command { svn_branches . }
.workdir.bottom.buttons.cvsfuncs.bdiff configure -state normal
.workdir.bottom.buttons.cvsfuncs.blogfile configure -state normal \
-command { svn_branches [workdir_list_files] }
.workdir.bottom.buttons.cvsfuncs.bfilelog configure -state normal \
-command { svn_log "verbose" [workdir_list_files] }
.workdir.bottom.buttons.cvsfuncs.bannotate configure -state normal \
-command { svn_annotate rBASE [workdir_list_files] }
.workdir.bottom.buttons.cvsfuncs.bconflict configure -state normal \
-command { foreach f [workdir_list_files] {svn_reconcile_conflict \"$f\"} }
.workdir.bottom.buttons.cvsfuncs.badd_files configure -state normal
.workdir.bottom.buttons.cvsfuncs.bremove configure -state normal
.workdir.bottom.buttons.cvsfuncs.bupdate configure -state normal \
-command { svn_update [workdir_list_files] }
.workdir.bottom.buttons.cvsfuncs.bupdateopts configure -state normal \
-command { svn_update_options }
.workdir.bottom.buttons.cvsfuncs.bcheckin configure -state normal \
-command svn_commit_dialog
.workdir.bottom.buttons.cvsfuncs.brevert configure -state normal \
-command { svn_revert [workdir_list_files] }
.workdir.bottom.buttons.cvsfuncs.btag configure -state normal
.workdir.bottom.buttons.cvsfuncs.bbranchtag configure -state normal
grid .workdir.bottom.buttons.oddfuncs.block -column 0 -row 0
grid .workdir.bottom.buttons.oddfuncs.bunlock -column 0 -row 1
.workdir.bottom.buttons.oddfuncs.block configure -state normal \
-command { svn_lock lock [workdir_list_files] }
.workdir.bottom.buttons.oddfuncs.bunlock configure -state normal \
-command { svn_lock unlock [workdir_list_files] }
# Reports menu for SVN
# Check Directory (svn status)
.workdir.menubar.reports entryconfigure "Check Directory" -state normal \
-command { svn_check }
# Status (svn status <filelist>)
.workdir.menubar.reports entryconfigure "Status" -state normal
.workdir.menubar.reports.status_detail entryconfigure "Terse" \
-command { svn_status "terse" [workdir_list_files] }
.workdir.menubar.reports.status_detail entryconfigure "Summary" \
-command { svn_status "summary" [workdir_list_files] }
.workdir.menubar.reports.status_detail entryconfigure "Verbose" \
-command { svn_status "verbose" [workdir_list_files] }
# Log (svn log)
.workdir.menubar.reports entryconfigure "Log" -state normal
.workdir.menubar.reports.log_detail entryconfigure "Latest" \
-command { svn_log "latest" [workdir_list_files] }
.workdir.menubar.reports.log_detail entryconfigure "Summary" \
-command { svn_log "summary" [workdir_list_files] }
.workdir.menubar.reports.log_detail entryconfigure "Verbose" \
-command { svn_log "verbose" [workdir_list_files] }
# General info (svn info)
.workdir.menubar.reports entryconfigure "Info" -state normal \
-command { svn_info [workdir_list_files] }
# Options for reports
.workdir.menubar.reports entryconfigure "Report Unknown Files" -state normal
.workdir.menubar.reports entryconfigure "Report Recursively" -state normal
} elseif {$incvs} {
# Top
gen_log:log D "CONFIGURE CVS MENUS"
.workdir.menubar insert [expr {$filemenu_idx + 1}] cascade -label "CVS" \
-menu .workdir.menubar.cvs
.workdir.top.bmodbrowse configure -image Modules_cvs -command modbrowse_run
.workdir.top.lmodule configure -text "Module"
.workdir.top.ltagname configure -text "Tag"
.workdir.top.lcvsroot configure -text "CVSROOT"
.workdir.top.tcvsroot configure -textvariable cvscfg(cvsroot)
set cvsglb(root) $cvscfg(cvsroot)
set cvsglb(vcs) cvs
# Buttons
.workdir.bottom.buttons.funcs.bview_files configure \
-command { workdir_view_file [workdir_list_files] }
.workdir.bottom.buttons.dirfuncs.bcheckdir configure -state normal \
-command { cvs_check }
.workdir.bottom.buttons.dirfuncs.patchdiff configure -state normal \
-command { cvs_diff }
.workdir.bottom.buttons.cvsfuncs.bjoin configure -state normal \
-image DirBranches -command cvs_joincanvas
.workdir.bottom.buttons.cvsfuncs.bdiff configure -state normal
.workdir.bottom.buttons.cvsfuncs.bconflict configure -state normal \
-command { cvs_reconcile_conflict [workdir_list_files] }
.workdir.bottom.buttons.cvsfuncs.bfilelog configure -state normal \
-command { cvs_log "verbose" [workdir_list_files] }
.workdir.bottom.buttons.cvsfuncs.bannotate configure -state normal \
-command { cvs_annotate $current_tagname [workdir_list_files] }
.workdir.bottom.buttons.cvsfuncs.badd_files configure -state normal
.workdir.bottom.buttons.cvsfuncs.bremove configure -state normal
.workdir.bottom.buttons.cvsfuncs.bupdate configure -state normal \
-command { \
cvs_update {BASE} {Normal} {Remove} {recurse} {prune} {No} { } [workdir_list_files] }
.workdir.bottom.buttons.cvsfuncs.bupdateopts configure -state normal \
-command { cvs_update_options }
.workdir.bottom.buttons.cvsfuncs.bcheckin configure -state normal \
-command cvs_commit_dialog
.workdir.bottom.buttons.cvsfuncs.brevert configure -state normal \
-command {cvs_revert [workdir_list_files] }
.workdir.bottom.buttons.cvsfuncs.btag configure -state normal
.workdir.bottom.buttons.cvsfuncs.bbranchtag configure -state normal
.workdir.bottom.buttons.cvsfuncs.blogfile configure -state normal \
-command { cvs_branches [workdir_list_files] }
grid .workdir.bottom.buttons.oddfuncs.block -column 0 -row 0
grid .workdir.bottom.buttons.oddfuncs.bunlock -column 0 -row 1
grid .workdir.bottom.buttons.oddfuncs.bcvsedit_files -column 1 -row 0
grid .workdir.bottom.buttons.oddfuncs.bunedit_files -column 1 -row 1
if {$cvscfg(econtrol)} {
.workdir.bottom.buttons.oddfuncs.bcvsedit_files configure -state normal
.workdir.bottom.buttons.oddfuncs.bunedit_files configure -state normal
} else {
.workdir.bottom.buttons.oddfuncs.bcvsedit_files configure -state disabled
.workdir.bottom.buttons.oddfuncs.bunedit_files configure -state disabled
}
if {$cvscfg(cvslock)} {
.workdir.bottom.buttons.oddfuncs.block configure -state normal \
-command { cvs_lock lock [workdir_list_files] }
.workdir.bottom.buttons.oddfuncs.bunlock configure -state normal \
-command { cvs_lock unlock [workdir_list_files] }
} else {
.workdir.bottom.buttons.oddfuncs.block configure -state disabled
.workdir.bottom.buttons.oddfuncs.bunlock configure -state disabled
}
# Reports menu for CVS
# Check Directory (cvs -n -q update)
.workdir.menubar.reports entryconfigure "Check Directory" -state normal \
-command { cvs_check }
# Status (cvs -Q status)
.workdir.menubar.reports entryconfigure "Status" -state normal
.workdir.menubar.reports.status_detail entryconfigure "Terse" \
-command { cvs_status "terse" [workdir_list_files] }
.workdir.menubar.reports.status_detail entryconfigure "Summary" \
-command { cvs_status "summary" [workdir_list_files] }
.workdir.menubar.reports.status_detail entryconfigure "Verbose" \
-command { cvs_status "verbose" [workdir_list_files] }
# Log (cvs log)
.workdir.menubar.reports entryconfigure "Log" -state normal
.workdir.menubar.reports.log_detail entryconfigure "Latest" \
-command { cvs_log "latest" [workdir_list_files] }
.workdir.menubar.reports.log_detail entryconfigure "Summary" \
-command { cvs_log "summary" [workdir_list_files] }
.workdir.menubar.reports.log_detail entryconfigure "Verbose" \
-command { cvs_log "verbose" [workdir_list_files] }
.workdir.menubar.reports entryconfigure "Info" -state disabled
# Options for reports
.workdir.menubar.reports entryconfigure "Report Unknown Files" -state normal
.workdir.menubar.reports entryconfigure "Report Recursively" -state normal
} elseif {$ingit} {
# Top
gen_log:log D "CONFIGURE GIT MENUS"
.workdir.menubar insert [expr {$filemenu_idx + 1}] cascade -label "GIT" \
-menu .workdir.menubar.git
.workdir.menubar insert [expr {$filemenu_idx + 4}] cascade -label "Git Tools" \
-menu .workdir.menubar.gittools
.workdir.top.bmodbrowse configure -image Modules_git -command modbrowse_run
.workdir.top.lmodule configure -text "path"
.workdir.top.ltagname configure -text "branch"
.workdir.top.lcvsroot configure -text "$cvscfg(origin)"
.workdir.top.tcvsroot configure -textvariable cvscfg(url)
set cvsglb(root) $cvscfg(url)
set cvsglb(vcs) git
# Buttons
.workdir.bottom.buttons.funcs.bview_files configure \
-command { workdir_view_file [workdir_list_files] }
.workdir.bottom.buttons.dirfuncs.bcheckdir configure -state normal \
-command { git_check }
.workdir.bottom.buttons.dirfuncs.patchdiff configure -state normal \
-command { git_patch "" }
.workdir.bottom.buttons.cvsfuncs.bdiff configure -state normal
.workdir.bottom.buttons.cvsfuncs.bconflict configure -state normal \
-command { foreach f [workdir_list_files] {git_reconcile_conflict \"$f\"} }
.workdir.bottom.buttons.cvsfuncs.blogfile configure -state normal \
-command { git_branches [workdir_list_files] }
.workdir.bottom.buttons.cvsfuncs.bjoin configure -state normal \
-image BranchNo -command { git_fast_diagram [workdir_list_files] }
.workdir.bottom.buttons.cvsfuncs.bfilelog configure -state normal \
-command { git_log "verbose" [workdir_list_files] }
.workdir.bottom.buttons.cvsfuncs.bannotate configure -state normal \
-command { git_annotate $current_tagname [workdir_list_files] }
.workdir.bottom.buttons.cvsfuncs.bcheckin configure -state normal \
-image GitCheckin -command { git_commit_dialog }
.workdir.bottom.buttons.cvsfuncs.brevert configure -state normal \
-command { git_reset [workdir_list_files] }
.workdir.bottom.buttons.cvsfuncs.bupdate configure -state normal \
-image GitCheckout -command { git_checkout [workdir_list_files] }
.workdir.bottom.buttons.cvsfuncs.bupdateopts configure -state normal \
-command { git_update_options }
.workdir.bottom.buttons.cvsfuncs.badd_files configure -state normal
.workdir.bottom.buttons.cvsfuncs.bremove configure -state normal
.workdir.bottom.buttons.cvsfuncs.btag configure -state normal
.workdir.bottom.buttons.cvsfuncs.bbranchtag configure -state normal
grid .workdir.bottom.buttons.oddfuncs.bpush -column 0 -row 0
grid .workdir.bottom.buttons.oddfuncs.bfetch -column 0 -row 1
.workdir.bottom.buttons.oddfuncs.block configure -state normal \
-command { rcs_lock lock [workdir_list_files] }
.workdir.bottom.buttons.oddfuncs.bunlock configure -state normal \
-command { rcs_lock unlock [workdir_list_files] }
set_tooltips .workdir.bottom.buttons.cvsfuncs.bjoin \
{"Fast log diagram"}
set_tooltips .workdir.bottom.buttons.cvsfuncs.badd_files \
{"Add the selected files to the staging area"}
set_tooltips .workdir.bottom.buttons.cvsfuncs.bremove \
{"Remove the selected files from the staging area"}
set_tooltips .workdir.bottom.buttons.cvsfuncs.bcheckin \
{"Check in (commit) the selected files to the staging area"}
set_tooltips .workdir.bottom.buttons.cvsfuncs.bupdate \
{"Update (checkout, patch) the selected files from the staging area"}
set_tooltips .workdir.bottom.buttons.cvsfuncs.brevert \
{"Reset, discarding local edits"}
# Reports menu for GIT
# Check Directory (git status --short)
.workdir.menubar.reports entryconfigure "Check Directory" -state normal \
-command { git_check }
# Status (git status -v)
.workdir.menubar.reports entryconfigure "Status" -state normal
.workdir.menubar.reports.status_detail entryconfigure "Terse" \
-command { git_status "terse" [workdir_list_files] }
.workdir.menubar.reports.status_detail entryconfigure "Summary" \
-command { git_status "summary" [workdir_list_files] }
.workdir.menubar.reports.status_detail entryconfigure "Verbose" \
-command { git_status "verbose" [workdir_list_files] }
# Log (git log)
.workdir.menubar.reports entryconfigure "Log" -state normal
.workdir.menubar.reports.log_detail entryconfigure "Latest" \
-command { git_log "latest" [workdir_list_files] }
.workdir.menubar.reports.log_detail entryconfigure "Summary" \
-command { git_log "summary" [workdir_list_files] }
.workdir.menubar.reports.log_detail entryconfigure "Verbose" \
-command { git_log "verbose" [workdir_list_files] }
.workdir.menubar.reports entryconfigure "Info" -state disabled
# Options for reports
.workdir.menubar.reports entryconfigure "Report Unknown Files" -state normal
.workdir.menubar.reports entryconfigure "Report Recursively" -state disabled
} else {
.workdir.menubar insert [expr {$filemenu_idx + 1}] cascade -label "Import" \
-menu .workdir.menubar.import
}
picklist_used directory "[pwd]"
# Have to do this to display the new value in the list
.workdir.top.tcwd configure -values $cvsglb(directory)
DirCanvas:create .workdir.main
pack .workdir.main.pw -side bottom -fill both -expand yes
set cvsglb(current_selection) {}
# Check for VCS-specific ignore filters
if {$incvs} {
.workdir.bottom.filters.vcshidelbl configure -text " .cvsignore"
if { [ file exists ".cvsignore" ] } {
set fileId [ open ".cvsignore" "r" ]
while { [ eof $fileId ] == 0 } {
gets $fileId line
append cvsglb(vcs_hidden_files) " $line"
}
close $fileId
}
} elseif {$insvn} {
.workdir.bottom.filters.vcshidelbl configure -text " svn:ignore"
# Have to do eval exec because we need the error output
set command "svn propget svn:ignore ."
gen_log:log C "$command"
set ret [catch {exec {*}$command} output]
if {$ret} {
gen_log:log E "$output"
} else {
gen_log:log F "$output"
foreach infoline [split $output "\n"] {
append cvsglb(vcs_hidden_files) " $infoline"
}
}
} elseif {$ingit} {
.workdir.bottom.filters.vcshidelbl configure -text " .gitignore"
if { [ file exists ".gitignore" ] } {
set fileId [ open ".gitignore" "r" ]
while { [ eof $fileId ] == 0 } {
gets $fileId line
append cvsglb(vcs_hidden_files) " $line"
}
close $fileId
}
}
set filelist [ getFiles ]
directory_list $filelist
# Update, otherwise it won't be mapped before we restore the scroll position
update
gen_log:log T "LEAVE"
}
proc directory_list { filenames } {
global module_dir
global incvs inrcs insvn ingit
global cvs
global cwd
global cvscfg
global cvsglb
global cmd
global Filelist
gen_log:log T "ENTER ($filenames)"
if {[info exists Filelist]} {
unset Filelist
}
busy_start .workdir.main
#gen_log:log F "processing files in the local directory"
set cwd [pwd]
set my_cwd $cwd
# If we have commands running they were for a different directory
# and won't be needed now. (i.e. this is a recursive invocation
# triggered by a button click)
if {[info exists cmd(cvs_status)]} {
catch {$cmd(cvs_status)\::abort}
catch {unset cmd(cvs_status)}
}
if {[info exists cmd(cvs_editors)]} {
catch {$cmd(cvs_editors)\::abort}
catch {unset cmd(cvs_editors)}
}
# Select from those files only the ones we want (e.g., no CVS dirs)
foreach i $filenames {
if { $i == "." || $i == ".."} {
gen_log:log D "SKIPPING $i"
continue
}
# can be file, directory, characterSpecial, blockSpecial,
# fifo, link, or socket
set fret [catch {file type $i} ft]
if {$ft eq "directory"} {
if {[isCmDirectory $i]} {
# Read the bookkeeping files but don't list the directory
if {$i == "CVS" || $i == ".svn" || $i == "RCS" || $i == ".git"} {
continue
}
}
if {[file exists [file join $i "CVS"]]} {
set Filelist($i:status) "<directory:CVS>"
} elseif {[file exists [file join $i ".svn"]]} {
set Filelist($i:status) "<directory:SVN>"
} elseif {[file exists [file join $i ".git"]]} {
set Filelist($i:status) "<directory:GIT>"
} elseif {[file exists [file join $i "RCS"]]} {
set Filelist($i:status) "<directory:RCS>"
} else {
set Filelist($i:status) "<directory>"
}
} else {
if {$i == ".git"} {continue}
if {$incvs} {
set Filelist($i:status) "Not managed by CVS"
} else {
set Filelist($i:status) "<$ft>"
}
}
#set Filelist($i:wrev) ""
set Filelist($i:stickytag) ""
set Filelist($i:option) ""
# Prepending ./ to the filename prevents tilde expansion
catch {set Filelist($i:date) \
[clock format [file mtime ./$i] -format $cvscfg(dateformat)]}
}
# Now we send the files to the VCS for its status
gen_log:log D "incvs=$incvs insvn=$insvn inrcs=$inrcs ingit=$ingit"
if {$incvs} {
.workdir.main.tree heading wrevcol -text "Revision"
.workdir.main.tree heading editcol -text "Author"
cvs_workdir_status
}
if {$inrcs} {
.workdir.main.tree heading wrevcol -text "Revision"
.workdir.main.tree heading editcol -text "Locked by"
rcs_workdir_status
} elseif {$insvn} {
.workdir.main.tree heading wrevcol -text "Revision"
.workdir.main.tree heading editcol -text "Author"
svn_workdir_status
} elseif {$ingit} {
.workdir.main.tree heading wrevcol -text "Commit ID"
.workdir.main.tree heading editcol -text "Committer"
# We need the filenames in git for ignore_file_filter
git_workdir_status $filenames
}
gen_log:log D "Sending all files to the canvas"
set n_show [llength [array names Filelist]]
if {$n_show == 0} {
cvsalwaysconfirm "No files matched" .workdir
}
foreach i [array names Filelist *:status] {
regsub {:status$} $i "" j
# If it's locally removed or missing, it may not have
# gotten a date especially on a remote client.
if {! [info exists Filelist($j:date)]} {
set Filelist($j:date) ""
}
DirCanvas:newitem .workdir.main "$j"
}
DirCanvas:bindings .workdir.main
set col [lindex $cvscfg(sort_pref) 0]
set sense [lindex $cvscfg(sort_pref) 1]
DirCanvas:sort_by_col .workdir.main.tree $col $sense
busy_done .workdir.main
gen_log:log T "LEAVE"
}
proc workdir_cleanup {} {
global cvscfg
gen_log:log T "ENTER"
set rmitem ""
set list [ split $cvscfg(clean_these) " " ]
foreach pattern $list {
gen_log:log D "pattern $pattern"
if { $pattern != "" } {
set items [lsort [glob -nocomplain $pattern]]
gen_log:log D "$items"
if {[llength $items] != 0} {
append rmitem " [concat $items]"
}
}
}
if {$rmitem != ""} {
if { [ are_you_sure "You are about to delete:\n" $rmitem] == 1 } {
gen_log:log F "DELETE $rmitem"
eval file delete -force -- $rmitem
}
} else {
gen_log:log F "No files to delete"
cvsok "Nothing matched $cvscfg(clean_these)" .workdir
return
}
setup_dir
gen_log:log T "LEAVE"
}
proc workdir_delete_file {args} {
gen_log:log T "ENTER ($args)"
set filelist [join $args]
if {$filelist == ""} {
cvsfail "Please select some files to delete first!" .workdir
return
}
if { [ are_you_sure "This will delete these files from your local, working directory:\n" $filelist ] == 1 } {
gen_log:log F "DELETE $filelist"
eval file delete -force -- $filelist
setup_dir
}
gen_log:log T "LEAVE"
}
proc are_you_sure {mess args} {
#
# General posting message
#
global cvscfg
gen_log:log T "ENTER ($mess $args)"
set filelist [join $args]
if {$cvscfg(confirm_prompt)} {
append mess "\n"
set indent " "
foreach item $filelist {
if { $item != {} } {
append mess " $indent"
append mess " $item\n"
}
}
append mess "\nAre you sure?"
if {[cvsconfirm $mess .workdir] != "ok"} {
gen_log:log T "LEAVE 0"
return 0
}
}
gen_log:log T "LEAVE 1"
return 1
}
proc workdir_print_file {args} {
global cvscfg
gen_log:log T "ENTER ($args)"
set filelist [join $args]
if {$filelist == ""} {
cvsfail "Please select some files to print first!" .workdir
return
}
set mess "This will print these files:\n\n"
foreach file $filelist {
append mess " $file\n"
}
append mess "\nUsing $cvscfg(print_cmd)\n"
append mess "\nAre you sure?"
if {[cvsconfirm $mess .workdir] == "ok"} {
set final_result ""
foreach file $filelist {
set commandline [concat $cvscfg(print_cmd) \"$file\"]
exec::new $commandline
}
}
gen_log:log T "LEAVE"
}
# Is directory in CVS?
proc incvs_detect { dir } {
gen_log:log T "ENTER ($dir)"
set cvsrootfile [file join $dir CVS Root]
gen_log:log C "isfile $cvsrootfile"
if {[file isfile $cvsrootfile]} {
set cvs_detected [ read_cvs_dir [file join $dir CVS]]
} else {
set cvs_detected 0
}
gen_log:log T "LEAVE ($cvs_detected)"
return $cvs_detected
}
# Is directory in SVN?
proc insvn_detect { dir } {
gen_log:log T "ENTER ($dir)"
gen_log:log C "svn info"
set svnret [catch {exec {*}svn info} svnout]
if {! $svnret} {
gen_log:log F $svnout
set svn_detected [ read_svn_dir $dir ]
} else {
set svn_detected 0
}
gen_log:log T "LEAVE ($svn_detected)"
return $svn_detected
}
# Is directory in Git?
proc ingit_detect { dir } {
gen_log:log T "ENTER ($dir)"
gen_log:log C "git rev-parse --is-inside-work-tree"
set gitret [catch {exec {*}git rev-parse --is-inside-work-tree} gitout]
if {! $gitret} {
# revparse may return "false"
gen_log:log F "gitout $gitout"
if {$gitout} {
set git_detected 1
find_git_remote $dir
}
} else {
set git_detected 0
}
gen_log:log T "LEAVE ($git_detected)"
return $git_detected
}
proc inrcs_detect { dir } {
global cvscfg
gen_log:log T "ENTER ($dir)"
set rcsdir [file join $dir RCS]
gen_log:log C "searching for local RCS files"
if {[file isdirectory $rcsdir]} {
gen_log:log C "isdirectory $rcsdir"
set cvscfg(rcsdir) $rcsdir
set rcs_detected 1
} elseif {[llength [glob -nocomplain -directory $dir *,v]] > 0} {
gen_log:log C "*,v files exist"
set rcs_detected 1
set cvscfg(rcsdir) $dir
} else {
set cvscfg(rcsdir) ""
set rcs_detected 0
}
if {$rcs_detected} {
# Make sure we have rcs, and bag this (silently) if we don't
set command "rcs --version"
gen_log:log C "$command"
set ret [catch {exec {*}$command} raw_rcs_log]
gen_log:log F "$raw_rcs_log"
if {$ret} {
if {[string match {rcs*} $raw_rcs_log]} {
# An old version of RCS, but it's here
set rcs_detected 1
} else {
set rcs_detected 0
}
}
}
gen_log:log T "LEAVE ($rcs_detected)"
return $rcs_detected
}
# Detect which version control system the directory is in,
proc vcs_detect { dir } {
global cvsglb
global incvs insvn inrcs ingit
gen_log:log T "ENTER ($dir)"
gen_log:log D "cvsglb(vcspref) $cvsglb(vcspref)"
lassign {0 0 0 0} incvs insvn inrcs ingit
foreach vcs $cvsglb(vcspref) {
set procname [join "in $vcs _detect" ""]
set reply [$procname $dir]
set in$vcs $reply
if {$reply} { break }
gen_log:log D "$vcs in$vcs $reply"
}
gen_log:log T "LEAVE ($incvs $insvn $inrcs $ingit)"
return [list $incvs $insvn $inrcs $ingit]
}
proc isCmDirectory { file } {
#gen_log:log T "ENTER ($file)"
switch -- $file {
"CVS" -
"RCS" -
".svn" -
".git" -
"SCCS" { set value 1 }
default { set value 0 }
}
#gen_log:log T "LEAVE ($value)"
return $value
}
# Get the files in the current working directory. Use the file_filter
# values. Add hidden files if desired by the user. Sort them to match
# the ordering that will be returned by cvs commands (this matches the
# default ls ordering.).
proc getFiles { } {
global cvscfg
global cvsglb
gen_log:log T "ENTER"
set filelist ""
# make sure the file filter is at least set to "*".
if { $cvscfg(show_file_filter) == "" } {
set cvscfg(show_file_filter) "*"
}
# get the initial file list, including dotfiles if requested, filtered by show_file_filter
if {$cvscfg(allfiles)} {
# get hidden as well
foreach item $cvscfg(show_file_filter) {
gen_log:log T "glob -nocomplain .$item $item"
set filelist [ concat [ glob -nocomplain .$item $item ] $filelist ]
}
} else {
foreach item $cvscfg(show_file_filter) {
gen_log:log T "glob -nocomplain $item"
set filelist [ concat [ glob -nocomplain $item ] $filelist ]
}
}
#gen_log:log D "filelist ($filelist)"
# ignore files if requested by ingore_file_filter
set ignore_file_filter [concat $cvscfg(ignore_file_filter) $cvsglb(vcs_hidden_files)]
if { $ignore_file_filter != "" } {
foreach item $ignore_file_filter {
# for each pattern
if { $item != "*" } {
# if not "*"
set idx [lsearch $filelist $item]
while { [set idx [lsearch $filelist $item]] != -1 } {
# for each occurence, delete
catch { set filelist [ lreplace $filelist $idx $idx ] }
}
}
}
}
# If file starts with ~, make it ./~
set newlist {}
foreach item $filelist {
lappend newlist [regsub {^\~} $item {./~}]
}
set filelist $newlist
# make sure "." is always in the list for 'cd' purposes
if { "." ni $filelist} {
set filelist [ concat "." $filelist ]
}
# make sure ".." is always in the list for 'cd' purposes
if { ".." ni $filelist} {
set filelist [ concat ".." $filelist ]
}
# sort it
set filelist [ lsort $filelist ]
# if this directory is under CVS and CVS is not in the list, add it. Its
# presence is needed for later processing
if { ( [ file exists "CVS" ] ) && ("CVS" ni $filelist) } {
#puts "********* added CVS"
catch { set filelist [ concat "CVS" $filelist ] }
}
gen_log:log T "return ($filelist)"
return $filelist
}
proc log_toggle { } {
global cvscfg
if {$cvscfg(logging)} {
gen_log:init
} else {
gen_log:quit
}
}
proc exit_cleanup { force } {
global cvscfg
# Count the number of toplevels that are currently interacting
# with the user (i.e. exist and are not withdrawn)
set wlist {}
foreach w [winfo children .] {
if {[wm state $w] != {withdrawn}} {
lappend wlist $w
}
}
if {$force == 0 && [llength $wlist] != 0 \
&& $wlist != {.trace} && $wlist != {.bgerrorTrace}} {
return
}
# If toplevel windows exist ask them to close gracefully if possible
foreach w $wlist {
# Except .trace!
if {$w != {.trace}} {
catch {$w.close invoke}
} else {
# Invoking trace's close turns off logging. We don't want that,
# but we do want to save its geometry.
if {[winfo exists .trace]} {
set cvscfg(tracgeom) [wm geometry .trace]
}
}
}
save_options
set pid [pid]
gen_log:log F "DELETE $cvscfg(tmpdir)/cvstmpdir.$pid"
catch {file delete -force [file join $cvscfg(tmpdir) cvstmpdir.$pid]}
exit
}
proc save_options { } {
#
# Save the options which are configurable from the GUI
#
global cvscfg
global logcfg
global bookmarks
gen_log:log T "ENTER"
# There are two kinds of options we can set
set BOOLopts { allfiles auto_status confirm_prompt gitdetail \
match_desktop showstatcol showdatecol showwrevcol showeditcol auto_tag \
status_filter recurse large_icons logging blame_linenums use_cvseditor }
set STRGopts { show_file_filter ignore_file_filter clean_these editor preftab \
gitblame_since gitbranchgroups gitlog_opts gitlog_since \
gitmaxbranch gitmaxhist gitbranchregex \
printer log_classes lastdir sort_pref editor editorargs \
workgeom modgeom loggeom shell tkdiff toomany_tags tracgeom blamegeom \
svn_trunkdir svn_branchdir svn_tagdir vcspref }
# Plus the branch_diagram options
set LOGopts [concat [array names logcfg show_*] scale]
# remove obsolete settings
if {[info exists cvscfg(editorargs)] } {
if {$cvscfg(editorargs) != ""} {
set cvscfg(editor) [concat $cvscfg(editor) $cvscfg(editorargs)]
}
unset cvscfg(editorargs)
}
if {[info exists cvscfg(gitsince)] } {
unset cvscfg(gitsince)
}
# Save the list so we can keep track of what we've done
set BOOLset $BOOLopts
set STRGset $STRGopts
set LOGset $LOGopts
set optfile [file join $cvscfg(home) .tkrev]
set bakfile [file join $cvscfg(home) .tkrev.bak]
# Save the old .tkrev file
gen_log:log F "MOVE $optfile $bakfile"
catch {file rename -force $optfile $bakfile}
gen_log:log F "OPEN $optfile"
if {[catch {set fo [open $optfile w]}]} {
cvsfail "Cannot open $optfile for writing" .workdir
return
}
gen_log:log F "OPEN $bakfile"
if {! [catch {set fi [open $bakfile r]}]} {
while { [eof $fi] == 0 } {
gets $fi line
set match 0
if {[regexp {^#} $line]} {
# Don't try to scan comments.
#gen_log:log D "PASSING \"$line\""
puts $fo "$line"
continue
} elseif {[string match "*set *bookmarks*" $line]} {
# Discard old bookmarks
continue
} else {
foreach opt $BOOLopts {
if {! [info exists cvscfg($opt)]} { continue }
if {[string match "*set *cvscfg($opt)*" $line]} {
# Print it and remove it from the list
gen_log:log D "REPLACING $line w/ set cvscfg($opt) $cvscfg($opt)"
puts $fo "set cvscfg($opt) $cvscfg($opt)"
set idx [lsearch $BOOLset $opt]
set BOOLset [lreplace $BOOLset $idx $idx]
set match 1
break
}
}
foreach opt $STRGopts {
if {! [info exists cvscfg($opt)]} { continue }
if {[string match "*set *cvscfg($opt)*" $line]} {
# Print it and remove it from the list
gen_log:log D "REPLACING $line w/ set cvscfg($opt) $cvscfg($opt)"
puts $fo "set cvscfg($opt) \{$cvscfg($opt)\}"
set idx [lsearch $STRGset $opt]
set STRGset [lreplace $STRGset $idx $idx]
set match 1
break
}
}
if {[string match "*set *cvscfg(editorargs)*" $line]} {
# editorargs is no longer necessary
continue
}
foreach opt $LOGopts {
if {! [info exists logcfg($opt)]} { continue }
if {[string match "*set *logcfg($opt)*" $line]} {
# Print it and remove it from the list
gen_log:log D "REPLACING \"$line\" w/ set logcfg($opt) \"$logcfg($opt)\""
puts $fo "set logcfg($opt) \"$logcfg($opt)\""
set idx [lsearch $LOGset $opt]
set LOGset [lreplace $LOGset $idx $idx]
set match 1
break
}
}
if {$match == 0} {
# We didn't do a replacement
gen_log:log D "PASSING \"$line\""
# If we don't check this, we get an extra blank line every time
# we save the file. Messy.
if {[eof $fi] == 1} { break }
puts $fo "$line"
}
}
}
foreach mark [lsort [array names bookmarks]] {
gen_log:log D "Adding bookmark \"$mark\""
puts $fo "set \"bookmarks($mark)\" \"$bookmarks($mark)\""
}
close $fi
}
# Print what's left over
foreach opt $BOOLset {
if {! [info exists cvscfg($opt)]} { continue }
gen_log:log D "ADDING cvscfg($opt) $cvscfg($opt)"
puts $fo "set cvscfg($opt) $cvscfg($opt)"
}
foreach opt $STRGset {
if {! [info exists cvscfg($opt)]} { continue }
gen_log:log D "ADDING cvscfg($opt) \"$cvscfg($opt)\""
puts $fo "set cvscfg($opt) \"$cvscfg($opt)\""
}
foreach opt $LOGset {
if {! [info exists logcfg($opt)]} { continue }
gen_log:log D "ADDING logcfg($opt) \"$logcfg($opt)\""
puts $fo "set logcfg($opt) \"$logcfg($opt)\""
}
close $fo
picklist_save
gen_log:log T "LEAVE"
}