From: Ron F. <ro...@us...> - 2004-05-04 12:23:51
|
Update of /cvsroot/nscldaq/clients/dvdwrite In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8434 Added Files: Tag: daqclients-7_4_development TopGUi.ui.tcl burngui burnpackage.tcl dvdburn dvdburnoutput.ui.tcl Log Message: Initial version, copied from SEE, with only some filenames modified. --- NEW FILE: TopGUi.ui.tcl --- # interface generated by SpecTcl version 1.1 from H:/Wincluster/DAQDocs/See/DVDburn/TopGUi.ui # root is the parent window for this user interface proc TopGUi_ui {root args} { # this treats "." as a special case if {$root == "."} { set base "" } else { set base $root } frame $base.frame#2 frame $base.frame#1 label $base.label#3 \ -text {SEETF DVD Burn procedure} radiobutton $base.radiobutton#1 \ -justify left \ -text {All Runs} \ -textvariable example_2 \ -value 1 \ -variable all radiobutton $base.radiobutton#2 \ -justify left \ -text {Select Runs} \ -value 0 \ -variable all label $base.label#1 \ -text {First Run Number:} entry $base.entry#1 \ -textvariable FirstRun label $base.label#2 \ -text {Last Run Number} entry $base.entry#2 \ -cursor {} \ -textvariable LastRun button $base.button#1 \ -command Burn \ -text Burn button $base.button#2 \ -command exit \ -text Cancel # Geometry management grid $base.frame#2 -in $root -row 5 -column 1 \ -columnspan 3 grid $base.frame#1 -in $root -row 1 -column 2 \ -columnspan 2 grid $base.label#3 -in $base.frame#1 -row 1 -column 1 grid $base.radiobutton#1 -in $root -row 2 -column 1 \ -sticky nw grid $base.radiobutton#2 -in $root -row 3 -column 1 \ -sticky nw grid $base.label#1 -in $root -row 3 -column 2 grid $base.entry#1 -in $root -row 3 -column 3 grid $base.label#2 -in $root -row 4 -column 2 grid $base.entry#2 -in $root -row 4 -column 3 grid $base.button#1 -in $base.frame#2 -row 1 -column 1 grid $base.button#2 -in $base.frame#2 -row 1 -column 2 # Resize behavior management grid rowconfigure $base.frame#2 1 -weight 0 -minsize 30 grid columnconfigure $base.frame#2 1 -weight 0 -minsize 30 grid columnconfigure $base.frame#2 2 -weight 0 -minsize 30 grid rowconfigure $root 1 -weight 0 -minsize 30 grid rowconfigure $root 2 -weight 0 -minsize 30 grid rowconfigure $root 3 -weight 0 -minsize 30 grid rowconfigure $root 4 -weight 0 -minsize 30 grid rowconfigure $root 5 -weight 0 -minsize 30 grid columnconfigure $root 1 -weight 0 -minsize 30 grid columnconfigure $root 2 -weight 0 -minsize 30 grid columnconfigure $root 3 -weight 0 -minsize 30 grid rowconfigure $base.frame#1 1 -weight 0 -minsize 30 grid columnconfigure $base.frame#1 1 -weight 0 -minsize 41 # additional interface code global all set all 1; # Default is record all runs. # end additional interface code } # Allow interface to be run "stand-alone" for testing catch { if [info exists embed_args] { # we are running in the plugin TopGUi_ui . } else { # we are running in stand-alone mode if {$argv0 == [info script]} { wm title . "Testing TopGUi_ui" TopGUi_ui . } } } --- NEW FILE: dvdburn --- #!/bin/sh # start tclsh \ exec tclsh ${0} ${@} proc Usage {} { puts "Usage: " puts { seeburn [firstrun [lastrun]]} puts " firstrun - An optional lowest run number to burn." puts " lastrun - An optional last run number to burn. " puts " If neither firstrun nor lastrun is present, all runs " puts " will be burned. If only firstrun is present, then " puts " all runs from firstrun on will be burned" puts " Examples: " puts " seeburn \# burn all runs" puts " seeburn 100 \# Burn from run 100 on." puts " seeburn 100 200 \# burn runs 100 through 200" } # set up to locate and load burnpackage.tcl set me $argv0 set mypath [file dirname $me] source $mypath/burnpackage.tcl package require SEETFDvd namespace import SEETFDvd::CreateDvds set range ""; # Assume there's no range information. if {[llength $argv] > 2} { Usage exit -1 } foreach element $argv { if {[scan $element "%d" dummy] != 1} { Usage exit -2 } lappend range $element } if {[catch "CreateDvds {$range}" msg]} { puts $msg exit -3 } exit 0 --- NEW FILE: burngui --- #!/bin/sh # start wish: \ exec wish ${0} ${@} set me $argv0 set mypath [file dirname $me] source $mypath/TopGUi.ui.tcl source $mypath/seeburnoutput.ui.tcl set burning 0 set burnfd "" # Set up the initial prompting GUI: frame .top TopGUi_ui .top pack .top # # This is called when the user is ready to do the burn. # Pop up the output catpure gui, figure out the parameters and start # The burn job. # proc Burn {} { global FirstRun global LastRun global all destroy .top # Put up the caputure GUI: frame .capture seeburnoutput_ui .capture pack .capture wm geometry . 500x500 set runrange "" if {!$all} { if {$FirstRun != ""} { lappend runrange $FirstRun if {$LastRun != ""} { lappend runrange $LastRun } } } BurnRange $runrange } # # Called to cancel the burn in the middle of the operation. # proc KillBurn {} { global burning global burnfd if {! $burning } { exit } else { close $burnfd exit } } # # Start the burn off with output captured by # .capture.output # proc BurnRange {range} { global burning global burnfd set burnfd [open "| seeburn [lindex $range 0] [lindex $range 1]" r+] fconfigure $burnfd -blocking 0 fileevent $burnfd readable CaptureOutput set burning 1 } # # Capture output from the pipe: # proc CaptureOutput {} { global burnfd global burning if {[eof $burnfd]} { close $burnfd set burning 0 .capture.cancel config -text "Dismiss" .capture.output insert end \ "DONE!!! Check the log for errors before dismissing" .capture.output see end } else { set line [gets $burnfd] append line "\n" .capture.output insert end $line .capture.output see end # # Is it a disk prompt? # if {[regexp BURNDVD: $line]} { tk_dialog .next "Next DVD" "Put a blank DVD in the burner" \ questhead 0 "Ready to Burn" puts $burnfd "\n" flush $burnfd } } } --- NEW FILE: dvdburnoutput.ui.tcl --- # interface generated by SpecTcl version 1.1 from H:/Wincluster/DAQDocs/See/DVDburn/seeburnoutput.ui # root is the parent window for this user interface proc seeburnoutput_ui {root args} { # this treats "." as a special case if {$root == "."} { set base "" } else { set base $root } text $base.output \ -height 1 \ -width 1 \ -yscrollcommand "$base.scrollbar#1 set" scrollbar $base.scrollbar#1 \ -command "$base.output yview" \ -orient v button $base.cancel \ -command KillBurn \ -text Cancel # Geometry management grid $base.output -in $root -row 1 -column 1 \ -columnspan 2 \ -sticky nesw grid $base.scrollbar#1 -in $root -row 1 -column 3 \ -sticky ns grid $base.cancel -in $root -row 2 -column 2 # Resize behavior management grid rowconfigure $root 1 -weight 1 -minsize 436 grid rowconfigure $root 2 -weight 0 -minsize 30 grid columnconfigure $root 1 -weight 0 -minsize 30 grid columnconfigure $root 2 -weight 0 -minsize 442 grid columnconfigure $root 3 -weight 0 -minsize 30 # additional interface code # end additional interface code } # Allow interface to be run "stand-alone" for testing catch { if [info exists embed_args] { # we are running in the plugin seeburnoutput_ui . } else { # we are running in stand-alone mode if {$argv0 == [info script]} { wm title . "Testing seeburnoutput_ui" seeburnoutput_ui . } } } --- NEW FILE: burnpackage.tcl --- # # package to support burning a DVD set for SEE. This package is used by the # SEETF to burn a set of DVD's that export the data they take. # # package provide SEETFDvd 1.0 namespace eval SEETFDvd { # # Package/namespace global variables: # variable ExperimentRoot "~/experiment"; # Root of experiment files. variable ISOFSroot "/scratch/seetfisos"; # Where ISO temp data lives. variable MarshallDir $ISOFSroot/tmp; # Where runs get marshalled. variable DVDSize 4000; # Mbytes in a DVD. # # Exported functions: # namespace export EnumerateRuns; # List the set of runs. namespace export FilterList; # Filter a tcl list. namespace export MarshallRun; # Marshall a run to a temp directory namespace export CreateDVDDirectory; # Create root of dvd filesystem. namespace export RunToDVD; # Transfer a marshalled run to dvd-fs. namespace export CreateISO; # Create an iso from a dvd-fs tree. namespace export BurnDVD; # Burn a single dvd from an iso. namespace export CreateDvds; # Burn a dvd set. namespace export LowRunFilter; # Low cutoff filter predicate for runs namespace export HighRunFilter; # High cutoff filter predicate for runs # Procedure: DirectoryToRun # Purpose: Translate a directory name to a runnumber. # Inputs: A directory. # Outputs: The number of the run that corresponds to the directory. # Errors: If the directory does not correspond to a run number. # e.g. ~/experiment/george. # Description: The last path element of the directory is matched # against patterns of the form run<run-number> # The run number is decoded and returned. # proc DirectoryToRun {directory} { # # Ensure the final element of the directory path is of the form. # run<n> where n is a number, and extract the run number. # set SubDirectory [file tail $directory]; if {![regexp {^run([0-9]+)$} $SubDirectory]} { error "DirectoryToRun: No match for run<number> in $SubDirectory" } if {[scan $SubDirectory "run%d" RunNumber] != 1} { error "DirectoryToRun: Scan for run number failed $SubDirectory" } return $RunNumber } # Procedure: CompareRuns # Purpose: Compare a pair of run number directory files. # Inputs: dir1 - full path to the first run directory. # dir2 - Full path to the second run directory. # Outputs: -1 The run number for dir1 is < the run number for dir2. # 0 The run number for dir1 is == the run number for dir2. # 1 The run number for dir1 is > the run number for dir2. # Description: For both directories, DirectoryToRun is called to convert # the directories to run numbers. If successful, the runs # are compared as described in Outputs above. Failures # are handled as follows: # failure on dir1 returns 1 -> pushing it towards the list # end in an lsort. # failur on dir2 returns -1 -> Pushing it towards the list # end in an lsort. # proc CompareRuns {dir1 dir2} { if {[catch "DirectoryToRun $dir1" run1]} { return 1 } if {[catch "DirectoryToRun $dir2" run2]} { return -1 } if {$run1 < $run2} { return -1 } if {$run1 > $run2} { return 1 } return 0 } # Procedure: LowRunFilter # Purpose: Predicate that filters run directory lists with a low level # cutoff. # Inputs: Run directory name (full path).Low cutoff # Outputs: · True if the run number of the directory is >= to the # run number specified by the predicate argument. # · False if run number is < run number specified by predicate # argument. # Errors: NONE # Description: Extracts the run number associated with the run # directory name and returns true if this is >= to the # predicate argument. Note that directories that don't # decode to run numbers result in a false without even # a whimper of an error message. # proc LowRunFilter {directory cutoff} { if { [catch "DirectoryToRun $directory" RunNumber]} { return 0 } return [expr $RunNumber >= $cutoff] } # Procedure: HighRunFilter # Purpose: Predicate that filters run directory lists with a high # levelcutoff. # Inputs: Run directory name (fullpath)High cutoff # Outputs: · True if the run number of the directory is <= the high # cutoff parameters # · False if the run number of the directory is > the high # cutoff parameter. # Errors: NONE # Description: Filter predicate that can be used to produce a # list of the run directories that corresponds to # runs <= a particular run number. proc HighRunFilter {directory cutoff} { if {[catch "DirectoryToRun $directory" RunNumber]} { return 0 } return [expr $RunNumber <= $cutoff] } # Procedure: FilterList (reuse lib). # Purpose: Reduce a list according to some filter criteria # Inputs: List - An arbitrary TCL list. # Predicate - see description below, the predicate # returns true for each element of the # list that is acceptable in the output list. # Predicate arg - Parameter passed without # interpretation to the predicate. # Outputs: The set of list elements that passed the predicate's # test. # Errors: None. # Description: Each element of the list is passed to the predicate # member function. The predicate returns true if the # element is acceptable for the output list, and false # otherwise. The predicate is called as follows: # Predicate element arg # Where element is a complete entry that appears in the # input list. and arg is the predicate argument passed # into FilterList. The predicate function can do # arbitrary processing. proc FilterList {List Predicate PredicateArgument} { set OutputList "" foreach element $List { if {[$Predicate $element $PredicateArgument] } { lappend OutputList $element } } return $OutputList } # Procedure: EnumerateRuns # Purpose: Return a list of all of the runs that exist in an # experiment. # Inputs: Experiment top level directory (e.g. ~/experiment). # Outputs: A TCL list of run directory names e.g. {run1 run2 run3} # Errors: Error if toplevel directory does not exist. Note that # run list can be empty. # Description: Determines the set of run directories that exist below # the top level directory specified. The set of run # directory names is sorted by the numeric run number. # (not e.g. run1 run10 run11). The full path of each # directory is returned (e.g. /user/03901/run1 not run1). proc EnumerateRuns {TopDirectory} { set RunList [glob -nocomplain $TopDirectory/run*]; # Raw enumeration. return [lsort -command CompareRuns $RunList]; # Sorted enumeration. } # Procedure: MarshallRun # Purpose: Copies all the files that will be recorded for a run # to a specified target directory. # Inputs: Run number - Number of the run to marshall # Source experiment root - Where the run dirs live. # Target directory. - Destination of the marshal. # Outputs: Number of Mbytes of data in the run (floating point). # Errors: Any errors in the copy operation. # Description: The target directory is removed if it exists and a # new one created. The following files are copied into # that directory: # · All files in the source run directory with links # followed. This copy is a deep (hierarchical) copy. # · A spectra directory is created and the spectra # associated with that run are copied from # root/../savedspectra # · A scaler directory is created and the scaler files # associated with the run are copied from # root/../scalerfiles to it. # proc MarshallRun {Run SourceRoot Target} { # # If the target exists, delete it. # Failure to delete is an error. if {[file exists $Target]} { if {[catch "file delete -force $Target"]} { error "MarshallRun: Unable to remove an existing $Target" } } # Make the new target: # if {[catch "file mkdir $Target"]} { error "MarshallRun: Could not create marshalling target $Target" } # Compute the directory that holds the run and ensure it exists: # set Source $SourceRoot/run$Run if {![file exists $Source]} { error "MarshallRun: Source directory $Source does not exist" } # tar the source directory to the target: set wd [pwd] cd $Source if {[catch "exec tar czhf - . | tar xzfC - $Target" msg]} { cd $wd error "MarshallRun: Bulk data tar failed: $msg" } # Now get all the little niggly stuff too: # Spectrum files: set pattern see.*run$Run.spec cd $SourceRoot/../savedspectra set spectra [glob -nocomplain $pattern] if {[catch "file mkdir $Target/spectra"]} { cd $wd error "MarshallRun: Could not make directory $Target/spectra" } foreach spectrum $spectra { if {[catch "file copy $spectrum $Target/spectra"]} { cd $wd error "MarshallRun: Could not copy $spectrum to $Target/spectra" } } # Scaler files: cd $SourceRoot/../scalerfiles set scalers [glob -nocomplain run$Run*.scalers] if {[catch "file mkdir $Target/scalers"]} { cd $wd error "MarshallRun: Could not create $Target/scalers" } foreach file $scalers { if {[catch "file copy $file $Target/scalers"]} { cd $wd error "MarshallRun: Could not copy $file to $Target/scalers" } } cd $wd; # Restore working directory. # Size the result with du and return the size of the result. # size will be either # nnU # nn a floating point and U a unit (K, M or G). # or: # nn (in which case the units are K). # set size [exec du -sh $Target] set n [scan $size "%f%s" size units] if {$n == 1} { # Units are K. return [expr $size/1000] ; # Return mBytes. } else { switch $units { K { return [expr $size/1000] } M { return $size } G { return $size*1000 } default { error "MarshallRun: Unrecognized size units: $units" } } } error "MarshallRun: >>BUG<<< control should not have reached here" } # Procedure: CreateDVDDirectory # Purpose: Create a top level directory in which a dvd file # image will be created. # Inputs: DVDRoot - a top level directory in which the file # systems are being created. # DVDNumber- Volume number within the dvd set. # Outputs: Full path to the dvd directory. # Errors: If mkdir fails. # Description: Creates a directory, into which the file system of a # dvd can be created. (named Root/diskn where n is the # dvd volume number). proc CreateDVDDirectory {DVDRoot DVDNumber} { # Figure out the directory name: set Directory $DVDRoot/Disk$DVDNumber # Create the directory... if {[catch "file mkdir $Directory"]} { error "CreateDVDDirectory - unable to create $Directory" } return $Directory } # Procedure: RunToDVD # Purpose: Move a marshaled run into a dvd filesystem image # Inputs: Source directory # DVD volume root (from CreateDVDDirectory) # Run Number # Outputs: NONE # Errors: Errors from the move. # Description: The source directory is mv'd to the runrunnumber # under the DVD volume root specified. proc RunToDVD {Source DVDRoot Run} { # Figure out the target: set ResultingDirectory $DVDRoot/run$Run # If this directory already exists we need to remove it or # we'll get a nested directory... if {[catch "file delete -force $ResultingDirectory"]} { error "RunToDVD Unable to remove pre-existing $ResultingDirectory" } # Now we can do the mv. if {[catch "file rename $Source $ResultingDirectory"]} { error "RunToDVD Unable to rename $Source -> $ResultingDirectory" } } # Procedure: FdToStdout # Purpose: Copy all input from a filedescriptor until EOF to # stdout. Flushes are done after all writes # Just in case stdout is e.g. a pipe. # Inputs: file # Outputs -> Stdout. # Errors: NONE: # Description: Opens the designated fifo # Reads until eof, writing each line on stdout. # Close the fifo. proc FdToStdout {fifo} { set fd [open |cat $fifo r] puts [gets $fd] while {![eof $fd]} { puts [gets $fd] flush stdout } close $fd } # Procedure: Fifo # Purpose: Create a fifo special file, destroying an existing one # Inputs: path to the fifo. # proc Fifo {fifo} { file delete -force $fifo exec mkfifo $fifo return $fifo } # Procedure: CreateISO # Purpose: Create an ISO image of a dvd file image. # Inputs: DVDVolume root (from CreateDVDDirectory) # Desired output file. # Outputs: # Errors: # Description: Runs mkisofs to create the desired dvd ISOimage from # the specified DVDVolume root. proc CreateISO {DVDRoot isoname} { set fifo [Fifo .mkisofs] exec cat $fifo & exec mkisofs -r -J -v -o $isoname $DVDRoot > $fifo 2> $fifo } # Procedure: BurnDVD # Purpose: Burn a dvd from an ISO Image. # Inputs: ISO filename. # Outputs: None # Errors: # Description: Interacts with the DVD Burn programs to burn a dvd # from the specified ISO image. proc BurnDVD {iso} { set fifo [Fifo .burndvd] exec cat $fifo & exec burnDVD $iso > $fifo 2> $fifo } # Procedure: CreateDvds # Purpose: Create the set of dvds that spans the runs desired. # Inputs: Run-range [optional] If present, the range of # runs desired. # Outputs: NONE # Errors: # Description: Creates all of the DVDs needed to save the run files # that need to be saved for the specified runs. If # supplied, run-range will specify a subset of runs to # save. Valid specifications for run-range are:Low # All runs beginning with run number Low and ending with # the highest numbered run taken are saved.Low-High All # runs beginning with run number Low and ending with # (and including) run High are saved. proc CreateDvds {{range {}}} { variable ExperimentRoot variable ISOFSroot variable DVDSize variable MarshallDir file delete -force $ISOFSroot; # Get rid of any pre-existing stuff. # Enumerate and if necessary filter the run set so that we # have the runs that can be burned in RunList: set RunList [EnumerateRuns $ExperimentRoot] if {[llength $range] != 0} { # Must filter: set low [lindex $range 0] set RunList [FilterList $RunList LowRunFilter $low] set hi [lindex $range 1] if {$hi != ""} { set RunList [FilterList $RunList HighRunFilter $hi] } } if {[llength $RunList] == 0} { puts "There are no runs in the specified range" exit -2 } # Now Build the DVD file systems set volume 1; # DVD number. set volroot($volume) [CreateDVDDirectory $ISOFSroot $volume] set SizeLeft $DVDSize foreach run $RunList { set runnum [DirectoryToRun $run] puts "Marshalling run $runnum $SizeLeft MB remaining." set RunSize [MarshallRun $runnum $ExperimentRoot $MarshallDir] if {$RunSize > $SizeLeft} { puts " run $runnum does not fit... starting new filesystem root" incr volume set volroot($volume) [CreateDVDDirectory $ISOFSroot $volume] set SizeLeft $DVDSize } if {$RunSize > $SizeLeft} { error " run $runnum is bigger than a DVD!!!" } puts " Moving run $runnum ($RunSize MB) to $volroot($volume): " RunToDVD $MarshallDir $volroot($volume) $runnum set SizeLeft [expr $SizeLeft - $RunSize] } puts " All runs are marshalled. Now we make $volume ISO images: " for {set i 1} {$i <= $volume} {incr i} { CreateISO $volroot($i) $ISOFSroot/iso$i.iso puts "Finished with volume $i" } puts "Now we will burn $volume DVD(s)" for {set i 1} {$i <= $volume} {incr i} { puts "BURNDVD: Put volume $i in the burner, hit <ENTER> to burn" gets stdin BurnDVD $ISOFSroot/iso$i.iso } } } |