5 Make sure you respect the minimal coding rules and gently reformat files for you. 7 .gitconfig configuration : 13 source-patterns = *.cpp *.cxx *.c 14 header-patterns = *.hpp *.hxx *.h 15 misc-patterns = *.cmake *.txt *.xml *.json 16 uncrustify-path=C:\Program files\uncrustify\uncrustify.exe 17 additional-projects = "D:/Dev/src/fw4spl-ar;D:/Dev/src/fw4spl-ext" 19 Available options are : 20 source-patterns : file patterns to process as source code files - default to *.cpp *.cxx *.c 21 header-patterns : file patterns to process as header files - default to *.hpp *.hxx *.h 22 misc-patterns : file patterns to process as non-source code files (build, configuration, etc...) 23 Reformatting is limited to TABs and EOL - default to *.options *.cmake *.txt *.xml 24 uncrustify-path : path to the uncrustify program - default to uncrustify 25 additional-projects : additional fw4spl repositories paths used to sort includes (separated with a ;). 26 default parent folder of the current repository. 32 from fnmatch
import fnmatch
36 from common
import FormatReturn
38 SEPARATOR =
'%s\n' % (
'-' * 79)
40 UNCRUSTIFY_PATH =
'uncrustify' 41 BACKUP_LIST_FILE =
'backupList' 43 LICENSE =
'/\* \*\*\*\*\* BEGIN LICENSE BLOCK \*\*\*\*\*\n\ 44 \* FW4SPL - Copyright \(C\) IRCAD, (.*).\n\ 45 \* Distributed under the terms of the GNU Lesser General Public License \(LGPL\) as\n\ 46 \* published by the Free Software Foundation.\n\ 47 \* \*\*\*\*\*\* END LICENSE BLOCK \*\*\*\*\*\* \*/' 52 def codingstyle(files, enable_reformat, check_lgpl, check_commits_date):
53 source_patterns =
common.get_option(
'codingstyle-hook.source-patterns', default=
'*.cpp *.cxx *.c').split()
54 header_patterns =
common.get_option(
'codingstyle-hook.header-patterns', default=
'*.hpp *.hxx *.h').split()
55 misc_patterns =
common.get_option(
'codingstyle-hook.misc-patterns', default=
'*.cmake *.txt *.xml *.json').split()
57 code_patterns = source_patterns + header_patterns
58 include_patterns = code_patterns + misc_patterns
60 sort_includes =
common.get_option(
'codingstyle-hook.sort-includes', default=
"true", type=
'--bool') ==
"true" 66 common.warn(
"Cannot find 'fw4spl' repository structure")
69 parent_repo = os.path.abspath(os.path.join(repoRoot, os.pardir))
71 fw4spl_configured_projects =
common.get_option(
'codingstyle-hook.additional-projects', default=
None)
74 if fw4spl_configured_projects
is None:
76 fw4spl_projects.append(parent_repo)
78 fw4spl_projects = fw4spl_configured_projects.split(
";")
80 fw4spl_projects.append(repoRoot)
82 fw4spl_projects = map(os.path.normpath, fw4spl_projects)
84 fw4spl_projects = list(set(fw4spl_projects))
86 global UNCRUSTIFY_PATH
88 if common.g_uncrustify_path_arg
is not None and len(common.g_uncrustify_path_arg) > 0:
89 UNCRUSTIFY_PATH = common.g_uncrustify_path_arg
91 UNCRUSTIFY_PATH =
common.get_option(
'codingstyle-hook.uncrustify-path', default=UNCRUSTIFY_PATH,
92 type=
'--path').strip()
102 reformatted_list = []
109 if f
in checked
or not any(f.fnmatch(p)
for p
in include_patterns):
117 file_path = os.path.join(repoRoot, f.path)
118 if os.path.isfile(file_path):
119 res = format_file(file_path, enable_reformat, code_patterns, header_patterns, misc_patterns, check_lgpl,
120 sort_includes, f.status, check_commits_date)
122 if res == FormatReturn.Modified:
123 reformatted_list.append(f.path)
125 elif res == FormatReturn.Error:
131 common.note(
'%d file(s) checked, %d file(s) reformatted.' % (count, reformat_count))
133 return ret, reformatted_list
140 def format_file(source_file, enable_reformat, code_patterns, header_patterns, misc_patterns, check_lgpl, sort_includes,
141 status, check_commits_date):
143 if any(fnmatch(source_file, p)
for p
in code_patterns):
145 common.trace(
'Launching uncrustify on : ' + source_file)
146 config_file = os.path.join(os.path.dirname(__file__),
'uncrustify.cfg')
151 if check_lgpl
is True:
152 ret.add(fix_license_year(source_file, enable_reformat, status, check_commits_date))
155 if sort_includes
is True:
158 if any(fnmatch(source_file, p)
for p
in header_patterns):
159 ret.add(fix_header_guard(source_file, enable_reformat))
162 command = UNCRUSTIFY_PATH +
' -c ' + config_file +
' -q %s ' + source_file
164 if enable_reformat
is True:
168 if uncrustify.status != 0:
170 if uncrustify.status != 0:
171 common.error(
'Uncrustify failure on file: ' + source_file)
173 return FormatReturn.Error
174 ret.add(FormatReturn.Modified)
178 if uncrustify.status != 0:
179 common.error(
'Uncrustify failure on file: ' + source_file)
180 return FormatReturn.Error
185 elif any(fnmatch(source_file, p)
for p
in misc_patterns):
187 common.trace(
'Parsing: ' + source_file +
' to replace CR, CRLF and TABs')
189 str_old_file = open(source_file,
'rb').read()
191 str_new_file = re.sub(
'\t',
' ', str_old_file)
192 tmp_str = re.sub(
'\r\n',
'\n', str_new_file)
193 str_new_file = re.sub(
'\r',
'\n', tmp_str)
195 if str_old_file == str_new_file:
196 return FormatReturn.NotModified
199 open(source_file,
'wb').write(str_new_file)
200 return FormatReturn.Modified
206 def fix_license_year(path, enable_reformat, status, check_commits_date):
207 with open(path,
'r') as source_file: 208 content = source_file.read() 215 licence_number = len(re.findall(LICENSE, content, re.MULTILINE))
216 if licence_number > 1:
218 common.error(
"There should be just one licence header per file in :" + FILEWARN(path) +
".")
219 return FormatReturn.Error
221 elif licence_number < 1:
226 lic = lic.replace(
"(.*)",
"%s-%s" % (YEAR, YEAR))
227 lic = lic.replace(
"\\",
"")
229 with open(path,
'wb')
as source_file:
231 source_file.write(lic +
"\n\n")
232 source_file.write(content)
234 common.note(
'LGPL license header fixed in : ' + FILEWARN(path) +
'.')
235 return FormatReturn.Modified
239 common.error(
"There should be at least one licence header per file in :" + FILEWARN(path) +
".")
240 return FormatReturn.Error
245 LICENSE_YEAR =
r"(.*)FW4SPL - Copyright \(C\) IRCAD, ([0-9]+)." 246 LICENSE_YEAR_RANGE =
r"(.*)FW4SPL - Copyright \(C\) IRCAD, ([0-9]+)-([0-9]+)." 249 if re.search(LICENSE_YEAR_RANGE, content):
251 LICENSE_YEAR_REPLACE =
r"\1FW4SPL - Copyright (C) IRCAD, \2-" + str(YEAR) +
"." 252 str_new_file = re.sub(LICENSE_YEAR_RANGE, LICENSE_YEAR_REPLACE, content)
256 match = re.search(LICENSE_YEAR, content)
260 if status ==
'A' or match.group(2) == str(YEAR):
262 LICENSE_YEAR_REPLACE =
r"\1FW4SPL - Copyright (C) IRCAD, " + str(YEAR) +
"." 263 str_new_file = re.sub(LICENSE_YEAR, LICENSE_YEAR_REPLACE, content)
267 LICENSE_YEAR_REPLACE =
r"\1FW4SPL - Copyright (C) IRCAD, \2-" + str(YEAR) +
"." 268 str_new_file = re.sub(LICENSE_YEAR, LICENSE_YEAR_REPLACE, content)
271 common.error(
'Licence year format in : ' + FILEWARN(path) +
' is not correct.')
272 return FormatReturn.Error
274 if str_new_file != content:
278 common.note(
'Licence year fixed in : ' + FILEWARN(path))
279 with open(path,
'wb')
as source_file:
280 source_file.write(str_new_file)
281 return FormatReturn.Modified
285 common.error(
'Licence year in : ' + FILEWARN(path) +
' is not up-to-date.')
286 return FormatReturn.Error
288 return FormatReturn.NotModified
294 def fix_header_guard(path, enable_reformat):
297 with open(path,
'r') as source_file: 298 content = source_file.read() 301 single_comment =
"(\/\/([^(\n|\r)]|\(|\))*)" 302 multi_comment =
"(\/\*([^\*\/]|\*[^\/]|\/)*\*\/)" 303 useless_char =
"\t| |\r" 304 pragma_once =
"#pragma(" + useless_char +
")+once" 305 all_before_pragma =
".*" + pragma_once +
"(" + useless_char +
")*\n" 308 path_upper = path.upper()
309 path_upper = path_upper.replace(
"\\",
"/")
310 substrings = path_upper.split(
'/');
313 for i
in range(0, len(substrings)):
314 if substrings[i] ==
"INCLUDE":
316 elif substrings[i] ==
"TEST":
317 res += substrings[i - 1].upper() +
"_UT_";
319 res += substrings[i].upper() +
"_";
320 expected_guard = res.split(
'.');
321 expected_guard[0] +=
"_HPP__";
323 expected_guard = expected_guard[0]
326 while len(re.findall(
"#(ifndef|define|endif)((" + useless_char +
")|(/\*)|(\/\/))*" + expected_guard +
"[^\n]*",
327 content, re.DOTALL)) != 0:
329 match2 = re.search(
"#(ifndef|define|endif)((" + useless_char +
")|(/\*)|(\/\/))*" + expected_guard +
"[^\n]*",
333 content = content.replace(match2.group(0),
"")
334 common.note(
"Old style of header guard fixed : " + match2.group(0) +
"in file : " + FILEWARN(path) +
".")
335 with open(path,
'wb')
as source_file:
336 source_file.write(content)
337 ret.add(FormatReturn.Modified)
341 common.error(
"Old style of header guard found : " + match2.group(0) +
"in file : " + FILEWARN(path) +
".")
342 ret.add(FormatReturn.Error)
346 pragma_number = len(re.findall(pragma_once, content, re.MULTILINE))
347 if pragma_number > 1:
349 common.error(
"There should be just one '#pragma once' per file in :" + FILEWARN(path) +
".")
350 ret.add(FormatReturn.Error)
353 elif pragma_number < 1:
358 match = re.search(
"(" + single_comment +
"|" + multi_comment +
"|" + useless_char +
"|\n)*", content,
361 with open(path,
'wb')
as source_file:
362 source_file.write(match.group(0))
363 source_file.write(
"#pragma once\n\n")
364 source_file.write(content.replace(match.group(0),
""))
366 common.note(
"'#pragma once' fixed in :" + FILEWARN(path))
368 ret.add(FormatReturn.Modified)
373 common.error(
"There should be at least one '#pragma once' per file in :" + FILEWARN(path) +
".")
374 ret.add(FormatReturn.Error)
380 out = re.search(all_before_pragma, content, re.DOTALL).group(0)
383 match2 = re.search(pragma_once, out, re.DOTALL)
384 out = out.replace(match2.group(0),
"")
387 while len(re.findall(multi_comment, out, re.DOTALL)) != 0:
388 match2 = re.search(multi_comment, out, re.DOTALL)
389 out = out.replace(match2.group(0),
"")
392 while len(re.findall(single_comment, out, re.DOTALL)) != 0:
393 match2 = re.search(single_comment, out, re.DOTALL)
394 out = out.replace(match2.group(0),
"")
397 if len(re.findall(
"[^\n]", out, re.DOTALL)) != 0:
399 (
"Unexpected : '%s' befor #pragma once in :" % re.search(
"^.+$", out, re.MULTILINE).group(0)) + FILEWARN(
401 ret.add(FormatReturn.Error)
405 if len(re.findall(
"#pragma once", content, re.DOTALL)) == 0:
409 out = re.search(all_before_pragma, content, re.DOTALL).group(0)
412 match2 = re.search(pragma_once, out, re.DOTALL)
413 out2 = out.replace(match2.group(0),
"")
415 with open(path,
'wb')
as source_file:
417 source_file.write(out2)
418 source_file.write(
"#pragma once\n")
419 source_file.write(content.replace(out,
""))
421 ret.add(FormatReturn.Modified)
426 common.error(
"Needed : '#pragma once', actual : '" + re.search(pragma_once, content, re.DOTALL).group(
427 0) +
"' in file :" + FILEWARN(path) +
".")
428 ret.add(FormatReturn.Error)
431 ret.add(FormatReturn.NotModified)
def get_file_datetime(path, check_commits_date)
def find_libraries_and_bundles(fw4spl_projects)
def execute_command(proc)
def get_option(option, default, type="")
def sort_includes(path, enable_reformat)