cmCTestUpdateHandler.cxx 14 KB

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