1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3 4# 5# Copyright (c) 2020 Huawei Device Co., Ltd. 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18 19import os 20import subprocess 21from datetime import datetime 22from distutils.spawn import find_executable 23from hb_internal.common.utils import exec_command 24from hb_internal.common.utils import hb_warning 25 26 27class PreBuild: 28 def __init__(self, config): 29 self._root_path = config.root_path 30 self._out_path = config.out_path 31 self._log_path = config.log_path 32 33 def set_ccache(self): 34 ccache_local_dir = os.environ.get('CCACHE_LOCAL_DIR') 35 ccache_log_suffix = os.environ.get('CCACHE_LOG_SUFFIX') 36 if not ccache_local_dir: 37 ccache_local_dir = '.ccache' 38 ccache_base = os.environ.get('CCACHE_BASE') 39 if ccache_base is None: 40 ccache_base = os.path.join(self._root_path, ccache_local_dir) 41 if not os.path.exists(ccache_base): 42 os.makedirs(ccache_base) 43 ccache_log_file_name = "ccache.log" 44 if ccache_log_suffix: 45 ccache_log_file_name = "ccache." + ccache_log_suffix + ".log" 46 47 logfile = os.path.join(self._root_path, ccache_log_file_name) 48 if os.path.exists(logfile): 49 oldfile_name = ccache_log_file_name + ".old" 50 oldfile = os.path.join(self._root_path, oldfile_name) 51 if os.path.exists(oldfile): 52 os.unlink(oldfile) 53 os.rename(logfile, oldfile) 54 55 ccache_path = find_executable('ccache') 56 if ccache_path is None: 57 hb_warning('Failed to find ccache, ccache disabled.') 58 return 59 os.environ['CCACHE_EXEC'] = ccache_path 60 os.environ['CCACHE_LOGFILE'] = logfile 61 os.environ['USE_CCACHE'] = '1' 62 os.environ['CCACHE_DIR'] = ccache_base 63 os.environ['CCACHE_UMASK'] = '002' 64 os.environ['CCACHE_BASEDIR'] = self._root_path 65 ccache_max_size = os.environ.get('CCACHE_MAXSIZE') 66 if not ccache_max_size: 67 ccache_max_size = '100G' 68 69 cmd = ['ccache', '-M', ccache_max_size] 70 exec_command(cmd, log_path=self._log_path) 71 72 def set_pycache(self): 73 pycache_dir = os.path.join(self._root_path, '.pycache') 74 os.environ['PYCACHE_DIR'] = pycache_dir 75 pyd_start_cmd = [ 76 'python3', 77 '{}/build/scripts/util/pyd.py'.format(self._root_path), 78 '--root', 79 pycache_dir, 80 '--start', 81 ] 82 cmd = ['/bin/bash', '-c', ' '.join(pyd_start_cmd), '&'] 83 subprocess.Popen(cmd) 84 85 def rename_last_logfile(self): 86 logfile = os.path.join(self._out_path, 'build.log') 87 if os.path.exists(logfile): 88 mtime = os.stat(logfile).st_mtime 89 os.rename(logfile, '{}/build.{}.log'.format(self._out_path, mtime)) 90 91 def prepare(self, args): 92 actions = [self.set_ccache, self.rename_last_logfile] 93 for action in actions: 94 action() 95 96 97class PostBuild: 98 def __init__(self, config): 99 self._root_path = config.root_path 100 self._out_path = config.out_path 101 self._log_path = config.log_path 102 103 def clean(self, start_time, disable_post_build_args): 104 if not disable_post_build_args or 'stat_ccache' not in disable_post_build_args: 105 self.stat_ccache() 106 if not disable_post_build_args or 'generate_ninja_trace' not in disable_post_build_args: 107 self.generate_ninja_trace(start_time) 108 if not disable_post_build_args or 'get_warning_list' not in disable_post_build_args: 109 self.get_warning_list() 110 if not disable_post_build_args or 'compute_overlap_rate' not in disable_post_build_args: 111 self.compute_overlap_rate() 112 113 def package_image(self): 114 image_path = os.path.join(self._out_path, 'packages/phone/images/') 115 if os.path.exists(image_path): 116 packaged_file_path = os.path.join(self._out_path, 'images.tar.gz') 117 cmd = ['tar', '-zcvf', packaged_file_path, image_path] 118 exec_command(cmd, log_path=self._log_path) 119 120 def stat_pycache(self): 121 cmd = [ 122 'python3', '{}/build/scripts/util/pyd.py'.format(self._root_path), 123 '--stat' 124 ] 125 exec_command(cmd, log_path=self._log_path) 126 127 def manage_cache_data(self): 128 cmd = [ 129 'python3', '{}/build/scripts/util/pyd.py'.format(self._root_path), 130 '--manage' 131 ] 132 exec_command(cmd, log_path=self._log_path) 133 134 def stop_pyd(self): 135 cmd = [ 136 'python3', '{}/build/scripts/util/pyd.py'.format(self._root_path), 137 '--stop' 138 ] 139 exec_command(cmd, log_path=self._log_path) 140 141 def stat_ccache(self): 142 ccache_path = find_executable('ccache') 143 if ccache_path is None: 144 return 145 146 ccache_log_file_name = "ccache.log" 147 ccache_log_suffix = os.environ.get('CCACHE_LOG_SUFFIX') 148 if ccache_log_suffix: 149 ccache_log_file_name = "ccache." + ccache_log_suffix + ".log" 150 cmd = [ 151 'python3', '{}/build/scripts/summary_ccache_hitrate.py'.format( 152 self._root_path), '{}/{}'.format(self._root_path, ccache_log_file_name) 153 ] 154 exec_command(cmd, log_path=self._log_path) 155 156 def get_warning_list(self): 157 cmd = [ 158 'python3', 159 '{}/build/scripts/get_warnings.py'.format(self._root_path), 160 '--build-log-file', 161 '{}/build.log'.format(self._out_path), 162 '--warning-out-file', 163 '{}/packages/WarningList.txt'.format(self._out_path), 164 ] 165 exec_command(cmd, log_path=self._log_path) 166 167 def generate_ninja_trace(self, start_time): 168 def get_unixtime(dt): 169 epoch = datetime.utcfromtimestamp(0) 170 unixtime = '%f' % ((dt - epoch).total_seconds() * 10**9) 171 return str(unixtime) 172 173 cmd = [ 174 'python3', 175 '{}/build/scripts/ninja2trace.py'.format(self._root_path), 176 '--ninja-log', 177 '{}/.ninja_log'.format(self._out_path), 178 "--trace-file", 179 "{}/build.trace".format(self._out_path), 180 "--ninja-start-time", 181 get_unixtime(start_time), 182 "--duration-file", 183 "{}/sorted_action_duration.txt".format(self._out_path), 184 ] 185 exec_command(cmd, log_path=self._log_path) 186 187 def compute_overlap_rate(self): 188 cmd = [ 189 'python3', 190 '{}/build/ohos/statistics/build_overlap_statistics.py'.format( 191 self._root_path), "--build-out-dir", self._out_path, 192 "--subsystem-config-file", 193 "{}/build/subsystem_config.json".format(self._root_path), 194 "--root-source-dir", self._root_path 195 ] 196 exec_command(cmd, log_path=self._log_path) 197