Skip to content

Commit c021305

Browse files
committed
📝 Update tools/validate_config.py
1 parent 59051c2 commit c021305

1 file changed

Lines changed: 187 additions & 0 deletions

File tree

tools/validate_config.py

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
#!/usr/bin/env python3
2+
3+
import fnmatch
4+
import os
5+
import re
6+
import ntpath
7+
import sys
8+
import argparse
9+
10+
def check_config_style(filepath):
11+
bad_count_file = 0
12+
def pushClosing(t):
13+
closingStack.append(closing.expr)
14+
closing << Literal( closingFor[t[0]] )
15+
16+
def popClosing():
17+
closing << closingStack.pop()
18+
19+
reIsClass = re.compile(r'^\s*class(.*)')
20+
reIsClassInherit = re.compile(r'^\s*class(.*):')
21+
reIsClassBody = re.compile(r'^\s*class(.*){')
22+
reBadColon = re.compile(r'\s*class (.*) :')
23+
reSpaceAfterColon = re.compile(r'\s*class (.*): ')
24+
reSpaceBeforeCurly = re.compile(r'\s*class (.*) {')
25+
reClassSingleLine = re.compile(r'\s*class (.*)[{;]')
26+
27+
with open(filepath, 'r', encoding='utf-8', errors='ignore') as file:
28+
content = file.read()
29+
30+
# Store all brackets we find in this file, so we can validate everything on the end
31+
brackets_list = []
32+
33+
# To check if we are in a comment block
34+
isInCommentBlock = False
35+
checkIfInComment = False
36+
# Used in case we are in a line comment (//)
37+
ignoreTillEndOfLine = False
38+
# Used in case we are in a comment block (/* */). This is true if we detect a * inside a comment block.
39+
# If the next character is a /, it means we end our comment block.
40+
checkIfNextIsClosingBlock = False
41+
42+
# We ignore everything inside a string
43+
isInString = False
44+
# Used to store the starting type of a string, so we can match that to the end of a string
45+
inStringType = '';
46+
47+
lastIsCurlyBrace = False
48+
checkForSemiColumn = False
49+
50+
# Extra information so we know what line we find errors at
51+
lineNumber = 1
52+
53+
indexOfCharacter = 0
54+
# Parse all characters in the content of this file to search for potential errors
55+
for c in content:
56+
if (lastIsCurlyBrace):
57+
lastIsCurlyBrace = False
58+
if c == '\n': # Keeping track of our line numbers
59+
lineNumber += 1 # so we can print accurate line number information when we detect a possible error
60+
if (isInString): # while we are in a string, we can ignore everything else, except the end of the string
61+
if (c == inStringType):
62+
isInString = False
63+
# if we are not in a comment block, we will check if we are at the start of one or count the () {} and []
64+
elif (isInCommentBlock == False):
65+
66+
# This means we have encountered a /, so we are now checking if this is an inline comment or a comment block
67+
if (checkIfInComment):
68+
checkIfInComment = False
69+
if c == '*': # if the next character after / is a *, we are at the start of a comment block
70+
isInCommentBlock = True
71+
elif (c == '/'): # Otherwise, will check if we are in an line comment
72+
ignoreTillEndOfLine = True # and an line comment is a / followed by another / (//) We won't care about anything that comes after it
73+
74+
if (isInCommentBlock == False):
75+
if (ignoreTillEndOfLine): # we are in a line comment, just continue going through the characters until we find an end of line
76+
if (c == '\n'):
77+
ignoreTillEndOfLine = False
78+
else: # validate brackets
79+
if (c == '"' or c == "'"):
80+
isInString = True
81+
inStringType = c
82+
elif (c == '/'):
83+
checkIfInComment = True
84+
elif (c == '('):
85+
brackets_list.append('(')
86+
elif (c == ')'):
87+
if (len(brackets_list) > 0 and brackets_list[-1] in ['{', '[']):
88+
print("ERROR: Possible missing round bracket ')' detected at {0} Line number: {1}".format(filepath,lineNumber))
89+
bad_count_file += 1
90+
brackets_list.append(')')
91+
elif (c == '['):
92+
brackets_list.append('[')
93+
elif (c == ']'):
94+
if (len(brackets_list) > 0 and brackets_list[-1] in ['{', '(']):
95+
print("ERROR: Possible missing square bracket ']' detected at {0} Line number: {1}".format(filepath,lineNumber))
96+
bad_count_file += 1
97+
brackets_list.append(']')
98+
elif (c == '{'):
99+
brackets_list.append('{')
100+
elif (c == '}'):
101+
lastIsCurlyBrace = True
102+
if (len(brackets_list) > 0 and brackets_list[-1] in ['(', '[']):
103+
print("ERROR: Possible missing curly brace '}}' detected at {0} Line number: {1}".format(filepath,lineNumber))
104+
bad_count_file += 1
105+
brackets_list.append('}')
106+
elif (c== '\t'):
107+
print("ERROR: Tab detected at {0} Line number: {1}".format(filepath,lineNumber))
108+
bad_count_file += 1
109+
110+
else: # Look for the end of our comment block
111+
if (c == '*'):
112+
checkIfNextIsClosingBlock = True;
113+
elif (checkIfNextIsClosingBlock):
114+
if (c == '/'):
115+
isInCommentBlock = False
116+
elif (c != '*'):
117+
checkIfNextIsClosingBlock = False
118+
indexOfCharacter += 1
119+
120+
if brackets_list.count('[') != brackets_list.count(']'):
121+
print("ERROR: A possible missing square bracket [ or ] in file {0} [ = {1} ] = {2}".format(filepath,brackets_list.count('['),brackets_list.count(']')))
122+
bad_count_file += 1
123+
if brackets_list.count('(') != brackets_list.count(')'):
124+
print("ERROR: A possible missing round bracket ( or ) in file {0} ( = {1} ) = {2}".format(filepath,brackets_list.count('('),brackets_list.count(')')))
125+
bad_count_file += 1
126+
if brackets_list.count('{') != brackets_list.count('}'):
127+
print("ERROR: A possible missing curly brace {{ or }} in file {0} {{ = {1} }} = {2}".format(filepath,brackets_list.count('{'),brackets_list.count('}')))
128+
bad_count_file += 1
129+
130+
file.seek(0)
131+
for lineNumber, line in enumerate(file.readlines()):
132+
if reIsClass.match(line):
133+
if reBadColon.match(line):
134+
print(f"WARNING: bad class colon {filepath} Line number: {lineNumber+1}")
135+
# bad_count_file += 1
136+
if reIsClassInherit.match(line):
137+
if not reSpaceAfterColon.match(line):
138+
print(f"WARNING: bad class missing space after colon {filepath} Line number: {lineNumber+1}")
139+
if reIsClassBody.match(line):
140+
if not reSpaceBeforeCurly.match(line):
141+
print(f"WARNING: bad class inherit missing space before curly braces {filepath} Line number: {lineNumber+1}")
142+
if not reClassSingleLine.match(line):
143+
print(f"WARNING: bad class braces placement {filepath} Line number: {lineNumber+1}")
144+
# bad_count_file += 1
145+
146+
return bad_count_file
147+
148+
def main():
149+
150+
print("Validating Config Style")
151+
152+
sqf_list = []
153+
bad_count = 0
154+
155+
parser = argparse.ArgumentParser()
156+
parser.add_argument('-m','--module', help='only search specified module addon folder', required=False, default="")
157+
args = parser.parse_args()
158+
159+
for folder in ['addons', 'optionals']:
160+
# Allow running from root directory as well as from inside the tools directory
161+
rootDir = "../" + folder
162+
if (os.path.exists(folder)):
163+
rootDir = folder
164+
165+
for root, dirnames, filenames in os.walk(rootDir + '/' + args.module):
166+
for filename in fnmatch.filter(filenames, '*.cpp'):
167+
sqf_list.append(os.path.join(root, filename))
168+
for filename in fnmatch.filter(filenames, '*.hpp'):
169+
sqf_list.append(os.path.join(root, filename))
170+
for filename in fnmatch.filter(filenames, '*.rvmat'):
171+
sqf_list.append(os.path.join(root, filename))
172+
for filename in fnmatch.filter(filenames, '*.cfg'):
173+
sqf_list.append(os.path.join(root, filename))
174+
175+
for filename in sqf_list:
176+
bad_count = bad_count + check_config_style(filename)
177+
178+
print("------\nChecked {0} files\nErrors detected: {1}".format(len(sqf_list), bad_count))
179+
if (bad_count == 0):
180+
print("Config validation PASSED")
181+
else:
182+
print("Config validation FAILED")
183+
184+
return bad_count
185+
186+
if __name__ == "__main__":
187+
sys.exit(main())

0 commit comments

Comments
 (0)