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
11 from os.path import relpath, join
12 from argparse import ArgumentParser
18 '''return meson.build files found in path'''
19 for root, dirs, files in os.walk(path):
20 if 'meson.build' in files:
21 yield(relpath(join(root, 'meson.build')))
24 def split_code_comments(line):
25 'splits a line into a code part and a comment part, returns (code, comment) tuple'
26 if line.lstrip().startswith('#'):
28 elif '#' in line and '#include' not in line: # catch 99% of cases, not 100%
30 while (line[idx - 1].isspace()):
32 return line[:idx], line[idx:]
37 def setline(contents, index, value):
38 'sets the contents[index] to value. Returns the line, along with code and comments part'
39 line = contents[index] = value
40 code, comments = split_code_comments(line)
41 return line, code, comments
44 def check_indentation(filename, contents):
45 '''check that a list or files() is correctly indented'''
49 for lineno, line in enumerate(contents):
50 code, comments = split_code_comments(line)
53 if code.endswith('files('):
55 raise(f'Error parsing {filename}:{lineno}, got "files(" when already parsing files list')
57 print(f'Error parsing {filename}:{lineno}, got "files(" when already parsing array list')
59 indent_count = len(code) - len(code.lstrip(' '))
60 indent = ' ' * (indent_count + 8) # double indent required
61 elif code.endswith('= ['):
63 raise(f'Error parsing {filename}:{lineno}, got start of array when already parsing files list')
65 print(f'Error parsing {filename}:{lineno}, got start of array when already parsing array list')
67 indent_count = len(code) - len(code.lstrip(' '))
68 indent = ' ' * (indent_count + 8) # double indent required
69 elif infiles and (code.endswith(')') or code.strip().startswith(')')):
72 elif inlist and (code.endswith(']') or code.strip().startswith(']')):
75 elif inlist or infiles:
76 # skip further subarrays or lists
77 if '[' in code or ']' in code:
79 if not code.startswith(indent) or code[len(indent)] == ' ':
80 print(f'Error: Incorrect indent at {filename}:{lineno + 1}')
81 line, code, comments = setline(contents, lineno, indent + line.strip())
83 if not code.endswith(','):
84 print(f'Error: Missing trailing "," in list at {filename}:{lineno + 1}')
85 line, code, comments = setline(contents, lineno, code + ',' + comments)
87 if len(code.split(',')) > 2: # only one comma per line
88 print(f'Error: multiple entries per line in list at {filename}:{lineno +1}')
89 entries = [e.strip() for e in code.split(',') if e.strip()]
90 line, code, comments = setline(contents, lineno,
91 indent + (',\n' + indent).join(entries) +
97 def process_file(filename, fix):
98 '''run checks on file "filename"'''
100 print(f'Processing {filename}')
101 with open(filename) as f:
102 contents = [ln.rstrip() for ln in f.readlines()]
104 if check_indentation(filename, contents) > 0 and fix:
105 print(f"Fixing {filename}")
106 with open(filename, 'w') as f:
107 f.writelines([f'{ln}\n' for ln in contents])
111 '''parse arguments and then call other functions to do work'''
113 parser = ArgumentParser(description='Run syntax checks on DPDK meson.build files')
114 parser.add_argument('-d', metavar='directory', default='.', help='Directory to process')
115 parser.add_argument('--fix', action='store_true', help='Attempt to fix errors')
116 parser.add_argument('-v', action='store_true', help='Verbose output')
117 args = parser.parse_args()
120 for f in scan_dir(args.d):
121 process_file(f, args.fix)
124 if __name__ == "__main__":