##// END OF EJS Templates
implements #291 email notification sent to all admin users
marcink -
r1642:c0d8171a default
parent child Browse files
Show More
@@ -1,412 +1,414
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.celerylib.tasks
3 rhodecode.lib.celerylib.tasks
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 RhodeCode task modules, containing all task that suppose to be run
6 RhodeCode task modules, containing all task that suppose to be run
7 by celery daemon
7 by celery daemon
8
8
9 :created_on: Oct 6, 2010
9 :created_on: Oct 6, 2010
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
12 :license: GPLv3, see COPYING for more details.
12 :license: GPLv3, see COPYING for more details.
13 """
13 """
14 # This program is free software: you can redistribute it and/or modify
14 # This program is free software: you can redistribute it and/or modify
15 # it under the terms of the GNU General Public License as published by
15 # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation, either version 3 of the License, or
16 # the Free Software Foundation, either version 3 of the License, or
17 # (at your option) any later version.
17 # (at your option) any later version.
18 #
18 #
19 # This program is distributed in the hope that it will be useful,
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
22 # GNU General Public License for more details.
23 #
23 #
24 # You should have received a copy of the GNU General Public License
24 # You should have received a copy of the GNU General Public License
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 from celery.decorators import task
26 from celery.decorators import task
27
27
28 import os
28 import os
29 import traceback
29 import traceback
30 import logging
30 import logging
31 from os.path import dirname as dn, join as jn
31 from os.path import dirname as dn, join as jn
32
32
33 from time import mktime
33 from time import mktime
34 from operator import itemgetter
34 from operator import itemgetter
35 from string import lower
35 from string import lower
36
36
37 from pylons import config, url
37 from pylons import config, url
38 from pylons.i18n.translation import _
38 from pylons.i18n.translation import _
39
39
40 from rhodecode.lib import LANGUAGES_EXTENSIONS_MAP, safe_str
40 from rhodecode.lib import LANGUAGES_EXTENSIONS_MAP, safe_str
41 from rhodecode.lib.celerylib import run_task, locked_task, str2bool, \
41 from rhodecode.lib.celerylib import run_task, locked_task, str2bool, \
42 __get_lockkey, LockHeld, DaemonLock
42 __get_lockkey, LockHeld, DaemonLock
43 from rhodecode.lib.helpers import person
43 from rhodecode.lib.helpers import person
44 from rhodecode.lib.smtp_mailer import SmtpMailer
44 from rhodecode.lib.smtp_mailer import SmtpMailer
45 from rhodecode.lib.utils import add_cache
45 from rhodecode.lib.utils import add_cache
46 from rhodecode.lib.compat import json, OrderedDict
46 from rhodecode.lib.compat import json, OrderedDict
47
47
48 from rhodecode.model import init_model
48 from rhodecode.model import init_model
49 from rhodecode.model import meta
49 from rhodecode.model import meta
50 from rhodecode.model.db import RhodeCodeUi, Statistics, Repository
50 from rhodecode.model.db import RhodeCodeUi, Statistics, Repository, User
51
51
52 from vcs.backends import get_repo
52 from vcs.backends import get_repo
53
53
54 from sqlalchemy import engine_from_config
54 from sqlalchemy import engine_from_config
55
55
56 add_cache(config)
56 add_cache(config)
57
57
58
58
59
59
60 __all__ = ['whoosh_index', 'get_commits_stats',
60 __all__ = ['whoosh_index', 'get_commits_stats',
61 'reset_user_password', 'send_email']
61 'reset_user_password', 'send_email']
62
62
63 CELERY_ON = str2bool(config['app_conf'].get('use_celery'))
63 CELERY_ON = str2bool(config['app_conf'].get('use_celery'))
64
64
65
65
66 def get_session():
66 def get_session():
67 if CELERY_ON:
67 if CELERY_ON:
68 engine = engine_from_config(config, 'sqlalchemy.db1.')
68 engine = engine_from_config(config, 'sqlalchemy.db1.')
69 init_model(engine)
69 init_model(engine)
70 sa = meta.Session()
70 sa = meta.Session()
71 return sa
71 return sa
72
72
73
73
74 def get_repos_path():
74 def get_repos_path():
75 sa = get_session()
75 sa = get_session()
76 q = sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
76 q = sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
77 return q.ui_value
77 return q.ui_value
78
78
79
79
80 @task(ignore_result=True)
80 @task(ignore_result=True)
81 @locked_task
81 @locked_task
82 def whoosh_index(repo_location, full_index):
82 def whoosh_index(repo_location, full_index):
83 #log = whoosh_index.get_logger()
83 #log = whoosh_index.get_logger()
84 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
84 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
85 index_location = config['index_dir']
85 index_location = config['index_dir']
86 WhooshIndexingDaemon(index_location=index_location,
86 WhooshIndexingDaemon(index_location=index_location,
87 repo_location=repo_location, sa=get_session())\
87 repo_location=repo_location, sa=get_session())\
88 .run(full_index=full_index)
88 .run(full_index=full_index)
89
89
90
90
91 @task(ignore_result=True)
91 @task(ignore_result=True)
92 def get_commits_stats(repo_name, ts_min_y, ts_max_y):
92 def get_commits_stats(repo_name, ts_min_y, ts_max_y):
93 try:
93 try:
94 log = get_commits_stats.get_logger()
94 log = get_commits_stats.get_logger()
95 except:
95 except:
96 log = logging.getLogger(__name__)
96 log = logging.getLogger(__name__)
97
97
98 lockkey = __get_lockkey('get_commits_stats', repo_name, ts_min_y,
98 lockkey = __get_lockkey('get_commits_stats', repo_name, ts_min_y,
99 ts_max_y)
99 ts_max_y)
100 lockkey_path = config['here']
100 lockkey_path = config['here']
101
101
102 log.info('running task with lockkey %s', lockkey)
102 log.info('running task with lockkey %s', lockkey)
103 try:
103 try:
104 lock = l = DaemonLock(file_=jn(lockkey_path, lockkey))
104 lock = l = DaemonLock(file_=jn(lockkey_path, lockkey))
105
105
106 #for js data compatibilty cleans the key for person from '
106 #for js data compatibilty cleans the key for person from '
107 akc = lambda k: person(k).replace('"', "")
107 akc = lambda k: person(k).replace('"', "")
108
108
109 co_day_auth_aggr = {}
109 co_day_auth_aggr = {}
110 commits_by_day_aggregate = {}
110 commits_by_day_aggregate = {}
111 repos_path = get_repos_path()
111 repos_path = get_repos_path()
112 repo = get_repo(safe_str(os.path.join(repos_path, repo_name)))
112 repo = get_repo(safe_str(os.path.join(repos_path, repo_name)))
113 repo_size = len(repo.revisions)
113 repo_size = len(repo.revisions)
114 #return if repo have no revisions
114 #return if repo have no revisions
115 if repo_size < 1:
115 if repo_size < 1:
116 lock.release()
116 lock.release()
117 return True
117 return True
118
118
119 skip_date_limit = True
119 skip_date_limit = True
120 parse_limit = int(config['app_conf'].get('commit_parse_limit'))
120 parse_limit = int(config['app_conf'].get('commit_parse_limit'))
121 last_rev = 0
121 last_rev = 0
122 last_cs = None
122 last_cs = None
123 timegetter = itemgetter('time')
123 timegetter = itemgetter('time')
124
124
125 sa = get_session()
125 sa = get_session()
126
126
127 dbrepo = sa.query(Repository)\
127 dbrepo = sa.query(Repository)\
128 .filter(Repository.repo_name == repo_name).scalar()
128 .filter(Repository.repo_name == repo_name).scalar()
129 cur_stats = sa.query(Statistics)\
129 cur_stats = sa.query(Statistics)\
130 .filter(Statistics.repository == dbrepo).scalar()
130 .filter(Statistics.repository == dbrepo).scalar()
131
131
132 if cur_stats is not None:
132 if cur_stats is not None:
133 last_rev = cur_stats.stat_on_revision
133 last_rev = cur_stats.stat_on_revision
134
134
135 if last_rev == repo.get_changeset().revision and repo_size > 1:
135 if last_rev == repo.get_changeset().revision and repo_size > 1:
136 #pass silently without any work if we're not on first revision or
136 #pass silently without any work if we're not on first revision or
137 #current state of parsing revision(from db marker) is the
137 #current state of parsing revision(from db marker) is the
138 #last revision
138 #last revision
139 lock.release()
139 lock.release()
140 return True
140 return True
141
141
142 if cur_stats:
142 if cur_stats:
143 commits_by_day_aggregate = OrderedDict(json.loads(
143 commits_by_day_aggregate = OrderedDict(json.loads(
144 cur_stats.commit_activity_combined))
144 cur_stats.commit_activity_combined))
145 co_day_auth_aggr = json.loads(cur_stats.commit_activity)
145 co_day_auth_aggr = json.loads(cur_stats.commit_activity)
146
146
147 log.debug('starting parsing %s', parse_limit)
147 log.debug('starting parsing %s', parse_limit)
148 lmktime = mktime
148 lmktime = mktime
149
149
150 last_rev = last_rev + 1 if last_rev > 0 else last_rev
150 last_rev = last_rev + 1 if last_rev > 0 else last_rev
151
151
152 for cs in repo[last_rev:last_rev + parse_limit]:
152 for cs in repo[last_rev:last_rev + parse_limit]:
153 last_cs = cs # remember last parsed changeset
153 last_cs = cs # remember last parsed changeset
154 k = lmktime([cs.date.timetuple()[0], cs.date.timetuple()[1],
154 k = lmktime([cs.date.timetuple()[0], cs.date.timetuple()[1],
155 cs.date.timetuple()[2], 0, 0, 0, 0, 0, 0])
155 cs.date.timetuple()[2], 0, 0, 0, 0, 0, 0])
156
156
157 if akc(cs.author) in co_day_auth_aggr:
157 if akc(cs.author) in co_day_auth_aggr:
158 try:
158 try:
159 l = [timegetter(x) for x in
159 l = [timegetter(x) for x in
160 co_day_auth_aggr[akc(cs.author)]['data']]
160 co_day_auth_aggr[akc(cs.author)]['data']]
161 time_pos = l.index(k)
161 time_pos = l.index(k)
162 except ValueError:
162 except ValueError:
163 time_pos = False
163 time_pos = False
164
164
165 if time_pos >= 0 and time_pos is not False:
165 if time_pos >= 0 and time_pos is not False:
166
166
167 datadict = \
167 datadict = \
168 co_day_auth_aggr[akc(cs.author)]['data'][time_pos]
168 co_day_auth_aggr[akc(cs.author)]['data'][time_pos]
169
169
170 datadict["commits"] += 1
170 datadict["commits"] += 1
171 datadict["added"] += len(cs.added)
171 datadict["added"] += len(cs.added)
172 datadict["changed"] += len(cs.changed)
172 datadict["changed"] += len(cs.changed)
173 datadict["removed"] += len(cs.removed)
173 datadict["removed"] += len(cs.removed)
174
174
175 else:
175 else:
176 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
176 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
177
177
178 datadict = {"time": k,
178 datadict = {"time": k,
179 "commits": 1,
179 "commits": 1,
180 "added": len(cs.added),
180 "added": len(cs.added),
181 "changed": len(cs.changed),
181 "changed": len(cs.changed),
182 "removed": len(cs.removed),
182 "removed": len(cs.removed),
183 }
183 }
184 co_day_auth_aggr[akc(cs.author)]['data']\
184 co_day_auth_aggr[akc(cs.author)]['data']\
185 .append(datadict)
185 .append(datadict)
186
186
187 else:
187 else:
188 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
188 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
189 co_day_auth_aggr[akc(cs.author)] = {
189 co_day_auth_aggr[akc(cs.author)] = {
190 "label": akc(cs.author),
190 "label": akc(cs.author),
191 "data": [{"time":k,
191 "data": [{"time":k,
192 "commits":1,
192 "commits":1,
193 "added":len(cs.added),
193 "added":len(cs.added),
194 "changed":len(cs.changed),
194 "changed":len(cs.changed),
195 "removed":len(cs.removed),
195 "removed":len(cs.removed),
196 }],
196 }],
197 "schema": ["commits"],
197 "schema": ["commits"],
198 }
198 }
199
199
200 #gather all data by day
200 #gather all data by day
201 if k in commits_by_day_aggregate:
201 if k in commits_by_day_aggregate:
202 commits_by_day_aggregate[k] += 1
202 commits_by_day_aggregate[k] += 1
203 else:
203 else:
204 commits_by_day_aggregate[k] = 1
204 commits_by_day_aggregate[k] = 1
205
205
206 overview_data = sorted(commits_by_day_aggregate.items(),
206 overview_data = sorted(commits_by_day_aggregate.items(),
207 key=itemgetter(0))
207 key=itemgetter(0))
208
208
209 if not co_day_auth_aggr:
209 if not co_day_auth_aggr:
210 co_day_auth_aggr[akc(repo.contact)] = {
210 co_day_auth_aggr[akc(repo.contact)] = {
211 "label": akc(repo.contact),
211 "label": akc(repo.contact),
212 "data": [0, 1],
212 "data": [0, 1],
213 "schema": ["commits"],
213 "schema": ["commits"],
214 }
214 }
215
215
216 stats = cur_stats if cur_stats else Statistics()
216 stats = cur_stats if cur_stats else Statistics()
217 stats.commit_activity = json.dumps(co_day_auth_aggr)
217 stats.commit_activity = json.dumps(co_day_auth_aggr)
218 stats.commit_activity_combined = json.dumps(overview_data)
218 stats.commit_activity_combined = json.dumps(overview_data)
219
219
220 log.debug('last revison %s', last_rev)
220 log.debug('last revison %s', last_rev)
221 leftovers = len(repo.revisions[last_rev:])
221 leftovers = len(repo.revisions[last_rev:])
222 log.debug('revisions to parse %s', leftovers)
222 log.debug('revisions to parse %s', leftovers)
223
223
224 if last_rev == 0 or leftovers < parse_limit:
224 if last_rev == 0 or leftovers < parse_limit:
225 log.debug('getting code trending stats')
225 log.debug('getting code trending stats')
226 stats.languages = json.dumps(__get_codes_stats(repo_name))
226 stats.languages = json.dumps(__get_codes_stats(repo_name))
227
227
228 try:
228 try:
229 stats.repository = dbrepo
229 stats.repository = dbrepo
230 stats.stat_on_revision = last_cs.revision if last_cs else 0
230 stats.stat_on_revision = last_cs.revision if last_cs else 0
231 sa.add(stats)
231 sa.add(stats)
232 sa.commit()
232 sa.commit()
233 except:
233 except:
234 log.error(traceback.format_exc())
234 log.error(traceback.format_exc())
235 sa.rollback()
235 sa.rollback()
236 lock.release()
236 lock.release()
237 return False
237 return False
238
238
239 #final release
239 #final release
240 lock.release()
240 lock.release()
241
241
242 #execute another task if celery is enabled
242 #execute another task if celery is enabled
243 if len(repo.revisions) > 1 and CELERY_ON:
243 if len(repo.revisions) > 1 and CELERY_ON:
244 run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y)
244 run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y)
245 return True
245 return True
246 except LockHeld:
246 except LockHeld:
247 log.info('LockHeld')
247 log.info('LockHeld')
248 return 'Task with key %s already running' % lockkey
248 return 'Task with key %s already running' % lockkey
249
249
250 @task(ignore_result=True)
250 @task(ignore_result=True)
251 def send_password_link(user_email):
251 def send_password_link(user_email):
252 try:
252 try:
253 log = reset_user_password.get_logger()
253 log = reset_user_password.get_logger()
254 except:
254 except:
255 log = logging.getLogger(__name__)
255 log = logging.getLogger(__name__)
256
256
257 from rhodecode.lib import auth
257 from rhodecode.lib import auth
258 from rhodecode.model.db import User
258 from rhodecode.model.db import User
259
259
260 try:
260 try:
261 sa = get_session()
261 sa = get_session()
262 user = sa.query(User).filter(User.email == user_email).scalar()
262 user = sa.query(User).filter(User.email == user_email).scalar()
263
263
264 if user:
264 if user:
265 link = url('reset_password_confirmation', key=user.api_key,
265 link = url('reset_password_confirmation', key=user.api_key,
266 qualified=True)
266 qualified=True)
267 tmpl = """
267 tmpl = """
268 Hello %s
268 Hello %s
269
269
270 We received a request to create a new password for your account.
270 We received a request to create a new password for your account.
271
271
272 You can generate it by clicking following URL:
272 You can generate it by clicking following URL:
273
273
274 %s
274 %s
275
275
276 If you didn't request new password please ignore this email.
276 If you didn't request new password please ignore this email.
277 """
277 """
278 run_task(send_email, user_email,
278 run_task(send_email, user_email,
279 "RhodeCode password reset link",
279 "RhodeCode password reset link",
280 tmpl % (user.short_contact, link))
280 tmpl % (user.short_contact, link))
281 log.info('send new password mail to %s', user_email)
281 log.info('send new password mail to %s', user_email)
282
282
283 except:
283 except:
284 log.error('Failed to update user password')
284 log.error('Failed to update user password')
285 log.error(traceback.format_exc())
285 log.error(traceback.format_exc())
286 return False
286 return False
287
287
288 return True
288 return True
289
289
290 @task(ignore_result=True)
290 @task(ignore_result=True)
291 def reset_user_password(user_email):
291 def reset_user_password(user_email):
292 try:
292 try:
293 log = reset_user_password.get_logger()
293 log = reset_user_password.get_logger()
294 except:
294 except:
295 log = logging.getLogger(__name__)
295 log = logging.getLogger(__name__)
296
296
297 from rhodecode.lib import auth
297 from rhodecode.lib import auth
298 from rhodecode.model.db import User
298 from rhodecode.model.db import User
299
299
300 try:
300 try:
301 try:
301 try:
302 sa = get_session()
302 sa = get_session()
303 user = sa.query(User).filter(User.email == user_email).scalar()
303 user = sa.query(User).filter(User.email == user_email).scalar()
304 new_passwd = auth.PasswordGenerator().gen_password(8,
304 new_passwd = auth.PasswordGenerator().gen_password(8,
305 auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
305 auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
306 if user:
306 if user:
307 user.password = auth.get_crypt_password(new_passwd)
307 user.password = auth.get_crypt_password(new_passwd)
308 user.api_key = auth.generate_api_key(user.username)
308 user.api_key = auth.generate_api_key(user.username)
309 sa.add(user)
309 sa.add(user)
310 sa.commit()
310 sa.commit()
311 log.info('change password for %s', user_email)
311 log.info('change password for %s', user_email)
312 if new_passwd is None:
312 if new_passwd is None:
313 raise Exception('unable to generate new password')
313 raise Exception('unable to generate new password')
314
314
315 except:
315 except:
316 log.error(traceback.format_exc())
316 log.error(traceback.format_exc())
317 sa.rollback()
317 sa.rollback()
318
318
319 run_task(send_email, user_email,
319 run_task(send_email, user_email,
320 "Your new RhodeCode password",
320 "Your new RhodeCode password",
321 'Your new RhodeCode password:%s' % (new_passwd))
321 'Your new RhodeCode password:%s' % (new_passwd))
322 log.info('send new password mail to %s', user_email)
322 log.info('send new password mail to %s', user_email)
323
323
324 except:
324 except:
325 log.error('Failed to update user password')
325 log.error('Failed to update user password')
326 log.error(traceback.format_exc())
326 log.error(traceback.format_exc())
327
327
328 return True
328 return True
329
329
330
330
331 @task(ignore_result=True)
331 @task(ignore_result=True)
332 def send_email(recipients, subject, body):
332 def send_email(recipients, subject, body):
333 """
333 """
334 Sends an email with defined parameters from the .ini files.
334 Sends an email with defined parameters from the .ini files.
335
335
336 :param recipients: list of recipients, it this is empty the defined email
336 :param recipients: list of recipients, it this is empty the defined email
337 address from field 'email_to' is used instead
337 address from field 'email_to' is used instead
338 :param subject: subject of the mail
338 :param subject: subject of the mail
339 :param body: body of the mail
339 :param body: body of the mail
340 """
340 """
341 try:
341 try:
342 log = send_email.get_logger()
342 log = send_email.get_logger()
343 except:
343 except:
344 log = logging.getLogger(__name__)
344 log = logging.getLogger(__name__)
345
345
346 email_config = config
346 email_config = config
347
347
348 if not recipients:
348 if not recipients:
349 recipients = [email_config.get('email_to')]
349 # if recipients are not defined we send to email_config + all admins
350 admins = [u.email for u in User.query().filter(User.admin==True).all()]
351 recipients = [email_config.get('email_to')] + admins
350
352
351 mail_from = email_config.get('app_email_from')
353 mail_from = email_config.get('app_email_from')
352 user = email_config.get('smtp_username')
354 user = email_config.get('smtp_username')
353 passwd = email_config.get('smtp_password')
355 passwd = email_config.get('smtp_password')
354 mail_server = email_config.get('smtp_server')
356 mail_server = email_config.get('smtp_server')
355 mail_port = email_config.get('smtp_port')
357 mail_port = email_config.get('smtp_port')
356 tls = str2bool(email_config.get('smtp_use_tls'))
358 tls = str2bool(email_config.get('smtp_use_tls'))
357 ssl = str2bool(email_config.get('smtp_use_ssl'))
359 ssl = str2bool(email_config.get('smtp_use_ssl'))
358 debug = str2bool(config.get('debug'))
360 debug = str2bool(config.get('debug'))
359 smtp_auth = email_config.get('smtp_auth')
361 smtp_auth = email_config.get('smtp_auth')
360
362
361 try:
363 try:
362 m = SmtpMailer(mail_from, user, passwd, mail_server,smtp_auth,
364 m = SmtpMailer(mail_from, user, passwd, mail_server,smtp_auth,
363 mail_port, ssl, tls, debug=debug)
365 mail_port, ssl, tls, debug=debug)
364 m.send(recipients, subject, body)
366 m.send(recipients, subject, body)
365 except:
367 except:
366 log.error('Mail sending failed')
368 log.error('Mail sending failed')
367 log.error(traceback.format_exc())
369 log.error(traceback.format_exc())
368 return False
370 return False
369 return True
371 return True
370
372
371
373
372 @task(ignore_result=True)
374 @task(ignore_result=True)
373 def create_repo_fork(form_data, cur_user):
375 def create_repo_fork(form_data, cur_user):
374 from rhodecode.model.repo import RepoModel
376 from rhodecode.model.repo import RepoModel
375 from vcs import get_backend
377 from vcs import get_backend
376
378
377 try:
379 try:
378 log = create_repo_fork.get_logger()
380 log = create_repo_fork.get_logger()
379 except:
381 except:
380 log = logging.getLogger(__name__)
382 log = logging.getLogger(__name__)
381
383
382 repo_model = RepoModel(get_session())
384 repo_model = RepoModel(get_session())
383 repo_model.create(form_data, cur_user, just_db=True, fork=True)
385 repo_model.create(form_data, cur_user, just_db=True, fork=True)
384 repo_name = form_data['repo_name']
386 repo_name = form_data['repo_name']
385 repos_path = get_repos_path()
387 repos_path = get_repos_path()
386 repo_path = os.path.join(repos_path, repo_name)
388 repo_path = os.path.join(repos_path, repo_name)
387 repo_fork_path = os.path.join(repos_path, form_data['fork_name'])
389 repo_fork_path = os.path.join(repos_path, form_data['fork_name'])
388 alias = form_data['repo_type']
390 alias = form_data['repo_type']
389
391
390 log.info('creating repo fork %s as %s', repo_name, repo_path)
392 log.info('creating repo fork %s as %s', repo_name, repo_path)
391 backend = get_backend(alias)
393 backend = get_backend(alias)
392 backend(str(repo_fork_path), create=True, src_url=str(repo_path))
394 backend(str(repo_fork_path), create=True, src_url=str(repo_path))
393
395
394
396
395 def __get_codes_stats(repo_name):
397 def __get_codes_stats(repo_name):
396 repos_path = get_repos_path()
398 repos_path = get_repos_path()
397 repo = get_repo(safe_str(os.path.join(repos_path, repo_name)))
399 repo = get_repo(safe_str(os.path.join(repos_path, repo_name)))
398 tip = repo.get_changeset()
400 tip = repo.get_changeset()
399 code_stats = {}
401 code_stats = {}
400
402
401 def aggregate(cs):
403 def aggregate(cs):
402 for f in cs[2]:
404 for f in cs[2]:
403 ext = lower(f.extension)
405 ext = lower(f.extension)
404 if ext in LANGUAGES_EXTENSIONS_MAP.keys() and not f.is_binary:
406 if ext in LANGUAGES_EXTENSIONS_MAP.keys() and not f.is_binary:
405 if ext in code_stats:
407 if ext in code_stats:
406 code_stats[ext] += 1
408 code_stats[ext] += 1
407 else:
409 else:
408 code_stats[ext] = 1
410 code_stats[ext] = 1
409
411
410 map(aggregate, tip.walk('/'))
412 map(aggregate, tip.walk('/'))
411
413
412 return code_stats or {}
414 return code_stats or {}
General Comments 0
You need to be logged in to leave comments. Login now