import os
from builder.common.logger import logger
from builder.common.utils import exec_sys_command
_EXCLUDE_DIRS = ["out", "prebuilts", "third_party"]
_C_CPP_EXTS = [".c", ".cc", ".cxx", ".cpp", ".h", ".hpp"]
_GN_EXTS = [".gn", ".gni"]
class Formatter:
def __init__(self, args):
self.args = args
self.clang_format_cmds = ['clang-format', '-i', '-style=file', '-fallback-style=none']
self.gn_format_cmds = [self.args.gn_path, 'format']
self.exclude_dirs = []
for dir in _EXCLUDE_DIRS:
self.exclude_dirs.append(os.path.join(self.args.project_dir, dir))
if self.args.code_path is None:
self.code_path = self.args.project_dir
else:
self.code_path = os.path.abspath(self.code_path)
def _is_subpath(self, path, parent_paths) -> bool:
path = os.path.abspath(path)
return any(os.path.commonpath([path, p]) == p for p in parent_paths)
def pre_format(self) -> bool:
if self.args.verbose:
self.clang_format_cmds.append("-verbose")
return True
def _do_format(self, abs_file_name: str, exts: list, format_cmds: list) -> bool:
should_format = False
for ext in exts:
if abs_file_name.endswith(ext):
should_format = True
break
if should_format:
cmds = format_cmds + [abs_file_name]
rst, _ = exec_sys_command(cmds)
if not rst:
return False
return True
def do_format(self) -> bool:
logger.info(f"Start format files in {self.code_path}...")
for [dirpath, _, filenames] in os.walk(self.code_path):
if self._is_subpath(dirpath, self.exclude_dirs):
logger.debug(f"Escape dir: {dirpath}")
continue
for filename in filenames:
abs_file_name = os.path.join(dirpath, filename)
if not self._do_format(abs_file_name, _C_CPP_EXTS, self.clang_format_cmds):
logger.error(f"Failed to format C/C++ file: {abs_file_name}")
return False
if not self._do_format(abs_file_name, _GN_EXTS, self.gn_format_cmds):
logger.error(f"Failed to format GN file: {abs_file_name}")
return False
return True
def exec_command(self) -> bool:
logger.info(f'Exec "format" command...')
if not self.pre_format():
return False
return self.do_format()