##// END OF EJS Templates
pasters RhodeCode commands help text improvements
marcink -
r3339:b76a595b beta
parent child Browse files
Show More
@@ -1,66 +1,66 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.lib.dbmigrate.__init__
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Database migration modules
7 7
8 8 :created_on: Dec 11, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 import logging
27 27 from sqlalchemy import engine_from_config
28 28
29 29
30 30 from rhodecode.lib.utils import BasePasterCommand, Command, add_cache
31 31 from rhodecode.lib.db_manage import DbManage
32 32
33 33 log = logging.getLogger(__name__)
34 34
35 35
36 36 class UpgradeDb(BasePasterCommand):
37 37 """Command used for paster to upgrade our database to newer version
38 38 """
39 39
40 40 max_args = 1
41 41 min_args = 1
42 42
43 43 usage = "CONFIG_FILE"
44 summary = "Upgrades current db to newer version given configuration file"
44 summary = "Upgrades current db to newer version"
45 45 group_name = "RhodeCode"
46 46
47 47 parser = Command.standard_parser(verbose=True)
48 48
49 49 def command(self):
50 50 from pylons import config
51 51
52 52 add_cache(config)
53 53
54 54 db_uri = config['sqlalchemy.db1.url']
55 55
56 56 dbmanage = DbManage(log_sql=True, dbconf=db_uri,
57 57 root=config['here'], tests=False)
58 58
59 59 dbmanage.upgrade()
60 60
61 61 def update_parser(self):
62 62 self.parser.add_option('--sql',
63 63 action='store_true',
64 64 dest='just_sql',
65 65 help="Prints upgrade sql for further investigation",
66 66 default=False)
@@ -1,280 +1,280 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.lib.indexers.__init__
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Whoosh indexing module for RhodeCode
7 7
8 8 :created_on: Aug 17, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25 import os
26 26 import sys
27 27 import traceback
28 28 import logging
29 29 from os.path import dirname as dn, join as jn
30 30
31 31 #to get the rhodecode import
32 32 sys.path.append(dn(dn(dn(os.path.realpath(__file__)))))
33 33
34 34 from string import strip
35 35 from shutil import rmtree
36 36
37 37 from whoosh.analysis import RegexTokenizer, LowercaseFilter, StopFilter
38 38 from whoosh.fields import TEXT, ID, STORED, NUMERIC, BOOLEAN, Schema, FieldType, DATETIME
39 39 from whoosh.index import create_in, open_dir
40 40 from whoosh.formats import Characters
41 41 from whoosh.highlight import highlight, HtmlFormatter, ContextFragmenter
42 42
43 43 from webhelpers.html.builder import escape, literal
44 44 from sqlalchemy import engine_from_config
45 45
46 46 from rhodecode.model import init_model
47 47 from rhodecode.model.scm import ScmModel
48 48 from rhodecode.model.repo import RepoModel
49 49 from rhodecode.config.environment import load_environment
50 50 from rhodecode.lib.utils2 import LazyProperty
51 51 from rhodecode.lib.utils import BasePasterCommand, Command, add_cache,\
52 52 load_rcextensions
53 53
54 54 log = logging.getLogger(__name__)
55 55
56 56 # CUSTOM ANALYZER wordsplit + lowercase filter
57 57 ANALYZER = RegexTokenizer(expression=r"\w+") | LowercaseFilter()
58 58
59 59 #INDEX SCHEMA DEFINITION
60 60 SCHEMA = Schema(
61 61 fileid=ID(unique=True),
62 62 owner=TEXT(),
63 63 repository=TEXT(stored=True),
64 64 path=TEXT(stored=True),
65 65 content=FieldType(format=Characters(), analyzer=ANALYZER,
66 66 scorable=True, stored=True),
67 67 modtime=STORED(),
68 68 extension=TEXT(stored=True)
69 69 )
70 70
71 71 IDX_NAME = 'HG_INDEX'
72 72 FORMATTER = HtmlFormatter('span', between='\n<span class="break">...</span>\n')
73 73 FRAGMENTER = ContextFragmenter(200)
74 74
75 75 CHGSETS_SCHEMA = Schema(
76 76 raw_id=ID(unique=True, stored=True),
77 77 date=NUMERIC(stored=True),
78 78 last=BOOLEAN(),
79 79 owner=TEXT(),
80 80 repository=ID(unique=True, stored=True),
81 81 author=TEXT(stored=True),
82 82 message=FieldType(format=Characters(), analyzer=ANALYZER,
83 83 scorable=True, stored=True),
84 84 parents=TEXT(),
85 85 added=TEXT(),
86 86 removed=TEXT(),
87 87 changed=TEXT(),
88 88 )
89 89
90 90 CHGSET_IDX_NAME = 'CHGSET_INDEX'
91 91
92 92 # used only to generate queries in journal
93 93 JOURNAL_SCHEMA = Schema(
94 94 username=TEXT(),
95 95 date=DATETIME(),
96 96 action=TEXT(),
97 97 repository=TEXT(),
98 98 ip=TEXT(),
99 99 )
100 100
101 101
102 102 class MakeIndex(BasePasterCommand):
103 103
104 104 max_args = 1
105 105 min_args = 1
106 106
107 107 usage = "CONFIG_FILE"
108 summary = "Creates index for full text search given configuration file"
108 summary = "Creates or update full text search index"
109 109 group_name = "RhodeCode"
110 110 takes_config_file = -1
111 111 parser = Command.standard_parser(verbose=True)
112 112
113 113 def command(self):
114 114 logging.config.fileConfig(self.path_to_ini_file)
115 115 from pylons import config
116 116 add_cache(config)
117 117 engine = engine_from_config(config, 'sqlalchemy.db1.')
118 118 init_model(engine)
119 119 index_location = config['index_dir']
120 120 repo_location = self.options.repo_location \
121 121 if self.options.repo_location else RepoModel().repos_path
122 122 repo_list = map(strip, self.options.repo_list.split(',')) \
123 123 if self.options.repo_list else None
124 124 repo_update_list = map(strip, self.options.repo_update_list.split(',')) \
125 125 if self.options.repo_update_list else None
126 126 load_rcextensions(config['here'])
127 127 #======================================================================
128 128 # WHOOSH DAEMON
129 129 #======================================================================
130 130 from rhodecode.lib.pidlock import LockHeld, DaemonLock
131 131 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
132 132 try:
133 133 l = DaemonLock(file_=jn(dn(dn(index_location)), 'make_index.lock'))
134 134 WhooshIndexingDaemon(index_location=index_location,
135 135 repo_location=repo_location,
136 136 repo_list=repo_list,
137 137 repo_update_list=repo_update_list)\
138 138 .run(full_index=self.options.full_index)
139 139 l.release()
140 140 except LockHeld:
141 141 sys.exit(1)
142 142
143 143 def update_parser(self):
144 144 self.parser.add_option('--repo-location',
145 145 action='store',
146 146 dest='repo_location',
147 147 help="Specifies repositories location to index OPTIONAL",
148 148 )
149 149 self.parser.add_option('--index-only',
150 150 action='store',
151 151 dest='repo_list',
152 152 help="Specifies a comma separated list of repositores "
153 153 "to build index on. If not given all repositories "
154 154 "are scanned for indexing. OPTIONAL",
155 155 )
156 156 self.parser.add_option('--update-only',
157 157 action='store',
158 158 dest='repo_update_list',
159 159 help="Specifies a comma separated list of repositores "
160 160 "to re-build index on. OPTIONAL",
161 161 )
162 162 self.parser.add_option('-f',
163 163 action='store_true',
164 164 dest='full_index',
165 165 help="Specifies that index should be made full i.e"
166 166 " destroy old and build from scratch",
167 167 default=False)
168 168
169 169
170 170 class WhooshResultWrapper(object):
171 171 def __init__(self, search_type, searcher, matcher, highlight_items,
172 172 repo_location):
173 173 self.search_type = search_type
174 174 self.searcher = searcher
175 175 self.matcher = matcher
176 176 self.highlight_items = highlight_items
177 177 self.fragment_size = 200
178 178 self.repo_location = repo_location
179 179
180 180 @LazyProperty
181 181 def doc_ids(self):
182 182 docs_id = []
183 183 while self.matcher.is_active():
184 184 docnum = self.matcher.id()
185 185 chunks = [offsets for offsets in self.get_chunks()]
186 186 docs_id.append([docnum, chunks])
187 187 self.matcher.next()
188 188 return docs_id
189 189
190 190 def __str__(self):
191 191 return '<%s at %s>' % (self.__class__.__name__, len(self.doc_ids))
192 192
193 193 def __repr__(self):
194 194 return self.__str__()
195 195
196 196 def __len__(self):
197 197 return len(self.doc_ids)
198 198
199 199 def __iter__(self):
200 200 """
201 201 Allows Iteration over results,and lazy generate content
202 202
203 203 *Requires* implementation of ``__getitem__`` method.
204 204 """
205 205 for docid in self.doc_ids:
206 206 yield self.get_full_content(docid)
207 207
208 208 def __getitem__(self, key):
209 209 """
210 210 Slicing of resultWrapper
211 211 """
212 212 i, j = key.start, key.stop
213 213
214 214 slices = []
215 215 for docid in self.doc_ids[i:j]:
216 216 slices.append(self.get_full_content(docid))
217 217 return slices
218 218
219 219 def get_full_content(self, docid):
220 220 res = self.searcher.stored_fields(docid[0])
221 221 log.debug('result: %s' % res)
222 222 if self.search_type == 'content':
223 223 full_repo_path = jn(self.repo_location, res['repository'])
224 224 f_path = res['path'].split(full_repo_path)[-1]
225 225 f_path = f_path.lstrip(os.sep)
226 226 content_short = self.get_short_content(res, docid[1])
227 227 res.update({'content_short': content_short,
228 228 'content_short_hl': self.highlight(content_short),
229 229 'f_path': f_path
230 230 })
231 231 elif self.search_type == 'path':
232 232 full_repo_path = jn(self.repo_location, res['repository'])
233 233 f_path = res['path'].split(full_repo_path)[-1]
234 234 f_path = f_path.lstrip(os.sep)
235 235 res.update({'f_path': f_path})
236 236 elif self.search_type == 'message':
237 237 res.update({'message_hl': self.highlight(res['message'])})
238 238
239 239 log.debug('result: %s' % res)
240 240
241 241 return res
242 242
243 243 def get_short_content(self, res, chunks):
244 244
245 245 return ''.join([res['content'][chunk[0]:chunk[1]] for chunk in chunks])
246 246
247 247 def get_chunks(self):
248 248 """
249 249 Smart function that implements chunking the content
250 250 but not overlap chunks so it doesn't highlight the same
251 251 close occurrences twice.
252 252
253 253 :param matcher:
254 254 :param size:
255 255 """
256 256 memory = [(0, 0)]
257 257 if self.matcher.supports('positions'):
258 258 for span in self.matcher.spans():
259 259 start = span.startchar or 0
260 260 end = span.endchar or 0
261 261 start_offseted = max(0, start - self.fragment_size)
262 262 end_offseted = end + self.fragment_size
263 263
264 264 if start_offseted < memory[-1][1]:
265 265 start_offseted = memory[-1][1]
266 266 memory.append((start_offseted, end_offseted,))
267 267 yield (start_offseted, end_offseted,)
268 268
269 269 def highlight(self, content, top=5):
270 270 if self.search_type not in ['content', 'message']:
271 271 return ''
272 272 hl = highlight(
273 273 text=content,
274 274 terms=self.highlight_items,
275 275 analyzer=ANALYZER,
276 276 fragmenter=FRAGMENTER,
277 277 formatter=FORMATTER,
278 278 top=top
279 279 )
280 280 return hl
General Comments 0
You need to be logged in to leave comments. Login now