1 # Copyright (c) 2005 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:
282 desc
= '%s, %s' % (desc
, self
._suboption
.desc
)
285 return super(Option
, self
).__getattribute
__(attr
)
287 def suboption(self
, name
, desc
, **kwargs
):
288 subo
= SubOption(name
, desc
, **kwargs
)
289 subo
.config
= self
.config
290 subo
.group
= self
.group
292 subo
.number
= len(self
._suboptions
)
293 self
._suboptions
.append(subo
)
296 def clone(self
, suboptions
=True):
297 option
= Option(self
.__dict
__['name'], self
.__dict
__['desc'])
299 option
.group
= self
.group
300 option
.config
= self
.config
301 option
.number
= self
.number
303 option
._suboptions
.extend(self
._suboptions
)
304 option
._suboption
= self
._suboption
308 if not self
._suboptions
:
312 for subo
in self
._suboptions
:
313 option
= self
.clone()
314 option
._suboption
= subo
315 subopts
.append(option
)
320 super(Option
, self
).printinfo()
321 print 'config: %s' % self
.config
.name
322 super(Option
, self
).printverbose()
325 def __init__(self
, name
, desc
, **kwargs
):
326 super(Group
, self
).__init
__(name
, desc
, **kwargs
)
328 self
.checkpoint
= False
331 def option(self
, name
, desc
, **kwargs
):
332 opt
= Option(name
, desc
, **kwargs
)
333 opt
.config
= self
.config
335 opt
.number
= len(self
._options
)
336 self
._options
.append(opt
)
344 for opt
in self
._options
:
345 for subo
in opt
.subopts():
350 super(Group
, self
).printinfo()
351 print 'config: %s' % self
.config
.name
352 print 'options: %s' % [ o
.name
for o
in self
._options
]
353 super(Group
, self
).printverbose()
355 class Configuration(Data
):
356 def __init__(self
, name
, desc
, **kwargs
):
357 super(Configuration
, self
).__init
__(name
, desc
, **kwargs
)
360 def group(self
, name
, desc
, **kwargs
):
361 grp
= Group(name
, desc
, **kwargs
)
363 grp
.number
= len(self
._groups
)
364 self
._groups
.append(grp
)
367 def groups(self
, flags
=Flags(), sign
=True):
371 return [ grp
for grp
in self
._groups
if sign ^ grp
.flags
.match(flags
) ]
373 def checkchildren(self
, kids
):
375 if kid
.config
!= self
:
376 raise AttributeError, "child from the wrong configuration"
378 def sortgroups(self
, groups
):
379 groups
= [ (grp
.number
, grp
) for grp
in groups
]
381 return [ grp
[1] for grp
in groups
]
383 def options(self
, groups
= None, checkpoint
= False):
385 groups
= self
._groups
386 self
.checkchildren(groups
)
387 groups
= self
.sortgroups(groups
)
389 groups
= [ grp
for grp
in groups
if grp
.checkpoint
]
390 optgroups
= [ g
.options() for g
in groups
]
392 optgroups
= [ g
.subopts() for g
in groups
]
393 for options
in crossproduct(optgroups
):
395 cpt
= opt
.group
.checkpoint
396 if not isinstance(cpt
, bool) and cpt
!= opt
:
405 def checkpoints(self
, groups
= None):
406 for options
in self
.options(groups
, True):
409 def jobs(self
, groups
= None):
410 for options
in self
.options(groups
, False):
413 def alljobs(self
, groups
= None):
414 for options
in self
.options(groups
, True):
416 for options
in self
.options(groups
, False):
419 def find(self
, jobname
):
420 for job
in self
.alljobs():
421 if job
.name
== jobname
:
424 raise AttributeError, "job '%s' not found" % jobname
426 def job(self
, options
):
427 self
.checkchildren(options
)
428 options
= [ (opt
.group
.number
, opt
) for opt
in options
]
430 options
= [ opt
[1] for opt
in options
]
435 super(Configuration
, self
).printinfo()
436 print 'groups: %s' % [ g
.name
for g
in self
._grouips
]
437 super(Configuration
, self
).printverbose()
439 def JobFile(jobfile
):
440 from os
.path
import expanduser
, isfile
, join
as joinpath
441 filename
= expanduser(jobfile
)
443 # Can't find filename in the current path, search sys.path
444 if not isfile(filename
):
445 for path
in sys
.path
:
446 testname
= joinpath(path
, filename
)
451 raise AttributeError, \
452 "Could not find file '%s'" % jobfile
455 execfile(filename
, data
)
456 if 'conf' not in data
:
457 raise ImportError, 'cannot import name conf from %s' % jobfile
460 if not isinstance(conf
, Configuration
):
461 raise AttributeError, \
462 'conf in jobfile: %s (%s) is not type %s' % \
463 (jobfile
, type(conf
), Configuration
)
466 if __name__
== '__main__':
467 from jobfile
import *
470 usage
= 'Usage: %s [-b] [-c] [-v] <jobfile>' % sys
.argv
[0]
474 opts
, args
= getopt
.getopt(sys
.argv
[1:], '-bcv')
475 except getopt
.GetoptError
:
479 raise AttributeError, usage
494 conf
= JobFile(jobfile
)
499 gen
= conf
.checkpoints()
507 cpt
= job
.checkpoint
.name