##// END OF EJS Templates
readme/markup: improved order of generating readme files. Fixes #4050...
marcink -
r396:2ba4c171 default
parent child Browse files
Show More
@@ -30,36 +30,6 b' from rhodecode.lib.utils2 import __get_l'
30 # extensions will index it's content
30 # extensions will index it's content
31 LANGUAGES_EXTENSIONS_MAP = __get_lem()
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 DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
33 DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
64
34
65 DATE_FORMAT = "%Y-%m-%d"
35 DATE_FORMAT = "%Y-%m-%d"
@@ -24,14 +24,12 b' Summary controller for RhodeCode Enterpr'
24
24
25 import logging
25 import logging
26 from string import lower
26 from string import lower
27 from itertools import product
28
27
29 from pylons import tmpl_context as c, request
28 from pylons import tmpl_context as c, request
30 from pylons.i18n.translation import _
29 from pylons.i18n.translation import _
31 from beaker.cache import cache_region, region_invalidate
30 from beaker.cache import cache_region, region_invalidate
32
31
33 from rhodecode.config.conf import (
32 from rhodecode.config.conf import (LANGUAGES_EXTENSIONS_MAP)
34 ALL_READMES, ALL_EXTS, LANGUAGES_EXTENSIONS_MAP)
35 from rhodecode.controllers import utils
33 from rhodecode.controllers import utils
36 from rhodecode.controllers.changelog import _load_changelog_summary
34 from rhodecode.controllers.changelog import _load_changelog_summary
37 from rhodecode.lib import caches, helpers as h
35 from rhodecode.lib import caches, helpers as h
@@ -49,10 +47,6 b' from rhodecode.model.db import Statistic'
49
47
50 log = logging.getLogger(__name__)
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 class SummaryController(BaseRepoController):
51 class SummaryController(BaseRepoController):
58
52
@@ -62,6 +56,7 b' class SummaryController(BaseRepoControll'
62 def __get_readme_data(self, db_repo):
56 def __get_readme_data(self, db_repo):
63 repo_name = db_repo.repo_name
57 repo_name = db_repo.repo_name
64 log.debug('Looking for README file')
58 log.debug('Looking for README file')
59 default_renderer = c.visual.default_renderer
65
60
66 @cache_region('long_term')
61 @cache_region('long_term')
67 def _generate_readme(cache_key):
62 def _generate_readme(cache_key):
@@ -73,7 +68,7 b' class SummaryController(BaseRepoControll'
73 if isinstance(commit, EmptyCommit):
68 if isinstance(commit, EmptyCommit):
74 raise EmptyRepositoryError()
69 raise EmptyRepositoryError()
75 renderer = MarkupRenderer()
70 renderer = MarkupRenderer()
76 for f in README_FILES:
71 for f in renderer.pick_readme_order(default_renderer):
77 try:
72 try:
78 node = commit.get_node(f)
73 node = commit.get_node(f)
79 except NodeDoesNotExistError:
74 except NodeDoesNotExistError:
@@ -1726,17 +1726,7 b' def markdown(source, mentions=False):'
1726 mentions=mentions))
1726 mentions=mentions))
1727
1727
1728 def renderer_from_filename(filename, exclude=None):
1728 def renderer_from_filename(filename, exclude=None):
1729 from rhodecode.config.conf import MARKDOWN_EXTS, RST_EXTS
1729 return MarkupRenderer.renderer_from_filename(filename, exclude=exclude)
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'
1740
1730
1741
1731
1742 def render(source, renderer='rst', mentions=False):
1732 def render(source, renderer='rst', mentions=False):
@@ -23,10 +23,11 b''
23 Renderer for markup languages with ability to parse using rst or markdown
23 Renderer for markup languages with ability to parse using rst or markdown
24 """
24 """
25
25
26
27 import re
26 import re
28 import os
27 import os
29 import logging
28 import logging
29 import itertools
30
30 from mako.lookup import TemplateLookup
31 from mako.lookup import TemplateLookup
31
32
32 from docutils.core import publish_parts
33 from docutils.core import publish_parts
@@ -50,6 +51,37 b' class MarkupRenderer(object):'
50 RST_PAT = re.compile(r'\.re?st$', re.IGNORECASE)
51 RST_PAT = re.compile(r'\.re?st$', re.IGNORECASE)
51 PLAIN_PAT = re.compile(r'^readme$', re.IGNORECASE)
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 def _detect_renderer(self, source, filename=None):
85 def _detect_renderer(self, source, filename=None):
54 """
86 """
55 runs detection of what renderer should be used for generating html
87 runs detection of what renderer should be used for generating html
@@ -72,6 +104,48 b' class MarkupRenderer(object):'
72
104
73 return getattr(MarkupRenderer, detected_renderer)
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 def render(self, source, filename=None):
149 def render(self, source, filename=None):
76 """
150 """
77 Renders a given filename using detected renderer
151 Renders a given filename using detected renderer
@@ -177,3 +177,37 b' Auto status change to |new_status|'
177 renderer = RstTemplateRenderer()
177 renderer = RstTemplateRenderer()
178 rendered = renderer.render('auto_status_change.mako', **params)
178 rendered = renderer.render('auto_status_change.mako', **params)
179 assert expected == rendered
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