blob: d5f45d65e6fc1bd9c68c530459ff559b620e701b [file] [log] [blame]
borenetdc89ca52014-10-17 07:37:05 -07001#!/usr/bin/env python
2# Copyright (c) 2012 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Archives or replays webpages and creates SKPs in a Google Storage location.
7
8To archive webpages and store SKP files (archives should be rarely updated):
9
kkinnunenfcf35c52014-12-03 05:51:24 -080010cd skia
kkinnunenb4ee7ea2015-03-31 00:18:26 -070011python tools/skp/webpages_playback.py --data_store=gs://rmistry --record \
borenetdc89ca52014-10-17 07:37:05 -070012--page_sets=all --skia_tools=/home/default/trunk/out/Debug/ \
13--browser_executable=/tmp/chromium/out/Release/chrome
14
kkinnunenb4ee7ea2015-03-31 00:18:26 -070015The above command uses Google Storage bucket 'rmistry' to download needed files.
borenetdc89ca52014-10-17 07:37:05 -070016
17To replay archived webpages and re-generate SKP files (should be run whenever
18SkPicture.PICTURE_VERSION changes):
19
kkinnunenfcf35c52014-12-03 05:51:24 -080020cd skia
kkinnunenb4ee7ea2015-03-31 00:18:26 -070021python tools/skp/webpages_playback.py --data_store=gs://rmistry \
borenetdc89ca52014-10-17 07:37:05 -070022--page_sets=all --skia_tools=/home/default/trunk/out/Debug/ \
23--browser_executable=/tmp/chromium/out/Release/chrome
24
25
26Specify the --page_sets flag (default value is 'all') to pick a list of which
27webpages should be archived and/or replayed. Eg:
28
kkinnunenfcf35c52014-12-03 05:51:24 -080029--page_sets=tools/skp/page_sets/skia_yahooanswers_desktop.py,\
30tools/skp/page_sets/skia_googlecalendar_nexus10.py
borenetdc89ca52014-10-17 07:37:05 -070031
32The --browser_executable flag should point to the browser binary you want to use
33to capture archives and/or capture SKP files. Majority of the time it should be
34a newly built chrome binary.
35
kkinnunenb4ee7ea2015-03-31 00:18:26 -070036The --data_store flag controls where the needed artifacts, such as
37credential files, are downloaded from. It also controls where the
38generated artifacts, such as recorded webpages and resulting skp renderings,
39are uploaded to. URLs with scheme 'gs://' use Google Storage. Otherwise
40use local filesystem.
41
42The --upload=True flag means generated artifacts will be
43uploaded or copied to the location specified by --data_store. (default value is
44False if not specified).
borenetdc89ca52014-10-17 07:37:05 -070045
46The --non-interactive flag controls whether the script will prompt the user
47(default value is False if not specified).
48
49The --skia_tools flag if specified will allow this script to run
50debugger, render_pictures, and render_pdfs on the captured
51SKP(s). The tools are run after all SKPs are succesfully captured to make sure
52they can be added to the buildbots with no breakages.
borenetdc89ca52014-10-17 07:37:05 -070053"""
54
55import glob
56import optparse
57import os
58import posixpath
59import shutil
60import subprocess
61import sys
62import tempfile
63import time
64import traceback
65
66sys.path.insert(0, os.getcwd())
67
68from common.py.utils import gs_utils
69from common.py.utils import shell_utils
70
71ROOT_PLAYBACK_DIR_NAME = 'playback'
72SKPICTURES_DIR_NAME = 'skps'
73
rmistry0575c492016-02-01 10:27:05 -080074PARTNERS_GS_BUCKET = 'gs://chrome-partner-telemetry'
borenetdc89ca52014-10-17 07:37:05 -070075
76# Local archive and SKP directories.
77LOCAL_PLAYBACK_ROOT_DIR = os.path.join(
78 tempfile.gettempdir(), ROOT_PLAYBACK_DIR_NAME)
79LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR = os.path.join(
80 os.path.abspath(os.path.dirname(__file__)), 'page_sets', 'data')
81TMP_SKP_DIR = tempfile.mkdtemp()
82
rmistryf802f322014-10-22 05:04:43 -070083# Location of the credentials.json file and the string that represents missing
84# passwords.
85CREDENTIALS_FILE_PATH = os.path.join(
86 os.path.abspath(os.path.dirname(__file__)), 'page_sets', 'data',
87 'credentials.json'
88)
89
borenetdc89ca52014-10-17 07:37:05 -070090# Name of the SKP benchmark
91SKP_BENCHMARK = 'skpicture_printer'
92
93# The max base name length of Skp files.
94MAX_SKP_BASE_NAME_LEN = 31
95
96# Dictionary of device to platform prefixes for SKP files.
97DEVICE_TO_PLATFORM_PREFIX = {
98 'desktop': 'desk',
99 'galaxynexus': 'mobi',
100 'nexus10': 'tabl'
101}
102
103# How many times the record_wpr binary should be retried.
104RETRY_RECORD_WPR_COUNT = 5
borenet78399152014-10-17 12:15:46 -0700105# How many times the run_benchmark binary should be retried.
borenetdc89ca52014-10-17 07:37:05 -0700106RETRY_RUN_MEASUREMENT_COUNT = 5
107
rmistryf802f322014-10-22 05:04:43 -0700108# Location of the credentials.json file in Google Storage.
109CREDENTIALS_GS_PATH = '/playback/credentials/credentials.json'
110
borenetdc89ca52014-10-17 07:37:05 -0700111X11_DISPLAY = os.getenv('DISPLAY', ':0')
112
113GS_PREDEFINED_ACL = gs_utils.GSUtils.PredefinedACL.PRIVATE
114GS_FINE_GRAINED_ACL_LIST = [
115 (gs_utils.GSUtils.IdType.GROUP_BY_DOMAIN, 'google.com',
116 gs_utils.GSUtils.Permission.READ),
117]
118
rmistry49d093c2015-03-31 05:04:29 -0700119# Path to Chromium's page sets.
120CHROMIUM_PAGE_SETS_PATH = os.path.join('tools', 'perf', 'page_sets')
121
122# Dictionary of supported Chromium page sets to their file prefixes.
123CHROMIUM_PAGE_SETS_TO_PREFIX = {
rmistry5af9a372015-03-31 06:22:55 -0700124 'key_mobile_sites_smooth.py': 'keymobi',
rmistry2a3c8492015-03-31 10:59:15 -0700125 'top_25_smooth.py': 'top25desk',
rmistry49d093c2015-03-31 05:04:29 -0700126}
127
128
kkinnunene75d2d22014-12-03 04:38:46 -0800129def remove_prefix(s, prefix):
130 if s.startswith(prefix):
131 return s[len(prefix):]
132 return s
borenetdc89ca52014-10-17 07:37:05 -0700133
rmistry49d093c2015-03-31 05:04:29 -0700134
borenetdc89ca52014-10-17 07:37:05 -0700135class SkPicturePlayback(object):
136 """Class that archives or replays webpages and creates SKPs."""
137
138 def __init__(self, parse_options):
139 """Constructs a SkPicturePlayback BuildStep instance."""
140 assert parse_options.browser_executable, 'Must specify --browser_executable'
141 self._browser_executable = parse_options.browser_executable
rmistryaa31ee72015-04-23 12:47:33 -0700142 self._browser_args = '--disable-setuid-sandbox'
143 if parse_options.browser_extra_args:
144 self._browser_args = '%s %s' % (
145 self._browser_args, parse_options.browser_extra_args)
borenetdc89ca52014-10-17 07:37:05 -0700146
rmistry49d093c2015-03-31 05:04:29 -0700147 self._chrome_page_sets_path = os.path.join(parse_options.chrome_src_path,
148 CHROMIUM_PAGE_SETS_PATH)
borenetdc89ca52014-10-17 07:37:05 -0700149 self._all_page_sets_specified = parse_options.page_sets == 'all'
150 self._page_sets = self._ParsePageSets(parse_options.page_sets)
151
borenetdc89ca52014-10-17 07:37:05 -0700152 self._record = parse_options.record
153 self._skia_tools = parse_options.skia_tools
154 self._non_interactive = parse_options.non_interactive
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700155 self._upload = parse_options.upload
rmistryaa31ee72015-04-23 12:47:33 -0700156 self._skp_prefix = parse_options.skp_prefix
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700157 data_store_location = parse_options.data_store
158 if data_store_location.startswith(gs_utils.GS_PREFIX):
159 self.gs = GoogleStorageDataStore(data_store_location)
160 else:
161 self.gs = LocalFileSystemDataStore(data_store_location)
rmistry0575c492016-02-01 10:27:05 -0800162 self._upload_to_partner_bucket = parse_options.upload_to_partner_bucket
borenetdc89ca52014-10-17 07:37:05 -0700163 self._alternate_upload_dir = parse_options.alternate_upload_dir
borenetdc89ca52014-10-17 07:37:05 -0700164 self._telemetry_binaries_dir = os.path.join(parse_options.chrome_src_path,
165 'tools', 'perf')
rmistryafaf4962016-02-27 10:04:57 -0800166 self._catapult_dir = os.path.join(parse_options.chrome_src_path,
167 'third_party', 'catapult')
borenetdc89ca52014-10-17 07:37:05 -0700168
169 self._local_skp_dir = os.path.join(
170 parse_options.output_dir, ROOT_PLAYBACK_DIR_NAME, SKPICTURES_DIR_NAME)
171 self._local_record_webpages_archive_dir = os.path.join(
172 parse_options.output_dir, ROOT_PLAYBACK_DIR_NAME, 'webpages_archive')
173
174 # List of SKP files generated by this script.
175 self._skp_files = []
176
177 def _ParsePageSets(self, page_sets):
178 if not page_sets:
179 raise ValueError('Must specify at least one page_set!')
180 elif self._all_page_sets_specified:
181 # Get everything from the page_sets directory.
182 page_sets_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)),
183 'page_sets')
184 ps = [os.path.join(page_sets_dir, page_set)
185 for page_set in os.listdir(page_sets_dir)
186 if not os.path.isdir(os.path.join(page_sets_dir, page_set)) and
187 page_set.endswith('.py')]
rmistry49d093c2015-03-31 05:04:29 -0700188 chromium_ps = [
189 os.path.join(self._chrome_page_sets_path, cr_page_set)
190 for cr_page_set in CHROMIUM_PAGE_SETS_TO_PREFIX]
191 ps.extend(chromium_ps)
borenetdc89ca52014-10-17 07:37:05 -0700192 elif '*' in page_sets:
193 # Explode and return the glob.
194 ps = glob.glob(page_sets)
195 else:
196 ps = page_sets.split(',')
197 ps.sort()
198 return ps
199
rmistry49d093c2015-03-31 05:04:29 -0700200 def _IsChromiumPageSet(self, page_set):
201 """Returns true if the specified page set is a Chromium page set."""
202 return page_set.startswith(self._chrome_page_sets_path)
203
borenetdc89ca52014-10-17 07:37:05 -0700204 def Run(self):
205 """Run the SkPicturePlayback BuildStep."""
206
rmistryf802f322014-10-22 05:04:43 -0700207 # Download the credentials file if it was not previously downloaded.
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700208 if not os.path.isfile(CREDENTIALS_FILE_PATH):
209 # Download the credentials.json file from Google Storage.
210 self.gs.download_file(CREDENTIALS_GS_PATH, CREDENTIALS_FILE_PATH)
211
212 if not os.path.isfile(CREDENTIALS_FILE_PATH):
213 print """\n\nCould not locate credentials file in the storage.
214 Please create a %s file that contains:
rmistryf802f322014-10-22 05:04:43 -0700215 {
216 "google": {
217 "username": "google_testing_account_username",
218 "password": "google_testing_account_password"
219 },
220 "facebook": {
221 "username": "facebook_testing_account_username",
222 "password": "facebook_testing_account_password"
223 }
224 }\n\n""" % CREDENTIALS_FILE_PATH
225 raw_input("Please press a key when you are ready to proceed...")
rmistryf802f322014-10-22 05:04:43 -0700226
borenetdc89ca52014-10-17 07:37:05 -0700227 # Delete any left over data files in the data directory.
228 for archive_file in glob.glob(
229 os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR, 'skia_*')):
230 os.remove(archive_file)
231
232 # Delete the local root directory if it already exists.
233 if os.path.exists(LOCAL_PLAYBACK_ROOT_DIR):
234 shutil.rmtree(LOCAL_PLAYBACK_ROOT_DIR)
235
236 # Create the required local storage directories.
237 self._CreateLocalStorageDirs()
238
239 # Start the timer.
240 start_time = time.time()
241
242 # Loop through all page_sets.
243 for page_set in self._page_sets:
244
rmistry7620bf02014-10-27 06:42:11 -0700245 page_set_basename = os.path.basename(page_set).split('.')[0]
246 page_set_json_name = page_set_basename + '.json'
borenetdc89ca52014-10-17 07:37:05 -0700247 wpr_data_file = page_set.split(os.path.sep)[-1].split('.')[0] + '_000.wpr'
rmistry7620bf02014-10-27 06:42:11 -0700248 page_set_dir = os.path.dirname(page_set)
borenetdc89ca52014-10-17 07:37:05 -0700249
rmistry49d093c2015-03-31 05:04:29 -0700250 if self._IsChromiumPageSet(page_set):
251 print 'Using Chromium\'s captured archives for Chromium\'s page sets.'
252 elif self._record:
borenetdc89ca52014-10-17 07:37:05 -0700253 # Create an archive of the specified webpages if '--record=True' is
254 # specified.
255 record_wpr_cmd = (
rmistryafaf4962016-02-27 10:04:57 -0800256 'PYTHONPATH=%s:%s:$PYTHONPATH' % (page_set_dir, self._catapult_dir),
borenetdc89ca52014-10-17 07:37:05 -0700257 'DISPLAY=%s' % X11_DISPLAY,
258 os.path.join(self._telemetry_binaries_dir, 'record_wpr'),
rmistryaa31ee72015-04-23 12:47:33 -0700259 '--extra-browser-args="%s"' % self._browser_args,
borenetdc89ca52014-10-17 07:37:05 -0700260 '--browser=exact',
261 '--browser-executable=%s' % self._browser_executable,
rmistry7620bf02014-10-27 06:42:11 -0700262 '%s_page_set' % page_set_basename,
263 '--page-set-base-dir=%s' % page_set_dir
borenetdc89ca52014-10-17 07:37:05 -0700264 )
265 for _ in range(RETRY_RECORD_WPR_COUNT):
rmistry0ec28af2014-10-28 14:25:17 -0700266 try:
267 shell_utils.run(' '.join(record_wpr_cmd), shell=True)
kkinnunenf9310fe2015-03-29 22:33:16 -0700268
269 # Move over the created archive into the local webpages archive
270 # directory.
271 shutil.move(
272 os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR, wpr_data_file),
273 self._local_record_webpages_archive_dir)
274 shutil.move(
275 os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR,
276 page_set_json_name),
277 self._local_record_webpages_archive_dir)
278
borenetdc89ca52014-10-17 07:37:05 -0700279 # Break out of the retry loop since there were no errors.
280 break
rmistry0ec28af2014-10-28 14:25:17 -0700281 except Exception:
282 # There was a failure continue with the loop.
283 traceback.print_exc()
borenetdc89ca52014-10-17 07:37:05 -0700284 else:
285 # If we get here then record_wpr did not succeed and thus did not
286 # break out of the loop.
287 raise Exception('record_wpr failed for page_set: %s' % page_set)
288
289 else:
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700290 # Get the webpages archive so that it can be replayed.
291 self._DownloadWebpagesArchive(wpr_data_file, page_set_json_name)
borenetdc89ca52014-10-17 07:37:05 -0700292
borenet78399152014-10-17 12:15:46 -0700293 run_benchmark_cmd = (
rmistryafaf4962016-02-27 10:04:57 -0800294 'PYTHONPATH=%s:%s:$PYTHONPATH' % (page_set_dir, self._catapult_dir),
borenetdc89ca52014-10-17 07:37:05 -0700295 'DISPLAY=%s' % X11_DISPLAY,
296 'timeout', '300',
borenet78399152014-10-17 12:15:46 -0700297 os.path.join(self._telemetry_binaries_dir, 'run_benchmark'),
rmistryaa31ee72015-04-23 12:47:33 -0700298 '--extra-browser-args="%s"' % self._browser_args,
borenetdc89ca52014-10-17 07:37:05 -0700299 '--browser=exact',
300 '--browser-executable=%s' % self._browser_executable,
301 SKP_BENCHMARK,
rmistry7620bf02014-10-27 06:42:11 -0700302 '--page-set-name=%s' % page_set_basename,
rmistryf802f322014-10-22 05:04:43 -0700303 '--page-set-base-dir=%s' % page_set_dir,
304 '--skp-outdir=%s' % TMP_SKP_DIR,
305 '--also-run-disabled-tests'
borenetdc89ca52014-10-17 07:37:05 -0700306 )
borenetdc89ca52014-10-17 07:37:05 -0700307
308 for _ in range(RETRY_RUN_MEASUREMENT_COUNT):
309 try:
310 print '\n\n=======Capturing SKP of %s=======\n\n' % page_set
borenet78399152014-10-17 12:15:46 -0700311 shell_utils.run(' '.join(run_benchmark_cmd), shell=True)
borenetdc89ca52014-10-17 07:37:05 -0700312 except shell_utils.CommandFailedException:
313 # skpicture_printer sometimes fails with AssertionError but the
314 # captured SKP is still valid. This is a known issue.
315 pass
316
borenetdc89ca52014-10-17 07:37:05 -0700317 # Rename generated SKP files into more descriptive names.
318 try:
319 self._RenameSkpFiles(page_set)
320 # Break out of the retry loop since there were no errors.
321 break
322 except Exception:
323 # There was a failure continue with the loop.
324 traceback.print_exc()
325 print '\n\n=======Retrying %s=======\n\n' % page_set
326 time.sleep(10)
327 else:
borenet78399152014-10-17 12:15:46 -0700328 # If we get here then run_benchmark did not succeed and thus did not
borenetdc89ca52014-10-17 07:37:05 -0700329 # break out of the loop.
borenet78399152014-10-17 12:15:46 -0700330 raise Exception('run_benchmark failed for page_set: %s' % page_set)
borenetdc89ca52014-10-17 07:37:05 -0700331
borenetdc89ca52014-10-17 07:37:05 -0700332 print '\n\n=======Capturing SKP files took %s seconds=======\n\n' % (
333 time.time() - start_time)
334
335 if self._skia_tools:
336 render_pictures_cmd = [
337 os.path.join(self._skia_tools, 'render_pictures'),
338 '-r', self._local_skp_dir
339 ]
340 render_pdfs_cmd = [
341 os.path.join(self._skia_tools, 'render_pdfs'),
kkinnunen3a6aa862014-12-03 04:22:06 -0800342 '-r', self._local_skp_dir
borenetdc89ca52014-10-17 07:37:05 -0700343 ]
344
345 for tools_cmd in (render_pictures_cmd, render_pdfs_cmd):
346 print '\n\n=======Running %s=======' % ' '.join(tools_cmd)
347 proc = subprocess.Popen(tools_cmd)
rmistry0ec28af2014-10-28 14:25:17 -0700348 (code, _) = shell_utils.log_process_after_completion(proc, echo=False)
borenetdc89ca52014-10-17 07:37:05 -0700349 if code != 0:
350 raise Exception('%s failed!' % ' '.join(tools_cmd))
351
352 if not self._non_interactive:
353 print '\n\n=======Running debugger======='
354 os.system('%s %s' % (os.path.join(self._skia_tools, 'debugger'),
kkinnunen960fb502014-12-03 06:18:12 -0800355 self._local_skp_dir))
borenetdc89ca52014-10-17 07:37:05 -0700356
357 print '\n\n'
358
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700359 if self._upload:
360 print '\n\n=======Uploading to %s=======\n\n' % self.gs.target_type()
borenetdc89ca52014-10-17 07:37:05 -0700361 # Copy the directory structure in the root directory into Google Storage.
362 dest_dir_name = ROOT_PLAYBACK_DIR_NAME
363 if self._alternate_upload_dir:
364 dest_dir_name = self._alternate_upload_dir
365
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700366 self.gs.upload_dir_contents(
rmistry009b0692015-03-31 05:20:12 -0700367 LOCAL_PLAYBACK_ROOT_DIR, dest_dir=dest_dir_name,
borenetdc89ca52014-10-17 07:37:05 -0700368 upload_if=gs_utils.GSUtils.UploadIf.IF_MODIFIED,
369 predefined_acl=GS_PREDEFINED_ACL,
370 fine_grained_acl_list=GS_FINE_GRAINED_ACL_LIST)
371
372 print '\n\n=======New SKPs have been uploaded to %s =======\n\n' % (
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700373 posixpath.join(self.gs.target_name(), dest_dir_name,
374 SKPICTURES_DIR_NAME))
rmistry0575c492016-02-01 10:27:05 -0800375
376 if self._upload_to_partner_bucket:
377 print '\n\n=======Uploading to Partner bucket %s =======\n\n' % (
378 PARTNERS_GS_BUCKET)
379 partner_gs = GoogleStorageDataStore(PARTNERS_GS_BUCKET)
rmistryc33c79c2016-02-03 04:27:54 -0800380 partner_gs.delete_path(SKPICTURES_DIR_NAME)
rmistry0575c492016-02-01 10:27:05 -0800381 partner_gs.upload_dir_contents(
382 os.path.join(LOCAL_PLAYBACK_ROOT_DIR, SKPICTURES_DIR_NAME),
rmistry8870e942016-02-02 13:55:38 -0800383 dest_dir=SKPICTURES_DIR_NAME,
rmistry0575c492016-02-01 10:27:05 -0800384 upload_if=gs_utils.GSUtils.UploadIf.IF_MODIFIED)
385 print '\n\n=======New SKPs have been uploaded to %s =======\n\n' % (
rmistry8870e942016-02-02 13:55:38 -0800386 posixpath.join(partner_gs.target_name(), SKPICTURES_DIR_NAME))
borenetdc89ca52014-10-17 07:37:05 -0700387 else:
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700388 print '\n\n=======Not Uploading to %s=======\n\n' % self.gs.target_type()
borenetdc89ca52014-10-17 07:37:05 -0700389 print 'Generated resources are available in %s\n\n' % (
390 LOCAL_PLAYBACK_ROOT_DIR)
391
392 return 0
393
rmistry49d093c2015-03-31 05:04:29 -0700394 def _GetSkiaSkpFileName(self, page_set):
395 """Returns the SKP file name for Skia page sets."""
396 # /path/to/skia_yahooanswers_desktop.py -> skia_yahooanswers_desktop.py
397 ps_filename = os.path.basename(page_set)
398 # skia_yahooanswers_desktop.py -> skia_yahooanswers_desktop
399 ps_basename, _ = os.path.splitext(ps_filename)
400 # skia_yahooanswers_desktop -> skia, yahooanswers, desktop
401 _, page_name, device = ps_basename.split('_')
402 basename = '%s_%s' % (DEVICE_TO_PLATFORM_PREFIX[device], page_name)
403 return basename[:MAX_SKP_BASE_NAME_LEN] + '.skp'
404
405 def _GetChromiumSkpFileName(self, page_set, site):
406 """Returns the SKP file name for Chromium page sets."""
407 # /path/to/http___mobile_news_sandbox_pt0 -> http___mobile_news_sandbox_pt0
408 _, webpage = os.path.split(site)
409 # http___mobile_news_sandbox_pt0 -> mobile_news_sandbox_pt0
rmistry80bd3ae2015-04-03 08:22:51 -0700410 for prefix in ('http___', 'https___', 'www_'):
rmistry2a3c8492015-03-31 10:59:15 -0700411 if webpage.startswith(prefix):
412 webpage = webpage[len(prefix):]
rmistry49d093c2015-03-31 05:04:29 -0700413 # /path/to/skia_yahooanswers_desktop.py -> skia_yahooanswers_desktop.py
414 ps_filename = os.path.basename(page_set)
415 # http___mobile_news_sandbox -> pagesetprefix_http___mobile_news_sandbox
416 basename = '%s_%s' % (CHROMIUM_PAGE_SETS_TO_PREFIX[ps_filename], webpage)
417 return basename[:MAX_SKP_BASE_NAME_LEN] + '.skp'
418
borenetdc89ca52014-10-17 07:37:05 -0700419 def _RenameSkpFiles(self, page_set):
420 """Rename generated SKP files into more descriptive names.
421
422 Look into the subdirectory of TMP_SKP_DIR and find the most interesting
423 .skp in there to be this page_set's representative .skp.
424 """
borenetdc89ca52014-10-17 07:37:05 -0700425 subdirs = glob.glob(os.path.join(TMP_SKP_DIR, '*'))
borenetdc89ca52014-10-17 07:37:05 -0700426 for site in subdirs:
rmistry49d093c2015-03-31 05:04:29 -0700427 if self._IsChromiumPageSet(page_set):
428 filename = self._GetChromiumSkpFileName(page_set, site)
429 else:
430 filename = self._GetSkiaSkpFileName(page_set)
rmistry80bd3ae2015-04-03 08:22:51 -0700431 filename = filename.lower()
rmistry49d093c2015-03-31 05:04:29 -0700432
rmistryaa31ee72015-04-23 12:47:33 -0700433 if self._skp_prefix:
434 filename = '%s%s' % (self._skp_prefix, filename)
435
borenetdc89ca52014-10-17 07:37:05 -0700436 # We choose the largest .skp as the most likely to be interesting.
437 largest_skp = max(glob.glob(os.path.join(site, '*.skp')),
438 key=lambda path: os.stat(path).st_size)
439 dest = os.path.join(self._local_skp_dir, filename)
440 print 'Moving', largest_skp, 'to', dest
441 shutil.move(largest_skp, dest)
442 self._skp_files.append(filename)
443 shutil.rmtree(site)
444
445 def _CreateLocalStorageDirs(self):
446 """Creates required local storage directories for this script."""
447 for d in (self._local_record_webpages_archive_dir,
448 self._local_skp_dir):
449 if os.path.exists(d):
450 shutil.rmtree(d)
451 os.makedirs(d)
452
rmistry7620bf02014-10-27 06:42:11 -0700453 def _DownloadWebpagesArchive(self, wpr_data_file, page_set_json_name):
borenetdc89ca52014-10-17 07:37:05 -0700454 """Downloads the webpages archive and its required page set from GS."""
455 wpr_source = posixpath.join(ROOT_PLAYBACK_DIR_NAME, 'webpages_archive',
456 wpr_data_file)
457 page_set_source = posixpath.join(ROOT_PLAYBACK_DIR_NAME,
458 'webpages_archive',
rmistry7620bf02014-10-27 06:42:11 -0700459 page_set_json_name)
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700460 gs = self.gs
461 if (gs.does_storage_object_exist(wpr_source) and
462 gs.does_storage_object_exist(page_set_source)):
463 gs.download_file(wpr_source,
borenetdc89ca52014-10-17 07:37:05 -0700464 os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR,
465 wpr_data_file))
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700466 gs.download_file(page_set_source,
borenetdc89ca52014-10-17 07:37:05 -0700467 os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR,
rmistry7620bf02014-10-27 06:42:11 -0700468 page_set_json_name))
borenetdc89ca52014-10-17 07:37:05 -0700469 else:
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700470 raise Exception('%s and %s do not exist in %s!' % (gs.target_type(),
471 wpr_source, page_set_source))
borenetdc89ca52014-10-17 07:37:05 -0700472
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700473class DataStore:
474 """An abstract base class for uploading recordings to a data storage.
475 The interface emulates the google storage api."""
476 def target_name(self):
477 raise NotImplementedError()
478 def target_type(self):
479 raise NotImplementedError()
480 def does_storage_object_exist(self, *args):
481 raise NotImplementedError()
482 def download_file(self, *args):
483 raise NotImplementedError()
484 def upload_dir_contents(self, source_dir, **kwargs):
485 raise NotImplementedError()
486
487class GoogleStorageDataStore(DataStore):
488 def __init__(self, data_store_url):
489 self._data_store_url = data_store_url
rmistry49d093c2015-03-31 05:04:29 -0700490 self._bucket = remove_prefix(self._data_store_url.lstrip(),
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700491 gs_utils.GS_PREFIX)
492 self.gs = gs_utils.GSUtils()
493 def target_name(self):
494 return self._data_store_url
495 def target_type(self):
496 return 'Google Storage'
497 def does_storage_object_exist(self, *args):
498 return self.gs.does_storage_object_exist(self._bucket, *args)
rmistryc33c79c2016-02-03 04:27:54 -0800499 def delete_path(self, path):
rmistryf5e83952016-02-03 05:58:31 -0800500 _, files = self.gs.list_bucket_contents(self._bucket, subdir=path)
501 for f in files:
502 self.gs.delete_file(self._bucket, posixpath.join(path, f))
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700503 def download_file(self, *args):
504 self.gs.download_file(self._bucket, *args)
505 def upload_dir_contents(self, source_dir, **kwargs):
506 self.gs.upload_dir_contents(source_dir, self._bucket, **kwargs)
507
508class LocalFileSystemDataStore(DataStore):
509 def __init__(self, data_store_location):
510 self._base_dir = data_store_location
511 def target_name(self):
512 return self._base_dir
513 def target_type(self):
514 return self._base_dir
515 def does_storage_object_exist(self, name, *args):
516 return os.path.isfile(os.path.join(self._base_dir, name))
rmistryc33c79c2016-02-03 04:27:54 -0800517 def delete_path(self, path):
518 shutil.rmtree(path)
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700519 def download_file(self, name, local_path, *args):
520 shutil.copyfile(os.path.join(self._base_dir, name), local_path)
521 def upload_dir_contents(self, source_dir, dest_dir, **kwargs):
522 def copytree(source_dir, dest_dir):
523 if not os.path.exists(dest_dir):
524 os.makedirs(dest_dir)
525 for item in os.listdir(source_dir):
526 source = os.path.join(source_dir, item)
527 dest = os.path.join(dest_dir, item)
528 if os.path.isdir(source):
529 copytree(source, dest)
530 else:
531 shutil.copy2(source, dest)
532 copytree(source_dir, os.path.join(self._base_dir, dest_dir))
borenetdc89ca52014-10-17 07:37:05 -0700533
534if '__main__' == __name__:
535 option_parser = optparse.OptionParser()
536 option_parser.add_option(
537 '', '--page_sets',
538 help='Specifies the page sets to use to archive. Supports globs.',
539 default='all')
540 option_parser.add_option(
borenetdc89ca52014-10-17 07:37:05 -0700541 '', '--record', action='store_true',
542 help='Specifies whether a new website archive should be created.',
543 default=False)
544 option_parser.add_option(
borenetdc89ca52014-10-17 07:37:05 -0700545 '', '--skia_tools',
546 help=('Path to compiled Skia executable tools. '
547 'render_pictures/render_pdfs is run on the set '
548 'after all SKPs are captured. If the script is run without '
549 '--non-interactive then the debugger is also run at the end. Debug '
550 'builds are recommended because they seem to catch more failures '
551 'than Release builds.'),
552 default=None)
553 option_parser.add_option(
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700554 '', '--upload', action='store_true',
555 help=('Uploads to Google Storage or copies to local filesystem storage '
556 ' if this is True.'),
borenetdc89ca52014-10-17 07:37:05 -0700557 default=False)
558 option_parser.add_option(
rmistry0575c492016-02-01 10:27:05 -0800559 '', '--upload_to_partner_bucket', action='store_true',
560 help=('Uploads SKPs to the chrome-partner-telemetry Google Storage '
561 'bucket if true.'),
562 default=False)
563 option_parser.add_option(
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700564 '', '--data_store',
565 help=('The location of the file storage to use to download and upload '
566 'files. Can be \'gs://<bucket>\' for Google Storage, or '
567 'a directory for local filesystem storage'),
568 default='gs://chromium-skia-gm')
569 option_parser.add_option(
borenetdc89ca52014-10-17 07:37:05 -0700570 '', '--alternate_upload_dir',
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700571 help= ('Uploads to a different directory in Google Storage or local '
572 'storage if this flag is specified'),
borenetdc89ca52014-10-17 07:37:05 -0700573 default=None)
574 option_parser.add_option(
575 '', '--output_dir',
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700576 help=('Temporary directory where SKPs and webpage archives will be '
577 'outputted to.'),
borenetdc89ca52014-10-17 07:37:05 -0700578 default=tempfile.gettempdir())
579 option_parser.add_option(
580 '', '--browser_executable',
581 help='The exact browser executable to run.',
582 default=None)
583 option_parser.add_option(
rmistryaa31ee72015-04-23 12:47:33 -0700584 '', '--browser_extra_args',
585 help='Additional arguments to pass to the browser.',
586 default=None)
587 option_parser.add_option(
borenetdc89ca52014-10-17 07:37:05 -0700588 '', '--chrome_src_path',
589 help='Path to the chromium src directory.',
590 default=None)
591 option_parser.add_option(
592 '', '--non-interactive', action='store_true',
593 help='Runs the script without any prompts. If this flag is specified and '
594 '--skia_tools is specified then the debugger is not run.',
595 default=False)
rmistryaa31ee72015-04-23 12:47:33 -0700596 option_parser.add_option(
597 '', '--skp_prefix',
598 help='Prefix to add to the names of generated SKPs.',
599 default=None)
borenetdc89ca52014-10-17 07:37:05 -0700600 options, unused_args = option_parser.parse_args()
601
602 playback = SkPicturePlayback(options)
603 sys.exit(playback.Run())