blob: e8dcc62b7e65ad774f1552843f6ca5963a3fda64 [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
Ravi Mistry97477112017-12-13 10:39:20 -050036The --data_store flag controls where the needed artifacts are downloaded from.
37It also controls where the generated artifacts, such as recorded webpages and
38resulting skp renderings, are uploaded to. URLs with scheme 'gs://' use Google
39Storage. Otherwise use local filesystem.
kkinnunenb4ee7ea2015-03-31 00:18:26 -070040
41The --upload=True flag means generated artifacts will be
42uploaded or copied to the location specified by --data_store. (default value is
43False if not specified).
borenetdc89ca52014-10-17 07:37:05 -070044
45The --non-interactive flag controls whether the script will prompt the user
46(default value is False if not specified).
47
48The --skia_tools flag if specified will allow this script to run
49debugger, render_pictures, and render_pdfs on the captured
50SKP(s). The tools are run after all SKPs are succesfully captured to make sure
51they can be added to the buildbots with no breakages.
borenetdc89ca52014-10-17 07:37:05 -070052"""
53
54import glob
55import optparse
56import os
57import posixpath
58import shutil
59import subprocess
60import sys
61import tempfile
62import time
63import traceback
64
borenetdc89ca52014-10-17 07:37:05 -070065
66ROOT_PLAYBACK_DIR_NAME = 'playback'
67SKPICTURES_DIR_NAME = 'skps'
68
borenet644638c2016-10-10 05:57:18 -070069GS_PREFIX = 'gs://'
70
rmistry0575c492016-02-01 10:27:05 -080071PARTNERS_GS_BUCKET = 'gs://chrome-partner-telemetry'
borenetdc89ca52014-10-17 07:37:05 -070072
73# Local archive and SKP directories.
borenetdc89ca52014-10-17 07:37:05 -070074LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR = os.path.join(
75 os.path.abspath(os.path.dirname(__file__)), 'page_sets', 'data')
76TMP_SKP_DIR = tempfile.mkdtemp()
77
borenetdc89ca52014-10-17 07:37:05 -070078# Name of the SKP benchmark
79SKP_BENCHMARK = 'skpicture_printer'
80
81# The max base name length of Skp files.
82MAX_SKP_BASE_NAME_LEN = 31
83
84# Dictionary of device to platform prefixes for SKP files.
85DEVICE_TO_PLATFORM_PREFIX = {
86 'desktop': 'desk',
87 'galaxynexus': 'mobi',
88 'nexus10': 'tabl'
89}
90
91# How many times the record_wpr binary should be retried.
92RETRY_RECORD_WPR_COUNT = 5
borenet78399152014-10-17 12:15:46 -070093# How many times the run_benchmark binary should be retried.
Ravi Mistry0f8e4db2017-11-28 11:24:32 -050094RETRY_RUN_MEASUREMENT_COUNT = 3
borenetdc89ca52014-10-17 07:37:05 -070095
96X11_DISPLAY = os.getenv('DISPLAY', ':0')
97
rmistry49d093c2015-03-31 05:04:29 -070098# Path to Chromium's page sets.
99CHROMIUM_PAGE_SETS_PATH = os.path.join('tools', 'perf', 'page_sets')
100
101# Dictionary of supported Chromium page sets to their file prefixes.
102CHROMIUM_PAGE_SETS_TO_PREFIX = {
rmistry5af9a372015-03-31 06:22:55 -0700103 'key_mobile_sites_smooth.py': 'keymobi',
rmistry2a3c8492015-03-31 10:59:15 -0700104 'top_25_smooth.py': 'top25desk',
rmistry49d093c2015-03-31 05:04:29 -0700105}
106
Ravi Mistry19ea45e2017-11-29 08:38:12 -0500107PAGE_SETS_TO_EXCLUSIONS = {
108 # See skbug.com/7348
109 'key_mobile_sites_smooth.py': '"(digg|worldjournal)"',
110}
111
rmistry49d093c2015-03-31 05:04:29 -0700112
kkinnunene75d2d22014-12-03 04:38:46 -0800113def remove_prefix(s, prefix):
114 if s.startswith(prefix):
115 return s[len(prefix):]
116 return s
borenetdc89ca52014-10-17 07:37:05 -0700117
rmistry49d093c2015-03-31 05:04:29 -0700118
borenetdc89ca52014-10-17 07:37:05 -0700119class SkPicturePlayback(object):
120 """Class that archives or replays webpages and creates SKPs."""
121
122 def __init__(self, parse_options):
123 """Constructs a SkPicturePlayback BuildStep instance."""
124 assert parse_options.browser_executable, 'Must specify --browser_executable'
125 self._browser_executable = parse_options.browser_executable
rmistryaa31ee72015-04-23 12:47:33 -0700126 self._browser_args = '--disable-setuid-sandbox'
127 if parse_options.browser_extra_args:
128 self._browser_args = '%s %s' % (
129 self._browser_args, parse_options.browser_extra_args)
borenetdc89ca52014-10-17 07:37:05 -0700130
rmistry49d093c2015-03-31 05:04:29 -0700131 self._chrome_page_sets_path = os.path.join(parse_options.chrome_src_path,
132 CHROMIUM_PAGE_SETS_PATH)
borenetdc89ca52014-10-17 07:37:05 -0700133 self._all_page_sets_specified = parse_options.page_sets == 'all'
134 self._page_sets = self._ParsePageSets(parse_options.page_sets)
135
borenetdc89ca52014-10-17 07:37:05 -0700136 self._record = parse_options.record
137 self._skia_tools = parse_options.skia_tools
138 self._non_interactive = parse_options.non_interactive
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700139 self._upload = parse_options.upload
rmistryaa31ee72015-04-23 12:47:33 -0700140 self._skp_prefix = parse_options.skp_prefix
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700141 data_store_location = parse_options.data_store
borenet644638c2016-10-10 05:57:18 -0700142 if data_store_location.startswith(GS_PREFIX):
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700143 self.gs = GoogleStorageDataStore(data_store_location)
144 else:
145 self.gs = LocalFileSystemDataStore(data_store_location)
rmistry0575c492016-02-01 10:27:05 -0800146 self._upload_to_partner_bucket = parse_options.upload_to_partner_bucket
borenetdc89ca52014-10-17 07:37:05 -0700147 self._alternate_upload_dir = parse_options.alternate_upload_dir
borenetdc89ca52014-10-17 07:37:05 -0700148 self._telemetry_binaries_dir = os.path.join(parse_options.chrome_src_path,
149 'tools', 'perf')
rmistryafaf4962016-02-27 10:04:57 -0800150 self._catapult_dir = os.path.join(parse_options.chrome_src_path,
151 'third_party', 'catapult')
borenetdc89ca52014-10-17 07:37:05 -0700152
153 self._local_skp_dir = os.path.join(
154 parse_options.output_dir, ROOT_PLAYBACK_DIR_NAME, SKPICTURES_DIR_NAME)
155 self._local_record_webpages_archive_dir = os.path.join(
156 parse_options.output_dir, ROOT_PLAYBACK_DIR_NAME, 'webpages_archive')
157
158 # List of SKP files generated by this script.
159 self._skp_files = []
160
161 def _ParsePageSets(self, page_sets):
162 if not page_sets:
163 raise ValueError('Must specify at least one page_set!')
164 elif self._all_page_sets_specified:
165 # Get everything from the page_sets directory.
166 page_sets_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)),
167 'page_sets')
168 ps = [os.path.join(page_sets_dir, page_set)
169 for page_set in os.listdir(page_sets_dir)
170 if not os.path.isdir(os.path.join(page_sets_dir, page_set)) and
171 page_set.endswith('.py')]
rmistry49d093c2015-03-31 05:04:29 -0700172 chromium_ps = [
173 os.path.join(self._chrome_page_sets_path, cr_page_set)
174 for cr_page_set in CHROMIUM_PAGE_SETS_TO_PREFIX]
175 ps.extend(chromium_ps)
borenetdc89ca52014-10-17 07:37:05 -0700176 elif '*' in page_sets:
177 # Explode and return the glob.
178 ps = glob.glob(page_sets)
179 else:
180 ps = page_sets.split(',')
181 ps.sort()
182 return ps
183
rmistry49d093c2015-03-31 05:04:29 -0700184 def _IsChromiumPageSet(self, page_set):
185 """Returns true if the specified page set is a Chromium page set."""
186 return page_set.startswith(self._chrome_page_sets_path)
187
borenetdc89ca52014-10-17 07:37:05 -0700188 def Run(self):
189 """Run the SkPicturePlayback BuildStep."""
190
191 # Delete any left over data files in the data directory.
192 for archive_file in glob.glob(
193 os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR, 'skia_*')):
194 os.remove(archive_file)
195
borenetdc89ca52014-10-17 07:37:05 -0700196 # Create the required local storage directories.
197 self._CreateLocalStorageDirs()
198
199 # Start the timer.
200 start_time = time.time()
201
202 # Loop through all page_sets.
203 for page_set in self._page_sets:
204
rmistry7620bf02014-10-27 06:42:11 -0700205 page_set_basename = os.path.basename(page_set).split('.')[0]
206 page_set_json_name = page_set_basename + '.json'
Ravi Mistry0d056ba2017-08-02 11:21:58 -0400207 wpr_data_file = (
208 page_set.split(os.path.sep)[-1].split('.')[0] + '_000.wprgo')
rmistry7620bf02014-10-27 06:42:11 -0700209 page_set_dir = os.path.dirname(page_set)
borenetdc89ca52014-10-17 07:37:05 -0700210
rmistry49d093c2015-03-31 05:04:29 -0700211 if self._IsChromiumPageSet(page_set):
212 print 'Using Chromium\'s captured archives for Chromium\'s page sets.'
213 elif self._record:
borenetdc89ca52014-10-17 07:37:05 -0700214 # Create an archive of the specified webpages if '--record=True' is
215 # specified.
216 record_wpr_cmd = (
rmistryafaf4962016-02-27 10:04:57 -0800217 'PYTHONPATH=%s:%s:$PYTHONPATH' % (page_set_dir, self._catapult_dir),
borenetdc89ca52014-10-17 07:37:05 -0700218 'DISPLAY=%s' % X11_DISPLAY,
219 os.path.join(self._telemetry_binaries_dir, 'record_wpr'),
rmistryaa31ee72015-04-23 12:47:33 -0700220 '--extra-browser-args="%s"' % self._browser_args,
borenetdc89ca52014-10-17 07:37:05 -0700221 '--browser=exact',
222 '--browser-executable=%s' % self._browser_executable,
Ravi Mistry0d056ba2017-08-02 11:21:58 -0400223 '--use-wpr-go',
rmistry7620bf02014-10-27 06:42:11 -0700224 '%s_page_set' % page_set_basename,
225 '--page-set-base-dir=%s' % page_set_dir
borenetdc89ca52014-10-17 07:37:05 -0700226 )
227 for _ in range(RETRY_RECORD_WPR_COUNT):
rmistry0ec28af2014-10-28 14:25:17 -0700228 try:
borenet644638c2016-10-10 05:57:18 -0700229 subprocess.check_call(' '.join(record_wpr_cmd), shell=True)
kkinnunenf9310fe2015-03-29 22:33:16 -0700230
Ravi Mistry863ffef2017-07-18 13:13:53 -0400231 # Copy over the created archive into the local webpages archive
kkinnunenf9310fe2015-03-29 22:33:16 -0700232 # directory.
Ravi Mistry863ffef2017-07-18 13:13:53 -0400233 shutil.copy(
kkinnunenf9310fe2015-03-29 22:33:16 -0700234 os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR, wpr_data_file),
235 self._local_record_webpages_archive_dir)
Ravi Mistry863ffef2017-07-18 13:13:53 -0400236 shutil.copy(
kkinnunenf9310fe2015-03-29 22:33:16 -0700237 os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR,
238 page_set_json_name),
239 self._local_record_webpages_archive_dir)
240
borenetdc89ca52014-10-17 07:37:05 -0700241 # Break out of the retry loop since there were no errors.
242 break
rmistry0ec28af2014-10-28 14:25:17 -0700243 except Exception:
244 # There was a failure continue with the loop.
245 traceback.print_exc()
borenetdc89ca52014-10-17 07:37:05 -0700246 else:
247 # If we get here then record_wpr did not succeed and thus did not
248 # break out of the loop.
249 raise Exception('record_wpr failed for page_set: %s' % page_set)
250
251 else:
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700252 # Get the webpages archive so that it can be replayed.
253 self._DownloadWebpagesArchive(wpr_data_file, page_set_json_name)
borenetdc89ca52014-10-17 07:37:05 -0700254
Ravi Mistry19ea45e2017-11-29 08:38:12 -0500255 run_benchmark_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,
Ravi Mistry57d69652016-09-08 09:08:44 -0400258 'timeout', '1800',
borenet78399152014-10-17 12:15:46 -0700259 os.path.join(self._telemetry_binaries_dir, 'run_benchmark'),
rmistryaa31ee72015-04-23 12:47:33 -0700260 '--extra-browser-args="%s"' % self._browser_args,
borenetdc89ca52014-10-17 07:37:05 -0700261 '--browser=exact',
262 '--browser-executable=%s' % self._browser_executable,
263 SKP_BENCHMARK,
rmistry7620bf02014-10-27 06:42:11 -0700264 '--page-set-name=%s' % page_set_basename,
rmistryf802f322014-10-22 05:04:43 -0700265 '--page-set-base-dir=%s' % page_set_dir,
266 '--skp-outdir=%s' % TMP_SKP_DIR,
Ravi Mistry0f8e4db2017-11-28 11:24:32 -0500267 '--also-run-disabled-tests',
Ravi Mistry19ea45e2017-11-29 08:38:12 -0500268 ]
269
270 exclusions = PAGE_SETS_TO_EXCLUSIONS.get(os.path.basename(page_set))
271 if exclusions:
272 run_benchmark_cmd.append('--story-filter-exclude=' + exclusions)
borenetdc89ca52014-10-17 07:37:05 -0700273
274 for _ in range(RETRY_RUN_MEASUREMENT_COUNT):
275 try:
276 print '\n\n=======Capturing SKP of %s=======\n\n' % page_set
borenet644638c2016-10-10 05:57:18 -0700277 subprocess.check_call(' '.join(run_benchmark_cmd), shell=True)
278 except subprocess.CalledProcessError:
borenetdc89ca52014-10-17 07:37:05 -0700279 # There was a failure continue with the loop.
280 traceback.print_exc()
281 print '\n\n=======Retrying %s=======\n\n' % page_set
282 time.sleep(10)
Ravi Mistry0f8e4db2017-11-28 11:24:32 -0500283 continue
284
285 # Rename generated SKP files into more descriptive names.
286 self._RenameSkpFiles(page_set)
287 # Break out of the retry loop since there were no errors.
288 break
borenetdc89ca52014-10-17 07:37:05 -0700289 else:
borenet78399152014-10-17 12:15:46 -0700290 # If we get here then run_benchmark did not succeed and thus did not
borenetdc89ca52014-10-17 07:37:05 -0700291 # break out of the loop.
borenet78399152014-10-17 12:15:46 -0700292 raise Exception('run_benchmark failed for page_set: %s' % page_set)
borenetdc89ca52014-10-17 07:37:05 -0700293
borenetdc89ca52014-10-17 07:37:05 -0700294 print '\n\n=======Capturing SKP files took %s seconds=======\n\n' % (
295 time.time() - start_time)
296
297 if self._skia_tools:
298 render_pictures_cmd = [
299 os.path.join(self._skia_tools, 'render_pictures'),
300 '-r', self._local_skp_dir
301 ]
302 render_pdfs_cmd = [
303 os.path.join(self._skia_tools, 'render_pdfs'),
kkinnunen3a6aa862014-12-03 04:22:06 -0800304 '-r', self._local_skp_dir
borenetdc89ca52014-10-17 07:37:05 -0700305 ]
306
307 for tools_cmd in (render_pictures_cmd, render_pdfs_cmd):
308 print '\n\n=======Running %s=======' % ' '.join(tools_cmd)
borenet644638c2016-10-10 05:57:18 -0700309 subprocess.check_call(tools_cmd)
borenetdc89ca52014-10-17 07:37:05 -0700310
311 if not self._non_interactive:
312 print '\n\n=======Running debugger======='
313 os.system('%s %s' % (os.path.join(self._skia_tools, 'debugger'),
kkinnunen960fb502014-12-03 06:18:12 -0800314 self._local_skp_dir))
borenetdc89ca52014-10-17 07:37:05 -0700315
316 print '\n\n'
317
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700318 if self._upload:
319 print '\n\n=======Uploading to %s=======\n\n' % self.gs.target_type()
borenetdc89ca52014-10-17 07:37:05 -0700320 # Copy the directory structure in the root directory into Google Storage.
321 dest_dir_name = ROOT_PLAYBACK_DIR_NAME
322 if self._alternate_upload_dir:
323 dest_dir_name = self._alternate_upload_dir
324
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700325 self.gs.upload_dir_contents(
borenet644638c2016-10-10 05:57:18 -0700326 self._local_skp_dir, dest_dir=dest_dir_name)
borenetdc89ca52014-10-17 07:37:05 -0700327
328 print '\n\n=======New SKPs have been uploaded to %s =======\n\n' % (
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700329 posixpath.join(self.gs.target_name(), dest_dir_name,
330 SKPICTURES_DIR_NAME))
rmistry0575c492016-02-01 10:27:05 -0800331
borenetdc89ca52014-10-17 07:37:05 -0700332 else:
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700333 print '\n\n=======Not Uploading to %s=======\n\n' % self.gs.target_type()
borenetdc89ca52014-10-17 07:37:05 -0700334 print 'Generated resources are available in %s\n\n' % (
borenet1413d522016-08-08 06:26:00 -0700335 self._local_skp_dir)
borenetdc89ca52014-10-17 07:37:05 -0700336
borenet28698472016-07-25 05:18:15 -0700337 if self._upload_to_partner_bucket:
338 print '\n\n=======Uploading to Partner bucket %s =======\n\n' % (
339 PARTNERS_GS_BUCKET)
340 partner_gs = GoogleStorageDataStore(PARTNERS_GS_BUCKET)
341 partner_gs.delete_path(SKPICTURES_DIR_NAME)
borenet1413d522016-08-08 06:26:00 -0700342 print 'Uploading %s to %s' % (self._local_skp_dir, SKPICTURES_DIR_NAME)
borenet644638c2016-10-10 05:57:18 -0700343 partner_gs.upload_dir_contents(self._local_skp_dir, SKPICTURES_DIR_NAME)
borenet28698472016-07-25 05:18:15 -0700344 print '\n\n=======New SKPs have been uploaded to %s =======\n\n' % (
345 posixpath.join(partner_gs.target_name(), SKPICTURES_DIR_NAME))
346
borenetdc89ca52014-10-17 07:37:05 -0700347 return 0
348
rmistry49d093c2015-03-31 05:04:29 -0700349 def _GetSkiaSkpFileName(self, page_set):
350 """Returns the SKP file name for Skia page sets."""
351 # /path/to/skia_yahooanswers_desktop.py -> skia_yahooanswers_desktop.py
352 ps_filename = os.path.basename(page_set)
353 # skia_yahooanswers_desktop.py -> skia_yahooanswers_desktop
354 ps_basename, _ = os.path.splitext(ps_filename)
355 # skia_yahooanswers_desktop -> skia, yahooanswers, desktop
356 _, page_name, device = ps_basename.split('_')
357 basename = '%s_%s' % (DEVICE_TO_PLATFORM_PREFIX[device], page_name)
358 return basename[:MAX_SKP_BASE_NAME_LEN] + '.skp'
359
360 def _GetChromiumSkpFileName(self, page_set, site):
361 """Returns the SKP file name for Chromium page sets."""
362 # /path/to/http___mobile_news_sandbox_pt0 -> http___mobile_news_sandbox_pt0
363 _, webpage = os.path.split(site)
364 # http___mobile_news_sandbox_pt0 -> mobile_news_sandbox_pt0
rmistry80bd3ae2015-04-03 08:22:51 -0700365 for prefix in ('http___', 'https___', 'www_'):
rmistry2a3c8492015-03-31 10:59:15 -0700366 if webpage.startswith(prefix):
367 webpage = webpage[len(prefix):]
rmistry49d093c2015-03-31 05:04:29 -0700368 # /path/to/skia_yahooanswers_desktop.py -> skia_yahooanswers_desktop.py
369 ps_filename = os.path.basename(page_set)
370 # http___mobile_news_sandbox -> pagesetprefix_http___mobile_news_sandbox
371 basename = '%s_%s' % (CHROMIUM_PAGE_SETS_TO_PREFIX[ps_filename], webpage)
372 return basename[:MAX_SKP_BASE_NAME_LEN] + '.skp'
373
borenetdc89ca52014-10-17 07:37:05 -0700374 def _RenameSkpFiles(self, page_set):
375 """Rename generated SKP files into more descriptive names.
376
377 Look into the subdirectory of TMP_SKP_DIR and find the most interesting
378 .skp in there to be this page_set's representative .skp.
379 """
borenetdc89ca52014-10-17 07:37:05 -0700380 subdirs = glob.glob(os.path.join(TMP_SKP_DIR, '*'))
borenetdc89ca52014-10-17 07:37:05 -0700381 for site in subdirs:
rmistry49d093c2015-03-31 05:04:29 -0700382 if self._IsChromiumPageSet(page_set):
383 filename = self._GetChromiumSkpFileName(page_set, site)
384 else:
385 filename = self._GetSkiaSkpFileName(page_set)
rmistry80bd3ae2015-04-03 08:22:51 -0700386 filename = filename.lower()
rmistry49d093c2015-03-31 05:04:29 -0700387
rmistryaa31ee72015-04-23 12:47:33 -0700388 if self._skp_prefix:
389 filename = '%s%s' % (self._skp_prefix, filename)
390
borenetdc89ca52014-10-17 07:37:05 -0700391 # We choose the largest .skp as the most likely to be interesting.
392 largest_skp = max(glob.glob(os.path.join(site, '*.skp')),
393 key=lambda path: os.stat(path).st_size)
394 dest = os.path.join(self._local_skp_dir, filename)
395 print 'Moving', largest_skp, 'to', dest
396 shutil.move(largest_skp, dest)
397 self._skp_files.append(filename)
398 shutil.rmtree(site)
399
400 def _CreateLocalStorageDirs(self):
401 """Creates required local storage directories for this script."""
402 for d in (self._local_record_webpages_archive_dir,
403 self._local_skp_dir):
404 if os.path.exists(d):
405 shutil.rmtree(d)
406 os.makedirs(d)
407
rmistry7620bf02014-10-27 06:42:11 -0700408 def _DownloadWebpagesArchive(self, wpr_data_file, page_set_json_name):
borenetdc89ca52014-10-17 07:37:05 -0700409 """Downloads the webpages archive and its required page set from GS."""
410 wpr_source = posixpath.join(ROOT_PLAYBACK_DIR_NAME, 'webpages_archive',
411 wpr_data_file)
412 page_set_source = posixpath.join(ROOT_PLAYBACK_DIR_NAME,
413 'webpages_archive',
rmistry7620bf02014-10-27 06:42:11 -0700414 page_set_json_name)
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700415 gs = self.gs
416 if (gs.does_storage_object_exist(wpr_source) and
417 gs.does_storage_object_exist(page_set_source)):
418 gs.download_file(wpr_source,
borenetdc89ca52014-10-17 07:37:05 -0700419 os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR,
420 wpr_data_file))
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700421 gs.download_file(page_set_source,
borenetdc89ca52014-10-17 07:37:05 -0700422 os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR,
rmistry7620bf02014-10-27 06:42:11 -0700423 page_set_json_name))
borenetdc89ca52014-10-17 07:37:05 -0700424 else:
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700425 raise Exception('%s and %s do not exist in %s!' % (gs.target_type(),
426 wpr_source, page_set_source))
borenetdc89ca52014-10-17 07:37:05 -0700427
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700428class DataStore:
429 """An abstract base class for uploading recordings to a data storage.
430 The interface emulates the google storage api."""
431 def target_name(self):
432 raise NotImplementedError()
433 def target_type(self):
434 raise NotImplementedError()
borenet644638c2016-10-10 05:57:18 -0700435 def does_storage_object_exist(self, name):
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700436 raise NotImplementedError()
borenet644638c2016-10-10 05:57:18 -0700437 def download_file(self, name, local_path):
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700438 raise NotImplementedError()
borenet644638c2016-10-10 05:57:18 -0700439 def upload_dir_contents(self, source_dir, dest_dir):
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700440 raise NotImplementedError()
441
borenet644638c2016-10-10 05:57:18 -0700442
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700443class GoogleStorageDataStore(DataStore):
444 def __init__(self, data_store_url):
borenet1cebf7b2016-10-10 08:14:11 -0700445 self._url = data_store_url.rstrip('/')
borenet644638c2016-10-10 05:57:18 -0700446
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700447 def target_name(self):
borenet644638c2016-10-10 05:57:18 -0700448 return self._url
449
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700450 def target_type(self):
451 return 'Google Storage'
borenet644638c2016-10-10 05:57:18 -0700452
453 def does_storage_object_exist(self, name):
454 try:
455 output = subprocess.check_output([
456 'gsutil', 'ls', '/'.join((self._url, name))])
457 except subprocess.CalledProcessError:
458 return False
borenet75358672016-10-10 13:20:49 -0700459 if len(output.splitlines()) != 1:
borenet644638c2016-10-10 05:57:18 -0700460 return False
461 return True
462
rmistryc33c79c2016-02-03 04:27:54 -0800463 def delete_path(self, path):
borenet77874632016-10-17 05:12:10 -0700464 subprocess.check_call(['gsutil', 'rm', '-r', '/'.join((self._url, path))])
borenet644638c2016-10-10 05:57:18 -0700465
466 def download_file(self, name, local_path):
467 subprocess.check_call([
468 'gsutil', 'cp', '/'.join((self._url, name)), local_path])
469
470 def upload_dir_contents(self, source_dir, dest_dir):
471 subprocess.check_call([
borenet27f93e02016-10-17 08:09:33 -0700472 'gsutil', 'cp', '-r', source_dir, '/'.join((self._url, dest_dir))])
borenet644638c2016-10-10 05:57:18 -0700473
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700474
475class LocalFileSystemDataStore(DataStore):
476 def __init__(self, data_store_location):
477 self._base_dir = data_store_location
478 def target_name(self):
479 return self._base_dir
480 def target_type(self):
481 return self._base_dir
borenet644638c2016-10-10 05:57:18 -0700482 def does_storage_object_exist(self, name):
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700483 return os.path.isfile(os.path.join(self._base_dir, name))
rmistryc33c79c2016-02-03 04:27:54 -0800484 def delete_path(self, path):
485 shutil.rmtree(path)
borenet644638c2016-10-10 05:57:18 -0700486 def download_file(self, name, local_path):
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700487 shutil.copyfile(os.path.join(self._base_dir, name), local_path)
borenet644638c2016-10-10 05:57:18 -0700488 def upload_dir_contents(self, source_dir, dest_dir):
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700489 def copytree(source_dir, dest_dir):
490 if not os.path.exists(dest_dir):
491 os.makedirs(dest_dir)
492 for item in os.listdir(source_dir):
493 source = os.path.join(source_dir, item)
494 dest = os.path.join(dest_dir, item)
495 if os.path.isdir(source):
496 copytree(source, dest)
497 else:
498 shutil.copy2(source, dest)
499 copytree(source_dir, os.path.join(self._base_dir, dest_dir))
borenetdc89ca52014-10-17 07:37:05 -0700500
501if '__main__' == __name__:
502 option_parser = optparse.OptionParser()
503 option_parser.add_option(
504 '', '--page_sets',
505 help='Specifies the page sets to use to archive. Supports globs.',
506 default='all')
507 option_parser.add_option(
borenetdc89ca52014-10-17 07:37:05 -0700508 '', '--record', action='store_true',
509 help='Specifies whether a new website archive should be created.',
510 default=False)
511 option_parser.add_option(
borenetdc89ca52014-10-17 07:37:05 -0700512 '', '--skia_tools',
513 help=('Path to compiled Skia executable tools. '
514 'render_pictures/render_pdfs is run on the set '
515 'after all SKPs are captured. If the script is run without '
516 '--non-interactive then the debugger is also run at the end. Debug '
517 'builds are recommended because they seem to catch more failures '
518 'than Release builds.'),
519 default=None)
520 option_parser.add_option(
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700521 '', '--upload', action='store_true',
522 help=('Uploads to Google Storage or copies to local filesystem storage '
523 ' if this is True.'),
borenetdc89ca52014-10-17 07:37:05 -0700524 default=False)
525 option_parser.add_option(
rmistry0575c492016-02-01 10:27:05 -0800526 '', '--upload_to_partner_bucket', action='store_true',
527 help=('Uploads SKPs to the chrome-partner-telemetry Google Storage '
528 'bucket if true.'),
529 default=False)
530 option_parser.add_option(
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700531 '', '--data_store',
532 help=('The location of the file storage to use to download and upload '
533 'files. Can be \'gs://<bucket>\' for Google Storage, or '
534 'a directory for local filesystem storage'),
boreneta86952a2016-10-05 08:23:04 -0700535 default='gs://skia-skps')
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700536 option_parser.add_option(
borenetdc89ca52014-10-17 07:37:05 -0700537 '', '--alternate_upload_dir',
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700538 help= ('Uploads to a different directory in Google Storage or local '
539 'storage if this flag is specified'),
borenetdc89ca52014-10-17 07:37:05 -0700540 default=None)
541 option_parser.add_option(
542 '', '--output_dir',
kkinnunenb4ee7ea2015-03-31 00:18:26 -0700543 help=('Temporary directory where SKPs and webpage archives will be '
544 'outputted to.'),
borenetdc89ca52014-10-17 07:37:05 -0700545 default=tempfile.gettempdir())
546 option_parser.add_option(
547 '', '--browser_executable',
548 help='The exact browser executable to run.',
549 default=None)
550 option_parser.add_option(
rmistryaa31ee72015-04-23 12:47:33 -0700551 '', '--browser_extra_args',
552 help='Additional arguments to pass to the browser.',
553 default=None)
554 option_parser.add_option(
borenetdc89ca52014-10-17 07:37:05 -0700555 '', '--chrome_src_path',
556 help='Path to the chromium src directory.',
557 default=None)
558 option_parser.add_option(
559 '', '--non-interactive', action='store_true',
560 help='Runs the script without any prompts. If this flag is specified and '
561 '--skia_tools is specified then the debugger is not run.',
562 default=False)
rmistryaa31ee72015-04-23 12:47:33 -0700563 option_parser.add_option(
564 '', '--skp_prefix',
565 help='Prefix to add to the names of generated SKPs.',
566 default=None)
borenetdc89ca52014-10-17 07:37:05 -0700567 options, unused_args = option_parser.parse_args()
568
569 playback = SkPicturePlayback(options)
570 sys.exit(playback.Run())