ca5686dee7297fea6f203a8bf6dc25c13e9b1ba9
[be.git] / libbe / util / plugin.py
1 # Copyright (C) 2005-2012 Aaron Bentley <abentley@panoramicfeedback.com>
2 #                         Chris Ball <cjb@laptop.org>
3 #                         Gianluca Montecchi <gian@grys.it>
4 #                         Marien Zwart <marien.zwart@gmail.com>
5 #                         W. Trevor King <wking@drexel.edu>
6 #
7 # This file is part of Bugs Everywhere.
8 #
9 # Bugs Everywhere is free software: you can redistribute it and/or modify it
10 # under the terms of the GNU General Public License as published by the Free
11 # Software Foundation, either version 2 of the License, or (at your option) any
12 # later version.
13 #
14 # Bugs Everywhere is distributed in the hope that it will be useful, but
15 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
17 # more details.
18 #
19 # You should have received a copy of the GNU General Public License along with
20 # Bugs Everywhere.  If not, see <http://www.gnu.org/licenses/>.
21
22 """
23 Allow simple listing and loading of the various becommands and libbe
24 submodules (i.e. "plugins").
25 """
26
27 import os
28 import os.path
29 import sys
30 import zipfile
31
32
33 _PLUGIN_PATH = os.path.realpath(
34     os.path.dirname(
35         os.path.dirname(
36             os.path.dirname(__file__))))
37 if _PLUGIN_PATH not in sys.path:
38     sys.path.append(_PLUGIN_PATH)
39
40 def import_by_name(modname):
41     """
42     >>> mod = import_by_name('libbe.bugdir')
43     >>> 'BugDir' in dir(mod)
44     True
45     >>> import_by_name('libbe.highly_unlikely')
46     Traceback (most recent call last):
47       ...
48     ImportError: No module named highly_unlikely
49     """
50     module = __import__(modname)
51     components = modname.split('.')
52     for comp in components[1:]:
53         module = getattr(module, comp)
54     return module
55
56 def zip_listdir(path, components):
57     """Lists items in a directory contained in a zip file
58     """
59     dirpath = '/'.join(components)
60     with zipfile.ZipFile(path, 'r') as f:
61         return [os.path.relpath(f, dirpath) for f in f.namelist()
62                 if f.startswith(dirpath)]
63
64 def modnames(prefix):
65     """
66     >>> 'list' in [n for n in modnames('libbe.command')]
67     True
68     >>> 'plugin' in [n for n in modnames('libbe.util')]
69     True
70     """
71     components = prefix.split('.')
72     egg = os.path.isfile(_PLUGIN_PATH)  # are we inside a zip archive (egg)?
73     if egg:
74         modfiles = zip_listdir(_PLUGIN_PATH, components)
75     else:
76         modfiles = os.listdir(os.path.join(_PLUGIN_PATH, *components))
77     # normalize .py/.pyc extensions and sort
78     base_ext = [os.path.splitext(f) for f in modfiles]
79     modfiles = sorted(set(
80             base + '.py' for base,ext in base_ext if ext in ['.py', '.pyc']))
81     for modfile in modfiles:
82         if modfile.startswith('.') or not modfile:
83             continue # the occasional emacs temporary file or .* file
84         if modfile.endswith('.py') and modfile != '__init__.py':
85             yield modfile[:-3]