Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / common / extensions / docs / server2 / content_provider.py
blob6c1146549f7c622bc1b175ad260e53e7b3e1ad9c
1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 import mimetypes
6 import posixpath
8 from compiled_file_system import SingleFile
9 from directory_zipper import DirectoryZipper
10 from docs_server_utils import ToUnicode
11 from file_system import FileNotFoundError
12 from future import Gettable, Future
13 from third_party.handlebar import Handlebar
14 from third_party.markdown import markdown
17 class ContentAndType(object):
18 '''Return value from ContentProvider.GetContentAndType.
19 '''
21 def __init__(self, content, content_type):
22 self.content = content
23 self.content_type = content_type
26 class ContentProvider(object):
27 '''Returns file contents correctly typed for their content-types (in the HTTP
28 sense). Content-type is determined from Python's mimetype library which
29 guesses based on the file extension.
31 Typically the file contents will be either str (for binary content) or
32 unicode (for text content). However, HTML files *may* be returned as
33 Handlebar templates (if supports_templates is True on construction), in which
34 case the caller will presumably want to Render them.
35 '''
37 def __init__(self,
38 name,
39 compiled_fs_factory,
40 file_system,
41 supports_templates=False,
42 supports_zip=False):
43 # Public.
44 self.name = name
45 self.file_system = file_system
46 # Private.
47 self._content_cache = compiled_fs_factory.Create(file_system,
48 self._CompileContent,
49 ContentProvider)
50 self._supports_templates = supports_templates
51 if supports_zip:
52 self._directory_zipper = DirectoryZipper(compiled_fs_factory, file_system)
53 else:
54 self._directory_zipper = None
56 @SingleFile
57 def _CompileContent(self, path, text):
58 assert text is not None, path
59 mimetype = mimetypes.guess_type(path)[0]
60 if posixpath.splitext(path)[1] == '.md':
61 # See http://pythonhosted.org/Markdown/extensions
62 # for details on "extensions=".
63 content = markdown(ToUnicode(text),
64 extensions=('extra', 'headerid', 'sane_lists'))
65 if self._supports_templates:
66 content = Handlebar(content, name=path)
67 mimetype = 'text/html'
68 elif mimetype is None:
69 content = text
70 mimetype = 'text/plain'
71 elif mimetype == 'text/html':
72 content = ToUnicode(text)
73 if self._supports_templates:
74 content = Handlebar(content, name=path)
75 elif (mimetype.startswith('text/') or
76 mimetype in ('application/javascript', 'application/json')):
77 content = ToUnicode(text)
78 else:
79 content = text
80 return ContentAndType(content, mimetype)
82 def _MaybeMarkdown(self, path):
83 if posixpath.splitext(path)[1] != '.html':
84 return path
86 dirname, file_name = posixpath.split(path)
87 if dirname != '':
88 dirname = dirname + '/'
89 file_list = self.file_system.ReadSingle(dirname).Get()
90 if file_name in file_list:
91 return path
93 if posixpath.splitext(file_name)[0] + '.md' in file_list:
94 return posixpath.splitext(path)[0] + '.md'
95 return path
97 def GetContentAndType(self, path):
98 path = path.lstrip('/')
99 base, ext = posixpath.splitext(path)
101 # Check for a zip file first, if zip is enabled.
102 if self._directory_zipper and ext == '.zip':
103 zip_future = self._directory_zipper.Zip(base)
104 return Future(delegate=Gettable(
105 lambda: ContentAndType(zip_future.Get(), 'application/zip')))
107 return self._content_cache.GetFromFile(self._MaybeMarkdown(path))
109 def Cron(self):
110 # Running Refresh() on the file system is enough to pull GitHub content,
111 # which is all we need for now while the full render-every-page cron step
112 # is in effect.
113 # TODO(kalman): Walk over the whole filesystem and compile the content.
114 return self.file_system.Refresh()
116 def __repr__(self):
117 return 'ContentProvider of <%s>' % repr(self.file_system)