ctdb-daemon: Use ctdb_parse_node_address() in ctdbd
[samba4-gss.git] / third_party / waf / waflib / extras / cpplint.py
blobafc09c9472ca40647fec2304233d28f3ba383302
1 #! /usr/bin/env python
2 # encoding: utf-8
4 # written by Sylvain Rouquette, 2014
6 '''
8 This is an extra tool, not bundled with the default waf binary.
9 To add the cpplint tool to the waf file:
10 $ ./waf-light --tools=compat15,cpplint
12 this tool also requires cpplint for python.
13 If you have PIP, you can install it like this: pip install cpplint
15 When using this tool, the wscript will look like:
17 def options(opt):
18 opt.load('compiler_cxx cpplint')
20 def configure(conf):
21 conf.load('compiler_cxx cpplint')
22 # optional, you can also specify them on the command line
23 conf.env.CPPLINT_FILTERS = ','.join((
24 '-whitespace/newline', # c++11 lambda
25 '-readability/braces', # c++11 constructor
26 '-whitespace/braces', # c++11 constructor
27 '-build/storage_class', # c++11 for-range
28 '-whitespace/blank_line', # user pref
29 '-whitespace/labels' # user pref
32 def build(bld):
33 bld(features='cpplint', source='main.cpp', target='app')
34 # add include files, because they aren't usually built
35 bld(features='cpplint', source=bld.path.ant_glob('**/*.hpp'))
36 '''
38 from __future__ import absolute_import
39 import sys, re
40 import logging
41 from waflib import Errors, Task, TaskGen, Logs, Options, Node, Utils
44 critical_errors = 0
45 CPPLINT_FORMAT = '[CPPLINT] %(filename)s:\nline %(linenum)s, severity %(confidence)s, category: %(category)s\n%(message)s\n'
46 RE_EMACS = re.compile(r'(?P<filename>.*):(?P<linenum>\d+): (?P<message>.*) \[(?P<category>.*)\] \[(?P<confidence>\d+)\]')
47 CPPLINT_RE = {
48 'waf': RE_EMACS,
49 'emacs': RE_EMACS,
50 'vs7': re.compile(r'(?P<filename>.*)\((?P<linenum>\d+)\): (?P<message>.*) \[(?P<category>.*)\] \[(?P<confidence>\d+)\]'),
51 'eclipse': re.compile(r'(?P<filename>.*):(?P<linenum>\d+): warning: (?P<message>.*) \[(?P<category>.*)\] \[(?P<confidence>\d+)\]'),
53 CPPLINT_STR = ('${CPPLINT} '
54 '--verbose=${CPPLINT_LEVEL} '
55 '--output=${CPPLINT_OUTPUT} '
56 '--filter=${CPPLINT_FILTERS} '
57 '--root=${CPPLINT_ROOT} '
58 '--linelength=${CPPLINT_LINE_LENGTH} ')
61 def options(opt):
62 opt.add_option('--cpplint-filters', type='string',
63 default='', dest='CPPLINT_FILTERS',
64 help='add filters to cpplint')
65 opt.add_option('--cpplint-length', type='int',
66 default=80, dest='CPPLINT_LINE_LENGTH',
67 help='specify the line length (default: 80)')
68 opt.add_option('--cpplint-level', default=1, type='int', dest='CPPLINT_LEVEL',
69 help='specify the log level (default: 1)')
70 opt.add_option('--cpplint-break', default=5, type='int', dest='CPPLINT_BREAK',
71 help='break the build if error >= level (default: 5)')
72 opt.add_option('--cpplint-root', type='string',
73 default='', dest='CPPLINT_ROOT',
74 help='root directory used to derive header guard')
75 opt.add_option('--cpplint-skip', action='store_true',
76 default=False, dest='CPPLINT_SKIP',
77 help='skip cpplint during build')
78 opt.add_option('--cpplint-output', type='string',
79 default='waf', dest='CPPLINT_OUTPUT',
80 help='select output format (waf, emacs, vs7, eclipse)')
83 def configure(conf):
84 try:
85 conf.find_program('cpplint', var='CPPLINT')
86 except Errors.ConfigurationError:
87 conf.env.CPPLINT_SKIP = True
90 class cpplint_formatter(Logs.formatter, object):
91 def __init__(self, fmt):
92 logging.Formatter.__init__(self, CPPLINT_FORMAT)
93 self.fmt = fmt
95 def format(self, rec):
96 if self.fmt == 'waf':
97 result = CPPLINT_RE[self.fmt].match(rec.msg).groupdict()
98 rec.msg = CPPLINT_FORMAT % result
99 if rec.levelno <= logging.INFO:
100 rec.c1 = Logs.colors.CYAN
101 return super(cpplint_formatter, self).format(rec)
104 class cpplint_handler(Logs.log_handler, object):
105 def __init__(self, stream=sys.stderr, **kw):
106 super(cpplint_handler, self).__init__(stream, **kw)
107 self.stream = stream
109 def emit(self, rec):
110 rec.stream = self.stream
111 self.emit_override(rec)
112 self.flush()
115 class cpplint_wrapper(object):
116 def __init__(self, logger, threshold, fmt):
117 self.logger = logger
118 self.threshold = threshold
119 self.fmt = fmt
121 def __enter__(self):
122 return self
124 def __exit__(self, exc_type, exc_value, traceback):
125 if isinstance(exc_value, Utils.subprocess.CalledProcessError):
126 messages = [m for m in exc_value.output.splitlines()
127 if 'Done processing' not in m
128 and 'Total errors found' not in m]
129 for message in messages:
130 self.write(message)
131 return True
133 def write(self, message):
134 global critical_errors
135 result = CPPLINT_RE[self.fmt].match(message)
136 if not result:
137 return
138 level = int(result.groupdict()['confidence'])
139 if level >= self.threshold:
140 critical_errors += 1
141 if level <= 2:
142 self.logger.info(message)
143 elif level <= 4:
144 self.logger.warning(message)
145 else:
146 self.logger.error(message)
149 cpplint_logger = None
150 def get_cpplint_logger(fmt):
151 global cpplint_logger
152 if cpplint_logger:
153 return cpplint_logger
154 cpplint_logger = logging.getLogger('cpplint')
155 hdlr = cpplint_handler()
156 hdlr.setFormatter(cpplint_formatter(fmt))
157 cpplint_logger.addHandler(hdlr)
158 cpplint_logger.setLevel(logging.DEBUG)
159 return cpplint_logger
162 class cpplint(Task.Task):
163 color = 'PINK'
165 def __init__(self, *k, **kw):
166 super(cpplint, self).__init__(*k, **kw)
168 def run(self):
169 global critical_errors
170 with cpplint_wrapper(get_cpplint_logger(self.env.CPPLINT_OUTPUT), self.env.CPPLINT_BREAK, self.env.CPPLINT_OUTPUT):
171 params = {key: str(self.env[key]) for key in self.env if 'CPPLINT_' in key}
172 if params['CPPLINT_OUTPUT'] == 'waf':
173 params['CPPLINT_OUTPUT'] = 'emacs'
174 params['CPPLINT'] = self.env.get_flat('CPPLINT')
175 cmd = Utils.subst_vars(CPPLINT_STR, params)
176 env = self.env.env or None
177 Utils.subprocess.check_output(cmd + self.inputs[0].abspath(),
178 stderr=Utils.subprocess.STDOUT,
179 env=env, shell=True)
180 return critical_errors
182 @TaskGen.extension('.h', '.hh', '.hpp', '.hxx')
183 def cpplint_includes(self, node):
184 pass
186 @TaskGen.feature('cpplint')
187 @TaskGen.before_method('process_source')
188 def post_cpplint(self):
189 if not self.env.CPPLINT_INITIALIZED:
190 for key, value in Options.options.__dict__.items():
191 if not key.startswith('CPPLINT_') or self.env[key]:
192 continue
193 self.env[key] = value
194 self.env.CPPLINT_INITIALIZED = True
196 if self.env.CPPLINT_SKIP:
197 return
199 if not self.env.CPPLINT_OUTPUT in CPPLINT_RE:
200 return
202 for src in self.to_list(getattr(self, 'source', [])):
203 if isinstance(src, Node.Node):
204 node = src
205 else:
206 node = self.path.find_or_declare(src)
207 if not node:
208 self.bld.fatal('Could not find %r' % src)
209 self.create_task('cpplint', node)