1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
|
#
# This file is part of Checkbox.
#
# Copyright 2008 Canonical Ltd.
#
# Checkbox is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Checkbox is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
#
import os
import re
import itertools
import logging
import posixpath
from checkbox.lib.cache import cache
from checkbox.lib.path import path_expand_recursive
from checkbox.properties import List, String
from checkbox.variables import get_variables
class ComponentSection(object):
"""
Component section which is essentially a container of modules. These
map to the modules referenced in the configuration passed as argument
to the constructor.
"""
modules = List(type=String())
whitelist = List(type=String(), default_factory=lambda:"")
blacklist = List(type=String(), default_factory=lambda:"")
def __init__(self, config, name):
"""
Constructor which takes a configuration instance and name as
argument. The former is expected to contain modules.
"""
self._config = config
self.name = name
self.modules = config.modules
self.whitelist = config.get("whitelist")
self.blacklist = config.get("blacklist")
@cache
def get_names(self):
"""
Get all the module names contained in the filenames or directories
for this section.
"""
whitelist_patterns = [re.compile(r"^%s$" % r) for r in self.whitelist]
blacklist_patterns = [re.compile(r"^%s$" % r) for r in self.blacklist]
# Determine names
names = set()
filenames = itertools.chain(*[path_expand_recursive(m)
for m in self.modules])
for filename in filenames:
name = posixpath.basename(filename)
if not name.endswith(".py") or name == "__init__.py":
# Ignore silently
continue
name = name.replace(".py", "")
if whitelist_patterns:
if not [name for p in whitelist_patterns if p.match(name)]:
logging.info("Not whitelisted module: %s", name)
continue
elif blacklist_patterns:
if [name for p in blacklist_patterns if p.match(name)]:
logging.info("Blacklisted module: %s", name)
continue
names.add(name)
return list(names)
def has_module(self, name):
"""
Check if the given name is in this section.
"""
return name in self.get_names()
def load_module(self, name):
"""
Load a single module by name from this section.
"""
logging.info("Loading module %s from section %s",
name, self.name)
if not self.has_module(name):
raise Exception, "No such such module: %s" % name
filenames = itertools.chain(*[path_expand_recursive(m)
for m in self.modules])
for filename in filenames:
if filename.endswith(".py") and posixpath.exists(filename):
basename = posixpath.basename(filename)
basename = basename.replace(".py", "")
if basename == name:
globals = {}
exec open(filename) in globals
if "factory" not in globals:
raise Exception, "Variable 'factory' not found in: %s" \
% filename
module = globals["factory"]()
module.__module__ = name
config_name = "/".join([self.name, name])
config = self._config.parent.get_section(config_name)
# Set configuration values
variables = get_variables(module)
environ = dict([(k.lower(), v) for k, v in os.environ.iteritems()])
for attribute, variable in variables.iteritems():
if config and attribute.name in config:
value = config.get(attribute.name)
variable.set(value)
else:
value = variable.get()
if isinstance(value, basestring):
value = value % environ
variable.set(value)
elif isinstance(value, list):
value = [v % environ for v in value]
variable.set(value)
# Check required attributes
for attribute, variable in variables.iteritems():
value = variable.get()
if value is None and variable._required:
raise Exception, "Configuration '%s' missing " \
"required attribute: %s" \
% (config_name, attribute.name)
return module
raise Exception, "Failed to find module '%s' in: %s" % (name, filenames)
def load_modules(self):
"""
Load all modules contained in this section.
"""
modules = []
for name in self.get_names():
module = self.load_module(name)
modules.append(module)
return modules
class ComponentManager(object):
"""
Component manager which is essentially a container of sections.
"""
_section_factory = ComponentSection
def __init__(self, config):
"""
Constructor which takes a configuration instance as argument. This
will be used to load sections by name.
"""
self._config = config
def load_section(self, name):
"""
Load a section by name which must correspond to a module in the
configuration instance pased as argument to the constructor.
"""
logging.info("Loading component section %s", name)
config = self._config.get_section(name)
return self._section_factory(config, name)
|