05f0d578e0
Requires Coverity Static Analysis to be installed on the machine running the script. The password is kept in a local file that is read by the script. Not tested on Windows but Chromium seem to run their script on Windows. We'll use Linux for the periodic execution. It has been running without issues for a month now. BUG= TEST=Tested successfully on my local Linux workstation with tools/coverity/coverity.py --source-dir=$HOME/code/webrtc/trunk --coverity-bin-dir=$HOME/coverity-integrity-center/static-analysis/bin --coverity-intermediate-dir=$HOME/cov-temp --coverity-db-host=webrtc-coverity.eem.corp.google.com --coverity-target=Linux --coverity-password-file=$HOME/coverity-password-file Review URL: https://webrtc-codereview.appspot.com/345001 git-svn-id: http://webrtc.googlecode.com/svn/trunk@1760 4adac7df-926f-26a2-2b94-8c16560cd09d
325 lines
12 KiB
Python
Executable File
325 lines
12 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
|
#
|
|
# Use of this source code is governed by a BSD-style license
|
|
# that can be found in the LICENSE file in the root of the source
|
|
# tree. An additional intellectual property rights grant can be found
|
|
# in the file PATENTS. All contributing project authors may
|
|
# be found in the AUTHORS file in the root of the source tree.
|
|
|
|
"""
|
|
Runs Coverity Static Analysis on a build of WebRTC.
|
|
|
|
This script is a modified copy of Chromium's tools/coverity/coverity.py
|
|
Changes made:
|
|
* Replaced deprecated switches for cov-commit-defects command:
|
|
* Using --host instead of --remote
|
|
* Using --stream instead of --product
|
|
* Removed --cxx (now default enabled)
|
|
* Changed cleaning of output path, since WebRTC's out dir is located directly
|
|
in trunk/
|
|
* Updated some default constants.
|
|
|
|
The script runs on all WebRTC supported platforms.
|
|
|
|
On Windows, this script should be run in a Visual Studio Command Prompt, so
|
|
that the INCLUDE, LIB, and PATH environment variables are set properly for
|
|
Visual Studio.
|
|
|
|
Usage examples:
|
|
coverity.py
|
|
coverity.py --dry-run
|
|
coverity.py --target=debug
|
|
%comspec% /c ""C:\Program Files\Microsoft Visual Studio 8\VC\vcvarsall.bat"
|
|
x86 && C:\Python24\python.exe C:\coverity.py"
|
|
|
|
For a full list of options, pass the '--help' switch.
|
|
|
|
See http://support.microsoft.com/kb/308569 for running this script as a
|
|
Scheduled Task on Windows XP.
|
|
"""
|
|
|
|
import optparse
|
|
import os
|
|
import os.path
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
|
|
# These constants provide default values, but are exposed as command-line
|
|
# flags. See the --help for more info. Note that for historical reasons
|
|
# (the script started out as Windows-only and has legacy usages which pre-date
|
|
# these switches), the constants are all tuned for Windows.
|
|
# Usage of this script on Linux pretty much requires explicit
|
|
# --source-dir, --coverity-bin-dir, --coverity-intermediate-dir, and
|
|
# --coverity-target command line flags.
|
|
|
|
WEBRTC_SOURCE_DIR = 'C:\\webrtc.latest'
|
|
|
|
# Relative to WEBRTC_SOURCE_DIR. Only applies to Windows platform.
|
|
WEBRTC_SOLUTION_FILE = 'webrtc.sln'
|
|
|
|
# Relative to WEBRTC_SOURCE_DIR. Only applies to Windows platform.
|
|
WEBRTC_SOLUTION_DIR = 'build'
|
|
|
|
COVERITY_BIN_DIR = 'C:\\coverity-integrity-center\\static-analysis\\bin'
|
|
|
|
COVERITY_INTERMEDIATE_DIR = 'C:\\coverity\\cvbuild\\cr_int'
|
|
|
|
COVERITY_ANALYZE_OPTIONS = ('--security --concurrency '
|
|
'--enable ATOMICITY '
|
|
'--enable MISSING_LOCK '
|
|
'--enable DELETE_VOID '
|
|
'--checker-option PASS_BY_VALUE:size_threshold:16 '
|
|
'--checker-option '
|
|
'USE_AFTER_FREE:allow_simple_use:false '
|
|
'--enable-constraint-fpp '
|
|
'--enable-callgraph-metrics')
|
|
|
|
# Might need to be changed to FQDN
|
|
COVERITY_REMOTE = 'localhost'
|
|
|
|
COVERITY_PORT = '8080'
|
|
|
|
COVERITY_STREAM = 'trunk'
|
|
|
|
COVERITY_TARGET = 'Windows'
|
|
|
|
COVERITY_USER = 'coverityanalyzer'
|
|
# looking for a PASSWORD constant? Look at --coverity-password-file instead.
|
|
|
|
# Relative to WEBRTC_SOURCE_DIR. Contains the pid of this script.
|
|
LOCK_FILE = 'coverity.lock'
|
|
|
|
|
|
def _ReadPassword(pwfilename):
|
|
"""Reads the coverity password in from a file where it was stashed"""
|
|
pwfile = open(pwfilename, 'r')
|
|
password = pwfile.readline()
|
|
pwfile.close()
|
|
return password.rstrip()
|
|
|
|
|
|
def _RunCommand(cmd, dry_run, shell=False, echo_cmd=True):
|
|
"""Runs the command if dry_run is false, otherwise just prints the command."""
|
|
if echo_cmd:
|
|
print cmd
|
|
if not dry_run:
|
|
return subprocess.call(cmd, shell=shell)
|
|
else:
|
|
return 0
|
|
|
|
|
|
def _ReleaseLock(lock_file, lock_filename):
|
|
"""Removes the lockfile. Function-ized so we can bail from anywhere"""
|
|
os.close(lock_file)
|
|
os.remove(lock_filename)
|
|
|
|
|
|
def run_coverity(options, args):
|
|
"""Runs all the selected tests for the given build type and target."""
|
|
# Create the lock file to prevent another instance of this script from
|
|
# running.
|
|
lock_filename = os.path.join(options.source_dir, LOCK_FILE)
|
|
try:
|
|
lock_file = os.open(lock_filename,
|
|
os.O_CREAT | os.O_EXCL | os.O_TRUNC | os.O_RDWR)
|
|
except OSError, err:
|
|
print 'Failed to open lock file:\n ' + str(err)
|
|
return 1
|
|
|
|
# Write the pid of this script (the python.exe process) to the lock file.
|
|
os.write(lock_file, str(os.getpid()))
|
|
|
|
options.target = options.target.title()
|
|
|
|
start_time = time.time()
|
|
|
|
print 'Change directory to ' + options.source_dir
|
|
os.chdir(options.source_dir)
|
|
|
|
# The coverity-password filename may have been a relative path.
|
|
# If so, assume it's relative to the source directory, which means
|
|
# the time to read the password is after we do the chdir().
|
|
coverity_password = _ReadPassword(options.coverity_password_file)
|
|
|
|
cmd = 'gclient sync'
|
|
gclient_exit = _RunCommand(cmd, options.dry_run, shell=True)
|
|
if gclient_exit != 0:
|
|
print 'gclient aborted with status %s' % gclient_exit
|
|
_ReleaseLock(lock_file, lock_filename)
|
|
return 1
|
|
|
|
print 'Elapsed time: %ds' % (time.time() - start_time)
|
|
|
|
# Do a clean build. Remove the build output directory first.
|
|
if sys.platform.startswith('linux'):
|
|
rm_path = os.path.join(options.source_dir,'out',options.target)
|
|
elif sys.platform == 'win32':
|
|
rm_path = os.path.join(options.source_dir,options.solution_dir,
|
|
options.target)
|
|
elif sys.platform == 'darwin':
|
|
rm_path = os.path.join(options.source_dir,'xcodebuild')
|
|
else:
|
|
print 'Platform "%s" unrecognized, aborting' % sys.platform
|
|
_ReleaseLock(lock_file, lock_filename)
|
|
return 1
|
|
|
|
if options.dry_run:
|
|
print 'shutil.rmtree(%s)' % repr(rm_path)
|
|
else:
|
|
shutil.rmtree(rm_path,True)
|
|
|
|
if options.preserve_intermediate_dir:
|
|
print 'Preserving intermediate directory.'
|
|
else:
|
|
if options.dry_run:
|
|
print 'shutil.rmtree(%s)' % repr(options.coverity_intermediate_dir)
|
|
print 'os.mkdir(%s)' % repr(options.coverity_intermediate_dir)
|
|
else:
|
|
shutil.rmtree(options.coverity_intermediate_dir,True)
|
|
os.mkdir(options.coverity_intermediate_dir)
|
|
|
|
print 'Elapsed time: %ds' % (time.time() - start_time)
|
|
|
|
use_shell_during_make = False
|
|
if sys.platform.startswith('linux'):
|
|
use_shell_during_make = True
|
|
_RunCommand('pwd', options.dry_run, shell=True)
|
|
cmd = '%s/cov-build --dir %s make BUILDTYPE=%s All' % (
|
|
options.coverity_bin_dir, options.coverity_intermediate_dir,
|
|
options.target)
|
|
elif sys.platform == 'win32':
|
|
cmd = ('%s\\cov-build.exe --dir %s devenv.com %s\\%s /build %s '
|
|
'/project webrtc.vcproj') % (
|
|
options.coverity_bin_dir, options.coverity_intermediate_dir,
|
|
options.source_dir, options.solution_file, options.target)
|
|
elif sys.platform == 'darwin':
|
|
use_shell_during_make = True
|
|
_RunCommand('pwd', options.dry_run, shell=True)
|
|
cmd = ('%s/cov-build --dir %s xcodebuild -project webrtc.xcodeproj '
|
|
'-configuration %s -target All') % (
|
|
options.coverity_bin_dir, options.coverity_intermediate_dir,
|
|
options.target)
|
|
|
|
|
|
_RunCommand(cmd, options.dry_run, shell=use_shell_during_make)
|
|
print 'Elapsed time: %ds' % (time.time() - start_time)
|
|
|
|
cov_analyze_exe = os.path.join(options.coverity_bin_dir,'cov-analyze')
|
|
cmd = '%s --dir %s %s' % (cov_analyze_exe,
|
|
options.coverity_intermediate_dir,
|
|
options.coverity_analyze_options)
|
|
_RunCommand(cmd, options.dry_run, shell=use_shell_during_make)
|
|
print 'Elapsed time: %ds' % (time.time() - start_time)
|
|
|
|
cov_commit_exe = os.path.join(options.coverity_bin_dir,'cov-commit-defects')
|
|
|
|
# On Linux we have started using a Target with a space in it, so we want
|
|
# to quote it. On the other hand, Windows quoting doesn't work quite the
|
|
# same way. To be conservative, I'd like to avoid quoting an argument
|
|
# that doesn't need quoting and which we haven't historically been quoting
|
|
# on that platform. So, only quote the target if we have to.
|
|
coverity_target = options.coverity_target
|
|
if sys.platform != 'win32':
|
|
coverity_target = '"%s"' % coverity_target
|
|
|
|
cmd = ('%s --dir %s --host %s --port %s '
|
|
'--stream %s '
|
|
'--target %s '
|
|
'--user %s '
|
|
'--password %s') % (cov_commit_exe,
|
|
options.coverity_intermediate_dir,
|
|
options.coverity_dbhost,
|
|
options.coverity_port,
|
|
options.coverity_stream,
|
|
coverity_target,
|
|
options.coverity_user,
|
|
coverity_password)
|
|
# Avoid echoing the Commit command because it has a password in it
|
|
print 'Commiting defects to Coverity Integrity Manager server...'
|
|
_RunCommand(cmd, options.dry_run, shell=use_shell_during_make, echo_cmd=False)
|
|
|
|
print 'Completed! Total time: %ds' % (time.time() - start_time)
|
|
|
|
_ReleaseLock(lock_file, lock_filename)
|
|
|
|
return 0
|
|
|
|
|
|
def main():
|
|
option_parser = optparse.OptionParser()
|
|
option_parser.add_option('', '--dry-run', action='store_true', default=False,
|
|
help='print but don\'t run the commands')
|
|
|
|
option_parser.add_option('', '--target', default='Release',
|
|
help='build target (Debug or Release)')
|
|
|
|
option_parser.add_option('', '--source-dir', dest='source_dir',
|
|
help='full path to directory ABOVE "src"',
|
|
default=WEBRTC_SOURCE_DIR)
|
|
|
|
option_parser.add_option('', '--solution-file', dest='solution_file',
|
|
help='filename of solution file to build (Win only)',
|
|
default=WEBRTC_SOLUTION_FILE)
|
|
|
|
option_parser.add_option('', '--solution-dir', dest='solution_dir',
|
|
help='build directory for the solution (Win only)',
|
|
default=WEBRTC_SOLUTION_DIR)
|
|
|
|
option_parser.add_option('', '--coverity-bin-dir', dest='coverity_bin_dir',
|
|
default=COVERITY_BIN_DIR)
|
|
|
|
option_parser.add_option('', '--coverity-intermediate-dir',
|
|
dest='coverity_intermediate_dir',
|
|
default=COVERITY_INTERMEDIATE_DIR)
|
|
|
|
option_parser.add_option('', '--coverity-analyze-options',
|
|
dest='coverity_analyze_options',
|
|
help=('all cov-analyze options, e.g. "%s"'
|
|
% COVERITY_ANALYZE_OPTIONS),
|
|
default=COVERITY_ANALYZE_OPTIONS)
|
|
|
|
option_parser.add_option('', '--coverity-db-host',
|
|
dest='coverity_dbhost',
|
|
help=('coverity defect db server hostname, e.g. %s'
|
|
% COVERITY_REMOTE),
|
|
default=COVERITY_REMOTE)
|
|
|
|
option_parser.add_option('', '--coverity-db-port', dest='coverity_port',
|
|
help=('port # of coverity web/db server, e.g. %s'
|
|
% COVERITY_PORT),
|
|
default=COVERITY_PORT)
|
|
|
|
option_parser.add_option('', '--coverity-stream', dest='coverity_stream',
|
|
help=('Name of stream reported to Coverity, e.g. %s'
|
|
% COVERITY_STREAM),
|
|
default=COVERITY_STREAM)
|
|
|
|
option_parser.add_option('', '--coverity-target', dest='coverity_target',
|
|
help='Platform Target reported to coverity',
|
|
default=COVERITY_TARGET)
|
|
|
|
option_parser.add_option('', '--coverity-user', dest='coverity_user',
|
|
help='Username used to log into coverity',
|
|
default=COVERITY_USER)
|
|
|
|
option_parser.add_option('', '--coverity-password-file',
|
|
dest='coverity_password_file',
|
|
help='file containing the coverity password',
|
|
default='coverity-password')
|
|
|
|
helpmsg = ('By default, the intermediate dir is emptied before analysis. '
|
|
'This switch disables that behavior.')
|
|
option_parser.add_option('', '--preserve-intermediate-dir',
|
|
action='store_true', help=helpmsg,
|
|
default=False)
|
|
|
|
options, args = option_parser.parse_args()
|
|
return run_coverity(options, args)
|
|
|
|
|
|
if '__main__' == __name__:
|
|
sys.exit(main())
|