| OLD | NEW |
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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 import logging | 5 import logging |
| 6 import time | 6 import time |
| 7 import traceback | 7 import traceback |
| 8 | 8 |
| 9 from app_yaml_helper import AppYamlHelper | 9 from app_yaml_helper import AppYamlHelper |
| 10 from appengine_wrappers import ( | 10 from appengine_wrappers import ( |
| 11 GetAppVersion, IsDeadlineExceededError, IsDevServer, logservice) | 11 GetAppVersion, IsDeadlineExceededError, IsDevServer, logservice) |
| 12 from branch_utility import BranchUtility | 12 from branch_utility import BranchUtility |
| 13 from compiled_file_system import CompiledFileSystem | 13 from compiled_file_system import CompiledFileSystem |
| 14 from data_source_registry import CreateDataSources | 14 from data_source_registry import CreateDataSources |
| 15 from empty_dir_file_system import EmptyDirFileSystem | 15 from empty_dir_file_system import EmptyDirFileSystem |
| 16 from file_system_util import CreateURLsFromPaths | 16 from file_system_util import CreateURLsFromPaths |
| 17 from github_file_system import GithubFileSystem | 17 from github_file_system import GithubFileSystem |
| 18 from host_file_system_creator import HostFileSystemCreator | 18 from host_file_system_provider import HostFileSystemProvider |
| 19 from object_store_creator import ObjectStoreCreator | 19 from object_store_creator import ObjectStoreCreator |
| 20 from render_servlet import RenderServlet | 20 from render_servlet import RenderServlet |
| 21 from server_instance import ServerInstance | 21 from server_instance import ServerInstance |
| 22 from servlet import Servlet, Request, Response | 22 from servlet import Servlet, Request, Response |
| 23 import svn_constants | 23 import svn_constants |
| 24 | 24 |
| 25 class _SingletonRenderServletDelegate(RenderServlet.Delegate): | 25 class _SingletonRenderServletDelegate(RenderServlet.Delegate): |
| 26 def __init__(self, server_instance): | 26 def __init__(self, server_instance): |
| 27 self._server_instance = server_instance | 27 self._server_instance = server_instance |
| 28 | 28 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 83 def __init__(self, request, delegate_for_test=None): | 83 def __init__(self, request, delegate_for_test=None): |
| 84 Servlet.__init__(self, request) | 84 Servlet.__init__(self, request) |
| 85 self._delegate = delegate_for_test or CronServlet.Delegate() | 85 self._delegate = delegate_for_test or CronServlet.Delegate() |
| 86 | 86 |
| 87 class Delegate(object): | 87 class Delegate(object): |
| 88 '''CronServlet's runtime dependencies. Override for testing. | 88 '''CronServlet's runtime dependencies. Override for testing. |
| 89 ''' | 89 ''' |
| 90 def CreateBranchUtility(self, object_store_creator): | 90 def CreateBranchUtility(self, object_store_creator): |
| 91 return BranchUtility.Create(object_store_creator) | 91 return BranchUtility.Create(object_store_creator) |
| 92 | 92 |
| 93 def CreateHostFileSystemCreator(self, object_store_creator): | 93 def CreateHostFileSystemProvider(self, |
| 94 return HostFileSystemCreator(object_store_creator) | 94 object_store_creator, |
| 95 max_trunk_revision=None): |
| 96 return HostFileSystemProvider(object_store_creator, |
| 97 max_trunk_revision=max_trunk_revision) |
| 95 | 98 |
| 96 def CreateAppSamplesFileSystem(self, object_store_creator): | 99 def CreateAppSamplesFileSystem(self, object_store_creator): |
| 97 # TODO(kalman): CachingFileSystem wrapper for GithubFileSystem, but it's | 100 # TODO(kalman): CachingFileSystem wrapper for GithubFileSystem, but it's |
| 98 # not supported yet (see comment there). | 101 # not supported yet (see comment there). |
| 99 return (EmptyDirFileSystem() if IsDevServer() else | 102 return (EmptyDirFileSystem() if IsDevServer() else |
| 100 GithubFileSystem.Create(object_store_creator)) | 103 GithubFileSystem.Create(object_store_creator)) |
| 101 | 104 |
| 102 def GetAppVersion(self): | 105 def GetAppVersion(self): |
| 103 return GetAppVersion() | 106 return GetAppVersion() |
| 104 | 107 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 126 # little wasteful, but hopefully rendering is really fast (if it isn't we | 129 # little wasteful, but hopefully rendering is really fast (if it isn't we |
| 127 # have a problem). | 130 # have a problem). |
| 128 _cronlog.info('starting') | 131 _cronlog.info('starting') |
| 129 | 132 |
| 130 # This is returned every time RenderServlet wants to create a new | 133 # This is returned every time RenderServlet wants to create a new |
| 131 # ServerInstance. | 134 # ServerInstance. |
| 132 # | 135 # |
| 133 # TODO(kalman): IMPORTANT. This sometimes throws an exception, breaking | 136 # TODO(kalman): IMPORTANT. This sometimes throws an exception, breaking |
| 134 # everything. Need retry logic at the fetcher level. | 137 # everything. Need retry logic at the fetcher level. |
| 135 server_instance = self._GetSafeServerInstance() | 138 server_instance = self._GetSafeServerInstance() |
| 139 trunk_fs = server_instance.host_file_system_provider.GetTrunk() |
| 136 | 140 |
| 137 def render(path): | 141 def render(path): |
| 138 request = Request(path, self._request.host, self._request.headers) | 142 request = Request(path, self._request.host, self._request.headers) |
| 139 delegate = _SingletonRenderServletDelegate(server_instance) | 143 delegate = _SingletonRenderServletDelegate(server_instance) |
| 140 return RenderServlet(request, delegate).Get() | 144 return RenderServlet(request, delegate).Get() |
| 141 | 145 |
| 142 def request_files_in_dir(path, prefix=''): | 146 def request_files_in_dir(path, prefix=''): |
| 143 '''Requests every file found under |path| in this host file system, with | 147 '''Requests every file found under |path| in this host file system, with |
| 144 a request prefix of |prefix|. | 148 a request prefix of |prefix|. |
| 145 ''' | 149 ''' |
| 146 files = [name for name, _ in | 150 files = [name for name, _ in CreateURLsFromPaths(trunk_fs, path, prefix)] |
| 147 CreateURLsFromPaths(server_instance.host_file_system, path, prefix)] | |
| 148 return _RequestEachItem(path, files, render) | 151 return _RequestEachItem(path, files, render) |
| 149 | 152 |
| 150 results = [] | 153 results = [] |
| 151 | 154 |
| 152 try: | 155 try: |
| 153 # Rendering the public templates will also pull in all of the private | 156 # Rendering the public templates will also pull in all of the private |
| 154 # templates. | 157 # templates. |
| 155 results.append(request_files_in_dir(svn_constants.PUBLIC_TEMPLATE_PATH)) | 158 results.append(request_files_in_dir(svn_constants.PUBLIC_TEMPLATE_PATH)) |
| 156 | 159 |
| 157 # Rendering the public templates will have pulled in the .js and | 160 # Rendering the public templates will have pulled in the .js and |
| 158 # manifest.json files (for listing examples on the API reference pages), | 161 # manifest.json files (for listing examples on the API reference pages), |
| 159 # but there are still images, CSS, etc. | 162 # but there are still images, CSS, etc. |
| 160 results.append(request_files_in_dir(svn_constants.STATIC_PATH, | 163 results.append(request_files_in_dir(svn_constants.STATIC_PATH, |
| 161 prefix='static/')) | 164 prefix='static/')) |
| 162 | 165 |
| 163 # Samples are too expensive to run on the dev server, where there is no | 166 # Samples are too expensive to run on the dev server, where there is no |
| 164 # parallel fetch. | 167 # parallel fetch. |
| 165 if not IsDevServer(): | 168 if not IsDevServer(): |
| 166 # Fetch each individual sample file. | 169 # Fetch each individual sample file. |
| 167 results.append(request_files_in_dir(svn_constants.EXAMPLES_PATH, | 170 results.append(request_files_in_dir(svn_constants.EXAMPLES_PATH, |
| 168 prefix='extensions/examples/')) | 171 prefix='extensions/examples/')) |
| 169 | 172 |
| 170 # Fetch the zip file of each example (contains all the individual | 173 # Fetch the zip file of each example (contains all the individual |
| 171 # files). | 174 # files). |
| 172 example_zips = [] | 175 example_zips = [] |
| 173 for root, _, files in server_instance.host_file_system.Walk( | 176 for root, _, files in trunk_fs.Walk(svn_constants.EXAMPLES_PATH): |
| 174 svn_constants.EXAMPLES_PATH): | |
| 175 example_zips.extend( | 177 example_zips.extend( |
| 176 root + '.zip' for name in files if name == 'manifest.json') | 178 root + '.zip' for name in files if name == 'manifest.json') |
| 177 results.append(_RequestEachItem( | 179 results.append(_RequestEachItem( |
| 178 'example zips', | 180 'example zips', |
| 179 example_zips, | 181 example_zips, |
| 180 lambda path: render('extensions/examples/' + path))) | 182 lambda path: render('extensions/examples/' + path))) |
| 181 | 183 |
| 182 def run_cron(data_source): | 184 def run_cron(data_source): |
| 183 title = data_source.__class__.__name__ | 185 title = data_source.__class__.__name__ |
| 184 _cronlog.info('%s: starting' % title) | 186 _cronlog.info('%s: starting' % title) |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 220 # IMPORTANT: Get a ServerInstance pinned to the most recent revision, not | 222 # IMPORTANT: Get a ServerInstance pinned to the most recent revision, not |
| 221 # HEAD. These cron jobs take a while and run very frequently such that | 223 # HEAD. These cron jobs take a while and run very frequently such that |
| 222 # there is usually one running at any given time, and eventually a file | 224 # there is usually one running at any given time, and eventually a file |
| 223 # that we're dealing with will change underneath it, putting the server in | 225 # that we're dealing with will change underneath it, putting the server in |
| 224 # an undefined state. | 226 # an undefined state. |
| 225 server_instance_near_head = self._CreateServerInstance( | 227 server_instance_near_head = self._CreateServerInstance( |
| 226 self._GetMostRecentRevision()) | 228 self._GetMostRecentRevision()) |
| 227 | 229 |
| 228 app_yaml_handler = AppYamlHelper( | 230 app_yaml_handler = AppYamlHelper( |
| 229 svn_constants.APP_YAML_PATH, | 231 svn_constants.APP_YAML_PATH, |
| 230 server_instance_near_head.host_file_system, | |
| 231 server_instance_near_head.object_store_creator, | 232 server_instance_near_head.object_store_creator, |
| 232 server_instance_near_head.host_file_system_creator) | 233 server_instance_near_head.host_file_system_provider) |
| 233 | 234 |
| 234 if app_yaml_handler.IsUpToDate(delegate.GetAppVersion()): | 235 if app_yaml_handler.IsUpToDate(delegate.GetAppVersion()): |
| 235 return server_instance_near_head | 236 return server_instance_near_head |
| 236 | 237 |
| 237 # The version in app.yaml is greater than the currently running app's. | 238 # The version in app.yaml is greater than the currently running app's. |
| 238 # The safe version is the one before it changed. | 239 # The safe version is the one before it changed. |
| 239 safe_revision = app_yaml_handler.GetFirstRevisionGreaterThan( | 240 safe_revision = app_yaml_handler.GetFirstRevisionGreaterThan( |
| 240 delegate.GetAppVersion()) - 1 | 241 delegate.GetAppVersion()) - 1 |
| 241 | 242 |
| 242 _cronlog.info('app version %s is out of date, safe is %s', | 243 _cronlog.info('app version %s is out of date, safe is %s', |
| 243 delegate.GetAppVersion(), safe_revision) | 244 delegate.GetAppVersion(), safe_revision) |
| 244 | 245 |
| 245 return self._CreateServerInstance(safe_revision) | 246 return self._CreateServerInstance(safe_revision) |
| 246 | 247 |
| 247 def _GetMostRecentRevision(self): | 248 def _GetMostRecentRevision(self): |
| 248 '''Gets the revision of the most recent patch submitted to the host file | 249 '''Gets the revision of the most recent patch submitted to the host file |
| 249 system. This is similar to HEAD but it's a concrete revision so won't | 250 system. This is similar to HEAD but it's a concrete revision so won't |
| 250 change as the cron runs. | 251 change as the cron runs. |
| 251 ''' | 252 ''' |
| 252 return self._CreateServerInstance(None).host_file_system.Stat('/').version | 253 head_fs = ( |
| 254 self._CreateServerInstance(None).host_file_system_provider.GetTrunk()) |
| 255 return head_fs.Stat('/').version |
| 253 | 256 |
| 254 def _CreateServerInstance(self, revision): | 257 def _CreateServerInstance(self, revision): |
| 255 '''Creates a ServerInstance pinned to |revision|, or HEAD if None. | 258 '''Creates a ServerInstance pinned to |revision|, or HEAD if None. |
| 256 NOTE: If passed None it's likely that during the cron run patches will be | 259 NOTE: If passed None it's likely that during the cron run patches will be |
| 257 submitted at HEAD, which may change data underneath the cron run. | 260 submitted at HEAD, which may change data underneath the cron run. |
| 258 ''' | 261 ''' |
| 259 object_store_creator = ObjectStoreCreator(start_empty=True) | 262 object_store_creator = ObjectStoreCreator(start_empty=True) |
| 260 branch_utility = self._delegate.CreateBranchUtility(object_store_creator) | 263 branch_utility = self._delegate.CreateBranchUtility(object_store_creator) |
| 261 host_file_system_creator = self._delegate.CreateHostFileSystemCreator( | 264 host_file_system_provider = self._delegate.CreateHostFileSystemProvider( |
| 262 object_store_creator) | 265 object_store_creator, max_trunk_revision=revision) |
| 263 host_file_system = host_file_system_creator.Create(revision=revision) | |
| 264 app_samples_file_system = self._delegate.CreateAppSamplesFileSystem( | 266 app_samples_file_system = self._delegate.CreateAppSamplesFileSystem( |
| 265 object_store_creator) | 267 object_store_creator) |
| 266 compiled_host_fs_factory = CompiledFileSystem.Factory( | 268 compiled_host_fs_factory = CompiledFileSystem.Factory( |
| 267 host_file_system, | 269 host_file_system_provider.GetTrunk(), |
| 268 object_store_creator) | 270 object_store_creator) |
| 269 return ServerInstance(object_store_creator, | 271 return ServerInstance(object_store_creator, |
| 270 host_file_system, | |
| 271 app_samples_file_system, | 272 app_samples_file_system, |
| 272 compiled_host_fs_factory, | 273 compiled_host_fs_factory, |
| 273 branch_utility, | 274 branch_utility, |
| 274 host_file_system_creator) | 275 host_file_system_provider) |
| OLD | NEW |