Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / common / extensions / docs / server2 / content_providers.py
blob0c44d9e4a268428dcdc8fb4623bc7f947f229d93
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.
5 import logging
6 import traceback
8 from chroot_file_system import ChrootFileSystem
9 from content_provider import ContentProvider
10 from extensions_paths import CONTENT_PROVIDERS
11 from future import Gettable, Future
12 from third_party.json_schema_compiler.memoize import memoize
15 class ContentProviders(object):
16 '''Implements the content_providers.json configuration; see
17 chrome/common/extensions/docs/templates/json/content_providers.json for its
18 current state and a description of the format.
20 Returns ContentProvider instances based on how they're configured there.
21 '''
23 def __init__(self,
24 compiled_fs_factory,
25 host_file_system,
26 github_file_system_provider):
27 self._compiled_fs_factory = compiled_fs_factory
28 self._host_file_system = host_file_system
29 self._github_file_system_provider = github_file_system_provider
30 self._cache = compiled_fs_factory.ForJson(host_file_system)
32 @memoize
33 def GetByName(self, name):
34 '''Gets the ContentProvider keyed by |name| in content_providers.json, or
35 None of there is no such content provider.
36 '''
37 config = self._GetConfig().get(name)
38 if config is None:
39 logging.error('No content provider found with name "%s"' % name)
40 return None
41 return self._CreateContentProvider(name, config)
43 @memoize
44 def GetByServeFrom(self, path):
45 '''Gets a (content_provider, path_in_content_provider) tuple, where
46 content_provider is the ContentProvider with the longest "serveFrom"
47 property that is a subpath of |path|, and path_in_content_provider is the
48 remainder of |path|.
50 For example, if content provider A serves from "foo" and content provider B
51 serves from "foo/bar", GetByServeFrom("foo/bar/baz") will return (B, "baz").
53 Returns (None, |path|) if no ContentProvider serves from |path|.
54 '''
55 serve_from_to_config = dict(
56 (config['serveFrom'], (name, config))
57 for name, config in self._GetConfig().iteritems())
58 path_parts = path.split('/')
59 for i in xrange(len(path_parts), -1, -1):
60 name_and_config = serve_from_to_config.get('/'.join(path_parts[:i]))
61 if name_and_config is not None:
62 return (self._CreateContentProvider(name_and_config[0],
63 name_and_config[1]),
64 '/'.join(path_parts[i:]))
65 return None, path
67 def _GetConfig(self):
68 return self._cache.GetFromFile(CONTENT_PROVIDERS).Get()
70 def _CreateContentProvider(self, name, config):
71 supports_templates = config.get('supportsTemplates', False)
72 supports_zip = config.get('supportsZip', False)
74 if 'chromium' in config:
75 chromium_config = config['chromium']
76 if 'dir' not in chromium_config:
77 logging.error('%s: "chromium" must have a "dir" property' % name)
78 return None
79 file_system = ChrootFileSystem(self._host_file_system,
80 chromium_config['dir'])
81 elif 'github' in config:
82 github_config = config['github']
83 if 'owner' not in github_config or 'repo' not in github_config:
84 logging.error('%s: "github" must provide an "owner" and "repo"' % name)
85 return None
86 file_system = self._github_file_system_provider.Create(
87 github_config['owner'], github_config['repo'])
88 if 'dir' in github_config:
89 file_system = ChrootFileSystem(file_system, github_config['dir'])
90 else:
91 logging.error(
92 '%s: content provider type "%s" not supported' % (name, type_))
93 return None
95 return ContentProvider(name,
96 self._compiled_fs_factory,
97 file_system,
98 supports_templates=supports_templates,
99 supports_zip=supports_zip)
101 def Cron(self):
102 def safe(name, action, callback):
103 '''Safely runs |callback| for a ContentProvider called |name| by
104 swallowing exceptions and turning them into a None return value. It's
105 important to run all ContentProvider Crons even if some of them fail.
107 try:
108 return callback()
109 except:
110 logging.error('Error %s Cron for ContentProvider "%s":\n%s' %
111 (action, name, traceback.format_exc()))
112 return None
114 futures = [(name, safe(name,
115 'initializing',
116 self._CreateContentProvider(name, config).Cron))
117 for name, config in self._GetConfig().iteritems()]
118 return Future(delegate=Gettable(
119 lambda: [safe(name, 'resolving', f.Get) for name, f in futures if f]))