2 # SPDX-License-Identifier: BSD-3-Clause
3 # Copyright(c) 2021 Intel Corporation
6 A Python script to run some checks on meson.build files in DPDK
12 from os.path import relpath, join
13 from argparse import ArgumentParser
19 '''return meson.build files found in path'''
20 for root, dirs, files in os.walk(path):
21 if 'meson.build' in files:
22 yield(relpath(join(root, 'meson.build')))
25 def split_code_comments(line):
26 'splits a line into a code part and a comment part, returns (code, comment) tuple'
27 if line.lstrip().startswith('#'):
29 elif '#' in line and '#include' not in line: # catch 99% of cases, not 100%
31 while (line[idx - 1].isspace()):
33 return line[:idx], line[idx:]
38 def setline(contents, index, value):
39 'sets the contents[index] to value. Returns the line, along with code and comments part'
40 line = contents[index] = value
41 code, comments = split_code_comments(line)
42 return line, code, comments
45 def check_indentation(filename, contents):
46 '''check that a list or files() is correctly indented'''
50 for lineno, line in enumerate(contents):
51 code, comments = split_code_comments(line)
54 if re.match('^ *\t', code):
55 print(f'Error parsing {filename}:{lineno}, got some tabulation')
56 if code.endswith('files('):
58 raise(f'Error parsing {filename}:{lineno}, got "files(" when already parsing files list')
60 print(f'Error parsing {filename}:{lineno}, got "files(" when already parsing array list')
62 indent_count = len(code) - len(code.lstrip(' '))
63 indent = ' ' * (indent_count + 8) # double indent required
64 elif code.endswith('= ['):
66 raise(f'Error parsing {filename}:{lineno}, got start of array when already parsing files list')
68 print(f'Error parsing {filename}:{lineno}, got start of array when already parsing array list')
70 indent_count = len(code) - len(code.lstrip(' '))
71 indent = ' ' * (indent_count + 8) # double indent required
72 elif infiles and (code.endswith(')') or code.strip().startswith(')')):
75 elif inlist and (code.endswith(']') or code.strip().startswith(']')):
78 elif inlist or infiles:
79 # skip further subarrays or lists
80 if '[' in code or ']' in code:
82 if not code.startswith(indent) or code[len(indent)] == ' ':
83 print(f'Error: Incorrect indent at {filename}:{lineno + 1}')
84 line, code, comments = setline(contents, lineno, indent + line.strip())
86 if not code.endswith(','):
87 print(f'Error: Missing trailing "," in list at {filename}:{lineno + 1}')
88 line, code, comments = setline(contents, lineno, code + ',' + comments)
90 if len(code.split(',')) > 2: # only one comma per line
91 print(f'Error: multiple entries per line in list at {filename}:{lineno +1}')
92 entries = [e.strip() for e in code.split(',') if e.strip()]
93 line, code, comments = setline(contents, lineno,
94 indent + (',\n' + indent).join(entries) +
100 def process_file(filename, fix):
101 '''run checks on file "filename"'''
103 print(f'Processing {filename}')
104 with open(filename) as f:
105 contents = [ln.rstrip() for ln in f.readlines()]
107 if check_indentation(filename, contents) > 0 and fix:
108 print(f"Fixing {filename}")
109 with open(filename, 'w') as f:
110 f.writelines([f'{ln}\n' for ln in contents])
114 '''parse arguments and then call other functions to do work'''
116 parser = ArgumentParser(description='Run syntax checks on DPDK meson.build files')
117 parser.add_argument('-d', metavar='directory', default='.', help='Directory to process')
118 parser.add_argument('--fix', action='store_true', help='Attempt to fix errors')
119 parser.add_argument('-v', action='store_true', help='Verbose output')
120 args = parser.parse_args()
123 for f in scan_dir(args.d):
124 process_file(f, args.fix)
127 if __name__ == "__main__":