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 class ternary(object):
32 def __new__(cls
, *args
):
35 '%s() takes at most 1 argument (%d given)' % \
36 (cls
.__name
__, len(args
))
39 if not isinstance(args
[0], (bool, ternary
)):
41 '%s() argument must be True, False, or Any' % \
44 return super(ternary
, cls
).__new
__(cls
)
52 def __eq__(self
, other
):
55 def __ne__(self
, other
):
67 def __init__(self
, *args
, **kwargs
):
68 super(Flags
, self
).__init
__()
69 self
.update(*args
, **kwargs
)
71 def __getattr__(self
, attr
):
74 def __setattr__(self
, attr
, value
):
77 def __setitem__(self
, item
, value
):
78 return super(Flags
, self
).__setitem
__(item
, ternary(value
))
80 def __getitem__(self
, item
):
83 return super(Flags
, self
).__getitem
__(item
)
85 def update(self
, *args
, **kwargs
):
87 if isinstance(arg
, Flags
):
88 super(Flags
, self
).update(arg
)
89 elif isinstance(arg
, dict):
90 for key
,val
in kwargs
.iteritems():
93 raise AttributeError, \
94 'flags not of type %s or %s, but %s' % \
95 (Flags
, dict, type(arg
))
97 for key
,val
in kwargs
.iteritems():
100 def match(self
, *args
, **kwargs
):
101 match
= Flags(*args
, **kwargs
)
103 for key
,value
in match
.iteritems():
104 if self
[key
] != value
:
109 def crossproduct(items
):
110 if not isinstance(items
, (list, tuple)):
111 raise AttributeError, 'crossproduct works only on sequences'
118 remainder
= items
[1:]
120 if not hasattr(current
, '__iter__'):
121 current
= [ current
]
124 for rem
in crossproduct(remainder
):
131 if not isinstance(items
, (list, tuple)):
136 for flat
in flatten(item
):
140 def __init__(self
, name
, desc
, **kwargs
):
146 for k
,v
in kwargs
.iteritems():
149 def update(self
, obj
):
150 if not isinstance(obj
, Data
):
151 raise AttributeError, "can only update from Data object"
153 self
.env
.update(obj
.env
)
154 self
.flags
.update(obj
.flags
)
156 if self
.system
and self
.system
!= obj
.system
:
157 raise AttributeError, \
158 "conflicting values for system: '%s'/'%s'" % \
159 (self
.system
, obj
.system
)
160 self
.system
= obj
.system
164 print 'name: %s' % self
.name
166 print 'desc: %s' % self
.desc
168 print 'system: %s' % self
.system
170 def printverbose(self
):
172 keys
= self
.flags
.keys()
175 print ' %s = %s' % (key
, self
.flags
[key
])
177 keys
= self
.env
.keys()
180 print ' %s = %s' % (key
, self
.env
[key
])
187 def __init__(self
, options
):
188 super(Job
, self
).__init
__('', '')
189 self
.setoptions(options
)
191 self
.checkpoint
= False
194 cpt
= opt
.group
.checkpoint
196 self
.checkpoint
= True
198 if isinstance(cpt
, Option
):
199 opt
= cpt
.clone(suboptions
=False)
201 opt
= opt
.clone(suboptions
=False)
206 self
.checkpoint
= False
209 self
.checkpoint
= Job(opts
)
212 return Job(self
.options
)
214 def __getattribute__(self
, attr
):
217 for opt
in self
.options
:
219 names
.append(opt
.name
)
220 return ':'.join(names
)
224 for opt
in self
.options
:
226 descs
.append(opt
.desc
)
227 return ', '.join(descs
)
229 return super(Job
, self
).__getattribute
__(attr
)
231 def setoptions(self
, options
):
232 config
= options
[0].config
234 if opt
.config
!= config
:
235 raise AttributeError, \
236 "All options are not from the same Configuration"
239 self
.groups
= [ opt
.group
for opt
in options
]
240 self
.options
= options
242 self
.update(self
.config
)
243 for group
in self
.groups
:
246 for option
in self
.options
:
248 if option
._suboption
:
249 self
.update(option
._suboption
)
252 super(Job
, self
).printinfo()
254 print 'checkpoint: %s' % self
.checkpoint
.name
255 print 'config: %s' % self
.config
.name
256 print 'groups: %s' % [ g
.name
for g
in self
.groups
]
257 print 'options: %s' % [ o
.name
for o
in self
.options
]
258 super(Job
, self
).printverbose()
260 class SubOption(Data
):
261 def __init__(self
, name
, desc
, **kwargs
):
262 super(SubOption
, self
).__init
__(name
, desc
, **kwargs
)
266 def __init__(self
, name
, desc
, **kwargs
):
267 super(Option
, self
).__init
__(name
, desc
, **kwargs
)
268 self
._suboptions
= []
269 self
._suboption
= None
272 def __getattribute__(self
, attr
):
274 name
= self
.__dict
__[attr
]
275 if self
._suboption
is not None:
276 name
= '%s:%s' % (name
, self
._suboption
.name
)
280 desc
= [ self
.__dict
__[attr
] ]
281 if self
._suboption
is not None and self
._suboption
.desc
:
282 desc
.append(self
._suboption
.desc
)
283 return ', '.join(desc
)
286 return super(Option
, self
).__getattribute
__(attr
)
288 def suboption(self
, name
, desc
, **kwargs
):
289 subo
= SubOption(name
, desc
, **kwargs
)
290 subo
.config
= self
.config
291 subo
.group
= self
.group
293 subo
.number
= len(self
._suboptions
)
294 self
._suboptions
.append(subo
)
297 def clone(self
, suboptions
=True):
298 option
= Option(self
.__dict
__['name'], self
.__dict
__['desc'])
300 option
.group
= self
.group
301 option
.config
= self
.config
302 option
.number
= self
.number
304 option
._suboptions
.extend(self
._suboptions
)
305 option
._suboption
= self
._suboption
309 if not self
._suboptions
:
313 for subo
in self
._suboptions
:
314 option
= self
.clone()
315 option
._suboption
= subo
316 subopts
.append(option
)
321 super(Option
, self
).printinfo()
322 print 'config: %s' % self
.config
.name
323 super(Option
, self
).printverbose()
326 def __init__(self
, name
, desc
, **kwargs
):
327 super(Group
, self
).__init
__(name
, desc
, **kwargs
)
329 self
.checkpoint
= False
332 def option(self
, name
, desc
, **kwargs
):
333 opt
= Option(name
, desc
, **kwargs
)
334 opt
.config
= self
.config
336 opt
.number
= len(self
._options
)
337 self
._options
.append(opt
)
345 for opt
in self
._options
:
346 for subo
in opt
.subopts():
351 super(Group
, self
).printinfo()
352 print 'config: %s' % self
.config
.name
353 print 'options: %s' % [ o
.name
for o
in self
._options
]
354 super(Group
, self
).printverbose()
356 class Configuration(Data
):
357 def __init__(self
, name
, desc
, **kwargs
):
358 super(Configuration
, self
).__init
__(name
, desc
, **kwargs
)
360 self
._posfilters
= []
361 self
._negfilters
= []
363 def group(self
, name
, desc
, **kwargs
):
364 grp
= Group(name
, desc
, **kwargs
)
366 grp
.number
= len(self
._groups
)
367 self
._groups
.append(grp
)
370 def groups(self
, flags
=Flags(), sign
=True):
374 return [ grp
for grp
in self
._groups
if sign ^ grp
.flags
.match(flags
) ]
376 def checkchildren(self
, kids
):
378 if kid
.config
!= self
:
379 raise AttributeError, "child from the wrong configuration"
381 def sortgroups(self
, groups
):
382 groups
= [ (grp
.number
, grp
) for grp
in groups
]
384 return [ grp
[1] for grp
in groups
]
386 def options(self
, groups
= None, checkpoint
= False):
388 groups
= self
._groups
389 self
.checkchildren(groups
)
390 groups
= self
.sortgroups(groups
)
392 groups
= [ grp
for grp
in groups
if grp
.checkpoint
]
393 optgroups
= [ g
.options() for g
in groups
]
395 optgroups
= [ g
.subopts() for g
in groups
]
396 for options
in crossproduct(optgroups
):
398 cpt
= opt
.group
.checkpoint
399 if not isinstance(cpt
, bool) and cpt
!= opt
:
408 def addfilter(self
, filt
, pos
=True):
410 filt
= re
.compile(filt
)
412 self
._posfilters
.append(filt
)
414 self
._negfilters
.append(filt
)
416 def jobfilter(self
, job
):
417 for filt
in self
._negfilters
:
418 if filt
.match(job
.name
):
421 if not self
._posfilters
:
424 for filt
in self
._posfilters
:
425 if filt
.match(job
.name
):
430 def checkpoints(self
, groups
= None):
431 for options
in self
.options(groups
, True):
433 if self
.jobfilter(job
):
436 def jobs(self
, groups
= None):
437 for options
in self
.options(groups
, False):
439 if self
.jobfilter(job
):
442 def alljobs(self
, groups
= None):
443 for options
in self
.options(groups
, True):
445 for options
in self
.options(groups
, False):
448 def find(self
, jobname
):
449 for job
in self
.alljobs():
450 if job
.name
== jobname
:
453 raise AttributeError, "job '%s' not found" % jobname
455 def job(self
, options
):
456 self
.checkchildren(options
)
457 options
= [ (opt
.group
.number
, opt
) for opt
in options
]
459 options
= [ opt
[1] for opt
in options
]
464 super(Configuration
, self
).printinfo()
465 print 'groups: %s' % [ g
.name
for g
in self
._grouips
]
466 super(Configuration
, self
).printverbose()
468 def JobFile(jobfile
):
469 from os
.path
import expanduser
, isfile
, join
as joinpath
470 filename
= expanduser(jobfile
)
472 # Can't find filename in the current path, search sys.path
473 if not isfile(filename
):
474 for path
in sys
.path
:
475 testname
= joinpath(path
, filename
)
480 raise AttributeError, \
481 "Could not find file '%s'" % jobfile
484 execfile(filename
, data
)
485 if 'conf' not in data
:
486 raise ImportError, 'cannot import name conf from %s' % jobfile
489 if not isinstance(conf
, Configuration
):
490 raise AttributeError, \
491 'conf in jobfile: %s (%s) is not type %s' % \
492 (jobfile
, type(conf
), Configuration
)
495 if __name__
== '__main__':
496 from jobfile
import *
499 usage
= 'Usage: %s [-b] [-c] [-v] <jobfile>' % sys
.argv
[0]
503 opts
, args
= getopt
.getopt(sys
.argv
[1:], '-bcv')
504 except getopt
.GetoptError
:
508 raise AttributeError, usage
523 conf
= JobFile(jobfile
)
528 gen
= conf
.checkpoints()
536 cpt
= job
.checkpoint
.name