b535e90f1126b4b37a1449f317748139a693890d
[tiramisu.git] / tiramisu / tool.py
1 # Copyright (C) 2012 Team tiramisu (see AUTHORS for all contributors)
2 #
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16 #
17 # The original `Config` design model is unproudly borrowed from 
18 # the rough gus of pypy: pypy: http://codespeak.net/svn/pypy/dist/pypy/config/
19 # the whole pypy projet is under MIT licence
20 from tiramisu.config import Config
21 from tiramisu.option import (OptionDescription, Option, ChoiceOption, BoolOption, 
22                     FloatOption, StrOption, IntOption, IPOption, NetmaskOption, 
23                     ArbitraryOption, group_types, apply_requires)
24
25 # ____________________________________________________________
26 # reverse factory
27 # XXX HAAAAAAAAAAAACK (but possibly a good one)
28 def reverse_from_paths(data):
29     "rebuilds a (fake) data structure from an unflatten `make_dict()` result"
30     # ____________________________________________________________
31     _build_map = {
32         bool: BoolOption,
33         int: IntOption,
34         float: FloatOption,
35         str: StrOption,
36     }
37     def option_factory(name, value):
38         "dummy -> Option('dummy')"
39         if isinstance(value, list):
40             return _build_map[type(value[0])](name, '', multi=True, default=value)
41         else:            
42             return _build_map[type(value)](name, '', default=value)
43
44     def build_options(data):
45         "config.gc.dummy ->  Option('dummy')"
46         for key, value in data.items():
47             name = key.split('.')[-1]
48             yield (key, option_factory(name, value))
49     # ____________________________________________________________
50     def parent(pathname):
51         "config.gc.dummy -> config.gc"
52         if "." in pathname:
53             return ".".join(pathname.split('.')[:-1])
54         # no parent except rootconfig, naturally returns None    
55
56     def subgroups(pathname):
57         "config.gc.dummy.bool -> [config.gc, config.gc.dummy]"
58         group = parent(pathname)
59         parents =[]
60         while group is not None:
61             parents.append(group)
62             group = parent(group)
63         return parents 
64
65     def build_option_descriptions(data):
66         all_groups = []
67         for key in data.keys():
68             for group in subgroups(key):
69                 # so group is unique in the list 
70                 if group not in all_groups:
71                     all_groups.append(group)
72         for group in all_groups:
73             name = group.split('.')[-1]
74             yield (group, OptionDescription(name, '', []))
75     # ____________________________________________________________
76     descr = OptionDescription('tiramisu', 'fake rebuild structure', [])
77     cfg = Config(descr)
78     # add descrs in cfg
79     def compare(a, b):
80         l1 = a.split(".")
81         l2 = b.split(".")
82         if len(l1) < len(l2):
83             return -1
84         elif len(l1) > len(l2):
85             return 1
86         else:
87             return 0
88     grps = list(build_option_descriptions(data))
89     groups = dict(grps)
90     grp_paths = [pathname for pathname, opt_descr in grps]
91     grp_paths.sort(compare)
92     for grp in grp_paths:
93         if not "." in grp:
94             cfg._cfgimpl_descr.add_child(groups[grp])
95             cfg.cfgimpl_update()
96         else:
97             parentdescr = cfg.unwrap_from_path(parent(grp))
98             parentdescr.add_child(groups[grp])
99             getattr(cfg, parent(grp)).cfgimpl_update()
100     # add options in descrs
101     for pathname, opt in build_options(data):
102         current_group_name = parent(pathname)
103         if current_group_name == None:
104             cfg._cfgimpl_descr.add_child(opt)
105             cfg.cfgimpl_update()
106         else:
107             curr_grp = groups[current_group_name]
108             curr_grp.add_child(opt)
109             getattr(cfg, current_group_name).cfgimpl_update()
110
111     return cfg
112 # ____________________________________________________________
113 # extendable type
114 class extend(type):
115     """
116     A magic trick for classes, which lets you add methods or attributes to a
117     class
118     """
119     def extend(cls, extclass):
120         bases = list(extclass.__bases__)
121         bases.append(extclass)
122         for cl in bases:
123             for key, value in cl.__dict__.items():
124                 if key == '__module__':
125                     continue
126                 setattr(cls, key, value)
127
128 # ____________________________________________________________
129