| Index: chrome/common/extensions/docs/server2/server_instance.py
|
| diff --git a/chrome/common/extensions/docs/server2/server_instance.py b/chrome/common/extensions/docs/server2/server_instance.py
|
| index c3ecabc664f5f91dd611c664044a52076a85fb32..507665df7719a4ac2542867e59825b0d83a62c92 100644
|
| --- a/chrome/common/extensions/docs/server2/server_instance.py
|
| +++ b/chrome/common/extensions/docs/server2/server_instance.py
|
| @@ -6,48 +6,183 @@ from fnmatch import fnmatch
|
| import mimetypes
|
| import os
|
|
|
| +from api_data_source import APIDataSource
|
| +from api_list_data_source import APIListDataSource
|
| +from appengine_blobstore import AppEngineBlobstore
|
| +from appengine_url_fetcher import AppEngineUrlFetcher
|
| +from branch_utility import BranchUtility
|
| +from compiled_file_system import CompiledFileSystem
|
| +from example_zipper import ExampleZipper
|
| from file_system import FileNotFoundError
|
| -import compiled_file_system as compiled_fs
|
| -
|
| -STATIC_DIR_PREFIX = 'docs'
|
| -DOCS_PATH = 'docs'
|
| +from github_file_system import GithubFileSystem
|
| +from in_memory_object_store import InMemoryObjectStore
|
| +from intro_data_source import IntroDataSource
|
| +from local_file_system import LocalFileSystem
|
| +from caching_file_system import CachingFileSystem
|
| +from object_store_creator import ObjectStoreCreator
|
| +from path_canonicalizer import PathCanonicalizer
|
| +from reference_resolver import ReferenceResolver
|
| +from samples_data_source import SamplesDataSource
|
| +from sidenav_data_source import SidenavDataSource
|
| +from subversion_file_system import SubversionFileSystem
|
| +import svn_constants
|
| +from template_data_source import TemplateDataSource
|
| +from third_party.json_schema_compiler.model import UnixName
|
| +import url_constants
|
|
|
| def _IsBinaryMimetype(mimetype):
|
| return any(mimetype.startswith(prefix)
|
| for prefix in ['audio', 'image', 'video'])
|
|
|
| class ServerInstance(object):
|
| - """This class is used to hold a data source and fetcher for an instance of a
|
| - server. Each new branch will get its own ServerInstance.
|
| - """
|
| - def __init__(self,
|
| - template_data_source_factory,
|
| - example_zipper,
|
| - cache_factory):
|
| - self._template_data_source_factory = template_data_source_factory
|
| - self._example_zipper = example_zipper
|
| - self._cache = cache_factory.Create(lambda _, x: x, compiled_fs.STATIC)
|
| + '''Per-instance per-branch state.
|
| + '''
|
| + _instances = {}
|
| +
|
| + branch_utility = None
|
| + github_file_system = None
|
| +
|
| + @staticmethod
|
| + def GetOrCreate(channel):
|
| + # Lazily create so that we don't do unnecessary work in tests.
|
| + if ServerInstance.branch_utility is None:
|
| + ServerInstance.branch_utility = BranchUtility(
|
| + url_constants.OMAHA_PROXY_URL, AppEngineUrlFetcher())
|
| + branch = ServerInstance.branch_utility.GetBranchNumberForChannelName(
|
| + channel)
|
| +
|
| + # Use the branch as the key to |_instances| since the branch data is
|
| + # predictable while the channel data (channels can swich branches) isn't.
|
| + instance = ServerInstance._instances.get(branch)
|
| + if instance is None:
|
| + instance = ServerInstance._CreateForProduction(channel, branch)
|
| + ServerInstance._instances[branch] = instance
|
| + return instance
|
| +
|
| + @staticmethod
|
| + def _CreateForProduction(channel, branch):
|
| + if branch == 'trunk':
|
| + svn_url = '/'.join((url_constants.SVN_TRUNK_URL,
|
| + 'src',
|
| + svn_constants.EXTENSIONS_PATH))
|
| + else:
|
| + svn_url = '/'.join((url_constants.SVN_BRANCH_URL,
|
| + branch,
|
| + 'src',
|
| + svn_constants.EXTENSIONS_PATH))
|
| +
|
| + viewvc_url = svn_url.replace(url_constants.SVN_URL,
|
| + url_constants.VIEWVC_URL)
|
| +
|
| + svn_file_system = CachingFileSystem(
|
| + SubversionFileSystem(AppEngineUrlFetcher(svn_url),
|
| + AppEngineUrlFetcher(viewvc_url)))
|
| +
|
| + # Lazily create so we don't create github file systems unnecessarily in
|
| + # tests.
|
| + if ServerInstance.github_file_system is None:
|
| + ServerInstance.github_file_system = GithubFileSystem(
|
| + AppEngineUrlFetcher(url_constants.GITHUB_URL),
|
| + AppEngineBlobstore())
|
| +
|
| + return ServerInstance(channel,
|
| + svn_file_system,
|
| + ServerInstance.github_file_system)
|
| +
|
| + @staticmethod
|
| + def CreateForTest(file_system):
|
| + return ServerInstance('test', file_system, None)
|
| +
|
| + def __init__(self, channel, svn_file_system, github_file_system):
|
| + self.svn_file_system = svn_file_system
|
| +
|
| + self.github_file_system = github_file_system
|
| +
|
| + self.compiled_fs_factory = CompiledFileSystem.Factory(svn_file_system)
|
| +
|
| + self.api_list_data_source_factory = APIListDataSource.Factory(
|
| + self.compiled_fs_factory,
|
| + svn_constants.API_PATH,
|
| + svn_constants.PUBLIC_TEMPLATE_PATH)
|
| +
|
| + self.api_data_source_factory = APIDataSource.Factory(
|
| + self.compiled_fs_factory,
|
| + svn_constants.API_PATH)
|
| +
|
| + self.ref_resolver_factory = ReferenceResolver.Factory(
|
| + self.api_data_source_factory,
|
| + self.api_list_data_source_factory)
|
| +
|
| + self.api_data_source_factory.SetReferenceResolverFactory(
|
| + self.ref_resolver_factory)
|
| +
|
| + self.samples_data_source_factory = SamplesDataSource.Factory(
|
| + channel,
|
| + self.svn_file_system,
|
| + ServerInstance.github_file_system,
|
| + self.ref_resolver_factory,
|
| + svn_constants.EXAMPLES_PATH)
|
| +
|
| + self.api_data_source_factory.SetSamplesDataSourceFactory(
|
| + self.samples_data_source_factory)
|
| +
|
| + self.intro_data_source_factory = IntroDataSource.Factory(
|
| + self.compiled_fs_factory,
|
| + self.ref_resolver_factory,
|
| + [svn_constants.INTRO_PATH, svn_constants.ARTICLE_PATH])
|
| +
|
| + self.sidenav_data_source_factory = SidenavDataSource.Factory(
|
| + self.compiled_fs_factory,
|
| + svn_constants.JSON_PATH)
|
| +
|
| + self.template_data_source_factory = TemplateDataSource.Factory(
|
| + channel,
|
| + self.api_data_source_factory,
|
| + self.api_list_data_source_factory,
|
| + self.intro_data_source_factory,
|
| + self.samples_data_source_factory,
|
| + self.sidenav_data_source_factory,
|
| + self.compiled_fs_factory,
|
| + self.ref_resolver_factory,
|
| + svn_constants.PUBLIC_TEMPLATE_PATH,
|
| + svn_constants.PRIVATE_TEMPLATE_PATH)
|
| +
|
| + self.example_zipper = ExampleZipper(
|
| + self.svn_file_system,
|
| + self.compiled_fs_factory,
|
| + svn_constants.DOCS_PATH)
|
| +
|
| + self.path_canonicalizer = PathCanonicalizer(
|
| + channel,
|
| + self.compiled_fs_factory)
|
| +
|
| + self.content_cache = self.compiled_fs_factory.GetOrCreateIdentity()
|
|
|
| def _FetchStaticResource(self, path, response):
|
| """Fetch a resource in the 'static' directory.
|
| """
|
| mimetype = mimetypes.guess_type(path)[0] or 'text/plain'
|
| try:
|
| - result = self._cache.GetFromFile(STATIC_DIR_PREFIX + '/' + path,
|
| - binary=_IsBinaryMimetype(mimetype))
|
| + result = self.content_cache.GetFromFile(
|
| + svn_constants.DOCS_PATH + '/' + path,
|
| + binary=_IsBinaryMimetype(mimetype))
|
| except FileNotFoundError:
|
| return None
|
| response.headers['content-type'] = mimetype
|
| return result
|
|
|
| def Get(self, path, request, response):
|
| - # TODO(cduvall): bundle up all the request-scoped data into a single object.
|
| - templates = self._template_data_source_factory.Create(request, path)
|
| + templates = self.template_data_source_factory.Create(request, path)
|
| +
|
| + if path.rsplit('/', 1)[-1] in ('favicon.ico', 'robots.txt'):
|
| + response.set_status(404)
|
| + response.out.write(templates.Render('404'))
|
| + return
|
|
|
| content = None
|
| if fnmatch(path, 'extensions/examples/*.zip'):
|
| try:
|
| - content = self._example_zipper.Create(
|
| + content = self.example_zipper.Create(
|
| path[len('extensions/'):-len('.zip')])
|
| response.headers['content-type'] = 'application/zip'
|
| except FileNotFoundError:
|
| @@ -55,8 +190,8 @@ class ServerInstance(object):
|
| elif path.startswith('extensions/examples/'):
|
| mimetype = mimetypes.guess_type(path)[0] or 'text/plain'
|
| try:
|
| - content = self._cache.GetFromFile(
|
| - '%s/%s' % (DOCS_PATH, path[len('extensions/'):]),
|
| + content = self.content_cache.GetFromFile(
|
| + '%s/%s' % (svn_constants.DOCS_PATH, path[len('extensions/'):]),
|
| binary=_IsBinaryMimetype(mimetype))
|
| response.headers['content-type'] = 'text/plain'
|
| except FileNotFoundError:
|
|
|