fw4spl
cppcheck.py
1 #!/usr/bin/env python2
2 # -*- coding: utf-8 -*-
3 
4 """
5 Cppcheck your code.
6 
7 .gitconfig configuration :
8 
9 [fw4spl-hooks]
10  hooks = cppcheck
11 
12 [cppcheck]
13  source-patterns = *.cpp *.cxx *.c
14  header-patterns = *.hpp *.hxx *.h
15  cppcheck-path="C:/Program Files/Cppcheck/cppcheck.exe"
16 """
17 
18 import os
19 import re
20 import subprocess
21 from fnmatch import fnmatch
22 
23 import common
24 
25 SEPARATOR = '%s\n' % ('-' * 79)
26 CPPCHECK_PATH = 'cppcheck'
27 
28 
29 # ------------------------------------------------------------------------------
30 
31 # Can we run cppcheck ?
32 def check_cppcheck_install():
33  p = subprocess.Popen([CPPCHECK_PATH, '--version'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
34  p.communicate()
35 
36  return p.wait() != 0
37 
38 
39 # ------------------------------------------------------------------------------
40 
41 # Return True if cppcheck find errors in specified file
42 def check_file(file):
43  common.note('Checking with ' + CPPCHECK_PATH + ' file: ' + file)
44 
45  # Invoke cppcheck for source code files
46  p = subprocess.Popen([CPPCHECK_PATH, \
47  '--suppress=missingInclude', \
48  '--suppress=noExplicitConstructor', \
49  '--suppress=unmatchedSuppression', \
50  '--suppress=unusedFunction', \
51  '--enable=all', '--quiet', \
52  '--template={file}@!@{line}@!@{severity}@!@{message}', \
53  file], \
54  stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
55  out, err = p.communicate()
56 
57  if err is not None:
58  print(err)
59 
60  if out is not None:
61  print(out)
62 
63  if p.wait() != 0:
64  common.error('Cppcheck failure on file: ' + file)
65  common.error('Aborting')
66  return True
67 
68  if out:
69  common.error('Cppcheck failure on file: ' + file)
70  for line in out.splitlines():
71  words = re.findall('(.+)@!@(.+)@!@(.+)@!@(.+)', line)
72  if (words):
73  num_line = words[0][1]
74  severity = words[0][2]
75  message = words[0][3]
76  common.error('[%s] line %s: %s' % (severity, num_line, message))
77  common.error(SEPARATOR)
78  return True
79 
80  return False
81 
82 
83 # ------------------------------------------------------------------------------
84 
85 def cppcheck(files):
86  abort = False
87  source_patterns = common.get_option('cppcheck-hook.source-patterns', default='*.cpp *.cxx *.c').split()
88  header_patterns = common.get_option('cppcheck-hook.header-patterns', default='*.hpp *.hxx *.h').split()
89 
90  code_patterns = source_patterns + header_patterns
91 
92  global CPPCHECK_PATH
93 
94  if common.g_cppcheck_path_arg is not None and len(common.g_cppcheck_path_arg) > 0:
95  CPPCHECK_PATH = common.g_cppcheck_path_arg
96  else:
97  CPPCHECK_PATH = common.get_option('cppcheck-hook.cppcheck-path', default=CPPCHECK_PATH, type='--path').strip()
98 
99  if check_cppcheck_install():
100  common.error('Failed to launch cppcheck.=')
101  return True
102 
103  repoRoot = common.get_repo_root()
104  for f in files:
105  if any(fnmatch(f.path.lower(), p) for p in code_patterns):
106 
107  if not common.binary(f.contents):
108  file = os.path.join(repoRoot, f.path)
109  abort = check_file(file) or abort
110 
111  return abort
112 
113 
114 hooks = {
115  'cppcheck': cppcheck,
116 }
def get_repo_root()
Definition: common.py:71
def error(msg)
Definition: common.py:52
def binary(s)
Definition: common.py:60
def note(msg)
Definition: common.py:43
def get_option(option, default, type="")
Definition: common.py:150