##// END OF EJS Templates
Improved RSS/ATOM feeds...
marcink -
r2385:a455b2c7 beta
parent child Browse files
Show More
@@ -544,6 +544,15 b' class ApiController(JSONRPCController):'
544 raise JSONRPCError('failed to create repository %s' % repo_name)
544 raise JSONRPCError('failed to create repository %s' % repo_name)
545
545
546 @HasPermissionAnyDecorator('hg.admin')
546 @HasPermissionAnyDecorator('hg.admin')
547 def fork_repo(self, apiuser, repoid):
548 repo = RepoModel().get_repo(repoid)
549 if repo is None:
550 raise JSONRPCError('unknown repository "%s"' % (repo or repoid))
551
552 RepoModel().create_fork(form_data, cur_user)
553
554
555 @HasPermissionAnyDecorator('hg.admin')
547 def delete_repo(self, apiuser, repo_name):
556 def delete_repo(self, apiuser, repo_name):
548 """
557 """
549 Deletes a given repository
558 Deletes a given repository
@@ -28,11 +28,12 b' import logging'
28 from pylons import url, response, tmpl_context as c
28 from pylons import url, response, tmpl_context as c
29 from pylons.i18n.translation import _
29 from pylons.i18n.translation import _
30
30
31 from rhodecode.lib.utils2 import safe_unicode
31 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
32
33 from rhodecode.lib import helpers as h
32 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
34 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
33 from rhodecode.lib.base import BaseRepoController
35 from rhodecode.lib.base import BaseRepoController
34
36 from rhodecode.lib.diffs import DiffProcessor
35 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
36
37
37 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
38
39
@@ -49,31 +50,36 b' class FeedController(BaseRepoController)'
49 self.title = self.title = _('%s %s feed') % (c.rhodecode_name, '%s')
50 self.title = self.title = _('%s %s feed') % (c.rhodecode_name, '%s')
50 self.language = 'en-us'
51 self.language = 'en-us'
51 self.ttl = "5"
52 self.ttl = "5"
52 self.feed_nr = 10
53 self.feed_nr = 20
53
54
54 def _get_title(self, cs):
55 def _get_title(self, cs):
55 return "R%s:%s - %s" % (
56 return "%s" % (
56 cs.revision, cs.short_id, cs.message
57 h.shorter(cs.message, 160)
57 )
58 )
58
59
59 def __changes(self, cs):
60 def __changes(self, cs):
60 changes = []
61 changes = []
61
62
62 a = [safe_unicode(n.path) for n in cs.added]
63 diffprocessor = DiffProcessor(cs.diff())
63 if a:
64 stats = diffprocessor.prepare(inline_diff=False)
64 changes.append('\nA ' + '\nA '.join(a))
65 for st in stats:
65
66 st.update({'added': st['stats'][0],
66 m = [safe_unicode(n.path) for n in cs.changed]
67 'removed': st['stats'][1]})
67 if m:
68 changes.append('\n %(operation)s %(filename)s '
68 changes.append('\nM ' + '\nM '.join(m))
69 '(%(added)s lines added, %(removed)s lines removed)'
70 % st)
71 return changes
69
72
70 d = [safe_unicode(n.path) for n in cs.removed]
73 def __get_desc(self, cs):
71 if d:
74 desc_msg = []
72 changes.append('\nD ' + '\nD '.join(d))
75 desc_msg.append('%s %s %s:<br/>' % (cs.author, _('commited on'),
73
76 cs.date))
74 changes.append('</pre>')
77 desc_msg.append('<pre>')
75
78 desc_msg.append(cs.message)
76 return ''.join(changes)
79 desc_msg.append('\n')
80 desc_msg.extend(self.__changes(cs))
81 desc_msg.append('</pre>')
82 return desc_msg
77
83
78 def atom(self, repo_name):
84 def atom(self, repo_name):
79 """Produce an atom-1.0 feed via feedgenerator module"""
85 """Produce an atom-1.0 feed via feedgenerator module"""
@@ -87,15 +93,13 b' class FeedController(BaseRepoController)'
87 )
93 )
88
94
89 for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
95 for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
90 desc_msg = []
91 desc_msg.append('%s - %s<br/><pre>' % (cs.author, cs.date))
92 desc_msg.append(self.__changes(cs))
93
94 feed.add_item(title=self._get_title(cs),
96 feed.add_item(title=self._get_title(cs),
95 link=url('changeset_home', repo_name=repo_name,
97 link=url('changeset_home', repo_name=repo_name,
96 revision=cs.raw_id, qualified=True),
98 revision=cs.raw_id, qualified=True),
97 author_name=cs.author,
99 author_name=cs.author,
98 description=''.join(desc_msg))
100 description=''.join(self.__get_desc(cs)),
101 pubdate=cs.date,
102 )
99
103
100 response.content_type = feed.mime_type
104 response.content_type = feed.mime_type
101 return feed.writeString('utf-8')
105 return feed.writeString('utf-8')
@@ -112,15 +116,12 b' class FeedController(BaseRepoController)'
112 )
116 )
113
117
114 for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
118 for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
115 desc_msg = []
116 desc_msg.append('%s - %s<br/><pre>' % (cs.author, cs.date))
117 desc_msg.append(self.__changes(cs))
118
119 feed.add_item(title=self._get_title(cs),
119 feed.add_item(title=self._get_title(cs),
120 link=url('changeset_home', repo_name=repo_name,
120 link=url('changeset_home', repo_name=repo_name,
121 revision=cs.raw_id, qualified=True),
121 revision=cs.raw_id, qualified=True),
122 author_name=cs.author,
122 author_name=cs.author,
123 description=''.join(desc_msg),
123 description=''.join(self.__get_desc(cs)),
124 pubdate=cs.date,
124 )
125 )
125
126
126 response.content_type = feed.mime_type
127 response.content_type = feed.mime_type
@@ -128,7 +128,7 b' class DiffProcessor(object):'
128 """
128 """
129 _chunk_re = re.compile(r'@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)')
129 _chunk_re = re.compile(r'@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)')
130
130
131 def __init__(self, diff, differ='diff', format='udiff'):
131 def __init__(self, diff, differ='diff', format='gitdiff'):
132 """
132 """
133 :param diff: a text in diff format or generator
133 :param diff: a text in diff format or generator
134 :param format: format of diff passed, `udiff` or `gitdiff`
134 :param format: format of diff passed, `udiff` or `gitdiff`
@@ -171,7 +171,7 b' class DiffProcessor(object):'
171
171
172 def _extract_rev(self, line1, line2):
172 def _extract_rev(self, line1, line2):
173 """
173 """
174 Extract the filename and revision hint from a line.
174 Extract the operation (A/M/D), filename and revision hint from a line.
175 """
175 """
176
176
177 try:
177 try:
@@ -189,11 +189,15 b' class DiffProcessor(object):'
189 filename = (old_filename
189 filename = (old_filename
190 if old_filename != '/dev/null' else new_filename)
190 if old_filename != '/dev/null' else new_filename)
191
191
192 return filename, new_rev, old_rev
192 operation = 'D' if new_filename == '/dev/null' else None
193 if not operation:
194 operation = 'M' if old_filename != '/dev/null' else 'A'
195
196 return operation, filename, new_rev, old_rev
193 except (ValueError, IndexError):
197 except (ValueError, IndexError):
194 pass
198 pass
195
199
196 return None, None, None
200 return None, None, None, None
197
201
198 def _parse_gitdiff(self, diffiterator):
202 def _parse_gitdiff(self, diffiterator):
199 def line_decoder(l):
203 def line_decoder(l):
@@ -278,7 +282,7 b' class DiffProcessor(object):'
278 do(line)
282 do(line)
279 do(next_)
283 do(next_)
280
284
281 def _parse_udiff(self):
285 def _parse_udiff(self, inline_diff=True):
282 """
286 """
283 Parse the diff an return data for the template.
287 Parse the diff an return data for the template.
284 """
288 """
@@ -293,13 +297,16 b' class DiffProcessor(object):'
293 continue
297 continue
294
298
295 chunks = []
299 chunks = []
296 filename, old_rev, new_rev = \
300 stats = [0, 0]
301 operation, filename, old_rev, new_rev = \
297 self._extract_rev(line, lineiter.next())
302 self._extract_rev(line, lineiter.next())
298 files.append({
303 files.append({
299 'filename': filename,
304 'filename': filename,
300 'old_revision': old_rev,
305 'old_revision': old_rev,
301 'new_revision': new_rev,
306 'new_revision': new_rev,
302 'chunks': chunks
307 'chunks': chunks,
308 'operation': operation,
309 'stats': stats,
303 })
310 })
304
311
305 line = lineiter.next()
312 line = lineiter.next()
@@ -331,7 +338,6 b' class DiffProcessor(object):'
331 })
338 })
332
339
333 line = lineiter.next()
340 line = lineiter.next()
334
335 while old_line < old_end or new_line < new_end:
341 while old_line < old_end or new_line < new_end:
336 if line:
342 if line:
337 command, line = line[0], line[1:]
343 command, line = line[0], line[1:]
@@ -345,9 +351,11 b' class DiffProcessor(object):'
345 elif command == '+':
351 elif command == '+':
346 affects_new = True
352 affects_new = True
347 action = 'add'
353 action = 'add'
354 stats[0] += 1
348 elif command == '-':
355 elif command == '-':
349 affects_old = True
356 affects_old = True
350 action = 'del'
357 action = 'del'
358 stats[1] += 1
351 else:
359 else:
352 affects_old = affects_new = True
360 affects_old = affects_new = True
353 action = 'unmod'
361 action = 'unmod'
@@ -371,13 +379,16 b' class DiffProcessor(object):'
371 })
379 })
372
380
373 line = lineiter.next()
381 line = lineiter.next()
374
375 except StopIteration:
382 except StopIteration:
376 pass
383 pass
377
384
385 sorter = lambda info: {'A': 0, 'M': 1, 'D': 2}.get(info['operation'])
386 if inline_diff is False:
387 return sorted(files, key=sorter)
388
378 # highlight inline changes
389 # highlight inline changes
379 for _ in files:
390 for diff_data in files:
380 for chunk in chunks:
391 for chunk in diff_data['chunks']:
381 lineiter = iter(chunk)
392 lineiter = iter(chunk)
382 try:
393 try:
383 while 1:
394 while 1:
@@ -391,14 +402,14 b' class DiffProcessor(object):'
391 except StopIteration:
402 except StopIteration:
392 pass
403 pass
393
404
394 return files
405 return sorted(files, key=sorter)
395
406
396 def prepare(self):
407 def prepare(self, inline_diff=True):
397 """
408 """
398 Prepare the passed udiff for HTML rendering. It'l return a list
409 Prepare the passed udiff for HTML rendering. It'l return a list
399 of dicts
410 of dicts
400 """
411 """
401 return self._parse_udiff()
412 return self._parse_udiff(inline_diff=inline_diff)
402
413
403 def _safe_id(self, idstring):
414 def _safe_id(self, idstring):
404 """Make a string safe for including in an id attribute.
415 """Make a string safe for including in an id attribute.
@@ -432,7 +443,7 b' class DiffProcessor(object):'
432
443
433 def as_html(self, table_class='code-difftable', line_class='line',
444 def as_html(self, table_class='code-difftable', line_class='line',
434 new_lineno_class='lineno old', old_lineno_class='lineno new',
445 new_lineno_class='lineno old', old_lineno_class='lineno new',
435 code_class='code', enable_comments=False):
446 code_class='code', enable_comments=False, diff_lines=None):
436 """
447 """
437 Return udiff as html table with customized css classes
448 Return udiff as html table with customized css classes
438 """
449 """
@@ -448,7 +459,8 b' class DiffProcessor(object):'
448 }
459 }
449 else:
460 else:
450 return label
461 return label
451 diff_lines = self.prepare()
462 if diff_lines is None:
463 diff_lines = self.prepare()
452 _html_empty = True
464 _html_empty = True
453 _html = []
465 _html = []
454 _html.append('''<table class="%(table_class)s">\n''' % {
466 _html.append('''<table class="%(table_class)s">\n''' % {
General Comments 0
You need to be logged in to leave comments. Login now