1# Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file 2# for details. All rights reserved. Use of this source code is governed by a 3# BSD-style license that can be found in the LICENSE file. 4 5# Different utility functions used accross scripts 6 7import hashlib 8import os 9import re 10import shutil 11import subprocess 12import sys 13import tempfile 14 15TOOLS_DIR = os.path.abspath(os.path.normpath(os.path.join(__file__, '..'))) 16REPO_ROOT = os.path.realpath(os.path.join(TOOLS_DIR, '..')) 17MEMORY_USE_TMP_FILE = 'memory_use.tmp' 18DEX_SEGMENTS_JAR = os.path.join(REPO_ROOT, 'build', 'libs', 19 'dexsegments.jar') 20DEX_SEGMENTS_RESULT_PATTERN = re.compile('- ([^:]+): ([0-9]+)') 21 22def PrintCmd(s): 23 if type(s) is list: 24 s = ' '.join(s) 25 print 'Running: %s' % s 26 # I know this will hit os on windows eventually if we don't do this. 27 sys.stdout.flush() 28 29def IsWindows(): 30 return os.name == 'nt' 31 32def DownloadFromGoogleCloudStorage(sha1_file, bucket='r8-deps'): 33 suffix = '.bat' if IsWindows() else '' 34 download_script = 'download_from_google_storage%s' % suffix 35 cmd = [download_script, '-n', '-b', bucket, '-u', '-s', 36 sha1_file] 37 PrintCmd(cmd) 38 subprocess.check_call(cmd) 39 40def get_sha1(filename): 41 sha1 = hashlib.sha1() 42 with open(filename, 'rb') as f: 43 while True: 44 chunk = f.read(1024*1024) 45 if not chunk: 46 break 47 sha1.update(chunk) 48 return sha1.hexdigest() 49 50def makedirs_if_needed(path): 51 try: 52 os.makedirs(path) 53 except OSError: 54 if not os.path.isdir(path): 55 raise 56 57def upload_html_to_cloud_storage(directory, destination): 58 # Upload and make the content encoding right for viewing directly 59 cmd = ['gsutil.py', 'cp', '-z', 'html', '-a', 60 'public-read', '-R', directory, destination] 61 PrintCmd(cmd) 62 subprocess.check_call(cmd) 63 64class TempDir(object): 65 def __init__(self, prefix=''): 66 self._temp_dir = None 67 self._prefix = prefix 68 69 def __enter__(self): 70 self._temp_dir = tempfile.mkdtemp(self._prefix) 71 return self._temp_dir 72 73 def __exit__(self, *_): 74 shutil.rmtree(self._temp_dir, ignore_errors=True) 75 76class ChangedWorkingDirectory(object): 77 def __init__(self, working_directory): 78 self._working_directory = working_directory 79 80 def __enter__(self): 81 self._old_cwd = os.getcwd() 82 print 'Enter directory = ', self._working_directory 83 os.chdir(self._working_directory) 84 85 def __exit__(self, *_): 86 print 'Enter directory = ', self._old_cwd 87 os.chdir(self._old_cwd) 88 89# Reading Android CTS test_result.xml 90 91class CtsModule(object): 92 def __init__(self, module_name): 93 self.name = module_name 94 95class CtsTestCase(object): 96 def __init__(self, test_case_name): 97 self.name = test_case_name 98 99class CtsTest(object): 100 def __init__(self, test_name, outcome): 101 self.name = test_name 102 self.outcome = outcome 103 104# Generator yielding CtsModule, CtsTestCase or CtsTest from 105# reading through a CTS test_result.xml file. 106def read_cts_test_result(file_xml): 107 re_module = re.compile('<Module name="([^"]*)"') 108 re_test_case = re.compile('<TestCase name="([^"]*)"') 109 re_test = re.compile('<Test result="(pass|fail)" name="([^"]*)"') 110 with open(file_xml) as f: 111 for line in f: 112 m = re_module.search(line) 113 if m: 114 yield CtsModule(m.groups()[0]) 115 continue 116 m = re_test_case.search(line) 117 if m: 118 yield CtsTestCase(m.groups()[0]) 119 continue 120 m = re_test.search(line) 121 if m: 122 outcome = m.groups()[0] 123 assert outcome in ['fail', 'pass'] 124 yield CtsTest(m.groups()[1], outcome == 'pass') 125 126def grep_memoryuse(logfile): 127 re_vmhwm = re.compile('^VmHWM:[ \t]*([0-9]+)[ \t]*([a-zA-Z]*)') 128 result = None 129 with open(logfile) as f: 130 for line in f: 131 m = re_vmhwm.search(line) 132 if m: 133 groups = m.groups() 134 s = len(groups) 135 if s >= 1: 136 result = int(groups[0]) 137 if s >= 2: 138 unit = groups[1] 139 if unit == 'kB': 140 result *= 1024 141 elif unit != '': 142 raise Exception('Unrecognized unit in memory usage log: {}' 143 .format(unit)) 144 if result is None: 145 raise Exception('No memory usage found in log: {}'.format(logfile)) 146 return result 147 148# Return a dictionary: {segment_name -> segments_size} 149def getDexSegmentSizes(dex_files): 150 assert len(dex_files) > 0 151 cmd = ['java', '-jar', DEX_SEGMENTS_JAR] 152 cmd.extend(dex_files) 153 PrintCmd(cmd) 154 output = subprocess.check_output(cmd) 155 156 matches = DEX_SEGMENTS_RESULT_PATTERN.findall(output) 157 158 if matches is None or len(matches) == 0: 159 raise Exception('DexSegments failed to return any output for' \ 160 ' these files: {}'.format(dex_files)) 161 162 result = {} 163 164 for match in matches: 165 result[match[0]] = int(match[1]) 166 167 return result 168 169def print_dexsegments(prefix, dex_files): 170 for segment_name, size in getDexSegmentSizes(dex_files).items(): 171 print('{}-{}(CodeSize): {}' 172 .format(prefix, segment_name, size)) 173