diff --git a/src/python/SConscript b/src/python/SConscript index b39c9ea9c..0785b4307 100644 --- a/src/python/SConscript +++ b/src/python/SConscript @@ -36,18 +36,20 @@ Source('swig/pyobject.cc') PySource('m5', 'm5/__init__.py') PySource('m5', 'm5/SimObject.py') -PySource('m5', 'm5/attrdict.py') PySource('m5', 'm5/convert.py') PySource('m5', 'm5/event.py') PySource('m5', 'm5/main.py') -PySource('m5', 'm5/multidict.py') PySource('m5', 'm5/params.py') PySource('m5', 'm5/proxy.py') PySource('m5', 'm5/simulate.py') PySource('m5', 'm5/smartdict.py') PySource('m5', 'm5/stats.py') PySource('m5', 'm5/ticks.py') -PySource('m5', 'm5/util.py') +PySource('m5.util', 'm5/util/__init__.py') +PySource('m5.util', 'm5/util/attrdict.py') +PySource('m5.util', 'm5/util/jobfile.py') +PySource('m5.util', 'm5/util/misc.py') +PySource('m5.util', 'm5/util/multidict.py') SwigSource('m5.internal', 'swig/core.i') SwigSource('m5.internal', 'swig/debug.i') diff --git a/src/python/m5/SimObject.py b/src/python/m5/SimObject.py index d1aec44b3..41ed3df9e 100644 --- a/src/python/m5/SimObject.py +++ b/src/python/m5/SimObject.py @@ -32,7 +32,6 @@ import sys, types import proxy import m5 from util import * -from multidict import multidict # These utility functions have to come first because they're # referenced in params.py... otherwise they won't be defined when we diff --git a/src/python/m5/main.py b/src/python/m5/main.py index cbdd65492..5c3324224 100644 --- a/src/python/m5/main.py +++ b/src/python/m5/main.py @@ -33,7 +33,7 @@ import os import socket import sys -from attrdict import attrdict +from util import attrdict import defines import traceflags diff --git a/src/python/m5/util/__init__.py b/src/python/m5/util/__init__.py new file mode 100644 index 000000000..f82de696a --- /dev/null +++ b/src/python/m5/util/__init__.py @@ -0,0 +1,32 @@ +# Copyright (c) 2008 The Hewlett-Packard Development Company +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Nathan Binkert + +from attrdict import attrdict, optiondict +from misc import * +from multidict import multidict +import jobfile diff --git a/src/python/m5/attrdict.py b/src/python/m5/util/attrdict.py similarity index 88% rename from src/python/m5/attrdict.py rename to src/python/m5/util/attrdict.py index 4ee7f1b8c..44479c456 100644 --- a/src/python/m5/attrdict.py +++ b/src/python/m5/util/attrdict.py @@ -26,7 +26,7 @@ # # Authors: Nathan Binkert -__all__ = [ 'attrdict' ] +__all__ = [ 'attrdict', 'optiondict' ] class attrdict(dict): def __getattr__(self, attr): @@ -44,6 +44,15 @@ class attrdict(dict): return self.__delitem__(attr) return super(attrdict, self).__delattr__(attr, value) +class optiondict(attrdict): + def __getattr__(self, attr): + try: + return super(optiondict, self).__getattr__(attr) + except AttributeError: + #d = optionsdict() + #setattr(self, attr, d) + return None + if __name__ == '__main__': x = attrdict() x.y = 1 diff --git a/util/pbs/jobfile.py b/src/python/m5/util/jobfile.py similarity index 58% rename from util/pbs/jobfile.py rename to src/python/m5/util/jobfile.py index fd19b3bf5..5e015c4ad 100644 --- a/util/pbs/jobfile.py +++ b/src/python/m5/util/jobfile.py @@ -28,246 +28,155 @@ import sys -class ternary(object): - def __new__(cls, *args): - if len(args) > 1: - raise TypeError, \ - '%s() takes at most 1 argument (%d given)' % \ - (cls.__name__, len(args)) - - if args: - if not isinstance(args[0], (bool, ternary)): - raise TypeError, \ - '%s() argument must be True, False, or Any' % \ - cls.__name__ - return args[0] - return super(ternary, cls).__new__(cls) - - def __bool__(self): - return True - - def __neg__(self): - return self - - def __eq__(self, other): - return True - - def __ne__(self, other): - return False - - def __str__(self): - return 'Any' - - def __repr__(self): - return 'Any' - -Any = ternary() - -class Flags(dict): - def __init__(self, *args, **kwargs): - super(Flags, self).__init__() - self.update(*args, **kwargs) - - def __getattr__(self, attr): - return self[attr] - - def __setattr__(self, attr, value): - self[attr] = value - - def __setitem__(self, item, value): - return super(Flags, self).__setitem__(item, ternary(value)) - - def __getitem__(self, item): - if item not in self: - return False - return super(Flags, self).__getitem__(item) - - def update(self, *args, **kwargs): - for arg in args: - if isinstance(arg, Flags): - super(Flags, self).update(arg) - elif isinstance(arg, dict): - for key,val in kwargs.iteritems(): - self[key] = val - else: - raise AttributeError, \ - 'flags not of type %s or %s, but %s' % \ - (Flags, dict, type(arg)) - - for key,val in kwargs.iteritems(): - self[key] = val - - def match(self, *args, **kwargs): - match = Flags(*args, **kwargs) - - for key,value in match.iteritems(): - if self[key] != value: - return False - - return True - -def crossproduct(items): - if not isinstance(items, (list, tuple)): - raise AttributeError, 'crossproduct works only on sequences' - - if not items: - yield None - return - - current = items[0] - remainder = items[1:] - - if not hasattr(current, '__iter__'): - current = [ current ] - - for item in current: - for rem in crossproduct(remainder): - data = [ item ] - if rem: - data += rem - yield data - -def flatten(items): - if not isinstance(items, (list, tuple)): - yield items - return - - for item in items: - for flat in flatten(item): - yield flat +from attrdict import attrdict, optiondict +from misc import crossproduct, flatten class Data(object): def __init__(self, name, desc, **kwargs): self.name = name self.desc = desc - self.system = None - self.flags = Flags() - self.env = {} - for k,v in kwargs.iteritems(): - setattr(self, k, v) + self.__dict__.update(kwargs) def update(self, obj): if not isinstance(obj, Data): raise AttributeError, "can only update from Data object" - self.env.update(obj.env) - self.flags.update(obj.flags) - if obj.system: - if self.system and self.system != obj.system: + for k,v in obj.__dict__.iteritems(): + if not k.startswith('_'): + self.__dict__[k] = v + if hasattr(self, 'system') and hasattr(obj, 'system'): + if self.system != obj.system: raise AttributeError, \ "conflicting values for system: '%s'/'%s'" % \ (self.system, obj.system) - self.system = obj.system def printinfo(self): if self.name: print 'name: %s' % self.name if self.desc: print 'desc: %s' % self.desc - if self.system: - print 'system: %s' % self.system + try: + if self.system: + print 'system: %s' % self.system + except AttributeError: + pass def printverbose(self): - print 'flags:' - keys = self.flags.keys() - keys.sort() - for key in keys: - print ' %s = %s' % (key, self.flags[key]) - print 'env:' - keys = self.env.keys() - keys.sort() - for key in keys: - print ' %s = %s' % (key, self.env[key]) + for key in self: + val = self[key] + if isinstance(val, dict): + import pprint + val = pprint.pformat(val) + print '%-20s = %s' % (key, val) print + def __contains__(self, attr): + if attr.startswith('_'): + return False + return attr in self.__dict__ + + def __getitem__(self, key): + if key.startswith('_'): + raise KeyError, "Key '%s' not found" % attr + return self.__dict__[key] + + def __iter__(self): + keys = self.__dict__.keys() + keys.sort() + for key in keys: + if not key.startswith('_'): + yield key + + def optiondict(self): + result = optiondict() + for key in self: + result[key] = self[key] + return result + def __str__(self): return self.name class Job(Data): def __init__(self, options): super(Job, self).__init__('', '') - self.setoptions(options) - self.checkpoint = False - opts = [] + config = options[0]._config for opt in options: - cpt = opt.group.checkpoint - if not cpt: - self.checkpoint = True - continue - if isinstance(cpt, Option): - opt = cpt.clone(suboptions=False) - else: - opt = opt.clone(suboptions=False) - - opts.append(opt) - - if not opts: - self.checkpoint = False - - if self.checkpoint: - self.checkpoint = Job(opts) - - def clone(self): - return Job(self.options) - - def __getattribute__(self, attr): - if attr == 'name': - names = [ ] - for opt in self.options: - if opt.name: - names.append(opt.name) - return ':'.join(names) - - if attr == 'desc': - descs = [ ] - for opt in self.options: - if opt.desc: - descs.append(opt.desc) - return ', '.join(descs) - - return super(Job, self).__getattribute__(attr) - - def setoptions(self, options): - config = options[0].config - for opt in options: - if opt.config != config: + if opt._config != config: raise AttributeError, \ "All options are not from the same Configuration" - self.config = config - self.groups = [ opt.group for opt in options ] - self.options = options + self._config = config + self._groups = [ opt._group for opt in options ] + self._options = options - self.update(self.config) - for group in self.groups: + self.update(self._config) + for group in self._groups: self.update(group) - for option in self.options: + self._is_checkpoint = True + + for option in self._options: self.update(option) + if not option._group._checkpoint: + self._is_checkpoint = False + if option._suboption: self.update(option._suboption) + self._is_checkpoint = False + + names = [ ] + for opt in self._options: + if opt.name: + names.append(opt.name) + self.name = ':'.join(names) + + descs = [ ] + for opt in self._options: + if opt.desc: + descs.append(opt.desc) + self.desc = ', '.join(descs) + + self._checkpoint = None + if not self._is_checkpoint: + opts = [] + for opt in options: + cpt = opt._group._checkpoint + if not cpt: + continue + if isinstance(cpt, Option): + opt = cpt.clone(suboptions=False) + else: + opt = opt.clone(suboptions=False) + + opts.append(opt) + + if opts: + self._checkpoint = Job(opts) + + def clone(self): + return Job(self._options) def printinfo(self): super(Job, self).printinfo() - if self.checkpoint: - print 'checkpoint: %s' % self.checkpoint.name - print 'config: %s' % self.config.name - print 'groups: %s' % [ g.name for g in self.groups ] - print 'options: %s' % [ o.name for o in self.options ] + if self._checkpoint: + print 'checkpoint: %s' % self._checkpoint.name + print 'config: %s' % self._config.name + print 'groups: %s' % [ g.name for g in self._groups ] + print 'options: %s' % [ o.name for o in self._options ] super(Job, self).printverbose() class SubOption(Data): def __init__(self, name, desc, **kwargs): super(SubOption, self).__init__(name, desc, **kwargs) - self.number = None + self._number = None class Option(Data): def __init__(self, name, desc, **kwargs): super(Option, self).__init__(name, desc, **kwargs) self._suboptions = [] self._suboption = None - self.number = None + self._number = None def __getattribute__(self, attr): if attr == 'name': @@ -282,24 +191,23 @@ class Option(Data): desc.append(self._suboption.desc) return ', '.join(desc) - return super(Option, self).__getattribute__(attr) def suboption(self, name, desc, **kwargs): subo = SubOption(name, desc, **kwargs) - subo.config = self.config - subo.group = self.group - subo.option = self - subo.number = len(self._suboptions) + subo._config = self._config + subo._group = self._group + subo._option = self + subo._number = len(self._suboptions) self._suboptions.append(subo) return subo def clone(self, suboptions=True): option = Option(self.__dict__['name'], self.__dict__['desc']) option.update(self) - option.group = self.group - option.config = self.config - option.number = self.number + option._group = self._group + option._config = self._config + option._number = self._number if suboptions: option._suboptions.extend(self._suboptions) option._suboption = self._suboption @@ -319,21 +227,21 @@ class Option(Data): def printinfo(self): super(Option, self).printinfo() - print 'config: %s' % self.config.name + print 'config: %s' % self._config.name super(Option, self).printverbose() class Group(Data): def __init__(self, name, desc, **kwargs): super(Group, self).__init__(name, desc, **kwargs) self._options = [] - self.checkpoint = False - self.number = None + self._number = None + self._checkpoint = False def option(self, name, desc, **kwargs): opt = Option(name, desc, **kwargs) - opt.config = self.config - opt.group = self - opt.number = len(self._options) + opt._config = self._config + opt._group = self + opt._number = len(self._options) self._options.append(opt) return opt @@ -349,7 +257,7 @@ class Group(Data): def printinfo(self): super(Group, self).printinfo() - print 'config: %s' % self.config.name + print 'config: %s' % self._config.name print 'options: %s' % [ o.name for o in self._options ] super(Group, self).printverbose() @@ -362,40 +270,39 @@ class Configuration(Data): def group(self, name, desc, **kwargs): grp = Group(name, desc, **kwargs) - grp.config = self - grp.number = len(self._groups) + grp._config = self + grp._number = len(self._groups) self._groups.append(grp) return grp - def groups(self, flags=Flags(), sign=True): - if not flags: - return self._groups - - return [ grp for grp in self._groups if sign ^ grp.flags.match(flags) ] + def groups(self): + return self._groups def checkchildren(self, kids): for kid in kids: - if kid.config != self: + if kid._config != self: raise AttributeError, "child from the wrong configuration" def sortgroups(self, groups): - groups = [ (grp.number, grp) for grp in groups ] + groups = [ (grp._number, grp) for grp in groups ] groups.sort() return [ grp[1] for grp in groups ] - def options(self, groups = None, checkpoint = False): + def options(self, groups=None, checkpoint=False): if groups is None: groups = self._groups self.checkchildren(groups) groups = self.sortgroups(groups) if checkpoint: - groups = [ grp for grp in groups if grp.checkpoint ] + groups = [ grp for grp in groups if grp._checkpoint ] optgroups = [ g.options() for g in groups ] else: optgroups = [ g.subopts() for g in groups ] + if not optgroups: + return for options in crossproduct(optgroups): for opt in options: - cpt = opt.group.checkpoint + cpt = opt._group._checkpoint if not isinstance(cpt, bool) and cpt != opt: if checkpoint: break @@ -427,19 +334,19 @@ class Configuration(Data): return False - def checkpoints(self, groups = None): + def checkpoints(self, groups=None): for options in self.options(groups, True): job = Job(options) if self.jobfilter(job): yield job - def jobs(self, groups = None): + def jobs(self, groups=None): for options in self.options(groups, False): job = Job(options) if self.jobfilter(job): yield job - def alljobs(self, groups = None): + def alljobs(self, groups=None): for options in self.options(groups, True): yield Job(options) for options in self.options(groups, False): @@ -454,7 +361,7 @@ class Configuration(Data): def job(self, options): self.checkchildren(options) - options = [ (opt.group.number, opt) for opt in options ] + options = [ (opt._group._number, opt) for opt in options ] options.sort() options = [ opt[1] for opt in options ] job = Job(options) @@ -462,7 +369,7 @@ class Configuration(Data): def printinfo(self): super(Configuration, self).printinfo() - print 'groups: %s' % [ g.name for g in self._grouips ] + print 'groups: %s' % [ g.name for g in self._groups ] super(Configuration, self).printverbose() def JobFile(jobfile): @@ -492,8 +399,7 @@ def JobFile(jobfile): (jobfile, type(conf), Configuration) return conf -if __name__ == '__main__': - from jobfile import * +def main(conf=None): import sys usage = 'Usage: %s [-b] [-c] [-v] ' % sys.argv[0] @@ -504,9 +410,6 @@ if __name__ == '__main__': except getopt.GetoptError: sys.exit(usage) - if len(args) != 1: - raise AttributeError, usage - both = False checkpoint = False verbose = False @@ -519,21 +422,29 @@ if __name__ == '__main__': if opt == '-v': verbose = True - jobfile = args[0] - conf = JobFile(jobfile) + if conf is None: + if len(args) != 1: + raise AttributeError, usage + conf = JobFile(args[0]) + else: + if len(args) != 0: + raise AttributeError, usage if both: - gen = conf.alljobs() + jobs = conf.alljobs() elif checkpoint: - gen = conf.checkpoints() + jobs = conf.checkpoints() else: - gen = conf.jobs() + jobs = conf.jobs() - for job in gen: - if not verbose: - cpt = '' - if job.checkpoint: - cpt = job.checkpoint.name - print job.name, cpt - else: + for job in jobs: + if verbose: job.printinfo() + else: + cpt = '' + if job._checkpoint: + cpt = job._checkpoint.name + print job.name, cpt + +if __name__ == '__main__': + main() diff --git a/src/python/m5/util.py b/src/python/m5/util/misc.py similarity index 79% rename from src/python/m5/util.py rename to src/python/m5/util/misc.py index 28b8b1b94..094e3ed9a 100644 --- a/src/python/m5/util.py +++ b/src/python/m5/util/misc.py @@ -56,4 +56,32 @@ def applyOrMap(objOrSeq, meth, *args, **kwargs): else: return [applyMethod(o, meth, *args, **kwargs) for o in objOrSeq] +def crossproduct(items): + if not isinstance(items, (list, tuple)): + raise AttributeError, 'crossproduct works only on sequences' + if not items: + yield None + return + + current = items[0] + remainder = items[1:] + + if not hasattr(current, '__iter__'): + current = [ current ] + + for item in current: + for rem in crossproduct(remainder): + data = [ item ] + if rem: + data += rem + yield data + +def flatten(items): + if not isinstance(items, (list, tuple)): + yield items + return + + for item in items: + for flat in flatten(item): + yield flat diff --git a/src/python/m5/multidict.py b/src/python/m5/util/multidict.py similarity index 100% rename from src/python/m5/multidict.py rename to src/python/m5/util/multidict.py diff --git a/util/stats/orderdict.py b/src/python/m5/util/orderdict.py similarity index 100% rename from util/stats/orderdict.py rename to src/python/m5/util/orderdict.py diff --git a/util/batch/jobfile.py b/util/batch/jobfile.py deleted file mode 100644 index b78d7f3e1..000000000 --- a/util/batch/jobfile.py +++ /dev/null @@ -1,539 +0,0 @@ -# Copyright (c) 2006 The Regents of The University of Michigan -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Kevin Lim - -import sys - -class ternary(object): - def __new__(cls, *args): - if len(args) > 1: - raise TypeError, \ - '%s() takes at most 1 argument (%d given)' % \ - (cls.__name__, len(args)) - - if args: - if not isinstance(args[0], (bool, ternary)): - raise TypeError, \ - '%s() argument must be True, False, or Any' % \ - cls.__name__ - return args[0] - return super(ternary, cls).__new__(cls) - - def __bool__(self): - return True - - def __neg__(self): - return self - - def __eq__(self, other): - return True - - def __ne__(self, other): - return False - - def __str__(self): - return 'Any' - - def __repr__(self): - return 'Any' - -Any = ternary() - -class Flags(dict): - def __init__(self, *args, **kwargs): - super(Flags, self).__init__() - self.update(*args, **kwargs) - - def __getattr__(self, attr): - return self[attr] - - def __setattr__(self, attr, value): - self[attr] = value - - def __setitem__(self, item, value): - return super(Flags, self).__setitem__(item, ternary(value)) - - def __getitem__(self, item): - if item not in self: - return False - return super(Flags, self).__getitem__(item) - - def update(self, *args, **kwargs): - for arg in args: - if isinstance(arg, Flags): - super(Flags, self).update(arg) - elif isinstance(arg, dict): - for key,val in kwargs.iteritems(): - self[key] = val - else: - raise AttributeError, \ - 'flags not of type %s or %s, but %s' % \ - (Flags, dict, type(arg)) - - for key,val in kwargs.iteritems(): - self[key] = val - - def match(self, *args, **kwargs): - match = Flags(*args, **kwargs) - - for key,value in match.iteritems(): - if self[key] != value: - return False - - return True - -def crossproduct(items): - if not isinstance(items, (list, tuple)): - raise AttributeError, 'crossproduct works only on sequences' - - if not items: - yield None - return - - current = items[0] - remainder = items[1:] - - if not hasattr(current, '__iter__'): - current = [ current ] - - for item in current: - for rem in crossproduct(remainder): - data = [ item ] - if rem: - data += rem - yield data - -def flatten(items): - if not isinstance(items, (list, tuple)): - yield items - return - - for item in items: - for flat in flatten(item): - yield flat - -class Data(object): - def __init__(self, name, desc, **kwargs): - self.name = name - self.desc = desc - self.system = None - self.flags = Flags() - self.env = {} - for k,v in kwargs.iteritems(): - setattr(self, k, v) - - def update(self, obj): - if not isinstance(obj, Data): - raise AttributeError, "can only update from Data object" - - self.env.update(obj.env) - self.flags.update(obj.flags) - if obj.system: - if self.system and self.system != obj.system: - raise AttributeError, \ - "conflicting values for system: '%s'/'%s'" % \ - (self.system, obj.system) - self.system = obj.system - - def printinfo(self): - if self.name: - print 'name: %s' % self.name - if self.desc: - print 'desc: %s' % self.desc - if self.system: - print 'system: %s' % self.system - - def printverbose(self): - print 'flags:' - keys = self.flags.keys() - keys.sort() - for key in keys: - print ' %s = %s' % (key, self.flags[key]) - print 'env:' - keys = self.env.keys() - keys.sort() - for key in keys: - print ' %s = %s' % (key, self.env[key]) - print - - def __str__(self): - return self.name - -class Job(Data): - def __init__(self, options): - super(Job, self).__init__('', '') - self.setoptions(options) - - self.checkpoint = False - opts = [] - for opt in options: - cpt = opt.group.checkpoint - if not cpt: - self.checkpoint = True - continue - if isinstance(cpt, Option): - opt = cpt.clone(suboptions=False) - else: - opt = opt.clone(suboptions=False) - - opts.append(opt) - - if not opts: - self.checkpoint = False - - if self.checkpoint: - self.checkpoint = Job(opts) - - def clone(self): - return Job(self.options) - - def __getattribute__(self, attr): - if attr == 'name': - names = [ ] - for opt in self.options: - if opt.name: - names.append(opt.name) - return ':'.join(names) - - if attr == 'desc': - descs = [ ] - for opt in self.options: - if opt.desc: - descs.append(opt.desc) - return ', '.join(descs) - - return super(Job, self).__getattribute__(attr) - - def setoptions(self, options): - config = options[0].config - for opt in options: - if opt.config != config: - raise AttributeError, \ - "All options are not from the same Configuration" - - self.config = config - self.groups = [ opt.group for opt in options ] - self.options = options - - self.update(self.config) - for group in self.groups: - self.update(group) - - for option in self.options: - self.update(option) - if option._suboption: - self.update(option._suboption) - - def printinfo(self): - super(Job, self).printinfo() - if self.checkpoint: - print 'checkpoint: %s' % self.checkpoint.name - print 'config: %s' % self.config.name - print 'groups: %s' % [ g.name for g in self.groups ] - print 'options: %s' % [ o.name for o in self.options ] - super(Job, self).printverbose() - -class SubOption(Data): - def __init__(self, name, desc, **kwargs): - super(SubOption, self).__init__(name, desc, **kwargs) - self.number = None - -class Option(Data): - def __init__(self, name, desc, **kwargs): - super(Option, self).__init__(name, desc, **kwargs) - self._suboptions = [] - self._suboption = None - self.number = None - - def __getattribute__(self, attr): - if attr == 'name': - name = self.__dict__[attr] - if self._suboption is not None: - name = '%s:%s' % (name, self._suboption.name) - return name - - if attr == 'desc': - desc = [ self.__dict__[attr] ] - if self._suboption is not None and self._suboption.desc: - desc.append(self._suboption.desc) - return ', '.join(desc) - - - return super(Option, self).__getattribute__(attr) - - def suboption(self, name, desc, **kwargs): - subo = SubOption(name, desc, **kwargs) - subo.config = self.config - subo.group = self.group - subo.option = self - subo.number = len(self._suboptions) - self._suboptions.append(subo) - return subo - - def clone(self, suboptions=True): - option = Option(self.__dict__['name'], self.__dict__['desc']) - option.update(self) - option.group = self.group - option.config = self.config - option.number = self.number - if suboptions: - option._suboptions.extend(self._suboptions) - option._suboption = self._suboption - return option - - def subopts(self): - if not self._suboptions: - return [ self ] - - subopts = [] - for subo in self._suboptions: - option = self.clone() - option._suboption = subo - subopts.append(option) - - return subopts - - def printinfo(self): - super(Option, self).printinfo() - print 'config: %s' % self.config.name - super(Option, self).printverbose() - -class Group(Data): - def __init__(self, name, desc, **kwargs): - super(Group, self).__init__(name, desc, **kwargs) - self._options = [] - self.checkpoint = False - self.number = None - - def option(self, name, desc, **kwargs): - opt = Option(name, desc, **kwargs) - opt.config = self.config - opt.group = self - opt.number = len(self._options) - self._options.append(opt) - return opt - - def options(self): - return self._options - - def subopts(self): - subopts = [] - for opt in self._options: - for subo in opt.subopts(): - subopts.append(subo) - return subopts - - def printinfo(self): - super(Group, self).printinfo() - print 'config: %s' % self.config.name - print 'options: %s' % [ o.name for o in self._options ] - super(Group, self).printverbose() - -class Configuration(Data): - def __init__(self, name, desc, **kwargs): - super(Configuration, self).__init__(name, desc, **kwargs) - self._groups = [] - self._posfilters = [] - self._negfilters = [] - - def group(self, name, desc, **kwargs): - grp = Group(name, desc, **kwargs) - grp.config = self - grp.number = len(self._groups) - self._groups.append(grp) - return grp - - def groups(self, flags=Flags(), sign=True): - if not flags: - return self._groups - - return [ grp for grp in self._groups if sign ^ grp.flags.match(flags) ] - - def checkchildren(self, kids): - for kid in kids: - if kid.config != self: - raise AttributeError, "child from the wrong configuration" - - def sortgroups(self, groups): - groups = [ (grp.number, grp) for grp in groups ] - groups.sort() - return [ grp[1] for grp in groups ] - - def options(self, groups = None, checkpoint = False): - if groups is None: - groups = self._groups - self.checkchildren(groups) - groups = self.sortgroups(groups) - if checkpoint: - groups = [ grp for grp in groups if grp.checkpoint ] - optgroups = [ g.options() for g in groups ] - else: - optgroups = [ g.subopts() for g in groups ] - for options in crossproduct(optgroups): - for opt in options: - cpt = opt.group.checkpoint - if not isinstance(cpt, bool) and cpt != opt: - if checkpoint: - break - else: - yield options - else: - if checkpoint: - yield options - - def addfilter(self, filt, pos=True): - import re - filt = re.compile(filt) - if pos: - self._posfilters.append(filt) - else: - self._negfilters.append(filt) - - def jobfilter(self, job): - for filt in self._negfilters: - if filt.match(job.name): - return False - - if not self._posfilters: - return True - - for filt in self._posfilters: - if filt.match(job.name): - return True - - return False - - def checkpoints(self, groups = None): - for options in self.options(groups, True): - job = Job(options) - if self.jobfilter(job): - yield job - - def jobs(self, groups = None): - for options in self.options(groups, False): - job = Job(options) - if self.jobfilter(job): - yield job - - def alljobs(self, groups = None): - for options in self.options(groups, True): - yield Job(options) - for options in self.options(groups, False): - yield Job(options) - - def find(self, jobname): - for job in self.alljobs(): - if job.name == jobname: - return job - else: - raise AttributeError, "job '%s' not found" % jobname - - def job(self, options): - self.checkchildren(options) - options = [ (opt.group.number, opt) for opt in options ] - options.sort() - options = [ opt[1] for opt in options ] - job = Job(options) - return job - - def printinfo(self): - super(Configuration, self).printinfo() - print 'groups: %s' % [ g.name for g in self._grouips ] - super(Configuration, self).printverbose() - -def JobFile(jobfile): - from os.path import expanduser, isfile, join as joinpath - filename = expanduser(jobfile) - - # Can't find filename in the current path, search sys.path - if not isfile(filename): - for path in sys.path: - testname = joinpath(path, filename) - if isfile(testname): - filename = testname - break - else: - raise AttributeError, \ - "Could not find file '%s'" % jobfile - - data = {} - execfile(filename, data) - if 'conf' not in data: - raise ImportError, 'cannot import name conf from %s' % jobfile - conf = data['conf'] - import jobfile - if not isinstance(conf, Configuration): - raise AttributeError, \ - 'conf in jobfile: %s (%s) is not type %s' % \ - (jobfile, type(conf), Configuration) - return conf - -if __name__ == '__main__': - from jobfile import * - import sys - - usage = 'Usage: %s [-b] [-c] [-v] ' % sys.argv[0] - - try: - import getopt - opts, args = getopt.getopt(sys.argv[1:], '-bcv') - except getopt.GetoptError: - sys.exit(usage) - - if len(args) != 1: - raise AttributeError, usage - - both = False - checkpoint = False - verbose = False - for opt,arg in opts: - if opt == '-b': - both = True - checkpoint = True - if opt == '-c': - checkpoint = True - if opt == '-v': - verbose = True - - jobfile = args[0] - conf = JobFile(jobfile) - - if both: - gen = conf.alljobs() - elif checkpoint: - gen = conf.checkpoints() - else: - gen = conf.jobs() - - for job in gen: - if not verbose: - cpt = '' - if job.checkpoint: - cpt = job.checkpoint.name - print job.name, cpt - else: - job.printinfo()