spawn a subprocess for cpplint to avoid threading issue

This commit is contained in:
Daniel Bartel 2018-08-10 23:49:52 +02:00
parent 04e1b65ecb
commit ef90934434
1 changed files with 29 additions and 42 deletions

View File

@ -38,15 +38,7 @@ When using this tool, the wscript will look like:
from __future__ import absolute_import from __future__ import absolute_import
import sys, re import sys, re
import logging import logging
import threading from waflib import Errors, Task, TaskGen, Logs, Options, Node, Utils
from waflib import Task, TaskGen, Logs, Options, Node
try:
import cpplint.cpplint as cpplint_tool
except ImportError:
try:
import cpplint as cpplint_tool
except ImportError:
pass
critical_errors = 0 critical_errors = 0
@ -58,6 +50,13 @@ CPPLINT_RE = {
'vs7': re.compile('(?P<filename>.*)\((?P<linenum>\d+)\): (?P<message>.*) \[(?P<category>.*)\] \[(?P<confidence>\d+)\]'), 'vs7': re.compile('(?P<filename>.*)\((?P<linenum>\d+)\): (?P<message>.*) \[(?P<category>.*)\] \[(?P<confidence>\d+)\]'),
'eclipse': re.compile('(?P<filename>.*):(?P<linenum>\d+): warning: (?P<message>.*) \[(?P<category>.*)\] \[(?P<confidence>\d+)\]'), 'eclipse': re.compile('(?P<filename>.*):(?P<linenum>\d+): warning: (?P<message>.*) \[(?P<category>.*)\] \[(?P<confidence>\d+)\]'),
} }
CPPLINT_STR = ('${CPPLINT} '
'--verbose=${CPPLINT_LEVEL} '
'--output=${CPPLINT_OUTPUT} '
'--filter=${CPPLINT_FILTERS} '
'--root=${CPPLINT_ROOT} '
'--linelength=${CPPLINT_LINE_LENGTH} ')
def options(opt): def options(opt):
opt.add_option('--cpplint-filters', type='string', opt.add_option('--cpplint-filters', type='string',
@ -71,24 +70,21 @@ def options(opt):
opt.add_option('--cpplint-break', default=5, type='int', dest='CPPLINT_BREAK', opt.add_option('--cpplint-break', default=5, type='int', dest='CPPLINT_BREAK',
help='break the build if error >= level (default: 5)') help='break the build if error >= level (default: 5)')
opt.add_option('--cpplint-root', type='string', opt.add_option('--cpplint-root', type='string',
default=None, dest='CPPLINT_ROOT', default='', dest='CPPLINT_ROOT',
help='root directory used to derive header guard') help='root directory used to derive header guard')
opt.add_option('--cpplint-skip', action='store_true', opt.add_option('--cpplint-skip', action='store_true',
default=False, dest='CPPLINT_SKIP', default=False, dest='CPPLINT_SKIP',
help='skip cpplint during build') help='skip cpplint during build')
opt.add_option('--cpplint-output', type='string', opt.add_option('--cpplint-output', type='string',
default='waf', dest='CPPLINT_OUTPUT', default='waf', dest='CPPLINT_OUTPUT',
help='select output format (waf, emacs, vs7)') help='select output format (waf, emacs, vs7, eclipse)')
def configure(conf): def configure(conf):
conf.start_msg('Checking cpplint')
try: try:
cpplint_tool._cpplint_state conf.find_program('cpplint', var='CPPLINT')
conf.end_msg('ok') except Errors.ConfigurationError:
except NameError:
conf.env.CPPLINT_SKIP = True conf.env.CPPLINT_SKIP = True
conf.end_msg('not found, skipping it.')
class cpplint_formatter(Logs.formatter, object): class cpplint_formatter(Logs.formatter, object):
@ -117,34 +113,22 @@ class cpplint_handler(Logs.log_handler, object):
class cpplint_wrapper(object): class cpplint_wrapper(object):
stream = None
tasks_count = 0
lock = threading.RLock()
def __init__(self, logger, threshold, fmt): def __init__(self, logger, threshold, fmt):
self.logger = logger self.logger = logger
self.threshold = threshold self.threshold = threshold
self.error_count = 0
self.fmt = fmt self.fmt = fmt
def __enter__(self): def __enter__(self):
with cpplint_wrapper.lock: return self
cpplint_wrapper.tasks_count += 1
if cpplint_wrapper.tasks_count == 1:
sys.stderr.flush()
cpplint_wrapper.stream = sys.stderr
sys.stderr = self
return self
def __exit__(self, exc_type, exc_value, traceback): def __exit__(self, exc_type, exc_value, traceback):
with cpplint_wrapper.lock: if isinstance(exc_value, Utils.subprocess.CalledProcessError):
cpplint_wrapper.tasks_count -= 1 messages = [m for m in exc_value.output.splitlines()
if cpplint_wrapper.tasks_count == 0: if 'Done processing' not in m
sys.stderr = cpplint_wrapper.stream and 'Total errors found' not in m]
sys.stderr.flush() for message in messages:
self.write(message)
def isatty(self): return True
return True
def write(self, message): def write(self, message):
global critical_errors global critical_errors
@ -184,12 +168,15 @@ class cpplint(Task.Task):
def run(self): def run(self):
global critical_errors global critical_errors
with cpplint_wrapper(get_cpplint_logger(self.env.CPPLINT_OUTPUT), self.env.CPPLINT_BREAK, self.env.CPPLINT_OUTPUT): with cpplint_wrapper(get_cpplint_logger(self.env.CPPLINT_OUTPUT), self.env.CPPLINT_BREAK, self.env.CPPLINT_OUTPUT):
if self.env.CPPLINT_OUTPUT != 'waf': params = {key: str(self.env[key]) for key in self.env if 'CPPLINT_' in key}
cpplint_tool._SetOutputFormat(self.env.CPPLINT_OUTPUT) if params['CPPLINT_OUTPUT'] is 'waf':
cpplint_tool._SetFilters(self.env.CPPLINT_FILTERS) params['CPPLINT_OUTPUT'] = 'emacs'
cpplint_tool._line_length = self.env.CPPLINT_LINE_LENGTH params['CPPLINT'] = self.env.get_flat('CPPLINT')
cpplint_tool._root = self.env.CPPLINT_ROOT cmd = Utils.subst_vars(CPPLINT_STR, params)
cpplint_tool.ProcessFile(self.inputs[0].abspath(), self.env.CPPLINT_LEVEL) env = self.env.env or None
Utils.subprocess.check_output(cmd + self.inputs[0].abspath(),
stderr=Utils.subprocess.STDOUT,
env=env, shell=True)
return critical_errors return critical_errors
@TaskGen.extension('.h', '.hh', '.hpp', '.hxx') @TaskGen.extension('.h', '.hh', '.hpp', '.hxx')