1 # Copyright (c) 2005-2006 The Regents of The University of Michigan
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met: redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer;
8 # redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution;
11 # neither the name of the copyright holders nor the names of its
12 # contributors may be used to endorse or promote products derived from
13 # this software without specific prior written permission.
15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 # Authors: Nathan Binkert
31 from attrdict
import attrdict
, optiondict
32 from misc
import crossproduct
, flatten
35 def __init__(self
, name
, desc
, **kwargs
):
38 self
.__dict
__.update(kwargs
)
40 def update(self
, obj
):
41 if not isinstance(obj
, Data
):
42 raise AttributeError, "can only update from Data object"
44 for k
,v
in obj
.__dict
__.iteritems():
45 if not k
.startswith('_'):
47 if hasattr(self
, 'system') and hasattr(obj
, 'system'):
48 if self
.system
!= obj
.system
:
49 raise AttributeError, \
50 "conflicting values for system: '%s'/'%s'" % \
51 (self
.system
, obj
.system
)
55 print 'name: %s' % self
.name
57 print 'desc: %s' % self
.desc
60 print 'system: %s' % self
.system
61 except AttributeError:
64 def printverbose(self
):
67 if isinstance(val
, dict):
69 val
= pprint
.pformat(val
)
70 print '%-20s = %s' % (key
, val
)
73 def __contains__(self
, attr
):
74 if attr
.startswith('_'):
76 return attr
in self
.__dict
__
78 def __getitem__(self
, key
):
79 if key
.startswith('_'):
80 raise KeyError, "Key '%s' not found" % attr
81 return self
.__dict
__[key
]
84 keys
= self
.__dict
__.keys()
87 if not key
.startswith('_'):
93 result
[key
] = self
[key
]
100 def __init__(self
, options
):
101 super(Job
, self
).__init
__('', '')
103 config
= options
[0]._config
105 if opt
._config
!= config
:
106 raise AttributeError, \
107 "All options are not from the same Configuration"
109 self
._config
= config
110 self
._groups
= [ opt
._group
for opt
in options
]
111 self
._options
= options
113 self
.update(self
._config
)
114 for group
in self
._groups
:
117 self
._is
_checkpoint
= True
119 for option
in self
._options
:
121 if not option
._group
._checkpoint
:
122 self
._is
_checkpoint
= False
124 if option
._suboption
:
125 self
.update(option
._suboption
)
126 self
._is
_checkpoint
= False
129 for opt
in self
._options
:
131 names
.append(opt
.name
)
132 self
.name
= ':'.join(names
)
135 for opt
in self
._options
:
137 descs
.append(opt
.desc
)
138 self
.desc
= ', '.join(descs
)
140 self
._checkpoint
= None
141 if not self
._is
_checkpoint
:
144 cpt
= opt
._group
._checkpoint
147 if isinstance(cpt
, Option
):
148 opt
= cpt
.clone(suboptions
=False)
150 opt
= opt
.clone(suboptions
=False)
155 self
._checkpoint
= Job(opts
)
158 return Job(self
._options
)
161 super(Job
, self
).printinfo()
163 print 'checkpoint: %s' % self
._checkpoint
.name
164 print 'config: %s' % self
._config
.name
165 print 'groups: %s' % [ g
.name
for g
in self
._groups
]
166 print 'options: %s' % [ o
.name
for o
in self
._options
]
167 super(Job
, self
).printverbose()
169 class SubOption(Data
):
170 def __init__(self
, name
, desc
, **kwargs
):
171 super(SubOption
, self
).__init
__(name
, desc
, **kwargs
)
175 def __init__(self
, name
, desc
, **kwargs
):
176 super(Option
, self
).__init
__(name
, desc
, **kwargs
)
177 self
._suboptions
= []
178 self
._suboption
= None
181 def __getattribute__(self
, attr
):
183 name
= self
.__dict
__[attr
]
184 if self
._suboption
is not None:
185 name
= '%s:%s' % (name
, self
._suboption
.name
)
189 desc
= [ self
.__dict
__[attr
] ]
190 if self
._suboption
is not None and self
._suboption
.desc
:
191 desc
.append(self
._suboption
.desc
)
192 return ', '.join(desc
)
194 return super(Option
, self
).__getattribute
__(attr
)
196 def suboption(self
, name
, desc
, **kwargs
):
197 subo
= SubOption(name
, desc
, **kwargs
)
198 subo
._config
= self
._config
199 subo
._group
= self
._group
201 subo
._number
= len(self
._suboptions
)
202 self
._suboptions
.append(subo
)
205 def clone(self
, suboptions
=True):
206 option
= Option(self
.__dict
__['name'], self
.__dict
__['desc'])
208 option
._group
= self
._group
209 option
._config
= self
._config
210 option
._number
= self
._number
212 option
._suboptions
.extend(self
._suboptions
)
213 option
._suboption
= self
._suboption
217 if not self
._suboptions
:
221 for subo
in self
._suboptions
:
222 option
= self
.clone()
223 option
._suboption
= subo
224 subopts
.append(option
)
229 super(Option
, self
).printinfo()
230 print 'config: %s' % self
._config
.name
231 super(Option
, self
).printverbose()
234 def __init__(self
, name
, desc
, **kwargs
):
235 super(Group
, self
).__init
__(name
, desc
, **kwargs
)
238 self
._checkpoint
= False
240 def option(self
, name
, desc
, **kwargs
):
241 opt
= Option(name
, desc
, **kwargs
)
242 opt
._config
= self
._config
244 opt
._number
= len(self
._options
)
245 self
._options
.append(opt
)
253 for opt
in self
._options
:
254 for subo
in opt
.subopts():
259 super(Group
, self
).printinfo()
260 print 'config: %s' % self
._config
.name
261 print 'options: %s' % [ o
.name
for o
in self
._options
]
262 super(Group
, self
).printverbose()
264 class Configuration(Data
):
265 def __init__(self
, name
, desc
, **kwargs
):
266 super(Configuration
, self
).__init
__(name
, desc
, **kwargs
)
268 self
._posfilters
= []
269 self
._negfilters
= []
271 def group(self
, name
, desc
, **kwargs
):
272 grp
= Group(name
, desc
, **kwargs
)
274 grp
._number
= len(self
._groups
)
275 self
._groups
.append(grp
)
281 def checkchildren(self
, kids
):
283 if kid
._config
!= self
:
284 raise AttributeError, "child from the wrong configuration"
286 def sortgroups(self
, groups
):
287 groups
= [ (grp
._number
, grp
) for grp
in groups
]
289 return [ grp
[1] for grp
in groups
]
291 def options(self
, groups
=None, checkpoint
=False):
293 groups
= self
._groups
294 self
.checkchildren(groups
)
295 groups
= self
.sortgroups(groups
)
297 groups
= [ grp
for grp
in groups
if grp
._checkpoint
]
298 optgroups
= [ g
.options() for g
in groups
]
300 optgroups
= [ g
.subopts() for g
in groups
]
303 for options
in crossproduct(optgroups
):
305 cpt
= opt
._group
._checkpoint
306 if not isinstance(cpt
, bool) and cpt
!= opt
:
315 def addfilter(self
, filt
, pos
=True):
317 filt
= re
.compile(filt
)
319 self
._posfilters
.append(filt
)
321 self
._negfilters
.append(filt
)
323 def jobfilter(self
, job
):
324 for filt
in self
._negfilters
:
325 if filt
.match(job
.name
):
328 if not self
._posfilters
:
331 for filt
in self
._posfilters
:
332 if filt
.match(job
.name
):
337 def checkpoints(self
, groups
=None):
338 for options
in self
.options(groups
, True):
340 if self
.jobfilter(job
):
343 def jobs(self
, groups
=None):
344 for options
in self
.options(groups
, False):
346 if self
.jobfilter(job
):
349 def alljobs(self
, groups
=None):
350 for options
in self
.options(groups
, True):
352 for options
in self
.options(groups
, False):
355 def find(self
, jobname
):
356 for job
in self
.alljobs():
357 if job
.name
== jobname
:
360 raise AttributeError, "job '%s' not found" % jobname
362 def job(self
, options
):
363 self
.checkchildren(options
)
364 options
= [ (opt
._group
._number
, opt
) for opt
in options
]
366 options
= [ opt
[1] for opt
in options
]
371 super(Configuration
, self
).printinfo()
372 print 'groups: %s' % [ g
.name
for g
in self
._groups
]
373 super(Configuration
, self
).printverbose()
375 def JobFile(jobfile
):
376 from os
.path
import expanduser
, isfile
, join
as joinpath
377 filename
= expanduser(jobfile
)
379 # Can't find filename in the current path, search sys.path
380 if not isfile(filename
):
381 for path
in sys
.path
:
382 testname
= joinpath(path
, filename
)
387 raise AttributeError, \
388 "Could not find file '%s'" % jobfile
391 execfile(filename
, data
)
392 if 'conf' not in data
:
393 raise ImportError, 'cannot import name conf from %s' % jobfile
396 if not isinstance(conf
, Configuration
):
397 raise AttributeError, \
398 'conf in jobfile: %s (%s) is not type %s' % \
399 (jobfile
, type(conf
), Configuration
)
405 usage
= 'Usage: %s [-b] [-c] [-v] <jobfile>' % sys
.argv
[0]
409 opts
, args
= getopt
.getopt(sys
.argv
[1:], '-bcv')
410 except getopt
.GetoptError
:
427 raise AttributeError, usage
428 conf
= JobFile(args
[0])
431 raise AttributeError, usage
434 jobs
= conf
.alljobs()
436 jobs
= conf
.checkpoints()
446 cpt
= job
._checkpoint
.name
449 if __name__
== '__main__':