1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmCTestSubmitHandler.cxx,v $
6 Date: $Date: 2008/02/29 19:58:33 $
7 Version: $Revision: 1.30 $
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()
66 this->HTTPProxyType
= 0;
67 this->HTTPProxyAuth
= "";
70 this->FTPProxyType
= 0;
74 //----------------------------------------------------------------------------
75 void cmCTestSubmitHandler::Initialize()
78 this->Superclass::Initialize();
80 this->HTTPProxyType
= 0;
81 this->HTTPProxyAuth
= "";
83 this->FTPProxyType
= 0;
87 //----------------------------------------------------------------------------
88 bool cmCTestSubmitHandler::SubmitUsingFTP(const cmStdString
& localprefix
,
89 const std::set
<cmStdString
>& files
,
90 const cmStdString
& remoteprefix
,
91 const cmStdString
& url
)
96 char error_buffer
[1024];
98 /* In windows, this will init the winsock stuff */
99 ::curl_global_init(CURL_GLOBAL_ALL
);
101 cmCTest::SetOfStrings::const_iterator file
;
102 for ( file
= files
.begin(); file
!= files
.end(); ++file
)
104 /* get a curl handle */
105 curl
= curl_easy_init();
109 if ( this->FTPProxyType
> 0 )
111 curl_easy_setopt(curl
, CURLOPT_PROXY
, this->FTPProxy
.c_str());
112 switch (this->FTPProxyType
)
115 curl_easy_setopt(curl
, CURLOPT_PROXYTYPE
, CURLPROXY_SOCKS4
);
118 curl_easy_setopt(curl
, CURLOPT_PROXYTYPE
, CURLPROXY_SOCKS5
);
121 curl_easy_setopt(curl
, CURLOPT_PROXYTYPE
, CURLPROXY_HTTP
);
126 ::curl_easy_setopt(curl
, CURLOPT_UPLOAD
, 1) ;
128 cmStdString local_file
= *file
;
129 if ( !cmSystemTools::FileExists(local_file
.c_str()) )
131 local_file
= localprefix
+ "/" + *file
;
133 cmStdString upload_as
134 = url
+ "/" + remoteprefix
+ cmSystemTools::GetFilenameName(*file
);
137 if ( ::stat(local_file
.c_str(), &st
) )
139 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Cannot find file: "
140 << local_file
.c_str() << std::endl
);
141 ::curl_easy_cleanup(curl
);
142 ::curl_global_cleanup();
146 ftpfile
= ::fopen(local_file
.c_str(), "rb");
147 *this->LogFile
<< "\tUpload file: " << local_file
.c_str() << " to "
148 << upload_as
.c_str() << std::endl
;
149 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, " Upload file: "
150 << local_file
.c_str() << " to "
151 << upload_as
.c_str() << std::endl
);
153 ::curl_easy_setopt(curl
, CURLOPT_VERBOSE
, 1);
156 ::curl_easy_setopt(curl
,CURLOPT_URL
, upload_as
.c_str());
158 // now specify which file to upload
159 ::curl_easy_setopt(curl
, CURLOPT_INFILE
, ftpfile
);
161 // and give the size of the upload (optional)
162 ::curl_easy_setopt(curl
, CURLOPT_INFILESIZE
,
163 static_cast<long>(st
.st_size
));
165 // and give curl the buffer for errors
166 ::curl_easy_setopt(curl
, CURLOPT_ERRORBUFFER
, &error_buffer
);
168 // specify handler for output
169 ::curl_easy_setopt(curl
, CURLOPT_WRITEFUNCTION
,
170 cmCTestSubmitHandlerWriteMemoryCallback
);
171 ::curl_easy_setopt(curl
, CURLOPT_DEBUGFUNCTION
,
172 cmCTestSubmitHandlerCurlDebugCallback
);
174 /* we pass our 'chunk' struct to the callback function */
175 cmCTestSubmitHandlerVectorOfChar chunk
;
176 cmCTestSubmitHandlerVectorOfChar chunkDebug
;
177 ::curl_easy_setopt(curl
, CURLOPT_FILE
, (void *)&chunk
);
178 ::curl_easy_setopt(curl
, CURLOPT_DEBUGDATA
, (void *)&chunkDebug
);
180 // Now run off and do what you've been told!
181 res
= ::curl_easy_perform(curl
);
183 if ( chunk
.size() > 0 )
185 cmCTestLog(this->CTest
, DEBUG
, "CURL output: ["
186 << cmCTestLogWrite(&*chunk
.begin(), chunk
.size()) << "]"
189 if ( chunkDebug
.size() > 0 )
191 cmCTestLog(this->CTest
, DEBUG
, "CURL debug output: ["
192 << cmCTestLogWrite(&*chunkDebug
.begin(), chunkDebug
.size()) << "]"
199 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
200 " Error when uploading file: "
201 << local_file
.c_str() << std::endl
);
202 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Error message was: "
203 << error_buffer
<< std::endl
);
204 *this->LogFile
<< " Error when uploading file: "
205 << local_file
.c_str()
207 << " Error message was: "
208 << error_buffer
<< std::endl
209 << " Curl output was: ";
210 // avoid dereference of empty vector
213 *this->LogFile
<< cmCTestLogWrite(&*chunk
.begin(), chunk
.size());
214 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "CURL output: ["
215 << cmCTestLogWrite(&*chunk
.begin(), chunk
.size()) << "]"
218 *this->LogFile
<< std::endl
;
219 ::curl_easy_cleanup(curl
);
220 ::curl_global_cleanup();
224 ::curl_easy_cleanup(curl
);
225 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Uploaded: " + local_file
229 ::curl_global_cleanup();
233 //----------------------------------------------------------------------------
234 // Uploading files is simpler
235 bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString
& localprefix
,
236 const std::set
<cmStdString
>& files
,
237 const cmStdString
& remoteprefix
,
238 const cmStdString
& url
)
243 char error_buffer
[1024];
245 /* In windows, this will init the winsock stuff */
246 ::curl_global_init(CURL_GLOBAL_ALL
);
248 cmStdString::size_type kk
;
249 cmCTest::SetOfStrings::const_iterator file
;
250 for ( file
= files
.begin(); file
!= files
.end(); ++file
)
252 /* get a curl handle */
253 curl
= curl_easy_init();
258 if ( this->HTTPProxyType
> 0 )
260 curl_easy_setopt(curl
, CURLOPT_PROXY
, this->HTTPProxy
.c_str());
261 switch (this->HTTPProxyType
)
264 curl_easy_setopt(curl
, CURLOPT_PROXYTYPE
, CURLPROXY_SOCKS4
);
267 curl_easy_setopt(curl
, CURLOPT_PROXYTYPE
, CURLPROXY_SOCKS5
);
270 curl_easy_setopt(curl
, CURLOPT_PROXYTYPE
, CURLPROXY_HTTP
);
271 if (this->HTTPProxyAuth
.size() > 0)
273 curl_easy_setopt(curl
, CURLOPT_PROXYUSERPWD
,
274 this->HTTPProxyAuth
.c_str());
279 /* enable uploading */
280 curl_easy_setopt(curl
, CURLOPT_UPLOAD
, 1) ;
282 /* HTTP PUT please */
283 ::curl_easy_setopt(curl
, CURLOPT_PUT
, 1);
284 ::curl_easy_setopt(curl
, CURLOPT_VERBOSE
, 1);
286 cmStdString local_file
= *file
;
287 if ( !cmSystemTools::FileExists(local_file
.c_str()) )
289 local_file
= localprefix
+ "/" + *file
;
291 cmStdString remote_file
292 = remoteprefix
+ cmSystemTools::GetFilenameName(*file
);
294 *this->LogFile
<< "\tUpload file: " << local_file
.c_str() << " to "
295 << remote_file
.c_str() << std::endl
;
297 cmStdString ofile
= "";
298 for ( kk
= 0; kk
< remote_file
.size(); kk
++ )
300 char c
= remote_file
[kk
];
301 char hexCh
[4] = { 0, 0, 0, 0 };
313 sprintf(hexCh
, "%%%02X", (int)c
);
320 cmStdString upload_as
321 = url
+ ((url
.find("?",0) == cmStdString::npos
) ? "?" : "&")
322 + "FileName=" + ofile
;
325 if ( ::stat(local_file
.c_str(), &st
) )
327 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Cannot find file: "
328 << local_file
.c_str() << std::endl
);
329 ::curl_easy_cleanup(curl
);
330 ::curl_global_cleanup();
334 ftpfile
= ::fopen(local_file
.c_str(), "rb");
335 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, " Upload file: "
336 << local_file
.c_str() << " to "
337 << upload_as
.c_str() << " Size: " << st
.st_size
<< std::endl
);
341 ::curl_easy_setopt(curl
,CURLOPT_URL
, upload_as
.c_str());
343 // now specify which file to upload
344 ::curl_easy_setopt(curl
, CURLOPT_INFILE
, ftpfile
);
346 // and give the size of the upload (optional)
347 ::curl_easy_setopt(curl
, CURLOPT_INFILESIZE
,
348 static_cast<long>(st
.st_size
));
350 // and give curl the buffer for errors
351 ::curl_easy_setopt(curl
, CURLOPT_ERRORBUFFER
, &error_buffer
);
353 // specify handler for output
354 ::curl_easy_setopt(curl
, CURLOPT_WRITEFUNCTION
,
355 cmCTestSubmitHandlerWriteMemoryCallback
);
356 ::curl_easy_setopt(curl
, CURLOPT_DEBUGFUNCTION
,
357 cmCTestSubmitHandlerCurlDebugCallback
);
359 /* we pass our 'chunk' struct to the callback function */
360 cmCTestSubmitHandlerVectorOfChar chunk
;
361 cmCTestSubmitHandlerVectorOfChar chunkDebug
;
362 ::curl_easy_setopt(curl
, CURLOPT_FILE
, (void *)&chunk
);
363 ::curl_easy_setopt(curl
, CURLOPT_DEBUGDATA
, (void *)&chunkDebug
);
365 // Now run off and do what you've been told!
366 res
= ::curl_easy_perform(curl
);
368 if ( chunk
.size() > 0 )
370 cmCTestLog(this->CTest
, DEBUG
, "CURL output: ["
371 << cmCTestLogWrite(&*chunk
.begin(), chunk
.size()) << "]"
374 if ( chunkDebug
.size() > 0 )
376 cmCTestLog(this->CTest
, DEBUG
, "CURL debug output: ["
377 << cmCTestLogWrite(&*chunkDebug
.begin(), chunkDebug
.size()) << "]"
384 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
385 " Error when uploading file: "
386 << local_file
.c_str() << std::endl
);
387 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Error message was: "
388 << error_buffer
<< std::endl
);
389 *this->LogFile
<< " Error when uploading file: "
390 << local_file
.c_str()
392 << " Error message was: " << error_buffer
394 // avoid deref of begin for zero size array
397 *this->LogFile
<< " Curl output was: "
398 << cmCTestLogWrite(&*chunk
.begin(), chunk
.size())
400 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "CURL output: ["
401 << cmCTestLogWrite(&*chunk
.begin(), chunk
.size()) << "]"
404 ::curl_easy_cleanup(curl
);
405 ::curl_global_cleanup();
409 ::curl_easy_cleanup(curl
);
410 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Uploaded: " + local_file
414 ::curl_global_cleanup();
418 //----------------------------------------------------------------------------
419 bool cmCTestSubmitHandler::TriggerUsingHTTP(
420 const std::set
<cmStdString
>& files
,
421 const cmStdString
& remoteprefix
,
422 const cmStdString
& url
)
425 char error_buffer
[1024];
427 /* In windows, this will init the winsock stuff */
428 ::curl_global_init(CURL_GLOBAL_ALL
);
430 cmCTest::SetOfStrings::const_iterator file
;
431 for ( file
= files
.begin(); file
!= files
.end(); ++file
)
433 /* get a curl handle */
434 curl
= curl_easy_init();
438 if ( this->HTTPProxyType
> 0 )
440 curl_easy_setopt(curl
, CURLOPT_PROXY
, this->HTTPProxy
.c_str());
441 switch (this->HTTPProxyType
)
444 curl_easy_setopt(curl
, CURLOPT_PROXYTYPE
, CURLPROXY_SOCKS4
);
447 curl_easy_setopt(curl
, CURLOPT_PROXYTYPE
, CURLPROXY_SOCKS5
);
450 curl_easy_setopt(curl
, CURLOPT_PROXYTYPE
, CURLPROXY_HTTP
);
451 if (this->HTTPProxyAuth
.size() > 0)
453 curl_easy_setopt(curl
, CURLOPT_PROXYUSERPWD
,
454 this->HTTPProxyAuth
.c_str());
459 ::curl_easy_setopt(curl
, CURLOPT_VERBOSE
, 1);
461 // and give curl the buffer for errors
462 ::curl_easy_setopt(curl
, CURLOPT_ERRORBUFFER
, &error_buffer
);
464 // specify handler for output
465 ::curl_easy_setopt(curl
, CURLOPT_WRITEFUNCTION
,
466 cmCTestSubmitHandlerWriteMemoryCallback
);
467 ::curl_easy_setopt(curl
, CURLOPT_DEBUGFUNCTION
,
468 cmCTestSubmitHandlerCurlDebugCallback
);
470 /* we pass our 'chunk' struct to the callback function */
471 cmCTestSubmitHandlerVectorOfChar chunk
;
472 cmCTestSubmitHandlerVectorOfChar chunkDebug
;
473 ::curl_easy_setopt(curl
, CURLOPT_FILE
, (void *)&chunk
);
474 ::curl_easy_setopt(curl
, CURLOPT_DEBUGDATA
, (void *)&chunkDebug
);
477 = remoteprefix
+ cmSystemTools::GetFilenameName(*file
);
478 cmStdString ofile
= "";
479 cmStdString::iterator kk
;
480 for ( kk
= rfile
.begin(); kk
< rfile
.end(); ++ kk
)
483 char hexCh
[4] = { 0, 0, 0, 0 };
495 sprintf(hexCh
, "%%%02X", (int)c
);
503 = url
+ ((url
.find("?",0) == cmStdString::npos
) ? "?" : "&")
504 + "xmlfile=" + ofile
;
505 *this->LogFile
<< "Trigger url: " << turl
.c_str() << std::endl
;
506 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, " Trigger url: "
507 << turl
.c_str() << std::endl
);
508 curl_easy_setopt(curl
, CURLOPT_URL
, turl
.c_str());
509 if ( curl_easy_perform(curl
) )
511 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Error when triggering: "
512 << turl
.c_str() << std::endl
);
513 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Error message was: "
514 << error_buffer
<< std::endl
);
515 *this->LogFile
<< "\tTrigerring failed with error: " << error_buffer
517 << " Error message was: " << error_buffer
522 << " Curl output was: "
523 << cmCTestLogWrite(&*chunk
.begin(), chunk
.size()) << std::endl
;
524 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "CURL output: ["
525 << cmCTestLogWrite(&*chunk
.begin(), chunk
.size()) << "]"
528 ::curl_easy_cleanup(curl
);
529 ::curl_global_cleanup();
533 if ( chunk
.size() > 0 )
535 cmCTestLog(this->CTest
, DEBUG
, "CURL output: ["
536 << cmCTestLogWrite(&*chunk
.begin(), chunk
.size()) << "]"
539 if ( chunkDebug
.size() > 0 )
541 cmCTestLog(this->CTest
, DEBUG
, "CURL debug output: ["
542 << cmCTestLogWrite(&*chunkDebug
.begin(), chunkDebug
.size())
543 << "]" << std::endl
);
547 ::curl_easy_cleanup(curl
);
548 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, std::endl
);
551 ::curl_global_cleanup();
552 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Dart server triggered..."
557 //----------------------------------------------------------------------------
558 bool cmCTestSubmitHandler::SubmitUsingSCP(
559 const cmStdString
& scp_command
,
560 const cmStdString
& localprefix
,
561 const std::set
<cmStdString
>& files
,
562 const cmStdString
& remoteprefix
,
563 const cmStdString
& url
)
565 if ( !scp_command
.size() || !localprefix
.size() ||
566 !files
.size() || !remoteprefix
.size() || !url
.size() )
570 std::vector
<const char*> argv
;
571 argv
.push_back(scp_command
.c_str()); // Scp command
572 argv
.push_back(scp_command
.c_str()); // Dummy string for file
573 argv
.push_back(scp_command
.c_str()); // Dummy string for remote url
576 cmsysProcess
* cp
= cmsysProcess_New();
577 cmsysProcess_SetOption(cp
, cmsysProcess_Option_HideWindow
, 1);
578 //cmsysProcess_SetTimeout(cp, timeout);
582 cmCTest::SetOfStrings::const_iterator file
;
583 for ( file
= files
.begin(); file
!= files
.end(); ++file
)
587 std::string lfname
= localprefix
;
588 cmSystemTools::ConvertToUnixSlashes(lfname
);
589 lfname
+= "/" + *file
;
590 lfname
= cmSystemTools::ConvertToOutputPath(lfname
.c_str());
591 argv
[1] = lfname
.c_str();
592 std::string rfname
= url
+ "/" + remoteprefix
+ *file
;
593 argv
[2] = rfname
.c_str();
594 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, "Execute \"" << argv
[0]
595 << "\" \"" << argv
[1] << "\" \""
596 << argv
[2] << "\"" << std::endl
);
597 *this->LogFile
<< "Execute \"" << argv
[0] << "\" \"" << argv
[1] << "\" \""
598 << argv
[2] << "\"" << std::endl
;
600 cmsysProcess_SetCommand(cp
, &*argv
.begin());
601 cmsysProcess_Execute(cp
);
605 while(cmsysProcess_WaitForData(cp
, &data
, &length
, 0))
607 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
608 cmCTestLogWrite(data
, length
));
611 cmsysProcess_WaitForExit(cp
, 0);
613 int result
= cmsysProcess_GetState(cp
);
615 if(result
== cmsysProcess_State_Exited
)
617 retVal
= cmsysProcess_GetExitValue(cp
);
620 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, "\tSCP returned: "
621 << retVal
<< std::endl
);
622 *this->LogFile
<< "\tSCP returned: " << retVal
<< std::endl
;
626 else if(result
== cmsysProcess_State_Exception
)
628 retVal
= cmsysProcess_GetExitException(cp
);
629 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "\tThere was an exception: "
630 << retVal
<< std::endl
);
631 *this->LogFile
<< "\tThere was an exception: " << retVal
<< std::endl
;
634 else if(result
== cmsysProcess_State_Expired
)
636 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "\tThere was a timeout"
638 *this->LogFile
<< "\tThere was a timeout" << std::endl
;
641 else if(result
== cmsysProcess_State_Error
)
643 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "\tError executing SCP: "
644 << cmsysProcess_GetErrorString(cp
) << std::endl
);
645 *this->LogFile
<< "\tError executing SCP: "
646 << cmsysProcess_GetErrorString(cp
) << std::endl
;
650 cmsysProcess_Delete(cp
);
658 //----------------------------------------------------------------------------
659 bool cmCTestSubmitHandler::SubmitUsingXMLRPC(const cmStdString
& localprefix
,
660 const std::set
<cmStdString
>& files
,
661 const cmStdString
& remoteprefix
,
662 const cmStdString
& url
)
665 char ctestString
[] = "CTest";
666 std::string ctestVersionString
= cmVersion::GetCMakeVersion();
667 char* ctestVersion
= const_cast<char*>(ctestVersionString
.c_str());
669 cmStdString realURL
= url
+ "/" + remoteprefix
+ "/Command/";
671 /* Start up our XML-RPC client library. */
672 xmlrpc_client_init(XMLRPC_CLIENT_NO_FLAGS
, ctestString
, ctestVersion
);
674 /* Initialize our error-handling environment. */
675 xmlrpc_env_init(&env
);
677 /* Call the famous server at UserLand. */
678 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Submitting to: "
679 << realURL
.c_str() << " (" << remoteprefix
.c_str() << ")" << std::endl
);
680 cmCTest::SetOfStrings::const_iterator file
;
681 for ( file
= files
.begin(); file
!= files
.end(); ++file
)
683 xmlrpc_value
*result
;
685 cmStdString local_file
= *file
;
686 if ( !cmSystemTools::FileExists(local_file
.c_str()) )
688 local_file
= localprefix
+ "/" + *file
;
690 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Submit file: "
691 << local_file
.c_str() << std::endl
);
693 if ( ::stat(local_file
.c_str(), &st
) )
695 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Cannot find file: "
696 << local_file
.c_str() << std::endl
);
700 // off_t can be bigger than size_t. fread takes size_t.
701 // make sure the file is not too big.
702 if(static_cast<off_t
>(static_cast<size_t>(st
.st_size
)) !=
703 static_cast<off_t
>(st
.st_size
))
705 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " File too big: "
706 << local_file
.c_str() << std::endl
);
709 size_t fileSize
= static_cast<size_t>(st
.st_size
);
710 FILE* fp
= fopen(local_file
.c_str(), "rb");
713 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Cannot open file: "
714 << local_file
.c_str() << std::endl
);
718 unsigned char *fileBuffer
= new unsigned char[fileSize
];
719 if ( fread(fileBuffer
, 1, fileSize
, fp
) != fileSize
)
721 delete [] fileBuffer
;
723 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Cannot read file: "
724 << local_file
.c_str() << std::endl
);
729 char remoteCommand
[] = "Submit.put";
730 char* pRealURL
= const_cast<char*>(realURL
.c_str());
731 result
= xmlrpc_client_call(&env
, pRealURL
, remoteCommand
,
732 "(6)", fileBuffer
, (xmlrpc_int32
)fileSize
);
734 delete [] fileBuffer
;
736 if ( env
.fault_occurred
)
738 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Submission problem: "
739 << env
.fault_string
<< " (" << env
.fault_code
<< ")" << std::endl
);
740 xmlrpc_env_clean(&env
);
741 xmlrpc_client_cleanup();
745 /* Dispose of our result value. */
746 xmlrpc_DECREF(result
);
749 /* Clean up our error-handling environment. */
750 xmlrpc_env_clean(&env
);
752 /* Shutdown our XML-RPC client library. */
753 xmlrpc_client_cleanup();
757 //----------------------------------------------------------------------------
758 int cmCTestSubmitHandler::ProcessHandler()
760 std::string iscdash
= this->CTest
->GetCTestConfiguration("IsCDash");
761 // cdash does not need to trigger so just return true
767 const std::string
&buildDirectory
768 = this->CTest
->GetCTestConfiguration("BuildDirectory");
769 if ( buildDirectory
.size() == 0 )
771 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
772 "Cannot find BuildDirectory key in the DartConfiguration.tcl"
777 if ( getenv("HTTP_PROXY") )
779 this->HTTPProxyType
= 1;
780 this->HTTPProxy
= getenv("HTTP_PROXY");
781 if ( getenv("HTTP_PROXY_PORT") )
783 this->HTTPProxy
+= ":";
784 this->HTTPProxy
+= getenv("HTTP_PROXY_PORT");
786 if ( getenv("HTTP_PROXY_TYPE") )
788 cmStdString type
= getenv("HTTP_PROXY_TYPE");
789 // HTTP/SOCKS4/SOCKS5
790 if ( type
== "HTTP" )
792 this->HTTPProxyType
= 1;
794 else if ( type
== "SOCKS4" )
796 this->HTTPProxyType
= 2;
798 else if ( type
== "SOCKS5" )
800 this->HTTPProxyType
= 3;
803 if ( getenv("HTTP_PROXY_USER") )
805 this->HTTPProxyAuth
= getenv("HTTP_PROXY_USER");
807 if ( getenv("HTTP_PROXY_PASSWD") )
809 this->HTTPProxyAuth
+= ":";
810 this->HTTPProxyAuth
+= getenv("HTTP_PROXY_PASSWD");
814 if ( getenv("FTP_PROXY") )
816 this->FTPProxyType
= 1;
817 this->FTPProxy
= getenv("FTP_PROXY");
818 if ( getenv("FTP_PROXY_PORT") )
820 this->FTPProxy
+= ":";
821 this->FTPProxy
+= getenv("FTP_PROXY_PORT");
823 if ( getenv("FTP_PROXY_TYPE") )
825 cmStdString type
= getenv("FTP_PROXY_TYPE");
826 // HTTP/SOCKS4/SOCKS5
827 if ( type
== "HTTP" )
829 this->FTPProxyType
= 1;
831 else if ( type
== "SOCKS4" )
833 this->FTPProxyType
= 2;
835 else if ( type
== "SOCKS5" )
837 this->FTPProxyType
= 3;
842 if ( this->HTTPProxy
.size() > 0 )
844 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Use HTTP Proxy: "
845 << this->HTTPProxy
<< std::endl
);
847 if ( this->FTPProxy
.size() > 0 )
849 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Use FTP Proxy: "
850 << this->FTPProxy
<< std::endl
);
852 cmGeneratedFileStream ofs
;
853 this->StartLogFile("Submit", ofs
);
855 cmCTest::SetOfStrings files
;
856 std::string prefix
= this->GetSubmitResultsPrefix();
858 // Check if test is enabled
859 this->CTest
->AddIfExists(files
, "Update.xml");
860 this->CTest
->AddIfExists(files
, "Configure.xml");
861 this->CTest
->AddIfExists(files
, "Build.xml");
862 this->CTest
->AddIfExists(files
, "Test.xml");
863 if ( this->CTest
->AddIfExists(files
, "Coverage.xml") )
865 cmCTest::VectorOfStrings gfiles
;
867 = buildDirectory
+ "/Testing/" + this->CTest
->GetCurrentTag();
868 std::string::size_type glen
= gpath
.size() + 1;
869 gpath
= gpath
+ "/CoverageLog*";
870 cmCTestLog(this->CTest
, DEBUG
, "Globbing for: " << gpath
.c_str()
872 if ( cmSystemTools::SimpleGlob(gpath
, gfiles
, 1) )
875 for ( cc
= 0; cc
< gfiles
.size(); cc
++ )
877 gfiles
[cc
] = gfiles
[cc
].substr(glen
);
878 cmCTestLog(this->CTest
, DEBUG
, "Glob file: " << gfiles
[cc
].c_str()
880 files
.insert(gfiles
[cc
]);
885 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Problem globbing" << std::endl
);
888 this->CTest
->AddIfExists(files
, "DynamicAnalysis.xml");
889 this->CTest
->AddIfExists(files
, "Purify.xml");
890 this->CTest
->AddIfExists(files
, "Notes.xml");
892 cmCTest::SetOfStrings::iterator it
;
893 for ( it
= this->CTest
->GetSubmitFiles()->begin();
894 it
!= this->CTest
->GetSubmitFiles()->end();
897 files
.insert(files
.end(), *it
);
902 ofs
<< "Upload files:" << std::endl
;
904 for ( it
= files
.begin(); it
!= files
.end(); ++ it
)
906 ofs
<< cnt
<< "\t" << it
->c_str() << std::endl
;
910 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, "Submit files (using "
911 << this->CTest
->GetCTestConfiguration("DropMethod") << ")"
913 const char* specificTrack
= this->CTest
->GetSpecificTrack();
916 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Send to track: "
917 << specificTrack
<< std::endl
);
919 this->SetLogFile(&ofs
);
920 if ( this->CTest
->GetCTestConfiguration("DropMethod") == "" ||
921 this->CTest
->GetCTestConfiguration("DropMethod") == "ftp" )
923 ofs
<< "Using drop method: FTP" << std::endl
;
924 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Using FTP submit method"
926 << " Drop site: ftp://");
927 std::string url
= "ftp://";
928 url
+= cmCTest::MakeURLSafe(
929 this->CTest
->GetCTestConfiguration("DropSiteUser")) + ":" +
930 cmCTest::MakeURLSafe(this->CTest
->GetCTestConfiguration(
931 "DropSitePassword")) + "@" +
932 this->CTest
->GetCTestConfiguration("DropSite") +
933 cmCTest::MakeURLSafe(
934 this->CTest
->GetCTestConfiguration("DropLocation"));
935 if ( this->CTest
->GetCTestConfiguration("DropSiteUser").size() > 0 )
937 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
938 this->CTest
->GetCTestConfiguration(
939 "DropSiteUser").c_str());
940 if ( this->CTest
->GetCTestConfiguration("DropSitePassword").size() > 0 )
942 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, ":******");
944 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, "@");
946 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
947 this->CTest
->GetCTestConfiguration("DropSite")
948 << this->CTest
->GetCTestConfiguration("DropLocation") << std::endl
);
949 if ( !this->SubmitUsingFTP(buildDirectory
+ "/Testing/"
950 + this->CTest
->GetCurrentTag(),
951 files
, prefix
, url
) )
953 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
954 " Problems when submitting via FTP"
956 ofs
<< " Problems when submitting via FTP" << std::endl
;
961 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Using HTTP trigger method"
964 << this->CTest
->GetCTestConfiguration("TriggerSite")
966 if ( !this->TriggerUsingHTTP(files
, prefix
,
967 this->CTest
->GetCTestConfiguration("TriggerSite")) )
969 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
970 " Problems when triggering via HTTP" << std::endl
);
971 ofs
<< " Problems when triggering via HTTP" << std::endl
;
974 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Submission successful"
976 ofs
<< " Submission successful" << std::endl
;
980 else if ( this->CTest
->GetCTestConfiguration("DropMethod") == "http" )
982 ofs
<< "Using drop method: HTTP" << std::endl
;
983 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Using HTTP submit method"
985 << " Drop site: http://");
986 std::string url
= "http://";
987 if ( this->CTest
->GetCTestConfiguration("DropSiteUser").size() > 0 )
989 url
+= this->CTest
->GetCTestConfiguration("DropSiteUser");
990 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
991 this->CTest
->GetCTestConfiguration("DropSiteUser").c_str());
992 if ( this->CTest
->GetCTestConfiguration("DropSitePassword").size() > 0 )
994 url
+= ":" + this->CTest
->GetCTestConfiguration("DropSitePassword");
995 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, ":******");
998 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, "@");
1000 url
+= this->CTest
->GetCTestConfiguration("DropSite") +
1001 this->CTest
->GetCTestConfiguration("DropLocation");
1002 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
1003 this->CTest
->GetCTestConfiguration("DropSite")
1004 << this->CTest
->GetCTestConfiguration("DropLocation") << std::endl
);
1005 if ( !this->SubmitUsingHTTP(buildDirectory
+ "/Testing/" +
1006 this->CTest
->GetCurrentTag(), files
, prefix
, url
) )
1008 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1009 " Problems when submitting via HTTP" << std::endl
);
1010 ofs
<< " Problems when submitting via HTTP" << std::endl
;
1015 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Using HTTP trigger method"
1017 << " Trigger site: "
1018 << this->CTest
->GetCTestConfiguration("TriggerSite")
1020 if ( !this->TriggerUsingHTTP(files
, prefix
,
1021 this->CTest
->GetCTestConfiguration("TriggerSite")) )
1023 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1024 " Problems when triggering via HTTP" << std::endl
);
1025 ofs
<< " Problems when triggering via HTTP" << std::endl
;
1029 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Submission successful"
1031 ofs
<< " Submission successful" << std::endl
;
1034 else if ( this->CTest
->GetCTestConfiguration("DropMethod") == "xmlrpc" )
1036 ofs
<< "Using drop method: XML-RPC" << std::endl
;
1037 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Using XML-RPC submit method"
1039 std::string url
= this->CTest
->GetCTestConfiguration("DropSite");
1040 prefix
= this->CTest
->GetCTestConfiguration("DropLocation");
1041 if ( !this->SubmitUsingXMLRPC(buildDirectory
+ "/Testing/" +
1042 this->CTest
->GetCurrentTag(), files
, prefix
, url
) )
1044 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1045 " Problems when submitting via XML-RPC" << std::endl
);
1046 ofs
<< " Problems when submitting via XML-RPC" << std::endl
;
1049 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Submission successful"
1051 ofs
<< " Submission successful" << std::endl
;
1054 else if ( this->CTest
->GetCTestConfiguration("DropMethod") == "scp" )
1057 std::string oldWorkingDirectory
;
1058 if ( this->CTest
->GetCTestConfiguration("DropSiteUser").size() > 0 )
1060 url
+= this->CTest
->GetCTestConfiguration("DropSiteUser") + "@";
1062 url
+= this->CTest
->GetCTestConfiguration("DropSite") + ":" +
1063 this->CTest
->GetCTestConfiguration("DropLocation");
1065 // change to the build directory so that we can uses a relative path
1066 // on windows since scp dosn't support "c:" a drive in the path
1067 oldWorkingDirectory
= cmSystemTools::GetCurrentWorkingDirectory();
1068 cmSystemTools::ChangeDirectory(buildDirectory
.c_str());
1070 if ( !this->SubmitUsingSCP(
1071 this->CTest
->GetCTestConfiguration("ScpCommand"),
1072 "Testing/"+this->CTest
->GetCurrentTag(), files
, prefix
, url
) )
1074 cmSystemTools::ChangeDirectory(oldWorkingDirectory
.c_str());
1075 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1076 " Problems when submitting via SCP"
1078 ofs
<< " Problems when submitting via SCP" << std::endl
;
1081 cmSystemTools::ChangeDirectory(oldWorkingDirectory
.c_str());
1082 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Submission successful"
1084 ofs
<< " Submission successful" << std::endl
;
1088 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Unknown submission method: \""
1089 << this->CTest
->GetCTestConfiguration("DropMethod") << "\"" << std::endl
);
1093 //----------------------------------------------------------------------------
1094 std::string
cmCTestSubmitHandler::GetSubmitResultsPrefix()
1096 std::string name
= this->CTest
->GetCTestConfiguration("Site") +
1097 "___" + this->CTest
->GetCTestConfiguration("BuildName") +
1098 "___" + this->CTest
->GetCurrentTag() + "-" +
1099 this->CTest
->GetTestModelString() + "___XML___";