OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Archives or replays webpages and creates SKPs in a Google Storage location. | 6 """Archives or replays webpages and creates SKPs in a Google Storage location. |
7 | 7 |
8 To archive webpages and store SKP files (archives should be rarely updated): | 8 To archive webpages and store SKP files (archives should be rarely updated): |
9 | 9 |
10 cd skia | 10 cd skia |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 import optparse | 56 import optparse |
57 import os | 57 import os |
58 import posixpath | 58 import posixpath |
59 import shutil | 59 import shutil |
60 import subprocess | 60 import subprocess |
61 import sys | 61 import sys |
62 import tempfile | 62 import tempfile |
63 import time | 63 import time |
64 import traceback | 64 import traceback |
65 | 65 |
66 SKIA_DIR = os.path.abspath(os.path.join( | |
67 os.path.realpath(os.path.dirname(__file__)), | |
68 os.pardir, os.pardir)) | |
69 sys.path.insert(0, SKIA_DIR) | |
70 | |
71 from common.py.utils import gs_utils | |
72 from common.py.utils import shell_utils | |
73 | 66 |
74 ROOT_PLAYBACK_DIR_NAME = 'playback' | 67 ROOT_PLAYBACK_DIR_NAME = 'playback' |
75 SKPICTURES_DIR_NAME = 'skps' | 68 SKPICTURES_DIR_NAME = 'skps' |
76 | 69 |
| 70 GS_PREFIX = 'gs://' |
| 71 |
77 PARTNERS_GS_BUCKET = 'gs://chrome-partner-telemetry' | 72 PARTNERS_GS_BUCKET = 'gs://chrome-partner-telemetry' |
78 | 73 |
79 # Local archive and SKP directories. | 74 # Local archive and SKP directories. |
80 LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR = os.path.join( | 75 LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR = os.path.join( |
81 os.path.abspath(os.path.dirname(__file__)), 'page_sets', 'data') | 76 os.path.abspath(os.path.dirname(__file__)), 'page_sets', 'data') |
82 TMP_SKP_DIR = tempfile.mkdtemp() | 77 TMP_SKP_DIR = tempfile.mkdtemp() |
83 | 78 |
84 # Location of the credentials.json file and the string that represents missing | 79 # Location of the credentials.json file and the string that represents missing |
85 # passwords. | 80 # passwords. |
86 CREDENTIALS_FILE_PATH = os.path.join( | 81 CREDENTIALS_FILE_PATH = os.path.join( |
(...skipping 17 matching lines...) Expand all Loading... |
104 # How many times the record_wpr binary should be retried. | 99 # How many times the record_wpr binary should be retried. |
105 RETRY_RECORD_WPR_COUNT = 5 | 100 RETRY_RECORD_WPR_COUNT = 5 |
106 # How many times the run_benchmark binary should be retried. | 101 # How many times the run_benchmark binary should be retried. |
107 RETRY_RUN_MEASUREMENT_COUNT = 5 | 102 RETRY_RUN_MEASUREMENT_COUNT = 5 |
108 | 103 |
109 # Location of the credentials.json file in Google Storage. | 104 # Location of the credentials.json file in Google Storage. |
110 CREDENTIALS_GS_PATH = '/playback/credentials/credentials.json' | 105 CREDENTIALS_GS_PATH = '/playback/credentials/credentials.json' |
111 | 106 |
112 X11_DISPLAY = os.getenv('DISPLAY', ':0') | 107 X11_DISPLAY = os.getenv('DISPLAY', ':0') |
113 | 108 |
114 GS_PREDEFINED_ACL = gs_utils.GSUtils.PredefinedACL.PRIVATE | |
115 GS_FINE_GRAINED_ACL_LIST = [ | |
116 (gs_utils.GSUtils.IdType.GROUP_BY_DOMAIN, 'google.com', | |
117 gs_utils.GSUtils.Permission.READ), | |
118 ] | |
119 | |
120 # Path to Chromium's page sets. | 109 # Path to Chromium's page sets. |
121 CHROMIUM_PAGE_SETS_PATH = os.path.join('tools', 'perf', 'page_sets') | 110 CHROMIUM_PAGE_SETS_PATH = os.path.join('tools', 'perf', 'page_sets') |
122 | 111 |
123 # Dictionary of supported Chromium page sets to their file prefixes. | 112 # Dictionary of supported Chromium page sets to their file prefixes. |
124 CHROMIUM_PAGE_SETS_TO_PREFIX = { | 113 CHROMIUM_PAGE_SETS_TO_PREFIX = { |
125 'key_mobile_sites_smooth.py': 'keymobi', | 114 'key_mobile_sites_smooth.py': 'keymobi', |
126 'top_25_smooth.py': 'top25desk', | 115 'top_25_smooth.py': 'top25desk', |
127 } | 116 } |
128 | 117 |
129 | 118 |
(...skipping 19 matching lines...) Expand all Loading... |
149 CHROMIUM_PAGE_SETS_PATH) | 138 CHROMIUM_PAGE_SETS_PATH) |
150 self._all_page_sets_specified = parse_options.page_sets == 'all' | 139 self._all_page_sets_specified = parse_options.page_sets == 'all' |
151 self._page_sets = self._ParsePageSets(parse_options.page_sets) | 140 self._page_sets = self._ParsePageSets(parse_options.page_sets) |
152 | 141 |
153 self._record = parse_options.record | 142 self._record = parse_options.record |
154 self._skia_tools = parse_options.skia_tools | 143 self._skia_tools = parse_options.skia_tools |
155 self._non_interactive = parse_options.non_interactive | 144 self._non_interactive = parse_options.non_interactive |
156 self._upload = parse_options.upload | 145 self._upload = parse_options.upload |
157 self._skp_prefix = parse_options.skp_prefix | 146 self._skp_prefix = parse_options.skp_prefix |
158 data_store_location = parse_options.data_store | 147 data_store_location = parse_options.data_store |
159 if data_store_location.startswith(gs_utils.GS_PREFIX): | 148 if data_store_location.startswith(GS_PREFIX): |
160 self.gs = GoogleStorageDataStore(data_store_location) | 149 self.gs = GoogleStorageDataStore(data_store_location) |
161 else: | 150 else: |
162 self.gs = LocalFileSystemDataStore(data_store_location) | 151 self.gs = LocalFileSystemDataStore(data_store_location) |
163 self._upload_to_partner_bucket = parse_options.upload_to_partner_bucket | 152 self._upload_to_partner_bucket = parse_options.upload_to_partner_bucket |
164 self._alternate_upload_dir = parse_options.alternate_upload_dir | 153 self._alternate_upload_dir = parse_options.alternate_upload_dir |
165 self._telemetry_binaries_dir = os.path.join(parse_options.chrome_src_path, | 154 self._telemetry_binaries_dir = os.path.join(parse_options.chrome_src_path, |
166 'tools', 'perf') | 155 'tools', 'perf') |
167 self._catapult_dir = os.path.join(parse_options.chrome_src_path, | 156 self._catapult_dir = os.path.join(parse_options.chrome_src_path, |
168 'third_party', 'catapult') | 157 'third_party', 'catapult') |
169 | 158 |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
254 'DISPLAY=%s' % X11_DISPLAY, | 243 'DISPLAY=%s' % X11_DISPLAY, |
255 os.path.join(self._telemetry_binaries_dir, 'record_wpr'), | 244 os.path.join(self._telemetry_binaries_dir, 'record_wpr'), |
256 '--extra-browser-args="%s"' % self._browser_args, | 245 '--extra-browser-args="%s"' % self._browser_args, |
257 '--browser=exact', | 246 '--browser=exact', |
258 '--browser-executable=%s' % self._browser_executable, | 247 '--browser-executable=%s' % self._browser_executable, |
259 '%s_page_set' % page_set_basename, | 248 '%s_page_set' % page_set_basename, |
260 '--page-set-base-dir=%s' % page_set_dir | 249 '--page-set-base-dir=%s' % page_set_dir |
261 ) | 250 ) |
262 for _ in range(RETRY_RECORD_WPR_COUNT): | 251 for _ in range(RETRY_RECORD_WPR_COUNT): |
263 try: | 252 try: |
264 shell_utils.run(' '.join(record_wpr_cmd), shell=True) | 253 subprocess.check_call(' '.join(record_wpr_cmd), shell=True) |
265 | 254 |
266 # Move over the created archive into the local webpages archive | 255 # Move over the created archive into the local webpages archive |
267 # directory. | 256 # directory. |
268 shutil.move( | 257 shutil.move( |
269 os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR, wpr_data_file), | 258 os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR, wpr_data_file), |
270 self._local_record_webpages_archive_dir) | 259 self._local_record_webpages_archive_dir) |
271 shutil.move( | 260 shutil.move( |
272 os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR, | 261 os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR, |
273 page_set_json_name), | 262 page_set_json_name), |
274 self._local_record_webpages_archive_dir) | 263 self._local_record_webpages_archive_dir) |
(...skipping 23 matching lines...) Expand all Loading... |
298 SKP_BENCHMARK, | 287 SKP_BENCHMARK, |
299 '--page-set-name=%s' % page_set_basename, | 288 '--page-set-name=%s' % page_set_basename, |
300 '--page-set-base-dir=%s' % page_set_dir, | 289 '--page-set-base-dir=%s' % page_set_dir, |
301 '--skp-outdir=%s' % TMP_SKP_DIR, | 290 '--skp-outdir=%s' % TMP_SKP_DIR, |
302 '--also-run-disabled-tests' | 291 '--also-run-disabled-tests' |
303 ) | 292 ) |
304 | 293 |
305 for _ in range(RETRY_RUN_MEASUREMENT_COUNT): | 294 for _ in range(RETRY_RUN_MEASUREMENT_COUNT): |
306 try: | 295 try: |
307 print '\n\n=======Capturing SKP of %s=======\n\n' % page_set | 296 print '\n\n=======Capturing SKP of %s=======\n\n' % page_set |
308 shell_utils.run(' '.join(run_benchmark_cmd), shell=True) | 297 subprocess.check_call(' '.join(run_benchmark_cmd), shell=True) |
309 except shell_utils.CommandFailedException: | 298 except subprocess.CalledProcessError: |
310 # skpicture_printer sometimes fails with AssertionError but the | 299 # skpicture_printer sometimes fails with AssertionError but the |
311 # captured SKP is still valid. This is a known issue. | 300 # captured SKP is still valid. This is a known issue. |
312 pass | 301 pass |
313 | 302 |
314 # Rename generated SKP files into more descriptive names. | 303 # Rename generated SKP files into more descriptive names. |
315 try: | 304 try: |
316 self._RenameSkpFiles(page_set) | 305 self._RenameSkpFiles(page_set) |
317 # Break out of the retry loop since there were no errors. | 306 # Break out of the retry loop since there were no errors. |
318 break | 307 break |
319 except Exception: | 308 except Exception: |
(...skipping 14 matching lines...) Expand all Loading... |
334 os.path.join(self._skia_tools, 'render_pictures'), | 323 os.path.join(self._skia_tools, 'render_pictures'), |
335 '-r', self._local_skp_dir | 324 '-r', self._local_skp_dir |
336 ] | 325 ] |
337 render_pdfs_cmd = [ | 326 render_pdfs_cmd = [ |
338 os.path.join(self._skia_tools, 'render_pdfs'), | 327 os.path.join(self._skia_tools, 'render_pdfs'), |
339 '-r', self._local_skp_dir | 328 '-r', self._local_skp_dir |
340 ] | 329 ] |
341 | 330 |
342 for tools_cmd in (render_pictures_cmd, render_pdfs_cmd): | 331 for tools_cmd in (render_pictures_cmd, render_pdfs_cmd): |
343 print '\n\n=======Running %s=======' % ' '.join(tools_cmd) | 332 print '\n\n=======Running %s=======' % ' '.join(tools_cmd) |
344 proc = subprocess.Popen(tools_cmd) | 333 subprocess.check_call(tools_cmd) |
345 (code, _) = shell_utils.log_process_after_completion(proc, echo=False) | |
346 if code != 0: | |
347 raise Exception('%s failed!' % ' '.join(tools_cmd)) | |
348 | 334 |
349 if not self._non_interactive: | 335 if not self._non_interactive: |
350 print '\n\n=======Running debugger=======' | 336 print '\n\n=======Running debugger=======' |
351 os.system('%s %s' % (os.path.join(self._skia_tools, 'debugger'), | 337 os.system('%s %s' % (os.path.join(self._skia_tools, 'debugger'), |
352 self._local_skp_dir)) | 338 self._local_skp_dir)) |
353 | 339 |
354 print '\n\n' | 340 print '\n\n' |
355 | 341 |
356 if self._upload: | 342 if self._upload: |
357 print '\n\n=======Uploading to %s=======\n\n' % self.gs.target_type() | 343 print '\n\n=======Uploading to %s=======\n\n' % self.gs.target_type() |
358 # Copy the directory structure in the root directory into Google Storage. | 344 # Copy the directory structure in the root directory into Google Storage. |
359 dest_dir_name = ROOT_PLAYBACK_DIR_NAME | 345 dest_dir_name = ROOT_PLAYBACK_DIR_NAME |
360 if self._alternate_upload_dir: | 346 if self._alternate_upload_dir: |
361 dest_dir_name = self._alternate_upload_dir | 347 dest_dir_name = self._alternate_upload_dir |
362 | 348 |
363 self.gs.upload_dir_contents( | 349 self.gs.upload_dir_contents( |
364 self._local_skp_dir, dest_dir=dest_dir_name, | 350 self._local_skp_dir, dest_dir=dest_dir_name) |
365 upload_if=gs_utils.GSUtils.UploadIf.IF_MODIFIED, | |
366 predefined_acl=GS_PREDEFINED_ACL, | |
367 fine_grained_acl_list=GS_FINE_GRAINED_ACL_LIST) | |
368 | 351 |
369 print '\n\n=======New SKPs have been uploaded to %s =======\n\n' % ( | 352 print '\n\n=======New SKPs have been uploaded to %s =======\n\n' % ( |
370 posixpath.join(self.gs.target_name(), dest_dir_name, | 353 posixpath.join(self.gs.target_name(), dest_dir_name, |
371 SKPICTURES_DIR_NAME)) | 354 SKPICTURES_DIR_NAME)) |
372 | 355 |
373 else: | 356 else: |
374 print '\n\n=======Not Uploading to %s=======\n\n' % self.gs.target_type() | 357 print '\n\n=======Not Uploading to %s=======\n\n' % self.gs.target_type() |
375 print 'Generated resources are available in %s\n\n' % ( | 358 print 'Generated resources are available in %s\n\n' % ( |
376 self._local_skp_dir) | 359 self._local_skp_dir) |
377 | 360 |
378 if self._upload_to_partner_bucket: | 361 if self._upload_to_partner_bucket: |
379 print '\n\n=======Uploading to Partner bucket %s =======\n\n' % ( | 362 print '\n\n=======Uploading to Partner bucket %s =======\n\n' % ( |
380 PARTNERS_GS_BUCKET) | 363 PARTNERS_GS_BUCKET) |
381 partner_gs = GoogleStorageDataStore(PARTNERS_GS_BUCKET) | 364 partner_gs = GoogleStorageDataStore(PARTNERS_GS_BUCKET) |
382 partner_gs.delete_path(SKPICTURES_DIR_NAME) | 365 partner_gs.delete_path(SKPICTURES_DIR_NAME) |
383 print 'Uploading %s to %s' % (self._local_skp_dir, SKPICTURES_DIR_NAME) | 366 print 'Uploading %s to %s' % (self._local_skp_dir, SKPICTURES_DIR_NAME) |
384 partner_gs.upload_dir_contents( | 367 partner_gs.upload_dir_contents(self._local_skp_dir, SKPICTURES_DIR_NAME) |
385 self._local_skp_dir, | |
386 dest_dir=SKPICTURES_DIR_NAME, | |
387 upload_if=gs_utils.GSUtils.UploadIf.IF_MODIFIED) | |
388 print '\n\n=======New SKPs have been uploaded to %s =======\n\n' % ( | 368 print '\n\n=======New SKPs have been uploaded to %s =======\n\n' % ( |
389 posixpath.join(partner_gs.target_name(), SKPICTURES_DIR_NAME)) | 369 posixpath.join(partner_gs.target_name(), SKPICTURES_DIR_NAME)) |
390 | 370 |
391 return 0 | 371 return 0 |
392 | 372 |
393 def _GetSkiaSkpFileName(self, page_set): | 373 def _GetSkiaSkpFileName(self, page_set): |
394 """Returns the SKP file name for Skia page sets.""" | 374 """Returns the SKP file name for Skia page sets.""" |
395 # /path/to/skia_yahooanswers_desktop.py -> skia_yahooanswers_desktop.py | 375 # /path/to/skia_yahooanswers_desktop.py -> skia_yahooanswers_desktop.py |
396 ps_filename = os.path.basename(page_set) | 376 ps_filename = os.path.basename(page_set) |
397 # skia_yahooanswers_desktop.py -> skia_yahooanswers_desktop | 377 # skia_yahooanswers_desktop.py -> skia_yahooanswers_desktop |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
469 raise Exception('%s and %s do not exist in %s!' % (gs.target_type(), | 449 raise Exception('%s and %s do not exist in %s!' % (gs.target_type(), |
470 wpr_source, page_set_source)) | 450 wpr_source, page_set_source)) |
471 | 451 |
472 class DataStore: | 452 class DataStore: |
473 """An abstract base class for uploading recordings to a data storage. | 453 """An abstract base class for uploading recordings to a data storage. |
474 The interface emulates the google storage api.""" | 454 The interface emulates the google storage api.""" |
475 def target_name(self): | 455 def target_name(self): |
476 raise NotImplementedError() | 456 raise NotImplementedError() |
477 def target_type(self): | 457 def target_type(self): |
478 raise NotImplementedError() | 458 raise NotImplementedError() |
479 def does_storage_object_exist(self, *args): | 459 def does_storage_object_exist(self, name): |
480 raise NotImplementedError() | 460 raise NotImplementedError() |
481 def download_file(self, *args): | 461 def download_file(self, name, local_path): |
482 raise NotImplementedError() | 462 raise NotImplementedError() |
483 def upload_dir_contents(self, source_dir, **kwargs): | 463 def upload_dir_contents(self, source_dir, dest_dir): |
484 raise NotImplementedError() | 464 raise NotImplementedError() |
485 | 465 |
| 466 |
486 class GoogleStorageDataStore(DataStore): | 467 class GoogleStorageDataStore(DataStore): |
487 def __init__(self, data_store_url): | 468 def __init__(self, data_store_url): |
488 self._data_store_url = data_store_url | 469 self._url = data_store_url |
489 self._bucket = remove_prefix(self._data_store_url.lstrip(), | 470 |
490 gs_utils.GS_PREFIX) | |
491 self.gs = gs_utils.GSUtils() | |
492 def target_name(self): | 471 def target_name(self): |
493 return self._data_store_url | 472 return self._url |
| 473 |
494 def target_type(self): | 474 def target_type(self): |
495 return 'Google Storage' | 475 return 'Google Storage' |
496 def does_storage_object_exist(self, *args): | 476 |
497 return self.gs.does_storage_object_exist(self._bucket, *args) | 477 def does_storage_object_exist(self, name): |
| 478 try: |
| 479 output = subprocess.check_output([ |
| 480 'gsutil', 'ls', '/'.join((self._url, name))]) |
| 481 except subprocess.CalledProcessError: |
| 482 return False |
| 483 if len(output.splitlines) != 1: |
| 484 return False |
| 485 return True |
| 486 |
498 def delete_path(self, path): | 487 def delete_path(self, path): |
499 _, files = self.gs.list_bucket_contents(self._bucket, subdir=path) | 488 subprocess.check_call(['gsutil', 'rm', '-r', path]) |
500 for f in files: | 489 |
501 self.gs.delete_file(self._bucket, posixpath.join(path, f)) | 490 def download_file(self, name, local_path): |
502 def download_file(self, *args): | 491 subprocess.check_call([ |
503 self.gs.download_file(self._bucket, *args) | 492 'gsutil', 'cp', '/'.join((self._url, name)), local_path]) |
504 def upload_dir_contents(self, source_dir, **kwargs): | 493 |
505 self.gs.upload_dir_contents(source_dir, self._bucket, **kwargs) | 494 def upload_dir_contents(self, source_dir, dest_dir): |
| 495 subprocess.check_call([ |
| 496 'gsutil', 'cp', '-r', source_dir, '/'.join(self._url, dest_dir)]) |
| 497 |
506 | 498 |
507 class LocalFileSystemDataStore(DataStore): | 499 class LocalFileSystemDataStore(DataStore): |
508 def __init__(self, data_store_location): | 500 def __init__(self, data_store_location): |
509 self._base_dir = data_store_location | 501 self._base_dir = data_store_location |
510 def target_name(self): | 502 def target_name(self): |
511 return self._base_dir | 503 return self._base_dir |
512 def target_type(self): | 504 def target_type(self): |
513 return self._base_dir | 505 return self._base_dir |
514 def does_storage_object_exist(self, name, *args): | 506 def does_storage_object_exist(self, name): |
515 return os.path.isfile(os.path.join(self._base_dir, name)) | 507 return os.path.isfile(os.path.join(self._base_dir, name)) |
516 def delete_path(self, path): | 508 def delete_path(self, path): |
517 shutil.rmtree(path) | 509 shutil.rmtree(path) |
518 def download_file(self, name, local_path, *args): | 510 def download_file(self, name, local_path): |
519 shutil.copyfile(os.path.join(self._base_dir, name), local_path) | 511 shutil.copyfile(os.path.join(self._base_dir, name), local_path) |
520 def upload_dir_contents(self, source_dir, dest_dir, **kwargs): | 512 def upload_dir_contents(self, source_dir, dest_dir): |
521 def copytree(source_dir, dest_dir): | 513 def copytree(source_dir, dest_dir): |
522 if not os.path.exists(dest_dir): | 514 if not os.path.exists(dest_dir): |
523 os.makedirs(dest_dir) | 515 os.makedirs(dest_dir) |
524 for item in os.listdir(source_dir): | 516 for item in os.listdir(source_dir): |
525 source = os.path.join(source_dir, item) | 517 source = os.path.join(source_dir, item) |
526 dest = os.path.join(dest_dir, item) | 518 dest = os.path.join(dest_dir, item) |
527 if os.path.isdir(source): | 519 if os.path.isdir(source): |
528 copytree(source, dest) | 520 copytree(source, dest) |
529 else: | 521 else: |
530 shutil.copy2(source, dest) | 522 shutil.copy2(source, dest) |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
593 '--skia_tools is specified then the debugger is not run.', | 585 '--skia_tools is specified then the debugger is not run.', |
594 default=False) | 586 default=False) |
595 option_parser.add_option( | 587 option_parser.add_option( |
596 '', '--skp_prefix', | 588 '', '--skp_prefix', |
597 help='Prefix to add to the names of generated SKPs.', | 589 help='Prefix to add to the names of generated SKPs.', |
598 default=None) | 590 default=None) |
599 options, unused_args = option_parser.parse_args() | 591 options, unused_args = option_parser.parse_args() |
600 | 592 |
601 playback = SkPicturePlayback(options) | 593 playback = SkPicturePlayback(options) |
602 sys.exit(playback.Run()) | 594 sys.exit(playback.Run()) |
OLD | NEW |