1cb93a386Sopenharmony_ci#!/usr/bin/env python 2cb93a386Sopenharmony_ci# 3cb93a386Sopenharmony_ci# Copyright 2016 Google Inc. 4cb93a386Sopenharmony_ci# 5cb93a386Sopenharmony_ci# Use of this source code is governed by a BSD-style license that can be 6cb93a386Sopenharmony_ci# found in the LICENSE file. 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci 9cb93a386Sopenharmony_ci"""Create the SKP asset.""" 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_ci 12cb93a386Sopenharmony_cifrom __future__ import print_function 13cb93a386Sopenharmony_ciimport argparse 14cb93a386Sopenharmony_cifrom distutils.dir_util import copy_tree 15cb93a386Sopenharmony_ciimport os 16cb93a386Sopenharmony_ciimport shutil 17cb93a386Sopenharmony_ciimport subprocess 18cb93a386Sopenharmony_ciimport sys 19cb93a386Sopenharmony_ciimport tempfile 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_ciFILE_DIR = os.path.dirname(os.path.abspath(__file__)) 22cb93a386Sopenharmony_ciINFRA_BOTS_DIR = os.path.realpath(os.path.join(FILE_DIR, os.pardir, os.pardir)) 23cb93a386Sopenharmony_cisys.path.insert(0, INFRA_BOTS_DIR) 24cb93a386Sopenharmony_ciimport utils 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_ciBROWSER_EXECUTABLE_ENV_VAR = 'SKP_BROWSER_EXECUTABLE' 28cb93a386Sopenharmony_ciCHROME_SRC_PATH_ENV_VAR = 'SKP_CHROME_SRC_PATH' 29cb93a386Sopenharmony_ciUPLOAD_TO_PARTNER_BUCKET_ENV_VAR = 'SKP_UPLOAD_TO_PARTNER_BUCKET' 30cb93a386Sopenharmony_ciDM_PATH_ENV_VAR = 'DM_PATH' 31cb93a386Sopenharmony_ci 32cb93a386Sopenharmony_ciSKIA_TOOLS = os.path.join(INFRA_BOTS_DIR, os.pardir, os.pardir, 'tools') 33cb93a386Sopenharmony_ciPRIVATE_SKPS_GS = 'gs://skia-skps/private/skps' 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_cidef getenv(key): 37cb93a386Sopenharmony_ci val = os.environ.get(key) 38cb93a386Sopenharmony_ci if not val: 39cb93a386Sopenharmony_ci print(('Environment variable %s not set; you should run this via ' 40cb93a386Sopenharmony_ci 'create_and_upload.py.' % key), file=sys.stderr) 41cb93a386Sopenharmony_ci sys.exit(1) 42cb93a386Sopenharmony_ci return val 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_cidef get_flutter_skps(target_dir): 46cb93a386Sopenharmony_ci """Creates SKPs using Flutter's skp_generator tool. 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_ci Documentation is at https://github.com/flutter/tests/tree/master/skp_generator 49cb93a386Sopenharmony_ci """ 50cb93a386Sopenharmony_ci with utils.tmp_dir(): 51cb93a386Sopenharmony_ci print('Retrieving Flutter SKPs...') 52cb93a386Sopenharmony_ci utils.git_clone('https://github.com/flutter/tests.git', '.') 53cb93a386Sopenharmony_ci os.chdir('skp_generator') 54cb93a386Sopenharmony_ci subprocess.check_call(['bash', 'build.sh']) 55cb93a386Sopenharmony_ci # Fix invalid SKP file names. 56cb93a386Sopenharmony_ci for f in os.listdir('skps'): 57cb93a386Sopenharmony_ci original_file_name = os.path.splitext(f)[0] 58cb93a386Sopenharmony_ci new_file_name = ''.join([x if x.isalnum() else "_" 59cb93a386Sopenharmony_ci for x in original_file_name]) 60cb93a386Sopenharmony_ci if new_file_name != original_file_name: 61cb93a386Sopenharmony_ci os.rename(os.path.join('skps', f), 62cb93a386Sopenharmony_ci os.path.join('skps', new_file_name + '.skp')) 63cb93a386Sopenharmony_ci copy_tree('skps', target_dir) 64cb93a386Sopenharmony_ci print('Done retrieving Flutter SKPs.') 65cb93a386Sopenharmony_ci 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_cidef create_asset(chrome_src_path, browser_executable, target_dir, 68cb93a386Sopenharmony_ci upload_to_partner_bucket, dm_path): 69cb93a386Sopenharmony_ci """Create the SKP asset. 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_ci Creates the asset from 3 sources: 72cb93a386Sopenharmony_ci 1. From Flutter's skp_generator tool. 73cb93a386Sopenharmony_ci 2. The web pages defined in the tools/skp/page_sets/ directory. 74cb93a386Sopenharmony_ci 3. Any private SKPs stored in $PRIVATE_SKPS_GS after running dm on 75cb93a386Sopenharmony_ci them (see below). 76cb93a386Sopenharmony_ci 77cb93a386Sopenharmony_ci The script runs the following cmd on the non-generated SKPs stored in 78cb93a386Sopenharmony_ci $PRIVATE_SKPS_GS - 79cb93a386Sopenharmony_ci `dm --config skp -w newskps/ --skps oldskps/ --src skp` 80cb93a386Sopenharmony_ci The cmd updates the version stored in the SKPs so that the versions in 81cb93a386Sopenharmony_ci them do not eventually become unsupported. 82cb93a386Sopenharmony_ci """ 83cb93a386Sopenharmony_ci browser_executable = os.path.realpath(browser_executable) 84cb93a386Sopenharmony_ci chrome_src_path = os.path.realpath(chrome_src_path) 85cb93a386Sopenharmony_ci dm_path = os.path.realpath(dm_path) 86cb93a386Sopenharmony_ci target_dir = os.path.realpath(target_dir) 87cb93a386Sopenharmony_ci 88cb93a386Sopenharmony_ci if not os.path.exists(target_dir): 89cb93a386Sopenharmony_ci os.makedirs(target_dir) 90cb93a386Sopenharmony_ci 91cb93a386Sopenharmony_ci # 1. Flutter SKPs 92cb93a386Sopenharmony_ci get_flutter_skps(target_dir) 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ci # 2. Skia's SKPs from tools/skp/page_sets/ 95cb93a386Sopenharmony_ci with utils.tmp_dir(): 96cb93a386Sopenharmony_ci if os.environ.get('CHROME_HEADLESS'): 97cb93a386Sopenharmony_ci print('Starting xvfb') 98cb93a386Sopenharmony_ci # Start Xvfb if running on a bot. 99cb93a386Sopenharmony_ci try: 100cb93a386Sopenharmony_ci xvfb_proc = subprocess.Popen([ 101cb93a386Sopenharmony_ci 'sudo', 'Xvfb', ':0', '-screen', '0', '1280x1024x24']) 102cb93a386Sopenharmony_ci except Exception: 103cb93a386Sopenharmony_ci # It is ok if the above command fails, it just means that DISPLAY=:0 104cb93a386Sopenharmony_ci # is already up. 105cb93a386Sopenharmony_ci xvfb_proc = None 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_ci print('Running webpages_playback to generate SKPs...') 108cb93a386Sopenharmony_ci webpages_playback_cmd = [ 109cb93a386Sopenharmony_ci 'python', '-u', os.path.join(SKIA_TOOLS, 'skp', 'webpages_playback.py'), 110cb93a386Sopenharmony_ci '--page_sets', 'all', 111cb93a386Sopenharmony_ci '--browser_executable', browser_executable, 112cb93a386Sopenharmony_ci '--non-interactive', 113cb93a386Sopenharmony_ci '--output_dir', os.getcwd(), 114cb93a386Sopenharmony_ci '--chrome_src_path', chrome_src_path, 115cb93a386Sopenharmony_ci ] 116cb93a386Sopenharmony_ci if upload_to_partner_bucket: 117cb93a386Sopenharmony_ci webpages_playback_cmd.append('--upload_to_partner_bucket') 118cb93a386Sopenharmony_ci print('Running webpages_playback command:\n$ %s' % 119cb93a386Sopenharmony_ci ' '.join(webpages_playback_cmd)) 120cb93a386Sopenharmony_ci try: 121cb93a386Sopenharmony_ci subprocess.check_call(webpages_playback_cmd) 122cb93a386Sopenharmony_ci finally: 123cb93a386Sopenharmony_ci if xvfb_proc: 124cb93a386Sopenharmony_ci try: 125cb93a386Sopenharmony_ci xvfb_proc.kill() 126cb93a386Sopenharmony_ci except OSError as e: 127cb93a386Sopenharmony_ci print('Failed to kill xvfb process via Popen.kill();' 128cb93a386Sopenharmony_ci ' attempting `sudo kill`...') 129cb93a386Sopenharmony_ci try: 130cb93a386Sopenharmony_ci subprocess.check_call(['sudo', 'kill', '-9', str(xvfb_proc.pid)]) 131cb93a386Sopenharmony_ci except subprocess.CalledProcessError as e: 132cb93a386Sopenharmony_ci print('Failed to kill xvfb process via `sudo kill`;' 133cb93a386Sopenharmony_ci 'this may cause a hang.') 134cb93a386Sopenharmony_ci # Clean up any leftover browser instances. This can happen if there are 135cb93a386Sopenharmony_ci # telemetry crashes, processes are not always cleaned up appropriately by 136cb93a386Sopenharmony_ci # the webpagereplay and telemetry frameworks. 137cb93a386Sopenharmony_ci procs = subprocess.check_output(['ps', 'ax']).decode() 138cb93a386Sopenharmony_ci for line in procs.splitlines(): 139cb93a386Sopenharmony_ci if browser_executable in line: 140cb93a386Sopenharmony_ci print(line) 141cb93a386Sopenharmony_ci pid = line.strip().split(' ')[0] 142cb93a386Sopenharmony_ci if pid != str(os.getpid()) and not 'python' in line: 143cb93a386Sopenharmony_ci print('Kill browser process %s' % str(pid)) 144cb93a386Sopenharmony_ci try: 145cb93a386Sopenharmony_ci subprocess.check_call(['kill', '-9', str(pid)]) 146cb93a386Sopenharmony_ci except subprocess.CalledProcessError as e: 147cb93a386Sopenharmony_ci print(e) 148cb93a386Sopenharmony_ci else: 149cb93a386Sopenharmony_ci pass 150cb93a386Sopenharmony_ci if 'Xvfb' in line: 151cb93a386Sopenharmony_ci print(line) 152cb93a386Sopenharmony_ci pid = line.strip().split(' ')[0] 153cb93a386Sopenharmony_ci print('Kill Xvfb process %s' % str(pid)) 154cb93a386Sopenharmony_ci try: 155cb93a386Sopenharmony_ci subprocess.check_call(['sudo', 'kill', '-9', str(pid)]) 156cb93a386Sopenharmony_ci except subprocess.CalledProcessError as e: 157cb93a386Sopenharmony_ci print(e) 158cb93a386Sopenharmony_ci 159cb93a386Sopenharmony_ci src = os.path.join(os.getcwd(), 'playback', 'skps') 160cb93a386Sopenharmony_ci for f in os.listdir(src): 161cb93a386Sopenharmony_ci if f.endswith('.skp'): 162cb93a386Sopenharmony_ci shutil.copyfile(os.path.join(src, f), os.path.join(target_dir, f)) 163cb93a386Sopenharmony_ci print('Done running webpages_playback.') 164cb93a386Sopenharmony_ci 165cb93a386Sopenharmony_ci # 3. Copy over private SKPs from Google storage into the target_dir. 166cb93a386Sopenharmony_ci old_skps_dir = tempfile.mkdtemp() 167cb93a386Sopenharmony_ci new_skps_dir = tempfile.mkdtemp() 168cb93a386Sopenharmony_ci print('Copying non-generated SKPs from private GCS bucket...') 169cb93a386Sopenharmony_ci subprocess.check_call([ 170cb93a386Sopenharmony_ci 'gsutil', 'cp', os.path.join(PRIVATE_SKPS_GS, '*'), old_skps_dir]) 171cb93a386Sopenharmony_ci print('Updating non-generated SKP versions') 172cb93a386Sopenharmony_ci subprocess.check_call([ 173cb93a386Sopenharmony_ci dm_path, 174cb93a386Sopenharmony_ci '--config', 'skp', 175cb93a386Sopenharmony_ci '-w', new_skps_dir, 176cb93a386Sopenharmony_ci '--skps', old_skps_dir, 177cb93a386Sopenharmony_ci '--src', 'skp']) 178cb93a386Sopenharmony_ci for f in os.listdir(new_skps_dir): 179cb93a386Sopenharmony_ci if f.endswith('.skp'): 180cb93a386Sopenharmony_ci shutil.copyfile( 181cb93a386Sopenharmony_ci os.path.join(new_skps_dir, f), os.path.join(target_dir, f)) 182cb93a386Sopenharmony_ci shutil.rmtree(old_skps_dir) 183cb93a386Sopenharmony_ci shutil.rmtree(new_skps_dir) 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_ci 186cb93a386Sopenharmony_cidef main(): 187cb93a386Sopenharmony_ci parser = argparse.ArgumentParser() 188cb93a386Sopenharmony_ci parser.add_argument('--target_dir', '-t', required=True) 189cb93a386Sopenharmony_ci args = parser.parse_args() 190cb93a386Sopenharmony_ci 191cb93a386Sopenharmony_ci # Obtain flags from create_and_upload via environment variables, since 192cb93a386Sopenharmony_ci # this script is called via `sk` and not directly. 193cb93a386Sopenharmony_ci chrome_src_path = getenv(CHROME_SRC_PATH_ENV_VAR) 194cb93a386Sopenharmony_ci browser_executable = getenv(BROWSER_EXECUTABLE_ENV_VAR) 195cb93a386Sopenharmony_ci upload_to_partner_bucket = getenv(UPLOAD_TO_PARTNER_BUCKET_ENV_VAR) == '1' 196cb93a386Sopenharmony_ci dm_path = getenv(DM_PATH_ENV_VAR) 197cb93a386Sopenharmony_ci 198cb93a386Sopenharmony_ci create_asset(chrome_src_path, browser_executable, args.target_dir, 199cb93a386Sopenharmony_ci upload_to_partner_bucket, dm_path) 200cb93a386Sopenharmony_ci 201cb93a386Sopenharmony_ci 202cb93a386Sopenharmony_ciif __name__ == '__main__': 203cb93a386Sopenharmony_ci main() 204