Don't strip scheme from parameter when running external protocol handler
[chromium-blink-merge.git] / tools / coverity / coverity.py
blob6fed7ca8cfa9628f94f8ee67fd130cc8aa6a5955
1 #!/usr/bin/env python
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """
7 Runs Coverity Prevent on a build of Chromium.
9 This script should be run in a Visual Studio Command Prompt, so that the
10 INCLUDE, LIB, and PATH environment variables are set properly for Visual
11 Studio.
13 Usage examples:
14 coverity.py
15 coverity.py --dry-run
16 coverity.py --target=debug
17 %comspec% /c ""C:\Program Files\Microsoft Visual Studio 8\VC\vcvarsall.bat"
18 x86 && C:\Python24\python.exe C:\coverity.py"
20 For a full list of options, pass the '--help' switch.
22 See http://support.microsoft.com/kb/308569 for running this script as a
23 Scheduled Task on Windows XP.
25 """
27 import optparse
28 import os
29 import os.path
30 import shutil
31 import subprocess
32 import sys
33 import time
35 # These constants provide default values, but are exposed as command-line
36 # flags. See the --help for more info. Note that for historical reasons
37 # (the script started out as Windows-only and has legacy usages which pre-date
38 # these switches), the constants are all tuned for Windows.
39 # Usage of this script on Linux pretty much requires explicit
40 # --source-dir, --coverity-bin-dir, --coverity-intermediate-dir, and
41 # --coverity-target command line flags.
43 CHROMIUM_SOURCE_DIR = 'C:\\chromium.latest'
45 # Relative to CHROMIUM_SOURCE_DIR.
46 CHROMIUM_SOLUTION_FILE = 'src\\chrome\\chrome.sln'
48 # Relative to CHROMIUM_SOURCE_DIR.
49 CHROMIUM_SOLUTION_DIR = 'src\\chrome'
51 COVERITY_BIN_DIR = 'C:\\coverity\\prevent-win32-4.5.1\\bin'
53 COVERITY_INTERMEDIATE_DIR = 'C:\\coverity\\cvbuild\\cr_int'
55 COVERITY_ANALYZE_OPTIONS = ('--cxx --security --concurrency '
56 '--enable ATOMICITY '
57 '--enable MISSING_LOCK '
58 '--enable DELETE_VOID '
59 '--checker-option PASS_BY_VALUE:size_threshold:16 '
60 '--checker-option '
61 'USE_AFTER_FREE:allow_simple_use:false '
62 '--enable-constraint-fpp '
63 '--enable-callgraph-metrics')
65 # Might need to be changed to FQDN
66 COVERITY_REMOTE = 'chromecoverity-linux1'
68 COVERITY_PORT = '5467'
70 COVERITY_PRODUCT = 'Chromium'
72 COVERITY_TARGET = 'Windows'
74 COVERITY_USER = 'admin'
75 # looking for a PASSWORD constant? Look at --coverity-password-file instead.
77 # Relative to CHROMIUM_SOURCE_DIR. Contains the pid of this script.
78 LOCK_FILE = 'coverity.lock'
81 def _ReadPassword(pwfilename):
82 """Reads the coverity password in from a file where it was stashed"""
83 pwfile = open(pwfilename, 'r')
84 password = pwfile.readline()
85 pwfile.close()
86 return password.rstrip()
89 def _RunCommand(cmd, dry_run, shell=False, echo_cmd=True):
90 """Runs the command if dry_run is false, otherwise just prints the command."""
91 if echo_cmd:
92 print cmd
93 if not dry_run:
94 return subprocess.call(cmd, shell=shell)
95 else:
96 return 0
99 def _ReleaseLock(lock_file, lock_filename):
100 """Removes the lockfile. Function-ized so we can bail from anywhere"""
101 os.close(lock_file)
102 os.remove(lock_filename)
105 def run_coverity(options, args):
106 """Runs all the selected tests for the given build type and target."""
107 # Create the lock file to prevent another instance of this script from
108 # running.
109 lock_filename = os.path.join(options.source_dir, LOCK_FILE)
110 try:
111 lock_file = os.open(lock_filename,
112 os.O_CREAT | os.O_EXCL | os.O_TRUNC | os.O_RDWR)
113 except OSError, err:
114 print 'Failed to open lock file:\n ' + str(err)
115 return 1
117 # Write the pid of this script (the python.exe process) to the lock file.
118 os.write(lock_file, str(os.getpid()))
120 options.target = options.target.title()
122 start_time = time.time()
124 print 'Change directory to ' + options.source_dir
125 os.chdir(options.source_dir)
127 # The coverity-password filename may have been a relative path.
128 # If so, assume it's relative to the source directory, which means
129 # the time to read the password is after we do the chdir().
130 coverity_password = _ReadPassword(options.coverity_password_file)
132 cmd = 'gclient sync'
133 gclient_exit = _RunCommand(cmd, options.dry_run, shell=True)
134 if gclient_exit != 0:
135 print 'gclient aborted with status %s' % gclient_exit
136 _ReleaseLock(lock_file, lock_filename)
137 return 1
139 print 'Elapsed time: %ds' % (time.time() - start_time)
141 # Do a clean build. Remove the build output directory first.
142 if sys.platform.startswith('linux'):
143 rm_path = os.path.join(options.source_dir,'src','out',options.target)
144 elif sys.platform == 'win32':
145 rm_path = os.path.join(options.source_dir,options.solution_dir,
146 options.target)
147 elif sys.platform == 'darwin':
148 rm_path = os.path.join(options.source_dir,'src','xcodebuild')
149 else:
150 print 'Platform "%s" unrecognized, aborting' % sys.platform
151 _ReleaseLock(lock_file, lock_filename)
152 return 1
154 if options.dry_run:
155 print 'shutil.rmtree(%s)' % repr(rm_path)
156 else:
157 shutil.rmtree(rm_path,True)
159 if options.preserve_intermediate_dir:
160 print 'Preserving intermediate directory.'
161 else:
162 if options.dry_run:
163 print 'shutil.rmtree(%s)' % repr(options.coverity_intermediate_dir)
164 print 'os.mkdir(%s)' % repr(options.coverity_intermediate_dir)
165 else:
166 shutil.rmtree(options.coverity_intermediate_dir,True)
167 os.mkdir(options.coverity_intermediate_dir)
169 print 'Elapsed time: %ds' % (time.time() - start_time)
171 use_shell_during_make = False
172 if sys.platform.startswith('linux'):
173 use_shell_during_make = True
174 os.chdir('src')
175 _RunCommand('pwd', options.dry_run, shell=True)
176 cmd = '%s/cov-build --dir %s make BUILDTYPE=%s chrome' % (
177 options.coverity_bin_dir, options.coverity_intermediate_dir,
178 options.target)
179 elif sys.platform == 'win32':
180 cmd = ('%s\\cov-build.exe --dir %s devenv.com %s\\%s /build %s '
181 '/project chrome.vcproj') % (
182 options.coverity_bin_dir, options.coverity_intermediate_dir,
183 options.source_dir, options.solution_file, options.target)
184 elif sys.platform == 'darwin':
185 use_shell_during_make = True
186 os.chdir('src/chrome')
187 _RunCommand('pwd', options.dry_run, shell=True)
188 cmd = ('%s/cov-build --dir %s xcodebuild -project chrome.xcodeproj '
189 '-configuration %s -target chrome') % (
190 options.coverity_bin_dir, options.coverity_intermediate_dir,
191 options.target)
194 _RunCommand(cmd, options.dry_run, shell=use_shell_during_make)
195 print 'Elapsed time: %ds' % (time.time() - start_time)
197 cov_analyze_exe = os.path.join(options.coverity_bin_dir,'cov-analyze')
198 cmd = '%s --dir %s %s' % (cov_analyze_exe,
199 options.coverity_intermediate_dir,
200 options.coverity_analyze_options)
201 _RunCommand(cmd, options.dry_run, shell=use_shell_during_make)
202 print 'Elapsed time: %ds' % (time.time() - start_time)
204 cov_commit_exe = os.path.join(options.coverity_bin_dir,'cov-commit-defects')
206 # On Linux we have started using a Target with a space in it, so we want
207 # to quote it. On the other hand, Windows quoting doesn't work quite the
208 # same way. To be conservative, I'd like to avoid quoting an argument
209 # that doesn't need quoting and which we haven't historically been quoting
210 # on that platform. So, only quote the target if we have to.
211 coverity_target = options.coverity_target
212 if sys.platform != 'win32':
213 coverity_target = '"%s"' % coverity_target
215 cmd = ('%s --dir %s --remote %s --port %s '
216 '--product %s '
217 '--target %s '
218 '--user %s '
219 '--password %s') % (cov_commit_exe,
220 options.coverity_intermediate_dir,
221 options.coverity_dbhost,
222 options.coverity_port,
223 options.coverity_product,
224 coverity_target,
225 options.coverity_user,
226 coverity_password)
227 # Avoid echoing the Commit command because it has a password in it
228 _RunCommand(cmd, options.dry_run, shell=use_shell_during_make, echo_cmd=False)
230 print 'Total time: %ds' % (time.time() - start_time)
232 _ReleaseLock(lock_file, lock_filename)
234 return 0
237 def main():
238 option_parser = optparse.OptionParser()
239 option_parser.add_option('', '--dry-run', action='store_true', default=False,
240 help='print but don\'t run the commands')
242 option_parser.add_option('', '--target', default='Release',
243 help='build target (Debug or Release)')
245 option_parser.add_option('', '--source-dir', dest='source_dir',
246 help='full path to directory ABOVE "src"',
247 default=CHROMIUM_SOURCE_DIR)
249 option_parser.add_option('', '--solution-file', dest='solution_file',
250 default=CHROMIUM_SOLUTION_FILE)
252 option_parser.add_option('', '--solution-dir', dest='solution_dir',
253 default=CHROMIUM_SOLUTION_DIR)
255 option_parser.add_option('', '--coverity-bin-dir', dest='coverity_bin_dir',
256 default=COVERITY_BIN_DIR)
258 option_parser.add_option('', '--coverity-intermediate-dir',
259 dest='coverity_intermediate_dir',
260 default=COVERITY_INTERMEDIATE_DIR)
262 option_parser.add_option('', '--coverity-analyze-options',
263 dest='coverity_analyze_options',
264 help=('all cov-analyze options, e.g. "%s"'
265 % COVERITY_ANALYZE_OPTIONS),
266 default=COVERITY_ANALYZE_OPTIONS)
268 option_parser.add_option('', '--coverity-db-host',
269 dest='coverity_dbhost',
270 help=('coverity defect db server hostname, e.g. %s'
271 % COVERITY_REMOTE),
272 default=COVERITY_REMOTE)
274 option_parser.add_option('', '--coverity-db-port', dest='coverity_port',
275 help=('port # of coverity web/db server, e.g. %s'
276 % COVERITY_PORT),
277 default=COVERITY_PORT)
279 option_parser.add_option('', '--coverity-product', dest='coverity_product',
280 help=('Product name reported to coverity, e.g. %s'
281 % COVERITY_PRODUCT),
282 default=COVERITY_PRODUCT)
284 option_parser.add_option('', '--coverity-target', dest='coverity_target',
285 help='Platform Target reported to coverity',
286 default=COVERITY_TARGET)
288 option_parser.add_option('', '--coverity-user', dest='coverity_user',
289 help='Username used to log into coverity',
290 default=COVERITY_USER)
292 option_parser.add_option('', '--coverity-password-file',
293 dest='coverity_password_file',
294 help='file containing the coverity password',
295 default='coverity-password')
297 helpmsg = ('By default, the intermediate dir is emptied before analysis. '
298 'This switch disables that behavior.')
299 option_parser.add_option('', '--preserve-intermediate-dir',
300 action='store_true', help=helpmsg,
301 default=False)
303 options, args = option_parser.parse_args()
304 return run_coverity(options, args)
307 if '__main__' == __name__:
308 sys.exit(main())