11b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks#!/usr/bin/env python
21b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
31b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks"""
41b41716abf6856af893fd2f13cd0272dffa0e312Anna ZaksStatic Analyzer qualification infrastructure.
51b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
61b41716abf6856af893fd2f13cd0272dffa0e312Anna ZaksThe goal is to test the analyzer against different projects, check for failures,
71b41716abf6856af893fd2f13cd0272dffa0e312Anna Zakscompare results, and measure performance.
81b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga NainarRepository Directory will contain sources of the projects as well as the
1087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarinformation on how to build them and the expected output.
111b41716abf6856af893fd2f13cd0272dffa0e312Anna ZaksRepository Directory structure:
121b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks   - ProjectMap file
131b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks   - Historical Performance Data
141b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks   - Project Dir1
151b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks     - ReferenceOutput
161b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks   - Project Dir2
171b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks     - ReferenceOutput
181b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks   ..
1987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga NainarNote that the build tree must be inside the project dir.
201b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
211b41716abf6856af893fd2f13cd0272dffa0e312Anna ZaksTo test the build of the analyzer one would:
2287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar   - Copy over a copy of the Repository Directory. (TODO: Prefer to ensure that
231b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks     the build directory does not pollute the repository to min network traffic).
241b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks   - Build all projects, until error. Produce logs to report errors.
2587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar   - Compare results.
261b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
2787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga NainarThe files which should be kept around for failure investigations:
281b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks   RepositoryCopy/Project DirI/ScanBuildResults
2987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar   RepositoryCopy/Project DirI/run_static_analyzer.log
3087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
3187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga NainarAssumptions (TODO: shouldn't need to assume these.):
321b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks   The script is being run from the Repository Directory.
335fa3f1309b27d2f117dfd10a45a8642b7d4baae9Anna Zaks   The compiler for scan-build and scan-build are in the PATH.
341b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks   export PATH=/Users/zaks/workspace/c2llvm/build/Release+Asserts/bin:$PATH
351b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
361b41716abf6856af893fd2f13cd0272dffa0e312Anna ZaksFor more logging, set the  env variables:
371b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks   zaks:TI zaks$ export CCC_ANALYZER_LOG=1
381b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks   zaks:TI zaks$ export CCC_ANALYZER_VERBOSE=1
3987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
4087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga NainarThe list of checkers tested are hardcoded in the Checkers variable.
4187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga NainarFor testing additional checkers, use the SA_ADDITIONAL_CHECKERS environment
4287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarvariable. It should contain a comma separated list.
431b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks"""
441b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaksimport CmpRuns
451b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
461b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaksimport os
471b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaksimport csv
481b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaksimport sys
491b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaksimport glob
5082778af78a7337498e6bcfc81c75cee29d329915Ted Kremenekimport math
511b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaksimport shutil
521b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaksimport time
531b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaksimport plistlib
5487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarimport argparse
5587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarfrom subprocess import check_call, check_output, CalledProcessError
561b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
577c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek#------------------------------------------------------------------------------
587c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek# Helper functions.
597c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek#------------------------------------------------------------------------------
601b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
6182778af78a7337498e6bcfc81c75cee29d329915Ted Kremenekdef detectCPUs():
6282778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek    """
6382778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek    Detects the number of CPUs on a system. Cribbed from pp.
6482778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek    """
6582778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek    # Linux, Unix and MacOS:
6682778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek    if hasattr(os, "sysconf"):
6782778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek        if os.sysconf_names.has_key("SC_NPROCESSORS_ONLN"):
6882778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek            # Linux & Unix:
6982778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek            ncpus = os.sysconf("SC_NPROCESSORS_ONLN")
7082778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek            if isinstance(ncpus, int) and ncpus > 0:
7182778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek                return ncpus
7282778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek        else: # OSX:
7382778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek            return int(capture(['sysctl', '-n', 'hw.ncpu']))
7482778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek    # Windows:
7582778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek    if os.environ.has_key("NUMBER_OF_PROCESSORS"):
7682778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek        ncpus = int(os.environ["NUMBER_OF_PROCESSORS"])
7782778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek        if ncpus > 0:
7882778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek            return ncpus
7982778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek    return 1 # Default
8082778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek
815abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenekdef which(command, paths = None):
825abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek   """which(command, [paths]) - Look up the given command in the paths string
835abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek   (or the PATH environment variable, if unspecified)."""
845abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek
855abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek   if paths is None:
865abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek       paths = os.environ.get('PATH','')
875abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek
885abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek   # Check for absolute match first.
895abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek   if os.path.exists(command):
905abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek       return command
915abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek
925abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek   # Would be nice if Python had a lib function for this.
935abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek   if not paths:
945abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek       paths = os.defpath
955abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek
965abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek   # Get suffixes to search.
975abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek   # On Cygwin, 'PATHEXT' may exist but it should not be used.
985abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek   if os.pathsep == ';':
995abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek       pathext = os.environ.get('PATHEXT', '').split(';')
1005abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek   else:
1015abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek       pathext = ['']
1025abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek
1035abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek   # Search the paths...
1045abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek   for path in paths.split(os.pathsep):
1055abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek       for ext in pathext:
1065abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek           p = os.path.join(path, command + ext)
1075abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek           if os.path.exists(p):
1085abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek               return p
1095abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek
1105abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek   return None
1115abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek
112d3e29ef3e0c3f2f70ec41c83e68c271f970e1852Anna Zaks# Make sure we flush the output after every print statement.
113d3e29ef3e0c3f2f70ec41c83e68c271f970e1852Anna Zaksclass flushfile(object):
114d3e29ef3e0c3f2f70ec41c83e68c271f970e1852Anna Zaks    def __init__(self, f):
115d3e29ef3e0c3f2f70ec41c83e68c271f970e1852Anna Zaks        self.f = f
116d3e29ef3e0c3f2f70ec41c83e68c271f970e1852Anna Zaks    def write(self, x):
117d3e29ef3e0c3f2f70ec41c83e68c271f970e1852Anna Zaks        self.f.write(x)
118d3e29ef3e0c3f2f70ec41c83e68c271f970e1852Anna Zaks        self.f.flush()
119d3e29ef3e0c3f2f70ec41c83e68c271f970e1852Anna Zaks
120d3e29ef3e0c3f2f70ec41c83e68c271f970e1852Anna Zakssys.stdout = flushfile(sys.stdout)
121d3e29ef3e0c3f2f70ec41c83e68c271f970e1852Anna Zaks
1221b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaksdef getProjectMapPath():
12387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    ProjectMapPath = os.path.join(os.path.abspath(os.curdir),
1241b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks                                  ProjectMapFile)
1251b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    if not os.path.exists(ProjectMapPath):
1261b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        print "Error: Cannot find the Project Map file " + ProjectMapPath +\
1271b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks                "\nRunning script for the wrong directory?"
12887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        sys.exit(-1)
12987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    return ProjectMapPath
1301b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
1311b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaksdef getProjectDir(ID):
13287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    return os.path.join(os.path.abspath(os.curdir), ID)
1331b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
1346d7e3727996cf6c418e9fdccf8521dc3282f9368Jordan Rosedef getSBOutputDirName(IsReferenceBuild) :
13545518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    if IsReferenceBuild == True :
13645518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        return SBOutputDirReferencePrefix + SBOutputDirName
13745518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    else :
13845518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        return SBOutputDirName
13945518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks
1407c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek#------------------------------------------------------------------------------
1417c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek# Configuration setup.
1427c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek#------------------------------------------------------------------------------
1437c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek
1447c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek# Find Clang for static analysis.
1457c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted KremenekClang = which("clang", os.environ['PATH'])
1467c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenekif not Clang:
1477c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek    print "Error: cannot find 'clang' in PATH"
1487c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek    sys.exit(-1)
1497c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek
15082778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek# Number of jobs.
15158782bee56bf5e6ab42e6695af9ae5befe1fd479Jordan RoseJobs = int(math.ceil(detectCPUs() * 0.75))
15282778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek
1537c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek# Project map stores info about all the "registered" projects.
1547c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted KremenekProjectMapFile = "projectMap.csv"
1557c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek
1567c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek# Names of the project specific scripts.
15787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# The script that downloads the project.
15887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga NainarDownloadScript = "download_project.sh"
1597c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek# The script that needs to be executed before the build can start.
1607c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted KremenekCleanupScript = "cleanup_run_static_analyzer.sh"
16187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# This is a file containing commands for scan-build.
1627c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted KremenekBuildScript = "run_static_analyzer.cmd"
1637c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek
1647c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek# The log file name.
1657c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted KremenekLogFolderName = "Logs"
1667c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted KremenekBuildLogName = "run_static_analyzer.log"
16787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# Summary file - contains the summary of the failures. Ex: This info can be be
1687c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek# displayed when buildbot detects a build failure.
1697c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted KremenekNumOfFailuresInSummary = 10
1707c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted KremenekFailuresSummaryFileName = "failures.txt"
1717c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek# Summary of the result diffs.
1727c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted KremenekDiffsSummaryFileName = "diffs.txt"
1737c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek
1747c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek# The scan-build result directory.
1757c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted KremenekSBOutputDirName = "ScanBuildResults"
1767c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted KremenekSBOutputDirReferencePrefix = "Ref"
1777c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek
17887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# The name of the directory storing the cached project source. If this directory
17987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# does not exist, the download script will be executed. That script should
18087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# create the "CachedSource" directory and download the project source into it.
18187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga NainarCachedSourceDirName = "CachedSource"
18287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
18387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# The name of the directory containing the source code that will be analyzed.
18487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# Each time a project is analyzed, a fresh copy of its CachedSource directory
18587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# will be copied to the PatchedSource directory and then the local patches
18687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# in PatchfileName will be applied (if PatchfileName exists).
18787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga NainarPatchedSourceDirName = "PatchedSource"
18887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
18987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# The name of the patchfile specifying any changes that should be applied
19087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# to the CachedSource before analyzing.
19187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga NainarPatchfileName = "changes_for_analyzer.patch"
19287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
1937c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek# The list of checkers used during analyzes.
194651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines# Currently, consists of all the non-experimental checkers, plus a few alpha
195e449edc5bdace60f9d754c32abc5459bc7d94a14Jordan Rose# checkers we don't want to regress on.
196176edba5311f6eff0cad2631449885ddf4fbc9eaStephen HinesCheckers="alpha.unix.SimpleStream,alpha.security.taint,cplusplus.NewDeleteLeaks,core,cplusplus,deadcode,security,unix,osx"
1977c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek
1987c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted KremenekVerbose = 1
1997c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek
2007c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek#------------------------------------------------------------------------------
2017c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek# Test harness logic.
2027c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek#------------------------------------------------------------------------------
2037c14c4456532fbaff17c6ae3e5d259d475bfd7f7Ted Kremenek
2041b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks# Run pre-processing script if any.
2055fa3f1309b27d2f117dfd10a45a8642b7d4baae9Anna Zaksdef runCleanupScript(Dir, PBuildLogFile):
20687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    Cwd = os.path.join(Dir, PatchedSourceDirName)
2075fa3f1309b27d2f117dfd10a45a8642b7d4baae9Anna Zaks    ScriptPath = os.path.join(Dir, CleanupScript)
20887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    runScript(ScriptPath, PBuildLogFile, Cwd)
20987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
21087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# Run the script to download the project, if it exists.
21187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainardef runDownloadScript(Dir, PBuildLogFile):
21287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    ScriptPath = os.path.join(Dir, DownloadScript)
21387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    runScript(ScriptPath, PBuildLogFile, Dir)
21487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
21587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# Run the provided script if it exists.
21687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainardef runScript(ScriptPath, PBuildLogFile, Cwd):
2171b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    if os.path.exists(ScriptPath):
2181b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        try:
21987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            if Verbose == 1:
2201b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks                print "  Executing: %s" % (ScriptPath,)
2214967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            check_call("chmod +x '%s'" % ScriptPath, cwd = Cwd,
2221b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks                                              stderr=PBuildLogFile,
22387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                                              stdout=PBuildLogFile,
22487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                                              shell=True)
2254967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            check_call("'%s'" % ScriptPath, cwd = Cwd, stderr=PBuildLogFile,
22687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                                              stdout=PBuildLogFile,
2271b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks                                              shell=True)
2281b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        except:
22987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            print "Error: Running %s failed. See %s for details." % (ScriptPath,
23087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                PBuildLogFile.name)
2311b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks            sys.exit(-1)
2321b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
23387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# Download the project and apply the local patchfile if it exists.
23487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainardef downloadAndPatch(Dir, PBuildLogFile):
23587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    CachedSourceDirPath = os.path.join(Dir, CachedSourceDirName)
23687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
23787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    # If the we don't already have the cached source, run the project's
23887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    # download script to download it.
23987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    if not os.path.exists(CachedSourceDirPath):
24087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar      runDownloadScript(Dir, PBuildLogFile)
24187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar      if not os.path.exists(CachedSourceDirPath):
24287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        print "Error: '%s' not found after download." % (CachedSourceDirPath)
24387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        exit(-1)
24487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
24587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    PatchedSourceDirPath = os.path.join(Dir, PatchedSourceDirName)
24687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
24787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    # Remove potentially stale patched source.
24887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    if os.path.exists(PatchedSourceDirPath):
24987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        shutil.rmtree(PatchedSourceDirPath)
25087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
25187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    # Copy the cached source and apply any patches to the copy.
25287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    shutil.copytree(CachedSourceDirPath, PatchedSourceDirPath, symlinks=True)
25387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    applyPatch(Dir, PBuildLogFile)
25487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
25587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainardef applyPatch(Dir, PBuildLogFile):
25687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    PatchfilePath = os.path.join(Dir, PatchfileName)
25787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    PatchedSourceDirPath = os.path.join(Dir, PatchedSourceDirName)
25887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    if not os.path.exists(PatchfilePath):
25987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        print "  No local patches."
26087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        return
26187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
26287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    print "  Applying patch."
26387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    try:
2644967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        check_call("patch -p1 < '%s'" % (PatchfilePath),
26587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    cwd = PatchedSourceDirPath,
26687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    stderr=PBuildLogFile,
26787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    stdout=PBuildLogFile,
26887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    shell=True)
26987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    except:
27087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        print "Error: Patch failed. See %s for details." % (PBuildLogFile.name)
27187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        sys.exit(-1)
27287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
27387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# Build the project with scan-build by reading in the commands and
2741b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks# prefixing them with the scan-build options.
2751b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaksdef runScanBuild(Dir, SBOutputDir, PBuildLogFile):
2761b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    BuildScriptPath = os.path.join(Dir, BuildScript)
2771b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    if not os.path.exists(BuildScriptPath):
2781b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        print "Error: build script is not defined: %s" % BuildScriptPath
2795abd3d2ba4c4edb5140de5d65a16e5da4076f0b1Ted Kremenek        sys.exit(-1)
28087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
28187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    AllCheckers = Checkers
28287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    if os.environ.has_key('SA_ADDITIONAL_CHECKERS'):
28387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        AllCheckers = AllCheckers + ',' + os.environ['SA_ADDITIONAL_CHECKERS']
28487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
28587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    # Run scan-build from within the patched source directory.
28687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    SBCwd = os.path.join(Dir, PatchedSourceDirName)
28787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
2884967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    SBOptions = "--use-analyzer '%s' " %  Clang
2894967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    SBOptions += "-plist-html -o '%s' " % SBOutputDir
29087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    SBOptions += "-enable-checker " + AllCheckers + " "
29133e9500784a6b8dc7f01ae5c85ebf0883fbc6662Jordan Rose    SBOptions += "--keep-empty "
29287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    # Always use ccc-analyze to ensure that we can locate the failures
293e3a9baa45c91f5c06801a2d667b5d6d71bcfb355Anna Zaks    # directory.
294e3a9baa45c91f5c06801a2d667b5d6d71bcfb355Anna Zaks    SBOptions += "--override-compiler "
2951b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    try:
2961b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        SBCommandFile = open(BuildScriptPath, "r")
2971b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        SBPrefix = "scan-build " + SBOptions + " "
2981b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        for Command in SBCommandFile:
2991c840db980075f56e5747b5b636e319a26722fe3Jordan Rose            Command = Command.strip()
30087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            if len(Command) == 0:
30187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                continue;
30282778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek            # If using 'make', auto imply a -jX argument
30382778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek            # to speed up analysis.  xcodebuild will
30482778af78a7337498e6bcfc81c75cee29d329915Ted Kremenek            # automatically use the maximum number of cores.
3057bd51ea64fd06b9a243faaacb0b15c168afe47a6Jordan Rose            if (Command.startswith("make ") or Command == "make") and \
3067bd51ea64fd06b9a243faaacb0b15c168afe47a6Jordan Rose                "-j" not in Command:
30758782bee56bf5e6ab42e6695af9ae5befe1fd479Jordan Rose                Command += " -j%d" % Jobs
3081b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks            SBCommand = SBPrefix + Command
30987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            if Verbose == 1:
3101b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks                print "  Executing: %s" % (SBCommand,)
31187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            check_call(SBCommand, cwd = SBCwd, stderr=PBuildLogFile,
31287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                                               stdout=PBuildLogFile,
31387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                                               shell=True)
3141b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    except:
3151b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        print "Error: scan-build failed. See ",PBuildLogFile.name,\
3161b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks              " for details."
31745518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        raise
31845518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks
31945518b1f768c302837096d1359b2935cdb8ee08dAnna Zaksdef hasNoExtension(FileName):
32045518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    (Root, Ext) = os.path.splitext(FileName)
32145518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    if ((Ext == "")) :
32245518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        return True
32345518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    return False
3241b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
32545518b1f768c302837096d1359b2935cdb8ee08dAnna Zaksdef isValidSingleInputFile(FileName):
32645518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    (Root, Ext) = os.path.splitext(FileName)
32787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    if ((Ext == ".i") | (Ext == ".ii") |
32887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        (Ext == ".c") | (Ext == ".cpp") |
32945518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        (Ext == ".m") | (Ext == "")) :
33045518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        return True
33145518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    return False
33287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
33387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# Get the path to the SDK for the given SDK name. Returns None if
33487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# the path cannot be determined.
33587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainardef getSDKPath(SDKName):
33687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    if which("xcrun") is None:
33787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        return None
33887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
33987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    Cmd = "xcrun --sdk " + SDKName + " --show-sdk-path"
34087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    return check_output(Cmd, shell=True).rstrip()
34187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
34245518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks# Run analysis on a set of preprocessed files.
343817ce3dd26590bf3f099fb82d9b6fcc43e8a7ee9Anna Zaksdef runAnalyzePreprocessed(Dir, SBOutputDir, Mode):
34445518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    if os.path.exists(os.path.join(Dir, BuildScript)):
34545518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        print "Error: The preprocessed files project should not contain %s" % \
34645518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks               BuildScript
34787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        raise Exception()
34887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
34987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    CmdPrefix = Clang + " -cc1 "
35087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
35187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    # For now, we assume the preprocessed files should be analyzed
35287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    # with the OS X SDK.
35387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    SDKPath = getSDKPath("macosx")
35487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    if SDKPath is not None:
35587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar      CmdPrefix += "-isysroot " + SDKPath + " "
35687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
35787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    CmdPrefix += "-analyze -analyzer-output=plist -w "
35887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    CmdPrefix += "-analyzer-checker=" + Checkers +" -fcxx-exceptions -fblocks "
35945518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks
360817ce3dd26590bf3f099fb82d9b6fcc43e8a7ee9Anna Zaks    if (Mode == 2) :
36187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        CmdPrefix += "-std=c++11 "
36287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
36345518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    PlistPath = os.path.join(Dir, SBOutputDir, "date")
36445518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    FailPath = os.path.join(PlistPath, "failures");
36545518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    os.makedirs(FailPath);
36687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
36745518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    for FullFileName in glob.glob(Dir + "/*"):
36845518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        FileName = os.path.basename(FullFileName)
36945518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        Failed = False
37087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
37145518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        # Only run the analyzes on supported files.
37245518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        if (hasNoExtension(FileName)):
37345518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks            continue
37445518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        if (isValidSingleInputFile(FileName) == False):
37545518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks            print "Error: Invalid single input file %s." % (FullFileName,)
37645518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks            raise Exception()
37787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
37845518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        # Build and call the analyzer command.
3794967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        OutputOption = "-o '%s.plist' " % os.path.join(PlistPath, FileName)
3804967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        Command = CmdPrefix + OutputOption + ("'%s'" % FileName)
38145518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        LogFile = open(os.path.join(FailPath, FileName + ".stderr.txt"), "w+b")
38245518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        try:
38387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            if Verbose == 1:
38445518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks                print "  Executing: %s" % (Command,)
38545518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks            check_call(Command, cwd = Dir, stderr=LogFile,
38687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                                           stdout=LogFile,
38745518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks                                           shell=True)
38845518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        except CalledProcessError, e:
38945518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks            print "Error: Analyzes of %s failed. See %s for details." \
39045518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks                  "Error code %d." % \
39145518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks                   (FullFileName, LogFile.name, e.returncode)
39287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            Failed = True
39345518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        finally:
39487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            LogFile.close()
39587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
39645518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        # If command did not fail, erase the log file.
39745518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        if Failed == False:
39845518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks            os.remove(LogFile.name);
39945518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks
4004967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainardef getBuildLogPath(SBOutputDir):
4014967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  return os.path.join(SBOutputDir, LogFolderName, BuildLogName)
4024967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
4034967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainardef removeLogFile(SBOutputDir):
4044967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  BuildLogPath = getBuildLogPath(SBOutputDir)
4054967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  # Clean up the log file.
4064967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar  if (os.path.exists(BuildLogPath)) :
4074967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      RmCommand = "rm '%s'" % BuildLogPath
4084967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      if Verbose == 1:
4094967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar          print "  Executing: %s" % (RmCommand,)
4104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar      check_call(RmCommand, shell=True)
4114967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
412817ce3dd26590bf3f099fb82d9b6fcc43e8a7ee9Anna Zaksdef buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild):
41387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    TBegin = time.time()
4141b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
4154967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    BuildLogPath = getBuildLogPath(SBOutputDir)
41687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    print "Log file: %s" % (BuildLogPath,)
41745518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    print "Output directory: %s" %(SBOutputDir, )
41887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
4194967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    removeLogFile(SBOutputDir)
42087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
42145518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    # Clean up scan build results.
42245518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    if (os.path.exists(SBOutputDir)) :
4234967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        RmCommand = "rm -r '%s'" % SBOutputDir
42487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        if Verbose == 1:
42545518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks            print "  Executing: %s" % (RmCommand,)
42645518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks            check_call(RmCommand, shell=True)
42745518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    assert(not os.path.exists(SBOutputDir))
42845518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    os.makedirs(os.path.join(SBOutputDir, LogFolderName))
42987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
4301b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    # Open the log file.
4311b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    PBuildLogFile = open(BuildLogPath, "wb+")
43287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
43345518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    # Build and analyze the project.
43445518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    try:
435817ce3dd26590bf3f099fb82d9b6fcc43e8a7ee9Anna Zaks        if (ProjectBuildMode == 1):
43687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            downloadAndPatch(Dir, PBuildLogFile)
43787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            runCleanupScript(Dir, PBuildLogFile)
43845518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks            runScanBuild(Dir, SBOutputDir, PBuildLogFile)
43945518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        else:
440817ce3dd26590bf3f099fb82d9b6fcc43e8a7ee9Anna Zaks            runAnalyzePreprocessed(Dir, SBOutputDir, ProjectBuildMode)
44187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
44245518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        if IsReferenceBuild :
4435fa3f1309b27d2f117dfd10a45a8642b7d4baae9Anna Zaks            runCleanupScript(Dir, PBuildLogFile)
44487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
44587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            # Make the absolute paths relative in the reference results.
44687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            for (DirPath, Dirnames, Filenames) in os.walk(SBOutputDir):
44787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                for F in Filenames:
44887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    if (not F.endswith('plist')):
44987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                        continue
45087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    Plist = os.path.join(DirPath, F)
45187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    Data = plistlib.readPlist(Plist)
45287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    PathPrefix = Dir
45387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    if (ProjectBuildMode == 1):
45487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                        PathPrefix = os.path.join(Dir, PatchedSourceDirName)
45587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    Paths = [SourceFile[len(PathPrefix)+1:]\
45687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                              if SourceFile.startswith(PathPrefix)\
45787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                              else SourceFile for SourceFile in Data['files']]
45887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    Data['files'] = Paths
45987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    plistlib.writePlist(Data, Plist)
46087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
4611b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    finally:
4621b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        PBuildLogFile.close()
46387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
4641b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    print "Build complete (time: %.2f). See the log for more details: %s" % \
46587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar           ((time.time()-TBegin), BuildLogPath)
46687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
4671b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks# A plist file is created for each call to the analyzer(each source file).
46887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# We are only interested on the once that have bug reports, so delete the rest.
4691b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaksdef CleanUpEmptyPlists(SBOutputDir):
4701b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    for F in glob.glob(SBOutputDir + "/*/*.plist"):
4711b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        P = os.path.join(SBOutputDir, F)
47287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
4731b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        Data = plistlib.readPlist(P)
4741b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        # Delete empty reports.
4751b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        if not Data['files']:
4761b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks            os.remove(P)
4771b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks            continue
4781b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
47987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# Given the scan-build output directory, checks if the build failed
48087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# (by searching for the failures directories). If there are failures, it
48187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# creates a summary file in the output directory.
4821b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaksdef checkBuild(SBOutputDir):
4831b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    # Check if there are failures.
4841b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    Failures = glob.glob(SBOutputDir + "/*/failures/*.stderr.txt")
4851b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    TotalFailed = len(Failures);
4861b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    if TotalFailed == 0:
487191e2b1d4aad18794bc5612459384f0321ffdf38Jordan Rose        CleanUpEmptyPlists(SBOutputDir)
488191e2b1d4aad18794bc5612459384f0321ffdf38Jordan Rose        Plists = glob.glob(SBOutputDir + "/*/*.plist")
489651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        print "Number of bug reports (non-empty plist files) produced: %d" %\
490191e2b1d4aad18794bc5612459384f0321ffdf38Jordan Rose           len(Plists)
4911b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        return;
49287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
4931b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    # Create summary file to display when the build fails.
49445518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    SummaryPath = os.path.join(SBOutputDir, LogFolderName, FailuresSummaryFileName)
4951b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    if (Verbose > 0):
49645518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        print "  Creating the failures summary file %s" % (SummaryPath,)
49787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
4981b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    SummaryLog = open(SummaryPath, "w+")
4991b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    try:
5001b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        SummaryLog.write("Total of %d failures discovered.\n" % (TotalFailed,))
5011b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        if TotalFailed > NumOfFailuresInSummary:
50287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            SummaryLog.write("See the first %d below.\n"
5031b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks                                                   % (NumOfFailuresInSummary,))
5041b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        # TODO: Add a line "See the results folder for more."
50587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
5061b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        FailuresCopied = NumOfFailuresInSummary
5071b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        Idx = 0
50804bc014dfddd1298ae984a8632b41e0d77c9f556Jordan Rose        for FailLogPathI in Failures:
5091b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks            if Idx >= NumOfFailuresInSummary:
5101b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks                break;
51187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            Idx += 1
5121b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks            SummaryLog.write("\n-- Error #%d -----------\n" % (Idx,));
5131b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks            FailLogI = open(FailLogPathI, "r");
51487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            try:
5151b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks                shutil.copyfileobj(FailLogI, SummaryLog);
5161b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks            finally:
5171b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks                FailLogI.close()
5181b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    finally:
5191b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        SummaryLog.close()
52087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
521f063a3b783e22effa7972d05830cee942b2499ceAnna Zaks    print "Error: analysis failed. See ", SummaryPath
52287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    sys.exit(-1)
5231b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
5241b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks# Auxiliary object to discard stdout.
5251b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaksclass Discarder(object):
5261b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    def write(self, text):
5271b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        pass # do nothing
5281b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
5291b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks# Compare the warnings produced by scan-build.
53087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar# Strictness defines the success criteria for the test:
53187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar#   0 - success if there are no crashes or analyzer failure.
53287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar#   1 - success if there are no difference in the number of reported bugs.
53387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar#   2 - success if all the bug reports are identical.
53487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainardef runCmpResults(Dir, Strictness = 0):
53587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    TBegin = time.time()
5361b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
5371b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    RefDir = os.path.join(Dir, SBOutputDirReferencePrefix + SBOutputDirName)
5381b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    NewDir = os.path.join(Dir, SBOutputDirName)
53987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
5401b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    # We have to go one level down the directory tree.
54187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    RefList = glob.glob(RefDir + "/*")
5421b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    NewList = glob.glob(NewDir + "/*")
54387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
544de5f2ee2aa4afabd325056013becfee1172c8db2Jordan Rose    # Log folders are also located in the results dir, so ignore them.
545de5f2ee2aa4afabd325056013becfee1172c8db2Jordan Rose    RefLogDir = os.path.join(RefDir, LogFolderName)
546de5f2ee2aa4afabd325056013becfee1172c8db2Jordan Rose    if RefLogDir in RefList:
547de5f2ee2aa4afabd325056013becfee1172c8db2Jordan Rose        RefList.remove(RefLogDir)
54845518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    NewList.remove(os.path.join(NewDir, LogFolderName))
54987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
5501b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    if len(RefList) == 0 or len(NewList) == 0:
5511b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        return False
5521b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    assert(len(RefList) == len(NewList))
5531b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
55487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    # There might be more then one folder underneath - one per each scan-build
5551b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    # command (Ex: one for configure and one for make).
5561b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    if (len(RefList) > 1):
5571b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        # Assume that the corresponding folders have the same names.
5581b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        RefList.sort()
5591b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        NewList.sort()
56087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
5611b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    # Iterate and find the differences.
562a7a2564ff59a1917c5f27343923635bd231466d6Anna Zaks    NumDiffs = 0
56387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    PairList = zip(RefList, NewList)
56487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    for P in PairList:
56587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        RefDir = P[0]
5661b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        NewDir = P[1]
56787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
56887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        assert(RefDir != NewDir)
56987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        if Verbose == 1:
5701b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks            print "  Comparing Results: %s %s" % (RefDir, NewDir)
57187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
5721b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        DiffsPath = os.path.join(NewDir, DiffsSummaryFileName)
57387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        PatchedSourceDirPath = os.path.join(Dir, PatchedSourceDirName)
57487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        Opts = CmpRuns.CmpOptions(DiffsPath, "", PatchedSourceDirPath)
5751b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        # Discard everything coming out of stdout (CmpRun produces a lot of them).
5761b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        OLD_STDOUT = sys.stdout
5771b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        sys.stdout = Discarder()
5781b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        # Scan the results, delete empty plist files.
57987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        NumDiffs, ReportsInRef, ReportsInNew = \
58087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            CmpRuns.dumpScanBuildResultsDiff(RefDir, NewDir, Opts, False)
5811b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        sys.stdout = OLD_STDOUT
582a7a2564ff59a1917c5f27343923635bd231466d6Anna Zaks        if (NumDiffs > 0) :
583a7a2564ff59a1917c5f27343923635bd231466d6Anna Zaks            print "Warning: %r differences in diagnostics. See %s" % \
584a7a2564ff59a1917c5f27343923635bd231466d6Anna Zaks                  (NumDiffs, DiffsPath,)
58587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        if Strictness >= 2 and NumDiffs > 0:
58687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            print "Error: Diffs found in strict mode (2)."
58787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            sys.exit(-1)
58887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        elif Strictness >= 1 and ReportsInRef != ReportsInNew:
58987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            print "Error: The number of results are different in strict mode (1)."
59087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            sys.exit(-1)
59187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
59287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    print "Diagnostic comparison complete (time: %.2f)." % (time.time()-TBegin)
593a7a2564ff59a1917c5f27343923635bd231466d6Anna Zaks    return (NumDiffs > 0)
59487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
5954967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainardef cleanupReferenceResults(SBOutputDir):
5964967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    # Delete html, css, and js files from reference results. These can
5974967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    # include multiple copies of the benchmark source and so get very large.
5984967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    Extensions = ["html", "css", "js"]
5994967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    for E in Extensions:
6004967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        for F in glob.glob("%s/*/*.%s" % (SBOutputDir, E)):
6014967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            P = os.path.join(SBOutputDir, F)
6024967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            RmCommand = "rm '%s'" % P
6034967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar            check_call(RmCommand, shell=True)
6044967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
6054967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    # Remove the log file. It leaks absolute path names.
6064967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    removeLogFile(SBOutputDir)
6074967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar
60809e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaksdef updateSVN(Mode, ProjectsMap):
60909e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks    try:
61087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        ProjectsMap.seek(0)
61109e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks        for I in csv.reader(ProjectsMap):
61287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            ProjName = I[0]
6136d7e3727996cf6c418e9fdccf8521dc3282f9368Jordan Rose            Path = os.path.join(ProjName, getSBOutputDirName(True))
61487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
61509e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks            if Mode == "delete":
6164967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                Command = "svn delete '%s'" % (Path,)
61709e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks            else:
6184967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar                Command = "svn add '%s'" % (Path,)
61945518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks
62087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            if Verbose == 1:
62109e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks                print "  Executing: %s" % (Command,)
62287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            check_call(Command, shell=True)
62387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
62409e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks        if Mode == "delete":
62509e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks            CommitCommand = "svn commit -m \"[analyzer tests] Remove " \
62687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                            "reference results.\""
62709e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks        else:
62809e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks            CommitCommand = "svn commit -m \"[analyzer tests] Add new " \
62909e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks                            "reference results.\""
63087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        if Verbose == 1:
63109e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks            print "  Executing: %s" % (CommitCommand,)
63287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        check_call(CommitCommand, shell=True)
63309e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks    except:
63409e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks        print "Error: SVN update failed."
63509e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks        sys.exit(-1)
63687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
63787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainardef testProject(ID, ProjectBuildMode, IsReferenceBuild=False, Dir=None, Strictness = 0):
63845518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    print " \n\n--- Building project %s" % (ID,)
6391b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
64087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    TBegin = time.time()
6411b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
6421b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    if Dir is None :
64387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        Dir = getProjectDir(ID)
64487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    if Verbose == 1:
6451b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks        print "  Build directory: %s." % (Dir,)
64687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
6471b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    # Set the build results directory.
6486d7e3727996cf6c418e9fdccf8521dc3282f9368Jordan Rose    RelOutputDir = getSBOutputDirName(IsReferenceBuild)
64909e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks    SBOutputDir = os.path.join(Dir, RelOutputDir)
65087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
651817ce3dd26590bf3f099fb82d9b6fcc43e8a7ee9Anna Zaks    buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild)
6521b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks
6531b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    checkBuild(SBOutputDir)
65487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
655191e2b1d4aad18794bc5612459384f0321ffdf38Jordan Rose    if IsReferenceBuild == False:
65687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        runCmpResults(Dir, Strictness)
6574967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar    else:
6584967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar        cleanupReferenceResults(SBOutputDir)
65987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
6601b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    print "Completed tests for project %s (time: %.2f)." % \
6611b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks          (ID, (time.time()-TBegin))
66287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
66387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainardef testAll(IsReferenceBuild = False, UpdateSVN = False, Strictness = 0):
6641b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    PMapFile = open(getProjectMapPath(), "rb")
66587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    try:
66609e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks        # Validate the input.
66709e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks        for I in csv.reader(PMapFile):
66845518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks            if (len(I) != 2) :
66945518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks                print "Error: Rows in the ProjectMapFile should have 3 entries."
67045518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks                raise Exception()
671817ce3dd26590bf3f099fb82d9b6fcc43e8a7ee9Anna Zaks            if (not ((I[1] == "0") | (I[1] == "1") | (I[1] == "2"))):
672817ce3dd26590bf3f099fb82d9b6fcc43e8a7ee9Anna Zaks                print "Error: Second entry in the ProjectMapFile should be 0" \
673817ce3dd26590bf3f099fb82d9b6fcc43e8a7ee9Anna Zaks                      " (single file), 1 (project), or 2(single file c++11)."
67487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                raise Exception()
67509e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks
67687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        # When we are regenerating the reference results, we might need to
67709e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks        # update svn. Remove reference results from SVN.
67809e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks        if UpdateSVN == True:
6796d7e3727996cf6c418e9fdccf8521dc3282f9368Jordan Rose            assert(IsReferenceBuild == True);
68009e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks            updateSVN("delete",  PMapFile);
68187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
68209e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks        # Test the projects.
68387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        PMapFile.seek(0)
68409e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks        for I in csv.reader(PMapFile):
68587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            testProject(I[0], int(I[1]), IsReferenceBuild, None, Strictness)
68609e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks
68709e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks        # Add reference results to SVN.
68809e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks        if UpdateSVN == True:
68909e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks            updateSVN("add",  PMapFile);
69009e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks
69145518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks    except:
69245518b1f768c302837096d1359b2935cdb8ee08dAnna Zaks        print "Error occurred. Premature termination."
69387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        raise
6941b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaks    finally:
69587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        PMapFile.close()
69687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
6971b41716abf6856af893fd2f13cd0272dffa0e312Anna Zaksif __name__ == '__main__':
69887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    # Parse command line arguments.
69987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    Parser = argparse.ArgumentParser(description='Test the Clang Static Analyzer.')
70087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    Parser.add_argument('--strictness', dest='strictness', type=int, default=0,
70187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                       help='0 to fail on runtime errors, 1 to fail when the number\
70287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                             of found bugs are different from the reference, 2 to \
70387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                             fail on any difference from the reference. Default is 0.')
70487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    Parser.add_argument('-r', dest='regenerate', action='store_true', default=False,
70587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                        help='Regenerate reference output.')
70687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    Parser.add_argument('-rs', dest='update_reference', action='store_true',
70787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                        default=False, help='Regenerate reference output and update svn.')
70887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    Args = Parser.parse_args()
70987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
71009e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks    IsReference = False
71109e9cf0927641ee64bb0a354b0a6acca604361ccAnna Zaks    UpdateSVN = False
71287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    Strictness = Args.strictness
71387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    if Args.regenerate:
71487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        IsReference = True
71587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    elif Args.update_reference:
71687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        IsReference = True
71787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        UpdateSVN = True
71887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
71987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    testAll(IsReference, UpdateSVN, Strictness)
720