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 optiondict
32 from misc
import crossproduct
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 key
,val
in obj
.__dict
__.iteritems():
45 if key
.startswith('_') or key
in ('name', 'desc'):
48 if key
not in self
.__dict
__:
49 self
.__dict
__[key
] = val
52 if not isinstance(val
, dict):
53 if self
.__dict
__[key
] == val
:
56 raise AttributeError, \
57 "%s specified more than once old: %s new: %s" % \
58 (key
, self
.__dict
__[key
], val
)
60 d
= self
.__dict
__[key
]
61 for k
,v
in val
.iteritems():
63 raise AttributeError, \
64 "%s specified more than once in %s" % (k
, key
)
67 if hasattr(self
, 'system') and hasattr(obj
, 'system'):
68 if self
.system
!= obj
.system
:
69 raise AttributeError, \
70 "conflicting values for system: '%s'/'%s'" % \
71 (self
.system
, obj
.system
)
75 print 'name: %s' % self
.name
77 print 'desc: %s' % self
.desc
80 print 'system: %s' % self
.system
81 except AttributeError:
84 def printverbose(self
):
87 if isinstance(val
, dict):
89 val
= pprint
.pformat(val
)
90 print '%-20s = %s' % (key
, val
)
93 def __contains__(self
, attr
):
94 if attr
.startswith('_'):
96 return attr
in self
.__dict
__
98 def __getitem__(self
, key
):
99 if key
.startswith('_'):
100 raise KeyError, "Key '%s' not found" % attr
101 return self
.__dict
__[key
]
104 keys
= self
.__dict
__.keys()
107 if not key
.startswith('_'):
110 def optiondict(self
):
111 result
= optiondict()
113 result
[key
] = self
[key
]
118 for key
,value
in self
.__dict
__.iteritems():
119 if not key
.startswith('_'):
122 return "<%s: %s>" % (type(self
).__name
__, d
)
128 def __init__(self
, options
):
129 super(Job
, self
).__init
__('', '')
131 config
= options
[0]._config
133 if opt
._config
!= config
:
134 raise AttributeError, \
135 "All options are not from the same Configuration"
137 self
._config
= config
138 self
._groups
= [ opt
._group
for opt
in options
]
139 self
._options
= options
141 self
.update(self
._config
)
142 for group
in self
._groups
:
145 self
._is
_checkpoint
= True
147 for option
in self
._options
:
149 if not option
._group
._checkpoint
:
150 self
._is
_checkpoint
= False
152 if option
._suboption
:
153 self
.update(option
._suboption
)
154 self
._is
_checkpoint
= False
157 for opt
in self
._options
:
159 names
.append(opt
.name
)
160 self
.name
= ':'.join(names
)
163 for opt
in self
._options
:
165 descs
.append(opt
.desc
)
166 self
.desc
= ', '.join(descs
)
168 self
._checkpoint
= None
169 if not self
._is
_checkpoint
:
172 cpt
= opt
._group
._checkpoint
175 if isinstance(cpt
, Option
):
176 opt
= cpt
.clone(suboptions
=False)
178 opt
= opt
.clone(suboptions
=False)
183 self
._checkpoint
= Job(opts
)
186 return Job(self
._options
)
189 super(Job
, self
).printinfo()
191 print 'checkpoint: %s' % self
._checkpoint
.name
192 print 'config: %s' % self
._config
.name
193 print 'groups: %s' % [ g
.name
for g
in self
._groups
]
194 print 'options: %s' % [ o
.name
for o
in self
._options
]
195 super(Job
, self
).printverbose()
197 class SubOption(Data
):
198 def __init__(self
, name
, desc
, **kwargs
):
199 super(SubOption
, self
).__init
__(name
, desc
, **kwargs
)
203 def __init__(self
, name
, desc
, **kwargs
):
204 super(Option
, self
).__init
__(name
, desc
, **kwargs
)
205 self
._suboptions
= []
206 self
._suboption
= None
209 def __getattribute__(self
, attr
):
211 name
= self
.__dict
__[attr
]
212 if self
._suboption
is not None:
213 name
= '%s:%s' % (name
, self
._suboption
.name
)
217 desc
= [ self
.__dict
__[attr
] ]
218 if self
._suboption
is not None and self
._suboption
.desc
:
219 desc
.append(self
._suboption
.desc
)
220 return ', '.join(desc
)
222 return super(Option
, self
).__getattribute
__(attr
)
224 def suboption(self
, name
, desc
, **kwargs
):
225 subo
= SubOption(name
, desc
, **kwargs
)
226 subo
._config
= self
._config
227 subo
._group
= self
._group
229 subo
._number
= len(self
._suboptions
)
230 self
._suboptions
.append(subo
)
233 def clone(self
, suboptions
=True):
234 option
= Option(self
.__dict
__['name'], self
.__dict
__['desc'])
236 option
._group
= self
._group
237 option
._config
= self
._config
238 option
._number
= self
._number
240 option
._suboptions
.extend(self
._suboptions
)
241 option
._suboption
= self
._suboption
245 if not self
._suboptions
:
249 for subo
in self
._suboptions
:
250 option
= self
.clone()
251 option
._suboption
= subo
252 subopts
.append(option
)
257 super(Option
, self
).printinfo()
258 print 'config: %s' % self
._config
.name
259 super(Option
, self
).printverbose()
262 def __init__(self
, name
, desc
, **kwargs
):
263 super(Group
, self
).__init
__(name
, desc
, **kwargs
)
266 self
._checkpoint
= False
268 def option(self
, name
, desc
, **kwargs
):
269 opt
= Option(name
, desc
, **kwargs
)
270 opt
._config
= self
._config
272 opt
._number
= len(self
._options
)
273 self
._options
.append(opt
)
281 for opt
in self
._options
:
282 for subo
in opt
.subopts():
287 super(Group
, self
).printinfo()
288 print 'config: %s' % self
._config
.name
289 print 'options: %s' % [ o
.name
for o
in self
._options
]
290 super(Group
, self
).printverbose()
292 class Configuration(Data
):
293 def __init__(self
, name
, desc
, **kwargs
):
294 super(Configuration
, self
).__init
__(name
, desc
, **kwargs
)
296 self
._posfilters
= []
297 self
._negfilters
= []
299 def group(self
, name
, desc
, **kwargs
):
300 grp
= Group(name
, desc
, **kwargs
)
302 grp
._number
= len(self
._groups
)
303 self
._groups
.append(grp
)
309 def checkchildren(self
, kids
):
311 if kid
._config
!= self
:
312 raise AttributeError, "child from the wrong configuration"
314 def sortgroups(self
, groups
):
315 groups
= [ (grp
._number
, grp
) for grp
in groups
]
317 return [ grp
[1] for grp
in groups
]
319 def options(self
, groups
=None, checkpoint
=False):
321 groups
= self
._groups
322 self
.checkchildren(groups
)
323 groups
= self
.sortgroups(groups
)
325 groups
= [ grp
for grp
in groups
if grp
._checkpoint
]
326 optgroups
= [ g
.options() for g
in groups
]
328 optgroups
= [ g
.subopts() for g
in groups
]
331 for options
in crossproduct(optgroups
):
333 cpt
= opt
._group
._checkpoint
334 if not isinstance(cpt
, bool) and cpt
!= opt
:
343 def addfilter(self
, filt
, pos
=True):
345 filt
= re
.compile(filt
)
347 self
._posfilters
.append(filt
)
349 self
._negfilters
.append(filt
)
351 def jobfilter(self
, job
):
352 for filt
in self
._negfilters
:
353 if filt
.match(job
.name
):
356 if not self
._posfilters
:
359 for filt
in self
._posfilters
:
360 if filt
.match(job
.name
):
365 def checkpoints(self
, groups
=None):
366 for options
in self
.options(groups
, True):
368 if self
.jobfilter(job
):
371 def jobs(self
, groups
=None):
372 for options
in self
.options(groups
, False):
374 if self
.jobfilter(job
):
377 def alljobs(self
, groups
=None):
378 for options
in self
.options(groups
, True):
380 for options
in self
.options(groups
, False):
383 def find(self
, jobname
):
384 for job
in self
.alljobs():
385 if job
.name
== jobname
:
388 raise AttributeError, "job '%s' not found" % jobname
390 def job(self
, options
):
391 self
.checkchildren(options
)
392 options
= [ (opt
._group
._number
, opt
) for opt
in options
]
394 options
= [ opt
[1] for opt
in options
]
399 super(Configuration
, self
).printinfo()
400 print 'groups: %s' % [ g
.name
for g
in self
._groups
]
401 super(Configuration
, self
).printverbose()
403 def JobFile(jobfile
):
404 from os
.path
import expanduser
, isfile
, join
as joinpath
405 filename
= expanduser(jobfile
)
407 # Can't find filename in the current path, search sys.path
408 if not isfile(filename
):
409 for path
in sys
.path
:
410 testname
= joinpath(path
, filename
)
415 raise AttributeError, \
416 "Could not find file '%s'" % jobfile
419 execfile(filename
, data
)
420 if 'conf' not in data
:
421 raise ImportError, 'cannot import name conf from %s' % jobfile
425 usage
= 'Usage: %s [-b] [-c] [-v]' % sys
.argv
[0]
427 usage
+= ' <jobfile>'
431 opts
, args
= getopt
.getopt(sys
.argv
[1:], '-bcv')
432 except getopt
.GetoptError
:
449 raise AttributeError, usage
450 conf
= JobFile(args
[0])
453 raise AttributeError, usage
456 jobs
= conf
.alljobs()
458 jobs
= conf
.checkpoints()
468 cpt
= job
._checkpoint
.name
471 if __name__
== '__main__':