cmCTestSubmitHandler.cxx 37 KB

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