Parcourir la source

ENH: added support for -SP scripts in new processes

Ken Martin il y a 20 ans
Parent
commit
d81ebf0c23

+ 9 - 3
Source/CTest/cmCTestRunScriptCommand.cxx

@@ -27,11 +27,17 @@ bool cmCTestRunScriptCommand::InitialPass(
     return true;
     }
 
+  bool np = false;
+  unsigned int i = 0;
+  if (args[i] == "NEW_PROCESS")
+    {
+    np = true;
+    i++;
+    }
   // run each script
-  unsigned int i;
-  for (i = 0; i < args.size(); ++i)
+  for (; i < args.size(); ++i)
     {
-    cmCTestScriptHandler::RunScript(this->CTest, args[i].c_str());
+    cmCTestScriptHandler::RunScript(this->CTest, args[i].c_str(), !np);
     }
   return true;
 }

+ 3 - 2
Source/CTest/cmCTestRunScriptCommand.h

@@ -67,11 +67,12 @@ public:
   virtual const char* GetFullDocumentation()
     {
     return
-      "  CTEST_RUN_SCRIPT(script_file_name script_file_name1 \n"
+      "  CTEST_RUN_SCRIPT([NEW_PROCESS] 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.";
+      "the current settings of the variables. If NEW_PROCESS is specified "
+      "then each script will be run in a seperate process.";
     }
 
   cmTypeMacro(cmCTestRunScriptCommand, cmCTestCommand);

+ 88 - 13
Source/CTest/cmCTestScriptHandler.cxx

@@ -167,9 +167,10 @@ cmCTestScriptHandler::~cmCTestScriptHandler()
 
 //----------------------------------------------------------------------
 // just adds an argument to the vector
-void cmCTestScriptHandler::AddConfigurationScript(const char *script)
+void cmCTestScriptHandler::AddConfigurationScript(const char *script, bool pscope)
 {
   this->ConfigurationScripts.push_back(script);
+  this->ScriptProcessScope.push_back(pscope);
 }
 
 
@@ -179,14 +180,12 @@ void cmCTestScriptHandler::AddConfigurationScript(const char *script)
 int cmCTestScriptHandler::ProcessHandler()
 {
   int res = 0;
-  std::vector<cmStdString>::iterator it;
-  for ( it = this->ConfigurationScripts.begin();
-        it != this->ConfigurationScripts.end();
-        it ++ )
+  for (size_t i=0; i <  this->ConfigurationScripts.size(); ++i)
     {
     // for each script run it
-    res += this->RunConfigurationScript(
-      cmSystemTools::CollapseFullPath(it->c_str()));
+    res += this->RunConfigurationScript
+      (cmSystemTools::CollapseFullPath(this->ConfigurationScripts[i].c_str()),
+       this->ScriptProcessScope[i]);
     }
   if ( res )
     {
@@ -218,8 +217,73 @@ void cmCTestScriptHandler::AddCTestCommand(cmCTestCommand* command)
   this->CMake->AddCommand(newCom);
 }
 
+int cmCTestScriptHandler::ExecuteScript(const std::string& total_script_arg)
+{
+  // execute the script passing in the arguments to the script as well as the
+  // arguments from this invocation of cmake
+  std::vector<const char*> argv;
+  argv.push_back(this->CTest->GetCTestExecutable());
+  argv.push_back("-SR");
+  argv.push_back(total_script_arg.c_str());
+
+  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, 
+             "Executable for CTest is: " << 
+             this->CTest->GetCTestExecutable() << "\n");
+
+  // now pass through all the other arguments
+  std::vector<cmStdString> &initArgs = 
+    this->CTest->GetInitialCommandLineArguments();
+  for(size_t i=1; i < initArgs.size(); ++i)
+    {
+    argv.push_back(initArgs[i].c_str());
+    }
+  argv.push_back(0);
+
+  // Now create process object
+  cmsysProcess* cp = cmsysProcess_New();
+  cmsysProcess_SetCommand(cp, &*argv.begin());
+  //cmsysProcess_SetWorkingDirectory(cp, dir);
+  cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+  //cmsysProcess_SetTimeout(cp, timeout);
+  cmsysProcess_Execute(cp);
+
+  std::vector<char> out;
+  std::vector<char> err;
+  std::string line;
+  int pipe = cmSystemTools::WaitForLine(cp, line, 100.0, out, err);
+  while(pipe != cmsysProcess_Pipe_None)
+    {
+    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Output: " << line << "\n");
+    if(pipe == cmsysProcess_Pipe_STDERR)
+      {
+      cmCTestLog(this->CTest, ERROR_MESSAGE, line << "\n");
+      }
+    else if(pipe == cmsysProcess_Pipe_STDOUT)
+      {
+      cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, line << "\n");
+      }
+    pipe = cmSystemTools::WaitForLine(cp, line, 100, out, err);
+    }
+  
+  // Properly handle output of the build command
+  cmsysProcess_WaitForExit(cp, 0);
+  int result = cmsysProcess_GetState(cp);
+
+  int retVal = 0;
+  if(result == cmsysProcess_State_Exited)
+    {
+    retVal = cmsysProcess_GetExitValue(cp);
+    }
+  else
+    {
+    abort();
+    }
+  return retVal;
+}
+
+
 //----------------------------------------------------------------------
-// this sets up some variables for thew script to use, creates the required
+// this sets up some variables for the script to use, creates the required
 // cmake instance and generators, and then reads in the script
 int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg)
 {
@@ -426,8 +490,8 @@ void cmCTestScriptHandler::SleepInSeconds(unsigned int secondsToWait)
 
 //----------------------------------------------------------------------
 // run a specific script
-int cmCTestScriptHandler::RunConfigurationScript(
-  const std::string& total_script_arg)
+int cmCTestScriptHandler::RunConfigurationScript
+(const std::string& total_script_arg, bool pscope)
 {
   int result;
 
@@ -435,7 +499,18 @@ int cmCTestScriptHandler::RunConfigurationScript(
     cmSystemTools::GetTime();
 
   // read in the script
-  result = this->ReadInScript(total_script_arg);
+  if (pscope)
+    {
+    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+      "Reading Script: " << total_script_arg << std::endl);
+    result = this->ReadInScript(total_script_arg);
+    }
+  else
+    {
+    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+      "Executing Script: " << total_script_arg << std::endl);
+    result = this->ExecuteScript(total_script_arg);
+    }
   if (result)
     {
     return result;
@@ -847,11 +922,11 @@ void cmCTestScriptHandler::RestoreBackupDirectories()
     }
 }
 
-bool cmCTestScriptHandler::RunScript(cmCTest* ctest, const char *sname)
+bool cmCTestScriptHandler::RunScript(cmCTest* ctest, const char *sname, bool InProcess)
 {
   cmCTestScriptHandler* sh = new cmCTestScriptHandler();
   sh->SetCTestInstance(ctest);
-  sh->AddConfigurationScript(sname);
+  sh->AddConfigurationScript(sname,InProcess);
   sh->ProcessHandler();
   delete sh;
   return true;

+ 7 - 4
Source/CTest/cmCTestScriptHandler.h

@@ -69,9 +69,9 @@ public:
   cmTypeMacro(cmCTestScriptHandler, cmCTestGenericHandler);
 
   /**
-   * Add a script to run
+   * Add a script to run, and if is should run in the current process
    */
-  void AddConfigurationScript(const char *);
+  void AddConfigurationScript(const char *, bool pscope);
 
   /**
    * Run a dashboard using a specified confiuration script
@@ -81,7 +81,7 @@ public:
   /*
    * Run a script
    */
-  static bool RunScript(cmCTest* ctest, const char *script);
+  static bool RunScript(cmCTest* ctest, const char *script, bool InProcess);
   int RunCurrentScript();
 
   /*
@@ -99,9 +99,11 @@ public:
   ~cmCTestScriptHandler();
 
   void Initialize();
+
 private:
   // reads in a script
   int ReadInScript(const std::string& total_script_arg);
+  int ExecuteScript(const std::string& total_script_arg);
 
   // extract vars from the script to set ivars
   int ExtractVariables();
@@ -116,13 +118,14 @@ private:
   int BackupDirectories();
   void RestoreBackupDirectories();
 
-  int RunConfigurationScript(const std::string& script);
+  int RunConfigurationScript(const std::string& script, bool pscope);
   int RunConfigurationDashboard();
 
   // Add ctest command
   void AddCTestCommand(cmCTestCommand* command);
 
   std::vector<cmStdString> ConfigurationScripts;
+  std::vector<bool> ScriptProcessScope;
 
   bool Backup;
   bool EmptyBinDir;

+ 35 - 1
Source/cmCTest.cxx

@@ -1302,6 +1302,13 @@ int cmCTest::Run(std::vector<std::string>const& args, std::string* output)
   const char* ctestExec = "ctest";
   bool cmakeAndTest = false;
   bool performSomeTest = true;
+  bool SRArgumentSpecified = false;
+
+  // copy the command line
+  for(size_t i=0; i < args.size(); ++i)
+    {
+    this->InitialCommandLineArguments.push_back(args[i]);
+    }
   for(size_t i=1; i < args.size(); ++i)
     {
     std::string arg = args[i];
@@ -1347,13 +1354,40 @@ int cmCTest::Run(std::vector<std::string>const& args, std::string* output)
       this->ShowOnly = true;
       }
 
+    if(this->CheckArgument(arg, "-SP", "--script-new-process") && i < args.size() - 1 )
+      {
+      this->RunConfigurationScript = true;
+      i++;
+      cmCTestScriptHandler* ch
+        = static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
+      // -SR is an internal argument, -SP should be ignored when it is passed
+      if (!SRArgumentSpecified)
+        {
+        ch->AddConfigurationScript(args[i].c_str(),false);
+        }
+      }
+
+    if(this->CheckArgument(arg, "-SR", "--script-run") && i < args.size() - 1 )
+      {
+      SRArgumentSpecified = true;
+      this->RunConfigurationScript = true;
+      i++;
+      cmCTestScriptHandler* ch
+        = static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
+      ch->AddConfigurationScript(args[i].c_str(),true);
+      }
+
     if(this->CheckArgument(arg, "-S", "--script") && i < args.size() - 1 )
       {
       this->RunConfigurationScript = true;
       i++;
       cmCTestScriptHandler* ch
         = static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
-      ch->AddConfigurationScript(args[i].c_str());
+      // -SR is an internal argument, -S should be ignored when it is passed
+      if (!SRArgumentSpecified)
+        {
+        ch->AddConfigurationScript(args[i].c_str(),true);
+        }
       }
 
     if(this->CheckArgument(arg, "-O", "--output-log") && i < args.size() - 1 )

+ 5 - 1
Source/cmCTest.h

@@ -293,6 +293,9 @@ public:
   //! Read the custom configuration files and apply them to the current ctest
   int ReadCustomConfigurationFileTree(const char* dir);
 
+  std::vector<cmStdString> &GetInitialCommandLineArguments() 
+  { return this->InitialCommandLineArguments; };
+
 private:
   std::string ConfigType;
   bool Verbose;
@@ -383,7 +386,8 @@ private:
   int  DartVersion;
 
   std::set<cmStdString> SubmitFiles;
-
+  std::vector<cmStdString> InitialCommandLineArguments;
+  
   int SubmitIndex;
 
   cmGeneratedFileStream* OutputLogFile;

+ 1 - 1
Source/cmForEachCommand.cxx

@@ -42,7 +42,7 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf)
       this->Executing = true;
       std::vector<std::string>::const_iterator j = this->Args.begin();
       ++j;
-      
+
       std::string tmps;
       cmListFileArgument arg;
       for( ; j != this->Args.end(); ++j)

+ 103 - 1
Source/cmSystemTools.cxx

@@ -21,7 +21,6 @@
 
 #include <cmsys/RegularExpression.hxx>
 #include <cmsys/Directory.hxx>
-#include <cmsys/Process.h>
 
 // support for realpath call
 #ifndef _WIN32
@@ -1671,3 +1670,106 @@ bool cmSystemTools::ListTar(const char* outFileName,
   return false;
 #endif
 }
+
+int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
+                               double timeout,
+                               std::vector<char>& out,
+                               std::vector<char>& err)
+{
+  line = "";
+  std::vector<char>::iterator outiter = out.begin();
+  std::vector<char>::iterator erriter = err.begin();
+  while(1)
+    {
+    // Check for a newline in stdout.
+    for(;outiter != out.end(); ++outiter)
+      {
+      if((*outiter == '\r') && ((outiter+1) == out.end()))
+        {
+        break;
+        }
+      else if(*outiter == '\n' || *outiter == '\0')
+        {
+        int length = outiter-out.begin();
+        if(length > 1 && *(outiter-1) == '\r')
+          {
+          --length;
+          }
+        if(length > 0)
+          {
+          line.append(&out[0], length);
+          }
+        out.erase(out.begin(), outiter+1);
+        return cmsysProcess_Pipe_STDOUT;
+        }
+      }
+
+    // Check for a newline in stderr.
+    for(;erriter != err.end(); ++erriter)
+      {
+      if((*erriter == '\r') && ((erriter+1) == err.end()))
+        {
+        break;
+        }
+      else if(*erriter == '\n' || *erriter == '\0')
+        {
+        int length = erriter-err.begin();
+        if(length > 1 && *(erriter-1) == '\r')
+          {
+          --length;
+          }
+        if(length > 0)
+          {
+          line.append(&err[0], length);
+          }
+        err.erase(err.begin(), erriter+1);
+        return cmsysProcess_Pipe_STDERR;
+        }
+      }
+
+    // No newlines found.  Wait for more data from the process.
+    int length;
+    char* data;
+    int pipe = cmsysProcess_WaitForData(process, &data, &length, &timeout);
+    if(pipe == cmsysProcess_Pipe_Timeout)
+      {
+      // Timeout has been exceeded.
+      return pipe;
+      }
+    else if(pipe == cmsysProcess_Pipe_STDOUT)
+      {
+      // Append to the stdout buffer.
+      std::vector<char>::size_type size = out.size();
+      out.insert(out.end(), data, data+length);
+      outiter = out.begin()+size;
+      }
+    else if(pipe == cmsysProcess_Pipe_STDERR)
+      {
+      // Append to the stderr buffer.
+      std::vector<char>::size_type size = err.size();
+      err.insert(err.end(), data, data+length);
+      erriter = err.begin()+size;
+      }
+    else if(pipe == cmsysProcess_Pipe_None)
+      {
+      // Both stdout and stderr pipes have broken.  Return leftover data.
+      if(!out.empty())
+        {
+        line.append(&out[0], outiter-out.begin());
+        out.erase(out.begin(), out.end());
+        return cmsysProcess_Pipe_STDOUT;
+        }
+      else if(!err.empty())
+        {
+        line.append(&err[0], erriter-err.begin());
+        err.erase(err.begin(), err.end());
+        return cmsysProcess_Pipe_STDERR;
+        }
+      else
+        {
+        return cmsysProcess_Pipe_None;
+        }
+      }
+    }
+}
+

+ 9 - 0
Source/cmSystemTools.h

@@ -20,6 +20,9 @@
 #include "cmStandardIncludes.h"
 
 #include <cmsys/SystemTools.hxx>
+#include <cmsys/Process.h>
+
+
 
 /** \class cmSystemTools
  * \brief A collection of useful functions for CMake.
@@ -257,6 +260,12 @@ public:
    */
   static void ReportLastSystemError(const char* m);
   
+  /** a general output handler for cmsysProcess  */
+  static int WaitForLine(cmsysProcess* process, std::string& line,
+                         double timeout,
+                         std::vector<char>& out,
+                         std::vector<char>& err);
+    
   /** Split a string on its newlines into multiple lines.  Returns
       false only if the last line stored had no newline.  */
   static bool Split(const char* s, std::vector<cmStdString>& l);  

+ 2 - 104
Source/cmakexbuild.cxx

@@ -8,108 +8,6 @@
 // error, and re-runs xcodebuild until that error does
 // not show up.
 
-int WaitForLine(cmsysProcess* process, std::string& line,
-                double timeout,
-                std::vector<char>& out,
-                std::vector<char>& err)
-{
-  line = "";
-  std::vector<char>::iterator outiter = out.begin();
-  std::vector<char>::iterator erriter = err.begin();
-  while(1)
-    {
-    // Check for a newline in stdout.
-    for(;outiter != out.end(); ++outiter)
-      {
-      if((*outiter == '\r') && ((outiter+1) == out.end()))
-        {
-        break;
-        }
-      else if(*outiter == '\n' || *outiter == '\0')
-        {
-        int length = outiter-out.begin();
-        if(length > 1 && *(outiter-1) == '\r')
-          {
-          --length;
-          }
-        if(length > 0)
-          {
-          line.append(&out[0], length);
-          }
-        out.erase(out.begin(), outiter+1);
-        return cmsysProcess_Pipe_STDOUT;
-        }
-      }
-
-    // Check for a newline in stderr.
-    for(;erriter != err.end(); ++erriter)
-      {
-      if((*erriter == '\r') && ((erriter+1) == err.end()))
-        {
-        break;
-        }
-      else if(*erriter == '\n' || *erriter == '\0')
-        {
-        int length = erriter-err.begin();
-        if(length > 1 && *(erriter-1) == '\r')
-          {
-          --length;
-          }
-        if(length > 0)
-          {
-          line.append(&err[0], length);
-          }
-        err.erase(err.begin(), erriter+1);
-        return cmsysProcess_Pipe_STDERR;
-        }
-      }
-
-    // No newlines found.  Wait for more data from the process.
-    int length;
-    char* data;
-    int pipe = cmsysProcess_WaitForData(process, &data, &length, &timeout);
-    if(pipe == cmsysProcess_Pipe_Timeout)
-      {
-      // Timeout has been exceeded.
-      return pipe;
-      }
-    else if(pipe == cmsysProcess_Pipe_STDOUT)
-      {
-      // Append to the stdout buffer.
-      std::vector<char>::size_type size = out.size();
-      out.insert(out.end(), data, data+length);
-      outiter = out.begin()+size;
-      }
-    else if(pipe == cmsysProcess_Pipe_STDERR)
-      {
-      // Append to the stderr buffer.
-      std::vector<char>::size_type size = err.size();
-      err.insert(err.end(), data, data+length);
-      erriter = err.begin()+size;
-      }
-    else if(pipe == cmsysProcess_Pipe_None)
-      {
-      // Both stdout and stderr pipes have broken.  Return leftover data.
-      if(!out.empty())
-        {
-        line.append(&out[0], outiter-out.begin());
-        out.erase(out.begin(), out.end());
-        return cmsysProcess_Pipe_STDOUT;
-        }
-      else if(!err.empty())
-        {
-        line.append(&err[0], erriter-err.begin());
-        err.erase(err.begin(), err.end());
-        return cmsysProcess_Pipe_STDERR;
-        }
-      else
-        {
-        return cmsysProcess_Pipe_None;
-        }
-      }
-    }
-}
-
 int RunXCode(std::vector<const char*>& argv, bool& hitbug)
 {
   hitbug = false;
@@ -120,7 +18,7 @@ int RunXCode(std::vector<const char*>& argv, bool& hitbug)
   std::vector<char> out;
   std::vector<char> err;
   std::string line;
-  int pipe =WaitForLine(cp, line, 100.0, out, err);
+  int pipe = cmSystemTools::WaitForLine(cp, line, 100.0, out, err);
   while(pipe != cmsysProcess_Pipe_None)
     {
     if(line.find("/bin/sh: bad interpreter: Text file busy") 
@@ -144,7 +42,7 @@ int RunXCode(std::vector<const char*>& argv, bool& hitbug)
         std::cout << line << "\n";
         }
       }
-    pipe =WaitForLine(cp, line, 100, out, err);
+    pipe = cmSystemTools::WaitForLine(cp, line, 100, out, err);
     }
   cmsysProcess_WaitForExit(cp, 0);
   if(cmsysProcess_GetState(cp) == cmsysProcess_State_Exited)

+ 6 - 0
Source/ctest.cxx

@@ -103,6 +103,12 @@ static const cmDocumentationEntry cmDocumentationOptions[] =
    "ctest will do what is required to create and run a dashboard. This "
    "option basically sets up a dashboard and then runs ctest -D with the "
    "appropriate options."},
+  {"-SP <script>, --script-new-process <script>", "Execute a dashboard for a "
+   "configuration",
+   "This option does the same operations as -S but it will do them in a "
+   "seperate process. This is primarily useful in cases where the script "
+   "may modify the environment and you do not want the modified enviroment "
+   "to impact other -S scripts."},
   {"-A <file>, --add-notes <file>", "Add a notes file with submission",
    "This option tells ctest to include a notes file when submitting "
    "dashboard. "},