## AMB SearchAll - Search multiple trac projects at once from trac.core import * from trac.config import Option, ListOption from trac.web.href import Href try: from trac.search import ISearchSource, shorten_result except ImportError: from trac.Search import ISearchSource, shorten_result try: from trac.search.web_ui import SearchModule except ImportError: from trac.Search import SearchModule from trac.perm import IPermissionRequestor from trac.env import open_environment from trac.util import Markup from trac.util.datefmt import to_datetime from trac.util.text import to_unicode import re import posixpath import os import logging import copy from fnmatch import fnmatch class SearchAllPlugin(Component): """ Search the source repository. """ implements(ISearchSource) implements(IPermissionRequestor) include_projects = ListOption('searchall', 'include_projects', [], doc="Comma separated list of projects to include in ''Search All Projects''. If empty, all projects will be searched. Case sensitive.") exclude_projects = ListOption('searchall', 'exclude_projects', [], doc="Comma separated list of projects to exclude in ''Search All Projects''. Case sensitive.") def get_project_list(self, req): # get search path and base_url search_path, this_project = os.path.split(self.env.path) base_url, _ = posixpath.split(req.abs_href()) #Closes #4158, thanks to jholg if 'tracforge' in self.config: if self.config.get('tracforge', 'master_path') == self.env.path: base_url = '/'.join((base_url, this_project, 'projects')) projects = [] for project in os.listdir(search_path): # skip our own project if project == this_project: continue #Include only if project is in include_projects, or include_projects is empty if self.include_projects and (project not in self.include_projects): continue #Exclude if project is in exclude_projcets if project in self.exclude_projects: continue # make up URL for project project_url = '/'.join( (base_url, project) ) project_path = os.path.join(search_path, project) if not os.path.isdir( project_path ): continue try: env = open_environment(project_path, use_cache = True) except: try: env = open_environment(project_path) except: continue projects.append((project, project_path, project_url, env)) return projects # ISearchSource methods def get_search_filters(self, req): if not req.perm.has_permission('SEARCHALL_VIEW') and not req.perm.has_permission('TRAC_ADMIN'): return if hasattr(req, 'is_searchall_recursive'): return req.is_searchall_recursive = True #Check what filters are available in current project existing_filters = [] env_search = SearchModule(self.env) for source in env_search.search_sources: if source == self: continue existing_filters += source.get_search_filters(req) #Now get the filters available in other projects projects = self.get_project_list(req) for project, project_path, project_url, env in projects: env_search = SearchModule(env) available_filters = [] for source in env_search.search_sources: available_filters += source.get_search_filters(req) for filter in available_filters: if filter in existing_filters: continue existing_filters.append(filter) self.env.log.debug("Yielding %s from project %s", filter, project) yield filter yield ('searchall', 'All projects', 0) def get_search_results(self, req, query, filters): #return if search all is not active if 'searchall' not in filters: return if not req.perm.has_permission('SEARCHALL_VIEW') and not req.perm.has_permission('TRAC_ADMIN'): return # remove 'searchall' from filters subfilters = []; for filter in filters: if not filter == 'searchall': subfilters.append( filter ) # don't do anything if we have no filters if not subfilters: return projects = self.get_project_list(req) for project, project_path, project_url, env in projects: results = [] env_search = SearchModule(env) #available_filters = [] #for source in env_search.search_sources: # available_filters += source.get_search_filters(req) #subfilters = [x[0] for x in available_filters if x[0] != 'searchall'] self.env.log.debug("Searching project %s" % project ) self.env.log.debug("Searching for %s" % query[0] ) self.env.log.debug("Searching with filters %s" % subfilters ) #Update request data orig_href = req.href req.href = Href(project_url) for source in env_search.search_sources: for filter in subfilters: try: results += list(source.get_search_results(req, query, [filter])) except Exception, ex: results += [(req.href('search', **req.args), "ERROR in search filter %s" % filter, to_datetime(None), "none", "Exception: %s" % to_unicode(ex)),] req.href = orig_href for result in results: yield (result[0], Markup('%s
%s' % (env.project_name, result[1])))\ + result[2:] #IPermissionRequestor Methods def get_permission_actions(self): return ['SEARCHALL_VIEW']