content_providers.py revision f2477e01787aa58f445919b809d89e252beef54f
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. 4 5import logging 6from operator import itemgetter 7import posixpath 8 9from chroot_file_system import ChrootFileSystem 10from content_provider import ContentProvider 11from extensions_paths import CONTENT_PROVIDERS 12from future import Gettable, Future 13from third_party.json_schema_compiler.memoize import memoize 14 15 16class ContentProviders(object): 17 '''Implements the content_providers.json configuration; see 18 chrome/common/extensions/docs/templates/json/content_providers.json for its 19 current state and a description of the format. 20 21 Returns ContentProvider instances based on how they're configured there. 22 ''' 23 24 def __init__(self, 25 compiled_fs_factory, 26 host_file_system, 27 github_file_system_provider): 28 self._compiled_fs_factory = compiled_fs_factory 29 self._host_file_system = host_file_system 30 self._github_file_system_provider = github_file_system_provider 31 self._cache = compiled_fs_factory.ForJson(host_file_system) 32 33 @memoize 34 def GetByName(self, name): 35 '''Gets the ContentProvider keyed by |name| in content_providers.json, or 36 None of there is no such content provider. 37 ''' 38 config = self._GetConfig().get(name) 39 if config is None: 40 logging.error('No content provider found with name "%s"' % name) 41 return None 42 return self._CreateContentProvider(name, config) 43 44 @memoize 45 def GetByServeFrom(self, path): 46 '''Gets a (content_provider, path_in_content_provider) tuple, where 47 content_provider is the ContentProvider with the longest "serveFrom" 48 property that is a subpath of |path|, and path_in_content_provider is the 49 remainder of |path|. 50 51 For example, if content provider A serves from "foo" and content provider B 52 serves from "foo/bar", GetByServeFrom("foo/bar/baz") will return (B, "baz"). 53 54 Returns (None, |path|) if no ContentProvider serves from |path|. 55 ''' 56 serve_from_to_config = dict( 57 (config['serveFrom'], (name, config)) 58 for name, config in self._GetConfig().iteritems()) 59 path_parts = path.split('/') 60 for i in xrange(len(path_parts), -1, -1): 61 name_and_config = serve_from_to_config.get('/'.join(path_parts[:i])) 62 if name_and_config is not None: 63 return (self._CreateContentProvider(name_and_config[0], 64 name_and_config[1]), 65 '/'.join(path_parts[i:])) 66 return None, path 67 68 def _GetConfig(self): 69 return self._cache.GetFromFile(CONTENT_PROVIDERS).Get() 70 71 def _CreateContentProvider(self, name, config): 72 supports_templates = config.get('supportsTemplates', False) 73 supports_zip = config.get('supportsZip', False) 74 75 if 'chromium' in config: 76 chromium_config = config['chromium'] 77 if 'dir' not in chromium_config: 78 logging.error('%s: "chromium" must have a "dir" property' % name) 79 return None 80 file_system = ChrootFileSystem(self._host_file_system, 81 chromium_config['dir']) 82 elif 'github' in config: 83 github_config = config['github'] 84 if 'owner' not in github_config or 'repo' not in github_config: 85 logging.error('%s: "github" must provide an "owner" and "repo"' % name) 86 return None 87 file_system = self._github_file_system_provider.Create( 88 github_config['owner'], github_config['repo']) 89 if 'dir' in github_config: 90 file_system = ChrootFileSystem(file_system, github_config['dir']) 91 else: 92 logging.error( 93 '%s: content provider type "%s" not supported' % (name, type_)) 94 return None 95 96 return ContentProvider(name, 97 self._compiled_fs_factory, 98 file_system, 99 supports_templates=supports_templates, 100 supports_zip=supports_zip) 101 102 def Cron(self): 103 futures = [self._CreateContentProvider(name, config).Cron() 104 for name, config in self._GetConfig().iteritems()] 105 return Future(delegate=Gettable(lambda: [f.Get() for f in futures])) 106