def get_plugin_info(env, include_core=False): """Return package information about Trac core and installed plugins.""" path_sources = {} def find_distribution(module): name = module.__name__ path = get_module_path(module) sources = path_sources.get(path) if sources is None: sources = path_sources[path] = get_sources(path) dist = sources.get(name.replace('.', '/') + '.py') if dist is None: dist = sources.get(name.replace('.', '/') + '/__init__.py') if dist is None: # This is a plain Python source file, not an egg dist = pkg_resources.Distribution(project_name=name, version='', location=module.__file__) return dist plugins_dir = env.plugins_dir plugins = {} from trac.core import ComponentMeta for component in ComponentMeta._components: module = sys.modules[component.__module__] dist = find_distribution(module) plugin_filename = None if os.path.realpath(os.path.dirname(dist.location)) == plugins_dir: plugin_filename = os.path.basename(dist.location) if dist.project_name not in plugins: readonly = True if plugin_filename and os.access(dist.location, os.F_OK + os.W_OK): readonly = False # retrieve plugin metadata info = get_pkginfo(dist) if not info: info = {} for k in ('author', 'author_email', 'home_page', 'url', 'license', 'summary', 'trac'): v = getattr(module, k, '') if v and isinstance(v, basestring): if k in ('home_page', 'url'): k = 'home_page' v = v.replace('$', '').replace('URL: ', '') else: v = to_unicode(v) info[k] = v else: # Info found; set all those fields to "None" that have the # value "UNKNOWN" as this is the value for fields that # aren't specified in "setup.py" for k in info: if info[k] == 'UNKNOWN': info[k] = '' else: # Must be encoded as unicode as otherwise Genshi # may raise a "UnicodeDecodeError". info[k] = to_unicode(info[k]) # retrieve plugin version info version = dist.version if not version: version = (getattr(module, 'version', '') or getattr(module, 'revision', '')) # special handling for "$Rev$" strings if version != '$Rev$': version = version.replace('$', '').replace('Rev: ', 'r') else: # keyword hasn't been expanded version = '' plugins[dist.project_name] = { 'name': dist.project_name, 'version': version, 'path': dist.location, 'plugin_filename': plugin_filename, 'readonly': readonly, 'info': info, 'modules': {}, } modules = plugins[dist.project_name]['modules'] if module.__name__ not in modules: summary, description = get_doc(module) plugins[dist.project_name]['modules'][module.__name__] = { 'summary': summary, 'description': description, 'components': {}, } full_name = module.__name__ + '.' + component.__name__ summary, description = get_doc(component) c = component if c in env and not issubclass(c, env.__class__): c = component(env) modules[module.__name__]['components'][component.__name__] = { 'full_name': full_name, 'summary': summary, 'description': description, 'enabled': env.is_component_enabled(component), 'required': getattr(c, 'required', False), } if not include_core: for name in list(plugins): if name.lower() == 'trac': plugins.pop(name) return sorted(plugins.itervalues(), key=lambda p: (p['name'].lower() != 'trac', p['name'].lower()))
def get_plugin_info(env, include_core=False): """Return package information about Trac core and installed plugins.""" path_sources = {} def find_distribution(module): name = module.__name__ path = get_module_path(module) sources = path_sources.get(path) if sources is None: sources = path_sources[path] = get_sources(path) dist = sources.get(name.replace('.', '/') + '.py') if dist is None: dist = sources.get(name.replace('.', '/') + '/__init__.py') if dist is None: # This is a plain Python source file, not an egg dist = pkg_resources.Distribution(project_name=name, version='', location=module.__file__) return dist plugins_dir = get_plugins_dir(env) plugins = {} from trac.core import ComponentMeta for component in ComponentMeta._components: module = sys.modules[component.__module__] dist = find_distribution(module) plugin_filename = None if os.path.realpath(os.path.dirname(dist.location)) == plugins_dir: plugin_filename = os.path.basename(dist.location) if dist.project_name not in plugins: readonly = True if plugin_filename and os.access(dist.location, os.F_OK + os.W_OK): readonly = False # retrieve plugin metadata info = get_pkginfo(dist) if not info: info = {} for k in ('author', 'author_email', 'home_page', 'url', 'license', 'trac'): v = getattr(module, k, '') if v and isinstance(v, basestring): if k == 'home_page' or k == 'url': k = 'home_page' v = v.replace('$', '').replace('URL: ', '') else: v = to_unicode(v) info[k] = v else: # Info found; set all those fields to "None" that have the # value "UNKNOWN" as this is the value for fields that # aren't specified in "setup.py" for k in info: if info[k] == 'UNKNOWN': info[k] = '' else: # Must be encoded as unicode as otherwise Genshi # may raise a "UnicodeDecodeError". info[k] = to_unicode(info[k]) # retrieve plugin version info version = dist.version if not version: version = (getattr(module, 'version', '') or getattr(module, 'revision', '')) # special handling for "$Rev$" strings version = version.replace('$', '').replace('Rev: ', 'r') plugins[dist.project_name] = { 'name': dist.project_name, 'version': version, 'path': dist.location, 'plugin_filename': plugin_filename, 'readonly': readonly, 'info': info, 'modules': {}, } modules = plugins[dist.project_name]['modules'] if module.__name__ not in modules: summary, description = get_doc(module) plugins[dist.project_name]['modules'][module.__name__] = { 'summary': summary, 'description': description, 'components': {}, } full_name = module.__name__ + '.' + component.__name__ summary, description = get_doc(component) c = component if c in env and not issubclass(c, env.__class__): c = component(env) modules[module.__name__]['components'][component.__name__] = { 'full_name': full_name, 'summary': summary, 'description': description, 'enabled': env.is_component_enabled(component), 'required': getattr(c, 'required', False), } if not include_core: for name in plugins.keys(): if name.lower() == 'trac': plugins.pop(name) return sorted(plugins.itervalues(), key=lambda p: (p['name'].lower() != 'trac', p['name'].lower()))