Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1284)

Side by Side Diff: chrome/common/extensions/docs/server2/server_instance.py

Issue 13470005: Refactor the devserver to make it easier to control caching (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: cduvall, rebase Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 from fnmatch import fnmatch 5 from fnmatch import fnmatch
6 import mimetypes 6 import mimetypes
7 import os 7 import os
8 8
9 from api_data_source import APIDataSource
10 from api_list_data_source import APIListDataSource
11 from appengine_blobstore import AppEngineBlobstore
12 from appengine_url_fetcher import AppEngineUrlFetcher
13 from branch_utility import BranchUtility
14 from compiled_file_system import CompiledFileSystem
15 from example_zipper import ExampleZipper
9 from file_system import FileNotFoundError 16 from file_system import FileNotFoundError
10 import compiled_file_system as compiled_fs 17 from github_file_system import GithubFileSystem
11 18 from in_memory_object_store import InMemoryObjectStore
12 STATIC_DIR_PREFIX = 'docs' 19 from intro_data_source import IntroDataSource
13 DOCS_PATH = 'docs' 20 from local_file_system import LocalFileSystem
21 from caching_file_system import CachingFileSystem
22 from object_store_creator import ObjectStoreCreator
23 from path_canonicalizer import PathCanonicalizer
24 from reference_resolver import ReferenceResolver
25 from samples_data_source import SamplesDataSource
26 from sidenav_data_source import SidenavDataSource
27 from subversion_file_system import SubversionFileSystem
28 import svn_constants
29 from template_data_source import TemplateDataSource
30 from third_party.json_schema_compiler.model import UnixName
31 import url_constants
14 32
15 def _IsBinaryMimetype(mimetype): 33 def _IsBinaryMimetype(mimetype):
16 return any(mimetype.startswith(prefix) 34 return any(mimetype.startswith(prefix)
17 for prefix in ['audio', 'image', 'video']) 35 for prefix in ['audio', 'image', 'video'])
18 36
19 class ServerInstance(object): 37 class ServerInstance(object):
20 """This class is used to hold a data source and fetcher for an instance of a 38 '''Per-instance per-branch state.
21 server. Each new branch will get its own ServerInstance. 39 '''
22 """ 40 _instances = {}
23 def __init__(self, 41
24 template_data_source_factory, 42 branch_utility = None
25 example_zipper, 43 github_file_system = None
26 cache_factory): 44
27 self._template_data_source_factory = template_data_source_factory 45 @staticmethod
28 self._example_zipper = example_zipper 46 def GetOrCreate(channel):
29 self._cache = cache_factory.Create(lambda _, x: x, compiled_fs.STATIC) 47 # Lazily create so that we don't do unnecessary work in tests.
48 if ServerInstance.branch_utility is None:
49 ServerInstance.branch_utility = BranchUtility(
50 url_constants.OMAHA_PROXY_URL, AppEngineUrlFetcher())
51 branch = ServerInstance.branch_utility.GetBranchNumberForChannelName(
52 channel)
53
54 # Use the branch as the key to |_instances| since the branch data is
55 # predictable while the channel data (channels can swich branches) isn't.
56 instance = ServerInstance._instances.get(branch)
57 if instance is None:
58 instance = ServerInstance._CreateForProduction(channel, branch)
59 ServerInstance._instances[branch] = instance
60 return instance
61
62 @staticmethod
63 def _CreateForProduction(channel, branch):
64 if branch == 'trunk':
65 svn_url = '/'.join((url_constants.SVN_TRUNK_URL,
66 'src',
67 svn_constants.EXTENSIONS_PATH))
68 else:
69 svn_url = '/'.join((url_constants.SVN_BRANCH_URL,
70 branch,
71 'src',
72 svn_constants.EXTENSIONS_PATH))
73
74 viewvc_url = svn_url.replace(url_constants.SVN_URL,
75 url_constants.VIEWVC_URL)
76
77 svn_file_system = CachingFileSystem(
78 SubversionFileSystem(AppEngineUrlFetcher(svn_url),
79 AppEngineUrlFetcher(viewvc_url)))
80
81 # Lazily create so we don't create github file systems unnecessarily in
82 # tests.
83 if ServerInstance.github_file_system is None:
84 ServerInstance.github_file_system = GithubFileSystem(
85 AppEngineUrlFetcher(url_constants.GITHUB_URL),
86 AppEngineBlobstore())
87
88 return ServerInstance(channel,
89 svn_file_system,
90 ServerInstance.github_file_system)
91
92 @staticmethod
93 def CreateForTest(file_system):
94 return ServerInstance('test', file_system, None)
95
96 def __init__(self, channel, svn_file_system, github_file_system):
97 self.svn_file_system = svn_file_system
98
99 self.github_file_system = github_file_system
100
101 self.compiled_fs_factory = CompiledFileSystem.Factory(svn_file_system)
102
103 self.api_list_data_source_factory = APIListDataSource.Factory(
104 self.compiled_fs_factory,
105 svn_constants.API_PATH,
106 svn_constants.PUBLIC_TEMPLATE_PATH)
107
108 self.api_data_source_factory = APIDataSource.Factory(
109 self.compiled_fs_factory,
110 svn_constants.API_PATH)
111
112 self.ref_resolver_factory = ReferenceResolver.Factory(
113 self.api_data_source_factory,
114 self.api_list_data_source_factory)
115
116 self.api_data_source_factory.SetReferenceResolverFactory(
117 self.ref_resolver_factory)
118
119 self.samples_data_source_factory = SamplesDataSource.Factory(
120 channel,
121 self.svn_file_system,
122 ServerInstance.github_file_system,
123 self.ref_resolver_factory,
124 svn_constants.EXAMPLES_PATH)
125
126 self.api_data_source_factory.SetSamplesDataSourceFactory(
127 self.samples_data_source_factory)
128
129 self.intro_data_source_factory = IntroDataSource.Factory(
130 self.compiled_fs_factory,
131 self.ref_resolver_factory,
132 [svn_constants.INTRO_PATH, svn_constants.ARTICLE_PATH])
133
134 self.sidenav_data_source_factory = SidenavDataSource.Factory(
135 self.compiled_fs_factory,
136 svn_constants.JSON_PATH)
137
138 self.template_data_source_factory = TemplateDataSource.Factory(
139 channel,
140 self.api_data_source_factory,
141 self.api_list_data_source_factory,
142 self.intro_data_source_factory,
143 self.samples_data_source_factory,
144 self.sidenav_data_source_factory,
145 self.compiled_fs_factory,
146 self.ref_resolver_factory,
147 svn_constants.PUBLIC_TEMPLATE_PATH,
148 svn_constants.PRIVATE_TEMPLATE_PATH)
149
150 self.example_zipper = ExampleZipper(
151 self.svn_file_system,
152 self.compiled_fs_factory,
153 svn_constants.DOCS_PATH)
154
155 self.path_canonicalizer = PathCanonicalizer(
156 channel,
157 self.compiled_fs_factory)
158
159 self.content_cache = self.compiled_fs_factory.GetOrCreateIdentity()
30 160
31 def _FetchStaticResource(self, path, response): 161 def _FetchStaticResource(self, path, response):
32 """Fetch a resource in the 'static' directory. 162 """Fetch a resource in the 'static' directory.
33 """ 163 """
34 mimetype = mimetypes.guess_type(path)[0] or 'text/plain' 164 mimetype = mimetypes.guess_type(path)[0] or 'text/plain'
35 try: 165 try:
36 result = self._cache.GetFromFile(STATIC_DIR_PREFIX + '/' + path, 166 result = self.content_cache.GetFromFile(
37 binary=_IsBinaryMimetype(mimetype)) 167 svn_constants.DOCS_PATH + '/' + path,
168 binary=_IsBinaryMimetype(mimetype))
38 except FileNotFoundError: 169 except FileNotFoundError:
39 return None 170 return None
40 response.headers['content-type'] = mimetype 171 response.headers['content-type'] = mimetype
41 return result 172 return result
42 173
43 def Get(self, path, request, response): 174 def Get(self, path, request, response):
44 # TODO(cduvall): bundle up all the request-scoped data into a single object. 175 templates = self.template_data_source_factory.Create(request, path)
45 templates = self._template_data_source_factory.Create(request, path) 176
177 if path.rsplit('/', 1)[-1] in ('favicon.ico', 'robots.txt'):
178 response.set_status(404)
179 response.out.write(templates.Render('404'))
180 return
46 181
47 content = None 182 content = None
48 if fnmatch(path, 'extensions/examples/*.zip'): 183 if fnmatch(path, 'extensions/examples/*.zip'):
49 try: 184 try:
50 content = self._example_zipper.Create( 185 content = self.example_zipper.Create(
51 path[len('extensions/'):-len('.zip')]) 186 path[len('extensions/'):-len('.zip')])
52 response.headers['content-type'] = 'application/zip' 187 response.headers['content-type'] = 'application/zip'
53 except FileNotFoundError: 188 except FileNotFoundError:
54 content = None 189 content = None
55 elif path.startswith('extensions/examples/'): 190 elif path.startswith('extensions/examples/'):
56 mimetype = mimetypes.guess_type(path)[0] or 'text/plain' 191 mimetype = mimetypes.guess_type(path)[0] or 'text/plain'
57 try: 192 try:
58 content = self._cache.GetFromFile( 193 content = self.content_cache.GetFromFile(
59 '%s/%s' % (DOCS_PATH, path[len('extensions/'):]), 194 '%s/%s' % (svn_constants.DOCS_PATH, path[len('extensions/'):]),
60 binary=_IsBinaryMimetype(mimetype)) 195 binary=_IsBinaryMimetype(mimetype))
61 response.headers['content-type'] = 'text/plain' 196 response.headers['content-type'] = 'text/plain'
62 except FileNotFoundError: 197 except FileNotFoundError:
63 content = None 198 content = None
64 elif path.startswith('static/'): 199 elif path.startswith('static/'):
65 content = self._FetchStaticResource(path, response) 200 content = self._FetchStaticResource(path, response)
66 elif path.endswith('.html'): 201 elif path.endswith('.html'):
67 content = templates.Render(path) 202 content = templates.Render(path)
68 203
69 response.headers['x-frame-options'] = 'sameorigin' 204 response.headers['x-frame-options'] = 'sameorigin'
70 if content: 205 if content:
71 response.headers['cache-control'] = 'max-age=300' 206 response.headers['cache-control'] = 'max-age=300'
72 response.out.write(content) 207 response.out.write(content)
73 else: 208 else:
74 response.set_status(404); 209 response.set_status(404);
75 response.out.write(templates.Render('404')) 210 response.out.write(templates.Render('404'))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698