1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import os
20 import os.path
21 import sys
22 import pygtk; pygtk.require('2.0');
23 import gobject
24 from config import *
25 import storage
26 import traceback
27 import util
28 import debuglog
29
32
34 """Loads all python modules from a directory allows objects
35 to be constructed from said modules using specific constructors
36 for each object type."""
37
39 """Construct a ModuleLoader and will load all available
40 python modules from @module_path.
41 """
42 self.module_path = module_path
43 self.modules = []
44 self.__load_modules ()
45
47 """Load a python module named @module."""
48 dprint ("Loading module: %s", module)
49 cmd = "from sources import %s" % module
50 try:
51 exec (cmd)
52 except:
53 print >> sys.stderr, "Failed to import module '%s' cmd=\"%s\"" % (module, cmd)
54 traceback.print_exc(file=sys.stderr)
55 return
56 self.modules.append (module)
57
59 """Load all available modules from self.module_path."""
60 dprint ("Loading modules from %s", self.module_path)
61 sys.path.append (self.module_path)
62 for file in os.listdir (self.module_path):
63 if file[0] == '.':
64 continue
65 if file[-3:] != ".py":
66 continue
67 if file == "__init__.py":
68 continue
69 self.__load_module (file[:-3])
70
72 """Construct an object by invoking a function named @constructor,
73 with @arg as an argument, in the module called @module.
74 """
75 dprint ("Constructing object from loaded module using %s.%s", module, constructor)
76 cmd = ("from sources import %s\n"
77 "if %s.__dict__.has_key ('%s'):"
78 " ret = %s.%s (arg)") % (module, module, constructor, module, constructor)
79 try:
80 exec (cmd)
81 except:
82 print "Failed to invoke function '%s.%s': %s" % (module, constructor, sys.exc_type)
83 traceback.print_exc(file=sys.stderr)
84 return None
85
86 try:
87 ret = ret
88 except NameError:
89 return None
90 return ret
91
93 """Construct and return a list of objects by invoking a function
94 named @constructor, with @arg as an argument, in each of the
95 python modules in self.module_path which contain a function
96 by that name.
97 """
98 objects = []
99 for module in self.modules:
100 o = self.__construct_object (module, constructor, arg)
101 if o != None:
102 objects.append (o)
103 return objects
104
105 module_loader = None
112
114 """Abstract base class for encapsulating profile changes."""
115
116 - def __init__ (self, source, delegate = None):
117 """Construct a ProfileChange object.
118
119 source: the ProfileSource from which the change came.
120 """
121 gobject.GObject.__init__ (self)
122 self.source = source
123 self.delegate = delegate
124
126 """Get the ProfileSource from which this change came."""
127 return self.source
128
130 """Return and identifier for the configuration item which changed."""
131 raise Exception ("Not implemented")
132
134 """Return a short description of the configuration change."""
135 raise Exception ("Not implemented")
136
138 """Returns the default value for the ignore item for this change."""
139 return False;
140
142 """Returns the mandatory value of the change, or None to use the default"""
143 return None
144
146 """Merges info from previous change into this change. Return True to discard the new change."""
147 return False
148
149 gobject.type_register (ProfileChange)
150
152 """An abstract base class for helper classes which can be used
153 to intercept and modify changes from a given configuration
154 source."""
155
156 - def __init__ (self, delegate_name, source, namespace_section):
157 """Construct a SourceDelegate object.
158
159 @source: the ProfileSource whose changes the delegate wishes
160 to inspect.
161 @namepsace_section: the section of @source's configuration
162 namespace that the delegate wishes to inspect.
163 """
164 self.name = delegate_name
165 self.source = source
166 self.namespace_section = namespace_section
167
169 """Returns the configuration delegate's name."""
170 return self.name
171
173 """Returns a human readable description for @path.
174 @path must have been previously added by the delegate to the
175 #ProfileStorage.
176 """
177 return path
178
180 """Inspect a ProfileChange. Return #True if the change should
181 not be passed on any further (i.e. #True == 'handled') and
182 return #False if the change should be passed on unmodified.
183 """
184 raise Exception ("Not implemented")
185
187 """Commit a change to profile.
188
189 mandatory: whether the change should be committed such
190 that it overrides the user's value.
191 """
192 raise Exception ("Not implemented")
193
195 """Start monitoring for configuration changes."""
196 raise Exception ("Not implemented")
197
199 """Stop monitoring for configuration changes."""
200 raise Exception ("Not implemented")
201
203 """Save all committed changes to disk."""
204 raise Exception ("Not implemented")
205
207 """Temporary make mandatory setting non-mandatory."""
208 raise Exception ("Not implemented")
209
210 - def apply (self, is_sabayon_session):
211 """Apply profile to the current user's environment."""
212 raise Exception ("Not implemented")
213
215 """An abstract base class which each configuration source must
216 implement."""
217
218 __gsignals__ = {
219 "changed" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (ProfileChange, ))
220 }
221
222 - def __init__ (self, source_name, delegate_constructor = None):
234
236 """Return a delegate named @delegate_name."""
237 for delegate in self.delegates:
238 if delegate.get_name () == delegate_name:
239 return delegate
240 return None
241
243 """Returns the configuration source's name."""
244 return self.name
245
247 """Returns a human readable description for @path.
248 @path must have been previously added by the source to the
249 #ProfileStorage.
250 """
251 return path
252
254 """Pass @change to all register delegates for this source and
255 emit a 'changed' signal with @change if none of the delegates
256 return #True.
257 """
258 for delegate in self.delegates:
259 if not change.get_id ().startswith (delegate.namespace_section):
260 continue
261 if delegate.handle_change (change):
262 dprint ("Delegate '%s' handled change '%s'", delegate.get_name (), change.get_id ())
263 return
264 self.emit ("changed", change)
265
267 """Commit a change to profile.
268
269 mandatory: whether the change should be committed such
270 that it overrides the user's value.
271 """
272 if change.delegate:
273 change.delegate.commit_change (change, mandatory)
274 dprint ("Delegate '%s' committed changes '%s'", change.delegate.get_name (), change.get_id ())
275 return True
276 return False
277
279 """Start monitoring for configuration changes."""
280 raise Exception ("Not implemented")
281
283 """Stop monitoring for configuration changes."""
284 raise Exception ("Not implemented")
285
287 """Save all committed changes to disk."""
288 raise Exception ("Not implemented")
289
291 """Temporary make mandatory setting non-mandatory."""
292 raise Exception ("Not implemented")
293
294 - def apply (self, is_sabayon_session):
295 """Apply profile to the current user's environment."""
296 raise Exception ("Not implemented")
297
298 gobject.type_register (ProfileSource)
299
301 """An encapsulation of the user profile and backend sources."""
302
303 __gsignals__ = {
304 "changed" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (ProfileChange, ))
305 }
306
333
335 self.emit ("changed", change)
336
338 """Return a source named @source_name."""
339 for source in self.sources:
340 if source.get_name () == source_name:
341 return source
342 return None
343
345 """Return a delegate named @delegate_name."""
346 for source in self.sources:
347 delegate = source.get_delegate (delegate_name)
348 if not delegate is None:
349 return delegate
350 return None
351
362
370
379
387
388 - def apply (self, is_sabayon_session):
389 """Apply profile to the current user's environment."""
390 dprint ("Applying profile to user's environment")
391 for s in self.sources:
392 s.apply (is_sabayon_session)
393 for delegate in s.delegates:
394 delegate.apply (is_sabayon_session)
395
396 gobject.type_register (UserProfile)
397
398
399
400
402 class LocalTestChange (ProfileChange):
403 def __init__ (self, source, key, value):
404 ProfileChange.__init__ (self, source)
405 self.key = key
406 self.value = value
407 def get_id (self):
408 return self.key
409 def get_short_description (self):
410 return self.key
411
412 class LocalTestDelegate (SourceDelegate):
413 def __init__ (self, source):
414 SourceDelegate.__init__ (self, "local", source, "/bar")
415 def handle_change (self, change):
416 if change.get_id () == "/bar/foo1":
417 return True
418 return False
419
420 class LocalTestSource (ProfileSource):
421 def __init__ (self):
422 ProfileSource.__init__ (self, "local")
423
424 profile = UserProfile ("foo-storage")
425 assert len (profile.sources) > 0
426
427 testsource = None
428 for source in profile.sources:
429 if source.get_name () == "test":
430 testsource = source
431 break;
432 assert testsource != None
433 assert len (testsource.delegates) == 1
434
435 localsource = LocalTestSource ()
436 profile.sources.append (localsource)
437 def handle_source_changed (source, change, profile):
438 profile.emit ("changed", change)
439 localsource.connect ("changed", handle_source_changed, profile)
440 assert len (profile.sources) > 1
441
442 localdelegate = LocalTestDelegate (localsource)
443 localsource.delegates.append (localdelegate)
444
445 global n_signals
446 n_signals = 0
447 def handle_changed (profile, change):
448 global n_signals
449 n_signals += 1
450 profile.connect ("changed", handle_changed)
451
452
453 localsource.emit_change (LocalTestChange (localsource, "/bar/foo1", "1"))
454 localsource.emit_change (LocalTestChange (localsource, "/bar/foo2", "2"))
455 localsource.emit_change (LocalTestChange (localsource, "/bar/foo3", "3"))
456
457
458 testsource.emit_change (testsource.get_test_change ("/foo/bar1", "1"))
459 testsource.emit_change (testsource.get_test_change ("/foo/bar2", "2"))
460 testsource.emit_change (testsource.get_test_change ("/foo/bar3", "3"))
461
462 assert n_signals == 4
463