1 # Copyright 2015 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.
14 from branch_utility
import BranchUtility
15 from commit_tracker
import CommitTracker
16 from compiled_file_system
import CompiledFileSystem
17 from data_source_registry
import CreateDataSources
18 from environment
import GetAppVersion
19 from environment_wrappers
import CreateUrlFetcher
, GetAccessToken
20 from future
import All
21 from gcs_file_system_provider
import CloudStorageFileSystemProvider
22 from host_file_system_provider
import HostFileSystemProvider
23 from local_git_util
import ParseRevision
24 from object_store_creator
import ObjectStoreCreator
25 from persistent_object_store_fake
import PersistentObjectStoreFake
26 from render_refresher
import RenderRefresher
27 from server_instance
import ServerInstance
28 from timer
import Timer
31 # The path template to use for flushing the memcached. Should be formatted with
32 # with the app version.
33 _FLUSH_MEMCACHE_PATH
= ('https://%s-dot-chrome-apps-doc.appspot.com/'
37 def _UpdateCommitId(commit_name
, commit_id
):
38 '''Sets the commit ID for a named commit. This is the final step performed
39 during update. Once all the appropriate datastore entries have been populated
40 for a new commit ID, the 'master' commit entry is updated to that ID and the
41 frontend will begin serving the new data.
43 Note that this requires an access token identifying the main service account
44 for the chrome-apps-doc project. VM instances will get this automatically
45 from their environment, but if you want to do a local push to prod you will
46 need to set the DOCSERVER_ACCESS_TOKEN environment variable appropriately.
48 commit_tracker
= CommitTracker(
49 ObjectStoreCreator(store_type
=PersistentObjectStoreFake
,
51 commit_tracker
.Set(commit_name
, commit_id
).Get()
52 logging
.info('Commit "%s" updated to %s.' % (commit_name
, commit_id
))
55 def _GetCachedCommitId(commit_name
):
56 '''Determines which commit ID was last cached.
58 commit_tracker
= CommitTracker(
59 ObjectStoreCreator(store_type
=PersistentObjectStoreFake
,
61 return commit_tracker
.Get(commit_name
).Get()
65 '''Requests that the frontend flush its memcached to avoid serving stale data.
67 flush_url
= _FLUSH_MEMCACHE_PATH
% GetAppVersion()
68 headers
= { 'Authorization': 'Bearer %s' % GetAccessToken() }
69 response
= CreateUrlFetcher().Fetch(flush_url
, headers
)
70 if response
.status_code
!= 200:
71 logging
.error('Unable to flush memcache: HTTP %s (%s)' %
72 (response
.status_code
, response
.content
))
74 logging
.info('Memcache flushed.')
77 def _CreateServerInstance(commit
):
78 '''Creates a ServerInstance based on origin/master.
80 object_store_creator
= ObjectStoreCreator(
81 start_empty
=False, store_type
=PersistentObjectStoreFake
)
82 branch_utility
= BranchUtility
.Create(object_store_creator
)
83 host_file_system_provider
= HostFileSystemProvider(object_store_creator
,
85 gcs_file_system_provider
= CloudStorageFileSystemProvider(
87 return ServerInstance(object_store_creator
,
88 CompiledFileSystem
.Factory(object_store_creator
),
90 host_file_system_provider
,
91 gcs_file_system_provider
)
94 def _UpdateDataSource(name
, data_source
):
96 class_name
= data_source
.__class
__.__name
__
98 logging
.info('Updating %s...' % name
)
99 data_source
.Refresh().Get()
100 except Exception as e
:
101 logging
.error('%s: error %s' % (class_name
, traceback
.format_exc()))
104 logging
.info('Updating %s took %s' % (name
, timer
.Stop().FormatElapsed()))
107 def UpdateCache(single_data_source
=None, commit
=None):
108 '''Attempts to populate the datastore with a bunch of information derived from
111 server_instance
= _CreateServerInstance(commit
)
113 # This is the guy that would be responsible for refreshing the cache of
114 # examples. Here for posterity, hopefully it will be added to the targets
116 # render_refresher = RenderRefresher(server_instance, self._request)
118 data_sources
= CreateDataSources(server_instance
)
119 data_sources
['content_providers'] = server_instance
.content_providers
120 data_sources
['platform_bundle'] = server_instance
.platform_bundle
121 if single_data_source
:
122 _UpdateDataSource(single_data_source
, data_sources
[single_data_source
])
124 for name
, source
in data_sources
.iteritems():
125 _UpdateDataSource(name
, source
)
130 opts
= dict((name
[2:], value
) for name
, value
in
131 getopt
.getopt(argv
, '',
132 ['load-file=', 'data-source=', 'commit=',
133 'no-refresh', 'no-push', 'save-file=',
134 'no-master-update', 'push-all', 'force'])[0])
135 except getopt
.GetoptError
as e
:
138 'Usage: update_cache.py [options]\n\n'
140 ' --data-source=NAME Limit update to a single data source.\n'
141 ' --load-file=FILE Load object store data from FILE before\n'
142 ' starting the update.\n'
143 ' --save-file=FILE Save object store data to FILE after running\n'
145 ' --no-refresh Do not attempt to update any data sources.\n'
146 ' --no-push Do not push to Datastore.\n'
147 ' --commit=REV Commit ID to use for master update.\n'
148 ' --no-master-update Do not update the master commit ID.\n'
149 ' --push-all Push all entities to the Datastore even if\n'
150 ' they do not differ from the loaded cache.\n\n'
151 ' --force Force an update even if the latest commit is'
152 ' already cached.\n')
155 logging
.getLogger().setLevel(logging
.INFO
)
157 data_source
= opts
.get('data-source', None)
158 load_file
= opts
.get('load-file', None)
159 save_file
= opts
.get('save-file', None)
160 do_refresh
= 'no-refresh' not in opts
161 do_push
= 'no-push' not in opts
162 do_master_update
= 'no-master-update' not in opts
163 push_all
= do_push
and ('push-all' in opts
)
164 commit
= ParseRevision(opts
.get('commit', 'origin/HEAD'))
165 force_update
= 'force' in opts
169 logging
.info('Loading cache...')
170 PersistentObjectStoreFake
.LoadFromFile(load_file
)
172 original_data
= copy
.deepcopy(PersistentObjectStoreFake
.DATA
)
174 last_commit
= _GetCachedCommitId('master')
175 if ParseRevision(commit
) == last_commit
and not force_update
:
176 logging
.info('Latest cache (revision %s) is up to date. Bye.' % commit
)
181 logging
.info('Starting refresh from commit %s...' % ParseRevision(commit
))
183 UpdateCache(single_data_source
=data_source
,
186 UpdateCache(commit
=commit
)
189 from datastore_util
import PushData
191 _UpdateCommitId('master', commit
)
193 logging
.info('Pushing data into datastore...')
194 PushData(PersistentObjectStoreFake
.DATA
, original_data
=original_data
)
195 logging
.info('Done. Datastore push took %s' %
196 push_timer
.Stop().FormatElapsed())
199 PersistentObjectStoreFake
.SaveToFile(save_file
)
201 logging
.info('Update completed in %s' % timer
.Stop().FormatElapsed())
204 if __name__
== '__main__':