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.
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.
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.
41 supports_templates
=False,
45 self
.file_system
= file_system
47 self
._content
_cache
= compiled_fs_factory
.Create(file_system
,
50 self
._supports
_templates
= supports_templates
52 self
._directory
_zipper
= DirectoryZipper(compiled_fs_factory
, file_system
)
54 self
._directory
_zipper
= None
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:
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
)
80 return ContentAndType(content
, mimetype
)
82 def _MaybeMarkdown(self
, path
):
83 if posixpath
.splitext(path
)[1] != '.html':
86 dirname
, file_name
= posixpath
.split(path
)
88 dirname
= dirname
+ '/'
89 file_list
= self
.file_system
.ReadSingle(dirname
).Get()
90 if file_name
in file_list
:
93 if posixpath
.splitext(file_name
)[0] + '.md' in file_list
:
94 return posixpath
.splitext(path
)[0] + '.md'
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
))
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
113 # TODO(kalman): Walk over the whole filesystem and compile the content.
114 return self
.file_system
.Refresh()
117 return 'ContentProvider of <%s>' % repr(self
.file_system
)