432 lines
13 KiB
Python
Executable File
432 lines
13 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# coding=utf-8
|
|
# Copyright (c) CompanyNameMagicTag 2022-2022. All rights reserved.
|
|
|
|
"""
|
|
* Description: Utilities of compile system.
|
|
* Create: 2020-1-2
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import time
|
|
import subprocess
|
|
import re
|
|
import shutil
|
|
import logging
|
|
import fnmatch
|
|
import struct
|
|
import hashlib
|
|
import platform
|
|
import filecmp
|
|
|
|
root_path = os.path.join(os.path.split(os.path.realpath(__file__))[0], '..', '..', '..')
|
|
root_path = os.path.abspath(root_path)
|
|
script_path = os.path.join(root_path, 'build', 'script')
|
|
target_config_path = os.path.join(root_path, 'build', 'config', 'target_config')
|
|
output_root = os.path.join(root_path, 'output')
|
|
sdk_output_path = os.path.join(output_root, 'sdk')
|
|
pkg_tools_path = os.path.join(root_path, 'tools', 'pkg')
|
|
jlink_tools_path = os.path.join(root_path, 'tools', 'bin', 'jlink_tool')
|
|
lzma_tools_path = os.path.join(root_path, 'tools', 'bin', 'lzma_tool')
|
|
sign_tools_path = os.path.join(root_path, 'tools', 'bin', 'sign_tool')
|
|
memcheck_tools_path = os.path.join(root_path, 'tools', 'bin', 'memcheck')
|
|
factory_tools_path = os.path.join(root_path, 'tools', 'bin', 'factory_tools')
|
|
derived_tools_path = os.path.join(root_path, 'tools', 'bin', 'derived_key_tool')
|
|
ohos_tools_path = os.path.join(root_path, 'tools', 'bin', 'ohos_tools')
|
|
xts_tools_path = os.path.join(root_path, 'tools', 'bin', 'xts_tools')
|
|
|
|
"""
|
|
Colors defines. To highlight important output.
|
|
"""
|
|
__colors__ = {'purple': '\033[95m', 'red': '\033[91m', 'blue': '\033[94m', 'green': '\033[92m', 'end': '\033[0m'}
|
|
|
|
|
|
class BuildError(Exception):
|
|
"""
|
|
Error handling, highlight in red.
|
|
"""
|
|
def __init__(self, err):
|
|
emsg = "%s%s%s" % (color_red(), err, color_end())
|
|
Exception.__init__(self, emsg)
|
|
|
|
|
|
class BuildTimer:
|
|
"""
|
|
timer
|
|
"""
|
|
def __init__(self, name='A'):
|
|
self._start = -1
|
|
self._name = name
|
|
|
|
def start(self):
|
|
self._start = time.time()
|
|
|
|
def stop(self):
|
|
if self._start == -1:
|
|
raise BuildError("Timer %s never been started!" % self._name)
|
|
retval = time.time() - self._start
|
|
self._start = -1
|
|
return retval
|
|
|
|
|
|
class CopyModule:
|
|
def __init__(self, replace_root='', replace_suffix='', pattern='*', copy_header = True):
|
|
self.replace_root = replace_root
|
|
self.replace_suffix = replace_suffix
|
|
self.mask = ['__pycache__', '.git*']
|
|
self.pattern = pattern
|
|
self.copy_header = copy_header
|
|
|
|
def append_mask(self, mask):
|
|
if isinstance(mask, list):
|
|
self.mask.extend(mask)
|
|
return
|
|
self.mask.append(mask)
|
|
|
|
def __ignore(self, path, names):
|
|
ignored_names = []
|
|
names = set(names)
|
|
for mask in self.mask:
|
|
ignored_names.extend(fnmatch.filter(names, mask))
|
|
if self.pattern == "*.h":
|
|
for name in names:
|
|
if "." in name and not name.endswith('.h'):
|
|
ignored_names.append(name)
|
|
else:
|
|
ignored_names.extend(names - set(fnmatch.filter(names, self.pattern)))
|
|
return set(ignored_names)
|
|
|
|
def copy_file(self, file, dest=None):
|
|
if dest is None and self.replace_root:
|
|
dest = file.replace(root_path, self.replace_root)
|
|
if os.path.exists(dest) and os.path.isfile(dest):
|
|
return None
|
|
path = os.path.split(dest)[0]
|
|
if not os.path.exists(path):
|
|
os.makedirs(path, exist_ok=True)
|
|
if self.replace_suffix and os.path.exists(file + self.replace_suffix):
|
|
file = file + self.replace_suffix
|
|
try:
|
|
shutil.copy2(file, dest, follow_symlinks=True)
|
|
except:
|
|
print("[WARN] copy %s exception" % file)
|
|
return
|
|
if self.copy_header:
|
|
self.copy_file_header(file)
|
|
return dest
|
|
|
|
#add for copy header file
|
|
def copy_file_header(self, file):
|
|
file_path = os.path.dirname(file)
|
|
for inner_file in os.listdir(file_path):
|
|
if inner_file.endswith('.h'):
|
|
tmp_src = "%s/%s" %(file_path, inner_file)
|
|
tmp_dest = "%s/%s" %(file_path.replace(root_path, sdk_output_path), inner_file)
|
|
if self.replace_suffix and os.path.exists(tmp_src + self.replace_suffix):
|
|
tmp_src = tmp_src + self.replace_suffix
|
|
if not os.path.exists(tmp_dest):
|
|
shutil.copy(tmp_src, tmp_dest)
|
|
|
|
def copy_folder(self, path, dest=None):
|
|
if dest is None and self.replace_root:
|
|
dest = path.replace(root_path, self.replace_root)
|
|
shutil.copytree(path, dest, copy_function=self.copy_file, dirs_exist_ok=True, ignore=self.__ignore)
|
|
return dest
|
|
|
|
def copy(self, src, dest=None):
|
|
if not os.path.exists(src):
|
|
print("WARNING : Sdk copy src: %s is not exists!!" % src)
|
|
return
|
|
if os.path.isfile(src):
|
|
return self.copy_file(src, dest)
|
|
else:
|
|
return self.copy_folder(src, dest)
|
|
|
|
|
|
# End of class BuildTimer
|
|
|
|
def color_red():
|
|
return __colors__.get('red')
|
|
|
|
|
|
def color_purple():
|
|
return __colors__.get('purple')
|
|
|
|
|
|
def color_blue():
|
|
return __colors__.get('blue')
|
|
|
|
|
|
def color_green():
|
|
return __colors__.get('green')
|
|
|
|
|
|
def color_end():
|
|
return __colors__.get('end')
|
|
|
|
|
|
def print_info(msg):
|
|
print(msg)
|
|
|
|
|
|
def print_tips(msg):
|
|
print("%s%s%s" % (color_purple(), msg, color_end()))
|
|
|
|
|
|
def print_warning(msg):
|
|
print("%s%s%s" % (color_green(), msg, color_end()))
|
|
|
|
|
|
def print_alert(msg):
|
|
print("%s%s%s" % (color_red(), msg, color_end()))
|
|
|
|
def cmp_file(f1, f2):
|
|
filecmp.clear_cache()
|
|
return filecmp.cmp(f1, f2, shallow = False)
|
|
|
|
def fn_filter_dirs(dirs, filters=None):
|
|
if filters is None:
|
|
filters = []
|
|
retval = list(dirs)
|
|
for dir_path in dirs:
|
|
for item in filters:
|
|
fstr = "%s%s%s" % (os.sep, item, os.sep)
|
|
if dir_path.find(fstr) >= 0:
|
|
try:
|
|
print("remove dir_path:%s" % dir_path)
|
|
retval.remove(dir_path)
|
|
except ValueError as e:
|
|
print(e)
|
|
|
|
return retval
|
|
|
|
|
|
def fn_search_all_files(top_dir, file_name, excludes=[]):
|
|
"""
|
|
Traverse sub-folders to find all files named "file_name".
|
|
"""
|
|
retval = []
|
|
for dir_path, dir_names, file_names in os.walk(top_dir, followlinks=True):
|
|
# remove useless folder first
|
|
dir_names = [dir_names.remove(x) for x in dir_names if x.startswith(".")]
|
|
if file_name in file_names:
|
|
retval.append(os.path.join(dir_path, file_name))
|
|
return fn_filter_dirs(retval, excludes)
|
|
|
|
|
|
def fn_search_all_dirs(top_dir, dir_name, excludes=None):
|
|
"""
|
|
Traverse sub-folders to find all files named "dir_name".
|
|
"""
|
|
if excludes is None:
|
|
excludes = []
|
|
retval = []
|
|
for dir_path, dir_names, file_names in os.walk(top_dir, followlinks=True):
|
|
if not dir_names:
|
|
continue
|
|
# remove useless folder first
|
|
temp_dirs = list(dir_names)
|
|
dirnames = [x for x in dir_names if not x.startswith(".")]
|
|
for dirname in dirnames:
|
|
if dirname and dirname == dir_name:
|
|
retval.append(os.path.join(dir_path, dirname))
|
|
return fn_filter_dirs(retval, excludes)
|
|
|
|
|
|
def fn_get_subdirs(dir_path):
|
|
lst = [name for name in os.listdir(dir_path) if os.path.isdir(os.path.join(dir_path, name)) and name[0] != '.']
|
|
lst.sort()
|
|
return lst
|
|
|
|
|
|
def fn_str_to_int(text, num=None):
|
|
if num is not None:
|
|
return int(text, num)
|
|
match1 = re.match(r'\s*0x', text)
|
|
match2 = re.match(r'\s*0X', text)
|
|
if match1 or match2:
|
|
return int(text, 16)
|
|
else:
|
|
return int(text, 10)
|
|
|
|
|
|
def bf_to_str(bf):
|
|
"""
|
|
Convert build error from scons to string.
|
|
"""
|
|
if bf is None:
|
|
return '(unknown targets product None in list)'
|
|
elif bf.node:
|
|
return str(bf.node) + ': ' + bf.errstr
|
|
elif bf.filename:
|
|
return bf.filename + ': ' + bf.errstr
|
|
else:
|
|
return str(bf)
|
|
|
|
|
|
def exec_shell(cmd, logfile=None, cmd_dump=False):
|
|
"""
|
|
call shell
|
|
"""
|
|
cmd_list = cmd
|
|
logfp = None
|
|
if isinstance(cmd, str):
|
|
cmd_list = cmd.split(' ')
|
|
|
|
logger = logging.getLogger()
|
|
logger.setLevel(logging.INFO)
|
|
if not logger.handlers:
|
|
logger.addHandler(logging.StreamHandler(sys.stdout))
|
|
|
|
if logfile:
|
|
if os.path.isfile(logfile):
|
|
os.unlink(logfile)
|
|
if len(logger.handlers) < 2: # 1. console; 2. file
|
|
logfp = logging.FileHandler(logfile, encoding='utf-8')
|
|
logger.addHandler(logfp)
|
|
else:
|
|
logfp = logger.handlers[1]
|
|
try:
|
|
if cmd_dump:
|
|
logging.info(str(cmd_list))
|
|
logging.info('\n')
|
|
subp = subprocess.Popen(cmd_list, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
while True:
|
|
output = subp.stdout.readline()
|
|
try:
|
|
output = output.decode(encoding='utf-8', errors='strict')
|
|
except UnicodeDecodeError as err:
|
|
output = output.decode(encoding='gb2312', errors='replace')
|
|
finally:
|
|
if output == '' and subp.poll() is not None:
|
|
break
|
|
if output:
|
|
logging.info(output.strip())
|
|
if logfile and logfp:
|
|
logfp.close()
|
|
return subp.returncode
|
|
except FileNotFoundError as err:
|
|
logging.error(err)
|
|
raise Exception(err)
|
|
except Exception as err:
|
|
logging.error(err)
|
|
raise Exception(err)
|
|
finally:
|
|
if logfile and logfp:
|
|
logfp.close()
|
|
|
|
|
|
def add_temp_sys_path(path):
|
|
env_path = os.environ.get('PATH')
|
|
if path.startswith(os.sep):
|
|
work_path = path
|
|
else:
|
|
work_path = os.path.join(os.getcwd(), path)
|
|
|
|
if work_path not in env_path:
|
|
new_env_path = ':'.join([work_path, env_path])
|
|
os.environ['PATH'] = new_env_path
|
|
return os.environ.get('PATH')
|
|
|
|
|
|
def rm_all(items):
|
|
for item in items:
|
|
if os.path.isdir(item):
|
|
shutil.rmtree(item)
|
|
elif os.path.isfile(item):
|
|
os.unlink(item)
|
|
else:
|
|
pass
|
|
|
|
def add_len_and_sha256_info_to_ssb(source, chip=None):
|
|
with open(source, "rb+") as bin_file:
|
|
length = len(bin_file.read())
|
|
if chip == "brandy":
|
|
bin_file.seek(364, 0) # ssb length offset addr 0x16c
|
|
elif chip == "socmn1":
|
|
bin_file.seek(404, 0) # ssb length offset addr 0x194
|
|
else:
|
|
bin_file.seek(360, 0) # ssb length offset addr 0x168
|
|
bin_file.write(struct.pack('<L', length))
|
|
bin_file.close()
|
|
|
|
with open(source, "rb+") as bin_file:
|
|
sha = hashlib.sha256(bin_file.read())
|
|
bin_file.write(sha.digest()[0:32])
|
|
bin_file.close()
|
|
|
|
def create_hex_file(target, source):
|
|
with open(source, "rb") as binfile, open(
|
|
target, "wb") as hexfile:
|
|
while True:
|
|
bindata = binfile.read(4)
|
|
if not bindata:
|
|
break
|
|
longdata, = struct.unpack("<L", bindata)
|
|
hexstr = '{:x}'.format(longdata) # dec to hex number str
|
|
hexstr = '%s\n' % '{:0>8}'.format(hexstr).upper()
|
|
hexfile.write(str.encode(hexstr))
|
|
|
|
def compare_bin(bin1, bin2):
|
|
print("Comparing:")
|
|
print(bin1)
|
|
print(bin2)
|
|
if not cmp_file(bin1, bin2):
|
|
print("DIFF")
|
|
return False
|
|
print("SAME")
|
|
return True
|
|
|
|
def rm_pyc(root):
|
|
pyc_dirs = fn_search_all_dirs(root, "__pycache__")
|
|
rm_all(pyc_dirs)
|
|
|
|
|
|
def get_diff(list0, list1):
|
|
diff = list(set(list0) - set(list1))
|
|
return diff
|
|
|
|
|
|
def copy(src, dest, replace_suffix='', pattern="*"):
|
|
c = CopyModule(replace_suffix=replace_suffix, pattern=pattern)
|
|
c.copy(src, dest)
|
|
|
|
def copy_force(src, dest, pattern = ".a"):
|
|
for file_name in os.listdir(src):
|
|
if file_name.endswith(pattern):
|
|
tmp_src = "%s/%s" %(src, file_name)
|
|
shutil.copy(tmp_src, dest)
|
|
|
|
def get_platform_name():
|
|
return platform.system().lower()
|
|
|
|
if __name__ == "__main__":
|
|
func_list = [
|
|
"copy",
|
|
"add_len_and_sha256_info_to_ssb",
|
|
"create_hex_file",
|
|
"copy_force"
|
|
]
|
|
func = sys.argv[1]
|
|
if func not in func_list:
|
|
print("ERROR! WRONG FUNC!! YOU CAN ONLY INVOKE FUNC BELOW:")
|
|
for function in func_list:
|
|
print(function)
|
|
sys.exit(1)
|
|
arg_num = locals()[func].__code__.co_argcount
|
|
if arg_num == 1:
|
|
locals()[func](sys.argv[2])
|
|
elif arg_num == 2:
|
|
locals()[func](sys.argv[2], sys.argv[3])
|
|
elif arg_num == 3:
|
|
locals()[func](sys.argv[2], sys.argv[3], sys.argv[4])
|
|
elif arg_num == 4:
|
|
locals()[func](sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5])
|
|
elif arg_num == 5:
|
|
locals()[func](sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6])
|
|
elif arg_num == 6:
|
|
locals()[func](sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6], sys.argv[7])
|
|
else:
|
|
print("ERROR! arg number out of range")
|