• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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