15f9996aaSopenharmony_ci#!/usr/bin/env python3 25f9996aaSopenharmony_ci# -*- coding: utf-8 -*- 35f9996aaSopenharmony_ci 45f9996aaSopenharmony_ci# 55f9996aaSopenharmony_ci# Copyright (c) 2023 Huawei Device Co., Ltd. 65f9996aaSopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License"); 75f9996aaSopenharmony_ci# you may not use this file except in compliance with the License. 85f9996aaSopenharmony_ci# You may obtain a copy of the License at 95f9996aaSopenharmony_ci# 105f9996aaSopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0 115f9996aaSopenharmony_ci# 125f9996aaSopenharmony_ci# Unless required by applicable law or agreed to in writing, software 135f9996aaSopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS, 145f9996aaSopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 155f9996aaSopenharmony_ci# See the License for the specific language governing permissions and 165f9996aaSopenharmony_ci# limitations under the License. 175f9996aaSopenharmony_ci# 185f9996aaSopenharmony_ci 195f9996aaSopenharmony_ciimport sys 205f9996aaSopenharmony_ciimport re 215f9996aaSopenharmony_ciimport os 225f9996aaSopenharmony_ci 235f9996aaSopenharmony_cifrom containers.colors import Colors 245f9996aaSopenharmony_cifrom hb.helper.no_instance import NoInstance 255f9996aaSopenharmony_cifrom resources.global_var import STATUS_FILE 265f9996aaSopenharmony_cifrom util.io_util import IoUtil 275f9996aaSopenharmony_cifrom exceptions.ohos_exception import OHOSException 285f9996aaSopenharmony_ci 295f9996aaSopenharmony_ci 305f9996aaSopenharmony_ciclass LogLevel(): 315f9996aaSopenharmony_ci INFO = 0 325f9996aaSopenharmony_ci WARNING = 1 335f9996aaSopenharmony_ci ERROR = 2 345f9996aaSopenharmony_ci DEBUG = 3 355f9996aaSopenharmony_ci 365f9996aaSopenharmony_ci 375f9996aaSopenharmony_ciclass LogUtil(metaclass=NoInstance): 385f9996aaSopenharmony_ci 395f9996aaSopenharmony_ci @staticmethod 405f9996aaSopenharmony_ci def hb_info(msg, mode='normal'): 415f9996aaSopenharmony_ci level = 'info' 425f9996aaSopenharmony_ci if mode == 'silent': 435f9996aaSopenharmony_ci for line in str(msg).splitlines(): 445f9996aaSopenharmony_ci sys.stdout.write('\033[K') 455f9996aaSopenharmony_ci sys.stdout.write( 465f9996aaSopenharmony_ci '\r' + (LogUtil.message(level, line)).strip('\n')) 475f9996aaSopenharmony_ci sys.stdout.flush() 485f9996aaSopenharmony_ci elif mode == 'normal': 495f9996aaSopenharmony_ci level = 'info' 505f9996aaSopenharmony_ci for line in str(msg).splitlines(): 515f9996aaSopenharmony_ci sys.stdout.write(LogUtil.message(level, line)) 525f9996aaSopenharmony_ci sys.stdout.flush() 535f9996aaSopenharmony_ci 545f9996aaSopenharmony_ci @staticmethod 555f9996aaSopenharmony_ci def hb_warning(msg): 565f9996aaSopenharmony_ci level = 'warning' 575f9996aaSopenharmony_ci for line in str(msg).splitlines(): 585f9996aaSopenharmony_ci sys.stderr.write(LogUtil.message(level, line)) 595f9996aaSopenharmony_ci sys.stderr.flush() 605f9996aaSopenharmony_ci 615f9996aaSopenharmony_ci @staticmethod 625f9996aaSopenharmony_ci def hb_error(msg): 635f9996aaSopenharmony_ci level = 'error' 645f9996aaSopenharmony_ci sys.stderr.write('\n') 655f9996aaSopenharmony_ci for line in str(msg).splitlines(): 665f9996aaSopenharmony_ci sys.stderr.write(LogUtil.message(level, line)) 675f9996aaSopenharmony_ci sys.stderr.flush() 685f9996aaSopenharmony_ci 695f9996aaSopenharmony_ci @staticmethod 705f9996aaSopenharmony_ci def message(level, msg): 715f9996aaSopenharmony_ci if isinstance(msg, str) and not msg.endswith('\n'): 725f9996aaSopenharmony_ci msg += '\n' 735f9996aaSopenharmony_ci if level == 'error': 745f9996aaSopenharmony_ci msg = msg.replace('error:', f'{Colors.ERROR}error{Colors.END}:') 755f9996aaSopenharmony_ci return f'{Colors.ERROR}[OHOS {level.upper()}]{Colors.END} {msg}' 765f9996aaSopenharmony_ci elif level == 'info': 775f9996aaSopenharmony_ci return f'[OHOS {level.upper()}] {msg}' 785f9996aaSopenharmony_ci else: 795f9996aaSopenharmony_ci return f'{Colors.WARNING}[OHOS {level.upper()}]{Colors.END} {msg}' 805f9996aaSopenharmony_ci 815f9996aaSopenharmony_ci @staticmethod 825f9996aaSopenharmony_ci def write_log(log_path, msg, level): 835f9996aaSopenharmony_ci os.makedirs(os.path.dirname(log_path), exist_ok=True) 845f9996aaSopenharmony_ci sys.stderr.write('\n') 855f9996aaSopenharmony_ci with open(log_path, 'at', encoding='utf-8') as log_file: 865f9996aaSopenharmony_ci for line in str(msg).splitlines(): 875f9996aaSopenharmony_ci sys.stderr.write(LogUtil.message(level, line)) 885f9996aaSopenharmony_ci sys.stderr.flush() 895f9996aaSopenharmony_ci log_file.write(LogUtil.message(level, line)) 905f9996aaSopenharmony_ci 915f9996aaSopenharmony_ci @staticmethod 925f9996aaSopenharmony_ci def analyze_build_error(error_log, status_code_prefix): 935f9996aaSopenharmony_ci with open(error_log, 'rt', encoding='utf-8') as log_file: 945f9996aaSopenharmony_ci data = log_file.read() 955f9996aaSopenharmony_ci status_file = IoUtil.read_json_file(STATUS_FILE) 965f9996aaSopenharmony_ci choices = [] 975f9996aaSopenharmony_ci status_map = {} 985f9996aaSopenharmony_ci for status_code, status in status_file.items(): 995f9996aaSopenharmony_ci if not status_code.startswith(status_code_prefix): 1005f9996aaSopenharmony_ci continue 1015f9996aaSopenharmony_ci if isinstance(status, dict) and status.get('pattern'): 1025f9996aaSopenharmony_ci choices.append(status['pattern']) 1035f9996aaSopenharmony_ci status_map[status['pattern']] = status.get('code') 1045f9996aaSopenharmony_ci best_match = None 1055f9996aaSopenharmony_ci best_ratio = 0 1065f9996aaSopenharmony_ci for choice in choices: 1075f9996aaSopenharmony_ci pattern = re.compile(choice, re.DOTALL) 1085f9996aaSopenharmony_ci match = pattern.search(data) 1095f9996aaSopenharmony_ci if not match: 1105f9996aaSopenharmony_ci continue 1115f9996aaSopenharmony_ci ratio = len(match.group()) / len(data) 1125f9996aaSopenharmony_ci if ratio > best_ratio: 1135f9996aaSopenharmony_ci best_ratio = ratio 1145f9996aaSopenharmony_ci best_match = choice 1155f9996aaSopenharmony_ci return_status_code = status_map.get( 1165f9996aaSopenharmony_ci best_match) if best_match else f'{status_code_prefix}000' 1175f9996aaSopenharmony_ci return return_status_code 1185f9996aaSopenharmony_ci 1195f9996aaSopenharmony_ci @staticmethod 1205f9996aaSopenharmony_ci def get_gn_failed_log(log_path): 1215f9996aaSopenharmony_ci error_log = os.path.join(os.path.dirname(log_path), 'error.log') 1225f9996aaSopenharmony_ci is_gn_failed = False 1235f9996aaSopenharmony_ci with open(log_path, 'rt', encoding='utf-8') as log_file: 1245f9996aaSopenharmony_ci lines = log_file.readlines() 1255f9996aaSopenharmony_ci error_lines = [] 1265f9996aaSopenharmony_ci for i, line in enumerate(lines): 1275f9996aaSopenharmony_ci if line.startswith('ERROR at'): 1285f9996aaSopenharmony_ci error_lines.extend(lines[i: i + 50]) 1295f9996aaSopenharmony_ci is_gn_failed = True 1305f9996aaSopenharmony_ci break 1315f9996aaSopenharmony_ci for log in error_lines[:50]: 1325f9996aaSopenharmony_ci LogUtil.hb_error(log) 1335f9996aaSopenharmony_ci with open(error_log, 'at', encoding='utf-8') as log_file: 1345f9996aaSopenharmony_ci log_file.write(log + '\n') 1355f9996aaSopenharmony_ci if is_gn_failed: 1365f9996aaSopenharmony_ci return_status_code = LogUtil.analyze_build_error(error_log, '3') 1375f9996aaSopenharmony_ci raise OHOSException( 1385f9996aaSopenharmony_ci 'GN Failed! Please check error in {}, and for more build information in {}'.format( 1395f9996aaSopenharmony_ci error_log, log_path), return_status_code) 1405f9996aaSopenharmony_ci 1415f9996aaSopenharmony_ci @staticmethod 1425f9996aaSopenharmony_ci def get_ninja_failed_log(log_path): 1435f9996aaSopenharmony_ci error_log = os.path.join(os.path.dirname(log_path), 'error.log') 1445f9996aaSopenharmony_ci is_ninja_failed = False 1455f9996aaSopenharmony_ci with open(log_path, 'rt', encoding='utf-8') as log_file: 1465f9996aaSopenharmony_ci data = log_file.read() 1475f9996aaSopenharmony_ci failed_pattern = re.compile(r'(ninja: error:.*?)\n', re.DOTALL) 1485f9996aaSopenharmony_ci failed_log = failed_pattern.findall(data) 1495f9996aaSopenharmony_ci if failed_log: 1505f9996aaSopenharmony_ci is_ninja_failed = True 1515f9996aaSopenharmony_ci for log in failed_log: 1525f9996aaSopenharmony_ci LogUtil.hb_error(log) 1535f9996aaSopenharmony_ci with open(error_log, 'at', encoding='utf-8') as log_file: 1545f9996aaSopenharmony_ci log_file.write(log) 1555f9996aaSopenharmony_ci if is_ninja_failed: 1565f9996aaSopenharmony_ci return_status_code = LogUtil.analyze_build_error(error_log, '4') 1575f9996aaSopenharmony_ci raise OHOSException( 1585f9996aaSopenharmony_ci 'NINJA Failed! Please check error in {}, and for more build information in {}'.format( 1595f9996aaSopenharmony_ci error_log, log_path), return_status_code) 1605f9996aaSopenharmony_ci 1615f9996aaSopenharmony_ci @staticmethod 1625f9996aaSopenharmony_ci def get_compiler_failed_log(log_path): 1635f9996aaSopenharmony_ci error_log = os.path.join(os.path.dirname(log_path), 'error.log') 1645f9996aaSopenharmony_ci is_compiler_failed = False 1655f9996aaSopenharmony_ci with open(log_path, 'rt', encoding='utf-8') as log_file: 1665f9996aaSopenharmony_ci data = log_file.read() 1675f9996aaSopenharmony_ci failed_pattern = re.compile( 1685f9996aaSopenharmony_ci r'(\[\d+/\d+\].*?)(?=\[\d+/\d+\]|' 1695f9996aaSopenharmony_ci 'ninja: build stopped)', re.DOTALL) 1705f9996aaSopenharmony_ci failed_log = failed_pattern.findall(data) 1715f9996aaSopenharmony_ci if failed_log: 1725f9996aaSopenharmony_ci is_compiler_failed = True 1735f9996aaSopenharmony_ci for log in failed_log: 1745f9996aaSopenharmony_ci if 'FAILED:' in log: 1755f9996aaSopenharmony_ci LogUtil.hb_error(log) 1765f9996aaSopenharmony_ci with open(error_log, 'at', encoding='utf-8') as log_file: 1775f9996aaSopenharmony_ci log_file.write(log) 1785f9996aaSopenharmony_ci if is_compiler_failed: 1795f9996aaSopenharmony_ci return_status_code = LogUtil.analyze_build_error(error_log, '4') 1805f9996aaSopenharmony_ci raise OHOSException( 1815f9996aaSopenharmony_ci 'COMPILE Failed! Please check error in {}, and for more build information in {}'.format( 1825f9996aaSopenharmony_ci error_log, log_path), return_status_code) 1835f9996aaSopenharmony_ci 1845f9996aaSopenharmony_ci @staticmethod 1855f9996aaSopenharmony_ci def get_failed_log(log_path): 1865f9996aaSopenharmony_ci last_error_log = os.path.join(os.path.dirname(log_path), 'error.log') 1875f9996aaSopenharmony_ci if os.path.exists(last_error_log): 1885f9996aaSopenharmony_ci mtime = os.stat(last_error_log).st_mtime 1895f9996aaSopenharmony_ci os.rename( 1905f9996aaSopenharmony_ci last_error_log, '{}/error.{}.log'.format(os.path.dirname(last_error_log), mtime)) 1915f9996aaSopenharmony_ci LogUtil.get_gn_failed_log(log_path) 1925f9996aaSopenharmony_ci LogUtil.get_ninja_failed_log(log_path) 1935f9996aaSopenharmony_ci LogUtil.get_compiler_failed_log(log_path) 1945f9996aaSopenharmony_ci raise OHOSException( 1955f9996aaSopenharmony_ci 'BUILD Failed! Please check build log for more information: {}'.format(log_path)) 196