cmCTestSubmitHandler.cxx 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887
  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 "CTest/Curl/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, void *data)
  29. {
  30. register int realsize = size * nmemb;
  31. cmCTestSubmitHandlerVectorOfChar *vec = static_cast<cmCTestSubmitHandlerVectorOfChar*>(data);
  32. const char* chPtr = static_cast<char*>(ptr);
  33. vec->insert(vec->end(), chPtr, chPtr + realsize);
  34. return realsize;
  35. }
  36. static size_t
  37. cmCTestSubmitHandlerCurlDebugCallback(CURL *, curl_infotype, char *chPtr, size_t size, void *data)
  38. {
  39. cmCTestSubmitHandlerVectorOfChar *vec = static_cast<cmCTestSubmitHandlerVectorOfChar*>(data);
  40. vec->insert(vec->end(), chPtr, chPtr + size);
  41. return size;
  42. }
  43. //----------------------------------------------------------------------------
  44. cmCTestSubmitHandler::cmCTestSubmitHandler() : m_HTTPProxy(), m_FTPProxy()
  45. {
  46. m_HTTPProxy = "";
  47. m_HTTPProxyType = 0;
  48. m_HTTPProxyAuth = "";
  49. m_FTPProxy = "";
  50. m_FTPProxyType = 0;
  51. }
  52. //----------------------------------------------------------------------------
  53. void cmCTestSubmitHandler::Initialize()
  54. {
  55. m_HTTPProxy = "";
  56. m_HTTPProxyType = 0;
  57. m_HTTPProxyAuth = "";
  58. m_FTPProxy = "";
  59. m_FTPProxyType = 0;
  60. m_LogFile = 0;
  61. }
  62. //----------------------------------------------------------------------------
  63. bool cmCTestSubmitHandler::SubmitUsingFTP(const cmStdString& localprefix,
  64. const std::vector<cmStdString>& files,
  65. const cmStdString& remoteprefix,
  66. const cmStdString& url)
  67. {
  68. CURL *curl;
  69. CURLcode res;
  70. FILE* ftpfile;
  71. char error_buffer[1024];
  72. /* In windows, this will init the winsock stuff */
  73. ::curl_global_init(CURL_GLOBAL_ALL);
  74. cmStdString::size_type cc;
  75. for ( cc = 0; cc < files.size(); cc ++ )
  76. {
  77. /* get a curl handle */
  78. curl = curl_easy_init();
  79. if(curl)
  80. {
  81. // Using proxy
  82. if ( m_FTPProxyType > 0 )
  83. {
  84. curl_easy_setopt(curl, CURLOPT_PROXY, m_FTPProxy.c_str());
  85. switch (m_FTPProxyType)
  86. {
  87. case 2:
  88. curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
  89. break;
  90. case 3:
  91. curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
  92. break;
  93. default:
  94. curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
  95. }
  96. }
  97. // enable uploading
  98. ::curl_easy_setopt(curl, CURLOPT_UPLOAD, 1) ;
  99. cmStdString local_file = localprefix + "/" + files[cc];
  100. cmStdString upload_as = url + "/" + remoteprefix + files[cc];
  101. struct stat st;
  102. if ( ::stat(local_file.c_str(), &st) )
  103. {
  104. return false;
  105. }
  106. ftpfile = ::fopen(local_file.c_str(), "rb");
  107. *m_LogFile << "\tUpload file: " << local_file.c_str() << " to "
  108. << upload_as.c_str() << std::endl;
  109. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, " Upload file: " << local_file.c_str() << " to "
  110. << upload_as.c_str() << std::endl);
  111. ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
  112. // specify target
  113. ::curl_easy_setopt(curl,CURLOPT_URL, upload_as.c_str());
  114. // now specify which file to upload
  115. ::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
  116. // and give the size of the upload (optional)
  117. ::curl_easy_setopt(curl, CURLOPT_INFILESIZE, static_cast<long>(st.st_size));
  118. // and give curl the buffer for errors
  119. ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer);
  120. // specify handler for output
  121. ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cmCTestSubmitHandlerWriteMemoryCallback);
  122. ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, cmCTestSubmitHandlerCurlDebugCallback);
  123. /* we pass our 'chunk' struct to the callback function */
  124. cmCTestSubmitHandlerVectorOfChar chunk;
  125. cmCTestSubmitHandlerVectorOfChar chunkDebug;
  126. ::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&chunk);
  127. ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
  128. // Now run off and do what you've been told!
  129. res = ::curl_easy_perform(curl);
  130. cmCTestLog(m_CTest, DEBUG, "CURL output: ["
  131. << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]" << std::endl);
  132. cmCTestLog(m_CTest, DEBUG, "CURL debug output: ["
  133. << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]" << std::endl);
  134. fclose(ftpfile);
  135. if ( res )
  136. {
  137. cmCTestLog(m_CTest, ERROR_MESSAGE, " Error when uploading file: " << local_file.c_str() << std::endl);
  138. cmCTestLog(m_CTest, ERROR_MESSAGE, " Error message was: " << error_buffer << std::endl);
  139. *m_LogFile << " Error when uploading file: " << local_file.c_str() << std::endl
  140. << " Error message was: " << error_buffer << std::endl
  141. << " Curl output was: " << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << std::endl;
  142. cmCTestLog(m_CTest, ERROR_MESSAGE, "CURL output: ["
  143. << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]" << std::endl);
  144. ::curl_easy_cleanup(curl);
  145. ::curl_global_cleanup();
  146. return false;
  147. }
  148. // always cleanup
  149. ::curl_easy_cleanup(curl);
  150. cmCTestLog(m_CTest, HANDLER_OUTPUT, " Uploaded: " + local_file << std::endl);
  151. }
  152. }
  153. ::curl_global_cleanup();
  154. return true;
  155. }
  156. //----------------------------------------------------------------------------
  157. // Uploading files is simpler
  158. bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix,
  159. const std::vector<cmStdString>& files,
  160. const cmStdString& remoteprefix,
  161. const cmStdString& url)
  162. {
  163. CURL *curl;
  164. CURLcode res;
  165. FILE* ftpfile;
  166. char error_buffer[1024];
  167. /* In windows, this will init the winsock stuff */
  168. ::curl_global_init(CURL_GLOBAL_ALL);
  169. cmStdString::size_type cc, kk;
  170. for ( cc = 0; cc < files.size(); cc ++ )
  171. {
  172. /* get a curl handle */
  173. curl = curl_easy_init();
  174. if(curl)
  175. {
  176. // Using proxy
  177. if ( m_HTTPProxyType > 0 )
  178. {
  179. curl_easy_setopt(curl, CURLOPT_PROXY, m_HTTPProxy.c_str());
  180. switch (m_HTTPProxyType)
  181. {
  182. case 2:
  183. curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
  184. break;
  185. case 3:
  186. curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
  187. break;
  188. default:
  189. curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
  190. if (m_HTTPProxyAuth.size() > 0)
  191. {
  192. curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD,
  193. m_HTTPProxyAuth.c_str());
  194. }
  195. }
  196. }
  197. /* enable uploading */
  198. curl_easy_setopt(curl, CURLOPT_UPLOAD, 1) ;
  199. /* HTTP PUT please */
  200. ::curl_easy_setopt(curl, CURLOPT_PUT, 1);
  201. ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
  202. cmStdString local_file = localprefix + "/" + files[cc];
  203. cmStdString remote_file = remoteprefix + files[cc];
  204. *m_LogFile << "\tUpload file: " << local_file.c_str() << " to "
  205. << remote_file.c_str() << std::endl;
  206. cmStdString ofile = "";
  207. for ( kk = 0; kk < remote_file.size(); kk ++ )
  208. {
  209. char c = remote_file[kk];
  210. char hex[4] = { 0, 0, 0, 0 };
  211. hex[0] = c;
  212. switch ( c )
  213. {
  214. case '+':
  215. case '?':
  216. case '/':
  217. case '\\':
  218. case '&':
  219. case ' ':
  220. case '=':
  221. case '%':
  222. sprintf(hex, "%%%02X", (int)c);
  223. ofile.append(hex);
  224. break;
  225. default:
  226. ofile.append(hex);
  227. }
  228. }
  229. cmStdString upload_as
  230. = url + ((url.find("?",0) == cmStdString::npos) ? "?" : "&")
  231. + "FileName=" + ofile;
  232. struct stat st;
  233. if ( ::stat(local_file.c_str(), &st) )
  234. {
  235. return false;
  236. }
  237. ftpfile = ::fopen(local_file.c_str(), "rb");
  238. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, " Upload file: " << local_file.c_str() << " to "
  239. << upload_as.c_str() << " Size: " << st.st_size << std::endl);
  240. // specify target
  241. ::curl_easy_setopt(curl,CURLOPT_URL, upload_as.c_str());
  242. // now specify which file to upload
  243. ::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
  244. // and give the size of the upload (optional)
  245. ::curl_easy_setopt(curl, CURLOPT_INFILESIZE, static_cast<long>(st.st_size));
  246. // and give curl the buffer for errors
  247. ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer);
  248. // specify handler for output
  249. ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cmCTestSubmitHandlerWriteMemoryCallback);
  250. ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, cmCTestSubmitHandlerCurlDebugCallback);
  251. /* we pass our 'chunk' struct to the callback function */
  252. cmCTestSubmitHandlerVectorOfChar chunk;
  253. cmCTestSubmitHandlerVectorOfChar chunkDebug;
  254. ::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&chunk);
  255. ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
  256. // Now run off and do what you've been told!
  257. res = ::curl_easy_perform(curl);
  258. cmCTestLog(m_CTest, DEBUG, "CURL output: ["
  259. << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]" << std::endl);
  260. cmCTestLog(m_CTest, DEBUG, "CURL debug output: ["
  261. << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]" << std::endl);
  262. fclose(ftpfile);
  263. if ( res )
  264. {
  265. cmCTestLog(m_CTest, ERROR_MESSAGE, " Error when uploading file: " << local_file.c_str() << std::endl);
  266. cmCTestLog(m_CTest, ERROR_MESSAGE, " Error message was: " << error_buffer << std::endl);
  267. *m_LogFile << " Error when uploading file: " << local_file.c_str() << std::endl
  268. << " Error message was: " << error_buffer << std::endl
  269. << " Curl output was: " << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << std::endl;
  270. cmCTestLog(m_CTest, ERROR_MESSAGE, "CURL output: ["
  271. << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]" << std::endl);
  272. ::curl_easy_cleanup(curl);
  273. ::curl_global_cleanup();
  274. return false;
  275. }
  276. // always cleanup
  277. ::curl_easy_cleanup(curl);
  278. cmCTestLog(m_CTest, HANDLER_OUTPUT, " Uploaded: " + local_file << std::endl);
  279. }
  280. }
  281. ::curl_global_cleanup();
  282. return true;
  283. }
  284. //----------------------------------------------------------------------------
  285. bool cmCTestSubmitHandler::TriggerUsingHTTP(const std::vector<cmStdString>& files,
  286. const cmStdString& remoteprefix,
  287. const cmStdString& url)
  288. {
  289. CURL *curl;
  290. char error_buffer[1024];
  291. /* In windows, this will init the winsock stuff */
  292. ::curl_global_init(CURL_GLOBAL_ALL);
  293. cmStdString::size_type cc, kk;
  294. for ( cc = 0; cc < files.size(); cc ++ )
  295. {
  296. /* get a curl handle */
  297. curl = curl_easy_init();
  298. if(curl)
  299. {
  300. // Using proxy
  301. if ( m_HTTPProxyType > 0 )
  302. {
  303. curl_easy_setopt(curl, CURLOPT_PROXY, m_HTTPProxy.c_str());
  304. switch (m_HTTPProxyType)
  305. {
  306. case 2:
  307. curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
  308. break;
  309. case 3:
  310. curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
  311. break;
  312. default:
  313. curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
  314. if (m_HTTPProxyAuth.size() > 0)
  315. {
  316. curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD,
  317. m_HTTPProxyAuth.c_str());
  318. }
  319. }
  320. }
  321. ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
  322. // and give curl the buffer for errors
  323. ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer);
  324. // specify handler for output
  325. ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cmCTestSubmitHandlerWriteMemoryCallback);
  326. ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, cmCTestSubmitHandlerCurlDebugCallback);
  327. /* we pass our 'chunk' struct to the callback function */
  328. cmCTestSubmitHandlerVectorOfChar chunk;
  329. cmCTestSubmitHandlerVectorOfChar chunkDebug;
  330. ::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&chunk);
  331. ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
  332. cmStdString file = remoteprefix + files[cc];
  333. cmStdString ofile = "";
  334. for ( kk = 0; kk < file.size(); kk ++ )
  335. {
  336. char c = file[kk];
  337. char hex[4] = { 0, 0, 0, 0 };
  338. hex[0] = c;
  339. switch ( c )
  340. {
  341. case '+':
  342. case '?':
  343. case '/':
  344. case '\\':
  345. case '&':
  346. case ' ':
  347. case '=':
  348. case '%':
  349. sprintf(hex, "%%%02X", (int)c);
  350. ofile.append(hex);
  351. break;
  352. default:
  353. ofile.append(hex);
  354. }
  355. }
  356. cmStdString turl
  357. = url + ((url.find("?",0) == cmStdString::npos) ? "?" : "&")
  358. + "xmlfile=" + ofile;
  359. *m_LogFile << "Trigger url: " << turl.c_str() << std::endl;
  360. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, " Trigger url: " << turl.c_str() << std::endl);
  361. curl_easy_setopt(curl, CURLOPT_URL, turl.c_str());
  362. if ( curl_easy_perform(curl) )
  363. {
  364. cmCTestLog(m_CTest, ERROR_MESSAGE, " Error when triggering: " << turl.c_str() << std::endl);
  365. cmCTestLog(m_CTest, ERROR_MESSAGE, " Error message was: " << error_buffer << std::endl);
  366. *m_LogFile << "\tTrigerring failed with error: " << error_buffer << std::endl
  367. << " Error message was: " << error_buffer << std::endl
  368. << " Curl output was: " << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << std::endl;
  369. cmCTestLog(m_CTest, ERROR_MESSAGE, "CURL output: ["
  370. << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]" << std::endl);
  371. ::curl_easy_cleanup(curl);
  372. ::curl_global_cleanup();
  373. return false;
  374. }
  375. cmCTestLog(m_CTest, DEBUG, "CURL output: ["
  376. << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]" << std::endl);
  377. cmCTestLog(m_CTest, DEBUG, "CURL debug output: ["
  378. << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]" << std::endl);
  379. // always cleanup
  380. ::curl_easy_cleanup(curl);
  381. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, std::endl);
  382. }
  383. }
  384. ::curl_global_cleanup();
  385. cmCTestLog(m_CTest, HANDLER_OUTPUT, " Dart server triggered..." << std::endl);
  386. return true;
  387. }
  388. //----------------------------------------------------------------------------
  389. bool cmCTestSubmitHandler::SubmitUsingSCP(
  390. const cmStdString& scp_command,
  391. const cmStdString& localprefix,
  392. const std::vector<cmStdString>& files,
  393. const cmStdString& remoteprefix,
  394. const cmStdString& url)
  395. {
  396. if ( !scp_command.size() || !localprefix.size() ||
  397. !files.size() || !remoteprefix.size() || !url.size() )
  398. {
  399. return 0;
  400. }
  401. std::vector<const char*> argv;
  402. argv.push_back(scp_command.c_str()); // Scp command
  403. argv.push_back(scp_command.c_str()); // Dummy string for file
  404. argv.push_back(scp_command.c_str()); // Dummy string for remote url
  405. argv.push_back(0);
  406. cmsysProcess* cp = cmsysProcess_New();
  407. cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
  408. //cmsysProcess_SetTimeout(cp, timeout);
  409. int problems = 0;
  410. std::vector<cmStdString>::const_iterator it;
  411. for ( it = files.begin();
  412. it != files.end();
  413. it ++ )
  414. {
  415. int retVal;
  416. std::string lfname = localprefix;
  417. cmSystemTools::ConvertToUnixSlashes(lfname);
  418. lfname += "/" + *it;
  419. lfname = cmSystemTools::ConvertToOutputPath(lfname.c_str());
  420. argv[1] = lfname.c_str();
  421. std::string rfname = url + "/" + remoteprefix + *it;
  422. argv[2] = rfname.c_str();
  423. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, "Execute \"" << argv[0] << "\" \"" << argv[1] << "\" \""
  424. << argv[2] << "\"" << std::endl);
  425. *m_LogFile << "Execute \"" << argv[0] << "\" \"" << argv[1] << "\" \""
  426. << argv[2] << "\"" << std::endl;
  427. cmsysProcess_SetCommand(cp, &*argv.begin());
  428. cmsysProcess_Execute(cp);
  429. char* data;
  430. int length;
  431. while(cmsysProcess_WaitForData(cp, &data, &length, 0))
  432. {
  433. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, cmCTestLogWrite(data, length));
  434. }
  435. cmsysProcess_WaitForExit(cp, 0);
  436. int result = cmsysProcess_GetState(cp);
  437. if(result == cmsysProcess_State_Exited)
  438. {
  439. retVal = cmsysProcess_GetExitValue(cp);
  440. if ( retVal != 0 )
  441. {
  442. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, "\tSCP returned: " << retVal << std::endl);
  443. *m_LogFile << "\tSCP returned: " << retVal << std::endl;
  444. problems ++;
  445. }
  446. }
  447. else if(result == cmsysProcess_State_Exception)
  448. {
  449. retVal = cmsysProcess_GetExitException(cp);
  450. cmCTestLog(m_CTest, ERROR_MESSAGE, "\tThere was an exception: " << retVal << std::endl);
  451. *m_LogFile << "\tThere was an exception: " << retVal << std::endl;
  452. problems ++;
  453. }
  454. else if(result == cmsysProcess_State_Expired)
  455. {
  456. cmCTestLog(m_CTest, ERROR_MESSAGE, "\tThere was a timeout" << std::endl);
  457. *m_LogFile << "\tThere was a timeout" << std::endl;
  458. problems ++;
  459. }
  460. else if(result == cmsysProcess_State_Error)
  461. {
  462. cmCTestLog(m_CTest, ERROR_MESSAGE, "\tError executing SCP: "
  463. << cmsysProcess_GetErrorString(cp) << std::endl);
  464. *m_LogFile << "\tError executing SCP: "
  465. << cmsysProcess_GetErrorString(cp) << std::endl;
  466. problems ++;
  467. }
  468. }
  469. cmsysProcess_Delete(cp);
  470. if ( problems )
  471. {
  472. return false;
  473. }
  474. return true;
  475. }
  476. //----------------------------------------------------------------------------
  477. bool cmCTestSubmitHandler::SubmitUsingXMLRPC(const cmStdString& localprefix,
  478. const std::vector<cmStdString>& files,
  479. const cmStdString& remoteprefix,
  480. const cmStdString& url)
  481. {
  482. xmlrpc_env env;
  483. std::string ctestVersion = cmVersion::GetCMakeVersion();
  484. cmStdString realURL = url + "/" + remoteprefix + "/Command/";
  485. /* Start up our XML-RPC client library. */
  486. xmlrpc_client_init(XMLRPC_CLIENT_NO_FLAGS, "CTest", ctestVersion.c_str());
  487. /* Initialize our error-handling environment. */
  488. xmlrpc_env_init(&env);
  489. /* Call the famous server at UserLand. */
  490. cmCTestLog(m_CTest, HANDLER_OUTPUT, " Submitting to: " << realURL.c_str() << " (" << remoteprefix.c_str() << ")" << std::endl);
  491. std::vector<cmStdString>::const_iterator it;
  492. for ( it = files.begin(); it != files.end(); ++it )
  493. {
  494. xmlrpc_value *result;
  495. std::string local_file = localprefix + "/" + *it;
  496. cmCTestLog(m_CTest, HANDLER_OUTPUT, " Submit file: " << local_file.c_str() << std::endl);
  497. struct stat st;
  498. if ( ::stat(local_file.c_str(), &st) )
  499. {
  500. return false;
  501. }
  502. size_t fileSize = st.st_size;
  503. FILE* fp = fopen(local_file.c_str(), "rb");
  504. if ( !fp )
  505. {
  506. return false;
  507. }
  508. unsigned char *fileBuffer = new unsigned char[fileSize];
  509. if ( fread(fileBuffer, 1, fileSize, fp) != fileSize )
  510. {
  511. delete [] fileBuffer;
  512. fclose(fp);
  513. return false;
  514. }
  515. fclose(fp);
  516. std::string remoteCommand = "Submit.put";
  517. result = xmlrpc_client_call(&env, realURL.c_str(),
  518. remoteCommand.c_str(),
  519. "(6)", fileBuffer, (xmlrpc_int32)fileSize );
  520. delete [] fileBuffer;
  521. if ( env.fault_occurred )
  522. {
  523. cmCTestLog(m_CTest, ERROR_MESSAGE, " Submission problem: " << env.fault_string << " (" << env.fault_code << ")" << std::endl);
  524. xmlrpc_env_clean(&env);
  525. xmlrpc_client_cleanup();
  526. return false;
  527. }
  528. /* Dispose of our result value. */
  529. xmlrpc_DECREF(result);
  530. }
  531. /* Clean up our error-handling environment. */
  532. xmlrpc_env_clean(&env);
  533. /* Shutdown our XML-RPC client library. */
  534. xmlrpc_client_cleanup();
  535. return true;
  536. }
  537. //----------------------------------------------------------------------------
  538. int cmCTestSubmitHandler::ProcessHandler()
  539. {
  540. const std::string &buildDirectory = m_CTest->GetCTestConfiguration("BuildDirectory");
  541. if ( buildDirectory.size() == 0 )
  542. {
  543. cmCTestLog(m_CTest, ERROR_MESSAGE, "Cannot find BuildDirectory key in the DartConfiguration.tcl" << std::endl);
  544. return -1;
  545. }
  546. if ( getenv("HTTP_PROXY") )
  547. {
  548. m_HTTPProxyType = 1;
  549. m_HTTPProxy = getenv("HTTP_PROXY");
  550. if ( getenv("HTTP_PROXY_PORT") )
  551. {
  552. m_HTTPProxy += ":";
  553. m_HTTPProxy += getenv("HTTP_PROXY_PORT");
  554. }
  555. if ( getenv("HTTP_PROXY_TYPE") )
  556. {
  557. cmStdString type = getenv("HTTP_PROXY_TYPE");
  558. // HTTP/SOCKS4/SOCKS5
  559. if ( type == "HTTP" )
  560. {
  561. m_HTTPProxyType = 1;
  562. }
  563. else if ( type == "SOCKS4" )
  564. {
  565. m_HTTPProxyType = 2;
  566. }
  567. else if ( type == "SOCKS5" )
  568. {
  569. m_HTTPProxyType = 3;
  570. }
  571. }
  572. if ( getenv("HTTP_PROXY_USER") )
  573. {
  574. m_HTTPProxyAuth = getenv("HTTP_PROXY_USER");
  575. }
  576. if ( getenv("HTTP_PROXY_PASSWD") )
  577. {
  578. m_HTTPProxyAuth += ":";
  579. m_HTTPProxyAuth += getenv("HTTP_PROXY_PASSWD");
  580. }
  581. }
  582. if ( getenv("FTP_PROXY") )
  583. {
  584. m_FTPProxyType = 1;
  585. m_FTPProxy = getenv("FTP_PROXY");
  586. if ( getenv("FTP_PROXY_PORT") )
  587. {
  588. m_FTPProxy += ":";
  589. m_FTPProxy += getenv("FTP_PROXY_PORT");
  590. }
  591. if ( getenv("FTP_PROXY_TYPE") )
  592. {
  593. cmStdString type = getenv("FTP_PROXY_TYPE");
  594. // HTTP/SOCKS4/SOCKS5
  595. if ( type == "HTTP" )
  596. {
  597. m_FTPProxyType = 1;
  598. }
  599. else if ( type == "SOCKS4" )
  600. {
  601. m_FTPProxyType = 2;
  602. }
  603. else if ( type == "SOCKS5" )
  604. {
  605. m_FTPProxyType = 3;
  606. }
  607. }
  608. }
  609. if ( m_HTTPProxy.size() > 0 )
  610. {
  611. cmCTestLog(m_CTest, HANDLER_OUTPUT, " Use HTTP Proxy: " << m_HTTPProxy << std::endl);
  612. }
  613. if ( m_FTPProxy.size() > 0 )
  614. {
  615. cmCTestLog(m_CTest, HANDLER_OUTPUT, " Use FTP Proxy: " << m_FTPProxy << std::endl);
  616. }
  617. cmGeneratedFileStream ofs;
  618. m_CTest->OpenOutputFile("Temporary", "LastSubmit.log", ofs);
  619. cmCTest::tm_VectorOfStrings files;
  620. std::string prefix = this->GetSubmitResultsPrefix();
  621. // TODO:
  622. // Check if test is enabled
  623. m_CTest->AddIfExists(files, "Update.xml");
  624. m_CTest->AddIfExists(files, "Configure.xml");
  625. m_CTest->AddIfExists(files, "Build.xml");
  626. m_CTest->AddIfExists(files, "Test.xml");
  627. if ( m_CTest->AddIfExists(files, "Coverage.xml") )
  628. {
  629. cmCTest::tm_VectorOfStrings gfiles;
  630. std::string gpath = buildDirectory + "/Testing/" + m_CTest->GetCurrentTag();
  631. std::string::size_type glen = gpath.size() + 1;
  632. gpath = gpath + "/CoverageLog*";
  633. cmCTestLog(m_CTest, DEBUG, "Globbing for: " << gpath.c_str() << std::endl);
  634. if ( cmSystemTools::SimpleGlob(gpath, gfiles, 1) )
  635. {
  636. size_t cc;
  637. for ( cc = 0; cc < gfiles.size(); cc ++ )
  638. {
  639. gfiles[cc] = gfiles[cc].substr(glen);
  640. cmCTestLog(m_CTest, DEBUG, "Glob file: " << gfiles[cc].c_str() << std::endl);
  641. files.push_back(gfiles[cc]);
  642. }
  643. }
  644. else
  645. {
  646. cmCTestLog(m_CTest, ERROR_MESSAGE, "Problem globbing" << std::endl);
  647. }
  648. }
  649. m_CTest->AddIfExists(files, "DynamicAnalysis.xml");
  650. m_CTest->AddIfExists(files, "Purify.xml");
  651. m_CTest->AddIfExists(files, "Notes.xml");
  652. if ( ofs )
  653. {
  654. ofs << "Upload files:" << std::endl;
  655. int cnt = 0;
  656. cmCTest::tm_VectorOfStrings::iterator it;
  657. for ( it = files.begin(); it != files.end(); ++ it )
  658. {
  659. ofs << cnt << "\t" << it->c_str() << std::endl;
  660. cnt ++;
  661. }
  662. }
  663. cmCTestLog(m_CTest, HANDLER_OUTPUT, "Submit files (using " << m_CTest->GetCTestConfiguration("DropMethod") << ")"
  664. << std::endl);
  665. this->SetLogFile(&ofs);
  666. if ( m_CTest->GetCTestConfiguration("DropMethod") == "" ||
  667. m_CTest->GetCTestConfiguration("DropMethod") == "ftp" )
  668. {
  669. ofs << "Using drop method: FTP" << std::endl;
  670. cmCTestLog(m_CTest, HANDLER_OUTPUT, " Using FTP submit method" << std::endl
  671. << " Drop site: ftp://");
  672. std::string url = "ftp://";
  673. url += cmCTest::MakeURLSafe(m_CTest->GetCTestConfiguration("DropSiteUser")) + ":" +
  674. cmCTest::MakeURLSafe(m_CTest->GetCTestConfiguration("DropSitePassword")) + "@" +
  675. m_CTest->GetCTestConfiguration("DropSite") +
  676. cmCTest::MakeURLSafe(m_CTest->GetCTestConfiguration("DropLocation"));
  677. if ( m_CTest->GetCTestConfiguration("DropSiteUser").size() > 0 )
  678. {
  679. cmCTestLog(m_CTest, HANDLER_OUTPUT, m_CTest->GetCTestConfiguration("DropSiteUser").c_str());
  680. if ( m_CTest->GetCTestConfiguration("DropSitePassword").size() > 0 )
  681. {
  682. cmCTestLog(m_CTest, HANDLER_OUTPUT, ":******");
  683. }
  684. cmCTestLog(m_CTest, HANDLER_OUTPUT, "@");
  685. }
  686. cmCTestLog(m_CTest, HANDLER_OUTPUT, m_CTest->GetCTestConfiguration("DropSite")
  687. << m_CTest->GetCTestConfiguration("DropLocation") << std::endl);
  688. if ( !this->SubmitUsingFTP(buildDirectory+"/Testing/"+m_CTest->GetCurrentTag(),
  689. files, prefix, url) )
  690. {
  691. cmCTestLog(m_CTest, ERROR_MESSAGE, " Problems when submitting via FTP" << std::endl);
  692. ofs << " Problems when submitting via FTP" << std::endl;
  693. return -1;
  694. }
  695. cmCTestLog(m_CTest, HANDLER_OUTPUT, " Using HTTP trigger method" << std::endl
  696. << " Trigger site: " << m_CTest->GetCTestConfiguration("TriggerSite") << std::endl);
  697. if ( !this->TriggerUsingHTTP(files, prefix, m_CTest->GetCTestConfiguration("TriggerSite")) )
  698. {
  699. cmCTestLog(m_CTest, ERROR_MESSAGE, " Problems when triggering via HTTP" << std::endl);
  700. ofs << " Problems when triggering via HTTP" << std::endl;
  701. return -1;
  702. }
  703. cmCTestLog(m_CTest, HANDLER_OUTPUT, " Submission successful" << std::endl);
  704. ofs << " Submission successful" << std::endl;
  705. return 0;
  706. }
  707. else if ( m_CTest->GetCTestConfiguration("DropMethod") == "http" )
  708. {
  709. ofs << "Using drop method: HTTP" << std::endl;
  710. cmCTestLog(m_CTest, HANDLER_OUTPUT, " Using HTTP submit method" << std::endl
  711. << " Drop site: http://");
  712. std::string url = "http://";
  713. if ( m_CTest->GetCTestConfiguration("DropSiteUser").size() > 0 )
  714. {
  715. url += m_CTest->GetCTestConfiguration("DropSiteUser");
  716. cmCTestLog(m_CTest, HANDLER_OUTPUT, m_CTest->GetCTestConfiguration("DropSiteUser").c_str());
  717. if ( m_CTest->GetCTestConfiguration("DropSitePassword").size() > 0 )
  718. {
  719. url += ":" + m_CTest->GetCTestConfiguration("DropSitePassword");
  720. cmCTestLog(m_CTest, HANDLER_OUTPUT, ":******");
  721. }
  722. url += "@";
  723. cmCTestLog(m_CTest, HANDLER_OUTPUT, "@");
  724. }
  725. url += m_CTest->GetCTestConfiguration("DropSite") + m_CTest->GetCTestConfiguration("DropLocation");
  726. cmCTestLog(m_CTest, HANDLER_OUTPUT, m_CTest->GetCTestConfiguration("DropSite")
  727. << m_CTest->GetCTestConfiguration("DropLocation") << std::endl);
  728. if ( !this->SubmitUsingHTTP(buildDirectory +"/Testing/"+m_CTest->GetCurrentTag(), files, prefix, url) )
  729. {
  730. cmCTestLog(m_CTest, ERROR_MESSAGE, " Problems when submitting via HTTP" << std::endl);
  731. ofs << " Problems when submitting via HTTP" << std::endl;
  732. return -1;
  733. }
  734. cmCTestLog(m_CTest, HANDLER_OUTPUT, " Using HTTP trigger method" << std::endl
  735. << " Trigger site: " << m_CTest->GetCTestConfiguration("TriggerSite") << std::endl);
  736. if ( !this->TriggerUsingHTTP(files, prefix, m_CTest->GetCTestConfiguration("TriggerSite")) )
  737. {
  738. cmCTestLog(m_CTest, ERROR_MESSAGE, " Problems when triggering via HTTP" << std::endl);
  739. ofs << " Problems when triggering via HTTP" << std::endl;
  740. return -1;
  741. }
  742. cmCTestLog(m_CTest, HANDLER_OUTPUT, " Submission successful" << std::endl);
  743. ofs << " Submission successful" << std::endl;
  744. return 0;
  745. }
  746. else if ( m_CTest->GetCTestConfiguration("DropMethod") == "xmlrpc" )
  747. {
  748. ofs << "Using drop method: XML-RPC" << std::endl;
  749. cmCTestLog(m_CTest, HANDLER_OUTPUT, " Using XML-RPC submit method" << std::endl);
  750. std::string url = m_CTest->GetCTestConfiguration("DropSite");
  751. prefix = m_CTest->GetCTestConfiguration("DropLocation");
  752. if ( !this->SubmitUsingXMLRPC(buildDirectory+"/Testing/"+m_CTest->GetCurrentTag(), files, prefix, url) )
  753. {
  754. cmCTestLog(m_CTest, ERROR_MESSAGE, " Problems when submitting via XML-RPC" << std::endl);
  755. ofs << " Problems when submitting via XML-RPC" << std::endl;
  756. return -1;
  757. }
  758. cmCTestLog(m_CTest, HANDLER_OUTPUT, " Submission successful" << std::endl);
  759. ofs << " Submission successful" << std::endl;
  760. return 0;
  761. }
  762. else if ( m_CTest->GetCTestConfiguration("DropMethod") == "scp" )
  763. {
  764. std::string url;
  765. if ( m_CTest->GetCTestConfiguration("DropSiteUser").size() > 0 )
  766. {
  767. url += m_CTest->GetCTestConfiguration("DropSiteUser") + "@";
  768. }
  769. url += m_CTest->GetCTestConfiguration("DropSite") + ":" + m_CTest->GetCTestConfiguration("DropLocation");
  770. if ( !this->SubmitUsingSCP(m_CTest->GetCTestConfiguration("ScpCommand"),
  771. buildDirectory+"/Testing/"+m_CTest->GetCurrentTag(), files, prefix, url) )
  772. {
  773. cmCTestLog(m_CTest, ERROR_MESSAGE, " Problems when submitting via SCP" << std::endl);
  774. ofs << " Problems when submitting via SCP" << std::endl;
  775. return -1;
  776. }
  777. cmCTestLog(m_CTest, HANDLER_OUTPUT, " Submission successful" << std::endl);
  778. ofs << " Submission successful" << std::endl;
  779. }
  780. cmCTestLog(m_CTest, ERROR_MESSAGE, " Unknown submission method: \"" << m_CTest->GetCTestConfiguration("DropMethod") << "\"" << std::endl);
  781. return -1;
  782. }
  783. //----------------------------------------------------------------------------
  784. std::string cmCTestSubmitHandler::GetSubmitResultsPrefix()
  785. {
  786. std::string name = m_CTest->GetCTestConfiguration("Site") +
  787. "___" + m_CTest->GetCTestConfiguration("BuildName") +
  788. "___" + m_CTest->GetCurrentTag() + "-" +
  789. m_CTest->GetTestModelString() + "___XML___";
  790. return name;
  791. }