1
0

cmCTestSubmitHandler.cxx 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "cmCTestSubmitHandler.h"
  14. #include "cmSystemTools.h"
  15. #include "cmVersion.h"
  16. #include "cmGeneratedFileStream.h"
  17. #include "cmCTest.h"
  18. #include <cmsys/Process.h>
  19. #include <cmsys/Base64.h>
  20. // For XML-RPC submission
  21. #include "xmlrpc.h"
  22. #include "xmlrpc_client.h"
  23. // For curl submission
  24. #include "cmcurl/curl/curl.h"
  25. #include <sys/stat.h>
  26. typedef std::vector<char> cmCTestSubmitHandlerVectorOfChar;
  27. static size_t
  28. cmCTestSubmitHandlerWriteMemoryCallback(void *ptr, size_t size, size_t nmemb,
  29. void *data)
  30. {
  31. register int realsize = (int)(size * nmemb);
  32. cmCTestSubmitHandlerVectorOfChar *vec
  33. = static_cast<cmCTestSubmitHandlerVectorOfChar*>(data);
  34. const char* chPtr = static_cast<char*>(ptr);
  35. vec->insert(vec->end(), chPtr, chPtr + realsize);
  36. return realsize;
  37. }
  38. static size_t
  39. cmCTestSubmitHandlerCurlDebugCallback(CURL *, curl_infotype, char *chPtr,
  40. size_t size, void *data)
  41. {
  42. cmCTestSubmitHandlerVectorOfChar *vec
  43. = static_cast<cmCTestSubmitHandlerVectorOfChar*>(data);
  44. vec->insert(vec->end(), chPtr, chPtr + size);
  45. return size;
  46. }
  47. //----------------------------------------------------------------------------
  48. cmCTestSubmitHandler::cmCTestSubmitHandler() : HTTPProxy(), FTPProxy()
  49. {
  50. this->HTTPProxy = "";
  51. this->HTTPProxyType = 0;
  52. this->HTTPProxyAuth = "";
  53. this->FTPProxy = "";
  54. this->FTPProxyType = 0;
  55. }
  56. //----------------------------------------------------------------------------
  57. void cmCTestSubmitHandler::Initialize()
  58. {
  59. this->Superclass::Initialize();
  60. this->HTTPProxy = "";
  61. this->HTTPProxyType = 0;
  62. this->HTTPProxyAuth = "";
  63. this->FTPProxy = "";
  64. this->FTPProxyType = 0;
  65. this->LogFile = 0;
  66. }
  67. //----------------------------------------------------------------------------
  68. bool cmCTestSubmitHandler::SubmitUsingFTP(const cmStdString& localprefix,
  69. const std::set<cmStdString>& files,
  70. const cmStdString& remoteprefix,
  71. const cmStdString& url)
  72. {
  73. CURL *curl;
  74. CURLcode res;
  75. FILE* ftpfile;
  76. char error_buffer[1024];
  77. /* In windows, this will init the winsock stuff */
  78. ::curl_global_init(CURL_GLOBAL_ALL);
  79. cmCTest::SetOfStrings::const_iterator file;
  80. for ( file = files.begin(); file != files.end(); ++file )
  81. {
  82. /* get a curl handle */
  83. curl = curl_easy_init();
  84. if(curl)
  85. {
  86. // Using proxy
  87. if ( this->FTPProxyType > 0 )
  88. {
  89. curl_easy_setopt(curl, CURLOPT_PROXY, this->FTPProxy.c_str());
  90. switch (this->FTPProxyType)
  91. {
  92. case 2:
  93. curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
  94. break;
  95. case 3:
  96. curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
  97. break;
  98. default:
  99. curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
  100. }
  101. }
  102. // enable uploading
  103. ::curl_easy_setopt(curl, CURLOPT_UPLOAD, 1) ;
  104. cmStdString local_file = *file;
  105. if ( !cmSystemTools::FileExists(local_file.c_str()) )
  106. {
  107. local_file = localprefix + "/" + *file;
  108. }
  109. cmStdString upload_as
  110. = url + "/" + remoteprefix + cmSystemTools::GetFilenameName(*file);
  111. struct stat st;
  112. if ( ::stat(local_file.c_str(), &st) )
  113. {
  114. cmCTestLog(this->CTest, ERROR_MESSAGE, " Cannot find file: "
  115. << local_file.c_str() << std::endl);
  116. ::curl_easy_cleanup(curl);
  117. ::curl_global_cleanup();
  118. return false;
  119. }
  120. ftpfile = ::fopen(local_file.c_str(), "rb");
  121. *this->LogFile << "\tUpload file: " << local_file.c_str() << " to "
  122. << upload_as.c_str() << std::endl;
  123. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Upload file: "
  124. << local_file.c_str() << " to "
  125. << upload_as.c_str() << std::endl);
  126. ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
  127. // specify target
  128. ::curl_easy_setopt(curl,CURLOPT_URL, upload_as.c_str());
  129. // now specify which file to upload
  130. ::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
  131. // and give the size of the upload (optional)
  132. ::curl_easy_setopt(curl, CURLOPT_INFILESIZE,
  133. static_cast<long>(st.st_size));
  134. // and give curl the buffer for errors
  135. ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer);
  136. // specify handler for output
  137. ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
  138. cmCTestSubmitHandlerWriteMemoryCallback);
  139. ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
  140. cmCTestSubmitHandlerCurlDebugCallback);
  141. /* we pass our 'chunk' struct to the callback function */
  142. cmCTestSubmitHandlerVectorOfChar chunk;
  143. cmCTestSubmitHandlerVectorOfChar chunkDebug;
  144. ::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&chunk);
  145. ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
  146. // Now run off and do what you've been told!
  147. res = ::curl_easy_perform(curl);
  148. if ( chunk.size() > 0 )
  149. {
  150. cmCTestLog(this->CTest, DEBUG, "CURL output: ["
  151. << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
  152. << std::endl);
  153. }
  154. if ( chunkDebug.size() > 0 )
  155. {
  156. cmCTestLog(this->CTest, DEBUG, "CURL debug output: ["
  157. << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]"
  158. << std::endl);
  159. }
  160. fclose(ftpfile);
  161. if ( res )
  162. {
  163. cmCTestLog(this->CTest, ERROR_MESSAGE,
  164. " Error when uploading file: "
  165. << local_file.c_str() << std::endl);
  166. cmCTestLog(this->CTest, ERROR_MESSAGE, " Error message was: "
  167. << error_buffer << std::endl);
  168. *this->LogFile << " Error when uploading file: "
  169. << local_file.c_str()
  170. << std::endl
  171. << " Error message was: " << error_buffer << std::endl
  172. << " Curl output was: "
  173. << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << std::endl;
  174. cmCTestLog(this->CTest, ERROR_MESSAGE, "CURL output: ["
  175. << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
  176. << std::endl);
  177. ::curl_easy_cleanup(curl);
  178. ::curl_global_cleanup();
  179. return false;
  180. }
  181. // always cleanup
  182. ::curl_easy_cleanup(curl);
  183. cmCTestLog(this->CTest, HANDLER_OUTPUT, " Uploaded: " + local_file
  184. << std::endl);
  185. }
  186. }
  187. ::curl_global_cleanup();
  188. return true;
  189. }
  190. //----------------------------------------------------------------------------
  191. // Uploading files is simpler
  192. bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix,
  193. const std::set<cmStdString>& files,
  194. const cmStdString& remoteprefix,
  195. const cmStdString& url)
  196. {
  197. CURL *curl;
  198. CURLcode res;
  199. FILE* ftpfile;
  200. char error_buffer[1024];
  201. /* In windows, this will init the winsock stuff */
  202. ::curl_global_init(CURL_GLOBAL_ALL);
  203. cmStdString::size_type kk;
  204. cmCTest::SetOfStrings::const_iterator file;
  205. for ( file = files.begin(); file != files.end(); ++file )
  206. {
  207. /* get a curl handle */
  208. curl = curl_easy_init();
  209. if(curl)
  210. {
  211. // Using proxy
  212. if ( this->HTTPProxyType > 0 )
  213. {
  214. curl_easy_setopt(curl, CURLOPT_PROXY, this->HTTPProxy.c_str());
  215. switch (this->HTTPProxyType)
  216. {
  217. case 2:
  218. curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
  219. break;
  220. case 3:
  221. curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
  222. break;
  223. default:
  224. curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
  225. if (this->HTTPProxyAuth.size() > 0)
  226. {
  227. curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD,
  228. this->HTTPProxyAuth.c_str());
  229. }
  230. }
  231. }
  232. /* enable uploading */
  233. curl_easy_setopt(curl, CURLOPT_UPLOAD, 1) ;
  234. /* HTTP PUT please */
  235. ::curl_easy_setopt(curl, CURLOPT_PUT, 1);
  236. ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
  237. cmStdString local_file = *file;
  238. if ( !cmSystemTools::FileExists(local_file.c_str()) )
  239. {
  240. local_file = localprefix + "/" + *file;
  241. }
  242. cmStdString remote_file
  243. = remoteprefix + cmSystemTools::GetFilenameName(*file);
  244. *this->LogFile << "\tUpload file: " << local_file.c_str() << " to "
  245. << remote_file.c_str() << std::endl;
  246. cmStdString ofile = "";
  247. for ( kk = 0; kk < remote_file.size(); kk ++ )
  248. {
  249. char c = remote_file[kk];
  250. char hexCh[4] = { 0, 0, 0, 0 };
  251. hexCh[0] = c;
  252. switch ( c )
  253. {
  254. case '+':
  255. case '?':
  256. case '/':
  257. case '\\':
  258. case '&':
  259. case ' ':
  260. case '=':
  261. case '%':
  262. sprintf(hexCh, "%%%02X", (int)c);
  263. ofile.append(hexCh);
  264. break;
  265. default:
  266. ofile.append(hexCh);
  267. }
  268. }
  269. cmStdString upload_as
  270. = url + ((url.find("?",0) == cmStdString::npos) ? "?" : "&")
  271. + "FileName=" + ofile;
  272. struct stat st;
  273. if ( ::stat(local_file.c_str(), &st) )
  274. {
  275. cmCTestLog(this->CTest, ERROR_MESSAGE, " Cannot find file: "
  276. << local_file.c_str() << std::endl);
  277. ::curl_easy_cleanup(curl);
  278. ::curl_global_cleanup();
  279. return false;
  280. }
  281. ftpfile = ::fopen(local_file.c_str(), "rb");
  282. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Upload file: "
  283. << local_file.c_str() << " to "
  284. << upload_as.c_str() << " Size: " << st.st_size << std::endl);
  285. // specify target
  286. ::curl_easy_setopt(curl,CURLOPT_URL, upload_as.c_str());
  287. // now specify which file to upload
  288. ::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
  289. // and give the size of the upload (optional)
  290. ::curl_easy_setopt(curl, CURLOPT_INFILESIZE,
  291. static_cast<long>(st.st_size));
  292. // and give curl the buffer for errors
  293. ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer);
  294. // specify handler for output
  295. ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
  296. cmCTestSubmitHandlerWriteMemoryCallback);
  297. ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
  298. cmCTestSubmitHandlerCurlDebugCallback);
  299. /* we pass our 'chunk' struct to the callback function */
  300. cmCTestSubmitHandlerVectorOfChar chunk;
  301. cmCTestSubmitHandlerVectorOfChar chunkDebug;
  302. ::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&chunk);
  303. ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
  304. // Now run off and do what you've been told!
  305. res = ::curl_easy_perform(curl);
  306. if ( chunk.size() > 0 )
  307. {
  308. cmCTestLog(this->CTest, DEBUG, "CURL output: ["
  309. << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
  310. << std::endl);
  311. }
  312. if ( chunkDebug.size() > 0 )
  313. {
  314. cmCTestLog(this->CTest, DEBUG, "CURL debug output: ["
  315. << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]"
  316. << std::endl);
  317. }
  318. fclose(ftpfile);
  319. if ( res )
  320. {
  321. cmCTestLog(this->CTest, ERROR_MESSAGE,
  322. " Error when uploading file: "
  323. << local_file.c_str() << std::endl);
  324. cmCTestLog(this->CTest, ERROR_MESSAGE, " Error message was: "
  325. << error_buffer << std::endl);
  326. *this->LogFile << " Error when uploading file: "
  327. << local_file.c_str()
  328. << std::endl
  329. << " Error message was: " << error_buffer << std::endl
  330. << " Curl output was: "
  331. << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << std::endl;
  332. cmCTestLog(this->CTest, ERROR_MESSAGE, "CURL output: ["
  333. << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
  334. << std::endl);
  335. ::curl_easy_cleanup(curl);
  336. ::curl_global_cleanup();
  337. return false;
  338. }
  339. // always cleanup
  340. ::curl_easy_cleanup(curl);
  341. cmCTestLog(this->CTest, HANDLER_OUTPUT, " Uploaded: " + local_file
  342. << std::endl);
  343. }
  344. }
  345. ::curl_global_cleanup();
  346. return true;
  347. }
  348. //----------------------------------------------------------------------------
  349. bool cmCTestSubmitHandler::TriggerUsingHTTP(
  350. const std::set<cmStdString>& files,
  351. const cmStdString& remoteprefix,
  352. const cmStdString& url)
  353. {
  354. CURL *curl;
  355. char error_buffer[1024];
  356. /* In windows, this will init the winsock stuff */
  357. ::curl_global_init(CURL_GLOBAL_ALL);
  358. cmCTest::SetOfStrings::const_iterator file;
  359. for ( file = files.begin(); file != files.end(); ++file )
  360. {
  361. /* get a curl handle */
  362. curl = curl_easy_init();
  363. if(curl)
  364. {
  365. // Using proxy
  366. if ( this->HTTPProxyType > 0 )
  367. {
  368. curl_easy_setopt(curl, CURLOPT_PROXY, this->HTTPProxy.c_str());
  369. switch (this->HTTPProxyType)
  370. {
  371. case 2:
  372. curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
  373. break;
  374. case 3:
  375. curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
  376. break;
  377. default:
  378. curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
  379. if (this->HTTPProxyAuth.size() > 0)
  380. {
  381. curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD,
  382. this->HTTPProxyAuth.c_str());
  383. }
  384. }
  385. }
  386. ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
  387. // and give curl the buffer for errors
  388. ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer);
  389. // specify handler for output
  390. ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
  391. cmCTestSubmitHandlerWriteMemoryCallback);
  392. ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
  393. cmCTestSubmitHandlerCurlDebugCallback);
  394. /* we pass our 'chunk' struct to the callback function */
  395. cmCTestSubmitHandlerVectorOfChar chunk;
  396. cmCTestSubmitHandlerVectorOfChar chunkDebug;
  397. ::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&chunk);
  398. ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
  399. cmStdString rfile
  400. = remoteprefix + cmSystemTools::GetFilenameName(*file);
  401. cmStdString ofile = "";
  402. cmStdString::iterator kk;
  403. for ( kk = rfile.begin(); kk < rfile.end(); ++ kk)
  404. {
  405. char c = *kk;
  406. char hexCh[4] = { 0, 0, 0, 0 };
  407. hexCh[0] = c;
  408. switch ( c )
  409. {
  410. case '+':
  411. case '?':
  412. case '/':
  413. case '\\':
  414. case '&':
  415. case ' ':
  416. case '=':
  417. case '%':
  418. sprintf(hexCh, "%%%02X", (int)c);
  419. ofile.append(hexCh);
  420. break;
  421. default:
  422. ofile.append(hexCh);
  423. }
  424. }
  425. cmStdString turl
  426. = url + ((url.find("?",0) == cmStdString::npos) ? "?" : "&")
  427. + "xmlfile=" + ofile;
  428. *this->LogFile << "Trigger url: " << turl.c_str() << std::endl;
  429. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Trigger url: "
  430. << turl.c_str() << std::endl);
  431. curl_easy_setopt(curl, CURLOPT_URL, turl.c_str());
  432. if ( curl_easy_perform(curl) )
  433. {
  434. cmCTestLog(this->CTest, ERROR_MESSAGE, " Error when triggering: "
  435. << turl.c_str() << std::endl);
  436. cmCTestLog(this->CTest, ERROR_MESSAGE, " Error message was: "
  437. << error_buffer << std::endl);
  438. *this->LogFile << "\tTrigerring failed with error: " << error_buffer
  439. << std::endl
  440. << " Error message was: " << error_buffer << std::endl
  441. << " Curl output was: "
  442. << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << std::endl;
  443. cmCTestLog(this->CTest, ERROR_MESSAGE, "CURL output: ["
  444. << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
  445. << std::endl);
  446. ::curl_easy_cleanup(curl);
  447. ::curl_global_cleanup();
  448. return false;
  449. }
  450. if ( chunk.size() > 0 )
  451. {
  452. cmCTestLog(this->CTest, DEBUG, "CURL output: ["
  453. << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
  454. << std::endl);
  455. }
  456. if ( chunkDebug.size() > 0 )
  457. {
  458. cmCTestLog(this->CTest, DEBUG, "CURL debug output: ["
  459. << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size())
  460. << "]" << std::endl);
  461. }
  462. // always cleanup
  463. ::curl_easy_cleanup(curl);
  464. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl);
  465. }
  466. }
  467. ::curl_global_cleanup();
  468. cmCTestLog(this->CTest, HANDLER_OUTPUT, " Dart server triggered..."
  469. << std::endl);
  470. return true;
  471. }
  472. //----------------------------------------------------------------------------
  473. bool cmCTestSubmitHandler::SubmitUsingSCP(
  474. const cmStdString& scp_command,
  475. const cmStdString& localprefix,
  476. const std::set<cmStdString>& files,
  477. const cmStdString& remoteprefix,
  478. const cmStdString& url)
  479. {
  480. if ( !scp_command.size() || !localprefix.size() ||
  481. !files.size() || !remoteprefix.size() || !url.size() )
  482. {
  483. return 0;
  484. }
  485. std::vector<const char*> argv;
  486. argv.push_back(scp_command.c_str()); // Scp command
  487. argv.push_back(scp_command.c_str()); // Dummy string for file
  488. argv.push_back(scp_command.c_str()); // Dummy string for remote url
  489. argv.push_back(0);
  490. cmsysProcess* cp = cmsysProcess_New();
  491. cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
  492. //cmsysProcess_SetTimeout(cp, timeout);
  493. int problems = 0;
  494. cmCTest::SetOfStrings::const_iterator file;
  495. for ( file = files.begin(); file != files.end(); ++file )
  496. {
  497. int retVal;
  498. std::string lfname = localprefix;
  499. cmSystemTools::ConvertToUnixSlashes(lfname);
  500. lfname += "/" + *file;
  501. lfname = cmSystemTools::ConvertToOutputPath(lfname.c_str());
  502. argv[1] = lfname.c_str();
  503. std::string rfname = url + "/" + remoteprefix + *file;
  504. argv[2] = rfname.c_str();
  505. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Execute \"" << argv[0]
  506. << "\" \"" << argv[1] << "\" \""
  507. << argv[2] << "\"" << std::endl);
  508. *this->LogFile << "Execute \"" << argv[0] << "\" \"" << argv[1] << "\" \""
  509. << argv[2] << "\"" << std::endl;
  510. cmsysProcess_SetCommand(cp, &*argv.begin());
  511. cmsysProcess_Execute(cp);
  512. char* data;
  513. int length;
  514. while(cmsysProcess_WaitForData(cp, &data, &length, 0))
  515. {
  516. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  517. cmCTestLogWrite(data, length));
  518. }
  519. cmsysProcess_WaitForExit(cp, 0);
  520. int result = cmsysProcess_GetState(cp);
  521. if(result == cmsysProcess_State_Exited)
  522. {
  523. retVal = cmsysProcess_GetExitValue(cp);
  524. if ( retVal != 0 )
  525. {
  526. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "\tSCP returned: "
  527. << retVal << std::endl);
  528. *this->LogFile << "\tSCP returned: " << retVal << std::endl;
  529. problems ++;
  530. }
  531. }
  532. else if(result == cmsysProcess_State_Exception)
  533. {
  534. retVal = cmsysProcess_GetExitException(cp);
  535. cmCTestLog(this->CTest, ERROR_MESSAGE, "\tThere was an exception: "
  536. << retVal << std::endl);
  537. *this->LogFile << "\tThere was an exception: " << retVal << std::endl;
  538. problems ++;
  539. }
  540. else if(result == cmsysProcess_State_Expired)
  541. {
  542. cmCTestLog(this->CTest, ERROR_MESSAGE, "\tThere was a timeout"
  543. << std::endl);
  544. *this->LogFile << "\tThere was a timeout" << std::endl;
  545. problems ++;
  546. }
  547. else if(result == cmsysProcess_State_Error)
  548. {
  549. cmCTestLog(this->CTest, ERROR_MESSAGE, "\tError executing SCP: "
  550. << cmsysProcess_GetErrorString(cp) << std::endl);
  551. *this->LogFile << "\tError executing SCP: "
  552. << cmsysProcess_GetErrorString(cp) << std::endl;
  553. problems ++;
  554. }
  555. }
  556. cmsysProcess_Delete(cp);
  557. if ( problems )
  558. {
  559. return false;
  560. }
  561. return true;
  562. }
  563. //----------------------------------------------------------------------------
  564. bool cmCTestSubmitHandler::SubmitUsingXMLRPC(const cmStdString& localprefix,
  565. const std::set<cmStdString>& files,
  566. const cmStdString& remoteprefix,
  567. const cmStdString& url)
  568. {
  569. xmlrpc_env env;
  570. std::string ctestVersion = cmVersion::GetCMakeVersion();
  571. cmStdString realURL = url + "/" + remoteprefix + "/Command/";
  572. /* Start up our XML-RPC client library. */
  573. xmlrpc_client_init(XMLRPC_CLIENT_NO_FLAGS, "CTest", ctestVersion.c_str());
  574. /* Initialize our error-handling environment. */
  575. xmlrpc_env_init(&env);
  576. /* Call the famous server at UserLand. */
  577. cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submitting to: "
  578. << realURL.c_str() << " (" << remoteprefix.c_str() << ")" << std::endl);
  579. cmCTest::SetOfStrings::const_iterator file;
  580. for ( file = files.begin(); file != files.end(); ++file )
  581. {
  582. xmlrpc_value *result;
  583. cmStdString local_file = *file;
  584. if ( !cmSystemTools::FileExists(local_file.c_str()) )
  585. {
  586. local_file = localprefix + "/" + *file;
  587. }
  588. cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submit file: "
  589. << local_file.c_str() << std::endl);
  590. struct stat st;
  591. if ( ::stat(local_file.c_str(), &st) )
  592. {
  593. cmCTestLog(this->CTest, ERROR_MESSAGE, " Cannot find file: "
  594. << local_file.c_str() << std::endl);
  595. return false;
  596. }
  597. size_t fileSize = st.st_size;
  598. FILE* fp = fopen(local_file.c_str(), "rb");
  599. if ( !fp )
  600. {
  601. cmCTestLog(this->CTest, ERROR_MESSAGE, " Cannot open file: "
  602. << local_file.c_str() << std::endl);
  603. return false;
  604. }
  605. unsigned char *fileBuffer = new unsigned char[fileSize];
  606. if ( fread(fileBuffer, 1, fileSize, fp) != fileSize )
  607. {
  608. delete [] fileBuffer;
  609. fclose(fp);
  610. cmCTestLog(this->CTest, ERROR_MESSAGE, " Cannot read file: "
  611. << local_file.c_str() << std::endl);
  612. return false;
  613. }
  614. fclose(fp);
  615. std::string remoteCommand = "Submit.put";
  616. result = xmlrpc_client_call(&env, realURL.c_str(),
  617. remoteCommand.c_str(),
  618. "(6)", fileBuffer, (xmlrpc_int32)fileSize );
  619. delete [] fileBuffer;
  620. if ( env.fault_occurred )
  621. {
  622. cmCTestLog(this->CTest, ERROR_MESSAGE, " Submission problem: "
  623. << env.fault_string << " (" << env.fault_code << ")" << std::endl);
  624. xmlrpc_env_clean(&env);
  625. xmlrpc_client_cleanup();
  626. return false;
  627. }
  628. /* Dispose of our result value. */
  629. xmlrpc_DECREF(result);
  630. }
  631. /* Clean up our error-handling environment. */
  632. xmlrpc_env_clean(&env);
  633. /* Shutdown our XML-RPC client library. */
  634. xmlrpc_client_cleanup();
  635. return true;
  636. }
  637. //----------------------------------------------------------------------------
  638. int cmCTestSubmitHandler::ProcessHandler()
  639. {
  640. const std::string &buildDirectory
  641. = this->CTest->GetCTestConfiguration("BuildDirectory");
  642. if ( buildDirectory.size() == 0 )
  643. {
  644. cmCTestLog(this->CTest, ERROR_MESSAGE,
  645. "Cannot find BuildDirectory key in the DartConfiguration.tcl"
  646. << std::endl);
  647. return -1;
  648. }
  649. if ( getenv("HTTP_PROXY") )
  650. {
  651. this->HTTPProxyType = 1;
  652. this->HTTPProxy = getenv("HTTP_PROXY");
  653. if ( getenv("HTTP_PROXY_PORT") )
  654. {
  655. this->HTTPProxy += ":";
  656. this->HTTPProxy += getenv("HTTP_PROXY_PORT");
  657. }
  658. if ( getenv("HTTP_PROXY_TYPE") )
  659. {
  660. cmStdString type = getenv("HTTP_PROXY_TYPE");
  661. // HTTP/SOCKS4/SOCKS5
  662. if ( type == "HTTP" )
  663. {
  664. this->HTTPProxyType = 1;
  665. }
  666. else if ( type == "SOCKS4" )
  667. {
  668. this->HTTPProxyType = 2;
  669. }
  670. else if ( type == "SOCKS5" )
  671. {
  672. this->HTTPProxyType = 3;
  673. }
  674. }
  675. if ( getenv("HTTP_PROXY_USER") )
  676. {
  677. this->HTTPProxyAuth = getenv("HTTP_PROXY_USER");
  678. }
  679. if ( getenv("HTTP_PROXY_PASSWD") )
  680. {
  681. this->HTTPProxyAuth += ":";
  682. this->HTTPProxyAuth += getenv("HTTP_PROXY_PASSWD");
  683. }
  684. }
  685. if ( getenv("FTP_PROXY") )
  686. {
  687. this->FTPProxyType = 1;
  688. this->FTPProxy = getenv("FTP_PROXY");
  689. if ( getenv("FTP_PROXY_PORT") )
  690. {
  691. this->FTPProxy += ":";
  692. this->FTPProxy += getenv("FTP_PROXY_PORT");
  693. }
  694. if ( getenv("FTP_PROXY_TYPE") )
  695. {
  696. cmStdString type = getenv("FTP_PROXY_TYPE");
  697. // HTTP/SOCKS4/SOCKS5
  698. if ( type == "HTTP" )
  699. {
  700. this->FTPProxyType = 1;
  701. }
  702. else if ( type == "SOCKS4" )
  703. {
  704. this->FTPProxyType = 2;
  705. }
  706. else if ( type == "SOCKS5" )
  707. {
  708. this->FTPProxyType = 3;
  709. }
  710. }
  711. }
  712. if ( this->HTTPProxy.size() > 0 )
  713. {
  714. cmCTestLog(this->CTest, HANDLER_OUTPUT, " Use HTTP Proxy: "
  715. << this->HTTPProxy << std::endl);
  716. }
  717. if ( this->FTPProxy.size() > 0 )
  718. {
  719. cmCTestLog(this->CTest, HANDLER_OUTPUT, " Use FTP Proxy: "
  720. << this->FTPProxy << std::endl);
  721. }
  722. cmGeneratedFileStream ofs;
  723. this->StartLogFile("Submit", ofs);
  724. cmCTest::SetOfStrings files;
  725. std::string prefix = this->GetSubmitResultsPrefix();
  726. // TODO:
  727. // Check if test is enabled
  728. this->CTest->AddIfExists(files, "Update.xml");
  729. this->CTest->AddIfExists(files, "Configure.xml");
  730. this->CTest->AddIfExists(files, "Build.xml");
  731. this->CTest->AddIfExists(files, "Test.xml");
  732. if ( this->CTest->AddIfExists(files, "Coverage.xml") )
  733. {
  734. cmCTest::VectorOfStrings gfiles;
  735. std::string gpath
  736. = buildDirectory + "/Testing/" + this->CTest->GetCurrentTag();
  737. std::string::size_type glen = gpath.size() + 1;
  738. gpath = gpath + "/CoverageLog*";
  739. cmCTestLog(this->CTest, DEBUG, "Globbing for: " << gpath.c_str()
  740. << std::endl);
  741. if ( cmSystemTools::SimpleGlob(gpath, gfiles, 1) )
  742. {
  743. size_t cc;
  744. for ( cc = 0; cc < gfiles.size(); cc ++ )
  745. {
  746. gfiles[cc] = gfiles[cc].substr(glen);
  747. cmCTestLog(this->CTest, DEBUG, "Glob file: " << gfiles[cc].c_str()
  748. << std::endl);
  749. files.insert(gfiles[cc]);
  750. }
  751. }
  752. else
  753. {
  754. cmCTestLog(this->CTest, ERROR_MESSAGE, "Problem globbing" << std::endl);
  755. }
  756. }
  757. this->CTest->AddIfExists(files, "DynamicAnalysis.xml");
  758. this->CTest->AddIfExists(files, "Purify.xml");
  759. this->CTest->AddIfExists(files, "Notes.xml");
  760. cmCTest::SetOfStrings::iterator it;
  761. for ( it = this->CTest->GetSubmitFiles()->begin();
  762. it != this->CTest->GetSubmitFiles()->end();
  763. ++ it )
  764. {
  765. files.insert(files.end(), *it);
  766. }
  767. if ( ofs )
  768. {
  769. ofs << "Upload files:" << std::endl;
  770. int cnt = 0;
  771. for ( it = files.begin(); it != files.end(); ++ it )
  772. {
  773. ofs << cnt << "\t" << it->c_str() << std::endl;
  774. cnt ++;
  775. }
  776. }
  777. cmCTestLog(this->CTest, HANDLER_OUTPUT, "Submit files (using "
  778. << this->CTest->GetCTestConfiguration("DropMethod") << ")"
  779. << std::endl);
  780. const char* specificTrack = this->CTest->GetSpecificTrack();
  781. if ( specificTrack )
  782. {
  783. cmCTestLog(this->CTest, HANDLER_OUTPUT, " Send to track: "
  784. << specificTrack << std::endl);
  785. }
  786. this->SetLogFile(&ofs);
  787. if ( this->CTest->GetCTestConfiguration("DropMethod") == "" ||
  788. this->CTest->GetCTestConfiguration("DropMethod") == "ftp" )
  789. {
  790. ofs << "Using drop method: FTP" << std::endl;
  791. cmCTestLog(this->CTest, HANDLER_OUTPUT, " Using FTP submit method"
  792. << std::endl
  793. << " Drop site: ftp://");
  794. std::string url = "ftp://";
  795. url += cmCTest::MakeURLSafe(
  796. this->CTest->GetCTestConfiguration("DropSiteUser")) + ":" +
  797. cmCTest::MakeURLSafe(this->CTest->GetCTestConfiguration(
  798. "DropSitePassword")) + "@" +
  799. this->CTest->GetCTestConfiguration("DropSite") +
  800. cmCTest::MakeURLSafe(
  801. this->CTest->GetCTestConfiguration("DropLocation"));
  802. if ( this->CTest->GetCTestConfiguration("DropSiteUser").size() > 0 )
  803. {
  804. cmCTestLog(this->CTest, HANDLER_OUTPUT,
  805. this->CTest->GetCTestConfiguration(
  806. "DropSiteUser").c_str());
  807. if ( this->CTest->GetCTestConfiguration("DropSitePassword").size() > 0 )
  808. {
  809. cmCTestLog(this->CTest, HANDLER_OUTPUT, ":******");
  810. }
  811. cmCTestLog(this->CTest, HANDLER_OUTPUT, "@");
  812. }
  813. cmCTestLog(this->CTest, HANDLER_OUTPUT,
  814. this->CTest->GetCTestConfiguration("DropSite")
  815. << this->CTest->GetCTestConfiguration("DropLocation") << std::endl);
  816. if ( !this->SubmitUsingFTP(buildDirectory + "/Testing/"
  817. + this->CTest->GetCurrentTag(),
  818. files, prefix, url) )
  819. {
  820. cmCTestLog(this->CTest, ERROR_MESSAGE,
  821. " Problems when submitting via FTP"
  822. << std::endl);
  823. ofs << " Problems when submitting via FTP" << std::endl;
  824. return -1;
  825. }
  826. cmCTestLog(this->CTest, HANDLER_OUTPUT, " Using HTTP trigger method"
  827. << std::endl
  828. << " Trigger site: "
  829. << this->CTest->GetCTestConfiguration("TriggerSite")
  830. << std::endl);
  831. if ( !this->TriggerUsingHTTP(files, prefix,
  832. this->CTest->GetCTestConfiguration("TriggerSite")) )
  833. {
  834. cmCTestLog(this->CTest, ERROR_MESSAGE,
  835. " Problems when triggering via HTTP" << std::endl);
  836. ofs << " Problems when triggering via HTTP" << std::endl;
  837. return -1;
  838. }
  839. cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submission successful"
  840. << std::endl);
  841. ofs << " Submission successful" << std::endl;
  842. return 0;
  843. }
  844. else if ( this->CTest->GetCTestConfiguration("DropMethod") == "http" )
  845. {
  846. ofs << "Using drop method: HTTP" << std::endl;
  847. cmCTestLog(this->CTest, HANDLER_OUTPUT, " Using HTTP submit method"
  848. << std::endl
  849. << " Drop site: http://");
  850. std::string url = "http://";
  851. if ( this->CTest->GetCTestConfiguration("DropSiteUser").size() > 0 )
  852. {
  853. url += this->CTest->GetCTestConfiguration("DropSiteUser");
  854. cmCTestLog(this->CTest, HANDLER_OUTPUT,
  855. this->CTest->GetCTestConfiguration("DropSiteUser").c_str());
  856. if ( this->CTest->GetCTestConfiguration("DropSitePassword").size() > 0 )
  857. {
  858. url += ":" + this->CTest->GetCTestConfiguration("DropSitePassword");
  859. cmCTestLog(this->CTest, HANDLER_OUTPUT, ":******");
  860. }
  861. url += "@";
  862. cmCTestLog(this->CTest, HANDLER_OUTPUT, "@");
  863. }
  864. url += this->CTest->GetCTestConfiguration("DropSite") +
  865. this->CTest->GetCTestConfiguration("DropLocation");
  866. cmCTestLog(this->CTest, HANDLER_OUTPUT,
  867. this->CTest->GetCTestConfiguration("DropSite")
  868. << this->CTest->GetCTestConfiguration("DropLocation") << std::endl);
  869. if ( !this->SubmitUsingHTTP(buildDirectory + "/Testing/" +
  870. this->CTest->GetCurrentTag(), files, prefix, url) )
  871. {
  872. cmCTestLog(this->CTest, ERROR_MESSAGE,
  873. " Problems when submitting via HTTP" << std::endl);
  874. ofs << " Problems when submitting via HTTP" << std::endl;
  875. return -1;
  876. }
  877. cmCTestLog(this->CTest, HANDLER_OUTPUT, " Using HTTP trigger method"
  878. << std::endl
  879. << " Trigger site: "
  880. << this->CTest->GetCTestConfiguration("TriggerSite")
  881. << std::endl);
  882. if ( !this->TriggerUsingHTTP(files, prefix,
  883. this->CTest->GetCTestConfiguration("TriggerSite")) )
  884. {
  885. cmCTestLog(this->CTest, ERROR_MESSAGE,
  886. " Problems when triggering via HTTP" << std::endl);
  887. ofs << " Problems when triggering via HTTP" << std::endl;
  888. return -1;
  889. }
  890. cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submission successful"
  891. << std::endl);
  892. ofs << " Submission successful" << std::endl;
  893. return 0;
  894. }
  895. else if ( this->CTest->GetCTestConfiguration("DropMethod") == "xmlrpc" )
  896. {
  897. ofs << "Using drop method: XML-RPC" << std::endl;
  898. cmCTestLog(this->CTest, HANDLER_OUTPUT, " Using XML-RPC submit method"
  899. << std::endl);
  900. std::string url = this->CTest->GetCTestConfiguration("DropSite");
  901. prefix = this->CTest->GetCTestConfiguration("DropLocation");
  902. if ( !this->SubmitUsingXMLRPC(buildDirectory + "/Testing/" +
  903. this->CTest->GetCurrentTag(), files, prefix, url) )
  904. {
  905. cmCTestLog(this->CTest, ERROR_MESSAGE,
  906. " Problems when submitting via XML-RPC" << std::endl);
  907. ofs << " Problems when submitting via XML-RPC" << std::endl;
  908. return -1;
  909. }
  910. cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submission successful"
  911. << std::endl);
  912. ofs << " Submission successful" << std::endl;
  913. return 0;
  914. }
  915. else if ( this->CTest->GetCTestConfiguration("DropMethod") == "scp" )
  916. {
  917. std::string url;
  918. std::string oldWorkingDirectory;
  919. if ( this->CTest->GetCTestConfiguration("DropSiteUser").size() > 0 )
  920. {
  921. url += this->CTest->GetCTestConfiguration("DropSiteUser") + "@";
  922. }
  923. url += this->CTest->GetCTestConfiguration("DropSite") + ":" +
  924. this->CTest->GetCTestConfiguration("DropLocation");
  925. // change to the build directory so that we can uses a relative path
  926. // on windows since scp dosn't support "c:" a drive in the path
  927. oldWorkingDirectory = cmSystemTools::GetCurrentWorkingDirectory();
  928. cmSystemTools::ChangeDirectory(buildDirectory.c_str());
  929. if ( !this->SubmitUsingSCP(
  930. this->CTest->GetCTestConfiguration("ScpCommand"),
  931. "Testing/"+this->CTest->GetCurrentTag(), files, prefix, url) )
  932. {
  933. cmSystemTools::ChangeDirectory(oldWorkingDirectory.c_str());
  934. cmCTestLog(this->CTest, ERROR_MESSAGE,
  935. " Problems when submitting via SCP"
  936. << std::endl);
  937. ofs << " Problems when submitting via SCP" << std::endl;
  938. return -1;
  939. }
  940. cmSystemTools::ChangeDirectory(oldWorkingDirectory.c_str());
  941. cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submission successful"
  942. << std::endl);
  943. ofs << " Submission successful" << std::endl;
  944. return 0;
  945. }
  946. cmCTestLog(this->CTest, ERROR_MESSAGE, " Unknown submission method: \""
  947. << this->CTest->GetCTestConfiguration("DropMethod") << "\"" << std::endl);
  948. return -1;
  949. }
  950. //----------------------------------------------------------------------------
  951. std::string cmCTestSubmitHandler::GetSubmitResultsPrefix()
  952. {
  953. std::string name = this->CTest->GetCTestConfiguration("Site") +
  954. "___" + this->CTest->GetCTestConfiguration("BuildName") +
  955. "___" + this->CTest->GetCurrentTag() + "-" +
  956. this->CTest->GetTestModelString() + "___XML___";
  957. return name;
  958. }