[Cmake-commits] [cmake-commits] king committed cmCTestBuildHandler.cxx 1.70 1.71 cmCTestBuildHandler.h 1.15 1.16

cmake-commits at cmake.org cmake-commits at cmake.org
Wed Feb 11 15:18:10 EST 2009


Update of /cvsroot/CMake/CMake/Source/CTest
In directory public:/mounts/ram/cvs-serv19955/Source/CTest

Modified Files:
	cmCTestBuildHandler.cxx cmCTestBuildHandler.h 
Log Message:
ENH: Teach CTest dashboard builds to use launchers

This defines a 'UseLaunchers' CTest configuration option.  When enabled,
CTest skips log scraping from the Build step output.  Instead it defines
the environment variable CTEST_LAUNCH_LOGS to a log directory during the
build.  After the build it looks for error-*.xml and warning-*.xml files
containing fragments for inclusion in Build.xml and submission.

This is useful in conjuction with 'ctest --launch' and the RULE_LAUNCH_*
properties to get reliable, highly-granular build failure reports.


Index: cmCTestBuildHandler.h
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/CTest/cmCTestBuildHandler.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -C 2 -d -r1.15 -r1.16
*** cmCTestBuildHandler.h	4 Feb 2009 19:34:12 -0000	1.15
--- cmCTestBuildHandler.h	11 Feb 2009 20:18:08 -0000	1.16
***************
*** 88,93 ****
--- 88,97 ----
    // generate the XML output
    void GenerateXMLHeader(std::ostream& os);
+   void GenerateXMLLaunched(std::ostream& os);
    void GenerateXMLLogScraped(std::ostream& os);
    void GenerateXMLFooter(std::ostream& os, double elapsed_build_time);
+   void GenerateXMLLaunchedFragment(std::ostream& os, const char* fname);
+   bool IsLaunchedErrorFile(const char* fname);
+   bool IsLaunchedWarningFile(const char* fname);
  
    std::string             StartBuild;
***************
*** 100,103 ****
--- 104,109 ----
    std::vector<cmStdString> CustomWarningMatches;
    std::vector<cmStdString> CustomWarningExceptions;
+   std::vector<std::string> ReallyCustomWarningMatches;
+   std::vector<std::string> ReallyCustomWarningExceptions;
    std::vector<cmCTestCompileErrorWarningRex> ErrorWarningFileLineRegex;
  
***************
*** 138,141 ****
--- 144,153 ----
    int                                   MaxErrors;
    int                                   MaxWarnings;
+ 
+   bool UseCTestLaunch;
+   std::string CTestLaunchDir;
+   class LaunchHelper;
+   friend class LaunchHelper;
+   class FragmentCompare;
  };
  

Index: cmCTestBuildHandler.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/CTest/cmCTestBuildHandler.cxx,v
retrieving revision 1.70
retrieving revision 1.71
diff -C 2 -d -r1.70 -r1.71
*** cmCTestBuildHandler.cxx	5 Feb 2009 21:31:37 -0000	1.70
--- cmCTestBuildHandler.cxx	11 Feb 2009 20:18:08 -0000	1.71
***************
*** 25,31 ****
--- 25,33 ----
  #include "cmGeneratedFileStream.h"
  #include "cmXMLSafe.h"
+ #include "cmFileTimeComparison.h"
  
  //#include <cmsys/RegularExpression.hxx>
  #include <cmsys/Process.h>
+ #include <cmsys/Directory.hxx>
  
  // used for sleep
***************
*** 186,189 ****
--- 188,192 ----
    this->LastErrorOrWarning = this->ErrorsAndWarnings.end();
  
+   this->UseCTestLaunch = false;
  }
  
***************
*** 198,201 ****
--- 201,206 ----
    this->CustomWarningMatches.clear();
    this->CustomWarningExceptions.clear();
+   this->ReallyCustomWarningMatches.clear();
+   this->ReallyCustomWarningExceptions.clear();
    this->ErrorWarningFileLineRegex.clear();
  
***************
*** 228,231 ****
--- 233,238 ----
    this->MaxErrors = 50;
    this->MaxWarnings = 50;
+ 
+   this->UseCTestLaunch = false;
  }
  
***************
*** 247,250 ****
--- 254,271 ----
                               "CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS",
                               this->MaxWarnings);
+ 
+   // Record the user-specified custom warning rules.
+   if(const char* customWarningMatchers =
+      mf->GetDefinition("CTEST_CUSTOM_WARNING_MATCH"))
+     {
+     cmSystemTools::ExpandListArgument(customWarningMatchers,
+                                       this->ReallyCustomWarningMatches);
+     }
+   if(const char* customWarningExceptions =
+      mf->GetDefinition("CTEST_CUSTOM_WARNING_EXCEPTION"))
+     {
+     cmSystemTools::ExpandListArgument(customWarningExceptions,
+                                       this->ReallyCustomWarningExceptions);
+     }
  }
  
***************
*** 307,310 ****
--- 328,335 ----
      }
  
+   std::string const& useLaunchers =
+     this->CTest->GetCTestConfiguration("UseLaunchers");
+   this->UseCTestLaunch = cmSystemTools::IsOn(useLaunchers.c_str());
+ 
    // Create a last build log
    cmGeneratedFileStream ofs;
***************
*** 468,472 ****
      }
    this->GenerateXMLHeader(xofs);
!   this->GenerateXMLLogScraped(xofs);
    this->GenerateXMLFooter(xofs, elapsed_build_time);
  
--- 493,504 ----
      }
    this->GenerateXMLHeader(xofs);
!   if(this->UseCTestLaunch)
!     {
!     this->GenerateXMLLaunched(xofs);
!     }
!   else
!     {
!     this->GenerateXMLLogScraped(xofs);
!     }
    this->GenerateXMLFooter(xofs, elapsed_build_time);
  
***************
*** 498,501 ****
--- 530,597 ----
  
  //----------------------------------------------------------------------------
+ class cmCTestBuildHandler::FragmentCompare
+ {
+ public:
+   FragmentCompare(cmFileTimeComparison* ftc): FTC(ftc) {}
+   bool operator()(std::string const& l, std::string const& r)
+     {
+     // Order files by modification time.  If comparison fails, just
+     // use lexicographic order (should not happen in our use case).
+     int result;
+     if(this->FTC->FileTimeCompare(l.c_str(), r.c_str(), &result))
+       {
+       return result < 0;
+       }
+     else
+       {
+       return l < r;
+       }
+     }
+ private:
+   cmFileTimeComparison* FTC;
+ };
+ 
+ //----------------------------------------------------------------------------
+ void cmCTestBuildHandler::GenerateXMLLaunched(std::ostream& os)
+ {
+   if(this->CTestLaunchDir.empty())
+     {
+     return;
+     }
+ 
+   // Sort XML fragments in chronological order.
+   cmFileTimeComparison ftc;
+   FragmentCompare fragmentCompare(&ftc);
+   typedef std::set<cmStdString, FragmentCompare> Fragments;
+   Fragments fragments(fragmentCompare);
+ 
+   // Identify fragments on disk.
+   cmsys::Directory launchDir;
+   launchDir.Load(this->CTestLaunchDir.c_str());
+   unsigned long n = launchDir.GetNumberOfFiles();
+   for(unsigned long i=0; i < n; ++i)
+     {
+     const char* fname = launchDir.GetFile(i);
+     if(this->IsLaunchedErrorFile(fname))
+       {
+       fragments.insert(this->CTestLaunchDir + "/" + fname);
+       ++this->TotalErrors;
+       }
+     else if(this->IsLaunchedWarningFile(fname))
+       {
+       fragments.insert(this->CTestLaunchDir + "/" + fname);
+       ++this->TotalWarnings;
+       }
+     }
+ 
+   // Copy the fragments into the final XML file.
+   for(Fragments::const_iterator fi = fragments.begin();
+       fi != fragments.end(); ++fi)
+     {
+     this->GenerateXMLLaunchedFragment(os, fi->c_str());
+     }
+ }
+ 
+ //----------------------------------------------------------------------------
  void cmCTestBuildHandler::GenerateXMLLogScraped(std::ostream& os)
  {
***************
*** 613,616 ****
--- 709,740 ----
  }
  
+ //----------------------------------------------------------------------------
+ void cmCTestBuildHandler::GenerateXMLLaunchedFragment(std::ostream& os,
+                                                       const char* fname)
+ {
+   std::ifstream fin(fname, std::ios::in | std::ios::binary);
+   std::string line;
+   while(cmSystemTools::GetLineFromStream(fin, line))
+     {
+     os << line << "\n";
+     }
+ }
+ 
+ //----------------------------------------------------------------------------
+ bool cmCTestBuildHandler::IsLaunchedErrorFile(const char* fname)
+ {
+   // error-{hash}.xml
+   return (strncmp(fname, "error-", 6) == 0 &&
+           strcmp(fname+strlen(fname)-4, ".xml") == 0);
+ }
+ 
+ //----------------------------------------------------------------------------
+ bool cmCTestBuildHandler::IsLaunchedWarningFile(const char* fname)
+ {
+   // warning-{hash}.xml
+   return (strncmp(fname, "warning-", 8) == 0 &&
+           strcmp(fname+strlen(fname)-4, ".xml") == 0);
+ }
+ 
  //######################################################################
  //######################################################################
***************
*** 618,621 ****
--- 742,841 ----
  //######################################################################
  
+ //----------------------------------------------------------------------------
+ class cmCTestBuildHandler::LaunchHelper
+ {
+ public:
+   LaunchHelper(cmCTestBuildHandler* handler);
+   ~LaunchHelper();
+ private:
+   cmCTestBuildHandler* Handler;
+   cmCTest* CTest;
+ 
+   void WriteScrapeMatchers();
+   void WriteScrapeMatchers(const char* purpose,
+                            std::vector<std::string> const& matchers);
+ };
+ 
+ //----------------------------------------------------------------------------
+ cmCTestBuildHandler::LaunchHelper::LaunchHelper(cmCTestBuildHandler* handler):
+   Handler(handler), CTest(handler->CTest)
+ {
+   std::string tag = this->CTest->GetCurrentTag();
+   if(tag.empty())
+     {
+     // This is not for a dashboard submission, so there is no XML.
+     // Skip enabling the launchers.
+     this->Handler->UseCTestLaunch = false;
+     }
+   else
+     {
+     // Compute a directory in which to store launcher fragments.
+     std::string& launchDir = this->Handler->CTestLaunchDir;
+     launchDir = this->CTest->GetBinaryDir();
+     launchDir += "/Testing/";
+     launchDir += tag;
+     launchDir += "/Build";
+ 
+     // Clean out any existing launcher fragments.
+     cmSystemTools::RemoveADirectory(launchDir.c_str());
+ 
+     if(this->Handler->UseCTestLaunch)
+       {
+       // Enable launcher fragments.
+       cmSystemTools::MakeDirectory(launchDir.c_str());
+       this->WriteScrapeMatchers();
+       std::string launchEnv = "CTEST_LAUNCH_LOGS=";
+       launchEnv += launchDir;
+       cmSystemTools::PutEnv(launchEnv.c_str());
+       }
+     }
+ 
+   // If not using launchers, make sure they passthru.
+   if(!this->Handler->UseCTestLaunch)
+     {
+     cmSystemTools::UnsetEnv("CTEST_LAUNCH_LOGS");
+     }
+ }
+ 
+ //----------------------------------------------------------------------------
+ cmCTestBuildHandler::LaunchHelper::~LaunchHelper()
+ {
+   if(this->Handler->UseCTestLaunch)
+     {
+     cmSystemTools::UnsetEnv("CTEST_LAUNCH_LOGS");
+     }
+ }
+ 
+ //----------------------------------------------------------------------------
+ void cmCTestBuildHandler::LaunchHelper::WriteScrapeMatchers()
+ {
+   this->WriteScrapeMatchers("Warning",
+                             this->Handler->ReallyCustomWarningMatches);
+   this->WriteScrapeMatchers("WarningSuppress",
+                             this->Handler->ReallyCustomWarningExceptions);
+ }
+ 
+ //----------------------------------------------------------------------------
+ void
+ cmCTestBuildHandler::LaunchHelper
+ ::WriteScrapeMatchers(const char* purpose,
+                       std::vector<std::string> const& matchers)
+ {
+   if(matchers.empty())
+     {
+     return;
+     }
+   std::string fname = this->Handler->CTestLaunchDir;
+   fname += "/Custom";
+   fname += purpose;
+   fname += ".txt";
+   cmGeneratedFileStream fout(fname.c_str());
+   for(std::vector<std::string>::const_iterator mi = matchers.begin();
+       mi != matchers.end(); ++mi)
+     {
+     fout << *mi << "\n";
+     }
+ }
+ 
  //----------------------------------------------------------------------
  int cmCTestBuildHandler::RunMakeCommand(const char* command,
***************
*** 646,649 ****
--- 866,873 ----
    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl);
  
+   // Optionally use make rule launchers to record errors and warnings.
+   LaunchHelper launchHelper(this);
+   static_cast<void>(launchHelper);
+ 
    // Now create process object
    cmsysProcess* cp = cmsysProcess_New();
***************
*** 663,667 ****
      "   Each symbol represents " << tick_len << " bytes of output."
      << std::endl
!     << "   '!' represents an error and '*' a warning." << std::endl
      << "    " << std::flush);
  
--- 887,892 ----
      "   Each symbol represents " << tick_len << " bytes of output."
      << std::endl
!     << (this->UseCTestLaunch? "" :
!         "   '!' represents an error and '*' a warning.\n")
      << "    " << std::flush);
  
***************
*** 940,943 ****
--- 1165,1174 ----
  int cmCTestBuildHandler::ProcessSingleLine(const char* data)
  {
+   if(this->UseCTestLaunch)
+     {
+     // No log scraping when using launchers.
+     return b_REGULAR_LINE;
+     }
+ 
    cmCTestLog(this->CTest, DEBUG, "Line: [" << data << "]" << std::endl);
  



More information about the Cmake-commits mailing list