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

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: cache static files in cron, fix path canonicalizer bug 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 branch_utility = ServerInstance.branch_utility
cduvall 2013/04/08 07:09:24 is it necessary to assign ServerInstance.branch_ut
not at google - send to devlin 2013/04/08 12:21:21 Done. For GithubFileSystem too.
48 if branch_utility is None:
49 branch_utility = BranchUtility(url_constants.OMAHA_PROXY_URL,
50 AppEngineUrlFetcher())
51 ServerInstance.branch_utility = branch_utility
52
53 branch = branch_utility.GetBranchNumberForChannelName(channel)
54
55 # Use the branch as the key to |_instances| since the branch data is
56 # predictable while the channel data (channels can swich branches) isn't.
57 instance = ServerInstance._instances.get(branch)
58 if instance is None:
59 instance = ServerInstance._CreateForProduction(channel, branch)
60 ServerInstance._instances[branch] = instance
61 return instance
62
63 @staticmethod
64 def _CreateForProduction(channel, branch):
65 if branch == 'trunk':
66 svn_url = '/'.join((url_constants.SVN_TRUNK_URL,
67 'src',
68 svn_constants.EXTENSIONS_PATH))
69 else:
70 svn_url = '/'.join((url_constants.SVN_BRANCH_URL,
71 branch,
72 'src',
73 svn_constants.EXTENSIONS_PATH))
74
75 viewvc_url = svn_url.replace(url_constants.SVN_URL,
76 url_constants.VIEWVC_URL)
77
78 svn_file_system = CachingFileSystem(
79 SubversionFileSystem(AppEngineUrlFetcher(svn_url),
80 AppEngineUrlFetcher(viewvc_url)))
81
82 github_file_system = ServerInstance.github_file_system
83 if github_file_system is None:
84 github_file_system = GithubFileSystem(
85 AppEngineUrlFetcher(url_constants.GITHUB_URL),
86 AppEngineBlobstore())
87 ServerInstance.github_file_system = github_file_system
88
89 return ServerInstance(channel, svn_file_system, github_file_system)
90
91 @staticmethod
92 def CreateForTest(file_system):
93 return ServerInstance('test', file_system, None)
94
95 def __init__(self, channel, svn_file_system, github_file_system):
96 self.svn_file_system = svn_file_system
97
98 self.github_file_system = github_file_system
99
100 self.compiled_fs_factory = CompiledFileSystem.Factory(svn_file_system)
101
102 self.api_list_data_source_factory = APIListDataSource.Factory(
103 self.compiled_fs_factory,
104 svn_constants.API_PATH,
105 svn_constants.PUBLIC_TEMPLATE_PATH)
106
107 self.api_data_source_factory = APIDataSource.Factory(
108 self.compiled_fs_factory,
109 svn_constants.API_PATH)
110
111 self.ref_resolver_factory = ReferenceResolver.Factory(
112 self.api_data_source_factory,
113 self.api_list_data_source_factory)
114
115 self.api_data_source_factory.SetReferenceResolverFactory(
116 self.ref_resolver_factory)
117
118 self.samples_data_source_factory = SamplesDataSource.Factory(
119 channel,
120 self.svn_file_system,
121 ServerInstance.github_file_system,
122 self.ref_resolver_factory,
123 svn_constants.EXAMPLES_PATH)
124
125 self.api_data_source_factory.SetSamplesDataSourceFactory(
126 self.samples_data_source_factory)
127
128 self.intro_data_source_factory = IntroDataSource.Factory(
129 self.compiled_fs_factory,
130 self.ref_resolver_factory,
131 [svn_constants.INTRO_PATH, svn_constants.ARTICLE_PATH])
132
133 self.sidenav_data_source_factory = SidenavDataSource.Factory(
134 self.compiled_fs_factory,
135 svn_constants.JSON_PATH)
136
137 self.template_data_source_factory = TemplateDataSource.Factory(
138 channel,
139 self.api_data_source_factory,
140 self.api_list_data_source_factory,
141 self.intro_data_source_factory,
142 self.samples_data_source_factory,
143 self.sidenav_data_source_factory,
144 self.compiled_fs_factory,
145 self.ref_resolver_factory,
146 svn_constants.PUBLIC_TEMPLATE_PATH,
147 svn_constants.PRIVATE_TEMPLATE_PATH)
148
149 self.example_zipper = ExampleZipper(
150 self.svn_file_system,
151 self.compiled_fs_factory,
152 svn_constants.DOCS_PATH)
153
154 self.path_canonicalizer = PathCanonicalizer(
155 channel,
156 self.compiled_fs_factory)
157
158 self.content_cache = self.compiled_fs_factory.GetOrCreateIdentity()
30 159
31 def _FetchStaticResource(self, path, response): 160 def _FetchStaticResource(self, path, response):
32 """Fetch a resource in the 'static' directory. 161 """Fetch a resource in the 'static' directory.
33 """ 162 """
34 mimetype = mimetypes.guess_type(path)[0] or 'text/plain' 163 mimetype = mimetypes.guess_type(path)[0] or 'text/plain'
35 try: 164 try:
36 result = self._cache.GetFromFile(STATIC_DIR_PREFIX + '/' + path, 165 result = self.content_cache.GetFromFile(
37 binary=_IsBinaryMimetype(mimetype)) 166 svn_constants.DOCS_PATH + '/' + path,
167 binary=_IsBinaryMimetype(mimetype))
38 except FileNotFoundError: 168 except FileNotFoundError:
39 return None 169 return None
40 response.headers['content-type'] = mimetype 170 response.headers['content-type'] = mimetype
41 return result 171 return result
42 172
43 def Get(self, path, request, response): 173 def Get(self, path, request, response):
44 # TODO(cduvall): bundle up all the request-scoped data into a single object. 174 templates = self.template_data_source_factory.Create(request, path)
45 templates = self._template_data_source_factory.Create(request, path) 175
176 if path.rsplit('/', 1)[-1] in ('favicon.ico', 'robots.txt'):
177 response.set_status(404)
178 response.out.write(templates.Render('404'))
179 return
46 180
47 content = None 181 content = None
48 if fnmatch(path, 'extensions/examples/*.zip'): 182 if fnmatch(path, 'extensions/examples/*.zip'):
49 try: 183 try:
50 content = self._example_zipper.Create( 184 content = self.example_zipper.Create(
51 path[len('extensions/'):-len('.zip')]) 185 path[len('extensions/'):-len('.zip')])
52 response.headers['content-type'] = 'application/zip' 186 response.headers['content-type'] = 'application/zip'
53 except FileNotFoundError: 187 except FileNotFoundError:
54 content = None 188 content = None
55 elif path.startswith('extensions/examples/'): 189 elif path.startswith('extensions/examples/'):
56 mimetype = mimetypes.guess_type(path)[0] or 'text/plain' 190 mimetype = mimetypes.guess_type(path)[0] or 'text/plain'
57 try: 191 try:
58 content = self._cache.GetFromFile( 192 content = self.content_cache.GetFromFile(
59 '%s/%s' % (DOCS_PATH, path[len('extensions/'):]), 193 '%s/%s' % (svn_constants.DOCS_PATH, path[len('extensions/'):]),
60 binary=_IsBinaryMimetype(mimetype)) 194 binary=_IsBinaryMimetype(mimetype))
61 response.headers['content-type'] = 'text/plain' 195 response.headers['content-type'] = 'text/plain'
62 except FileNotFoundError: 196 except FileNotFoundError:
63 content = None 197 content = None
64 elif path.startswith('static/'): 198 elif path.startswith('static/'):
65 content = self._FetchStaticResource(path, response) 199 content = self._FetchStaticResource(path, response)
66 elif path.endswith('.html'): 200 elif path.endswith('.html'):
67 content = templates.Render(path) 201 content = templates.Render(path)
68 202
69 response.headers['x-frame-options'] = 'sameorigin' 203 response.headers['x-frame-options'] = 'sameorigin'
70 if content: 204 if content:
71 response.headers['cache-control'] = 'max-age=300' 205 response.headers['cache-control'] = 'max-age=300'
72 response.out.write(content) 206 response.out.write(content)
73 else: 207 else:
74 response.set_status(404); 208 response.set_status(404);
75 response.out.write(templates.Render('404')) 209 response.out.write(templates.Render('404'))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698