1 '''
2 Defines the registrar functions responsible for managing an on-disk repository
3 of User Interface Elements (UIEs) that define the L{Perk}s, Devices, Choosers,
4 and Monitors available to the user and the system. Defines a helper class
5 L{UIESet} that is used internally by the registrar to represent collections
6 of UIEs that are to be loaded when LSR starts, when any L{Tier} starts, or when
7 a particular L{Tier} starts for a particular user.
8
9 Functions to install, uninstall, associate, disassociate, and list UIEs are
10 primarily of interest to third-party UIE developers and expert users. These
11 methods allow extensions to be added to LSR and associated with profiles so
12 they are loaded automatically at startup or when L{Tier}s are created. The
13 L{AEMain} script defines a command line interface for accessing these
14 methods. See the documentation in that module or the LSR man page for details.
15
16 Functions to load UIEs are of interest to LSR developers. Given a UIE name, the
17 L{loadOne} method will import the Python module containing the named UIE and
18 return an instance of the class in that module of the same name (if the UIE
19 module is properly installed). Given a UIE kind and name along with the name
20 of a , the L{loadAssociated} method will import all Python modules containing
21 the UIEs to be loaded and return a list of UIE objects sorted in the desired
22 load order. Objects, not classes, are returned by this method implying any
23 initialization requiring data from an external source must be done outside the
24 constructor.
25
26
27 @var LOCAL_PATH: Location of the set of installed UIEs for this user
28 @type LOCAL_PATH: string
29 @var GLOBAL_PATH: Location of the set of installed UIEs for all users of the
30 system
31 @type GLOBAL_PATH: string
32 @var PERK: Kind of UIE responsible for registering L{Task}s that handle
33 L{AEEvent}s and L{AEInput.Gesture}s
34 @type PERK: string
35 @var DEVICE: Kind of UIE responsible for managing a method of input
36 (e.g keyboard), managing a method of output (e.g speech), or both (e.g.
37 Braille device)
38 @type DEVICE: string
39 @var CHOOSER: Kind of UIE responsible for interacting with the user via more
40 than the usual LSR key combos (e.g. configuration, help, search)
41 @type CHOOSER: string
42 @var MONITOR: Kind of UIE responsible for creating a human-readable
43 representation (e.g. GUI dialog, log file) of some AccessEngine data (e.g.
44 input, output, events) for the purposes of development and debugging
45 @type MONITOR: string
46 @var ALL_KINDS: List of all known kinds of UIEs
47 @type ALL_KINDS: list
48 @var STARTUP_KINDS: Subset of L{ALL_KINDS} that should be loaded at startup
49 @type STARTUP_KINDS: list
50
51 @author: Peter Parente
52 @organization: IBM Corporation
53 @copyright: Copyright (c) 2005, 2007 IBM Corporation
54 @license: The BSD License
55
56 All rights reserved. This program and the accompanying materials are made
57 available under the terms of the BSD license which accompanies
58 this distribution, and is available at
59 U{http://www.opensource.org/licenses/bsd-license.php}
60 '''
61 import os, glob, imp, cPickle, sys, logging, shutil, traceback
62 from SettingsManager import SettingsManager
63 from i18n import _
64 from AEConstants import HOME_USER, HOME_DIR, PROG_VERSION, PROG_DATE, \
65 BUILTIN_PROFILES
66
67
68 log = logging.getLogger('UIRegistrar')
69
70
71
72 LOCAL_PATH = os.path.join(HOME_USER,os.path.basename(sys.argv[0])+'.installed')
73 GLOBAL_PATH = os.path.join(HOME_DIR, 'global.installed')
74
75
76
77 PERK = 'perk'
78 DEVICE = 'device'
79 CHOOSER = 'chooser'
80 MONITOR = 'monitor'
81
82
83 ALL_KINDS = [DEVICE, CHOOSER, MONITOR, PERK]
84 STARTUP_KINDS = [DEVICE, MONITOR]
85
128
130 '''
131 Associates the names of installed UIEs with times when they should be
132 automatically loaded by LSR under a particular user profile. Supported times
133 for automatically loading UIEs include when LSR starts, when any new L{Tier}
134 is created, or when a L{Tier} with a particular process name is created.
135
136 @ivar name: Name of this UIESet
137 @type name: string
138 @ivar on_startup: Lists of UIE names keyed by UIE kind
139 @type on_startup: dictionary
140 @ivar on_tier: Lists of UIE names keyed by UIE kind in dictionaries keyed by
141 L{Tier} name
142 @type on_tier: dictionary
143 @ivar on_any_tier: Lists of UIE names keyed by UIE kind
144 @type on_any_tier: dictionary
145 '''
147 '''
148 Stores the name of the UIESet. Initializes the instance dictionaries.
149
150 @param name: Name of the UIESet
151 @type name: string
152 '''
153 self.name = name
154 self.on_startup = {}
155 self.on_tier = {}
156 self.on_any_tier = {}
157
159 '''
160 Adds the name of a UIE of the given kind to the L{on_startup} dictionary so
161 that it is loaded automatically when LSR starts. The index determines when
162 in the list of all L{on_startup} UIEs of the given kind the named UIE is
163 loaded.
164
165 @param kind: Kind of UIE, one of L{ALL_KINDS}
166 @type kind: string
167 @param name: Name of the UIE, unique across all UIEs of the same kind
168 @type name: string
169 @param index: Load order of the UIE when multiple UIEs are to be loaded at
170 the given time. A value of None meaning after all other UIEs of the same
171 kind.
172 @type index: integer or None
173 '''
174 uies = self.on_startup.setdefault(kind, [])
175 if name in uies:
176 uies.remove(name)
177 if index is None:
178 index = len(uies)
179 uies.insert(index, name)
180
182 '''
183 Removes the name of a UIE of the given kind from the L{on_startup}
184 dictionary so that it is no longer loaded automatically on LSR startup.
185
186 @param kind: Kind of UIE, one of L{ALL_KINDS}
187 @type kind: string
188 @param name: Name of the UIE, unique across all UIEs of the same kind
189 @type name: string
190 @raise ValueError: When the UIE of the given name and kind is not associated
191 with this profile to be loaded on startup
192 '''
193 uies = self.on_startup.get(kind, [])
194 try:
195 uies.remove(name)
196 except ValueError:
197 raise ValueError(_('%s not associated with %s') % (name, self.name))
198
199 - def addToTier(self, kind, name, tier_name, index):
200 '''
201 Adds the name of a UIE of the given kind to the L{on_tier} dictionary so
202 that it is loaded automatically when a L{Tier} with the given name is
203 created. The index determines when in the list of all L{on_tier} UIEs of the
204 given kind the named UIE is loaded.
205
206 @param kind: Kind of UIE, one of L{ALL_KINDS}
207 @type kind: string
208 @param name: Name of the UIE, unique across all UIEs of the same kind
209 @type name: string
210 @param tier_name: Name of the L{Tier}
211 @type tier_name: string
212 @param index: Load order of the UIE when multiple UIEs are to be loaded at
213 the given time. A value of None meaning after all other UIEs of the same
214 kind.
215 @type index: integer or None
216 '''
217 kinds = self.on_tier.setdefault(tier_name, {})
218 uies = kinds.setdefault(kind, [])
219 if name in uies:
220 uies.remove(name)
221 if index is None:
222 index = len(uies)
223 uies.insert(index, name)
224
226 '''
227 Removes the name of a UIE of the given kind from the L{on_tier}
228 dictionary so that it is no longer loaded automatically on when a L{Tier}
229 with the given name is created.
230
231 @param kind: Kind of UIE, one of L{ALL_KINDS}
232 @type kind: string
233 @param name: Name of the UIE, unique across all UIEs
234 @type name: string
235 @param tier_name: Name of the L{Tier}
236 @type tier_name: string
237 @raise ValueError: When the UIE of the given name and kind is not associated
238 with this profile to be loaded when the given L{Tier} starts
239 '''
240 kinds = self.on_tier.get(tier_name, {})
241 uies = kinds.get(kind, [])
242 try:
243 uies.remove(name)
244 except ValueError:
245 raise ValueError(_('%s not associated with %s' % (name, self.name)))
246 if not len(uies):
247 del kinds[kind]
248 if not len(kinds):
249 del self.on_tier[tier_name]
250
252 '''
253 Adds the name of a UIE of the given kind to the L{on_any_tier} dictionary
254 so that it is loaded automatically when any L{Tier} starts. The index
255 determines when in the list of all L{on_any_tier} UIEs of the given kind
256 the named UIE is loaded.
257
258 @param kind: Kind of UIE, one of L{ALL_KINDS}
259 @type kind: string
260 @param name: Name of the UIE, unique across all UIEs of the same kind
261 @type name: string
262 @param index: Load order of the UIE when multiple UIEs are to be loaded at
263 the given time. A value of None meaning after all other UIEs of the same
264 kind.
265 @type index: integer or None
266 '''
267 uies = self.on_any_tier.setdefault(kind, [])
268 if name in uies:
269 uies.remove(name)
270 if index is None:
271 index = len(uies)
272 uies.insert(index, name)
273
275 '''
276 Removes the name of a UIE of the given kind from the L{on_any_tier}
277 dictionary so that it is no longer loaded automatically when any L{Tier} is
278 created.
279
280 @param kind: Kind of UIE, one of L{ALL_KINDS}
281 @type kind: string
282 @param name: Name of the UIE, unique across all UIEs of the same kind
283 @type name: string
284 @raise ValueError: When the UIE of the given name and kind is not associated
285 with this profile to be loaded when any L{Tier} is created
286 '''
287 uies = self.on_any_tier.get(kind, [])
288 try:
289 uies.remove(name)
290 except ValueError:
291 raise ValueError(_('%s not associated with %s' % (name, self.name)))
292
294 '''
295 Removes all references to the UIE with the given name and kind from the
296 L{on_startup}, L{on_tier}, and L{on_any_tier} dictionaries. Ignores all
297 exceptions.
298
299 @param name: Name of the UIE, unique across all UIEs of the same kind
300 @type name: string
301 @param kind: Kind of UIE, one of L{ALL_KINDS}, or None to indicate the kind
302 is unknown and all kinds should be searched
303 @type kind: string
304 '''
305 for kind in ALL_KINDS:
306 try:
307 self.removeFromStartup(kind, name)
308 except ValueError, e:
309 pass
310 try:
311 self.removeFromAnyTier(kind, name)
312 except ValueError, e:
313 pass
314 for tier_name in self.on_tier.keys():
315 try:
316 self.removeFromTier(kind, name, tier_name)
317 except ValueError, e:
318 pass
319
321 '''
322 Gets a list of all UIE names of the given kind that are to be loaded at LSR
323 startup.
324
325 @param kind: Kind of UIE, one of L{ALL_KINDS}
326 @type kind: string
327 @return: Names of all UIEs to be loaded at LSR startup
328 @rtype: list of string
329 '''
330 return self.on_startup.get(kind, [])
331
333 '''
334 Gets a list of all UIE names of the given kind paired with the names of the
335 L{Tier}s on which they will load.
336
337 @param kind: Kind of UIE, one of L{ALL_KINDS}
338 @type kind: string
339 @return: Lists of L{Perk} names associated with L{Tier} names
340 @rtype: dictionary of string : list
341 '''
342 d = {}
343 for name, kinds in self.on_tier.items():
344 try:
345 d[name] = kinds[kind]
346 except KeyError:
347 pass
348 return d
349
351 '''
352 Gets a list of all UIE names of the given kind that are to be loaded when
353 a L{Tier} with the given name is created. If the given L{Tier} name is
354 None, then list all UIEs to be loaded for particular L{Tier}s.
355
356 @param kind: Kind of UIE, one of L{ALL_KINDS}
357 @type kind: string
358 @param tier: Name of the L{Tier}
359 @type tier: string
360 @return: Names of all UIEs to be loaded at L{Tier} creation time
361 @rtype: list of string
362 '''
363
364 if tier is None:
365 l = []
366 for name, kinds in self.on_tier.items():
367 try:
368 l.extend(kinds[kind])
369 except KeyError:
370 pass
371 return l
372 else:
373
374 kinds = self.on_tier.get(tier, {})
375 return kinds.get(kind, [])
376
378 '''
379 Gets a list of all UIE names of the given kind that are to be loaded when
380 any L{Tier} is created.
381
382 @param kind: Kind of UIE, one of L{ALL_KINDS}
383 @type kind: string
384 @return: Names of all UIEs to be loaded at L{Tier} creation time
385 @rtype: list of string
386 '''
387 return self.on_any_tier.get(kind, [])
388
390 '''
391 Ensures the UIE module at the given path contains a class matching the
392 stated name. Ensure L{Metadata} is specified in the UIE to aid in
393 installation and association. Returns the UIE metadata.
394
395 @note: No longer checks if a class fits the definition of the given kind of
396 UIE. This validation is difficult when the module imports dependencies and
397 actually provides little useful information about whether or not the UIE is
398 implemented correctly. It can only tell us if it provides the proper
399 interface. We have gracefully degredation at runtime, so why bother "almost
400 ensuring" it's valid at install time?
401
402 @param real_path: Real path to the UIE module located on disk
403 @type real_path: string
404 @return: Metadata from the UIE
405 @rtype: L{Metadata}
406 @raise AttributeError: When __uie__ dictionary is missing from the UIE
407 @raise IOError: When the UIE module cannot be read
408 '''
409
410 name, ext = os.path.basename(real_path).split(os.extsep)
411
412 text = file(real_path).read()
413
414 if text.find('class %s' % name) < 0:
415 raise AttributeError(
416 _('Module %s must have class with name %s') % (name, name))
417
418 return _parseUIEMetadata(name, real_path, text)
419
444
446 '''
447 Gets an instance of the UIE class having the same name as the module
448 indicated by the given name.
449
450 @param name: Name of the UIE, unique across all UIEs of the same kind
451 @type name: string
452 @return: UIE instance
453 @rtype: object
454 @raise KeyError: When the UIE is not installed globally or locally
455 @raise AttributeError: When the module is missing a class of the given name
456 @raise ImportError: When the UIE module cannot be imported
457 @raise IOError: When the UIE module cannot be read
458 '''
459 mod = _getUIEModule(name)
460
461 cls = getattr(mod, name)
462 return cls()
463
465 '''
466 Loads the UIE module of the given name. Returns a reference to the module
467 for use by L{_getUIEInstance} by querying the L{InstallCache}.
468
469 @param name: Name of the UIE, unique across all UIEs
470 @type name: string
471 @return: Reference to the UIE module
472 @rtype: module
473 @raise KeyError: When the UIE is not installed globally or locally
474 @raise IOError: When the UIE module cannot be read
475 @raise ImportError: When the UIE module cannot be imported
476 '''
477
478 metadata = InstallCache.get(name)
479 path = os.path.dirname(metadata.path)
480
481 f, pathname, description = imp.find_module(name, [path])
482
483 sys.path.append(os.path.dirname(pathname))
484 try:
485
486 m = imp.load_module(name, f, pathname, description)
487 finally:
488
489 f.close()
490
491 sys.path.pop()
492
493 return m
494
495 -def install(real_path, local=True, overwrite=False):
496 '''
497 Installs a new UIE module in either the local or global repository.
498 Installing in the global repository requires write permissions on the LSR
499 home directory at its install location. Checks if the UIE to be installed is
500 valid as determined by L{_ensureUIEValid} and retrieves its metadata.
501
502 @param real_path: Relative or absolute location of the UIE module on disk
503 @type real_path: string
504 @param local: Install this UIE for the current user only (True) or for all
505 users (False)?
506 @type local: boolean
507 @param overwrite: Ignore errors if a UIE is already installed and overwrite?
508 @type overwrite: boolean
509 @raise AttributeError: When __uie__ dictionary is missing from the UIE
510 @raise KeyError: When the named UIE is already installed
511 @raise IOError: When the UIE module cannot be read
512 '''
513
514 metadata = _ensureUIEValid(real_path)
515 if local:
516 InstallCache.addLocal(metadata, overwrite)
517 else:
518 InstallCache.addGlobal(metadata, overwrite)
519
521 '''
522 Removes a UIE module from the global or local repository. Removes all
523 references to a UIE uninstalled from the local repository from existing
524 profiles.
525
526 @param name: Name of the UIE, unique across all UIEs
527 @type name: string
528 @param local: Uninstall this UIE for the current user only (True) or for all
529 users (False)?
530 @type local: boolean
531 @raise AttributeError: When __uie__ dictionary is missing from the UIE
532 @raise KeyError: When the UIE is not already installed
533 @raise IOError: When the local on-disk cache cannot be updated
534 '''
535
536 if local:
537 metadata = InstallCache.removeLocal(name)
538 else:
539 metadata = InstallCache.removeGlobal(name)
540 kind = metadata.kind
541
542 for pn in SettingsManager.listProfiles():
543 sm = SettingsManager(profile=pn)
544 uieset = sm.load(__name__)
545 uieset.removeFromAll(name, kind)
546 sm.save(__name__, uieset)
547
548 -def associate(name, profiles=None, tier=None, all_tiers=False,
549 index=None):
550 '''
551 Associates an installed UIE of the given name with a profile so that it is
552 loaded automatically by LSR.
553
554 @param name: Name of the UIE, unique across all UIEs
555 @type name: string
556 @param profiles: Names of the profiles in which UIE of the given name will
557 be loaded automatically. Defaults to None meaning L{BUILTIN_PROFILES}
558 will be used.
559 @type profiles: list of string
560 @param tier: Name of the L{Tier} which will cause the loading of the
561 given UIE. Defaults to None.
562 @type tier: string
563 @param all_tiers: Load this UIE on all L{Tier}s?
564 @type all_tiers: boolean
565 @param index: Load order of the UIE when multiple UIEs are to be loaded at
566 the given time. Defaults to None meaning after all other associated UIEs
567 of the same kind.
568 @type index: integer
569 @return: Names of profiles with which the UIE was associated
570 @rtype: list of string
571 @raise KeyError: When the UIE is not already installed
572 '''
573
574 metadata = InstallCache.get(name)
575 profiles = profiles or BUILTIN_PROFILES
576 all_tiers = all_tiers or metadata.all_tiers
577 tier = tier or metadata.tier
578 associated = []
579 for profile in profiles:
580
581 sm = SettingsManager(profile)
582 try:
583 uieset = sm.load(__name__)
584 except KeyError:
585
586 uieset = UIESet(profile)
587
588 if metadata.kind in STARTUP_KINDS:
589 uieset.addToStartup(metadata.kind, name, index)
590 elif all_tiers:
591 uieset.addToAnyTier(metadata.kind, name, index)
592 elif tier is not None:
593 uieset.addToTier(metadata.kind, name, tier, index)
594 else:
595
596 continue
597 associated.append(profile)
598
599 sm.save(__name__, uieset)
600 return associated
601
602 -def disassociate(name, profiles=None, tier=None, all_tiers=False):
603 '''
604 Disassociates an installed UIE of the given name from a profile so
605 that it is no longer loaded automatically by LSR.
606
607 @param name: Name of the UIE, unique across all UIEs
608 @type name: string
609 @param profiles: Names of the profiles in which UIE of the given name will
610 no longer be loaded automatically. Defaults to None meaning
611 L{BUILTIN_PROFILES} will be used.
612 @type profiles: list of string
613 @param tier: Name of the L{Tier} which will no longer cause the loading
614 of the given UIE. Defaults to None.
615 @type tier: string
616 @param all_tiers: Disassociate this UIE from loading in all L{Tier}s?
617 @type all_tiers: boolean
618 @return: Names of profiles from which the UIE was disassociated
619 @rtype: list of string
620 '''
621 try:
622
623 metadata = InstallCache.get(name)
624 all_tiers = all_tiers or metadata.all_tiers
625 tier = tier or metadata.tier
626 except KeyError:
627
628 metadata = None
629 profiles = profiles or BUILTIN_PROFILES
630 disassociated = []
631 for profile in profiles:
632
633 sm = SettingsManager(profile)
634 try:
635 uieset = sm.load(__name__)
636 except KeyError:
637
638 uieset = UIESet(profile)
639 disassociated.append(profile)
640 try:
641
642 if metadata is None:
643 uieset.removeFromAll(name)
644
645 elif metadata.kind in STARTUP_KINDS:
646 uieset.removeFromStartup(metadata.kind, name)
647 elif all_tiers:
648 uieset.removeFromAnyTier(metadata.kind, name)
649 elif tier is not None:
650 uieset.removeFromTier(metadata.kind, name, tier)
651 except ValueError:
652 pass
653
654 sm.save(__name__, uieset)
655 return disassociated
656
658 '''
659 Gets a list of all installed UIEs of the given kind, both local and global.
660
661 @param kind: Kind of UIE, one of L{ALL_KINDS} or None to indicate all kinds
662 @type kind: string
663 @return: Names of installed UIEs
664 @rtype: list of string
665 '''
666
667 uies = InstallCache.list()
668 if kind is None:
669
670 return uies
671
672 return [metadata.name for metadata in
673 (InstallCache.get(name) for name in uies)
674 if (metadata.kind == kind and os.path.exists(metadata.path))]
675
677 '''
678 Gets if at least one UIE of the given kind is associated with the given
679 L{Tier} in the profile.
680
681 @param kind: Kind of UIE, one of L{ALL_KINDS}
682 @type kind: string
683 @param profile: Name of the profile
684 @type profile: string
685 @param tier: Name of the L{Tier} potentially associated with UIEs
686 @type tier: string
687 @return: At least one L{Tier} specific UIE?
688 @rtype: boolean
689 @raise ValueError: When the named profile does not exist
690 '''
691
692 sm = SettingsManager(profile)
693 sm.ensureProfile()
694 try:
695 uieset = sm.load(__name__)
696 except KeyError:
697
698 uieset = UIESet(profile)
699 sm.save(__name__, uieset)
700 return len(uieset.listTier(kind, tier)) > 0
701
703 '''
704 Gets a map associating L{Tier} names with UIEs of the given kind in this
705 profile.
706
707 @param kind: Kind of UIE, one of L{ALL_KINDS}
708 @type kind: string
709 @param profile: Name of the profile
710 @type profile: string
711 @return: Dictionary mapping L{Tier} names to lists of UIE names
712 @rtype: dictionary of string : list
713 @raise ValueError: When the named profile does not exist
714 '''
715
716 sm = SettingsManager(profile)
717 sm.ensureProfile()
718 try:
719 uieset = sm.load(__name__)
720 except KeyError:
721
722 uieset = UIESet(profile)
723 sm.save(__name__, uieset)
724 return uieset.listTierMap(kind)
725
727 '''
728 Gets a list of UIEs of the given kind associated with any L{Tier} in this
729 profile.
730
731 @param kind: Kind of UIE, one of L{ALL_KINDS}
732 @type kind: string
733 @param profile: Name of the profile
734 @type profile: string
735 @return: List of UIEs that load on any L{Tier}
736 @rtype: list of string
737 @raise ValueError: When the named profile does not exist
738 '''
739
740 sm = SettingsManager(profile)
741 sm.ensureProfile()
742 try:
743 uieset = sm.load(__name__)
744 except KeyError:
745
746 uieset = UIESet(profile)
747 sm.save(__name__, uieset)
748 return uieset.listAnyTier(kind)
749
751 '''
752 Gets a list of the names of all UIEs of the given kind associated with the
753 given profile. The tier may be specified for L{PERK}s. If it is, only UIEs
754 associated with that L{Tier} are returned.
755
756 @param kind: Kind of UIE, one of L{ALL_KINDS}
757 @type kind: string
758 @param profile: Name of the profile
759 @type profile: string
760 @param tier: Name of the L{Tier} associated with the UIEs. If None, fetches
761 UIE names for all L{Tier}s.
762 @type tier: string
763 @return: Names of the UIEs
764 @rtype: list of string or 2-tuple
765 @raise ValueError: When the named profile does not exist
766 '''
767
768 sm = SettingsManager(profile)
769 sm.ensureProfile()
770 try:
771 uieset = sm.load(__name__)
772 except KeyError:
773
774 uieset = UIESet(profile)
775 sm.save(__name__, uieset)
776
777 if kind in STARTUP_KINDS:
778
779 return uieset.listStartup(kind)
780 else:
781
782 return uieset.listAnyTier(kind) + uieset.listTier(kind, tier)
783
785 '''
786 Gets the absolute path where an installed UIE is located on disk. Does not
787 include the filename of the UIE.
788
789 @param name: Name of the UIE, unique across all UIEs
790 @type name: string
791 @return: Absolute parent directory of the UIE module on disk
792 @rtype: string
793 @raise KeyError: When a UIE with the given name is not installed
794 '''
795 path = InstallCache.get(name).path
796 return os.path.dirname(path)
797
799 '''
800 Gets the class representing the installed UIE of the given kind and name.
801 Checks if the UIE is installed. Fails to load the UIE if any of the
802 dependencies are missing.
803
804 @param name: Name of the UIE, unique across all UIEs of the same kind
805 @type name: string
806 @return: Instantiated UIE object or None if the object could not be loaded
807 @rtype: object
808 '''
809 try:
810 return _getUIEInstance(name)
811 except SyntaxError, e:
812
813 log.error('syntax error in %s: %s', name, str(e))
814 return None
815 except Exception, e:
816
817 info = traceback.extract_tb(sys.exc_info()[2])
818 log.debug('cannot load %s (%d): %s', name, info[-1][1], str(e))
819 return None
820
822 '''
823 Gets all UIE classes in the given profile to be loaded at the given time.
824
825 @param kind: Kind of UIE, one of L{ALL_KINDS}
826 @type kind: string
827 @param profile: Name of the profile
828 @type profile: string
829 @param tier: Name of the L{Tier} which causes the loading of the listed UIEs
830 @type tier: string
831 @return: All UIE instances to be loaded sorted in proper load order
832 @rtype: list of object
833 '''
834 names = listAssociated(kind, profile, tier)
835 return [uie for uie in (loadOne(name) for name in names) if uie is not None]
836
838 '''
839 Manages an in-memory cache of installed UIEs with persistent storage of the
840 cache on disk. The in-memory cache is brought up-to-date each time data is
841 read on the cache. The on-disk cache is updated each time new data is written
842 to the cache.
843
844 @ivar l_timestamp: Timestamp of the local cache file on disk
845 @type l_timestamp: integer
846 @ivar g_timestamp: Timestamp of the global cache file on disk
847 @type g_timestamp: integer
848 @ivar local: In-memory cache of UIEs installed for the local user pairing UIE
849 names with their absolute install paths
850 @type local: dictionary
851 @ivar local: In-memory cache of UIEs installed globally to be shared across
852 all users of the system user pairing UIE names with their absolute install
853 paths
854 @type local: dictionary
855 '''
857 '''
858 Initialize timestamps and try to load UIEs from disk.
859 '''
860
861 self.l_timestamp = 0
862 self.g_timestamp = 0
863
864 self.local = {}
865 self.globl = {}
866
868 '''
869 Try to read the local and global contents from disk.
870 '''
871 self._refreshLocal()
872 self._refreshGlobal()
873
874 - def _write(self, path, data):
875 '''
876 Persist the in-memory cache on disk. Include the current version and
877 revision information.
878
879 @param path: Path to the on-disk cache
880 @type path: string
881 @param data: Dictionary of name/value pairs
882 @type data: dictionary
883 @raise IOError: When the cache file cannot be written
884 '''
885 try:
886 f = file(path, 'wb')
887 cPickle.dump((data, PROG_VERSION+PROG_DATE), f, protocol=-1)
888 except cPickle.PickleError:
889 f.close()
890 raise IOError
891
893 '''
894 Read the on-disk cache into memory. Loads the version and revision
895 information persisted when the cache was written also.
896
897 @param path: Path to the on-disk cache
898 @type path: string
899 @return: Dictionary of name/value pairs and version/revision informatoin
900 @rtype: tuple of dictionary and string
901 @raise IOError: When the cache file cannot be read
902 '''
903 try:
904 f = file(path, 'rb')
905 return cPickle.load(f)
906 except cPickle.PickleError:
907 f.close()
908 raise IOError
909
911 '''
912 @return: Modified time on the file at path
913 @rtype: integer
914 '''
915 try:
916 return os.stat(path).st_mtime
917 except OSError:
918 return 0
919
921 '''
922 Refreshes the in-memory local cache if the on-disk cache is newer.
923
924 @raise IOError: When the cache file cannot be read
925 '''
926 mtime = self._mtime(LOCAL_PATH)
927 if mtime > self.l_timestamp:
928 self.local, version = self._read(LOCAL_PATH)
929 self.l_timestamp = mtime
930
932 '''
933 Refreshes the in-memory global cache if the on-disk cache is newer.
934
935 @raise IOError: When the cache file cannot be read
936 '''
937 mtime = self._mtime(GLOBAL_PATH)
938 if mtime > self.g_timestamp:
939 self.globl, version = self._read(GLOBAL_PATH)
940 self.g_timestamp = mtime
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
971 '''
972 Lists all installed UIEs, regardless of local or global status.
973
974 @return: List of UIE names
975 @rtype: list
976 '''
977 self._refreshLocal()
978 self._refreshGlobal()
979 return self.local.keys() + self.globl.keys()
980
981 - def addLocal(self, metadata, overwrite):
982 '''
983 Adds a new UIE to the list of UIEs installed locally.
984
985 @param metadata: Metadata describing the UIE
986 @type metadata: L{Metadata}
987 @param overwrite: Ignore errors if a UIE is already installed and
988 overwrite?
989 @type overwrite: boolean
990 @raise KeyError: When a UIE of the given name is already installed locally
991 or globally
992 @raise IOError: When the local on-disk cache cannot be updated
993 '''
994 name = metadata.name
995 if not overwrite:
996 if self.local.has_key(name):
997 raise KeyError(_('%s is already installed locally') % name)
998 if self.globl.has_key(name):
999 raise KeyError(_('%s is already installed globally') % name)
1000 self.local[name] = metadata
1001 self._write(LOCAL_PATH, self.local)
1002
1004 '''
1005 Adds a new UIE to the list of UIEs installed globally.
1006
1007 @param metadata: Metadata describing the UIE
1008 @type metadata: L{Metadata}
1009 @param overwrite: Ignore errors if a UIE is already installed and
1010 overwrite?
1011 @type overwrite: boolean
1012 @raise KeyError: When a UIE of the given name is already installed globally
1013 @raise IOError: When the global on-disk cache cannot be updated
1014 '''
1015 name = metadata.name
1016 if not overwrite:
1017 if self.globl.has_key(name):
1018 raise KeyError(_('%s is already installed globally') % name)
1019 self.globl[name] = metadata
1020 self._write(GLOBAL_PATH, self.globl)
1021
1023 '''
1024 Uninstalls an existing UIE from the local cache.
1025
1026 @param name: Name of the UIE
1027 @type name: string
1028 @return: Metadata for the removed UIE
1029 @rtype: L{Metadata}
1030 @raise KeyError: When the UIE is not already installed
1031 @raise IOError: When the local on-disk cache cannot be updated
1032 '''
1033 try:
1034 metadata = self.local[name]
1035 except KeyError:
1036 raise KeyError(_('%s is not installed locally') % name)
1037 del self.local[name]
1038 self._write(LOCAL_PATH, self.local)
1039 return metadata
1040
1042 '''
1043 Uninstalls an existing UIE from the global cache.
1044
1045 @param name: Name of the UIE
1046 @type name: string
1047 @return: Metadata for the removed UIE
1048 @rtype: L{Metadata}
1049 @raise KeyError: When the UIE is not already installed
1050 @raise IOError: When the global on-disk cache cannot be updated
1051 '''
1052 try:
1053 metadata = self.globl[name]
1054 except KeyError:
1055 raise KeyError(_('%s is not installed globally') % name)
1056 del self.globl[name]
1057 self._write(GLOBAL_PATH, self.globl)
1058 return metadata
1059
1060 - def get(self, name):
1061 '''
1062 Gets the absolute path to an installed UIE whether it is local or global.
1063
1064 @param name: Name of the UIE
1065 @type name: string
1066 @param metadata: Metadata describing the UIE
1067 @type metadata: L{Metadata}
1068 @raise KeyError: When the UIE isn't installed locally or globally
1069 '''
1070 try:
1071 self._refreshLocal()
1072 return self.local[name]
1073 except KeyError:
1074 pass
1075 self._refreshGlobal()
1076 try:
1077 return self.globl[name]
1078 except KeyError:
1079 raise KeyError(_('%s not installed') % name)
1080
1081
1082 InstallCache = InstallCache()
1083 InstallCache.init()
1084