Azure-Kinect-Sensor-SDK/cmake/ValidateFormat.py

109 строки
4.4 KiB
Python

#!/usr/bin/env python3
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
# Invokes clang-format and reports formatting errors
# Optionally can cause clang-format to run the format in place with --reformat
import re, argparse, sys, subprocess, os.path, xml.dom.minidom
parser=argparse.ArgumentParser(description='Validate clang-fromat for files')
parser.add_argument('--file', metavar='INPUTFILE', type=str, nargs='+', help='Files to validate', required=True)
parser.add_argument('--output', metavar='OUTPUT', type=str, help='Output location', required=True)
parser.add_argument('--clangformat', type=str, help='path to the clang-format tool', required=True)
parser.add_argument('--reformat', action='store_true')
def main(argv):
args = parser.parse_args()
errorcount = 0
for file in args.file:
reformatcount = 0
# Invoke clang-format
if args.reformat:
# Retry the reformat operation so long as the file continues to be modified
# Sometimes clang-format will reformat a file, but running it again will apply additional changes
filetime = os.path.getmtime(file)
updatefile = True
while (updatefile):
proc = subprocess.Popen([args.clangformat] + ['-i', file], stdout=subprocess.PIPE, encoding="utf-8")
stdout = proc.stdout.read()
proc.wait()
updatefile = False
updatedtime = os.path.getmtime(file)
if (updatedtime != filetime):
updatefile = True
print("clang-format updated {}".format(file))
filetime = updatedtime
else:
proc = subprocess.Popen([args.clangformat] + ['-output-replacements-xml', file], stdout=subprocess.PIPE, encoding="utf-8")
stdout = proc.stdout.read()
proc.wait()
# Parse the output
dom = xml.dom.minidom.parseString(stdout)
# Iterate through the file and count the number of replacements on each source line
# Offset within the file
offset = 0
# Line number within the file
lineno = 0
# Current line with errors
linewitherrors = 0
replacementsonline = 0
with open (file, 'r') as input:
for replacement in dom.getElementsByTagName('replacement'):
reformatcount = reformatcount + 1
# replacement offset
roffset = int(replacement.getAttribute('offset'))
# advance the file one line at a time until the file offset
# is past the current replacement offset
while offset < roffset:
line = input.readline()
offset = input.tell()
lineno = lineno + 1
# If this replacement is on a different line from the last one,
# print the error information from the previous line
if linewitherrors != lineno and linewitherrors != 0:
err = "Error {} ({}): {} clang-format replacements on line".format(
file,
linewitherrors,
replacementsonline
)
print(err)
replacementsonline = 0
# Count the number of replacements on this line
linewitherrors = lineno
replacementsonline = replacementsonline + 1
# Print the last line of replacment information if any
if linewitherrors != 0:
err = "Error {} ({}): {} clang-format replacements on line".format(
file,
linewitherrors,
replacementsonline,
)
print(err)
print(" Run the clangformat target to auto-clean (e.g. \"ninja clangformat\")")
errorcount = errorcount + reformatcount
# Touch the output file if the operation was successful
if errorcount == 0:
with open (args.output, 'w') as output:
output.write("")
sys.exit(errorcount)
if __name__ == "__main__":
main(sys.argv[1:])