cmCTestUpdateHandler.cxx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  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 "cmCTestUpdateHandler.h"
  14. #include "cmCTest.h"
  15. #include "cmake.h"
  16. #include "cmMakefile.h"
  17. #include "cmLocalGenerator.h"
  18. #include "cmGlobalGenerator.h"
  19. //#include <cmsys/RegularExpression.hxx>
  20. #include <cmsys/Process.h>
  21. // used for sleep
  22. #ifdef _WIN32
  23. #include "windows.h"
  24. #endif
  25. #include <stdlib.h>
  26. #include <math.h>
  27. #include <float.h>
  28. //----------------------------------------------------------------------
  29. cmCTestUpdateHandler::cmCTestUpdateHandler()
  30. {
  31. m_Verbose = false;
  32. m_CTest = 0;
  33. }
  34. //----------------------------------------------------------------------
  35. //clearly it would be nice if this were broken up into a few smaller
  36. //functions and commented...
  37. int cmCTestUpdateHandler::UpdateDirectory(cmCTest *ctest_inst)
  38. {
  39. m_CTest = ctest_inst;
  40. int count = 0;
  41. std::string::size_type cc, kk;
  42. std::string cvsCommand = m_CTest->GetDartConfiguration("CVSCommand");
  43. if ( cvsCommand.size() == 0 )
  44. {
  45. std::cerr << "Cannot find CVSCommand key in the DartConfiguration.tcl" << std::endl;
  46. return -1;
  47. }
  48. std::string cvsOptions = m_CTest->GetDartConfiguration("CVSUpdateOptions");
  49. if ( cvsOptions.size() == 0 )
  50. {
  51. std::cerr << "Cannot find CVSUpdateOptions key in the DartConfiguration.tcl" << std::endl;
  52. return -1;
  53. }
  54. std::string sourceDirectory = m_CTest->GetDartConfiguration("SourceDirectory");
  55. if ( sourceDirectory.size() == 0 )
  56. {
  57. std::cerr << "Cannot find SourceDirectory key in the DartConfiguration.tcl" << std::endl;
  58. return -1;
  59. }
  60. std::string extra_update_opts;
  61. if ( m_CTest->GetTestModel() == cmCTest::NIGHTLY )
  62. {
  63. struct tm* t = cmCTest::GetNightlyTime(m_CTest->GetDartConfiguration("NightlyStartTime"),
  64. m_Verbose, m_CTest->GetTomorrowTag());
  65. char current_time[1024];
  66. sprintf(current_time, "%04d-%02d-%02d %02d:%02d:%02d UTC",
  67. t->tm_year + 1900,
  68. t->tm_mon + 1,
  69. t->tm_mday,
  70. t->tm_hour,
  71. t->tm_min,
  72. t->tm_sec);
  73. std::string today_update_date = current_time;
  74. extra_update_opts += "-D \"" + today_update_date +"\"";
  75. //std::cout << "Update: " << extra_update_opts << std::endl;
  76. }
  77. std::string command = cvsCommand + " -z3 update " + cvsOptions +
  78. " " + extra_update_opts;
  79. std::ofstream os;
  80. if ( !m_CTest->OpenOutputFile(m_CTest->GetCurrentTag(), "Update.xml", os) )
  81. {
  82. std::cerr << "Cannot open log file" << std::endl;
  83. }
  84. std::string start_time = m_CTest->CurrentTime();
  85. double elapsed_time_start = cmSystemTools::GetTime();
  86. std::string goutput;
  87. int retVal = 0;
  88. bool res = true;
  89. std::ofstream ofs;
  90. if ( !m_CTest->GetShowOnly() )
  91. {
  92. res = cmSystemTools::RunSingleCommand(command.c_str(), &goutput,
  93. &retVal, sourceDirectory.c_str(),
  94. m_Verbose, 0 /*m_TimeOut*/);
  95. if ( m_CTest->OpenOutputFile("Temporary", "LastUpdate.log", ofs) )
  96. {
  97. ofs << goutput << std::endl;;
  98. }
  99. }
  100. else
  101. {
  102. std::cout << "Update with command: " << command << std::endl;
  103. }
  104. os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  105. << "<Update mode=\"Client\" Generator=\"ctest-" << CMake_VERSION_FULL << "\">\n"
  106. << "\t<Site>" << m_CTest->GetDartConfiguration("Site") << "</Site>\n"
  107. << "\t<BuildName>" << m_CTest->GetDartConfiguration("BuildName")
  108. << "</BuildName>\n"
  109. << "\t<BuildStamp>" << m_CTest->GetCurrentTag() << "-"
  110. << m_CTest->GetTestModelString() << "</BuildStamp>" << std::endl;
  111. os << "\t<StartDateTime>" << start_time << "</StartDateTime>\n"
  112. << "\t<UpdateCommand>" << m_CTest->MakeXMLSafe(command)
  113. << "</UpdateCommand>\n"
  114. << "\t<UpdateReturnStatus>";
  115. int failed = 0;
  116. if ( !res || retVal )
  117. {
  118. os << "Update error: ";
  119. os << m_CTest->MakeXMLSafe(goutput);
  120. std::cerr << "Update with command: " << command << " failed" << std::endl;
  121. failed = 1;
  122. }
  123. os << "</UpdateReturnStatus>" << std::endl;
  124. if ( !failed )
  125. {
  126. std::vector<cmStdString> lines;
  127. cmSystemTools::Split(goutput.c_str(), lines);
  128. std::cout << "Updated; gathering version information" << std::endl;
  129. cmsys::RegularExpression date_author("^date: +([^;]+); +author: +([^;]+); +state: +[^;]+;");
  130. cmsys::RegularExpression revision("^revision +([^ ]*) *$");
  131. cmsys::RegularExpression end_of_file("^=============================================================================$");
  132. cmsys::RegularExpression end_of_comment("^----------------------------$");
  133. std::string current_path = "<no-path>";
  134. bool first_file = true;
  135. cmCTestUpdateHandler::AuthorsToUpdatesMap authors_files_map;
  136. int num_updated = 0;
  137. int num_modified = 0;
  138. int num_conflicting = 0;
  139. for ( cc= 0 ; cc < lines.size(); cc ++ )
  140. {
  141. const char* line = lines[cc].c_str();
  142. char mod = line[0];
  143. if ( line[1] == ' ' && mod != '?' )
  144. {
  145. if ( mod != 'M' && mod != 'C' )
  146. {
  147. count ++;
  148. }
  149. const char* file = line + 2;
  150. //std::cout << "Line" << cc << ": " << mod << " - " << file << std::endl;
  151. std::string logcommand = cvsCommand + " -z3 log -N " + file;
  152. //std::cout << "Do log: " << logcommand << std::endl;
  153. std::string output;
  154. res = cmSystemTools::RunSingleCommand(logcommand.c_str(), &output,
  155. &retVal, sourceDirectory.c_str(),
  156. m_Verbose, 0 /*m_TimeOut*/);
  157. if ( ofs )
  158. {
  159. ofs << output << std::endl;
  160. }
  161. if ( res && retVal == 0)
  162. {
  163. //std::cout << output << std::endl;
  164. std::vector<cmStdString> ulines;
  165. cmSystemTools::Split(output.c_str(), ulines);
  166. std::string::size_type sline = 0;
  167. std::string srevision1 = "Unknown";
  168. std::string sdate1 = "Unknown";
  169. std::string sauthor1 = "Unknown";
  170. std::string semail1 = "Unknown";
  171. std::string comment1 = "";
  172. std::string srevision2 = "Unknown";
  173. std::string sdate2 = "Unknown";
  174. std::string sauthor2 = "Unknown";
  175. std::string comment2 = "";
  176. std::string semail2 = "Unknown";
  177. bool have_first = false;
  178. bool have_second = false;
  179. for ( kk = 0; kk < ulines.size(); kk ++ )
  180. {
  181. const char* clp = ulines[kk].c_str();
  182. if ( !have_second && !sline && revision.find(clp) )
  183. {
  184. if ( !have_first )
  185. {
  186. srevision1 = revision.match(1);
  187. }
  188. else
  189. {
  190. srevision2 = revision.match(1);
  191. }
  192. }
  193. else if ( !have_second && !sline && date_author.find(clp) )
  194. {
  195. sline = kk + 1;
  196. if ( !have_first )
  197. {
  198. sdate1 = date_author.match(1);
  199. sauthor1 = date_author.match(2);
  200. }
  201. else
  202. {
  203. sdate2 = date_author.match(1);
  204. sauthor2 = date_author.match(2);
  205. }
  206. }
  207. else if ( sline && end_of_comment.find(clp) || end_of_file.find(clp))
  208. {
  209. if ( !have_first )
  210. {
  211. have_first = true;
  212. }
  213. else if ( !have_second )
  214. {
  215. have_second = true;
  216. }
  217. sline = 0;
  218. }
  219. else if ( sline )
  220. {
  221. if ( !have_first )
  222. {
  223. comment1 += clp;
  224. comment1 += "\n";
  225. }
  226. else
  227. {
  228. comment2 += clp;
  229. comment2 += "\n";
  230. }
  231. }
  232. }
  233. if ( mod == 'M' )
  234. {
  235. comment1 = "Locally modified file\n";
  236. }
  237. if ( mod == 'C' )
  238. {
  239. comment1 = "Conflict while updating\n";
  240. }
  241. std::string path = cmSystemTools::GetFilenamePath(file);
  242. std::string fname = cmSystemTools::GetFilenameName(file);
  243. if ( path != current_path )
  244. {
  245. if ( !first_file )
  246. {
  247. os << "\t</Directory>" << std::endl;
  248. }
  249. else
  250. {
  251. first_file = false;
  252. }
  253. os << "\t<Directory>\n"
  254. << "\t\t<Name>" << path << "</Name>" << std::endl;
  255. }
  256. if ( mod == 'C' )
  257. {
  258. num_conflicting ++;
  259. os << "\t<Conflicting>" << std::endl;
  260. }
  261. else if ( mod == 'M' )
  262. {
  263. num_modified ++;
  264. os << "\t<Modified>" << std::endl;
  265. }
  266. else
  267. {
  268. num_updated ++;
  269. os << "\t<Updated>" << std::endl;
  270. }
  271. if ( srevision2 == "Unknown" )
  272. {
  273. srevision2 = srevision1;
  274. }
  275. os << "\t\t<File Directory=\"" << path << "\">" << fname
  276. << "</File>\n"
  277. << "\t\t<Directory>" << path << "</Directory>\n"
  278. << "\t\t<FullName>" << file << "</FullName>\n"
  279. << "\t\t<CheckinDate>" << sdate1 << "</CheckinDate>\n"
  280. << "\t\t<Author>" << sauthor1 << "</Author>\n"
  281. << "\t\t<Email>" << semail1 << "</Email>\n"
  282. << "\t\t<Log>" << cmCTest::MakeXMLSafe(comment1) << "</Log>\n"
  283. << "\t\t<Revision>" << srevision1 << "</Revision>\n"
  284. << "\t\t<PriorRevision>" << srevision2 << "</PriorRevision>"
  285. << std::endl;
  286. if ( srevision2 != srevision1 )
  287. {
  288. os
  289. << "\t\t<Revisions>\n"
  290. << "\t\t\t<Revision>" << srevision1 << "</Revision>\n"
  291. << "\t\t\t<PreviousRevision>" << srevision2 << "</PreviousRevision>\n"
  292. << "\t\t\t<Author>" << sauthor1<< "</Author>\n"
  293. << "\t\t\t<Date>" << sdate1 << "</Date>\n"
  294. << "\t\t\t<Comment>" << cmCTest::MakeXMLSafe(comment1) << "</Comment>\n"
  295. << "\t\t\t<Email>" << semail1 << "</Email>\n"
  296. << "\t\t</Revisions>\n"
  297. << "\t\t<Revisions>\n"
  298. << "\t\t\t<Revision>" << srevision2 << "</Revision>\n"
  299. << "\t\t\t<PreviousRevision>" << srevision2 << "</PreviousRevision>\n"
  300. << "\t\t\t<Author>" << sauthor2<< "</Author>\n"
  301. << "\t\t\t<Date>" << sdate2 << "</Date>\n"
  302. << "\t\t\t<Comment>" << cmCTest::MakeXMLSafe(comment2) << "</Comment>\n"
  303. << "\t\t\t<Email>" << semail2 << "</Email>\n"
  304. << "\t\t</Revisions>" << std::endl;
  305. }
  306. if ( mod == 'C' )
  307. {
  308. os << "\t</Conflicting>" << std::endl;
  309. }
  310. else if ( mod == 'M' )
  311. {
  312. os << "\t</Modified>" << std::endl;
  313. }
  314. else
  315. {
  316. os << "\t</Updated>" << std::endl;
  317. }
  318. cmCTestUpdateHandler::UpdateFiles *u = &authors_files_map[sauthor1];
  319. cmCTestUpdateHandler::StringPair p;
  320. p.first = path;
  321. p.second = fname;
  322. u->push_back(p);
  323. current_path = path;
  324. }
  325. }
  326. }
  327. if ( num_updated )
  328. {
  329. std::cout << "Found " << num_updated << " updated files" << std::endl;
  330. }
  331. if ( num_modified )
  332. {
  333. std::cout << "Found " << num_modified << " locally modified files"
  334. << std::endl;
  335. }
  336. if ( num_conflicting )
  337. {
  338. std::cout << "Found " << num_conflicting << " conflicting files"
  339. << std::endl;
  340. }
  341. if ( !first_file )
  342. {
  343. os << "\t</Directory>" << std::endl;
  344. }
  345. cmCTestUpdateHandler::AuthorsToUpdatesMap::iterator it;
  346. for ( it = authors_files_map.begin();
  347. it != authors_files_map.end();
  348. it ++ )
  349. {
  350. os << "\t<Author>\n"
  351. << "\t\t<Name>" << it->first << "</Name>" << std::endl;
  352. cmCTestUpdateHandler::UpdateFiles *u = &(it->second);
  353. for ( cc = 0; cc < u->size(); cc ++ )
  354. {
  355. os << "\t\t<File Directory=\"" << (*u)[cc].first << "\">"
  356. << (*u)[cc].second << "</File>" << std::endl;
  357. }
  358. os << "\t</Author>" << std::endl;
  359. }
  360. }
  361. //std::cout << "End" << std::endl;
  362. std::string end_time = m_CTest->CurrentTime();
  363. os << "\t<EndDateTime>" << end_time << "</EndDateTime>\n"
  364. << "<ElapsedMinutes>" <<
  365. static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start)/6)/10.0
  366. << "</ElapsedMinutes>"
  367. << "</Update>" << std::endl;
  368. if ( ofs )
  369. {
  370. ofs.close();
  371. }
  372. if (! res || retVal )
  373. {
  374. std::cerr << "Error(s) when updating the project" << std::endl;
  375. std::cerr << "Output: " << goutput << std::endl;
  376. return -1;
  377. }
  378. return count;
  379. }