blob: 8e09a7adab4d9e92d8c06b82935a3a291bd6f2b9 [file] [log] [blame]
Anna Zaks1b417162011-10-06 23:26:27 +00001#!/usr/bin/env python
2
3"""
4Static Analyzer qualification infrastructure.
5
6The goal is to test the analyzer against different projects, check for failures,
7compare results, and measure performance.
8
9Repository Directory will contain sources of the projects as well as the
10information on how to build them and the expected output.
11Repository Directory structure:
12 - ProjectMap file
13 - Historical Performance Data
14 - Project Dir1
15 - ReferenceOutput
16 - Project Dir2
17 - ReferenceOutput
18 ..
19
20To test the build of the analyzer one would:
21 - Copy over a copy of the Repository Directory. (TODO: Prefer to ensure that
22 the build directory does not pollute the repository to min network traffic).
23 - Build all projects, until error. Produce logs to report errors.
24 - Compare results.
25
26The files which should be kept around for failure investigations:
27 RepositoryCopy/Project DirI/ScanBuildResults
28 RepositoryCopy/Project DirI/run_static_analyzer.log
29
30Assumptions (TODO: shouldn't need to assume these.):
31 The script is being run from the Repository Directory.
Anna Zaks5fa3f132011-11-02 20:46:50 +000032 The compiler for scan-build and scan-build are in the PATH.
Anna Zaks1b417162011-10-06 23:26:27 +000033 export PATH=/Users/zaks/workspace/c2llvm/build/Release+Asserts/bin:$PATH
34
35For more logging, set the env variables:
36 zaks:TI zaks$ export CCC_ANALYZER_LOG=1
37 zaks:TI zaks$ export CCC_ANALYZER_VERBOSE=1
38"""
39import CmpRuns
40
41import os
42import csv
43import sys
44import glob
Ted Kremenek82778af2012-08-28 20:40:04 +000045import math
Anna Zaks1b417162011-10-06 23:26:27 +000046import shutil
47import time
48import plistlib
Anna Zaks45518b12011-11-05 05:20:48 +000049from subprocess import check_call, CalledProcessError
Anna Zaks1b417162011-10-06 23:26:27 +000050
Ted Kremenek7c14c442012-08-28 20:40:02 +000051#------------------------------------------------------------------------------
52# Helper functions.
53#------------------------------------------------------------------------------
Anna Zaks1b417162011-10-06 23:26:27 +000054
Ted Kremenek82778af2012-08-28 20:40:04 +000055def detectCPUs():
56 """
57 Detects the number of CPUs on a system. Cribbed from pp.
58 """
59 # Linux, Unix and MacOS:
60 if hasattr(os, "sysconf"):
61 if os.sysconf_names.has_key("SC_NPROCESSORS_ONLN"):
62 # Linux & Unix:
63 ncpus = os.sysconf("SC_NPROCESSORS_ONLN")
64 if isinstance(ncpus, int) and ncpus > 0:
65 return ncpus
66 else: # OSX:
67 return int(capture(['sysctl', '-n', 'hw.ncpu']))
68 # Windows:
69 if os.environ.has_key("NUMBER_OF_PROCESSORS"):
70 ncpus = int(os.environ["NUMBER_OF_PROCESSORS"])
71 if ncpus > 0:
72 return ncpus
73 return 1 # Default
74
Ted Kremenek5abd3d22012-08-28 20:20:52 +000075def which(command, paths = None):
76 """which(command, [paths]) - Look up the given command in the paths string
77 (or the PATH environment variable, if unspecified)."""
78
79 if paths is None:
80 paths = os.environ.get('PATH','')
81
82 # Check for absolute match first.
83 if os.path.exists(command):
84 return command
85
86 # Would be nice if Python had a lib function for this.
87 if not paths:
88 paths = os.defpath
89
90 # Get suffixes to search.
91 # On Cygwin, 'PATHEXT' may exist but it should not be used.
92 if os.pathsep == ';':
93 pathext = os.environ.get('PATHEXT', '').split(';')
94 else:
95 pathext = ['']
96
97 # Search the paths...
98 for path in paths.split(os.pathsep):
99 for ext in pathext:
100 p = os.path.join(path, command + ext)
101 if os.path.exists(p):
102 return p
103
104 return None
105
Anna Zaksd3e29ef2012-01-10 18:10:25 +0000106# Make sure we flush the output after every print statement.
107class flushfile(object):
108 def __init__(self, f):
109 self.f = f
110 def write(self, x):
111 self.f.write(x)
112 self.f.flush()
113
114sys.stdout = flushfile(sys.stdout)
115
Anna Zaks1b417162011-10-06 23:26:27 +0000116def getProjectMapPath():
117 ProjectMapPath = os.path.join(os.path.abspath(os.curdir),
118 ProjectMapFile)
119 if not os.path.exists(ProjectMapPath):
120 print "Error: Cannot find the Project Map file " + ProjectMapPath +\
121 "\nRunning script for the wrong directory?"
122 sys.exit(-1)
123 return ProjectMapPath
124
125def getProjectDir(ID):
126 return os.path.join(os.path.abspath(os.curdir), ID)
127
Jordan Rose6d7e3722012-06-01 16:24:38 +0000128def getSBOutputDirName(IsReferenceBuild) :
Anna Zaks45518b12011-11-05 05:20:48 +0000129 if IsReferenceBuild == True :
130 return SBOutputDirReferencePrefix + SBOutputDirName
131 else :
132 return SBOutputDirName
133
Ted Kremenek7c14c442012-08-28 20:40:02 +0000134#------------------------------------------------------------------------------
135# Configuration setup.
136#------------------------------------------------------------------------------
137
138# Find Clang for static analysis.
139Clang = which("clang", os.environ['PATH'])
140if not Clang:
141 print "Error: cannot find 'clang' in PATH"
142 sys.exit(-1)
143
Ted Kremenek82778af2012-08-28 20:40:04 +0000144# Number of jobs.
Jordan Rose58782be2012-11-16 17:41:21 +0000145Jobs = int(math.ceil(detectCPUs() * 0.75))
Ted Kremenek82778af2012-08-28 20:40:04 +0000146
Ted Kremenek7c14c442012-08-28 20:40:02 +0000147# Project map stores info about all the "registered" projects.
148ProjectMapFile = "projectMap.csv"
149
150# Names of the project specific scripts.
151# The script that needs to be executed before the build can start.
152CleanupScript = "cleanup_run_static_analyzer.sh"
153# This is a file containing commands for scan-build.
154BuildScript = "run_static_analyzer.cmd"
155
156# The log file name.
157LogFolderName = "Logs"
158BuildLogName = "run_static_analyzer.log"
159# Summary file - contains the summary of the failures. Ex: This info can be be
160# displayed when buildbot detects a build failure.
161NumOfFailuresInSummary = 10
162FailuresSummaryFileName = "failures.txt"
163# Summary of the result diffs.
164DiffsSummaryFileName = "diffs.txt"
165
166# The scan-build result directory.
167SBOutputDirName = "ScanBuildResults"
168SBOutputDirReferencePrefix = "Ref"
169
170# The list of checkers used during analyzes.
Jordan Rosee449edc2013-04-05 17:55:07 +0000171# Currently, consists of all the non experimental checkers, plus a few alpha
172# checkers we don't want to regress on.
173Checkers="alpha.unix.SimpleStream,alpha.security.taint,alpha.cplusplus.NewDeleteLeaks,core,cplusplus,deadcode,security,unix,osx"
Ted Kremenek7c14c442012-08-28 20:40:02 +0000174
175Verbose = 1
176
177#------------------------------------------------------------------------------
178# Test harness logic.
179#------------------------------------------------------------------------------
180
Anna Zaks1b417162011-10-06 23:26:27 +0000181# Run pre-processing script if any.
Anna Zaks5fa3f132011-11-02 20:46:50 +0000182def runCleanupScript(Dir, PBuildLogFile):
183 ScriptPath = os.path.join(Dir, CleanupScript)
Anna Zaks1b417162011-10-06 23:26:27 +0000184 if os.path.exists(ScriptPath):
185 try:
186 if Verbose == 1:
187 print " Executing: %s" % (ScriptPath,)
188 check_call("chmod +x %s" % ScriptPath, cwd = Dir,
189 stderr=PBuildLogFile,
190 stdout=PBuildLogFile,
191 shell=True)
192 check_call(ScriptPath, cwd = Dir, stderr=PBuildLogFile,
193 stdout=PBuildLogFile,
194 shell=True)
195 except:
196 print "Error: The pre-processing step failed. See ", \
197 PBuildLogFile.name, " for details."
198 sys.exit(-1)
199
200# Build the project with scan-build by reading in the commands and
201# prefixing them with the scan-build options.
202def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
203 BuildScriptPath = os.path.join(Dir, BuildScript)
204 if not os.path.exists(BuildScriptPath):
205 print "Error: build script is not defined: %s" % BuildScriptPath
Ted Kremenek5abd3d22012-08-28 20:20:52 +0000206 sys.exit(-1)
207 SBOptions = "--use-analyzer " + Clang + " "
208 SBOptions += "-plist-html -o " + SBOutputDir + " "
Anna Zaks8d4a5152011-11-08 22:41:25 +0000209 SBOptions += "-enable-checker " + Checkers + " "
Jordan Rose33e95002013-01-24 23:07:59 +0000210 SBOptions += "--keep-empty "
Anna Zakse3a9baa2013-05-31 02:31:09 +0000211 # Always use ccc-analyze to ensure that we can locate the failures
212 # directory.
213 SBOptions += "--override-compiler "
Anna Zaks1b417162011-10-06 23:26:27 +0000214 try:
215 SBCommandFile = open(BuildScriptPath, "r")
216 SBPrefix = "scan-build " + SBOptions + " "
217 for Command in SBCommandFile:
Ted Kremenek82778af2012-08-28 20:40:04 +0000218 # If using 'make', auto imply a -jX argument
219 # to speed up analysis. xcodebuild will
220 # automatically use the maximum number of cores.
Jordan Rose7bd51ea2012-11-26 19:59:57 +0000221 if (Command.startswith("make ") or Command == "make") and \
222 "-j" not in Command:
Jordan Rose58782be2012-11-16 17:41:21 +0000223 Command += " -j%d" % Jobs
Anna Zaks1b417162011-10-06 23:26:27 +0000224 SBCommand = SBPrefix + Command
225 if Verbose == 1:
226 print " Executing: %s" % (SBCommand,)
227 check_call(SBCommand, cwd = Dir, stderr=PBuildLogFile,
228 stdout=PBuildLogFile,
229 shell=True)
230 except:
231 print "Error: scan-build failed. See ",PBuildLogFile.name,\
232 " for details."
Anna Zaks45518b12011-11-05 05:20:48 +0000233 raise
Anna Zaks1b417162011-10-06 23:26:27 +0000234
Anna Zaks45518b12011-11-05 05:20:48 +0000235def hasNoExtension(FileName):
236 (Root, Ext) = os.path.splitext(FileName)
237 if ((Ext == "")) :
238 return True
239 return False
240
241def isValidSingleInputFile(FileName):
242 (Root, Ext) = os.path.splitext(FileName)
243 if ((Ext == ".i") | (Ext == ".ii") |
244 (Ext == ".c") | (Ext == ".cpp") |
245 (Ext == ".m") | (Ext == "")) :
246 return True
247 return False
Ted Kremenek5abd3d22012-08-28 20:20:52 +0000248
Anna Zaks45518b12011-11-05 05:20:48 +0000249# Run analysis on a set of preprocessed files.
Anna Zaks817ce3d2012-09-06 23:30:27 +0000250def runAnalyzePreprocessed(Dir, SBOutputDir, Mode):
Anna Zaks45518b12011-11-05 05:20:48 +0000251 if os.path.exists(os.path.join(Dir, BuildScript)):
252 print "Error: The preprocessed files project should not contain %s" % \
253 BuildScript
254 raise Exception()
255
Ted Kremenek5abd3d22012-08-28 20:20:52 +0000256 CmdPrefix = Clang + " -cc1 -analyze -analyzer-output=plist -w "
Anna Zaks8c345c02012-01-21 01:11:35 +0000257 CmdPrefix += "-analyzer-checker=" + Checkers +" -fcxx-exceptions -fblocks "
Anna Zaks45518b12011-11-05 05:20:48 +0000258
Anna Zaks817ce3d2012-09-06 23:30:27 +0000259 if (Mode == 2) :
260 CmdPrefix += "-std=c++11 "
261
Anna Zaks45518b12011-11-05 05:20:48 +0000262 PlistPath = os.path.join(Dir, SBOutputDir, "date")
263 FailPath = os.path.join(PlistPath, "failures");
264 os.makedirs(FailPath);
265
266 for FullFileName in glob.glob(Dir + "/*"):
267 FileName = os.path.basename(FullFileName)
268 Failed = False
269
270 # Only run the analyzes on supported files.
271 if (hasNoExtension(FileName)):
272 continue
273 if (isValidSingleInputFile(FileName) == False):
274 print "Error: Invalid single input file %s." % (FullFileName,)
275 raise Exception()
276
277 # Build and call the analyzer command.
278 OutputOption = "-o " + os.path.join(PlistPath, FileName) + ".plist "
279 Command = CmdPrefix + OutputOption + os.path.join(Dir, FileName)
280 LogFile = open(os.path.join(FailPath, FileName + ".stderr.txt"), "w+b")
281 try:
282 if Verbose == 1:
283 print " Executing: %s" % (Command,)
284 check_call(Command, cwd = Dir, stderr=LogFile,
285 stdout=LogFile,
286 shell=True)
287 except CalledProcessError, e:
288 print "Error: Analyzes of %s failed. See %s for details." \
289 "Error code %d." % \
290 (FullFileName, LogFile.name, e.returncode)
291 Failed = True
292 finally:
293 LogFile.close()
294
295 # If command did not fail, erase the log file.
296 if Failed == False:
297 os.remove(LogFile.name);
298
Anna Zaks817ce3d2012-09-06 23:30:27 +0000299def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild):
Anna Zaks1b417162011-10-06 23:26:27 +0000300 TBegin = time.time()
301
Anna Zaks45518b12011-11-05 05:20:48 +0000302 BuildLogPath = os.path.join(SBOutputDir, LogFolderName, BuildLogName)
Anna Zaks1b417162011-10-06 23:26:27 +0000303 print "Log file: %s" % (BuildLogPath,)
Anna Zaks45518b12011-11-05 05:20:48 +0000304 print "Output directory: %s" %(SBOutputDir, )
305
Anna Zaks1b417162011-10-06 23:26:27 +0000306 # Clean up the log file.
307 if (os.path.exists(BuildLogPath)) :
308 RmCommand = "rm " + BuildLogPath
309 if Verbose == 1:
Anna Zaks5fa3f132011-11-02 20:46:50 +0000310 print " Executing: %s" % (RmCommand,)
Anna Zaks1b417162011-10-06 23:26:27 +0000311 check_call(RmCommand, shell=True)
Anna Zaks45518b12011-11-05 05:20:48 +0000312
313 # Clean up scan build results.
314 if (os.path.exists(SBOutputDir)) :
315 RmCommand = "rm -r " + SBOutputDir
316 if Verbose == 1:
317 print " Executing: %s" % (RmCommand,)
318 check_call(RmCommand, shell=True)
319 assert(not os.path.exists(SBOutputDir))
320 os.makedirs(os.path.join(SBOutputDir, LogFolderName))
Anna Zaks1b417162011-10-06 23:26:27 +0000321
322 # Open the log file.
323 PBuildLogFile = open(BuildLogPath, "wb+")
Anna Zaks1b417162011-10-06 23:26:27 +0000324
Anna Zaks45518b12011-11-05 05:20:48 +0000325 # Build and analyze the project.
326 try:
Anna Zaks5fa3f132011-11-02 20:46:50 +0000327 runCleanupScript(Dir, PBuildLogFile)
Anna Zaks5fa3f132011-11-02 20:46:50 +0000328
Anna Zaks817ce3d2012-09-06 23:30:27 +0000329 if (ProjectBuildMode == 1):
Anna Zaks45518b12011-11-05 05:20:48 +0000330 runScanBuild(Dir, SBOutputDir, PBuildLogFile)
331 else:
Anna Zaks817ce3d2012-09-06 23:30:27 +0000332 runAnalyzePreprocessed(Dir, SBOutputDir, ProjectBuildMode)
Anna Zaks45518b12011-11-05 05:20:48 +0000333
334 if IsReferenceBuild :
Anna Zaks5fa3f132011-11-02 20:46:50 +0000335 runCleanupScript(Dir, PBuildLogFile)
336
Anna Zaks1b417162011-10-06 23:26:27 +0000337 finally:
338 PBuildLogFile.close()
339
340 print "Build complete (time: %.2f). See the log for more details: %s" % \
341 ((time.time()-TBegin), BuildLogPath)
342
343# A plist file is created for each call to the analyzer(each source file).
344# We are only interested on the once that have bug reports, so delete the rest.
345def CleanUpEmptyPlists(SBOutputDir):
346 for F in glob.glob(SBOutputDir + "/*/*.plist"):
347 P = os.path.join(SBOutputDir, F)
348
349 Data = plistlib.readPlist(P)
350 # Delete empty reports.
351 if not Data['files']:
352 os.remove(P)
353 continue
354
355# Given the scan-build output directory, checks if the build failed
356# (by searching for the failures directories). If there are failures, it
357# creates a summary file in the output directory.
358def checkBuild(SBOutputDir):
359 # Check if there are failures.
360 Failures = glob.glob(SBOutputDir + "/*/failures/*.stderr.txt")
361 TotalFailed = len(Failures);
362 if TotalFailed == 0:
Jordan Rose191e2b12012-08-31 00:36:30 +0000363 CleanUpEmptyPlists(SBOutputDir)
364 Plists = glob.glob(SBOutputDir + "/*/*.plist")
365 print "Number of bug reports (non empty plist files) produced: %d" %\
366 len(Plists)
Anna Zaks1b417162011-10-06 23:26:27 +0000367 return;
368
369 # Create summary file to display when the build fails.
Anna Zaks45518b12011-11-05 05:20:48 +0000370 SummaryPath = os.path.join(SBOutputDir, LogFolderName, FailuresSummaryFileName)
Anna Zaks1b417162011-10-06 23:26:27 +0000371 if (Verbose > 0):
Anna Zaks45518b12011-11-05 05:20:48 +0000372 print " Creating the failures summary file %s" % (SummaryPath,)
Anna Zaks1b417162011-10-06 23:26:27 +0000373
374 SummaryLog = open(SummaryPath, "w+")
375 try:
376 SummaryLog.write("Total of %d failures discovered.\n" % (TotalFailed,))
377 if TotalFailed > NumOfFailuresInSummary:
378 SummaryLog.write("See the first %d below.\n"
379 % (NumOfFailuresInSummary,))
380 # TODO: Add a line "See the results folder for more."
381
382 FailuresCopied = NumOfFailuresInSummary
383 Idx = 0
Jordan Rose04bc0142012-06-01 16:24:43 +0000384 for FailLogPathI in Failures:
Anna Zaks1b417162011-10-06 23:26:27 +0000385 if Idx >= NumOfFailuresInSummary:
386 break;
387 Idx += 1
388 SummaryLog.write("\n-- Error #%d -----------\n" % (Idx,));
389 FailLogI = open(FailLogPathI, "r");
390 try:
391 shutil.copyfileobj(FailLogI, SummaryLog);
392 finally:
393 FailLogI.close()
394 finally:
395 SummaryLog.close()
396
Anna Zaksf063a3b2012-01-04 23:53:50 +0000397 print "Error: analysis failed. See ", SummaryPath
Anna Zaks1b417162011-10-06 23:26:27 +0000398 sys.exit(-1)
399
400# Auxiliary object to discard stdout.
401class Discarder(object):
402 def write(self, text):
403 pass # do nothing
404
405# Compare the warnings produced by scan-build.
406def runCmpResults(Dir):
407 TBegin = time.time()
408
409 RefDir = os.path.join(Dir, SBOutputDirReferencePrefix + SBOutputDirName)
410 NewDir = os.path.join(Dir, SBOutputDirName)
411
412 # We have to go one level down the directory tree.
413 RefList = glob.glob(RefDir + "/*")
414 NewList = glob.glob(NewDir + "/*")
Anna Zaks45518b12011-11-05 05:20:48 +0000415
416 # Log folders are also located in the results dir, so ignore them.
417 RefList.remove(os.path.join(RefDir, LogFolderName))
418 NewList.remove(os.path.join(NewDir, LogFolderName))
419
Anna Zaks1b417162011-10-06 23:26:27 +0000420 if len(RefList) == 0 or len(NewList) == 0:
421 return False
422 assert(len(RefList) == len(NewList))
423
424 # There might be more then one folder underneath - one per each scan-build
425 # command (Ex: one for configure and one for make).
426 if (len(RefList) > 1):
427 # Assume that the corresponding folders have the same names.
428 RefList.sort()
429 NewList.sort()
430
431 # Iterate and find the differences.
Anna Zaksa7a25642011-11-08 19:56:31 +0000432 NumDiffs = 0
Anna Zaks1b417162011-10-06 23:26:27 +0000433 PairList = zip(RefList, NewList)
434 for P in PairList:
435 RefDir = P[0]
436 NewDir = P[1]
437
438 assert(RefDir != NewDir)
439 if Verbose == 1:
440 print " Comparing Results: %s %s" % (RefDir, NewDir)
441
442 DiffsPath = os.path.join(NewDir, DiffsSummaryFileName)
443 Opts = CmpRuns.CmpOptions(DiffsPath)
444 # Discard everything coming out of stdout (CmpRun produces a lot of them).
445 OLD_STDOUT = sys.stdout
446 sys.stdout = Discarder()
447 # Scan the results, delete empty plist files.
Anna Zaks7acc4072012-07-16 20:21:42 +0000448 NumDiffs = CmpRuns.dumpScanBuildResultsDiff(RefDir, NewDir, Opts, False)
Anna Zaks1b417162011-10-06 23:26:27 +0000449 sys.stdout = OLD_STDOUT
Anna Zaksa7a25642011-11-08 19:56:31 +0000450 if (NumDiffs > 0) :
451 print "Warning: %r differences in diagnostics. See %s" % \
452 (NumDiffs, DiffsPath,)
Anna Zaks1b417162011-10-06 23:26:27 +0000453
454 print "Diagnostic comparison complete (time: %.2f)." % (time.time()-TBegin)
Anna Zaksa7a25642011-11-08 19:56:31 +0000455 return (NumDiffs > 0)
Anna Zaks45518b12011-11-05 05:20:48 +0000456
Anna Zaks09e9cf02012-02-03 06:35:23 +0000457def updateSVN(Mode, ProjectsMap):
458 try:
459 ProjectsMap.seek(0)
460 for I in csv.reader(ProjectsMap):
461 ProjName = I[0]
Jordan Rose6d7e3722012-06-01 16:24:38 +0000462 Path = os.path.join(ProjName, getSBOutputDirName(True))
Anna Zaks09e9cf02012-02-03 06:35:23 +0000463
464 if Mode == "delete":
465 Command = "svn delete %s" % (Path,)
466 else:
467 Command = "svn add %s" % (Path,)
Anna Zaks1b417162011-10-06 23:26:27 +0000468
Anna Zaks09e9cf02012-02-03 06:35:23 +0000469 if Verbose == 1:
470 print " Executing: %s" % (Command,)
Jordan Rose04bc0142012-06-01 16:24:43 +0000471 check_call(Command, shell=True)
Anna Zaks09e9cf02012-02-03 06:35:23 +0000472
473 if Mode == "delete":
474 CommitCommand = "svn commit -m \"[analyzer tests] Remove " \
475 "reference results.\""
476 else:
477 CommitCommand = "svn commit -m \"[analyzer tests] Add new " \
478 "reference results.\""
479 if Verbose == 1:
480 print " Executing: %s" % (CommitCommand,)
Jordan Rose04bc0142012-06-01 16:24:43 +0000481 check_call(CommitCommand, shell=True)
Anna Zaks09e9cf02012-02-03 06:35:23 +0000482 except:
483 print "Error: SVN update failed."
484 sys.exit(-1)
485
Anna Zaks817ce3d2012-09-06 23:30:27 +0000486def testProject(ID, ProjectBuildMode, IsReferenceBuild=False, Dir=None):
Anna Zaks45518b12011-11-05 05:20:48 +0000487 print " \n\n--- Building project %s" % (ID,)
488
Anna Zaks1b417162011-10-06 23:26:27 +0000489 TBegin = time.time()
490
491 if Dir is None :
492 Dir = getProjectDir(ID)
493 if Verbose == 1:
494 print " Build directory: %s." % (Dir,)
495
496 # Set the build results directory.
Jordan Rose6d7e3722012-06-01 16:24:38 +0000497 RelOutputDir = getSBOutputDirName(IsReferenceBuild)
Anna Zaks09e9cf02012-02-03 06:35:23 +0000498 SBOutputDir = os.path.join(Dir, RelOutputDir)
499
Anna Zaks817ce3d2012-09-06 23:30:27 +0000500 buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild)
Anna Zaks1b417162011-10-06 23:26:27 +0000501
502 checkBuild(SBOutputDir)
503
Jordan Rose191e2b12012-08-31 00:36:30 +0000504 if IsReferenceBuild == False:
505 runCmpResults(Dir)
Anna Zaks1b417162011-10-06 23:26:27 +0000506
507 print "Completed tests for project %s (time: %.2f)." % \
508 (ID, (time.time()-TBegin))
509
Jordan Rose6d7e3722012-06-01 16:24:38 +0000510def testAll(IsReferenceBuild = False, UpdateSVN = False):
Anna Zaks1b417162011-10-06 23:26:27 +0000511 PMapFile = open(getProjectMapPath(), "rb")
Anna Zaks09e9cf02012-02-03 06:35:23 +0000512 try:
513 # Validate the input.
514 for I in csv.reader(PMapFile):
Anna Zaks45518b12011-11-05 05:20:48 +0000515 if (len(I) != 2) :
516 print "Error: Rows in the ProjectMapFile should have 3 entries."
517 raise Exception()
Anna Zaks817ce3d2012-09-06 23:30:27 +0000518 if (not ((I[1] == "0") | (I[1] == "1") | (I[1] == "2"))):
519 print "Error: Second entry in the ProjectMapFile should be 0" \
520 " (single file), 1 (project), or 2(single file c++11)."
Anna Zaks45518b12011-11-05 05:20:48 +0000521 raise Exception()
Anna Zaks09e9cf02012-02-03 06:35:23 +0000522
523 # When we are regenerating the reference results, we might need to
524 # update svn. Remove reference results from SVN.
525 if UpdateSVN == True:
Jordan Rose6d7e3722012-06-01 16:24:38 +0000526 assert(IsReferenceBuild == True);
Anna Zaks09e9cf02012-02-03 06:35:23 +0000527 updateSVN("delete", PMapFile);
528
529 # Test the projects.
530 PMapFile.seek(0)
531 for I in csv.reader(PMapFile):
Jordan Rose6d7e3722012-06-01 16:24:38 +0000532 testProject(I[0], int(I[1]), IsReferenceBuild)
Anna Zaks09e9cf02012-02-03 06:35:23 +0000533
534 # Add reference results to SVN.
535 if UpdateSVN == True:
536 updateSVN("add", PMapFile);
537
Anna Zaks45518b12011-11-05 05:20:48 +0000538 except:
539 print "Error occurred. Premature termination."
540 raise
Anna Zaks1b417162011-10-06 23:26:27 +0000541 finally:
542 PMapFile.close()
543
544if __name__ == '__main__':
Anna Zaks09e9cf02012-02-03 06:35:23 +0000545 IsReference = False
546 UpdateSVN = False
547 if len(sys.argv) >= 2:
548 if sys.argv[1] == "-r":
549 IsReference = True
550 elif sys.argv[1] == "-rs":
551 IsReference = True
552 UpdateSVN = True
553 else:
554 print >> sys.stderr, 'Usage: ', sys.argv[0],\
555 '[-r|-rs]' \
556 'Use -r to regenerate reference output' \
557 'Use -rs to regenerate reference output and update svn'
558
559 testAll(IsReference, UpdateSVN)