1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmCTestSubmitHandler.cxx,v $
6 Date: $Date: 2009-03-31 19:30:36 $
7 Version: $Revision: 1.41 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmCTestSubmitHandler.h"
19 #include "cmSystemTools.h"
20 #include "cmVersion.h"
21 #include "cmGeneratedFileStream.h"
24 #include <cmsys/Process.h>
25 #include <cmsys/Base64.h>
27 // For XML-RPC submission
28 #include "cm_xmlrpc.h"
30 // For curl submission
35 typedef std::vector
<char> cmCTestSubmitHandlerVectorOfChar
;
38 cmCTestSubmitHandlerWriteMemoryCallback(void *ptr
, size_t size
, size_t nmemb
,
41 register int realsize
= (int)(size
* nmemb
);
43 cmCTestSubmitHandlerVectorOfChar
*vec
44 = static_cast<cmCTestSubmitHandlerVectorOfChar
*>(data
);
45 const char* chPtr
= static_cast<char*>(ptr
);
46 vec
->insert(vec
->end(), chPtr
, chPtr
+ realsize
);
52 cmCTestSubmitHandlerCurlDebugCallback(CURL
*, curl_infotype
, char *chPtr
,
53 size_t size
, void *data
)
55 cmCTestSubmitHandlerVectorOfChar
*vec
56 = static_cast<cmCTestSubmitHandlerVectorOfChar
*>(data
);
57 vec
->insert(vec
->end(), chPtr
, chPtr
+ size
);
62 //----------------------------------------------------------------------------
63 cmCTestSubmitHandler::cmCTestSubmitHandler() : HTTPProxy(), FTPProxy()
68 //----------------------------------------------------------------------------
69 void cmCTestSubmitHandler::Initialize()
71 // We submit all available parts by default.
72 for(cmCTest::Part p
= cmCTest::PartStart
;
73 p
!= cmCTest::PartCount
; p
= cmCTest::Part(p
+1))
75 this->SubmitPart
[p
] = true;
78 this->Superclass::Initialize();
80 this->HTTPProxyType
= 0;
81 this->HTTPProxyAuth
= "";
83 this->FTPProxyType
= 0;
88 //----------------------------------------------------------------------------
89 bool cmCTestSubmitHandler::SubmitUsingFTP(const cmStdString
& localprefix
,
90 const std::set
<cmStdString
>& files
,
91 const cmStdString
& remoteprefix
,
92 const cmStdString
& url
)
97 char error_buffer
[1024];
99 /* In windows, this will init the winsock stuff */
100 ::curl_global_init(CURL_GLOBAL_ALL
);
102 cmCTest::SetOfStrings::const_iterator file
;
103 for ( file
= files
.begin(); file
!= files
.end(); ++file
)
105 /* get a curl handle */
106 curl
= curl_easy_init();
110 if ( this->FTPProxyType
> 0 )
112 curl_easy_setopt(curl
, CURLOPT_PROXY
, this->FTPProxy
.c_str());
113 switch (this->FTPProxyType
)
116 curl_easy_setopt(curl
, CURLOPT_PROXYTYPE
, CURLPROXY_SOCKS4
);
119 curl_easy_setopt(curl
, CURLOPT_PROXYTYPE
, CURLPROXY_SOCKS5
);
122 curl_easy_setopt(curl
, CURLOPT_PROXYTYPE
, CURLPROXY_HTTP
);
127 ::curl_easy_setopt(curl
, CURLOPT_UPLOAD
, 1) ;
129 cmStdString local_file
= *file
;
130 if ( !cmSystemTools::FileExists(local_file
.c_str()) )
132 local_file
= localprefix
+ "/" + *file
;
134 cmStdString upload_as
135 = url
+ "/" + remoteprefix
+ cmSystemTools::GetFilenameName(*file
);
138 if ( ::stat(local_file
.c_str(), &st
) )
140 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Cannot find file: "
141 << local_file
.c_str() << std::endl
);
142 ::curl_easy_cleanup(curl
);
143 ::curl_global_cleanup();
147 ftpfile
= ::fopen(local_file
.c_str(), "rb");
148 *this->LogFile
<< "\tUpload file: " << local_file
.c_str() << " to "
149 << upload_as
.c_str() << std::endl
;
150 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, " Upload file: "
151 << local_file
.c_str() << " to "
152 << upload_as
.c_str() << std::endl
);
154 ::curl_easy_setopt(curl
, CURLOPT_VERBOSE
, 1);
157 ::curl_easy_setopt(curl
,CURLOPT_URL
, upload_as
.c_str());
159 // now specify which file to upload
160 ::curl_easy_setopt(curl
, CURLOPT_INFILE
, ftpfile
);
162 // and give the size of the upload (optional)
163 ::curl_easy_setopt(curl
, CURLOPT_INFILESIZE
,
164 static_cast<long>(st
.st_size
));
166 // and give curl the buffer for errors
167 ::curl_easy_setopt(curl
, CURLOPT_ERRORBUFFER
, &error_buffer
);
169 // specify handler for output
170 ::curl_easy_setopt(curl
, CURLOPT_WRITEFUNCTION
,
171 cmCTestSubmitHandlerWriteMemoryCallback
);
172 ::curl_easy_setopt(curl
, CURLOPT_DEBUGFUNCTION
,
173 cmCTestSubmitHandlerCurlDebugCallback
);
175 /* we pass our 'chunk' struct to the callback function */
176 cmCTestSubmitHandlerVectorOfChar chunk
;
177 cmCTestSubmitHandlerVectorOfChar chunkDebug
;
178 ::curl_easy_setopt(curl
, CURLOPT_FILE
, (void *)&chunk
);
179 ::curl_easy_setopt(curl
, CURLOPT_DEBUGDATA
, (void *)&chunkDebug
);
181 // Now run off and do what you've been told!
182 res
= ::curl_easy_perform(curl
);
184 if ( chunk
.size() > 0 )
186 cmCTestLog(this->CTest
, DEBUG
, "CURL output: ["
187 << cmCTestLogWrite(&*chunk
.begin(), chunk
.size()) << "]"
190 if ( chunkDebug
.size() > 0 )
192 cmCTestLog(this->CTest
, DEBUG
, "CURL debug output: ["
193 << cmCTestLogWrite(&*chunkDebug
.begin(), chunkDebug
.size()) << "]"
200 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
201 " Error when uploading file: "
202 << local_file
.c_str() << std::endl
);
203 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Error message was: "
204 << error_buffer
<< std::endl
);
205 *this->LogFile
<< " Error when uploading file: "
206 << local_file
.c_str()
208 << " Error message was: "
209 << error_buffer
<< std::endl
210 << " Curl output was: ";
211 // avoid dereference of empty vector
214 *this->LogFile
<< cmCTestLogWrite(&*chunk
.begin(), chunk
.size());
215 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "CURL output: ["
216 << cmCTestLogWrite(&*chunk
.begin(), chunk
.size()) << "]"
219 *this->LogFile
<< std::endl
;
220 ::curl_easy_cleanup(curl
);
221 ::curl_global_cleanup();
225 ::curl_easy_cleanup(curl
);
226 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Uploaded: " + local_file
230 ::curl_global_cleanup();
234 //----------------------------------------------------------------------------
235 // Uploading files is simpler
236 bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString
& localprefix
,
237 const std::set
<cmStdString
>& files
,
238 const cmStdString
& remoteprefix
,
239 const cmStdString
& url
)
244 char error_buffer
[1024];
246 /* In windows, this will init the winsock stuff */
247 ::curl_global_init(CURL_GLOBAL_ALL
);
249 cmStdString::size_type kk
;
250 cmCTest::SetOfStrings::const_iterator file
;
251 for ( file
= files
.begin(); file
!= files
.end(); ++file
)
253 /* get a curl handle */
254 curl
= curl_easy_init();
257 curl_easy_setopt(curl
, CURLOPT_SSL_VERIFYPEER
, 0);
260 if ( this->HTTPProxyType
> 0 )
262 curl_easy_setopt(curl
, CURLOPT_PROXY
, this->HTTPProxy
.c_str());
263 switch (this->HTTPProxyType
)
266 curl_easy_setopt(curl
, CURLOPT_PROXYTYPE
, CURLPROXY_SOCKS4
);
269 curl_easy_setopt(curl
, CURLOPT_PROXYTYPE
, CURLPROXY_SOCKS5
);
272 curl_easy_setopt(curl
, CURLOPT_PROXYTYPE
, CURLPROXY_HTTP
);
273 if (this->HTTPProxyAuth
.size() > 0)
275 curl_easy_setopt(curl
, CURLOPT_PROXYUSERPWD
,
276 this->HTTPProxyAuth
.c_str());
281 /* enable uploading */
282 curl_easy_setopt(curl
, CURLOPT_UPLOAD
, 1) ;
284 /* HTTP PUT please */
285 ::curl_easy_setopt(curl
, CURLOPT_PUT
, 1);
286 ::curl_easy_setopt(curl
, CURLOPT_VERBOSE
, 1);
288 cmStdString local_file
= *file
;
289 if ( !cmSystemTools::FileExists(local_file
.c_str()) )
291 local_file
= localprefix
+ "/" + *file
;
293 cmStdString remote_file
294 = remoteprefix
+ cmSystemTools::GetFilenameName(*file
);
296 *this->LogFile
<< "\tUpload file: " << local_file
.c_str() << " to "
297 << remote_file
.c_str() << std::endl
;
299 cmStdString ofile
= "";
300 for ( kk
= 0; kk
< remote_file
.size(); kk
++ )
302 char c
= remote_file
[kk
];
303 char hexCh
[4] = { 0, 0, 0, 0 };
315 sprintf(hexCh
, "%%%02X", (int)c
);
322 cmStdString upload_as
323 = url
+ ((url
.find("?",0) == cmStdString::npos
) ? "?" : "&")
324 + "FileName=" + ofile
;
327 if ( ::stat(local_file
.c_str(), &st
) )
329 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Cannot find file: "
330 << local_file
.c_str() << std::endl
);
331 ::curl_easy_cleanup(curl
);
332 ::curl_global_cleanup();
336 ftpfile
= ::fopen(local_file
.c_str(), "rb");
337 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, " Upload file: "
338 << local_file
.c_str() << " to "
339 << upload_as
.c_str() << " Size: " << st
.st_size
<< std::endl
);
343 ::curl_easy_setopt(curl
,CURLOPT_URL
, upload_as
.c_str());
345 // now specify which file to upload
346 ::curl_easy_setopt(curl
, CURLOPT_INFILE
, ftpfile
);
348 // and give the size of the upload (optional)
349 ::curl_easy_setopt(curl
, CURLOPT_INFILESIZE
,
350 static_cast<long>(st
.st_size
));
352 // and give curl the buffer for errors
353 ::curl_easy_setopt(curl
, CURLOPT_ERRORBUFFER
, &error_buffer
);
355 // specify handler for output
356 ::curl_easy_setopt(curl
, CURLOPT_WRITEFUNCTION
,
357 cmCTestSubmitHandlerWriteMemoryCallback
);
358 ::curl_easy_setopt(curl
, CURLOPT_DEBUGFUNCTION
,
359 cmCTestSubmitHandlerCurlDebugCallback
);
361 /* we pass our 'chunk' struct to the callback function */
362 cmCTestSubmitHandlerVectorOfChar chunk
;
363 cmCTestSubmitHandlerVectorOfChar chunkDebug
;
364 ::curl_easy_setopt(curl
, CURLOPT_FILE
, (void *)&chunk
);
365 ::curl_easy_setopt(curl
, CURLOPT_DEBUGDATA
, (void *)&chunkDebug
);
367 // Now run off and do what you've been told!
368 res
= ::curl_easy_perform(curl
);
370 if ( chunk
.size() > 0 )
372 cmCTestLog(this->CTest
, DEBUG
, "CURL output: ["
373 << cmCTestLogWrite(&*chunk
.begin(), chunk
.size()) << "]"
376 if ( chunkDebug
.size() > 0 )
378 cmCTestLog(this->CTest
, DEBUG
, "CURL debug output: ["
379 << cmCTestLogWrite(&*chunkDebug
.begin(), chunkDebug
.size()) << "]"
386 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
387 " Error when uploading file: "
388 << local_file
.c_str() << std::endl
);
389 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Error message was: "
390 << error_buffer
<< std::endl
);
391 *this->LogFile
<< " Error when uploading file: "
392 << local_file
.c_str()
394 << " Error message was: " << error_buffer
396 // avoid deref of begin for zero size array
399 *this->LogFile
<< " Curl output was: "
400 << cmCTestLogWrite(&*chunk
.begin(), chunk
.size())
402 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "CURL output: ["
403 << cmCTestLogWrite(&*chunk
.begin(), chunk
.size()) << "]"
406 ::curl_easy_cleanup(curl
);
407 ::curl_global_cleanup();
411 ::curl_easy_cleanup(curl
);
412 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Uploaded: " + local_file
416 ::curl_global_cleanup();
420 //----------------------------------------------------------------------------
421 bool cmCTestSubmitHandler::TriggerUsingHTTP(
422 const std::set
<cmStdString
>& files
,
423 const cmStdString
& remoteprefix
,
424 const cmStdString
& url
)
427 char error_buffer
[1024];
428 /* In windows, this will init the winsock stuff */
429 ::curl_global_init(CURL_GLOBAL_ALL
);
431 cmCTest::SetOfStrings::const_iterator file
;
432 for ( file
= files
.begin(); file
!= files
.end(); ++file
)
434 /* get a curl handle */
435 curl
= curl_easy_init();
439 if ( this->HTTPProxyType
> 0 )
441 curl_easy_setopt(curl
, CURLOPT_PROXY
, this->HTTPProxy
.c_str());
442 switch (this->HTTPProxyType
)
445 curl_easy_setopt(curl
, CURLOPT_PROXYTYPE
, CURLPROXY_SOCKS4
);
448 curl_easy_setopt(curl
, CURLOPT_PROXYTYPE
, CURLPROXY_SOCKS5
);
451 curl_easy_setopt(curl
, CURLOPT_PROXYTYPE
, CURLPROXY_HTTP
);
452 if (this->HTTPProxyAuth
.size() > 0)
454 curl_easy_setopt(curl
, CURLOPT_PROXYUSERPWD
,
455 this->HTTPProxyAuth
.c_str());
460 ::curl_easy_setopt(curl
, CURLOPT_VERBOSE
, 1);
462 // and give curl the buffer for errors
463 ::curl_easy_setopt(curl
, CURLOPT_ERRORBUFFER
, &error_buffer
);
465 // specify handler for output
466 ::curl_easy_setopt(curl
, CURLOPT_WRITEFUNCTION
,
467 cmCTestSubmitHandlerWriteMemoryCallback
);
468 ::curl_easy_setopt(curl
, CURLOPT_DEBUGFUNCTION
,
469 cmCTestSubmitHandlerCurlDebugCallback
);
471 /* we pass our 'chunk' struct to the callback function */
472 cmCTestSubmitHandlerVectorOfChar chunk
;
473 cmCTestSubmitHandlerVectorOfChar chunkDebug
;
474 ::curl_easy_setopt(curl
, CURLOPT_FILE
, (void *)&chunk
);
475 ::curl_easy_setopt(curl
, CURLOPT_DEBUGDATA
, (void *)&chunkDebug
);
478 = remoteprefix
+ cmSystemTools::GetFilenameName(*file
);
479 cmStdString ofile
= "";
480 cmStdString::iterator kk
;
481 for ( kk
= rfile
.begin(); kk
< rfile
.end(); ++ kk
)
484 char hexCh
[4] = { 0, 0, 0, 0 };
496 sprintf(hexCh
, "%%%02X", (int)c
);
504 = url
+ ((url
.find("?",0) == cmStdString::npos
) ? "?" : "&")
505 + "xmlfile=" + ofile
;
506 *this->LogFile
<< "Trigger url: " << turl
.c_str() << std::endl
;
507 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, " Trigger url: "
508 << turl
.c_str() << std::endl
);
509 curl_easy_setopt(curl
, CURLOPT_HTTPAUTH
, CURLAUTH_ANY
);
510 curl_easy_setopt(curl
, CURLOPT_URL
, turl
.c_str());
511 if ( curl_easy_perform(curl
) )
513 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Error when triggering: "
514 << turl
.c_str() << std::endl
);
515 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Error message was: "
516 << error_buffer
<< std::endl
);
517 *this->LogFile
<< "\tTrigerring failed with error: " << error_buffer
519 << " Error message was: " << error_buffer
524 << " Curl output was: "
525 << cmCTestLogWrite(&*chunk
.begin(), chunk
.size()) << std::endl
;
526 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "CURL output: ["
527 << cmCTestLogWrite(&*chunk
.begin(), chunk
.size()) << "]"
530 ::curl_easy_cleanup(curl
);
531 ::curl_global_cleanup();
535 if ( chunk
.size() > 0 )
537 cmCTestLog(this->CTest
, DEBUG
, "CURL output: ["
538 << cmCTestLogWrite(&*chunk
.begin(), chunk
.size()) << "]"
541 if ( chunkDebug
.size() > 0 )
543 cmCTestLog(this->CTest
, DEBUG
, "CURL debug output: ["
544 << cmCTestLogWrite(&*chunkDebug
.begin(), chunkDebug
.size())
545 << "]" << std::endl
);
549 ::curl_easy_cleanup(curl
);
550 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, std::endl
);
553 ::curl_global_cleanup();
554 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Dart server triggered..."
559 //----------------------------------------------------------------------------
560 bool cmCTestSubmitHandler::SubmitUsingSCP(
561 const cmStdString
& scp_command
,
562 const cmStdString
& localprefix
,
563 const std::set
<cmStdString
>& files
,
564 const cmStdString
& remoteprefix
,
565 const cmStdString
& url
)
567 if ( !scp_command
.size() || !localprefix
.size() ||
568 !files
.size() || !remoteprefix
.size() || !url
.size() )
572 std::vector
<const char*> argv
;
573 argv
.push_back(scp_command
.c_str()); // Scp command
574 argv
.push_back(scp_command
.c_str()); // Dummy string for file
575 argv
.push_back(scp_command
.c_str()); // Dummy string for remote url
578 cmsysProcess
* cp
= cmsysProcess_New();
579 cmsysProcess_SetOption(cp
, cmsysProcess_Option_HideWindow
, 1);
580 //cmsysProcess_SetTimeout(cp, timeout);
584 cmCTest::SetOfStrings::const_iterator file
;
585 for ( file
= files
.begin(); file
!= files
.end(); ++file
)
589 std::string lfname
= localprefix
;
590 cmSystemTools::ConvertToUnixSlashes(lfname
);
591 lfname
+= "/" + *file
;
592 lfname
= cmSystemTools::ConvertToOutputPath(lfname
.c_str());
593 argv
[1] = lfname
.c_str();
594 std::string rfname
= url
+ "/" + remoteprefix
+ *file
;
595 argv
[2] = rfname
.c_str();
596 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, "Execute \"" << argv
[0]
597 << "\" \"" << argv
[1] << "\" \""
598 << argv
[2] << "\"" << std::endl
);
599 *this->LogFile
<< "Execute \"" << argv
[0] << "\" \"" << argv
[1] << "\" \""
600 << argv
[2] << "\"" << std::endl
;
602 cmsysProcess_SetCommand(cp
, &*argv
.begin());
603 cmsysProcess_Execute(cp
);
607 while(cmsysProcess_WaitForData(cp
, &data
, &length
, 0))
609 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
610 cmCTestLogWrite(data
, length
));
613 cmsysProcess_WaitForExit(cp
, 0);
615 int result
= cmsysProcess_GetState(cp
);
617 if(result
== cmsysProcess_State_Exited
)
619 retVal
= cmsysProcess_GetExitValue(cp
);
622 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, "\tSCP returned: "
623 << retVal
<< std::endl
);
624 *this->LogFile
<< "\tSCP returned: " << retVal
<< std::endl
;
628 else if(result
== cmsysProcess_State_Exception
)
630 retVal
= cmsysProcess_GetExitException(cp
);
631 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "\tThere was an exception: "
632 << retVal
<< std::endl
);
633 *this->LogFile
<< "\tThere was an exception: " << retVal
<< std::endl
;
636 else if(result
== cmsysProcess_State_Expired
)
638 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "\tThere was a timeout"
640 *this->LogFile
<< "\tThere was a timeout" << std::endl
;
643 else if(result
== cmsysProcess_State_Error
)
645 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "\tError executing SCP: "
646 << cmsysProcess_GetErrorString(cp
) << std::endl
);
647 *this->LogFile
<< "\tError executing SCP: "
648 << cmsysProcess_GetErrorString(cp
) << std::endl
;
652 cmsysProcess_Delete(cp
);
660 //----------------------------------------------------------------------------
661 bool cmCTestSubmitHandler::SubmitUsingCP(
662 const cmStdString
& localprefix
,
663 const std::set
<cmStdString
>& files
,
664 const cmStdString
& remoteprefix
,
665 const cmStdString
& destination
)
667 if ( !localprefix
.size() ||
668 !files
.size() || !remoteprefix
.size() || !destination
.size() )
670 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
671 "Missing arguments for submit via cp:\n"
672 << "\tlocalprefix: " << localprefix
<< "\n"
673 << "\tNumber of files: " << files
.size() << "\n"
674 << "\tremoteprefix: " << remoteprefix
<< "\n"
675 << "\tdestination: " << destination
<< std::endl
);
678 cmCTest::SetOfStrings::const_iterator file
;
679 bool problems
= false;
680 for ( file
= files
.begin(); file
!= files
.end(); ++file
)
682 std::string lfname
= localprefix
;
683 cmSystemTools::ConvertToUnixSlashes(lfname
);
684 lfname
+= "/" + *file
;
685 std::string rfname
= destination
+ "/" + remoteprefix
+ *file
;
686 cmSystemTools::CopyFileAlways(lfname
.c_str(), rfname
.c_str());
687 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, " Copy file: "
688 << lfname
.c_str() << " to "
689 << rfname
.c_str() << std::endl
);
691 std::string tagDoneFile
= destination
+ "/" + remoteprefix
+ "DONE";
692 cmSystemTools::Touch(tagDoneFile
.c_str(), true);
701 //----------------------------------------------------------------------------
702 bool cmCTestSubmitHandler::SubmitUsingXMLRPC(const cmStdString
& localprefix
,
703 const std::set
<cmStdString
>& files
,
704 const cmStdString
& remoteprefix
,
705 const cmStdString
& url
)
708 char ctestString
[] = "CTest";
709 std::string ctestVersionString
= cmVersion::GetCMakeVersion();
710 char* ctestVersion
= const_cast<char*>(ctestVersionString
.c_str());
712 cmStdString realURL
= url
+ "/" + remoteprefix
+ "/Command/";
714 /* Start up our XML-RPC client library. */
715 xmlrpc_client_init(XMLRPC_CLIENT_NO_FLAGS
, ctestString
, ctestVersion
);
717 /* Initialize our error-handling environment. */
718 xmlrpc_env_init(&env
);
720 /* Call the famous server at UserLand. */
721 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Submitting to: "
722 << realURL
.c_str() << " (" << remoteprefix
.c_str() << ")" << std::endl
);
723 cmCTest::SetOfStrings::const_iterator file
;
724 for ( file
= files
.begin(); file
!= files
.end(); ++file
)
726 xmlrpc_value
*result
;
728 cmStdString local_file
= *file
;
729 if ( !cmSystemTools::FileExists(local_file
.c_str()) )
731 local_file
= localprefix
+ "/" + *file
;
733 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Submit file: "
734 << local_file
.c_str() << std::endl
);
736 if ( ::stat(local_file
.c_str(), &st
) )
738 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Cannot find file: "
739 << local_file
.c_str() << std::endl
);
743 // off_t can be bigger than size_t. fread takes size_t.
744 // make sure the file is not too big.
745 if(static_cast<off_t
>(static_cast<size_t>(st
.st_size
)) !=
746 static_cast<off_t
>(st
.st_size
))
748 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " File too big: "
749 << local_file
.c_str() << std::endl
);
752 size_t fileSize
= static_cast<size_t>(st
.st_size
);
753 FILE* fp
= fopen(local_file
.c_str(), "rb");
756 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Cannot open file: "
757 << local_file
.c_str() << std::endl
);
761 unsigned char *fileBuffer
= new unsigned char[fileSize
];
762 if ( fread(fileBuffer
, 1, fileSize
, fp
) != fileSize
)
764 delete [] fileBuffer
;
766 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Cannot read file: "
767 << local_file
.c_str() << std::endl
);
772 char remoteCommand
[] = "Submit.put";
773 char* pRealURL
= const_cast<char*>(realURL
.c_str());
774 result
= xmlrpc_client_call(&env
, pRealURL
, remoteCommand
,
775 "(6)", fileBuffer
, (xmlrpc_int32
)fileSize
);
777 delete [] fileBuffer
;
779 if ( env
.fault_occurred
)
781 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Submission problem: "
782 << env
.fault_string
<< " (" << env
.fault_code
<< ")" << std::endl
);
783 xmlrpc_env_clean(&env
);
784 xmlrpc_client_cleanup();
788 /* Dispose of our result value. */
789 xmlrpc_DECREF(result
);
792 /* Clean up our error-handling environment. */
793 xmlrpc_env_clean(&env
);
795 /* Shutdown our XML-RPC client library. */
796 xmlrpc_client_cleanup();
800 //----------------------------------------------------------------------------
801 int cmCTestSubmitHandler::ProcessHandler()
803 std::string iscdash
= this->CTest
->GetCTestConfiguration("IsCDash");
804 // cdash does not need to trigger so just return true
810 const std::string
&buildDirectory
811 = this->CTest
->GetCTestConfiguration("BuildDirectory");
812 if ( buildDirectory
.size() == 0 )
814 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
815 "Cannot find BuildDirectory key in the DartConfiguration.tcl"
820 if ( getenv("HTTP_PROXY") )
822 this->HTTPProxyType
= 1;
823 this->HTTPProxy
= getenv("HTTP_PROXY");
824 if ( getenv("HTTP_PROXY_PORT") )
826 this->HTTPProxy
+= ":";
827 this->HTTPProxy
+= getenv("HTTP_PROXY_PORT");
829 if ( getenv("HTTP_PROXY_TYPE") )
831 cmStdString type
= getenv("HTTP_PROXY_TYPE");
832 // HTTP/SOCKS4/SOCKS5
833 if ( type
== "HTTP" )
835 this->HTTPProxyType
= 1;
837 else if ( type
== "SOCKS4" )
839 this->HTTPProxyType
= 2;
841 else if ( type
== "SOCKS5" )
843 this->HTTPProxyType
= 3;
846 if ( getenv("HTTP_PROXY_USER") )
848 this->HTTPProxyAuth
= getenv("HTTP_PROXY_USER");
850 if ( getenv("HTTP_PROXY_PASSWD") )
852 this->HTTPProxyAuth
+= ":";
853 this->HTTPProxyAuth
+= getenv("HTTP_PROXY_PASSWD");
857 if ( getenv("FTP_PROXY") )
859 this->FTPProxyType
= 1;
860 this->FTPProxy
= getenv("FTP_PROXY");
861 if ( getenv("FTP_PROXY_PORT") )
863 this->FTPProxy
+= ":";
864 this->FTPProxy
+= getenv("FTP_PROXY_PORT");
866 if ( getenv("FTP_PROXY_TYPE") )
868 cmStdString type
= getenv("FTP_PROXY_TYPE");
869 // HTTP/SOCKS4/SOCKS5
870 if ( type
== "HTTP" )
872 this->FTPProxyType
= 1;
874 else if ( type
== "SOCKS4" )
876 this->FTPProxyType
= 2;
878 else if ( type
== "SOCKS5" )
880 this->FTPProxyType
= 3;
885 if ( this->HTTPProxy
.size() > 0 )
887 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Use HTTP Proxy: "
888 << this->HTTPProxy
<< std::endl
);
890 if ( this->FTPProxy
.size() > 0 )
892 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Use FTP Proxy: "
893 << this->FTPProxy
<< std::endl
);
895 cmGeneratedFileStream ofs
;
896 this->StartLogFile("Submit", ofs
);
898 cmCTest::SetOfStrings files
;
899 std::string prefix
= this->GetSubmitResultsPrefix();
901 if (!this->Files
.empty())
903 // Submit the explicitly selected files:
905 cmCTest::SetOfStrings::const_iterator it
;
906 for (it
= this->Files
.begin(); it
!= this->Files
.end(); ++it
)
912 // Add to the list of files to submit from any selected, existing parts:
916 // Check if test is enabled
918 this->CTest
->AddIfExists(cmCTest::PartUpdate
, "Update.xml");
919 this->CTest
->AddIfExists(cmCTest::PartConfigure
, "Configure.xml");
920 this->CTest
->AddIfExists(cmCTest::PartBuild
, "Build.xml");
921 this->CTest
->AddIfExists(cmCTest::PartTest
, "Test.xml");
922 if(this->CTest
->AddIfExists(cmCTest::PartCoverage
, "Coverage.xml"))
924 cmCTest::VectorOfStrings gfiles
;
926 = buildDirectory
+ "/Testing/" + this->CTest
->GetCurrentTag();
927 std::string::size_type glen
= gpath
.size() + 1;
928 gpath
= gpath
+ "/CoverageLog*";
929 cmCTestLog(this->CTest
, DEBUG
, "Globbing for: " << gpath
.c_str()
931 if ( cmSystemTools::SimpleGlob(gpath
, gfiles
, 1) )
934 for ( cc
= 0; cc
< gfiles
.size(); cc
++ )
936 gfiles
[cc
] = gfiles
[cc
].substr(glen
);
937 cmCTestLog(this->CTest
, DEBUG
, "Glob file: " << gfiles
[cc
].c_str()
939 this->CTest
->AddSubmitFile(cmCTest::PartCoverage
, gfiles
[cc
].c_str());
944 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Problem globbing" << std::endl
);
947 this->CTest
->AddIfExists(cmCTest::PartMemCheck
, "DynamicAnalysis.xml");
948 this->CTest
->AddIfExists(cmCTest::PartMemCheck
, "Purify.xml");
949 this->CTest
->AddIfExists(cmCTest::PartNotes
, "Notes.xml");
951 // Query parts for files to submit.
952 for(cmCTest::Part p
= cmCTest::PartStart
;
953 p
!= cmCTest::PartCount
; p
= cmCTest::Part(p
+1))
955 // Skip parts we are not submitting.
956 if(!this->SubmitPart
[p
])
961 // Submit files from this part.
962 std::vector
<std::string
> const& pfiles
= this->CTest
->GetSubmitFiles(p
);
963 for(std::vector
<std::string
>::const_iterator pi
= pfiles
.begin();
964 pi
!= pfiles
.end(); ++pi
)
972 ofs
<< "Upload files:" << std::endl
;
974 cmCTest::SetOfStrings::iterator it
;
975 for ( it
= files
.begin(); it
!= files
.end(); ++ it
)
977 ofs
<< cnt
<< "\t" << it
->c_str() << std::endl
;
981 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, "Submit files (using "
982 << this->CTest
->GetCTestConfiguration("DropMethod") << ")"
984 const char* specificTrack
= this->CTest
->GetSpecificTrack();
987 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Send to track: "
988 << specificTrack
<< std::endl
);
990 this->SetLogFile(&ofs
);
992 cmStdString
dropMethod(this->CTest
->GetCTestConfiguration("DropMethod"));
994 if ( dropMethod
== "" || dropMethod
== "ftp" )
996 ofs
<< "Using drop method: FTP" << std::endl
;
997 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Using FTP submit method"
999 << " Drop site: ftp://");
1000 std::string url
= "ftp://";
1001 url
+= cmCTest::MakeURLSafe(
1002 this->CTest
->GetCTestConfiguration("DropSiteUser")) + ":" +
1003 cmCTest::MakeURLSafe(this->CTest
->GetCTestConfiguration(
1004 "DropSitePassword")) + "@" +
1005 this->CTest
->GetCTestConfiguration("DropSite") +
1006 cmCTest::MakeURLSafe(
1007 this->CTest
->GetCTestConfiguration("DropLocation"));
1008 if ( this->CTest
->GetCTestConfiguration("DropSiteUser").size() > 0 )
1010 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
1011 this->CTest
->GetCTestConfiguration(
1012 "DropSiteUser").c_str());
1013 if ( this->CTest
->GetCTestConfiguration("DropSitePassword").size() > 0 )
1015 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, ":******");
1017 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, "@");
1019 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
1020 this->CTest
->GetCTestConfiguration("DropSite")
1021 << this->CTest
->GetCTestConfiguration("DropLocation") << std::endl
);
1022 if ( !this->SubmitUsingFTP(buildDirectory
+ "/Testing/"
1023 + this->CTest
->GetCurrentTag(),
1024 files
, prefix
, url
) )
1026 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1027 " Problems when submitting via FTP"
1029 ofs
<< " Problems when submitting via FTP" << std::endl
;
1034 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Using HTTP trigger method"
1036 << " Trigger site: "
1037 << this->CTest
->GetCTestConfiguration("TriggerSite")
1040 TriggerUsingHTTP(files
, prefix
,
1041 this->CTest
->GetCTestConfiguration("TriggerSite")))
1043 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1044 " Problems when triggering via HTTP" << std::endl
);
1045 ofs
<< " Problems when triggering via HTTP" << std::endl
;
1048 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Submission successful"
1050 ofs
<< " Submission successful" << std::endl
;
1054 else if ( dropMethod
== "http" || dropMethod
== "https" )
1056 std::string url
= dropMethod
;
1058 ofs
<< "Using drop method: HTTP" << std::endl
;
1059 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Using HTTP submit method"
1061 << " Drop site:" << url
);
1062 if ( this->CTest
->GetCTestConfiguration("DropSiteUser").size() > 0 )
1064 url
+= this->CTest
->GetCTestConfiguration("DropSiteUser");
1065 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
1066 this->CTest
->GetCTestConfiguration("DropSiteUser").c_str());
1067 if ( this->CTest
->GetCTestConfiguration("DropSitePassword").size() > 0 )
1069 url
+= ":" + this->CTest
->GetCTestConfiguration("DropSitePassword");
1070 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, ":******");
1073 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, "@");
1075 url
+= this->CTest
->GetCTestConfiguration("DropSite") +
1076 this->CTest
->GetCTestConfiguration("DropLocation");
1077 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
1078 this->CTest
->GetCTestConfiguration("DropSite")
1079 << this->CTest
->GetCTestConfiguration("DropLocation") << std::endl
);
1080 if ( !this->SubmitUsingHTTP(buildDirectory
+ "/Testing/" +
1081 this->CTest
->GetCurrentTag(), files
, prefix
, url
) )
1083 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1084 " Problems when submitting via HTTP" << std::endl
);
1085 ofs
<< " Problems when submitting via HTTP" << std::endl
;
1090 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Using HTTP trigger method"
1092 << " Trigger site: "
1093 << this->CTest
->GetCTestConfiguration("TriggerSite")
1096 TriggerUsingHTTP(files
, prefix
,
1097 this->CTest
->GetCTestConfiguration("TriggerSite")))
1099 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1100 " Problems when triggering via HTTP" << std::endl
);
1101 ofs
<< " Problems when triggering via HTTP" << std::endl
;
1105 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Submission successful"
1107 ofs
<< " Submission successful" << std::endl
;
1110 else if ( dropMethod
== "xmlrpc" )
1112 ofs
<< "Using drop method: XML-RPC" << std::endl
;
1113 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Using XML-RPC submit method"
1115 std::string url
= this->CTest
->GetCTestConfiguration("DropSite");
1116 prefix
= this->CTest
->GetCTestConfiguration("DropLocation");
1117 if ( !this->SubmitUsingXMLRPC(buildDirectory
+ "/Testing/" +
1118 this->CTest
->GetCurrentTag(), files
, prefix
, url
) )
1120 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1121 " Problems when submitting via XML-RPC" << std::endl
);
1122 ofs
<< " Problems when submitting via XML-RPC" << std::endl
;
1125 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Submission successful"
1127 ofs
<< " Submission successful" << std::endl
;
1130 else if ( dropMethod
== "scp" )
1133 std::string oldWorkingDirectory
;
1134 if ( this->CTest
->GetCTestConfiguration("DropSiteUser").size() > 0 )
1136 url
+= this->CTest
->GetCTestConfiguration("DropSiteUser") + "@";
1138 url
+= this->CTest
->GetCTestConfiguration("DropSite") + ":" +
1139 this->CTest
->GetCTestConfiguration("DropLocation");
1141 // change to the build directory so that we can uses a relative path
1142 // on windows since scp dosn't support "c:" a drive in the path
1143 oldWorkingDirectory
= cmSystemTools::GetCurrentWorkingDirectory();
1144 cmSystemTools::ChangeDirectory(buildDirectory
.c_str());
1146 if ( !this->SubmitUsingSCP(
1147 this->CTest
->GetCTestConfiguration("ScpCommand"),
1148 "Testing/"+this->CTest
->GetCurrentTag(), files
, prefix
, url
) )
1150 cmSystemTools::ChangeDirectory(oldWorkingDirectory
.c_str());
1151 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1152 " Problems when submitting via SCP"
1154 ofs
<< " Problems when submitting via SCP" << std::endl
;
1157 cmSystemTools::ChangeDirectory(oldWorkingDirectory
.c_str());
1158 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Submission successful"
1160 ofs
<< " Submission successful" << std::endl
;
1163 else if ( dropMethod
== "cp" )
1165 std::string location
1166 = this->CTest
->GetCTestConfiguration("DropLocation");
1169 // change to the build directory so that we can uses a relative path
1170 // on windows since scp dosn't support "c:" a drive in the path
1172 oldWorkingDirectory
= cmSystemTools::GetCurrentWorkingDirectory();
1173 cmSystemTools::ChangeDirectory(buildDirectory
.c_str());
1174 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, " Change directory: "
1175 << buildDirectory
.c_str() << std::endl
);
1177 if ( !this->SubmitUsingCP(
1178 "Testing/"+this->CTest
->GetCurrentTag(),
1183 cmSystemTools::ChangeDirectory(oldWorkingDirectory
.c_str());
1184 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1185 " Problems when submitting via CP"
1187 ofs
<< " Problems when submitting via cp" << std::endl
;
1190 cmSystemTools::ChangeDirectory(oldWorkingDirectory
.c_str());
1191 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Submission successful"
1193 ofs
<< " Submission successful" << std::endl
;
1197 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Unknown submission method: \""
1198 << dropMethod
<< "\"" << std::endl
);
1202 //----------------------------------------------------------------------------
1203 std::string
cmCTestSubmitHandler::GetSubmitResultsPrefix()
1205 std::string name
= this->CTest
->GetCTestConfiguration("Site") +
1206 "___" + this->CTest
->GetCTestConfiguration("BuildName") +
1207 "___" + this->CTest
->GetCurrentTag() + "-" +
1208 this->CTest
->GetTestModelString() + "___XML___";
1212 //----------------------------------------------------------------------------
1213 void cmCTestSubmitHandler::SelectParts(std::set
<cmCTest::Part
> const& parts
)
1215 // Check whether each part is selected.
1216 for(cmCTest::Part p
= cmCTest::PartStart
;
1217 p
!= cmCTest::PartCount
; p
= cmCTest::Part(p
+1))
1219 this->SubmitPart
[p
] =
1220 (std::set
<cmCTest::Part
>::const_iterator(parts
.find(p
)) != parts
.end());
1224 //----------------------------------------------------------------------------
1225 void cmCTestSubmitHandler::SelectFiles(cmCTest::SetOfStrings
const& files
)
1227 cmCTest::SetOfStrings::const_iterator it
;
1228 for (it
= files
.begin(); it
!= files
.end(); ++it
)
1230 this->Files
.insert(*it
);