1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc.
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
8 This software is distributed WITHOUT ANY WARRANTY; without even the
9 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License for more information.
11 ============================================================================*/
12 #include "cmCTestSubmitHandler.h"
14 #include "cmSystemTools.h"
15 #include "cmVersion.h"
16 #include "cmGeneratedFileStream.h"
18 #include "cmXMLParser.h"
20 #include <cmsys/Process.h>
21 #include <cmsys/Base64.h>
23 // For XML-RPC submission
24 #include "cm_xmlrpc.h"
26 // For curl submission
31 #define SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT 120
33 typedef std::vector<char> cmCTestSubmitHandlerVectorOfChar;
35 //----------------------------------------------------------------------------
36 class cmCTestSubmitHandler::ResponseParser: public cmXMLParser
39 ResponseParser() { this->Status = STATUS_OK; }
52 std::string CDashVersion;
59 std::vector<char> CurrentValue;
61 std::string GetCurrentValue()
64 if(this->CurrentValue.size())
66 val.assign(&this->CurrentValue[0], this->CurrentValue.size());
71 virtual void StartElement(const char* name, const char** atts)
73 this->CurrentValue.clear();
74 if(strcmp(name, "cdash") == 0)
76 this->CDashVersion = this->FindAttribute(atts, "version");
80 virtual void CharacterDataHandler(const char* data, int length)
82 this->CurrentValue.insert(this->CurrentValue.end(), data, data+length);
85 virtual void EndElement(const char* name)
87 if(strcmp(name, "status") == 0)
89 std::string status = cmSystemTools::UpperCase(this->GetCurrentValue());
90 if(status == "OK" || status == "SUCCESS")
92 this->Status = STATUS_OK;
94 else if(status == "WARNING")
96 this->Status = STATUS_WARNING;
100 this->Status = STATUS_ERROR;
103 else if(strcmp(name, "filename") == 0)
105 this->Filename = this->GetCurrentValue();
107 else if(strcmp(name, "md5") == 0)
109 this->MD5 = this->GetCurrentValue();
111 else if(strcmp(name, "message") == 0)
113 this->Message = this->GetCurrentValue();
120 cmCTestSubmitHandlerWriteMemoryCallback(void *ptr, size_t size, size_t nmemb,
123 register int realsize = (int)(size * nmemb);
125 cmCTestSubmitHandlerVectorOfChar *vec
126 = static_cast<cmCTestSubmitHandlerVectorOfChar*>(data);
127 const char* chPtr = static_cast<char*>(ptr);
128 vec->insert(vec->end(), chPtr, chPtr + realsize);
134 cmCTestSubmitHandlerCurlDebugCallback(CURL *, curl_infotype, char *chPtr,
135 size_t size, void *data)
137 cmCTestSubmitHandlerVectorOfChar *vec
138 = static_cast<cmCTestSubmitHandlerVectorOfChar*>(data);
139 vec->insert(vec->end(), chPtr, chPtr + size);
144 //----------------------------------------------------------------------------
145 cmCTestSubmitHandler::cmCTestSubmitHandler() : HTTPProxy(), FTPProxy()
150 //----------------------------------------------------------------------------
151 void cmCTestSubmitHandler::Initialize()
153 // We submit all available parts by default.
154 for(cmCTest::Part p = cmCTest::PartStart;
155 p != cmCTest::PartCount; p = cmCTest::Part(p+1))
157 this->SubmitPart[p] = true;
160 this->HasWarnings = false;
161 this->HasErrors = false;
162 this->Superclass::Initialize();
163 this->HTTPProxy = "";
164 this->HTTPProxyType = 0;
165 this->HTTPProxyAuth = "";
167 this->FTPProxyType = 0;
172 //----------------------------------------------------------------------------
173 bool cmCTestSubmitHandler::SubmitUsingFTP(const cmStdString& localprefix,
174 const std::set<cmStdString>& files,
175 const cmStdString& remoteprefix,
176 const cmStdString& url)
181 char error_buffer[1024];
183 /* In windows, this will init the winsock stuff */
184 ::curl_global_init(CURL_GLOBAL_ALL);
186 cmCTest::SetOfStrings::const_iterator file;
187 for ( file = files.begin(); file != files.end(); ++file )
189 /* get a curl handle */
190 curl = curl_easy_init();
194 if ( this->FTPProxyType > 0 )
196 curl_easy_setopt(curl, CURLOPT_PROXY, this->FTPProxy.c_str());
197 switch (this->FTPProxyType)
200 curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
203 curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
206 curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
211 ::curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
213 // if there is little to no activity for too long stop submitting
214 ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1);
215 ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME,
216 SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT);
218 ::curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
220 cmStdString local_file = *file;
221 if ( !cmSystemTools::FileExists(local_file.c_str()) )
223 local_file = localprefix + "/" + *file;
225 cmStdString upload_as
226 = url + "/" + remoteprefix + cmSystemTools::GetFilenameName(*file);
229 if ( ::stat(local_file.c_str(), &st) )
231 cmCTestLog(this->CTest, ERROR_MESSAGE, " Cannot find file: "
232 << local_file.c_str() << std::endl);
233 ::curl_easy_cleanup(curl);
234 ::curl_global_cleanup();
238 ftpfile = ::fopen(local_file.c_str(), "rb");
239 *this->LogFile << "\tUpload file: " << local_file.c_str() << " to "
240 << upload_as.c_str() << std::endl;
241 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Upload file: "
242 << local_file.c_str() << " to "
243 << upload_as.c_str() << std::endl);
245 ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
248 ::curl_easy_setopt(curl,CURLOPT_URL, upload_as.c_str());
250 // now specify which file to upload
251 ::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
253 // and give the size of the upload (optional)
254 ::curl_easy_setopt(curl, CURLOPT_INFILESIZE,
255 static_cast<long>(st.st_size));
257 // and give curl the buffer for errors
258 ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer);
260 // specify handler for output
261 ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
262 cmCTestSubmitHandlerWriteMemoryCallback);
263 ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
264 cmCTestSubmitHandlerCurlDebugCallback);
266 /* we pass our 'chunk' struct to the callback function */
267 cmCTestSubmitHandlerVectorOfChar chunk;
268 cmCTestSubmitHandlerVectorOfChar chunkDebug;
269 ::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&chunk);
270 ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
272 // Now run off and do what you've been told!
273 res = ::curl_easy_perform(curl);
275 if ( chunk.size() > 0 )
277 cmCTestLog(this->CTest, DEBUG, "CURL output: ["
278 << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
281 if ( chunkDebug.size() > 0 )
283 cmCTestLog(this->CTest, DEBUG, "CURL debug output: ["
284 << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]"
291 cmCTestLog(this->CTest, ERROR_MESSAGE,
292 " Error when uploading file: "
293 << local_file.c_str() << std::endl);
294 cmCTestLog(this->CTest, ERROR_MESSAGE, " Error message was: "
295 << error_buffer << std::endl);
296 *this->LogFile << " Error when uploading file: "
297 << local_file.c_str()
299 << " Error message was: "
300 << error_buffer << std::endl
301 << " Curl output was: ";
302 // avoid dereference of empty vector
305 *this->LogFile << cmCTestLogWrite(&*chunk.begin(), chunk.size());
306 cmCTestLog(this->CTest, ERROR_MESSAGE, "CURL output: ["
307 << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
310 *this->LogFile << std::endl;
311 ::curl_easy_cleanup(curl);
312 ::curl_global_cleanup();
316 ::curl_easy_cleanup(curl);
317 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Uploaded: " + local_file
321 ::curl_global_cleanup();
325 //----------------------------------------------------------------------------
326 // Uploading files is simpler
327 bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix,
328 const std::set<cmStdString>& files,
329 const cmStdString& remoteprefix,
330 const cmStdString& url)
335 char error_buffer[1024];
337 /* In windows, this will init the winsock stuff */
338 ::curl_global_init(CURL_GLOBAL_ALL);
339 cmStdString dropMethod(this->CTest->GetCTestConfiguration("DropMethod"));
340 cmStdString curlopt(this->CTest->GetCTestConfiguration("CurlOptions"));
341 std::vector<std::string> args;
342 cmSystemTools::ExpandListArgument(curlopt.c_str(), args);
343 bool verifyPeerOff = false;
344 bool verifyHostOff = false;
345 for( std::vector<std::string>::iterator i = args.begin();
346 i != args.end(); ++i)
348 if(*i == "CURLOPT_SSL_VERIFYPEER_OFF")
350 verifyPeerOff = true;
352 if(*i == "CURLOPT_SSL_VERIFYHOST_OFF")
354 verifyHostOff = true;
357 cmStdString::size_type kk;
358 cmCTest::SetOfStrings::const_iterator file;
359 for ( file = files.begin(); file != files.end(); ++file )
361 /* get a curl handle */
362 curl = curl_easy_init();
367 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
368 " Set CURLOPT_SSL_VERIFYPEER to off\n");
369 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
373 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
374 " Set CURLOPT_SSL_VERIFYHOST to off\n");
375 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
379 if ( this->HTTPProxyType > 0 )
381 curl_easy_setopt(curl, CURLOPT_PROXY, this->HTTPProxy.c_str());
382 switch (this->HTTPProxyType)
385 curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
388 curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
391 curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
392 if (this->HTTPProxyAuth.size() > 0)
394 curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD,
395 this->HTTPProxyAuth.c_str());
399 if(this->CTest->ShouldUseHTTP10())
401 curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
403 // enable HTTP ERROR parsing
404 curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
405 /* enable uploading */
406 curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
408 // if there is little to no activity for too long stop submitting
409 ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1);
410 ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME,
411 SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT);
413 /* HTTP PUT please */
414 ::curl_easy_setopt(curl, CURLOPT_PUT, 1);
415 ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
417 cmStdString local_file = *file;
418 if ( !cmSystemTools::FileExists(local_file.c_str()) )
420 local_file = localprefix + "/" + *file;
422 cmStdString remote_file
423 = remoteprefix + cmSystemTools::GetFilenameName(*file);
425 *this->LogFile << "\tUpload file: " << local_file.c_str() << " to "
426 << remote_file.c_str() << std::endl;
428 cmStdString ofile = "";
429 for ( kk = 0; kk < remote_file.size(); kk ++ )
431 char c = remote_file[kk];
432 char hexCh[4] = { 0, 0, 0, 0 };
444 sprintf(hexCh, "%%%02X", (int)c);
451 cmStdString upload_as
452 = url + ((url.find("?",0) == cmStdString::npos) ? "?" : "&")
453 + "FileName=" + ofile;
455 upload_as += "&MD5=";
457 if(cmSystemTools::IsOn(this->GetOption("InternalTest")))
459 upload_as += "bad_md5sum";
464 cmSystemTools::ComputeFileMD5(local_file.c_str(), md5);
470 if ( ::stat(local_file.c_str(), &st) )
472 cmCTestLog(this->CTest, ERROR_MESSAGE, " Cannot find file: "
473 << local_file.c_str() << std::endl);
474 ::curl_easy_cleanup(curl);
475 ::curl_global_cleanup();
479 ftpfile = ::fopen(local_file.c_str(), "rb");
480 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Upload file: "
481 << local_file.c_str() << " to "
482 << upload_as.c_str() << " Size: " << st.st_size << std::endl);
485 ::curl_easy_setopt(curl,CURLOPT_URL, upload_as.c_str());
487 // now specify which file to upload
488 ::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
490 // and give the size of the upload (optional)
491 ::curl_easy_setopt(curl, CURLOPT_INFILESIZE,
492 static_cast<long>(st.st_size));
494 // and give curl the buffer for errors
495 ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer);
497 // specify handler for output
498 ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
499 cmCTestSubmitHandlerWriteMemoryCallback);
500 ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
501 cmCTestSubmitHandlerCurlDebugCallback);
503 /* we pass our 'chunk' struct to the callback function */
504 cmCTestSubmitHandlerVectorOfChar chunk;
505 cmCTestSubmitHandlerVectorOfChar chunkDebug;
506 ::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&chunk);
507 ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
509 // Now run off and do what you've been told!
510 res = ::curl_easy_perform(curl);
512 if(cmSystemTools::IsOn(this->GetOption("InternalTest")) &&
513 cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
514 this->CTest->GetCDashVersion().c_str(), "1.7"))
516 // mock failure output for internal test case
517 std::string mock_output = "<cdash version=\"1.7.0\">\n"
518 " <status>ERROR</status>\n"
519 " <message>Checksum failed for file.</message>\n"
522 chunk.assign(mock_output.begin(), mock_output.end());
525 if ( chunk.size() > 0 )
527 cmCTestLog(this->CTest, DEBUG, "CURL output: ["
528 << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
530 this->ParseResponse(chunk);
532 if ( chunkDebug.size() > 0 )
534 cmCTestLog(this->CTest, DEBUG, "CURL debug output: ["
535 << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]"
539 // If curl failed for any reason, or checksum fails, wait and retry
541 if(res != CURLE_OK || this->HasErrors)
543 std::string retryDelay = this->GetOption("RetryDelay") == NULL ?
544 "" : this->GetOption("RetryDelay");
545 std::string retryCount = this->GetOption("RetryCount") == NULL ?
546 "" : this->GetOption("RetryCount");
548 int delay = retryDelay == "" ? atoi(this->CTest->GetCTestConfiguration(
549 "CTestSubmitRetryDelay").c_str()) : atoi(retryDelay.c_str());
550 int count = retryCount == "" ? atoi(this->CTest->GetCTestConfiguration(
551 "CTestSubmitRetryCount").c_str()) : atoi(retryCount.c_str());
553 for(int i = 0; i < count; i++)
555 cmCTestLog(this->CTest, HANDLER_OUTPUT,
556 " Submit failed, waiting " << delay << " seconds...\n");
558 double stop = cmSystemTools::GetTime() + delay;
559 while(cmSystemTools::GetTime() < stop)
561 cmSystemTools::Delay(100);
564 cmCTestLog(this->CTest, HANDLER_OUTPUT,
565 " Retry submission: Attempt " << (i + 1) << " of "
566 << count << std::endl);
569 ftpfile = ::fopen(local_file.c_str(), "rb");
570 ::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
574 this->HasErrors = false;
576 res = ::curl_easy_perform(curl);
578 if ( chunk.size() > 0 )
580 cmCTestLog(this->CTest, DEBUG, "CURL output: ["
581 << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
583 this->ParseResponse(chunk);
586 if(res == CURLE_OK && !this->HasErrors)
596 cmCTestLog(this->CTest, ERROR_MESSAGE,
597 " Error when uploading file: "
598 << local_file.c_str() << std::endl);
599 cmCTestLog(this->CTest, ERROR_MESSAGE, " Error message was: "
600 << error_buffer << std::endl);
601 *this->LogFile << " Error when uploading file: "
602 << local_file.c_str()
604 << " Error message was: " << error_buffer
606 // avoid deref of begin for zero size array
609 *this->LogFile << " Curl output was: "
610 << cmCTestLogWrite(&*chunk.begin(), chunk.size())
612 cmCTestLog(this->CTest, ERROR_MESSAGE, "CURL output: ["
613 << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
616 ::curl_easy_cleanup(curl);
617 ::curl_global_cleanup();
621 ::curl_easy_cleanup(curl);
622 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Uploaded: " + local_file
626 ::curl_global_cleanup();
630 //----------------------------------------------------------------------------
631 void cmCTestSubmitHandler
632 ::ParseResponse(cmCTestSubmitHandlerVectorOfChar chunk)
634 std::string output = "";
635 output.append(chunk.begin(), chunk.end());
637 if(output.find("<cdash") != output.npos)
639 ResponseParser parser;
640 parser.Parse(output.c_str());
642 if(parser.Status != ResponseParser::STATUS_OK)
644 this->HasErrors = true;
645 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submission failed: " <<
646 parser.Message << std::endl);
650 output = cmSystemTools::UpperCase(output);
651 if(output.find("WARNING") != std::string::npos)
653 this->HasWarnings = true;
655 if(output.find("ERROR") != std::string::npos)
657 this->HasErrors = true;
660 if(this->HasWarnings || this->HasErrors)
662 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Server Response:\n" <<
663 cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "\n");
667 //----------------------------------------------------------------------------
668 bool cmCTestSubmitHandler::TriggerUsingHTTP(
669 const std::set<cmStdString>& files,
670 const cmStdString& remoteprefix,
671 const cmStdString& url)
674 char error_buffer[1024];
675 /* In windows, this will init the winsock stuff */
676 ::curl_global_init(CURL_GLOBAL_ALL);
678 cmCTest::SetOfStrings::const_iterator file;
679 for ( file = files.begin(); file != files.end(); ++file )
681 /* get a curl handle */
682 curl = curl_easy_init();
686 if ( this->HTTPProxyType > 0 )
688 curl_easy_setopt(curl, CURLOPT_PROXY, this->HTTPProxy.c_str());
689 switch (this->HTTPProxyType)
692 curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
695 curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
698 curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
699 if (this->HTTPProxyAuth.size() > 0)
701 curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD,
702 this->HTTPProxyAuth.c_str());
707 ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
709 // and give curl the buffer for errors
710 ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer);
712 // specify handler for output
713 ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
714 cmCTestSubmitHandlerWriteMemoryCallback);
715 ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
716 cmCTestSubmitHandlerCurlDebugCallback);
718 /* we pass our 'chunk' struct to the callback function */
719 cmCTestSubmitHandlerVectorOfChar chunk;
720 cmCTestSubmitHandlerVectorOfChar chunkDebug;
721 ::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&chunk);
722 ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
725 = remoteprefix + cmSystemTools::GetFilenameName(*file);
726 cmStdString ofile = "";
727 cmStdString::iterator kk;
728 for ( kk = rfile.begin(); kk < rfile.end(); ++ kk)
731 char hexCh[4] = { 0, 0, 0, 0 };
743 sprintf(hexCh, "%%%02X", (int)c);
751 = url + ((url.find("?",0) == cmStdString::npos) ? "?" : "&")
752 + "xmlfile=" + ofile;
753 *this->LogFile << "Trigger url: " << turl.c_str() << std::endl;
754 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Trigger url: "
755 << turl.c_str() << std::endl);
756 curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
757 curl_easy_setopt(curl, CURLOPT_URL, turl.c_str());
758 if ( curl_easy_perform(curl) )
760 cmCTestLog(this->CTest, ERROR_MESSAGE, " Error when triggering: "
761 << turl.c_str() << std::endl);
762 cmCTestLog(this->CTest, ERROR_MESSAGE, " Error message was: "
763 << error_buffer << std::endl);
764 *this->LogFile << "\tTriggering failed with error: " << error_buffer
766 << " Error message was: " << error_buffer
771 << " Curl output was: "
772 << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << std::endl;
773 cmCTestLog(this->CTest, ERROR_MESSAGE, "CURL output: ["
774 << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
777 ::curl_easy_cleanup(curl);
778 ::curl_global_cleanup();
782 if ( chunk.size() > 0 )
784 cmCTestLog(this->CTest, DEBUG, "CURL output: ["
785 << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
788 if ( chunkDebug.size() > 0 )
790 cmCTestLog(this->CTest, DEBUG, "CURL debug output: ["
791 << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size())
792 << "]" << std::endl);
796 ::curl_easy_cleanup(curl);
797 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl);
800 ::curl_global_cleanup();
801 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Dart server triggered..."
806 //----------------------------------------------------------------------------
807 bool cmCTestSubmitHandler::SubmitUsingSCP(
808 const cmStdString& scp_command,
809 const cmStdString& localprefix,
810 const std::set<cmStdString>& files,
811 const cmStdString& remoteprefix,
812 const cmStdString& url)
814 if ( !scp_command.size() || !localprefix.size() ||
815 !files.size() || !remoteprefix.size() || !url.size() )
819 std::vector<const char*> argv;
820 argv.push_back(scp_command.c_str()); // Scp command
821 argv.push_back(scp_command.c_str()); // Dummy string for file
822 argv.push_back(scp_command.c_str()); // Dummy string for remote url
825 cmsysProcess* cp = cmsysProcess_New();
826 cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
827 //cmsysProcess_SetTimeout(cp, timeout);
831 cmCTest::SetOfStrings::const_iterator file;
832 for ( file = files.begin(); file != files.end(); ++file )
836 std::string lfname = localprefix;
837 cmSystemTools::ConvertToUnixSlashes(lfname);
838 lfname += "/" + *file;
839 lfname = cmSystemTools::ConvertToOutputPath(lfname.c_str());
840 argv[1] = lfname.c_str();
841 std::string rfname = url + "/" + remoteprefix + *file;
842 argv[2] = rfname.c_str();
843 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Execute \"" << argv[0]
844 << "\" \"" << argv[1] << "\" \""
845 << argv[2] << "\"" << std::endl);
846 *this->LogFile << "Execute \"" << argv[0] << "\" \"" << argv[1] << "\" \""
847 << argv[2] << "\"" << std::endl;
849 cmsysProcess_SetCommand(cp, &*argv.begin());
850 cmsysProcess_Execute(cp);
854 while(cmsysProcess_WaitForData(cp, &data, &length, 0))
856 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
857 cmCTestLogWrite(data, length));
860 cmsysProcess_WaitForExit(cp, 0);
862 int result = cmsysProcess_GetState(cp);
864 if(result == cmsysProcess_State_Exited)
866 retVal = cmsysProcess_GetExitValue(cp);
869 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "\tSCP returned: "
870 << retVal << std::endl);
871 *this->LogFile << "\tSCP returned: " << retVal << std::endl;
875 else if(result == cmsysProcess_State_Exception)
877 retVal = cmsysProcess_GetExitException(cp);
878 cmCTestLog(this->CTest, ERROR_MESSAGE, "\tThere was an exception: "
879 << retVal << std::endl);
880 *this->LogFile << "\tThere was an exception: " << retVal << std::endl;
883 else if(result == cmsysProcess_State_Expired)
885 cmCTestLog(this->CTest, ERROR_MESSAGE, "\tThere was a timeout"
887 *this->LogFile << "\tThere was a timeout" << std::endl;
890 else if(result == cmsysProcess_State_Error)
892 cmCTestLog(this->CTest, ERROR_MESSAGE, "\tError executing SCP: "
893 << cmsysProcess_GetErrorString(cp) << std::endl);
894 *this->LogFile << "\tError executing SCP: "
895 << cmsysProcess_GetErrorString(cp) << std::endl;
899 cmsysProcess_Delete(cp);
907 //----------------------------------------------------------------------------
908 bool cmCTestSubmitHandler::SubmitUsingCP(
909 const cmStdString& localprefix,
910 const std::set<cmStdString>& files,
911 const cmStdString& remoteprefix,
912 const cmStdString& destination)
914 if ( !localprefix.size() ||
915 !files.size() || !remoteprefix.size() || !destination.size() )
917 cmCTestLog(this->CTest, ERROR_MESSAGE,
918 "Missing arguments for submit via cp:\n"
919 << "\tlocalprefix: " << localprefix << "\n"
920 << "\tNumber of files: " << files.size() << "\n"
921 << "\tremoteprefix: " << remoteprefix << "\n"
922 << "\tdestination: " << destination << std::endl);
925 cmCTest::SetOfStrings::const_iterator file;
926 bool problems = false;
927 for ( file = files.begin(); file != files.end(); ++file )
929 std::string lfname = localprefix;
930 cmSystemTools::ConvertToUnixSlashes(lfname);
931 lfname += "/" + *file;
932 std::string rfname = destination + "/" + remoteprefix + *file;
933 cmSystemTools::CopyFileAlways(lfname.c_str(), rfname.c_str());
934 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Copy file: "
935 << lfname.c_str() << " to "
936 << rfname.c_str() << std::endl);
938 std::string tagDoneFile = destination + "/" + remoteprefix + "DONE";
939 cmSystemTools::Touch(tagDoneFile.c_str(), true);
948 //----------------------------------------------------------------------------
949 #if defined(CTEST_USE_XMLRPC)
950 bool cmCTestSubmitHandler::SubmitUsingXMLRPC(const cmStdString& localprefix,
951 const std::set<cmStdString>& files,
952 const cmStdString& remoteprefix,
953 const cmStdString& url)
956 char ctestString[] = "CTest";
957 std::string ctestVersionString = cmVersion::GetCMakeVersion();
958 char* ctestVersion = const_cast<char*>(ctestVersionString.c_str());
960 cmStdString realURL = url + "/" + remoteprefix + "/Command/";
962 /* Start up our XML-RPC client library. */
963 xmlrpc_client_init(XMLRPC_CLIENT_NO_FLAGS, ctestString, ctestVersion);
965 /* Initialize our error-handling environment. */
966 xmlrpc_env_init(&env);
968 /* Call the famous server at UserLand. */
969 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submitting to: "
970 << realURL.c_str() << " (" << remoteprefix.c_str() << ")" << std::endl);
971 cmCTest::SetOfStrings::const_iterator file;
972 for ( file = files.begin(); file != files.end(); ++file )
974 xmlrpc_value *result;
976 cmStdString local_file = *file;
977 if ( !cmSystemTools::FileExists(local_file.c_str()) )
979 local_file = localprefix + "/" + *file;
981 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submit file: "
982 << local_file.c_str() << std::endl);
984 if ( ::stat(local_file.c_str(), &st) )
986 cmCTestLog(this->CTest, ERROR_MESSAGE, " Cannot find file: "
987 << local_file.c_str() << std::endl);
991 // off_t can be bigger than size_t. fread takes size_t.
992 // make sure the file is not too big.
993 if(static_cast<off_t>(static_cast<size_t>(st.st_size)) !=
994 static_cast<off_t>(st.st_size))
996 cmCTestLog(this->CTest, ERROR_MESSAGE, " File too big: "
997 << local_file.c_str() << std::endl);
1000 size_t fileSize = static_cast<size_t>(st.st_size);
1001 FILE* fp = fopen(local_file.c_str(), "rb");
1004 cmCTestLog(this->CTest, ERROR_MESSAGE, " Cannot open file: "
1005 << local_file.c_str() << std::endl);
1009 unsigned char *fileBuffer = new unsigned char[fileSize];
1010 if ( fread(fileBuffer, 1, fileSize, fp) != fileSize )
1012 delete [] fileBuffer;
1014 cmCTestLog(this->CTest, ERROR_MESSAGE, " Cannot read file: "
1015 << local_file.c_str() << std::endl);
1020 char remoteCommand[] = "Submit.put";
1021 char* pRealURL = const_cast<char*>(realURL.c_str());
1022 result = xmlrpc_client_call(&env, pRealURL, remoteCommand,
1023 "(6)", fileBuffer, (xmlrpc_int32)fileSize );
1025 delete [] fileBuffer;
1027 if ( env.fault_occurred )
1029 cmCTestLog(this->CTest, ERROR_MESSAGE, " Submission problem: "
1030 << env.fault_string << " (" << env.fault_code << ")" << std::endl);
1031 xmlrpc_env_clean(&env);
1032 xmlrpc_client_cleanup();
1036 /* Dispose of our result value. */
1037 xmlrpc_DECREF(result);
1040 /* Clean up our error-handling environment. */
1041 xmlrpc_env_clean(&env);
1043 /* Shutdown our XML-RPC client library. */
1044 xmlrpc_client_cleanup();
1048 bool cmCTestSubmitHandler::SubmitUsingXMLRPC(cmStdString const&,
1049 std::set<cmStdString> const&,
1057 //----------------------------------------------------------------------------
1058 int cmCTestSubmitHandler::ProcessHandler()
1060 std::string iscdash = this->CTest->GetCTestConfiguration("IsCDash");
1061 // cdash does not need to trigger so just return true
1067 const std::string &buildDirectory
1068 = this->CTest->GetCTestConfiguration("BuildDirectory");
1069 if ( buildDirectory.size() == 0 )
1071 cmCTestLog(this->CTest, ERROR_MESSAGE,
1072 "Cannot find BuildDirectory key in the DartConfiguration.tcl"
1077 if ( getenv("HTTP_PROXY") )
1079 this->HTTPProxyType = 1;
1080 this->HTTPProxy = getenv("HTTP_PROXY");
1081 if ( getenv("HTTP_PROXY_PORT") )
1083 this->HTTPProxy += ":";
1084 this->HTTPProxy += getenv("HTTP_PROXY_PORT");
1086 if ( getenv("HTTP_PROXY_TYPE") )
1088 cmStdString type = getenv("HTTP_PROXY_TYPE");
1089 // HTTP/SOCKS4/SOCKS5
1090 if ( type == "HTTP" )
1092 this->HTTPProxyType = 1;
1094 else if ( type == "SOCKS4" )
1096 this->HTTPProxyType = 2;
1098 else if ( type == "SOCKS5" )
1100 this->HTTPProxyType = 3;
1103 if ( getenv("HTTP_PROXY_USER") )
1105 this->HTTPProxyAuth = getenv("HTTP_PROXY_USER");
1107 if ( getenv("HTTP_PROXY_PASSWD") )
1109 this->HTTPProxyAuth += ":";
1110 this->HTTPProxyAuth += getenv("HTTP_PROXY_PASSWD");
1114 if ( getenv("FTP_PROXY") )
1116 this->FTPProxyType = 1;
1117 this->FTPProxy = getenv("FTP_PROXY");
1118 if ( getenv("FTP_PROXY_PORT") )
1120 this->FTPProxy += ":";
1121 this->FTPProxy += getenv("FTP_PROXY_PORT");
1123 if ( getenv("FTP_PROXY_TYPE") )
1125 cmStdString type = getenv("FTP_PROXY_TYPE");
1126 // HTTP/SOCKS4/SOCKS5
1127 if ( type == "HTTP" )
1129 this->FTPProxyType = 1;
1131 else if ( type == "SOCKS4" )
1133 this->FTPProxyType = 2;
1135 else if ( type == "SOCKS5" )
1137 this->FTPProxyType = 3;
1142 if ( this->HTTPProxy.size() > 0 )
1144 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Use HTTP Proxy: "
1145 << this->HTTPProxy << std::endl);
1147 if ( this->FTPProxy.size() > 0 )
1149 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Use FTP Proxy: "
1150 << this->FTPProxy << std::endl);
1152 cmGeneratedFileStream ofs;
1153 this->StartLogFile("Submit", ofs);
1155 cmCTest::SetOfStrings files;
1156 std::string prefix = this->GetSubmitResultsPrefix();
1158 if (!this->Files.empty())
1160 // Submit the explicitly selected files:
1162 cmCTest::SetOfStrings::const_iterator it;
1163 for (it = this->Files.begin(); it != this->Files.end(); ++it)
1169 // Add to the list of files to submit from any selected, existing parts:
1173 // Check if test is enabled
1175 this->CTest->AddIfExists(cmCTest::PartUpdate, "Update.xml");
1176 this->CTest->AddIfExists(cmCTest::PartConfigure, "Configure.xml");
1177 this->CTest->AddIfExists(cmCTest::PartBuild, "Build.xml");
1178 this->CTest->AddIfExists(cmCTest::PartTest, "Test.xml");
1179 if(this->CTest->AddIfExists(cmCTest::PartCoverage, "Coverage.xml"))
1181 cmCTest::VectorOfStrings gfiles;
1183 = buildDirectory + "/Testing/" + this->CTest->GetCurrentTag();
1184 std::string::size_type glen = gpath.size() + 1;
1185 gpath = gpath + "/CoverageLog*";
1186 cmCTestLog(this->CTest, DEBUG, "Globbing for: " << gpath.c_str()
1188 if ( cmSystemTools::SimpleGlob(gpath, gfiles, 1) )
1191 for ( cc = 0; cc < gfiles.size(); cc ++ )
1193 gfiles[cc] = gfiles[cc].substr(glen);
1194 cmCTestLog(this->CTest, DEBUG, "Glob file: " << gfiles[cc].c_str()
1196 this->CTest->AddSubmitFile(cmCTest::PartCoverage, gfiles[cc].c_str());
1201 cmCTestLog(this->CTest, ERROR_MESSAGE, "Problem globbing" << std::endl);
1204 this->CTest->AddIfExists(cmCTest::PartMemCheck, "DynamicAnalysis.xml");
1205 this->CTest->AddIfExists(cmCTest::PartMemCheck, "Purify.xml");
1206 this->CTest->AddIfExists(cmCTest::PartNotes, "Notes.xml");
1207 this->CTest->AddIfExists(cmCTest::PartUpload, "Upload.xml");
1209 // Query parts for files to submit.
1210 for(cmCTest::Part p = cmCTest::PartStart;
1211 p != cmCTest::PartCount; p = cmCTest::Part(p+1))
1213 // Skip parts we are not submitting.
1214 if(!this->SubmitPart[p])
1219 // Submit files from this part.
1220 std::vector<std::string> const& pfiles = this->CTest->GetSubmitFiles(p);
1221 for(std::vector<std::string>::const_iterator pi = pfiles.begin();
1222 pi != pfiles.end(); ++pi)
1230 ofs << "Upload files:" << std::endl;
1232 cmCTest::SetOfStrings::iterator it;
1233 for ( it = files.begin(); it != files.end(); ++ it )
1235 ofs << cnt << "\t" << it->c_str() << std::endl;
1239 cmCTestLog(this->CTest, HANDLER_OUTPUT, "Submit files (using "
1240 << this->CTest->GetCTestConfiguration("DropMethod") << ")"
1242 const char* specificTrack = this->CTest->GetSpecificTrack();
1243 if ( specificTrack )
1245 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Send to track: "
1246 << specificTrack << std::endl);
1248 this->SetLogFile(&ofs);
1250 cmStdString dropMethod(this->CTest->GetCTestConfiguration("DropMethod"));
1252 if ( dropMethod == "" || dropMethod == "ftp" )
1254 ofs << "Using drop method: FTP" << std::endl;
1255 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Using FTP submit method"
1257 << " Drop site: ftp://");
1258 std::string url = "ftp://";
1259 url += cmCTest::MakeURLSafe(
1260 this->CTest->GetCTestConfiguration("DropSiteUser")) + ":" +
1261 cmCTest::MakeURLSafe(this->CTest->GetCTestConfiguration(
1262 "DropSitePassword")) + "@" +
1263 this->CTest->GetCTestConfiguration("DropSite") +
1264 cmCTest::MakeURLSafe(
1265 this->CTest->GetCTestConfiguration("DropLocation"));
1266 if ( this->CTest->GetCTestConfiguration("DropSiteUser").size() > 0 )
1268 cmCTestLog(this->CTest, HANDLER_OUTPUT,
1269 this->CTest->GetCTestConfiguration(
1270 "DropSiteUser").c_str());
1271 if ( this->CTest->GetCTestConfiguration("DropSitePassword").size() > 0 )
1273 cmCTestLog(this->CTest, HANDLER_OUTPUT, ":******");
1275 cmCTestLog(this->CTest, HANDLER_OUTPUT, "@");
1277 cmCTestLog(this->CTest, HANDLER_OUTPUT,
1278 this->CTest->GetCTestConfiguration("DropSite")
1279 << this->CTest->GetCTestConfiguration("DropLocation") << std::endl);
1280 if ( !this->SubmitUsingFTP(buildDirectory + "/Testing/"
1281 + this->CTest->GetCurrentTag(),
1282 files, prefix, url) )
1284 cmCTestLog(this->CTest, ERROR_MESSAGE,
1285 " Problems when submitting via FTP"
1287 ofs << " Problems when submitting via FTP" << std::endl;
1292 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Using HTTP trigger method"
1294 << " Trigger site: "
1295 << this->CTest->GetCTestConfiguration("TriggerSite")
1298 TriggerUsingHTTP(files, prefix,
1299 this->CTest->GetCTestConfiguration("TriggerSite")))
1301 cmCTestLog(this->CTest, ERROR_MESSAGE,
1302 " Problems when triggering via HTTP" << std::endl);
1303 ofs << " Problems when triggering via HTTP" << std::endl;
1306 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submission successful"
1308 ofs << " Submission successful" << std::endl;
1312 else if ( dropMethod == "http" || dropMethod == "https" )
1314 std::string url = dropMethod;
1316 ofs << "Using drop method: " << dropMethod << std::endl;
1317 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Using HTTP submit method"
1319 << " Drop site:" << url);
1320 if ( this->CTest->GetCTestConfiguration("DropSiteUser").size() > 0 )
1322 url += this->CTest->GetCTestConfiguration("DropSiteUser");
1323 cmCTestLog(this->CTest, HANDLER_OUTPUT,
1324 this->CTest->GetCTestConfiguration("DropSiteUser").c_str());
1325 if ( this->CTest->GetCTestConfiguration("DropSitePassword").size() > 0 )
1327 url += ":" + this->CTest->GetCTestConfiguration("DropSitePassword");
1328 cmCTestLog(this->CTest, HANDLER_OUTPUT, ":******");
1331 cmCTestLog(this->CTest, HANDLER_OUTPUT, "@");
1333 url += this->CTest->GetCTestConfiguration("DropSite") +
1334 this->CTest->GetCTestConfiguration("DropLocation");
1335 cmCTestLog(this->CTest, HANDLER_OUTPUT,
1336 this->CTest->GetCTestConfiguration("DropSite")
1337 << this->CTest->GetCTestConfiguration("DropLocation") << std::endl);
1338 if ( !this->SubmitUsingHTTP(buildDirectory + "/Testing/" +
1339 this->CTest->GetCurrentTag(), files, prefix, url) )
1341 cmCTestLog(this->CTest, ERROR_MESSAGE,
1342 " Problems when submitting via HTTP" << std::endl);
1343 ofs << " Problems when submitting via HTTP" << std::endl;
1348 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Using HTTP trigger method"
1350 << " Trigger site: "
1351 << this->CTest->GetCTestConfiguration("TriggerSite")
1354 TriggerUsingHTTP(files, prefix,
1355 this->CTest->GetCTestConfiguration("TriggerSite")))
1357 cmCTestLog(this->CTest, ERROR_MESSAGE,
1358 " Problems when triggering via HTTP" << std::endl);
1359 ofs << " Problems when triggering via HTTP" << std::endl;
1365 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Errors occurred during "
1366 "submission." << std::endl);
1367 ofs << " Errors occurred during submission. " << std::endl;
1371 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submission successful" <<
1372 (this->HasWarnings ? ", with warnings." : "") << std::endl);
1373 ofs << " Submission successful" <<
1374 (this->HasWarnings ? ", with warnings." : "") << std::endl;
1379 else if ( dropMethod == "xmlrpc" )
1381 #if defined(CTEST_USE_XMLRPC)
1382 ofs << "Using drop method: XML-RPC" << std::endl;
1383 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Using XML-RPC submit method"
1385 std::string url = this->CTest->GetCTestConfiguration("DropSite");
1386 prefix = this->CTest->GetCTestConfiguration("DropLocation");
1387 if ( !this->SubmitUsingXMLRPC(buildDirectory + "/Testing/" +
1388 this->CTest->GetCurrentTag(), files, prefix, url) )
1390 cmCTestLog(this->CTest, ERROR_MESSAGE,
1391 " Problems when submitting via XML-RPC" << std::endl);
1392 ofs << " Problems when submitting via XML-RPC" << std::endl;
1395 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submission successful"
1397 ofs << " Submission successful" << std::endl;
1400 cmCTestLog(this->CTest, ERROR_MESSAGE,
1401 " Submission method \"xmlrpc\" not compiled into CTest!"
1406 else if ( dropMethod == "scp" )
1409 std::string oldWorkingDirectory;
1410 if ( this->CTest->GetCTestConfiguration("DropSiteUser").size() > 0 )
1412 url += this->CTest->GetCTestConfiguration("DropSiteUser") + "@";
1414 url += this->CTest->GetCTestConfiguration("DropSite") + ":" +
1415 this->CTest->GetCTestConfiguration("DropLocation");
1417 // change to the build directory so that we can uses a relative path
1418 // on windows since scp dosn't support "c:" a drive in the path
1419 oldWorkingDirectory = cmSystemTools::GetCurrentWorkingDirectory();
1420 cmSystemTools::ChangeDirectory(buildDirectory.c_str());
1422 if ( !this->SubmitUsingSCP(
1423 this->CTest->GetCTestConfiguration("ScpCommand"),
1424 "Testing/"+this->CTest->GetCurrentTag(), files, prefix, url) )
1426 cmSystemTools::ChangeDirectory(oldWorkingDirectory.c_str());
1427 cmCTestLog(this->CTest, ERROR_MESSAGE,
1428 " Problems when submitting via SCP"
1430 ofs << " Problems when submitting via SCP" << std::endl;
1433 cmSystemTools::ChangeDirectory(oldWorkingDirectory.c_str());
1434 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submission successful"
1436 ofs << " Submission successful" << std::endl;
1439 else if ( dropMethod == "cp" )
1441 std::string location
1442 = this->CTest->GetCTestConfiguration("DropLocation");
1445 // change to the build directory so that we can uses a relative path
1446 // on windows since scp dosn't support "c:" a drive in the path
1448 oldWorkingDirectory = cmSystemTools::GetCurrentWorkingDirectory();
1449 cmSystemTools::ChangeDirectory(buildDirectory.c_str());
1450 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Change directory: "
1451 << buildDirectory.c_str() << std::endl);
1453 if ( !this->SubmitUsingCP(
1454 "Testing/"+this->CTest->GetCurrentTag(),
1459 cmSystemTools::ChangeDirectory(oldWorkingDirectory.c_str());
1460 cmCTestLog(this->CTest, ERROR_MESSAGE,
1461 " Problems when submitting via CP"
1463 ofs << " Problems when submitting via cp" << std::endl;
1466 cmSystemTools::ChangeDirectory(oldWorkingDirectory.c_str());
1467 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submission successful"
1469 ofs << " Submission successful" << std::endl;
1473 cmCTestLog(this->CTest, ERROR_MESSAGE, " Unknown submission method: \""
1474 << dropMethod << "\"" << std::endl);
1478 //----------------------------------------------------------------------------
1479 std::string cmCTestSubmitHandler::GetSubmitResultsPrefix()
1481 std::string name = this->CTest->GetCTestConfiguration("Site") +
1482 "___" + this->CTest->GetCTestConfiguration("BuildName") +
1483 "___" + this->CTest->GetCurrentTag() + "-" +
1484 this->CTest->GetTestModelString() + "___XML___";
1488 //----------------------------------------------------------------------------
1489 void cmCTestSubmitHandler::SelectParts(std::set<cmCTest::Part> const& parts)
1491 // Check whether each part is selected.
1492 for(cmCTest::Part p = cmCTest::PartStart;
1493 p != cmCTest::PartCount; p = cmCTest::Part(p+1))
1495 this->SubmitPart[p] =
1496 (std::set<cmCTest::Part>::const_iterator(parts.find(p)) != parts.end());
1500 //----------------------------------------------------------------------------
1501 void cmCTestSubmitHandler::SelectFiles(cmCTest::SetOfStrings const& files)
1503 cmCTest::SetOfStrings::const_iterator it;
1504 for (it = files.begin(); it != files.end(); ++it)
1506 this->Files.insert(*it);