cmCTestSubmitHandler.cxx 31 KB

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