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 re 21import subprocess 22import shutil 23import sys 24import json 25import tarfile 26import zipfile 27import importlib 28from datetime import datetime 29from collections import namedtuple 30 31 32def encode(data, encoding='utf-8'): 33 if sys.version_info.major == 2: 34 return data.encode(encoding) 35 return data 36 37 38def decode(data, encoding='utf-8'): 39 if sys.version_info.major == 2: 40 return data.decode(encoding) 41 return data 42 43 44def remove_path(path): 45 if os.path.exists(path): 46 shutil.rmtree(path) 47 48 49# Read json file data 50def read_json_file(input_file): 51 if not os.path.isfile(input_file): 52 raise OHOSException(f'{input_file} not found') 53 54 with open(input_file, 'rb') as input_f: 55 data = json.load(input_f) 56 return data 57 58 59def dump_json_file(dump_file, json_data): 60 with open(dump_file, 'wt', encoding='utf-8') as json_file: 61 json.dump(json_data, json_file, ensure_ascii=False, indent=2) 62 63 64def read_yaml_file(input_file): 65 if not os.path.isfile(input_file): 66 raise OHOSException(f'{input_file} not found') 67 68 yaml = importlib.import_module('yaml') 69 with open(input_file, 'rt', encoding='utf-8') as yaml_file: 70 try: 71 return yaml.safe_load(yaml_file) 72 except yaml.YAMLError as exc: 73 if hasattr(exc, 'problem_mark'): 74 mark = exc.problem_mark 75 raise OHOSException(f'{input_file} load failed, error line:' 76 f' {mark.line + 1}:{mark.column + 1}') 77 78 79def get_input(msg): 80 try: 81 user_input = input 82 except NameError: 83 raise OHOSException('python2.x not supported') 84 return user_input(msg) 85 86 87def exec_command(cmd, log_path='out/build.log', **kwargs): 88 useful_info_pattern = re.compile(r'\[\d+/\d+\].+') 89 is_log_filter = kwargs.pop('log_filter', False) 90 91 with open(log_path, 'at', encoding='utf-8') as log_file: 92 process = subprocess.Popen(cmd, 93 stdout=subprocess.PIPE, 94 stderr=subprocess.STDOUT, 95 encoding='utf-8', 96 **kwargs) 97 for line in iter(process.stdout.readline, ''): 98 if is_log_filter: 99 info = re.findall(useful_info_pattern, line) 100 if len(info): 101 hb_info(info[0]) 102 else: 103 hb_info(line) 104 log_file.write(line) 105 106 process.wait() 107 ret_code = process.returncode 108 109 if ret_code != 0: 110 if is_log_filter: 111 get_failed_log(log_path) 112 113 raise OHOSException('Please check build log in {}'.format(log_path)) 114 115 116def get_failed_log(log_path): 117 with open(log_path, 'rt', encoding='utf-8') as log_file: 118 data = log_file.read() 119 failed_pattern = re.compile( 120 r'(\[\d+/\d+\].*?)(?=\[\d+/\d+\]|' 121 'ninja: build stopped)', re.DOTALL) 122 failed_log = failed_pattern.findall(data) 123 for log in failed_log: 124 if 'FAILED:' in log: 125 hb_error(log) 126 127 failed_pattern = re.compile(r'(ninja: error:.*?)\n', re.DOTALL) 128 failed_log = failed_pattern.findall(data) 129 for log in failed_log: 130 hb_error(log) 131 132 error_log = os.path.join(os.path.dirname(log_path), 'error.log') 133 if os.path.isfile(error_log): 134 with open(error_log, 'rt', encoding='utf-8') as log_file: 135 hb_error(log_file.read()) 136 137 138def check_output(cmd, **kwargs): 139 try: 140 ret = subprocess.check_output(cmd, 141 stderr=subprocess.STDOUT, 142 universal_newlines=True, 143 **kwargs) 144 except subprocess.CalledProcessError as called_exception: 145 ret = called_exception.output 146 if isinstance(cmd, list): 147 cmd = ' '.join(cmd) 148 raise OHOSException(f'command: "{cmd}" failed\n' 149 f'return code: {ret}\n' 150 f'execution path: {os.getcwd()}') 151 152 return ret 153 154 155def makedirs(path, exist_ok=True, with_rm=False): 156 try: 157 os.makedirs(path) 158 except OSError: 159 if not os.path.isdir(path): 160 raise OHOSException(f"{path} makedirs failed") 161 if with_rm: 162 remove_path(path) 163 return os.makedirs(path) 164 if not exist_ok: 165 raise OHOSException(f"{path} exists, makedirs failed") 166 167 168def get_project_path(json_path): 169 json_data = read_json_file(json_path) 170 171 return json_data.get('root_path') 172 173 174def args_factory(args_dict): 175 if not len(args_dict): 176 raise OHOSException('at least one k_v param is ' 177 'required in args_factory') 178 179 args_cls = namedtuple('Args', [key for key in args_dict.keys()]) 180 args = args_cls(**args_dict) 181 return args 182 183 184def get_current_time(type='default'): 185 if type == 'timestamp': 186 return int(datetime.utcnow().timestamp() * 1000) 187 if type == 'datetime': 188 return datetime.now().strftime('%Y-%m-%d %H:%M:%S') 189 return datetime.now().replace(microsecond=0) 190 191 192class Colors: 193 HEADER = '\033[95m' 194 WARNING = '\033[93m' 195 ERROR = '\033[91m' 196 INFO = '\033[92m' 197 END = '\033[0m' 198 199 200def hb_info(msg): 201 level = 'info' 202 for line in str(msg).splitlines(): 203 sys.stdout.write(message(level, line)) 204 sys.stdout.flush() 205 206 207def hb_warning(msg): 208 level = 'warning' 209 for line in str(msg).splitlines(): 210 sys.stderr.write(message(level, line)) 211 sys.stderr.flush() 212 213 214def hb_error(msg): 215 level = 'error' 216 for line in str(msg).splitlines(): 217 sys.stderr.write(message(level, line)) 218 sys.stderr.flush() 219 220 221def message(level, msg): 222 if isinstance(msg, str) and not msg.endswith('\n'): 223 msg += '\n' 224 if level == 'error': 225 msg = msg.replace('error:', f'{Colors.ERROR}error{Colors.END}:') 226 return f'{Colors.ERROR}[OHOS {level.upper()}]{Colors.END} {msg}' 227 elif level == 'info': 228 return f'[OHOS {level.upper()}] {msg}' 229 else: 230 return f'{Colors.WARNING}[OHOS {level.upper()}]{Colors.END} {msg}' 231 232 233class Singleton(type): 234 _instances = {} 235 236 def __call__(cls, *args, **kwargs): 237 if cls not in cls._instances: 238 cls._instances[cls] = super(Singleton, 239 cls).__call__(*args, **kwargs) 240 return cls._instances[cls] 241 242 243class OHOSException(Exception): 244 pass 245 246 247def download_tool(url, dst, tgt_dir=None): 248 requests = importlib.import_module('requests') 249 try: 250 res = requests.get(url, stream=True, timeout=(5, 9)) 251 except OSError: 252 raise OHOSException(f'download {url} timeout!') 253 254 if res.status_code == 200: 255 hb_info(f'Downloading {url} ...') 256 else: 257 hb_error(f'Downloading {url} failed with code: {res.status_code}!') 258 return res.status_code 259 260 total_size = int(res.headers['content-length']) 261 download_size = 0 262 download_percent = 0 263 264 try: 265 with open(dst, "wb") as f: 266 for chunk in res.iter_content(chunk_size=1024): 267 if chunk: 268 f.write(chunk) 269 download_size += len(chunk) 270 download_percent = round( 271 float(download_size / total_size * 100), 2) 272 print('Progress: %s%%\r' % download_percent, end=' ') 273 hb_info('Download complete!') 274 except OSError: 275 raise OHOSException( 276 f'{url} download failed, please install it manually!') 277 278 if tgt_dir is not None: 279 extract_tool(dst, tgt_dir) 280 281 282def extract_tool(src, tgt_dir): 283 hb_info(f'Extracting to {tgt_dir}, please wait...') 284 try: 285 if tarfile.is_tarfile(src): 286 ef = tarfile.open(src) 287 elif zipfile.is_zipfile(src): 288 ef = zipfile.ZipFile(src) 289 else: 290 raise OHOSException(f'Extract file type not support!') 291 ef.extractall(tgt_dir) 292 ef.close() 293 except OSError: 294 raise OHOSException( 295 f'{src} extract failed, please install it manually!') 296