source: trunk/gui/scripts/tool.tcl @ 551

Last change on this file since 551 was 500, checked in by nkissebe, 18 years ago

Escape any backslashes found in tool string (primarily for the sake of Windows paths) before passing to bgexec eval.

Internally process "echo" commands found in tool string (primarily for Windows which does not have a usable external echo command to exec).

File size: 7.3 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: tool - represents an entire tool
3#
4#  This object represents an entire tool defined by Rappture.
5#  Each tool resides in an installation directory with other tool
6#  resources (libraries, examples, etc.).  Each tool is defined by
7#  its inputs and outputs, which are tied to various widgets in the
8#  GUI.  Each tool tracks the inputs, knows when they're changed,
9#  and knows how to run itself to produce new results.
10# ======================================================================
11#  AUTHOR:  Michael McLennan, Purdue University
12#  Copyright (c) 2004-2005  Purdue Research Foundation
13#
14#  See the file "license.terms" for information on usage and
15#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
16# ======================================================================
17package require BLT
18
19itcl::class Rappture::Tool {
20    inherit Rappture::ControlOwner
21
22    constructor {xmlobj installdir args} {
23        Rappture::ControlOwner::constructor ""
24    } { # defined below }
25
26    public method installdir {} { return $_installdir }
27
28    public method run {args}
29    public method abort {}
30
31    protected method _output {data}
32
33    private variable _installdir ""  ;# installation directory for this tool
34    private variable _outputcb ""    ;# callback for tool output
35    private common job               ;# array var used for blt::bgexec jobs
36    private common jobnum 0          ;# counter for unique job number
37
38    # resources file tells us the application name
39    public common _appname ""
40    public proc setAppName {name} { set _appname $name }
41}
42
43# must use this name -- plugs into Rappture::resources::load
44proc tool_init_resources {} {
45    Rappture::resources::register \
46        application_name Rappture::Tool::setAppName
47}
48                                                                               
49# ----------------------------------------------------------------------
50# CONSTRUCTOR
51# ----------------------------------------------------------------------
52itcl::body Rappture::Tool::constructor {xmlobj installdir args} {
53    if {![Rappture::library isvalid $xmlobj]} {
54        error "bad value \"$xmlobj\": should be Rappture::Library"
55    }
56    set _xmlobj $xmlobj
57
58    if {![file exists $installdir]} {
59        error "directory \"$installdir\" doesn't exist"
60    }
61    set _installdir $installdir
62
63    eval configure $args
64}
65
66# ----------------------------------------------------------------------
67# USAGE: run ?<path1> <value1> <path2> <value2> ...? ?-output <callbk>?
68#
69# This method causes the tool to run.  All widgets are synchronized
70# to the current XML representation, and a "driver.xml" file is
71# created as the input for the run.  That file is fed to the tool
72# according to the <tool><command> string, and the job is executed.
73#
74# Any "<path> <value>" arguments are used to override the current
75# settings from the GUI.  This is useful, for example, when filling
76# in missing simulation results from the analyzer.
77#
78# If the -output argument is included, then the next arg is a
79# callback command for output messages.  Any output that comes in
80# while the tool is running is sent back to the caller, so the user
81# can see progress running the tool.
82#
83# Returns a list of the form {status result}, where status is an
84# integer status code (0=success) and result is the output from the
85# simulator.  Successful output is something like {0 run1293921.xml},
86# where 0=success and run1293921.xml is the name of the file containing
87# results.
88# ----------------------------------------------------------------------
89itcl::body Rappture::Tool::run {args} {
90    global errorInfo
91
92    # make sure that we save the proper application name
93    if {"" != $_appname} {
94        $_xmlobj put tool.name $_appname
95    }
96
97    # sync all widgets to the XML tree
98    sync
99
100    # if there are any args, use them to override parameters
101    set _outputcb ""
102    foreach {path val} $args {
103        if {$path == "-output"} {
104            set _outputcb $val
105        } else {
106            $_xmlobj put $path.current $val
107        }
108    }
109
110    foreach item {control output error} { set job($item) "" }
111
112    # write out the driver.xml file for the tool
113    set file "driver[pid].xml"
114    set status [catch {
115        set fid [open $file w]
116        puts $fid "<?xml version=\"1.0\"?>"
117        puts $fid [$_xmlobj xml]
118        close $fid
119    } result]
120
121    # set limits for cpu time and file size
122    set limit [$_xmlobj get tool.limits.cputime]
123    if {"" == $limit || [catch {Rappture::rlimit set cputime $limit}]} {
124        Rappture::rlimit set cputime 900  ;# 15 mins by default
125    }
126
127    set limit [$_xmlobj get tool.limits.filesize]
128    if {"" == $limit || [catch {Rappture::rlimit set filesize $limit}]} {
129        Rappture::rlimit set filesize 1000000  ;# 1MB by default
130    }
131
132    # execute the tool using the path from the tool description
133    if {$status == 0} {
134        set cmd [$_xmlobj get tool.command]
135        regsub -all @tool $cmd $_installdir cmd
136        regsub -all @driver $cmd $file cmd
137        regsub -all {\\} $cmd {\\\\} cmd
138        set cmd [string trimleft $cmd " "]
139
140        # starting job...
141        Rappture::rusage mark
142
143        if {0 == [string compare -nocase -length 5 $cmd "ECHO "] } {
144            set status 0;
145            set job(output) [string range $cmd 5 end]
146        } else {
147        set status [catch {eval blt::bgexec \
148            ::Rappture::Tool::job(control) \
149            -keepnewline yes \
150            -killsignal SIGTERM \
151            -onoutput [list [itcl::code $this _output]] \
152            -output ::Rappture::Tool::job(output) \
153            -error ::Rappture::Tool::job(error) $cmd} result]
154        }
155        # ...job is finished
156        array set times [Rappture::rusage measure]
157        puts stderr "MiddlewareTime: job=[incr jobnum] event=simulation start=$times(start) walltime=$times(walltime) cputime=$times(cputime) status=$status"
158
159    } else {
160        set job(error) "$result\n$errorInfo"
161    }
162    if {$status == 0} {
163        file delete -force -- $file
164    }
165
166    # see if the job was aborted
167    if {[regexp {^KILLED} $job(control)]} {
168        return [list 0 "ABORT"]
169    }
170
171    #
172    # If successful, return the output, which should include
173    # a reference to the run.xml file containing results.
174    #
175    if {$status == 0} {
176        set file [string trim $job(output)]
177        return [list $status $file]
178    } elseif {"" != $job(output) || "" != $job(error)} {
179        return [list $status [string trim "$job(output)\n$job(error)"]]
180    }
181    return [list $status $result]
182}
183
184# ----------------------------------------------------------------------
185# USAGE: abort
186#
187# Clients use this during a "run" to abort the current job.
188# Kills the job and forces the "run" method to return.
189# ----------------------------------------------------------------------
190itcl::body Rappture::Tool::abort {} {
191    set job(control) "abort"
192}
193
194# ----------------------------------------------------------------------
195# USAGE: _output <data>
196#
197# Used internally to send each bit of output <data> coming from the
198# tool onto the caller, so the user can see progress.
199# ----------------------------------------------------------------------
200itcl::body Rappture::Tool::_output {data} {
201    if {[string length $_outputcb] > 0} {
202        uplevel #0 [list $_outputcb $data]
203    }
204}
Note: See TracBrowser for help on using the repository browser.