xref: /aosp_15_r20/external/skia/tools/skp/webpages_playback.py (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker#!/usr/bin/env python
2*c8dee2aaSAndroid Build Coastguard Worker# Copyright (c) 2012 The Chromium Authors. All rights reserved.
3*c8dee2aaSAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be
4*c8dee2aaSAndroid Build Coastguard Worker# found in the LICENSE file.
5*c8dee2aaSAndroid Build Coastguard Worker
6*c8dee2aaSAndroid Build Coastguard Worker"""Archives or replays webpages and creates SKPs in a Google Storage location.
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard WorkerTo archive webpages and store SKP files (archives should be rarely updated):
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Workercd skia
11*c8dee2aaSAndroid Build Coastguard Workerpython tools/skp/webpages_playback.py --data_store=gs://your-bucket-name \
12*c8dee2aaSAndroid Build Coastguard Worker--record --page_sets=all --skia_tools=/home/default/trunk/out/Debug/ \
13*c8dee2aaSAndroid Build Coastguard Worker--browser_executable=/tmp/chromium/out/Release/chrome
14*c8dee2aaSAndroid Build Coastguard Worker
15*c8dee2aaSAndroid Build Coastguard WorkerThe above command uses Google Storage bucket 'your-bucket-name' to download
16*c8dee2aaSAndroid Build Coastguard Workerneeded files.
17*c8dee2aaSAndroid Build Coastguard Worker
18*c8dee2aaSAndroid Build Coastguard WorkerTo replay archived webpages and re-generate SKP files (should be run whenever
19*c8dee2aaSAndroid Build Coastguard WorkerSkPicture.PICTURE_VERSION changes):
20*c8dee2aaSAndroid Build Coastguard Worker
21*c8dee2aaSAndroid Build Coastguard Workercd skia
22*c8dee2aaSAndroid Build Coastguard Workerpython tools/skp/webpages_playback.py --data_store=gs://your-bucket-name \
23*c8dee2aaSAndroid Build Coastguard Worker--page_sets=all --skia_tools=/home/default/trunk/out/Debug/ \
24*c8dee2aaSAndroid Build Coastguard Worker--browser_executable=/tmp/chromium/out/Release/chrome
25*c8dee2aaSAndroid Build Coastguard Worker
26*c8dee2aaSAndroid Build Coastguard Worker
27*c8dee2aaSAndroid Build Coastguard WorkerSpecify the --page_sets flag (default value is 'all') to pick a list of which
28*c8dee2aaSAndroid Build Coastguard Workerwebpages should be archived and/or replayed. Eg:
29*c8dee2aaSAndroid Build Coastguard Worker
30*c8dee2aaSAndroid Build Coastguard Worker--page_sets=tools/skp/page_sets/skia_yahooanswers_desktop.py,\
31*c8dee2aaSAndroid Build Coastguard Workertools/skp/page_sets/skia_googlecalendar_nexus10.py
32*c8dee2aaSAndroid Build Coastguard Worker
33*c8dee2aaSAndroid Build Coastguard WorkerThe --browser_executable flag should point to the browser binary you want to use
34*c8dee2aaSAndroid Build Coastguard Workerto capture archives and/or capture SKP files. Majority of the time it should be
35*c8dee2aaSAndroid Build Coastguard Workera newly built chrome binary.
36*c8dee2aaSAndroid Build Coastguard Worker
37*c8dee2aaSAndroid Build Coastguard WorkerThe --data_store flag controls where the needed artifacts are downloaded from.
38*c8dee2aaSAndroid Build Coastguard WorkerIt also controls where the generated artifacts, such as recorded webpages and
39*c8dee2aaSAndroid Build Coastguard Workerresulting skp renderings, are uploaded to. URLs with scheme 'gs://' use Google
40*c8dee2aaSAndroid Build Coastguard WorkerStorage. Otherwise use local filesystem.
41*c8dee2aaSAndroid Build Coastguard Worker
42*c8dee2aaSAndroid Build Coastguard WorkerThe --upload=True flag means generated artifacts will be
43*c8dee2aaSAndroid Build Coastguard Workeruploaded or copied to the location specified by --data_store. (default value is
44*c8dee2aaSAndroid Build Coastguard WorkerFalse if not specified).
45*c8dee2aaSAndroid Build Coastguard Worker
46*c8dee2aaSAndroid Build Coastguard WorkerThe --non-interactive flag controls whether the script will prompt the user
47*c8dee2aaSAndroid Build Coastguard Worker(default value is False if not specified).
48*c8dee2aaSAndroid Build Coastguard Worker
49*c8dee2aaSAndroid Build Coastguard WorkerThe --skia_tools flag if specified will allow this script to run
50*c8dee2aaSAndroid Build Coastguard Workerdebugger, render_pictures, and render_pdfs on the captured
51*c8dee2aaSAndroid Build Coastguard WorkerSKP(s). The tools are run after all SKPs are succesfully captured to make sure
52*c8dee2aaSAndroid Build Coastguard Workerthey can be added to the buildbots with no breakages.
53*c8dee2aaSAndroid Build Coastguard Worker"""
54*c8dee2aaSAndroid Build Coastguard Worker
55*c8dee2aaSAndroid Build Coastguard Worker
56*c8dee2aaSAndroid Build Coastguard Workerfrom __future__ import print_function
57*c8dee2aaSAndroid Build Coastguard Workerimport datetime
58*c8dee2aaSAndroid Build Coastguard Workerimport glob
59*c8dee2aaSAndroid Build Coastguard Workerimport optparse
60*c8dee2aaSAndroid Build Coastguard Workerimport os
61*c8dee2aaSAndroid Build Coastguard Workerimport posixpath
62*c8dee2aaSAndroid Build Coastguard Workerimport shutil
63*c8dee2aaSAndroid Build Coastguard Workerimport subprocess
64*c8dee2aaSAndroid Build Coastguard Workerimport sys
65*c8dee2aaSAndroid Build Coastguard Workerimport tempfile
66*c8dee2aaSAndroid Build Coastguard Workerimport time
67*c8dee2aaSAndroid Build Coastguard Workerimport traceback
68*c8dee2aaSAndroid Build Coastguard Worker
69*c8dee2aaSAndroid Build Coastguard Worker
70*c8dee2aaSAndroid Build Coastguard WorkerROOT_PLAYBACK_DIR_NAME = 'playback'
71*c8dee2aaSAndroid Build Coastguard WorkerSKPICTURES_DIR_NAME = 'skps'
72*c8dee2aaSAndroid Build Coastguard Worker
73*c8dee2aaSAndroid Build Coastguard WorkerGS_PREFIX = 'gs://'
74*c8dee2aaSAndroid Build Coastguard Worker
75*c8dee2aaSAndroid Build Coastguard WorkerPARTNERS_GS_BUCKET = 'gs://chrome-partner-telemetry'
76*c8dee2aaSAndroid Build Coastguard Worker
77*c8dee2aaSAndroid Build Coastguard Worker# Local archive and SKP directories.
78*c8dee2aaSAndroid Build Coastguard WorkerLOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR = os.path.join(
79*c8dee2aaSAndroid Build Coastguard Worker    os.path.abspath(os.path.dirname(__file__)), 'page_sets', 'data')
80*c8dee2aaSAndroid Build Coastguard WorkerTMP_SKP_DIR = tempfile.mkdtemp()
81*c8dee2aaSAndroid Build Coastguard Worker
82*c8dee2aaSAndroid Build Coastguard Worker# Location of the credentials.json file and the string that represents missing
83*c8dee2aaSAndroid Build Coastguard Worker# passwords.
84*c8dee2aaSAndroid Build Coastguard WorkerCREDENTIALS_FILE_PATH = os.path.join(
85*c8dee2aaSAndroid Build Coastguard Worker    os.path.abspath(os.path.dirname(__file__)), 'page_sets', 'data',
86*c8dee2aaSAndroid Build Coastguard Worker    'credentials.json'
87*c8dee2aaSAndroid Build Coastguard Worker)
88*c8dee2aaSAndroid Build Coastguard Worker
89*c8dee2aaSAndroid Build Coastguard Worker# Name of the SKP benchmark
90*c8dee2aaSAndroid Build Coastguard WorkerSKP_BENCHMARK = 'skpicture_printer'
91*c8dee2aaSAndroid Build Coastguard Worker
92*c8dee2aaSAndroid Build Coastguard Worker# The max base name length of Skp files.
93*c8dee2aaSAndroid Build Coastguard WorkerMAX_SKP_BASE_NAME_LEN = 31
94*c8dee2aaSAndroid Build Coastguard Worker
95*c8dee2aaSAndroid Build Coastguard Worker# Dictionary of device to platform prefixes for SKP files.
96*c8dee2aaSAndroid Build Coastguard WorkerDEVICE_TO_PLATFORM_PREFIX = {
97*c8dee2aaSAndroid Build Coastguard Worker    'desktop': 'desk',
98*c8dee2aaSAndroid Build Coastguard Worker    'mobile': 'mobi',
99*c8dee2aaSAndroid Build Coastguard Worker    'tablet': 'tabl'
100*c8dee2aaSAndroid Build Coastguard Worker}
101*c8dee2aaSAndroid Build Coastguard Worker
102*c8dee2aaSAndroid Build Coastguard Worker# How many times the record_wpr binary should be retried.
103*c8dee2aaSAndroid Build Coastguard WorkerRETRY_RECORD_WPR_COUNT = 5
104*c8dee2aaSAndroid Build Coastguard Worker# How many times the run_benchmark binary should be retried.
105*c8dee2aaSAndroid Build Coastguard WorkerRETRY_RUN_MEASUREMENT_COUNT = 3
106*c8dee2aaSAndroid Build Coastguard Worker
107*c8dee2aaSAndroid Build Coastguard Worker# Location of the credentials.json file in Google Storage.
108*c8dee2aaSAndroid Build Coastguard WorkerCREDENTIALS_GS_PATH = 'playback/credentials/credentials.json'
109*c8dee2aaSAndroid Build Coastguard Worker
110*c8dee2aaSAndroid Build Coastguard WorkerX11_DISPLAY = os.getenv('DISPLAY', ':0')
111*c8dee2aaSAndroid Build Coastguard Worker
112*c8dee2aaSAndroid Build Coastguard Worker# Path to Chromium's page sets.
113*c8dee2aaSAndroid Build Coastguard WorkerCHROMIUM_PAGE_SETS_PATH = os.path.join('tools', 'perf', 'page_sets')
114*c8dee2aaSAndroid Build Coastguard Worker
115*c8dee2aaSAndroid Build Coastguard Worker# Dictionary of supported Chromium page sets to their file prefixes.
116*c8dee2aaSAndroid Build Coastguard WorkerCHROMIUM_PAGE_SETS_TO_PREFIX = {
117*c8dee2aaSAndroid Build Coastguard Worker}
118*c8dee2aaSAndroid Build Coastguard Worker
119*c8dee2aaSAndroid Build Coastguard WorkerPAGE_SETS_TO_EXCLUSIONS = {
120*c8dee2aaSAndroid Build Coastguard Worker    # See skbug.com/7348
121*c8dee2aaSAndroid Build Coastguard Worker    'key_mobile_sites_smooth.py': '"(digg|worldjournal|twitter|espn)"',
122*c8dee2aaSAndroid Build Coastguard Worker    # See skbug.com/7421
123*c8dee2aaSAndroid Build Coastguard Worker    'top_25_smooth.py': '"(mail\.google\.com)"',
124*c8dee2aaSAndroid Build Coastguard Worker}
125*c8dee2aaSAndroid Build Coastguard Worker
126*c8dee2aaSAndroid Build Coastguard Worker
127*c8dee2aaSAndroid Build Coastguard Workerclass InvalidSKPException(Exception):
128*c8dee2aaSAndroid Build Coastguard Worker  """Raised when the created SKP is invalid."""
129*c8dee2aaSAndroid Build Coastguard Worker  pass
130*c8dee2aaSAndroid Build Coastguard Worker
131*c8dee2aaSAndroid Build Coastguard Worker
132*c8dee2aaSAndroid Build Coastguard Workerdef remove_prefix(s, prefix):
133*c8dee2aaSAndroid Build Coastguard Worker  if s.startswith(prefix):
134*c8dee2aaSAndroid Build Coastguard Worker    return s[len(prefix):]
135*c8dee2aaSAndroid Build Coastguard Worker  return s
136*c8dee2aaSAndroid Build Coastguard Worker
137*c8dee2aaSAndroid Build Coastguard Worker
138*c8dee2aaSAndroid Build Coastguard Workerclass SkPicturePlayback(object):
139*c8dee2aaSAndroid Build Coastguard Worker  """Class that archives or replays webpages and creates SKPs."""
140*c8dee2aaSAndroid Build Coastguard Worker
141*c8dee2aaSAndroid Build Coastguard Worker  def __init__(self, parse_options):
142*c8dee2aaSAndroid Build Coastguard Worker    """Constructs a SkPicturePlayback BuildStep instance."""
143*c8dee2aaSAndroid Build Coastguard Worker    assert parse_options.browser_executable, 'Must specify --browser_executable'
144*c8dee2aaSAndroid Build Coastguard Worker    self._browser_executable = parse_options.browser_executable
145*c8dee2aaSAndroid Build Coastguard Worker    self._browser_args = '--disable-setuid-sandbox --disable-field-trial-config'
146*c8dee2aaSAndroid Build Coastguard Worker    if parse_options.browser_extra_args:
147*c8dee2aaSAndroid Build Coastguard Worker      self._browser_args = '%s %s' % (
148*c8dee2aaSAndroid Build Coastguard Worker          self._browser_args, parse_options.browser_extra_args)
149*c8dee2aaSAndroid Build Coastguard Worker
150*c8dee2aaSAndroid Build Coastguard Worker    self._chrome_page_sets_path = os.path.join(parse_options.chrome_src_path,
151*c8dee2aaSAndroid Build Coastguard Worker                                               CHROMIUM_PAGE_SETS_PATH)
152*c8dee2aaSAndroid Build Coastguard Worker    self._all_page_sets_specified = parse_options.page_sets == 'all'
153*c8dee2aaSAndroid Build Coastguard Worker    self._page_sets = self._ParsePageSets(parse_options.page_sets)
154*c8dee2aaSAndroid Build Coastguard Worker
155*c8dee2aaSAndroid Build Coastguard Worker    self._record = parse_options.record
156*c8dee2aaSAndroid Build Coastguard Worker    self._skia_tools = parse_options.skia_tools
157*c8dee2aaSAndroid Build Coastguard Worker    self._non_interactive = parse_options.non_interactive
158*c8dee2aaSAndroid Build Coastguard Worker    self._upload = parse_options.upload
159*c8dee2aaSAndroid Build Coastguard Worker    self._skp_prefix = parse_options.skp_prefix
160*c8dee2aaSAndroid Build Coastguard Worker    data_store_location = parse_options.data_store
161*c8dee2aaSAndroid Build Coastguard Worker    if data_store_location.startswith(GS_PREFIX):
162*c8dee2aaSAndroid Build Coastguard Worker      self.gs = GoogleStorageDataStore(data_store_location)
163*c8dee2aaSAndroid Build Coastguard Worker    else:
164*c8dee2aaSAndroid Build Coastguard Worker      self.gs = LocalFileSystemDataStore(data_store_location)
165*c8dee2aaSAndroid Build Coastguard Worker    self._upload_to_partner_bucket = parse_options.upload_to_partner_bucket
166*c8dee2aaSAndroid Build Coastguard Worker    self._alternate_upload_dir = parse_options.alternate_upload_dir
167*c8dee2aaSAndroid Build Coastguard Worker    self._telemetry_binaries_dir = os.path.join(parse_options.chrome_src_path,
168*c8dee2aaSAndroid Build Coastguard Worker                                                'tools', 'perf')
169*c8dee2aaSAndroid Build Coastguard Worker    self._catapult_dir = os.path.join(parse_options.chrome_src_path,
170*c8dee2aaSAndroid Build Coastguard Worker                                      'third_party', 'catapult')
171*c8dee2aaSAndroid Build Coastguard Worker
172*c8dee2aaSAndroid Build Coastguard Worker    self._local_skp_dir = os.path.join(
173*c8dee2aaSAndroid Build Coastguard Worker        parse_options.output_dir, ROOT_PLAYBACK_DIR_NAME, SKPICTURES_DIR_NAME)
174*c8dee2aaSAndroid Build Coastguard Worker    self._local_record_webpages_archive_dir = os.path.join(
175*c8dee2aaSAndroid Build Coastguard Worker        parse_options.output_dir, ROOT_PLAYBACK_DIR_NAME, 'webpages_archive')
176*c8dee2aaSAndroid Build Coastguard Worker
177*c8dee2aaSAndroid Build Coastguard Worker    # List of SKP files generated by this script.
178*c8dee2aaSAndroid Build Coastguard Worker    self._skp_files = []
179*c8dee2aaSAndroid Build Coastguard Worker
180*c8dee2aaSAndroid Build Coastguard Worker  def _ParsePageSets(self, page_sets):
181*c8dee2aaSAndroid Build Coastguard Worker    if not page_sets:
182*c8dee2aaSAndroid Build Coastguard Worker      raise ValueError('Must specify at least one page_set!')
183*c8dee2aaSAndroid Build Coastguard Worker    elif self._all_page_sets_specified:
184*c8dee2aaSAndroid Build Coastguard Worker      # Get everything from the page_sets directory.
185*c8dee2aaSAndroid Build Coastguard Worker      page_sets_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)),
186*c8dee2aaSAndroid Build Coastguard Worker                                   'page_sets')
187*c8dee2aaSAndroid Build Coastguard Worker      ps = [os.path.join(page_sets_dir, page_set)
188*c8dee2aaSAndroid Build Coastguard Worker            for page_set in os.listdir(page_sets_dir)
189*c8dee2aaSAndroid Build Coastguard Worker            if not os.path.isdir(os.path.join(page_sets_dir, page_set)) and
190*c8dee2aaSAndroid Build Coastguard Worker               page_set.endswith('.py')]
191*c8dee2aaSAndroid Build Coastguard Worker      chromium_ps = [
192*c8dee2aaSAndroid Build Coastguard Worker          os.path.join(self._chrome_page_sets_path, cr_page_set)
193*c8dee2aaSAndroid Build Coastguard Worker          for cr_page_set in CHROMIUM_PAGE_SETS_TO_PREFIX]
194*c8dee2aaSAndroid Build Coastguard Worker      ps.extend(chromium_ps)
195*c8dee2aaSAndroid Build Coastguard Worker    elif '*' in page_sets:
196*c8dee2aaSAndroid Build Coastguard Worker      # Explode and return the glob.
197*c8dee2aaSAndroid Build Coastguard Worker      ps = glob.glob(page_sets)
198*c8dee2aaSAndroid Build Coastguard Worker    else:
199*c8dee2aaSAndroid Build Coastguard Worker      ps = page_sets.split(',')
200*c8dee2aaSAndroid Build Coastguard Worker    ps.sort()
201*c8dee2aaSAndroid Build Coastguard Worker    return ps
202*c8dee2aaSAndroid Build Coastguard Worker
203*c8dee2aaSAndroid Build Coastguard Worker  def _IsChromiumPageSet(self, page_set):
204*c8dee2aaSAndroid Build Coastguard Worker    """Returns true if the specified page set is a Chromium page set."""
205*c8dee2aaSAndroid Build Coastguard Worker    return page_set.startswith(self._chrome_page_sets_path)
206*c8dee2aaSAndroid Build Coastguard Worker
207*c8dee2aaSAndroid Build Coastguard Worker  def Run(self):
208*c8dee2aaSAndroid Build Coastguard Worker    """Run the SkPicturePlayback BuildStep."""
209*c8dee2aaSAndroid Build Coastguard Worker
210*c8dee2aaSAndroid Build Coastguard Worker    # Download the credentials file if it was not previously downloaded.
211*c8dee2aaSAndroid Build Coastguard Worker    if not os.path.isfile(CREDENTIALS_FILE_PATH):
212*c8dee2aaSAndroid Build Coastguard Worker      # Download the credentials.json file from Google Storage.
213*c8dee2aaSAndroid Build Coastguard Worker      self.gs.download_file(CREDENTIALS_GS_PATH, CREDENTIALS_FILE_PATH)
214*c8dee2aaSAndroid Build Coastguard Worker
215*c8dee2aaSAndroid Build Coastguard Worker    if not os.path.isfile(CREDENTIALS_FILE_PATH):
216*c8dee2aaSAndroid Build Coastguard Worker      raise Exception("""Could not locate credentials file in the storage.
217*c8dee2aaSAndroid Build Coastguard Worker      Please create a credentials file in gs://%s that contains:
218*c8dee2aaSAndroid Build Coastguard Worker      {
219*c8dee2aaSAndroid Build Coastguard Worker        "google": {
220*c8dee2aaSAndroid Build Coastguard Worker          "username": "google_testing_account_username",
221*c8dee2aaSAndroid Build Coastguard Worker          "password": "google_testing_account_password"
222*c8dee2aaSAndroid Build Coastguard Worker        }
223*c8dee2aaSAndroid Build Coastguard Worker      }\n\n""" % CREDENTIALS_GS_PATH)
224*c8dee2aaSAndroid Build Coastguard Worker
225*c8dee2aaSAndroid Build Coastguard Worker    # Delete any left over data files in the data directory.
226*c8dee2aaSAndroid Build Coastguard Worker    for archive_file in glob.glob(
227*c8dee2aaSAndroid Build Coastguard Worker        os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR, 'skia_*')):
228*c8dee2aaSAndroid Build Coastguard Worker      os.remove(archive_file)
229*c8dee2aaSAndroid Build Coastguard Worker
230*c8dee2aaSAndroid Build Coastguard Worker    # Create the required local storage directories.
231*c8dee2aaSAndroid Build Coastguard Worker    self._CreateLocalStorageDirs()
232*c8dee2aaSAndroid Build Coastguard Worker
233*c8dee2aaSAndroid Build Coastguard Worker    # Start the timer.
234*c8dee2aaSAndroid Build Coastguard Worker    start_time = time.time()
235*c8dee2aaSAndroid Build Coastguard Worker
236*c8dee2aaSAndroid Build Coastguard Worker    # Loop through all page_sets.
237*c8dee2aaSAndroid Build Coastguard Worker    for page_set in self._page_sets:
238*c8dee2aaSAndroid Build Coastguard Worker      if os.path.basename(page_set) == '__init__.py':
239*c8dee2aaSAndroid Build Coastguard Worker        continue
240*c8dee2aaSAndroid Build Coastguard Worker      page_set_basename = os.path.basename(page_set).split('.')[0]
241*c8dee2aaSAndroid Build Coastguard Worker      page_set_json_name = page_set_basename + '.json'
242*c8dee2aaSAndroid Build Coastguard Worker      wpr_data_file_glob = (
243*c8dee2aaSAndroid Build Coastguard Worker          page_set.split(os.path.sep)[-1].split('.')[0] + '_*.wprgo')
244*c8dee2aaSAndroid Build Coastguard Worker      page_set_dir = os.path.dirname(page_set)
245*c8dee2aaSAndroid Build Coastguard Worker
246*c8dee2aaSAndroid Build Coastguard Worker      if self._IsChromiumPageSet(page_set):
247*c8dee2aaSAndroid Build Coastguard Worker        print('Using Chromium\'s captured archives for Chromium\'s page sets.')
248*c8dee2aaSAndroid Build Coastguard Worker      elif self._record:
249*c8dee2aaSAndroid Build Coastguard Worker        # Create an archive of the specified webpages if '--record=True' is
250*c8dee2aaSAndroid Build Coastguard Worker        # specified.
251*c8dee2aaSAndroid Build Coastguard Worker        record_wpr_cmd = (
252*c8dee2aaSAndroid Build Coastguard Worker          'PYTHONPATH=%s:%s:$PYTHONPATH' % (page_set_dir, self._catapult_dir),
253*c8dee2aaSAndroid Build Coastguard Worker          'DISPLAY=%s' % X11_DISPLAY,
254*c8dee2aaSAndroid Build Coastguard Worker          os.path.join(self._telemetry_binaries_dir, 'record_wpr'),
255*c8dee2aaSAndroid Build Coastguard Worker          '--extra-browser-args="%s"' % self._browser_args,
256*c8dee2aaSAndroid Build Coastguard Worker          '--browser=exact',
257*c8dee2aaSAndroid Build Coastguard Worker          '--browser-executable=%s' % self._browser_executable,
258*c8dee2aaSAndroid Build Coastguard Worker          '%s_page_set' % page_set_basename,
259*c8dee2aaSAndroid Build Coastguard Worker          '--page-set-base-dir=%s' % page_set_dir
260*c8dee2aaSAndroid Build Coastguard Worker        )
261*c8dee2aaSAndroid Build Coastguard Worker        for _ in range(RETRY_RECORD_WPR_COUNT):
262*c8dee2aaSAndroid Build Coastguard Worker          try:
263*c8dee2aaSAndroid Build Coastguard Worker            subprocess.check_call(' '.join(record_wpr_cmd), shell=True)
264*c8dee2aaSAndroid Build Coastguard Worker
265*c8dee2aaSAndroid Build Coastguard Worker            # Copy over the created archive into the local webpages archive
266*c8dee2aaSAndroid Build Coastguard Worker            # directory.
267*c8dee2aaSAndroid Build Coastguard Worker            for wpr_data_file in glob.glob(os.path.join(
268*c8dee2aaSAndroid Build Coastguard Worker                LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR, wpr_data_file_glob)):
269*c8dee2aaSAndroid Build Coastguard Worker              shutil.copy(
270*c8dee2aaSAndroid Build Coastguard Worker                os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR, wpr_data_file),
271*c8dee2aaSAndroid Build Coastguard Worker                self._local_record_webpages_archive_dir)
272*c8dee2aaSAndroid Build Coastguard Worker            shutil.copy(
273*c8dee2aaSAndroid Build Coastguard Worker              os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR,
274*c8dee2aaSAndroid Build Coastguard Worker                           page_set_json_name),
275*c8dee2aaSAndroid Build Coastguard Worker              self._local_record_webpages_archive_dir)
276*c8dee2aaSAndroid Build Coastguard Worker
277*c8dee2aaSAndroid Build Coastguard Worker            # Break out of the retry loop since there were no errors.
278*c8dee2aaSAndroid Build Coastguard Worker            break
279*c8dee2aaSAndroid Build Coastguard Worker          except Exception:
280*c8dee2aaSAndroid Build Coastguard Worker            # There was a failure continue with the loop.
281*c8dee2aaSAndroid Build Coastguard Worker            traceback.print_exc()
282*c8dee2aaSAndroid Build Coastguard Worker        else:
283*c8dee2aaSAndroid Build Coastguard Worker          # If we get here then record_wpr did not succeed and thus did not
284*c8dee2aaSAndroid Build Coastguard Worker          # break out of the loop.
285*c8dee2aaSAndroid Build Coastguard Worker          raise Exception('record_wpr failed for page_set: %s' % page_set)
286*c8dee2aaSAndroid Build Coastguard Worker
287*c8dee2aaSAndroid Build Coastguard Worker      else:
288*c8dee2aaSAndroid Build Coastguard Worker        # Get the webpages archive so that it can be replayed.
289*c8dee2aaSAndroid Build Coastguard Worker        self._DownloadWebpagesArchive(wpr_data_file_glob, page_set_json_name)
290*c8dee2aaSAndroid Build Coastguard Worker
291*c8dee2aaSAndroid Build Coastguard Worker      run_benchmark_cmd = [
292*c8dee2aaSAndroid Build Coastguard Worker          'PYTHONPATH=%s:%s:$PYTHONPATH' % (page_set_dir, self._catapult_dir),
293*c8dee2aaSAndroid Build Coastguard Worker          'DISPLAY=%s' % X11_DISPLAY,
294*c8dee2aaSAndroid Build Coastguard Worker          'timeout', '1800',
295*c8dee2aaSAndroid Build Coastguard Worker          os.path.join(self._telemetry_binaries_dir, 'run_benchmark'),
296*c8dee2aaSAndroid Build Coastguard Worker          '--extra-browser-args="%s"' % self._browser_args,
297*c8dee2aaSAndroid Build Coastguard Worker          '--browser=exact',
298*c8dee2aaSAndroid Build Coastguard Worker          '--browser-executable=%s' % self._browser_executable,
299*c8dee2aaSAndroid Build Coastguard Worker          SKP_BENCHMARK,
300*c8dee2aaSAndroid Build Coastguard Worker          '--page-set-name=%s' % page_set_basename,
301*c8dee2aaSAndroid Build Coastguard Worker          '--page-set-base-dir=%s' % page_set_dir,
302*c8dee2aaSAndroid Build Coastguard Worker          '--skp-outdir=%s' % TMP_SKP_DIR,
303*c8dee2aaSAndroid Build Coastguard Worker          '--also-run-disabled-tests',
304*c8dee2aaSAndroid Build Coastguard Worker      ]
305*c8dee2aaSAndroid Build Coastguard Worker
306*c8dee2aaSAndroid Build Coastguard Worker      exclusions = PAGE_SETS_TO_EXCLUSIONS.get(os.path.basename(page_set))
307*c8dee2aaSAndroid Build Coastguard Worker      if exclusions:
308*c8dee2aaSAndroid Build Coastguard Worker        run_benchmark_cmd.append('--story-filter-exclude=' + exclusions)
309*c8dee2aaSAndroid Build Coastguard Worker
310*c8dee2aaSAndroid Build Coastguard Worker      for _ in range(RETRY_RUN_MEASUREMENT_COUNT):
311*c8dee2aaSAndroid Build Coastguard Worker        try:
312*c8dee2aaSAndroid Build Coastguard Worker          print('\n\n=======Capturing SKP of %s=======\n\n' % page_set)
313*c8dee2aaSAndroid Build Coastguard Worker          subprocess.check_call(' '.join(run_benchmark_cmd), shell=True)
314*c8dee2aaSAndroid Build Coastguard Worker        except subprocess.CalledProcessError:
315*c8dee2aaSAndroid Build Coastguard Worker          # There was a failure continue with the loop.
316*c8dee2aaSAndroid Build Coastguard Worker          traceback.print_exc()
317*c8dee2aaSAndroid Build Coastguard Worker          print('\n\n=======Retrying %s=======\n\n' % page_set)
318*c8dee2aaSAndroid Build Coastguard Worker          time.sleep(10)
319*c8dee2aaSAndroid Build Coastguard Worker          continue
320*c8dee2aaSAndroid Build Coastguard Worker
321*c8dee2aaSAndroid Build Coastguard Worker        try:
322*c8dee2aaSAndroid Build Coastguard Worker          # Rename generated SKP files into more descriptive names.
323*c8dee2aaSAndroid Build Coastguard Worker          self._RenameSkpFiles(page_set)
324*c8dee2aaSAndroid Build Coastguard Worker        except InvalidSKPException:
325*c8dee2aaSAndroid Build Coastguard Worker          # There was a failure continue with the loop.
326*c8dee2aaSAndroid Build Coastguard Worker          traceback.print_exc()
327*c8dee2aaSAndroid Build Coastguard Worker          print('\n\n=======Retrying %s=======\n\n' % page_set)
328*c8dee2aaSAndroid Build Coastguard Worker          time.sleep(10)
329*c8dee2aaSAndroid Build Coastguard Worker          continue
330*c8dee2aaSAndroid Build Coastguard Worker
331*c8dee2aaSAndroid Build Coastguard Worker        # Break out of the retry loop since there were no errors.
332*c8dee2aaSAndroid Build Coastguard Worker        break
333*c8dee2aaSAndroid Build Coastguard Worker      else:
334*c8dee2aaSAndroid Build Coastguard Worker        # If we get here then run_benchmark did not succeed and thus did not
335*c8dee2aaSAndroid Build Coastguard Worker        # break out of the loop.
336*c8dee2aaSAndroid Build Coastguard Worker        raise Exception('run_benchmark failed for page_set: %s' % page_set)
337*c8dee2aaSAndroid Build Coastguard Worker
338*c8dee2aaSAndroid Build Coastguard Worker    print('\n\n=======Capturing SKP files took %s seconds=======\n\n' % (
339*c8dee2aaSAndroid Build Coastguard Worker          time.time() - start_time))
340*c8dee2aaSAndroid Build Coastguard Worker
341*c8dee2aaSAndroid Build Coastguard Worker    if self._skia_tools:
342*c8dee2aaSAndroid Build Coastguard Worker      render_pictures_cmd = [
343*c8dee2aaSAndroid Build Coastguard Worker          os.path.join(self._skia_tools, 'render_pictures'),
344*c8dee2aaSAndroid Build Coastguard Worker          '-r', self._local_skp_dir
345*c8dee2aaSAndroid Build Coastguard Worker      ]
346*c8dee2aaSAndroid Build Coastguard Worker      render_pdfs_cmd = [
347*c8dee2aaSAndroid Build Coastguard Worker          os.path.join(self._skia_tools, 'render_pdfs'),
348*c8dee2aaSAndroid Build Coastguard Worker          '-r', self._local_skp_dir
349*c8dee2aaSAndroid Build Coastguard Worker      ]
350*c8dee2aaSAndroid Build Coastguard Worker
351*c8dee2aaSAndroid Build Coastguard Worker      for tools_cmd in (render_pictures_cmd, render_pdfs_cmd):
352*c8dee2aaSAndroid Build Coastguard Worker        print('\n\n=======Running %s=======' % ' '.join(tools_cmd))
353*c8dee2aaSAndroid Build Coastguard Worker        subprocess.check_call(tools_cmd)
354*c8dee2aaSAndroid Build Coastguard Worker
355*c8dee2aaSAndroid Build Coastguard Worker      if not self._non_interactive:
356*c8dee2aaSAndroid Build Coastguard Worker        print('\n\n=======Running debugger=======')
357*c8dee2aaSAndroid Build Coastguard Worker        os.system('%s %s' % (os.path.join(self._skia_tools, 'debugger'),
358*c8dee2aaSAndroid Build Coastguard Worker                             self._local_skp_dir))
359*c8dee2aaSAndroid Build Coastguard Worker
360*c8dee2aaSAndroid Build Coastguard Worker    print('\n\n')
361*c8dee2aaSAndroid Build Coastguard Worker
362*c8dee2aaSAndroid Build Coastguard Worker    if self._upload:
363*c8dee2aaSAndroid Build Coastguard Worker      print('\n\n=======Uploading to %s=======\n\n' % self.gs.target_type())
364*c8dee2aaSAndroid Build Coastguard Worker      # Copy the directory structure in the root directory into Google Storage.
365*c8dee2aaSAndroid Build Coastguard Worker      dest_dir_name = ROOT_PLAYBACK_DIR_NAME
366*c8dee2aaSAndroid Build Coastguard Worker      if self._alternate_upload_dir:
367*c8dee2aaSAndroid Build Coastguard Worker        dest_dir_name = self._alternate_upload_dir
368*c8dee2aaSAndroid Build Coastguard Worker
369*c8dee2aaSAndroid Build Coastguard Worker      self.gs.upload_dir_contents(
370*c8dee2aaSAndroid Build Coastguard Worker          self._local_skp_dir, dest_dir=dest_dir_name)
371*c8dee2aaSAndroid Build Coastguard Worker
372*c8dee2aaSAndroid Build Coastguard Worker      print('\n\n=======New SKPs have been uploaded to %s =======\n\n' %
373*c8dee2aaSAndroid Build Coastguard Worker            posixpath.join(self.gs.target_name(), dest_dir_name,
374*c8dee2aaSAndroid Build Coastguard Worker                           SKPICTURES_DIR_NAME))
375*c8dee2aaSAndroid Build Coastguard Worker
376*c8dee2aaSAndroid Build Coastguard Worker    else:
377*c8dee2aaSAndroid Build Coastguard Worker      print('\n\n=======Not Uploading to %s=======\n\n' % self.gs.target_type())
378*c8dee2aaSAndroid Build Coastguard Worker      print('Generated resources are available in %s\n\n' % self._local_skp_dir)
379*c8dee2aaSAndroid Build Coastguard Worker
380*c8dee2aaSAndroid Build Coastguard Worker    if self._upload_to_partner_bucket:
381*c8dee2aaSAndroid Build Coastguard Worker      print('\n\n=======Uploading to Partner bucket %s =======\n\n' %
382*c8dee2aaSAndroid Build Coastguard Worker            PARTNERS_GS_BUCKET)
383*c8dee2aaSAndroid Build Coastguard Worker      partner_gs = GoogleStorageDataStore(PARTNERS_GS_BUCKET)
384*c8dee2aaSAndroid Build Coastguard Worker      timestamp = datetime.datetime.utcnow().strftime('%Y-%m-%d')
385*c8dee2aaSAndroid Build Coastguard Worker      upload_dir = posixpath.join(SKPICTURES_DIR_NAME, timestamp)
386*c8dee2aaSAndroid Build Coastguard Worker      try:
387*c8dee2aaSAndroid Build Coastguard Worker        partner_gs.delete_path(upload_dir)
388*c8dee2aaSAndroid Build Coastguard Worker      except subprocess.CalledProcessError:
389*c8dee2aaSAndroid Build Coastguard Worker        print('Cannot delete %s because it does not exist yet.' % upload_dir)
390*c8dee2aaSAndroid Build Coastguard Worker      print('Uploading %s to %s' % (self._local_skp_dir, upload_dir))
391*c8dee2aaSAndroid Build Coastguard Worker      partner_gs.upload_dir_contents(self._local_skp_dir, upload_dir)
392*c8dee2aaSAndroid Build Coastguard Worker      print('\n\n=======New SKPs have been uploaded to %s =======\n\n' %
393*c8dee2aaSAndroid Build Coastguard Worker            posixpath.join(partner_gs.target_name(), upload_dir))
394*c8dee2aaSAndroid Build Coastguard Worker
395*c8dee2aaSAndroid Build Coastguard Worker    return 0
396*c8dee2aaSAndroid Build Coastguard Worker
397*c8dee2aaSAndroid Build Coastguard Worker  def _GetSkiaSkpFileName(self, page_set):
398*c8dee2aaSAndroid Build Coastguard Worker    """Returns the SKP file name for Skia page sets."""
399*c8dee2aaSAndroid Build Coastguard Worker    # /path/to/skia_yahooanswers_desktop.py -> skia_yahooanswers_desktop.py
400*c8dee2aaSAndroid Build Coastguard Worker    ps_filename = os.path.basename(page_set)
401*c8dee2aaSAndroid Build Coastguard Worker    # skia_yahooanswers_desktop.py -> skia_yahooanswers_desktop
402*c8dee2aaSAndroid Build Coastguard Worker    ps_basename, _ = os.path.splitext(ps_filename)
403*c8dee2aaSAndroid Build Coastguard Worker    # skia_yahooanswers_desktop -> skia, yahooanswers, desktop
404*c8dee2aaSAndroid Build Coastguard Worker    _, page_name, device = ps_basename.split('_')
405*c8dee2aaSAndroid Build Coastguard Worker    basename = '%s_%s' % (DEVICE_TO_PLATFORM_PREFIX[device], page_name)
406*c8dee2aaSAndroid Build Coastguard Worker    return basename[:MAX_SKP_BASE_NAME_LEN] + '.skp'
407*c8dee2aaSAndroid Build Coastguard Worker
408*c8dee2aaSAndroid Build Coastguard Worker  def _GetChromiumSkpFileName(self, page_set, site):
409*c8dee2aaSAndroid Build Coastguard Worker    """Returns the SKP file name for Chromium page sets."""
410*c8dee2aaSAndroid Build Coastguard Worker    # /path/to/http___mobile_news_sandbox_pt0 -> http___mobile_news_sandbox_pt0
411*c8dee2aaSAndroid Build Coastguard Worker    _, webpage = os.path.split(site)
412*c8dee2aaSAndroid Build Coastguard Worker    # http___mobile_news_sandbox_pt0 -> mobile_news_sandbox_pt0
413*c8dee2aaSAndroid Build Coastguard Worker    for prefix in ('http___', 'https___', 'www_'):
414*c8dee2aaSAndroid Build Coastguard Worker      if webpage.startswith(prefix):
415*c8dee2aaSAndroid Build Coastguard Worker        webpage = webpage[len(prefix):]
416*c8dee2aaSAndroid Build Coastguard Worker    # /path/to/skia_yahooanswers_desktop.py -> skia_yahooanswers_desktop.py
417*c8dee2aaSAndroid Build Coastguard Worker    ps_filename = os.path.basename(page_set)
418*c8dee2aaSAndroid Build Coastguard Worker    # http___mobile_news_sandbox -> pagesetprefix_http___mobile_news_sandbox
419*c8dee2aaSAndroid Build Coastguard Worker    basename = '%s_%s' % (CHROMIUM_PAGE_SETS_TO_PREFIX[ps_filename], webpage)
420*c8dee2aaSAndroid Build Coastguard Worker    return basename[:MAX_SKP_BASE_NAME_LEN] + '.skp'
421*c8dee2aaSAndroid Build Coastguard Worker
422*c8dee2aaSAndroid Build Coastguard Worker  def _RenameSkpFiles(self, page_set):
423*c8dee2aaSAndroid Build Coastguard Worker    """Rename generated SKP files into more descriptive names.
424*c8dee2aaSAndroid Build Coastguard Worker
425*c8dee2aaSAndroid Build Coastguard Worker    Look into the subdirectory of TMP_SKP_DIR and find the most interesting
426*c8dee2aaSAndroid Build Coastguard Worker    .skp in there to be this page_set's representative .skp.
427*c8dee2aaSAndroid Build Coastguard Worker
428*c8dee2aaSAndroid Build Coastguard Worker    Throws InvalidSKPException if the chosen .skp is less than 1KB. This
429*c8dee2aaSAndroid Build Coastguard Worker    typically happens when there is a 404 or a redirect loop. Anything greater
430*c8dee2aaSAndroid Build Coastguard Worker    than 1KB seems to have captured at least some useful information.
431*c8dee2aaSAndroid Build Coastguard Worker    """
432*c8dee2aaSAndroid Build Coastguard Worker    subdirs = glob.glob(os.path.join(TMP_SKP_DIR, '*'))
433*c8dee2aaSAndroid Build Coastguard Worker    for site in subdirs:
434*c8dee2aaSAndroid Build Coastguard Worker      if self._IsChromiumPageSet(page_set):
435*c8dee2aaSAndroid Build Coastguard Worker        filename = self._GetChromiumSkpFileName(page_set, site)
436*c8dee2aaSAndroid Build Coastguard Worker      else:
437*c8dee2aaSAndroid Build Coastguard Worker        filename = self._GetSkiaSkpFileName(page_set)
438*c8dee2aaSAndroid Build Coastguard Worker      filename = filename.lower()
439*c8dee2aaSAndroid Build Coastguard Worker
440*c8dee2aaSAndroid Build Coastguard Worker      if self._skp_prefix:
441*c8dee2aaSAndroid Build Coastguard Worker        filename = '%s%s' % (self._skp_prefix, filename)
442*c8dee2aaSAndroid Build Coastguard Worker
443*c8dee2aaSAndroid Build Coastguard Worker      # We choose the largest .skp as the most likely to be interesting.
444*c8dee2aaSAndroid Build Coastguard Worker      largest_skp = max(glob.glob(os.path.join(site, '*.skp')),
445*c8dee2aaSAndroid Build Coastguard Worker                        key=lambda path: os.stat(path).st_size)
446*c8dee2aaSAndroid Build Coastguard Worker      dest = os.path.join(self._local_skp_dir, filename)
447*c8dee2aaSAndroid Build Coastguard Worker      print('Moving', largest_skp, 'to', dest)
448*c8dee2aaSAndroid Build Coastguard Worker      shutil.move(largest_skp, dest)
449*c8dee2aaSAndroid Build Coastguard Worker      self._skp_files.append(filename)
450*c8dee2aaSAndroid Build Coastguard Worker      shutil.rmtree(site)
451*c8dee2aaSAndroid Build Coastguard Worker      skp_size = os.path.getsize(dest)
452*c8dee2aaSAndroid Build Coastguard Worker      if skp_size < 1024:
453*c8dee2aaSAndroid Build Coastguard Worker        raise InvalidSKPException(
454*c8dee2aaSAndroid Build Coastguard Worker            'Size of %s is only %d. Something is wrong.' % (dest, skp_size))
455*c8dee2aaSAndroid Build Coastguard Worker
456*c8dee2aaSAndroid Build Coastguard Worker
457*c8dee2aaSAndroid Build Coastguard Worker  def _CreateLocalStorageDirs(self):
458*c8dee2aaSAndroid Build Coastguard Worker    """Creates required local storage directories for this script."""
459*c8dee2aaSAndroid Build Coastguard Worker    for d in (self._local_record_webpages_archive_dir,
460*c8dee2aaSAndroid Build Coastguard Worker              self._local_skp_dir):
461*c8dee2aaSAndroid Build Coastguard Worker      if os.path.exists(d):
462*c8dee2aaSAndroid Build Coastguard Worker        shutil.rmtree(d)
463*c8dee2aaSAndroid Build Coastguard Worker      os.makedirs(d)
464*c8dee2aaSAndroid Build Coastguard Worker
465*c8dee2aaSAndroid Build Coastguard Worker  def _DownloadWebpagesArchive(self, wpr_data_file, page_set_json_name):
466*c8dee2aaSAndroid Build Coastguard Worker    """Downloads the webpages archive and its required page set from GS."""
467*c8dee2aaSAndroid Build Coastguard Worker    wpr_source = posixpath.join(ROOT_PLAYBACK_DIR_NAME, 'webpages_archive',
468*c8dee2aaSAndroid Build Coastguard Worker                                wpr_data_file)
469*c8dee2aaSAndroid Build Coastguard Worker    page_set_source = posixpath.join(ROOT_PLAYBACK_DIR_NAME,
470*c8dee2aaSAndroid Build Coastguard Worker                                     'webpages_archive',
471*c8dee2aaSAndroid Build Coastguard Worker                                     page_set_json_name)
472*c8dee2aaSAndroid Build Coastguard Worker    gs = self.gs
473*c8dee2aaSAndroid Build Coastguard Worker    if (gs.does_storage_object_exist(wpr_source) and
474*c8dee2aaSAndroid Build Coastguard Worker        gs.does_storage_object_exist(page_set_source)):
475*c8dee2aaSAndroid Build Coastguard Worker      gs.download_file(wpr_source, LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR)
476*c8dee2aaSAndroid Build Coastguard Worker      gs.download_file(page_set_source,
477*c8dee2aaSAndroid Build Coastguard Worker                       os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR,
478*c8dee2aaSAndroid Build Coastguard Worker                                    page_set_json_name))
479*c8dee2aaSAndroid Build Coastguard Worker    else:
480*c8dee2aaSAndroid Build Coastguard Worker      raise Exception('%s and %s do not exist in %s!' % (gs.target_type(),
481*c8dee2aaSAndroid Build Coastguard Worker        wpr_source, page_set_source))
482*c8dee2aaSAndroid Build Coastguard Worker
483*c8dee2aaSAndroid Build Coastguard Workerclass DataStore:
484*c8dee2aaSAndroid Build Coastguard Worker  """An abstract base class for uploading recordings to a data storage.
485*c8dee2aaSAndroid Build Coastguard Worker  The interface emulates the google storage api."""
486*c8dee2aaSAndroid Build Coastguard Worker  def target_name(self):
487*c8dee2aaSAndroid Build Coastguard Worker    raise NotImplementedError()
488*c8dee2aaSAndroid Build Coastguard Worker  def target_type(self):
489*c8dee2aaSAndroid Build Coastguard Worker    raise NotImplementedError()
490*c8dee2aaSAndroid Build Coastguard Worker  def does_storage_object_exist(self, name):
491*c8dee2aaSAndroid Build Coastguard Worker    raise NotImplementedError()
492*c8dee2aaSAndroid Build Coastguard Worker  def download_file(self, name, local_path):
493*c8dee2aaSAndroid Build Coastguard Worker    raise NotImplementedError()
494*c8dee2aaSAndroid Build Coastguard Worker  def upload_dir_contents(self, source_dir, dest_dir):
495*c8dee2aaSAndroid Build Coastguard Worker    raise NotImplementedError()
496*c8dee2aaSAndroid Build Coastguard Worker
497*c8dee2aaSAndroid Build Coastguard Worker
498*c8dee2aaSAndroid Build Coastguard Workerclass GoogleStorageDataStore(DataStore):
499*c8dee2aaSAndroid Build Coastguard Worker  def __init__(self, data_store_url):
500*c8dee2aaSAndroid Build Coastguard Worker    self._url = data_store_url.rstrip('/')
501*c8dee2aaSAndroid Build Coastguard Worker
502*c8dee2aaSAndroid Build Coastguard Worker  def target_name(self):
503*c8dee2aaSAndroid Build Coastguard Worker    return self._url
504*c8dee2aaSAndroid Build Coastguard Worker
505*c8dee2aaSAndroid Build Coastguard Worker  def target_type(self):
506*c8dee2aaSAndroid Build Coastguard Worker    return 'Google Storage'
507*c8dee2aaSAndroid Build Coastguard Worker
508*c8dee2aaSAndroid Build Coastguard Worker  def does_storage_object_exist(self, name):
509*c8dee2aaSAndroid Build Coastguard Worker    try:
510*c8dee2aaSAndroid Build Coastguard Worker      output = subprocess.check_output([
511*c8dee2aaSAndroid Build Coastguard Worker          'gsutil', 'ls', '/'.join((self._url, name))])
512*c8dee2aaSAndroid Build Coastguard Worker    except subprocess.CalledProcessError:
513*c8dee2aaSAndroid Build Coastguard Worker      return False
514*c8dee2aaSAndroid Build Coastguard Worker    if len(output.splitlines()) != 1:
515*c8dee2aaSAndroid Build Coastguard Worker      return False
516*c8dee2aaSAndroid Build Coastguard Worker    return True
517*c8dee2aaSAndroid Build Coastguard Worker
518*c8dee2aaSAndroid Build Coastguard Worker  def delete_path(self, path):
519*c8dee2aaSAndroid Build Coastguard Worker    subprocess.check_call(['gsutil', 'rm', '-r', '/'.join((self._url, path))])
520*c8dee2aaSAndroid Build Coastguard Worker
521*c8dee2aaSAndroid Build Coastguard Worker  def download_file(self, name, local_path):
522*c8dee2aaSAndroid Build Coastguard Worker    subprocess.check_call([
523*c8dee2aaSAndroid Build Coastguard Worker        'gsutil', 'cp', '/'.join((self._url, name)), local_path])
524*c8dee2aaSAndroid Build Coastguard Worker
525*c8dee2aaSAndroid Build Coastguard Worker  def upload_dir_contents(self, source_dir, dest_dir):
526*c8dee2aaSAndroid Build Coastguard Worker    subprocess.check_call([
527*c8dee2aaSAndroid Build Coastguard Worker        'gsutil', 'cp', '-r', source_dir, '/'.join((self._url, dest_dir))])
528*c8dee2aaSAndroid Build Coastguard Worker
529*c8dee2aaSAndroid Build Coastguard Worker
530*c8dee2aaSAndroid Build Coastguard Workerclass LocalFileSystemDataStore(DataStore):
531*c8dee2aaSAndroid Build Coastguard Worker  def __init__(self, data_store_location):
532*c8dee2aaSAndroid Build Coastguard Worker    self._base_dir = data_store_location
533*c8dee2aaSAndroid Build Coastguard Worker  def target_name(self):
534*c8dee2aaSAndroid Build Coastguard Worker    return self._base_dir
535*c8dee2aaSAndroid Build Coastguard Worker  def target_type(self):
536*c8dee2aaSAndroid Build Coastguard Worker    return self._base_dir
537*c8dee2aaSAndroid Build Coastguard Worker  def does_storage_object_exist(self, name):
538*c8dee2aaSAndroid Build Coastguard Worker    return os.path.isfile(os.path.join(self._base_dir, name))
539*c8dee2aaSAndroid Build Coastguard Worker  def delete_path(self, path):
540*c8dee2aaSAndroid Build Coastguard Worker    shutil.rmtree(path)
541*c8dee2aaSAndroid Build Coastguard Worker  def download_file(self, name, local_path):
542*c8dee2aaSAndroid Build Coastguard Worker    shutil.copyfile(os.path.join(self._base_dir, name), local_path)
543*c8dee2aaSAndroid Build Coastguard Worker  def upload_dir_contents(self, source_dir, dest_dir):
544*c8dee2aaSAndroid Build Coastguard Worker    def copytree(source_dir, dest_dir):
545*c8dee2aaSAndroid Build Coastguard Worker      if not os.path.exists(dest_dir):
546*c8dee2aaSAndroid Build Coastguard Worker        os.makedirs(dest_dir)
547*c8dee2aaSAndroid Build Coastguard Worker      for item in os.listdir(source_dir):
548*c8dee2aaSAndroid Build Coastguard Worker        source = os.path.join(source_dir, item)
549*c8dee2aaSAndroid Build Coastguard Worker        dest = os.path.join(dest_dir, item)
550*c8dee2aaSAndroid Build Coastguard Worker        if os.path.isdir(source):
551*c8dee2aaSAndroid Build Coastguard Worker          copytree(source, dest)
552*c8dee2aaSAndroid Build Coastguard Worker        else:
553*c8dee2aaSAndroid Build Coastguard Worker          shutil.copy2(source, dest)
554*c8dee2aaSAndroid Build Coastguard Worker    copytree(source_dir, os.path.join(self._base_dir, dest_dir))
555*c8dee2aaSAndroid Build Coastguard Worker
556*c8dee2aaSAndroid Build Coastguard Workerif '__main__' == __name__:
557*c8dee2aaSAndroid Build Coastguard Worker  option_parser = optparse.OptionParser()
558*c8dee2aaSAndroid Build Coastguard Worker  option_parser.add_option(
559*c8dee2aaSAndroid Build Coastguard Worker      '', '--page_sets',
560*c8dee2aaSAndroid Build Coastguard Worker      help='Specifies the page sets to use to archive. Supports globs.',
561*c8dee2aaSAndroid Build Coastguard Worker      default='all')
562*c8dee2aaSAndroid Build Coastguard Worker  option_parser.add_option(
563*c8dee2aaSAndroid Build Coastguard Worker      '', '--record', action='store_true',
564*c8dee2aaSAndroid Build Coastguard Worker      help='Specifies whether a new website archive should be created.',
565*c8dee2aaSAndroid Build Coastguard Worker      default=False)
566*c8dee2aaSAndroid Build Coastguard Worker  option_parser.add_option(
567*c8dee2aaSAndroid Build Coastguard Worker      '', '--skia_tools',
568*c8dee2aaSAndroid Build Coastguard Worker      help=('Path to compiled Skia executable tools. '
569*c8dee2aaSAndroid Build Coastguard Worker            'render_pictures/render_pdfs is run on the set '
570*c8dee2aaSAndroid Build Coastguard Worker            'after all SKPs are captured. If the script is run without '
571*c8dee2aaSAndroid Build Coastguard Worker            '--non-interactive then the debugger is also run at the end. Debug '
572*c8dee2aaSAndroid Build Coastguard Worker            'builds are recommended because they seem to catch more failures '
573*c8dee2aaSAndroid Build Coastguard Worker            'than Release builds.'),
574*c8dee2aaSAndroid Build Coastguard Worker      default=None)
575*c8dee2aaSAndroid Build Coastguard Worker  option_parser.add_option(
576*c8dee2aaSAndroid Build Coastguard Worker      '', '--upload', action='store_true',
577*c8dee2aaSAndroid Build Coastguard Worker      help=('Uploads to Google Storage or copies to local filesystem storage '
578*c8dee2aaSAndroid Build Coastguard Worker            ' if this is True.'),
579*c8dee2aaSAndroid Build Coastguard Worker      default=False)
580*c8dee2aaSAndroid Build Coastguard Worker  option_parser.add_option(
581*c8dee2aaSAndroid Build Coastguard Worker      '', '--upload_to_partner_bucket', action='store_true',
582*c8dee2aaSAndroid Build Coastguard Worker      help=('Uploads SKPs to the chrome-partner-telemetry Google Storage '
583*c8dee2aaSAndroid Build Coastguard Worker            'bucket if true.'),
584*c8dee2aaSAndroid Build Coastguard Worker      default=False)
585*c8dee2aaSAndroid Build Coastguard Worker  option_parser.add_option(
586*c8dee2aaSAndroid Build Coastguard Worker      '', '--data_store',
587*c8dee2aaSAndroid Build Coastguard Worker    help=('The location of the file storage to use to download and upload '
588*c8dee2aaSAndroid Build Coastguard Worker          'files. Can be \'gs://<bucket>\' for Google Storage, or '
589*c8dee2aaSAndroid Build Coastguard Worker          'a directory for local filesystem storage'),
590*c8dee2aaSAndroid Build Coastguard Worker      default='gs://skia-skps')
591*c8dee2aaSAndroid Build Coastguard Worker  option_parser.add_option(
592*c8dee2aaSAndroid Build Coastguard Worker      '', '--alternate_upload_dir',
593*c8dee2aaSAndroid Build Coastguard Worker      help= ('Uploads to a different directory in Google Storage or local '
594*c8dee2aaSAndroid Build Coastguard Worker             'storage if this flag is specified'),
595*c8dee2aaSAndroid Build Coastguard Worker      default=None)
596*c8dee2aaSAndroid Build Coastguard Worker  option_parser.add_option(
597*c8dee2aaSAndroid Build Coastguard Worker      '', '--output_dir',
598*c8dee2aaSAndroid Build Coastguard Worker      help=('Temporary directory where SKPs and webpage archives will be '
599*c8dee2aaSAndroid Build Coastguard Worker            'outputted to.'),
600*c8dee2aaSAndroid Build Coastguard Worker      default=tempfile.gettempdir())
601*c8dee2aaSAndroid Build Coastguard Worker  option_parser.add_option(
602*c8dee2aaSAndroid Build Coastguard Worker      '', '--browser_executable',
603*c8dee2aaSAndroid Build Coastguard Worker      help='The exact browser executable to run.',
604*c8dee2aaSAndroid Build Coastguard Worker      default=None)
605*c8dee2aaSAndroid Build Coastguard Worker  option_parser.add_option(
606*c8dee2aaSAndroid Build Coastguard Worker      '', '--browser_extra_args',
607*c8dee2aaSAndroid Build Coastguard Worker      help='Additional arguments to pass to the browser.',
608*c8dee2aaSAndroid Build Coastguard Worker      default=None)
609*c8dee2aaSAndroid Build Coastguard Worker  option_parser.add_option(
610*c8dee2aaSAndroid Build Coastguard Worker      '', '--chrome_src_path',
611*c8dee2aaSAndroid Build Coastguard Worker      help='Path to the chromium src directory.',
612*c8dee2aaSAndroid Build Coastguard Worker      default=None)
613*c8dee2aaSAndroid Build Coastguard Worker  option_parser.add_option(
614*c8dee2aaSAndroid Build Coastguard Worker      '', '--non-interactive', action='store_true',
615*c8dee2aaSAndroid Build Coastguard Worker      help='Runs the script without any prompts. If this flag is specified and '
616*c8dee2aaSAndroid Build Coastguard Worker           '--skia_tools is specified then the debugger is not run.',
617*c8dee2aaSAndroid Build Coastguard Worker      default=False)
618*c8dee2aaSAndroid Build Coastguard Worker  option_parser.add_option(
619*c8dee2aaSAndroid Build Coastguard Worker      '', '--skp_prefix',
620*c8dee2aaSAndroid Build Coastguard Worker      help='Prefix to add to the names of generated SKPs.',
621*c8dee2aaSAndroid Build Coastguard Worker      default=None)
622*c8dee2aaSAndroid Build Coastguard Worker  options, unused_args = option_parser.parse_args()
623*c8dee2aaSAndroid Build Coastguard Worker
624*c8dee2aaSAndroid Build Coastguard Worker  playback = SkPicturePlayback(options)
625*c8dee2aaSAndroid Build Coastguard Worker  sys.exit(playback.Run())
626