-
Notifications
You must be signed in to change notification settings - Fork 3
/
search.py
127 lines (105 loc) · 5 KB
/
search.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
from trac.admin.api import IAdminCommandProvider
from trac.core import *
from trac.config import *
from trac.search import ISearchSource, shorten_result
from trac.perm import IPermissionRequestor
from trac.mimeview.api import Mimeview
from trac.versioncontrol import RepositoryManager
from trac.versioncontrol.api import Node, IRepositoryChangeListener
from multireposearch.interfaces import IMultiRepoSearchBackend
class MultiRepoSearchPlugin(Component):
""" Search the source repository. """
implements(ISearchSource, IPermissionRequestor,
IAdminCommandProvider,
IRepositoryChangeListener)
search_backend = ExtensionOption(
'multireposearch', 'search_backend',
IMultiRepoSearchBackend,
'SqlIndexer',
"Name of the component implementing `IMultiRepoSearchBackend`, "
"which implements repository indexing and search strategies.")
def reindex_all(self, verbose=False):
repos = RepositoryManager(self.env).get_all_repositories()
for reponame in repos:
self.search_backend.reindex_repository(reponame, verbose=verbose)
## methods for IRepositoryChangeListener
def changeset_added(self, repos, changeset):
self.search_backend.reindex_repository(repos.reponame)
def changeset_modified(self, repos, changeset, old_changeset):
# TODO: not realy sure what to do here but i think we can ignore it,
# because changeset modifications can only pertain to commit-metadata
# which we don't care about
pass
### methods for IAdminCommandProvider
"""Extension point interface for adding commands to the console
administration interface `trac-admin`.
"""
def get_admin_commands(self):
"""Return a list of available admin commands.
The items returned by this function must be tuples of the form
`(command, args, help, complete, execute)`, where `command` contains
the space-separated command and sub-command names, `args` is a string
describing the command arguments and `help` is the help text. The
first paragraph of the help text is taken as a short help, shown in the
list of commands.
`complete` is called to auto-complete the command arguments, with the
current list of arguments as its only argument. It should return a list
of relevant values for the last argument in the list.
`execute` is called to execute the command, with the command arguments
passed as positional arguments.
"""
return [
('multireposearch reindex_all', '', 'reindex all known repositories',
None,
lambda: self.reindex_all(verbose=True)),
('multireposearch reindex', 'reponame', 'reindex a single repository',
None,
lambda reponame: self.search_backend.reindex_repository(reponame, verbose=True)),
]
# IPermissionRequestor methods
def get_permission_actions(self):
yield 'REPO_SEARCH'
# ISearchSource methods
def get_search_filters(self, req):
if req.perm.has_permission('REPO_SEARCH'):
yield ('repo', 'Source Repository', 1)
def get_search_results(self, req, query, filters):
if 'repo' not in filters:
return
for filename, reponame in self.search_backend.find_words(query):
try:
repo = self.env.get_repository(reponame=reponame, authname=req.authname)
except Exception, e:
# @@TODO: log it!
continue
if repo is None:
# @@TODO: log it? ask the search backend to remove the reference?
continue
try:
node = repo.get_node(filename)
except NoSuchNode, e:
# @@TODO: log it!
continue
if node.kind == Node.DIRECTORY:
yield (self.env.href.browser(reponame, filename),
"%s (in %s)" % (filename, reponame), change.date, change.author,
'Directory')
else:
found = 0
mimeview = Mimeview(self.env)
content = mimeview.to_unicode(node.get_content().read(), node.get_content_type())
for n, line in enumerate(content.splitlines()):
line = line.lower()
for q in query:
idx = line.find(q)
if idx != -1:
found = n + 1
break
if found:
break
change = repo.get_changeset(node.rev)
yield (self.env.href.browser(reponame, filename
) + (found and '#L%i' % found or ''
),
"%s (in %s)" % (filename, reponame), change.date, change.author,
shorten_result(content, query))