##// END OF EJS Templates
fixed whoosh indexing from admin panel
marcink -
r685:87943675 beta
parent child Browse files
Show More
@@ -1,298 +1,299 b''
1 from celery.decorators import task
1 from celery.decorators import task
2
2
3 from operator import itemgetter
3 from operator import itemgetter
4 from pylons.i18n.translation import _
4 from pylons.i18n.translation import _
5 from rhodecode.lib.celerylib import run_task, locked_task
5 from rhodecode.lib.celerylib import run_task, locked_task
6 from rhodecode.lib.helpers import person
6 from rhodecode.lib.helpers import person
7 from rhodecode.lib.smtp_mailer import SmtpMailer
7 from rhodecode.lib.smtp_mailer import SmtpMailer
8 from rhodecode.lib.utils import OrderedDict
8 from rhodecode.lib.utils import OrderedDict
9 from time import mktime
9 from time import mktime
10 import os
10 import os
11 import traceback
11 import traceback
12 from vcs.backends import get_repo
12 from vcs.backends import get_repo
13 from rhodecode.model.hg import HgModel
13 from rhodecode.model.hg import HgModel
14 try:
14 try:
15 import json
15 import json
16 except ImportError:
16 except ImportError:
17 #python 2.5 compatibility
17 #python 2.5 compatibility
18 import simplejson as json
18 import simplejson as json
19
19
20 try:
20 try:
21 from celeryconfig import PYLONS_CONFIG as config
21 from celeryconfig import PYLONS_CONFIG as config
22 celery_on = True
22 celery_on = True
23 except ImportError:
23 except ImportError:
24 #if celeryconfig is not present let's just load our pylons
24 #if celeryconfig is not present let's just load our pylons
25 #config instead
25 #config instead
26 from pylons import config
26 from pylons import config
27 celery_on = False
27 celery_on = False
28
28
29
29
30 __all__ = ['whoosh_index', 'get_commits_stats',
30 __all__ = ['whoosh_index', 'get_commits_stats',
31 'reset_user_password', 'send_email']
31 'reset_user_password', 'send_email']
32
32
33 def get_session():
33 def get_session():
34 if celery_on:
34 if celery_on:
35 from sqlalchemy import engine_from_config
35 from sqlalchemy import engine_from_config
36 from sqlalchemy.orm import sessionmaker, scoped_session
36 from sqlalchemy.orm import sessionmaker, scoped_session
37 engine = engine_from_config(dict(config.items('app:main')), 'sqlalchemy.db1.')
37 engine = engine_from_config(dict(config.items('app:main')),
38 'sqlalchemy.db1.')
38 sa = scoped_session(sessionmaker(bind=engine))
39 sa = scoped_session(sessionmaker(bind=engine))
39 else:
40 else:
40 #If we don't use celery reuse our current application Session
41 #If we don't use celery reuse our current application Session
41 from rhodecode.model.meta import Session
42 from rhodecode.model.meta import Session
42 sa = Session()
43 sa = Session()
43
44
44 return sa
45 return sa
45
46
46 @task
47 @task
47 @locked_task
48 @locked_task
48 def whoosh_index(repo_location, full_index):
49 def whoosh_index(repo_location, full_index):
49 log = whoosh_index.get_logger()
50 log = whoosh_index.get_logger()
50 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
51 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
51 index_location = ''
52 index_location = dict(config.items('app:main'))['index_dir']
52 WhooshIndexingDaemon(index_location=index_location,
53 WhooshIndexingDaemon(index_location=index_location,
53 repo_location=repo_location).run(full_index=full_index)
54 repo_location=repo_location).run(full_index=full_index)
54
55
55 @task
56 @task
56 @locked_task
57 @locked_task
57 def get_commits_stats(repo_name, ts_min_y, ts_max_y):
58 def get_commits_stats(repo_name, ts_min_y, ts_max_y):
58 from rhodecode.model.db import Statistics, Repository
59 from rhodecode.model.db import Statistics, Repository
59 log = get_commits_stats.get_logger()
60 log = get_commits_stats.get_logger()
60 author_key_cleaner = lambda k: person(k).replace('"', "") #for js data compatibilty
61 author_key_cleaner = lambda k: person(k).replace('"', "") #for js data compatibilty
61
62
62 commits_by_day_author_aggregate = {}
63 commits_by_day_author_aggregate = {}
63 commits_by_day_aggregate = {}
64 commits_by_day_aggregate = {}
64 repos_path = HgModel().repos_path
65 repos_path = HgModel().repos_path
65 p = os.path.join(repos_path, repo_name)
66 p = os.path.join(repos_path, repo_name)
66 repo = get_repo(p)
67 repo = get_repo(p)
67
68
68 skip_date_limit = True
69 skip_date_limit = True
69 parse_limit = 250 #limit for single task changeset parsing optimal for
70 parse_limit = 250 #limit for single task changeset parsing optimal for
70 last_rev = 0
71 last_rev = 0
71 last_cs = None
72 last_cs = None
72 timegetter = itemgetter('time')
73 timegetter = itemgetter('time')
73
74
74 sa = get_session()
75 sa = get_session()
75
76
76 dbrepo = sa.query(Repository)\
77 dbrepo = sa.query(Repository)\
77 .filter(Repository.repo_name == repo_name).scalar()
78 .filter(Repository.repo_name == repo_name).scalar()
78 cur_stats = sa.query(Statistics)\
79 cur_stats = sa.query(Statistics)\
79 .filter(Statistics.repository == dbrepo).scalar()
80 .filter(Statistics.repository == dbrepo).scalar()
80 if cur_stats:
81 if cur_stats:
81 last_rev = cur_stats.stat_on_revision
82 last_rev = cur_stats.stat_on_revision
82 if not repo.revisions:
83 if not repo.revisions:
83 return True
84 return True
84
85
85 if last_rev == repo.revisions[-1] and len(repo.revisions) > 1:
86 if last_rev == repo.revisions[-1] and len(repo.revisions) > 1:
86 #pass silently without any work if we're not on first revision or current
87 #pass silently without any work if we're not on first revision or current
87 #state of parsing revision(from db marker) is the last revision
88 #state of parsing revision(from db marker) is the last revision
88 return True
89 return True
89
90
90 if cur_stats:
91 if cur_stats:
91 commits_by_day_aggregate = OrderedDict(
92 commits_by_day_aggregate = OrderedDict(
92 json.loads(
93 json.loads(
93 cur_stats.commit_activity_combined))
94 cur_stats.commit_activity_combined))
94 commits_by_day_author_aggregate = json.loads(cur_stats.commit_activity)
95 commits_by_day_author_aggregate = json.loads(cur_stats.commit_activity)
95
96
96 log.debug('starting parsing %s', parse_limit)
97 log.debug('starting parsing %s', parse_limit)
97 lmktime = mktime
98 lmktime = mktime
98
99
99 for cnt, rev in enumerate(repo.revisions[last_rev:]):
100 for cnt, rev in enumerate(repo.revisions[last_rev:]):
100 last_cs = cs = repo.get_changeset(rev)
101 last_cs = cs = repo.get_changeset(rev)
101 k = '%s-%s-%s' % (cs.date.timetuple()[0], cs.date.timetuple()[1],
102 k = '%s-%s-%s' % (cs.date.timetuple()[0], cs.date.timetuple()[1],
102 cs.date.timetuple()[2])
103 cs.date.timetuple()[2])
103 timetupple = [int(x) for x in k.split('-')]
104 timetupple = [int(x) for x in k.split('-')]
104 timetupple.extend([0 for _ in xrange(6)])
105 timetupple.extend([0 for _ in xrange(6)])
105 k = lmktime(timetupple)
106 k = lmktime(timetupple)
106 if commits_by_day_author_aggregate.has_key(author_key_cleaner(cs.author)):
107 if commits_by_day_author_aggregate.has_key(author_key_cleaner(cs.author)):
107 try:
108 try:
108 l = [timegetter(x) for x in commits_by_day_author_aggregate\
109 l = [timegetter(x) for x in commits_by_day_author_aggregate\
109 [author_key_cleaner(cs.author)]['data']]
110 [author_key_cleaner(cs.author)]['data']]
110 time_pos = l.index(k)
111 time_pos = l.index(k)
111 except ValueError:
112 except ValueError:
112 time_pos = False
113 time_pos = False
113
114
114 if time_pos >= 0 and time_pos is not False:
115 if time_pos >= 0 and time_pos is not False:
115
116
116 datadict = commits_by_day_author_aggregate\
117 datadict = commits_by_day_author_aggregate\
117 [author_key_cleaner(cs.author)]['data'][time_pos]
118 [author_key_cleaner(cs.author)]['data'][time_pos]
118
119
119 datadict["commits"] += 1
120 datadict["commits"] += 1
120 datadict["added"] += len(cs.added)
121 datadict["added"] += len(cs.added)
121 datadict["changed"] += len(cs.changed)
122 datadict["changed"] += len(cs.changed)
122 datadict["removed"] += len(cs.removed)
123 datadict["removed"] += len(cs.removed)
123
124
124 else:
125 else:
125 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
126 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
126
127
127 datadict = {"time":k,
128 datadict = {"time":k,
128 "commits":1,
129 "commits":1,
129 "added":len(cs.added),
130 "added":len(cs.added),
130 "changed":len(cs.changed),
131 "changed":len(cs.changed),
131 "removed":len(cs.removed),
132 "removed":len(cs.removed),
132 }
133 }
133 commits_by_day_author_aggregate\
134 commits_by_day_author_aggregate\
134 [author_key_cleaner(cs.author)]['data'].append(datadict)
135 [author_key_cleaner(cs.author)]['data'].append(datadict)
135
136
136 else:
137 else:
137 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
138 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
138 commits_by_day_author_aggregate[author_key_cleaner(cs.author)] = {
139 commits_by_day_author_aggregate[author_key_cleaner(cs.author)] = {
139 "label":author_key_cleaner(cs.author),
140 "label":author_key_cleaner(cs.author),
140 "data":[{"time":k,
141 "data":[{"time":k,
141 "commits":1,
142 "commits":1,
142 "added":len(cs.added),
143 "added":len(cs.added),
143 "changed":len(cs.changed),
144 "changed":len(cs.changed),
144 "removed":len(cs.removed),
145 "removed":len(cs.removed),
145 }],
146 }],
146 "schema":["commits"],
147 "schema":["commits"],
147 }
148 }
148
149
149 #gather all data by day
150 #gather all data by day
150 if commits_by_day_aggregate.has_key(k):
151 if commits_by_day_aggregate.has_key(k):
151 commits_by_day_aggregate[k] += 1
152 commits_by_day_aggregate[k] += 1
152 else:
153 else:
153 commits_by_day_aggregate[k] = 1
154 commits_by_day_aggregate[k] = 1
154
155
155 if cnt >= parse_limit:
156 if cnt >= parse_limit:
156 #don't fetch to much data since we can freeze application
157 #don't fetch to much data since we can freeze application
157 break
158 break
158 overview_data = []
159 overview_data = []
159 for k, v in commits_by_day_aggregate.items():
160 for k, v in commits_by_day_aggregate.items():
160 overview_data.append([k, v])
161 overview_data.append([k, v])
161 overview_data = sorted(overview_data, key=itemgetter(0))
162 overview_data = sorted(overview_data, key=itemgetter(0))
162 if not commits_by_day_author_aggregate:
163 if not commits_by_day_author_aggregate:
163 commits_by_day_author_aggregate[author_key_cleaner(repo.contact)] = {
164 commits_by_day_author_aggregate[author_key_cleaner(repo.contact)] = {
164 "label":author_key_cleaner(repo.contact),
165 "label":author_key_cleaner(repo.contact),
165 "data":[0, 1],
166 "data":[0, 1],
166 "schema":["commits"],
167 "schema":["commits"],
167 }
168 }
168
169
169 stats = cur_stats if cur_stats else Statistics()
170 stats = cur_stats if cur_stats else Statistics()
170 stats.commit_activity = json.dumps(commits_by_day_author_aggregate)
171 stats.commit_activity = json.dumps(commits_by_day_author_aggregate)
171 stats.commit_activity_combined = json.dumps(overview_data)
172 stats.commit_activity_combined = json.dumps(overview_data)
172
173
173 log.debug('last revison %s', last_rev)
174 log.debug('last revison %s', last_rev)
174 leftovers = len(repo.revisions[last_rev:])
175 leftovers = len(repo.revisions[last_rev:])
175 log.debug('revisions to parse %s', leftovers)
176 log.debug('revisions to parse %s', leftovers)
176
177
177 if last_rev == 0 or leftovers < parse_limit:
178 if last_rev == 0 or leftovers < parse_limit:
178 stats.languages = json.dumps(__get_codes_stats(repo_name))
179 stats.languages = json.dumps(__get_codes_stats(repo_name))
179
180
180 stats.repository = dbrepo
181 stats.repository = dbrepo
181 stats.stat_on_revision = last_cs.revision
182 stats.stat_on_revision = last_cs.revision
182
183
183 try:
184 try:
184 sa.add(stats)
185 sa.add(stats)
185 sa.commit()
186 sa.commit()
186 except:
187 except:
187 log.error(traceback.format_exc())
188 log.error(traceback.format_exc())
188 sa.rollback()
189 sa.rollback()
189 return False
190 return False
190 if len(repo.revisions) > 1:
191 if len(repo.revisions) > 1:
191 run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y)
192 run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y)
192
193
193 return True
194 return True
194
195
195 @task
196 @task
196 def reset_user_password(user_email):
197 def reset_user_password(user_email):
197 log = reset_user_password.get_logger()
198 log = reset_user_password.get_logger()
198 from rhodecode.lib import auth
199 from rhodecode.lib import auth
199 from rhodecode.model.db import User
200 from rhodecode.model.db import User
200
201
201 try:
202 try:
202 try:
203 try:
203 sa = get_session()
204 sa = get_session()
204 user = sa.query(User).filter(User.email == user_email).scalar()
205 user = sa.query(User).filter(User.email == user_email).scalar()
205 new_passwd = auth.PasswordGenerator().gen_password(8,
206 new_passwd = auth.PasswordGenerator().gen_password(8,
206 auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
207 auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
207 if user:
208 if user:
208 user.password = auth.get_crypt_password(new_passwd)
209 user.password = auth.get_crypt_password(new_passwd)
209 sa.add(user)
210 sa.add(user)
210 sa.commit()
211 sa.commit()
211 log.info('change password for %s', user_email)
212 log.info('change password for %s', user_email)
212 if new_passwd is None:
213 if new_passwd is None:
213 raise Exception('unable to generate new password')
214 raise Exception('unable to generate new password')
214
215
215 except:
216 except:
216 log.error(traceback.format_exc())
217 log.error(traceback.format_exc())
217 sa.rollback()
218 sa.rollback()
218
219
219 run_task(send_email, user_email,
220 run_task(send_email, user_email,
220 "Your new rhodecode password",
221 "Your new rhodecode password",
221 'Your new rhodecode password:%s' % (new_passwd))
222 'Your new rhodecode password:%s' % (new_passwd))
222 log.info('send new password mail to %s', user_email)
223 log.info('send new password mail to %s', user_email)
223
224
224
225
225 except:
226 except:
226 log.error('Failed to update user password')
227 log.error('Failed to update user password')
227 log.error(traceback.format_exc())
228 log.error(traceback.format_exc())
228 return True
229 return True
229
230
230 @task
231 @task
231 def send_email(recipients, subject, body):
232 def send_email(recipients, subject, body):
232 log = send_email.get_logger()
233 log = send_email.get_logger()
233 email_config = dict(config.items('DEFAULT'))
234 email_config = dict(config.items('DEFAULT'))
234 mail_from = email_config.get('app_email_from')
235 mail_from = email_config.get('app_email_from')
235 user = email_config.get('smtp_username')
236 user = email_config.get('smtp_username')
236 passwd = email_config.get('smtp_password')
237 passwd = email_config.get('smtp_password')
237 mail_server = email_config.get('smtp_server')
238 mail_server = email_config.get('smtp_server')
238 mail_port = email_config.get('smtp_port')
239 mail_port = email_config.get('smtp_port')
239 tls = email_config.get('smtp_use_tls')
240 tls = email_config.get('smtp_use_tls')
240 ssl = False
241 ssl = False
241
242
242 try:
243 try:
243 m = SmtpMailer(mail_from, user, passwd, mail_server,
244 m = SmtpMailer(mail_from, user, passwd, mail_server,
244 mail_port, ssl, tls)
245 mail_port, ssl, tls)
245 m.send(recipients, subject, body)
246 m.send(recipients, subject, body)
246 except:
247 except:
247 log.error('Mail sending failed')
248 log.error('Mail sending failed')
248 log.error(traceback.format_exc())
249 log.error(traceback.format_exc())
249 return False
250 return False
250 return True
251 return True
251
252
252 @task
253 @task
253 def create_repo_fork(form_data, cur_user):
254 def create_repo_fork(form_data, cur_user):
254 from rhodecode.model.repo import RepoModel
255 from rhodecode.model.repo import RepoModel
255 from vcs import get_backend
256 from vcs import get_backend
256 log = create_repo_fork.get_logger()
257 log = create_repo_fork.get_logger()
257 repo_model = RepoModel(get_session())
258 repo_model = RepoModel(get_session())
258 repo_model.create(form_data, cur_user, just_db=True, fork=True)
259 repo_model.create(form_data, cur_user, just_db=True, fork=True)
259 repo_name = form_data['repo_name']
260 repo_name = form_data['repo_name']
260 repos_path = HgModel().repos_path
261 repos_path = HgModel().repos_path
261 repo_path = os.path.join(repos_path, repo_name)
262 repo_path = os.path.join(repos_path, repo_name)
262 repo_fork_path = os.path.join(repos_path, form_data['fork_name'])
263 repo_fork_path = os.path.join(repos_path, form_data['fork_name'])
263 alias = form_data['repo_type']
264 alias = form_data['repo_type']
264
265
265 log.info('creating repo fork %s as %s', repo_name, repo_path)
266 log.info('creating repo fork %s as %s', repo_name, repo_path)
266 backend = get_backend(alias)
267 backend = get_backend(alias)
267 backend(str(repo_fork_path), create=True, src_url=str(repo_path))
268 backend(str(repo_fork_path), create=True, src_url=str(repo_path))
268
269
269 def __get_codes_stats(repo_name):
270 def __get_codes_stats(repo_name):
270 LANGUAGES_EXTENSIONS = ['action', 'adp', 'ashx', 'asmx',
271 LANGUAGES_EXTENSIONS = ['action', 'adp', 'ashx', 'asmx',
271 'aspx', 'asx', 'axd', 'c', 'cfg', 'cfm', 'cpp', 'cs', 'diff', 'do', 'el',
272 'aspx', 'asx', 'axd', 'c', 'cfg', 'cfm', 'cpp', 'cs', 'diff', 'do', 'el',
272 'erl', 'h', 'java', 'js', 'jsp', 'jspx', 'lisp', 'lua', 'm', 'mako', 'ml',
273 'erl', 'h', 'java', 'js', 'jsp', 'jspx', 'lisp', 'lua', 'm', 'mako', 'ml',
273 'pas', 'patch', 'php', 'php3', 'php4', 'phtml', 'pm', 'py', 'rb', 'rst',
274 'pas', 'patch', 'php', 'php3', 'php4', 'phtml', 'pm', 'py', 'rb', 'rst',
274 's', 'sh', 'tpl', 'txt', 'vim', 'wss', 'xhtml', 'xml', 'xsl', 'xslt', 'yaws']
275 's', 'sh', 'tpl', 'txt', 'vim', 'wss', 'xhtml', 'xml', 'xsl', 'xslt', 'yaws']
275
276
276
277
277 repos_path = HgModel().repos_path
278 repos_path = HgModel().repos_path
278 p = os.path.join(repos_path, repo_name)
279 p = os.path.join(repos_path, repo_name)
279 repo = get_repo(p)
280 repo = get_repo(p)
280 tip = repo.get_changeset()
281 tip = repo.get_changeset()
281 code_stats = {}
282 code_stats = {}
282
283
283 def aggregate(cs):
284 def aggregate(cs):
284 for f in cs[2]:
285 for f in cs[2]:
285 k = f.mimetype
286 k = f.mimetype
286 if f.extension in LANGUAGES_EXTENSIONS:
287 if f.extension in LANGUAGES_EXTENSIONS:
287 if code_stats.has_key(k):
288 if code_stats.has_key(k):
288 code_stats[k] += 1
289 code_stats[k] += 1
289 else:
290 else:
290 code_stats[k] = 1
291 code_stats[k] = 1
291
292
292 map(aggregate, tip.walk('/'))
293 map(aggregate, tip.walk('/'))
293
294
294 return code_stats or {}
295 return code_stats or {}
295
296
296
297
297
298
298
299
General Comments 0
You need to be logged in to leave comments. Login now