diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 982b9649f..68fbfbb47 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -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) diff --git a/Source/CTest/cmCTestCommand.h b/Source/CTest/cmCTestCommand.h new file mode 100644 index 000000000..9d4b7a86e --- /dev/null +++ b/Source/CTest/cmCTestCommand.h @@ -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 diff --git a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx new file mode 100644 index 000000000..90d88ce4f --- /dev/null +++ b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx @@ -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 const& args) +{ + if(args.size() != 1 ) + { + this->SetError("called with incorrect number of arguments"); + return false; + } + + cmCTestScriptHandler::EmptyBinaryDirectory(args[0].c_str()); + + return true; +} + + diff --git a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h new file mode 100644 index 000000000..d8ac1c030 --- /dev/null +++ b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h @@ -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 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 diff --git a/Source/CTest/cmCTestRunScriptCommand.cxx b/Source/CTest/cmCTestRunScriptCommand.cxx new file mode 100644 index 000000000..53ce3d402 --- /dev/null +++ b/Source/CTest/cmCTestRunScriptCommand.cxx @@ -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 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; +} + + diff --git a/Source/CTest/cmCTestRunScriptCommand.h b/Source/CTest/cmCTestRunScriptCommand.h new file mode 100644 index 000000000..9bf1f3b27 --- /dev/null +++ b/Source/CTest/cmCTestRunScriptCommand.h @@ -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 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 diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx index 7f0c2ebf9..f34b45b9a 100644 --- a/Source/CTest/cmCTestScriptHandler.cxx +++ b/Source/CTest/cmCTestScriptHandler.cxx @@ -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 #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(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(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; +} diff --git a/Source/CTest/cmCTestScriptHandler.h b/Source/CTest/cmCTestScriptHandler.h index dc27e1f22..7b9635074 100644 --- a/Source/CTest/cmCTestScriptHandler.h +++ b/Source/CTest/cmCTestScriptHandler.h @@ -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; diff --git a/Source/CTest/cmCTestSleepCommand.cxx b/Source/CTest/cmCTestSleepCommand.cxx new file mode 100644 index 000000000..ec585f1a3 --- /dev/null +++ b/Source/CTest/cmCTestSleepCommand.cxx @@ -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 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; +} + + diff --git a/Source/CTest/cmCTestSleepCommand.h b/Source/CTest/cmCTestSleepCommand.h new file mode 100644 index 000000000..f119a43af --- /dev/null +++ b/Source/CTest/cmCTestSleepCommand.h @@ -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 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