1
0
mirror of https://github.com/Llewellynvdm/conky.git synced 2024-12-26 20:31:17 +00:00
conky/cmake/scripts/clang-format-check-changed.py
2021-01-23 17:59:07 -06:00

164 lines
5.0 KiB
Python
Executable File

#!/usr/bin/env python3
import argparse
import os
import sys
import subprocess
def check_file(filename, excludes, extensions):
"""
Check if a file should be included in our check
"""
name, ext = os.path.splitext(filename)
if len(ext) > 0 and ext in extensions:
if len(excludes) == 0:
return True
for exclude in excludes:
if exclude in filename:
return False
return True
return False
def check_directory(directory, excludes, extensions):
output = []
if len(excludes) > 0:
for exclude in excludes:
if exclude in directory:
directory_excluded = False
return output
for root, _, files in os.walk(directory):
for file in files:
filename = os.path.join(root, file)
if check_file(filename, excludes, extensions):
print("Will check file [{}]".format(filename))
output.append(filename)
return output
def get_git_root(git_bin):
cmd = [git_bin, "rev-parse", "--show-toplevel"]
try:
return subprocess.check_output(cmd).strip()
except subprocess.CalledProcessError, e:
print("Error calling git [{}]".format(e))
raise
def clean_git_filename(line):
"""
Takes a line from git status --porcelain and returns the filename
"""
file = None
git_status = line[:2]
# Not an exhaustive list of git status output but should
# be enough for this case
# check if this is a delete
if 'D' in git_status:
return None
# ignored file
if '!' in git_status:
return None
# Covers renamed files
if '->' in line:
file = line[3:].split('->')[-1].strip()
else:
file = line[3:].strip()
return file
def get_changed_files(git_bin, excludes, file_extensions):
"""
Run git status and return the list of changed files
"""
extensions = file_extensions.split(",")
# arguments coming from cmake will be *.xx. We want to remove the *
for i, extension in enumerate(extensions):
if extension[0] == '*':
extensions[i] = extension[1:]
git_root = get_git_root(git_bin)
cmd = [git_bin, "status", "--porcelain", "--ignore-submodules"]
print("git cmd = {}".format(cmd))
output = []
returncode = 0
try:
cmd_output = subprocess.check_output(cmd)
for line in cmd_output.split('\n'):
if len(line) > 0:
file = clean_git_filename(line)
if not file:
continue
file = os.path.join(git_root, file)
if file[-1] == "/":
directory_files = check_directory(
file, excludes, file_extensions)
output = output + directory_files
else:
if check_file(file, excludes, file_extensions):
print("Will check file [{}]".format(file))
output.append(file)
except subprocess.CalledProcessError, e:
print("Error calling git [{}]".format(e))
returncode = e.returncode
return output, returncode
def run_clang_format(clang_format_bin, changed_files):
"""
Run clang format on a list of files
@return 0 if formatted correctly.
"""
if len(changed_files) == 0:
return 0
cmd = [clang_format_bin, "-style=file",
"-output-replacements-xml"] + changed_files
print("clang-format cmd = {}".format(cmd))
try:
cmd_output = subprocess.check_output(cmd)
if "replacement offset" in cmd_output:
print("ERROR: Changed files don't match format")
return 1
except subprocess.CalledProcessError, e:
print("Error calling clang-format [{}]".format(e))
return e.returncode
return 0
def cli():
# global params
parser = argparse.ArgumentParser(prog='clang-format-check-changed',
description='Checks if files changed in git match the .clang-format specification')
parser.add_argument("--file-extensions", type=str,
default=".cpp,.h,.cxx,.hxx,.hpp,.cc,.ipp",
help="Comma separated list of file extensions to check")
parser.add_argument('--exclude', action='append', default=[],
help='Will not match the files / directories with these in the name')
parser.add_argument('--clang-format-bin', type=str, default="clang-format",
help="The clang format binary")
parser.add_argument('--git-bin', type=str, default="git",
help="The git binary")
args = parser.parse_args()
# Run gcovr to get the .gcda files form .gcno
changed_files, returncode = get_changed_files(
args.git_bin, args.exclude, args.file_extensions)
if returncode != 0:
return returncode
return run_clang_format(args.clang_format_bin, changed_files)
if __name__ == '__main__':
sys.exit(cli())