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 = |
|
53 | self.feed_nr = 20 | |
53 |
|
54 | |||
54 | def _get_title(self, cs): |
|
55 | def _get_title(self, cs): | |
55 |
return " |
|
56 | return "%s" % ( | |
56 |
|
|
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 |
|
|
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( |
|
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( |
|
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=' |
|
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 |
|
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