Show More
@@ -30,36 +30,6 b' from rhodecode.lib.utils2 import __get_l' | |||
|
30 | 30 | # extensions will index it's content |
|
31 | 31 | LANGUAGES_EXTENSIONS_MAP = __get_lem() |
|
32 | 32 | |
|
33 | # list of readme files to search in file tree and display in summary | |
|
34 | # attached weights defines the search order lower is first | |
|
35 | ALL_READMES = [ | |
|
36 | ('readme', 0), ('README', 0), ('Readme', 0), | |
|
37 | ('doc/readme', 1), ('doc/README', 1), ('doc/Readme', 1), | |
|
38 | ('Docs/readme', 2), ('Docs/README', 2), ('Docs/Readme', 2), | |
|
39 | ('DOCS/readme', 2), ('DOCS/README', 2), ('DOCS/Readme', 2), | |
|
40 | ('docs/readme', 2), ('docs/README', 2), ('docs/Readme', 2), | |
|
41 | ] | |
|
42 | ||
|
43 | # extension together with weights to search lower is first | |
|
44 | RST_EXTS = [ | |
|
45 | ('', 0), ('.rst', 1), ('.rest', 1), | |
|
46 | ('.RST', 2), ('.REST', 2) | |
|
47 | ] | |
|
48 | ||
|
49 | MARKDOWN_EXTS = [ | |
|
50 | ('.md', 1), ('.MD', 1), | |
|
51 | ('.mkdn', 2), ('.MKDN', 2), | |
|
52 | ('.mdown', 3), ('.MDOWN', 3), | |
|
53 | ('.markdown', 4), ('.MARKDOWN', 4) | |
|
54 | ] | |
|
55 | ||
|
56 | PLAIN_EXTS = [ | |
|
57 | ('.text', 2), ('.TEXT', 2), | |
|
58 | ('.txt', 3), ('.TXT', 3) | |
|
59 | ] | |
|
60 | ||
|
61 | ALL_EXTS = MARKDOWN_EXTS + RST_EXTS + PLAIN_EXTS | |
|
62 | ||
|
63 | 33 | DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S" |
|
64 | 34 | |
|
65 | 35 | DATE_FORMAT = "%Y-%m-%d" |
@@ -24,14 +24,12 b' Summary controller for RhodeCode Enterpr' | |||
|
24 | 24 | |
|
25 | 25 | import logging |
|
26 | 26 | from string import lower |
|
27 | from itertools import product | |
|
28 | 27 | |
|
29 | 28 | from pylons import tmpl_context as c, request |
|
30 | 29 | from pylons.i18n.translation import _ |
|
31 | 30 | from beaker.cache import cache_region, region_invalidate |
|
32 | 31 | |
|
33 | from rhodecode.config.conf import ( | |
|
34 | ALL_READMES, ALL_EXTS, LANGUAGES_EXTENSIONS_MAP) | |
|
32 | from rhodecode.config.conf import (LANGUAGES_EXTENSIONS_MAP) | |
|
35 | 33 | from rhodecode.controllers import utils |
|
36 | 34 | from rhodecode.controllers.changelog import _load_changelog_summary |
|
37 | 35 | from rhodecode.lib import caches, helpers as h |
@@ -49,10 +47,6 b' from rhodecode.model.db import Statistic' | |||
|
49 | 47 | |
|
50 | 48 | log = logging.getLogger(__name__) |
|
51 | 49 | |
|
52 | README_FILES = [''.join([x[0][0], x[1][0]]) | |
|
53 | for x in sorted(list(product(ALL_READMES, ALL_EXTS)), | |
|
54 | key=lambda y:y[0][1] + y[1][1])] | |
|
55 | ||
|
56 | 50 | |
|
57 | 51 | class SummaryController(BaseRepoController): |
|
58 | 52 | |
@@ -62,6 +56,7 b' class SummaryController(BaseRepoControll' | |||
|
62 | 56 | def __get_readme_data(self, db_repo): |
|
63 | 57 | repo_name = db_repo.repo_name |
|
64 | 58 | log.debug('Looking for README file') |
|
59 | default_renderer = c.visual.default_renderer | |
|
65 | 60 | |
|
66 | 61 | @cache_region('long_term') |
|
67 | 62 | def _generate_readme(cache_key): |
@@ -73,7 +68,7 b' class SummaryController(BaseRepoControll' | |||
|
73 | 68 | if isinstance(commit, EmptyCommit): |
|
74 | 69 | raise EmptyRepositoryError() |
|
75 | 70 | renderer = MarkupRenderer() |
|
76 | for f in README_FILES: | |
|
71 | for f in renderer.pick_readme_order(default_renderer): | |
|
77 | 72 | try: |
|
78 | 73 | node = commit.get_node(f) |
|
79 | 74 | except NodeDoesNotExistError: |
@@ -1726,17 +1726,7 b' def markdown(source, mentions=False):' | |||
|
1726 | 1726 | mentions=mentions)) |
|
1727 | 1727 | |
|
1728 | 1728 | def renderer_from_filename(filename, exclude=None): |
|
1729 | from rhodecode.config.conf import MARKDOWN_EXTS, RST_EXTS | |
|
1730 | ||
|
1731 | def _filter(elements): | |
|
1732 | if isinstance(exclude, (list, tuple)): | |
|
1733 | return [x for x in elements if x not in exclude] | |
|
1734 | return elements | |
|
1735 | ||
|
1736 | if filename.endswith(tuple(_filter([x[0] for x in MARKDOWN_EXTS if x[0]]))): | |
|
1737 | return 'markdown' | |
|
1738 | if filename.endswith(tuple(_filter([x[0] for x in RST_EXTS if x[0]]))): | |
|
1739 | return 'rst' | |
|
1729 | return MarkupRenderer.renderer_from_filename(filename, exclude=exclude) | |
|
1740 | 1730 | |
|
1741 | 1731 | |
|
1742 | 1732 | def render(source, renderer='rst', mentions=False): |
@@ -23,10 +23,11 b'' | |||
|
23 | 23 | Renderer for markup languages with ability to parse using rst or markdown |
|
24 | 24 | """ |
|
25 | 25 | |
|
26 | ||
|
27 | 26 | import re |
|
28 | 27 | import os |
|
29 | 28 | import logging |
|
29 | import itertools | |
|
30 | ||
|
30 | 31 | from mako.lookup import TemplateLookup |
|
31 | 32 | |
|
32 | 33 | from docutils.core import publish_parts |
@@ -50,6 +51,37 b' class MarkupRenderer(object):' | |||
|
50 | 51 | RST_PAT = re.compile(r'\.re?st$', re.IGNORECASE) |
|
51 | 52 | PLAIN_PAT = re.compile(r'^readme$', re.IGNORECASE) |
|
52 | 53 | |
|
54 | # list of readme files to search in file tree and display in summary | |
|
55 | # attached weights defines the search order lower is first | |
|
56 | ALL_READMES = [ | |
|
57 | ('readme', 0), ('README', 0), ('Readme', 0), | |
|
58 | ('doc/readme', 1), ('doc/README', 1), ('doc/Readme', 1), | |
|
59 | ('Docs/readme', 2), ('Docs/README', 2), ('Docs/Readme', 2), | |
|
60 | ('DOCS/readme', 2), ('DOCS/README', 2), ('DOCS/Readme', 2), | |
|
61 | ('docs/readme', 2), ('docs/README', 2), ('docs/Readme', 2), | |
|
62 | ] | |
|
63 | # extension together with weights. Lower is first means we control how | |
|
64 | # extensions are attached to readme names with those. | |
|
65 | PLAIN_EXTS = [ | |
|
66 | ('', 0), # special case that renders READMES names without extension | |
|
67 | ('.text', 2), ('.TEXT', 2), | |
|
68 | ('.txt', 3), ('.TXT', 3) | |
|
69 | ] | |
|
70 | ||
|
71 | RST_EXTS = [ | |
|
72 | ('.rst', 1), ('.rest', 1), | |
|
73 | ('.RST', 2), ('.REST', 2) | |
|
74 | ] | |
|
75 | ||
|
76 | MARKDOWN_EXTS = [ | |
|
77 | ('.md', 1), ('.MD', 1), | |
|
78 | ('.mkdn', 2), ('.MKDN', 2), | |
|
79 | ('.mdown', 3), ('.MDOWN', 3), | |
|
80 | ('.markdown', 4), ('.MARKDOWN', 4) | |
|
81 | ] | |
|
82 | ||
|
83 | ALL_EXTS = PLAIN_EXTS + MARKDOWN_EXTS + RST_EXTS | |
|
84 | ||
|
53 | 85 | def _detect_renderer(self, source, filename=None): |
|
54 | 86 | """ |
|
55 | 87 | runs detection of what renderer should be used for generating html |
@@ -72,6 +104,48 b' class MarkupRenderer(object):' | |||
|
72 | 104 | |
|
73 | 105 | return getattr(MarkupRenderer, detected_renderer) |
|
74 | 106 | |
|
107 | @classmethod | |
|
108 | def renderer_from_filename(cls, filename, exclude): | |
|
109 | """ | |
|
110 | Detect renderer from filename and optionally use exlcude list to | |
|
111 | remove some options. This is mostly used in helpers | |
|
112 | """ | |
|
113 | def _filter(elements): | |
|
114 | if isinstance(exclude, (list, tuple)): | |
|
115 | return [x for x in elements if x not in exclude] | |
|
116 | return elements | |
|
117 | ||
|
118 | if filename.endswith( | |
|
119 | tuple(_filter([x[0] for x in cls.MARKDOWN_EXTS if x[0]]))): | |
|
120 | return 'markdown' | |
|
121 | if filename.endswith(tuple(_filter([x[0] for x in cls.RST_EXTS if x[0]]))): | |
|
122 | return 'rst' | |
|
123 | ||
|
124 | return 'plain' | |
|
125 | ||
|
126 | @classmethod | |
|
127 | def generate_readmes(cls, all_readmes, extensions): | |
|
128 | combined = itertools.product(all_readmes, extensions) | |
|
129 | # sort by filename weight(y[0][1]) + extensions weight(y[1][1]) | |
|
130 | prioritized_readmes = sorted(combined, key=lambda y: y[0][1] + y[1][1]) | |
|
131 | # filename, extension | |
|
132 | return [''.join([x[0][0], x[1][0]]) for x in prioritized_readmes] | |
|
133 | ||
|
134 | def pick_readme_order(self, default_renderer): | |
|
135 | ||
|
136 | if default_renderer == 'markdown': | |
|
137 | markdown = self.generate_readmes(self.ALL_READMES, self.MARKDOWN_EXTS) | |
|
138 | readme_order = markdown + self.generate_readmes( | |
|
139 | self.ALL_READMES, self.RST_EXTS + self.PLAIN_EXTS) | |
|
140 | elif default_renderer == 'rst': | |
|
141 | markdown = self.generate_readmes(self.ALL_READMES, self.RST_EXTS) | |
|
142 | readme_order = markdown + self.generate_readmes( | |
|
143 | self.ALL_READMES, self.MARKDOWN_EXTS + self.PLAIN_EXTS) | |
|
144 | else: | |
|
145 | readme_order = self.generate_readmes(self.ALL_READMES, self.ALL_EXTS) | |
|
146 | ||
|
147 | return readme_order | |
|
148 | ||
|
75 | 149 | def render(self, source, filename=None): |
|
76 | 150 | """ |
|
77 | 151 | Renders a given filename using detected renderer |
@@ -177,3 +177,37 b' Auto status change to |new_status|' | |||
|
177 | 177 | renderer = RstTemplateRenderer() |
|
178 | 178 | rendered = renderer.render('auto_status_change.mako', **params) |
|
179 | 179 | assert expected == rendered |
|
180 | ||
|
181 | ||
|
182 | @pytest.mark.parametrize( | |
|
183 | "readmes, exts, order", | |
|
184 | [ | |
|
185 | ([], [], []), | |
|
186 | ||
|
187 | ([('readme1', 0), ('text1', 1)], [('.ext', 0), ('.txt', 1)], | |
|
188 | ['readme1.ext', 'readme1.txt', 'text1.ext', 'text1.txt']), | |
|
189 | ||
|
190 | ([('readme2', 0), ('text2', 1)], [('.ext', 2), ('.txt', 1)], | |
|
191 | ['readme2.txt', 'readme2.ext', 'text2.txt', 'text2.ext']), | |
|
192 | ||
|
193 | ([('readme3', 0), ('text3', 1)], [('.XXX', 1)], | |
|
194 | ['readme3.XXX', 'text3.XXX']), | |
|
195 | ]) | |
|
196 | def test_generate_readmes(readmes, exts, order): | |
|
197 | assert order == MarkupRenderer.generate_readmes(readmes, exts) | |
|
198 | ||
|
199 | ||
|
200 | @pytest.mark.parametrize( | |
|
201 | "renderer, expected_order", | |
|
202 | [ | |
|
203 | ('plain', ['readme', 'README', 'Readme']), | |
|
204 | ('text', ['readme', 'README', 'Readme']), | |
|
205 | ('markdown', MarkupRenderer.generate_readmes( | |
|
206 | MarkupRenderer.ALL_READMES, MarkupRenderer.MARKDOWN_EXTS)), | |
|
207 | ('rst', MarkupRenderer.generate_readmes( | |
|
208 | MarkupRenderer.ALL_READMES, MarkupRenderer.RST_EXTS)), | |
|
209 | ]) | |
|
210 | def test_order_of_readme_generation(renderer, expected_order): | |
|
211 | mkd_renderer = MarkupRenderer() | |
|
212 | assert expected_order == mkd_renderer.pick_readme_order( | |
|
213 | renderer)[:len(expected_order)] |
General Comments 0
You need to be logged in to leave comments.
Login now