ENH: added more capabilities to ctest

This commit is contained in:
Ken Martin 2005-01-27 10:11:04 -05:00
parent 3575fed90c
commit ef75402148
10 changed files with 567 additions and 15 deletions

View File

@ -145,6 +145,9 @@ SET(CMTEST_SRCS ctest.cxx cmCTest.cxx
CTest/cmCTestScriptHandler.cxx
CTest/cmCTestTestHandler.cxx
CTest/cmCTestUpdateHandler.cxx
CTest/cmCTestEmptyBinaryDirectoryCommand.cxx
CTest/cmCTestRunScriptCommand.cxx
CTest/cmCTestSleepCommand.cxx
)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/Source/CTest)

View File

@ -0,0 +1,46 @@
/*=========================================================================
Program: CMake - Cross-Platform Makefile Generator
Module: $RCSfile$
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#ifndef cmCTestCommand_h
#define cmCTestCommand_h
#include "cmCommand.h"
class cmCTest;
class cmCTestScriptHandler;
/** \class cmCTestCommand
* \brief A superclass for all commands added to the CTestScriptHandler
*
* cmCTestCommand is the superclass for all commands that will be added to
* the ctest script handlers parser.
*
*/
class cmCTestCommand : public cmCommand
{
public:
cmCTestCommand() {m_CTest = 0; m_CTestScriptHandler = 0;}
cmCTest *m_CTest;
cmCTestScriptHandler *m_CTestScriptHandler;
cmTypeMacro(cmCTestCommand, cmCommand);
};
#endif

View File

@ -0,0 +1,35 @@
/*=========================================================================
Program: CMake - Cross-Platform Makefile Generator
Module: $RCSfile$
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#include "cmCTestEmptyBinaryDirectoryCommand.h"
#include "cmCTestScriptHandler.h"
bool cmCTestEmptyBinaryDirectoryCommand::InitialPass(
std::vector<std::string> const& args)
{
if(args.size() != 1 )
{
this->SetError("called with incorrect number of arguments");
return false;
}
cmCTestScriptHandler::EmptyBinaryDirectory(args[0].c_str());
return true;
}

View File

@ -0,0 +1,81 @@
/*=========================================================================
Program: CMake - Cross-Platform Makefile Generator
Module: $RCSfile$
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#ifndef cmCTestEmptyBinaryDirectoryCommand_h
#define cmCTestEmptyBinaryDirectoryCommand_h
#include "cmCTestCommand.h"
/** \class cmCTestEmptyBinaryDirectory
* \brief Run a ctest script
*
* cmLibrarysCommand defines a list of executable (i.e., test)
* programs to create.
*/
class cmCTestEmptyBinaryDirectoryCommand : public cmCTestCommand
{
public:
cmCTestEmptyBinaryDirectoryCommand() {}
/**
* This is a virtual constructor for the command.
*/
virtual cmCommand* Clone()
{
cmCTestEmptyBinaryDirectoryCommand* ni = new cmCTestEmptyBinaryDirectoryCommand;
ni->m_CTest = this->m_CTest;
ni->m_CTestScriptHandler = this->m_CTestScriptHandler;
return ni;
}
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
*/
virtual bool InitialPass(std::vector<std::string> const& args);
/**
* The name of the command as specified in CMakeList.txt.
*/
virtual const char* GetName() { return "CTEST_EMPTY_BINARY_DIRECTORY";}
/**
* Succinct documentation.
*/
virtual const char* GetTerseDocumentation()
{
return "empties the binary directory";
}
/**
* More documentation.
*/
virtual const char* GetFullDocumentation()
{
return
" CTEST_EMPTY_BINARY_DIRECTORY( directory )\n"
"Removes a binary directory. This command will perform some checks "
"prior to deleting the directory in an attempt to avoid malicious "
"or accidental directory deletion.";
}
cmTypeMacro(cmCTestEmptyBinaryDirectoryCommand, cmCTestCommand);
};
#endif

View File

@ -0,0 +1,39 @@
/*=========================================================================
Program: CMake - Cross-Platform Makefile Generator
Module: $RCSfile$
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#include "cmCTestRunScriptCommand.h"
#include "cmCTestScriptHandler.h"
bool cmCTestRunScriptCommand::InitialPass(std::vector<std::string> const& args)
{
if(args.size() < 1 )
{
m_CTestScriptHandler->RunCurrentScript(m_CTest);
return true;
}
// run each script
unsigned int i;
for (i = 0; i < args.size(); ++i)
{
cmCTestScriptHandler::RunScript(m_CTest, args[i].c_str());
}
return true;
}

View File

@ -0,0 +1,82 @@
/*=========================================================================
Program: CMake - Cross-Platform Makefile Generator
Module: $RCSfile$
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#ifndef cmCTestRunScriptCommand_h
#define cmCTestRunScriptCommand_h
#include "cmCTestCommand.h"
/** \class cmCTestRunScript
* \brief Run a ctest script
*
* cmLibrarysCommand defines a list of executable (i.e., test)
* programs to create.
*/
class cmCTestRunScriptCommand : public cmCTestCommand
{
public:
cmCTestRunScriptCommand() {}
/**
* This is a virtual constructor for the command.
*/
virtual cmCommand* Clone()
{
cmCTestRunScriptCommand* ni = new cmCTestRunScriptCommand;
ni->m_CTest = this->m_CTest;
ni->m_CTestScriptHandler = this->m_CTestScriptHandler;
return ni;
}
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
*/
virtual bool InitialPass(std::vector<std::string> const& args);
/**
* The name of the command as specified in CMakeList.txt.
*/
virtual const char* GetName() { return "CTEST_RUN_SCRIPT";}
/**
* Succinct documentation.
*/
virtual const char* GetTerseDocumentation()
{
return "runs a ctest -S script";
}
/**
* More documentation.
*/
virtual const char* GetFullDocumentation()
{
return
" CTEST_RUN_SCRIPT(script_file_name script_file_name1 \n"
" script_file_name2 ...)\n"
"Runs a script or scripts much like if it was run from ctest -S. "
"If no argument is provided then the current script is run using "
"the current settings of the variables.";
}
cmTypeMacro(cmCTestRunScriptCommand, cmCTestCommand);
};
#endif

View File

@ -19,6 +19,7 @@
#include "cmCTest.h"
#include "cmake.h"
#include "cmFunctionBlocker.h"
#include "cmMakefile.h"
#include "cmLocalGenerator.h"
#include "cmGlobalGenerator.h"
@ -41,19 +42,48 @@
# include <unistd.h>
#endif
#include "cmCTestEmptyBinaryDirectoryCommand.h"
#include "cmCTestRunScriptCommand.h"
#include "cmCTestSleepCommand.h"
#define CTEST_INITIAL_CMAKE_OUTPUT_FILE_NAME "CTestInitialCMakeOutput.log"
// used to keep elapsed time up to date
class cmCTestScriptFunctionBlocker : public cmFunctionBlocker
{
public:
cmCTestScriptFunctionBlocker() {}
virtual ~cmCTestScriptFunctionBlocker() {}
virtual bool IsFunctionBlocked(const cmListFileFunction& lff,
cmMakefile &mf);
//virtual bool ShouldRemove(const cmListFileFunction& lff, cmMakefile &mf);
//virtual void ScopeEnded(cmMakefile &mf);
cmCTestScriptHandler* m_CTestScriptHandler;
};
// simply update the time and don't block anything
bool cmCTestScriptFunctionBlocker::
IsFunctionBlocked(const cmListFileFunction& , cmMakefile &)
{
m_CTestScriptHandler->UpdateElapsedTime();
return false;
}
//----------------------------------------------------------------------
cmCTestScriptHandler::cmCTestScriptHandler()
{
m_Verbose = false;
m_Backup = false;
m_ScriptHasRun = false;
m_EmptyBinDir = false;
m_EmptyBinDirOnce = false;
m_Makefile = 0;
m_LocalGenerator = 0;
m_CMake = 0;
m_GlobalGenerator = 0;
m_ScriptStartTime = 0;
// the *60 is becuase the settings are in minutes but GetTime is seconds
m_MinimumInterval = 30*60;
@ -110,11 +140,25 @@ int cmCTestScriptHandler::RunConfigurationScript(cmCTest* ctest)
return res;
}
void cmCTestScriptHandler::UpdateElapsedTime()
{
if (m_LocalGenerator)
{
// set the current elapsed time
char timeString[20];
int itime = static_cast<unsigned int>(cmSystemTools::GetTime()
- m_ScriptStartTime);
sprintf(timeString,"%i",itime);
m_LocalGenerator->GetMakefile()->AddDefinition("CTEST_ELAPSED_TIME",
timeString);
}
}
//----------------------------------------------------------------------
// this sets up some variables for thew script to use, creates the required
// cmake instance and generators, and then reads in the script
int cmCTestScriptHandler::ReadInScript(cmCTest* ctest, const std::string& total_script_arg)
int cmCTestScriptHandler::ReadInScript(cmCTest* ctest,
const std::string& total_script_arg)
{
// if the argument has a , in it then it needs to be broken into the fist
// argument (which is the script) and the second argument which will be
@ -158,12 +202,36 @@ int cmCTestScriptHandler::ReadInScript(cmCTest* ctest, const std::string& total_
script).c_str());
m_LocalGenerator->GetMakefile()->AddDefinition("CTEST_EXECUTABLE_NAME",
ctest->GetCTestExecutable());
this->UpdateElapsedTime();
// add any ctest specific commands, probably should have common superclass
// for ctest commands to clean this up. If a couple more commands are
// created with the same format lets do that - ken
cmCTestCommand* newCom = new cmCTestRunScriptCommand;
newCom->m_CTest = ctest;
newCom->m_CTestScriptHandler = this;
m_CMake->AddCommand(newCom);
newCom = new cmCTestEmptyBinaryDirectoryCommand;
newCom->m_CTest = ctest;
newCom->m_CTestScriptHandler = this;
m_CMake->AddCommand(newCom);
newCom = new cmCTestSleepCommand;
newCom->m_CTest = ctest;
newCom->m_CTestScriptHandler = this;
m_CMake->AddCommand(newCom);
// add the script arg if defined
if (script_arg.size())
{
m_LocalGenerator->GetMakefile()->AddDefinition(
"CTEST_SCRIPT_ARG", script_arg.c_str());
}
// always add a function blocker to update the elapsed time
cmCTestScriptFunctionBlocker *f = new cmCTestScriptFunctionBlocker();
f->m_CTestScriptHandler = this;
m_LocalGenerator->GetMakefile()->AddFunctionBlocker(f);
// finally read in the script
if (!m_LocalGenerator->GetMakefile()->ReadListFile(0, script.c_str()))
@ -264,11 +332,13 @@ int cmCTestScriptHandler::ExtractVariables()
}
this->UpdateElapsedTime();
return 0;
}
//----------------------------------------------------------------------
void cmCTestScriptHandler::LocalSleep(unsigned int secondsToWait)
void cmCTestScriptHandler::SleepInSeconds(unsigned int secondsToWait)
{
#if defined(_WIN32)
Sleep(1000*secondsToWait);
@ -284,13 +354,28 @@ int cmCTestScriptHandler::RunConfigurationScript(cmCTest* ctest,
{
int result;
m_ScriptStartTime =
cmSystemTools::GetTime();
// read in the script
result = this->ReadInScript(ctest, total_script_arg);
if (result)
{
return result;
}
if (!m_ScriptHasRun)
{
return this->RunCurrentScript(ctest);
}
return result;
}
int cmCTestScriptHandler::RunCurrentScript(cmCTest* ctest)
{
int result;
m_ScriptHasRun = true;
// no popup widows
cmSystemTools::SetRunCommandHideConsole(true);
@ -318,6 +403,7 @@ int cmCTestScriptHandler::RunConfigurationScript(cmCTest* ctest,
// for a continuous, do we ned to run it more than once?
if ( m_ContinuousDuration >= 0 )
{
this->UpdateElapsedTime();
double ending_time = cmSystemTools::GetTime() + m_ContinuousDuration;
if (m_EmptyBinDirOnce)
{
@ -330,7 +416,7 @@ int cmCTestScriptHandler::RunConfigurationScript(cmCTest* ctest,
interval = cmSystemTools::GetTime() - interval;
if (interval < m_MinimumInterval)
{
this->LocalSleep(
this->SleepInSeconds(
static_cast<unsigned int>(m_MinimumInterval - interval));
}
if (m_EmptyBinDirOnce)
@ -489,13 +575,7 @@ int cmCTestScriptHandler::RunConfigurationDashboard()
// clear the binary directory?
if (m_EmptyBinDir)
{
// try to avoid deleting directories that we shouldn't
std::string check = m_BinaryDir;
check += "/CMakeCache.txt";
if (cmSystemTools::FileExists(check.c_str()))
{
cmSystemTools::RemoveADirectory(m_BinaryDir.c_str());
}
cmCTestScriptHandler::EmptyBinaryDirectory(m_BinaryDir.c_str());
}
// make sure the binary directory exists if it isn't the srcdir
@ -681,4 +761,30 @@ void cmCTestScriptHandler::RestoreBackupDirectories()
}
}
bool cmCTestScriptHandler::RunScript(cmCTest *ctest, const char *sname)
{
cmCTestScriptHandler* sh = new cmCTestScriptHandler();
sh->AddConfigurationScript(sname);
sh->RunConfigurationScript(ctest);
delete sh;
return true;
}
bool cmCTestScriptHandler::EmptyBinaryDirectory(const char *sname)
{
// try to avoid deleting root
if (!sname || strlen(sname) < 2)
{
return false;
}
// try to avoid deleting directories that we shouldn't
std::string check = sname;
check += "/CMakeCache.txt";
if (cmSystemTools::FileExists(check.c_str()))
{
cmSystemTools::RemoveADirectory(sname);
return true;
}
return false;
}

View File

@ -81,7 +81,24 @@ public:
* If verbose then more informaiton is printed out
*/
void SetVerbose(bool val) { m_Verbose = val; }
/*
* Run a script
*/
static bool RunScript(cmCTest* ctest, const char *script);
int RunCurrentScript(cmCTest* ctest);
/*
* Empty Binary Directory
*/
static bool EmptyBinaryDirectory(const char *dir);
/*
* Some elapsed time handling functions
*/
static void SleepInSeconds(unsigned int secondsToWait);
void UpdateElapsedTime();
cmCTestScriptHandler();
~cmCTestScriptHandler();
@ -98,8 +115,6 @@ private:
// perform any extra cvs updates that were requested
int PerformExtraUpdates();
void LocalSleep(unsigned int secondsToWait);
// backup and restore dirs
int BackupDirectories();
void RestoreBackupDirectories();
@ -113,7 +128,8 @@ private:
bool m_Backup;
bool m_EmptyBinDir;
bool m_EmptyBinDirOnce;
bool m_ScriptHasRun;
cmStdString m_SourceDir;
cmStdString m_BinaryDir;
cmStdString m_BackupSourceDir;
@ -130,6 +146,9 @@ private:
double m_MinimumInterval;
double m_ContinuousDuration;
// what time in seconds did this script start running
double m_ScriptStartTime;
cmMakefile *m_Makefile;
cmLocalGenerator *m_LocalGenerator;

View File

@ -0,0 +1,59 @@
/*=========================================================================
Program: CMake - Cross-Platform Makefile Generator
Module: $RCSfile$
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#include "cmCTestSleepCommand.h"
#include "cmCTestScriptHandler.h"
bool cmCTestSleepCommand::InitialPass(
std::vector<std::string> const& args)
{
if (args.size() < 1)
{
this->SetError("called with incorrect number of arguments");
return false;
}
// sleep for specified seconds
unsigned int time1 = atoi(args[0].c_str());
if(args.size() == 1 )
{
cmCTestScriptHandler::SleepInSeconds(time1);
// update the elapsed time since it could have slept for a while
m_CTestScriptHandler->UpdateElapsedTime();
return true;
}
// sleep up to a duration
if(args.size() == 3 )
{
unsigned int duration = atoi(args[1].c_str());
unsigned int time2 = atoi(args[2].c_str());
if (time1 + duration > time2)
{
duration = (time1 + duration - time2);
cmCTestScriptHandler::SleepInSeconds(duration);
// update the elapsed time since it could have slept for a while
m_CTestScriptHandler->UpdateElapsedTime();
}
return true;
}
this->SetError("called with incorrect number of arguments");
return false;
}

View File

@ -0,0 +1,82 @@
/*=========================================================================
Program: CMake - Cross-Platform Makefile Generator
Module: $RCSfile$
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#ifndef cmCTestSleepCommand_h
#define cmCTestSleepCommand_h
#include "cmCTestCommand.h"
/** \class cmCTestSleep
* \brief Run a ctest script
*
* cmLibrarysCommand defines a list of executable (i.e., test)
* programs to create.
*/
class cmCTestSleepCommand : public cmCTestCommand
{
public:
cmCTestSleepCommand() {}
/**
* This is a virtual constructor for the command.
*/
virtual cmCommand* Clone()
{
cmCTestSleepCommand* ni = new cmCTestSleepCommand;
ni->m_CTest = this->m_CTest;
ni->m_CTestScriptHandler = this->m_CTestScriptHandler;
return ni;
}
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
*/
virtual bool InitialPass(std::vector<std::string> const& args);
/**
* The name of the command as specified in CMakeList.txt.
*/
virtual const char* GetName() { return "CTEST_SLEEP";}
/**
* Succinct documentation.
*/
virtual const char* GetTerseDocumentation()
{
return "sleeps for some amount of time";
}
/**
* More documentation.
*/
virtual const char* GetFullDocumentation()
{
return
" CTEST_SLEEP( seconds )\n"
" CTEST_SLEEP( time1 duration time2 )\n"
"With one argument it will sleep for a given number of seconds. "
"With three arguments it will wait for time2 - time1 - duration "
"seconds.";
}
cmTypeMacro(cmCTestSleepCommand, cmCTestCommand);
};
#endif