cmCTestUpdateHandler.cxx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "cmCTestUpdateHandler.h"
  11. #include "cmCTest.h"
  12. #include "cmake.h"
  13. #include "cmMakefile.h"
  14. #include "cmGlobalGenerator.h"
  15. #include "cmVersion.h"
  16. #include "cmGeneratedFileStream.h"
  17. #include "cmXMLParser.h"
  18. #include "cmXMLWriter.h"
  19. #include "cmCLocaleEnvironmentScope.h"
  20. #include "cmCTestVC.h"
  21. #include "cmCTestCVS.h"
  22. #include "cmCTestSVN.h"
  23. #include "cmCTestBZR.h"
  24. #include "cmCTestGIT.h"
  25. #include "cmCTestHG.h"
  26. #include "cmCTestP4.h"
  27. #include <cmsys/auto_ptr.hxx>
  28. //#include <cmsys/RegularExpression.hxx>
  29. #include <cmsys/Process.h>
  30. // used for sleep
  31. #ifdef _WIN32
  32. #include "windows.h"
  33. #endif
  34. #include <stdlib.h>
  35. #include <math.h>
  36. #include <float.h>
  37. //----------------------------------------------------------------------
  38. static const char* cmCTestUpdateHandlerUpdateStrings[] =
  39. {
  40. "Unknown",
  41. "CVS",
  42. "SVN",
  43. "BZR",
  44. "GIT",
  45. "HG",
  46. "P4"
  47. };
  48. static const char* cmCTestUpdateHandlerUpdateToString(int type)
  49. {
  50. if ( type < cmCTestUpdateHandler::e_UNKNOWN ||
  51. type >= cmCTestUpdateHandler::e_LAST )
  52. {
  53. return cmCTestUpdateHandlerUpdateStrings[cmCTestUpdateHandler::e_UNKNOWN];
  54. }
  55. return cmCTestUpdateHandlerUpdateStrings[type];
  56. }
  57. //----------------------------------------------------------------------
  58. cmCTestUpdateHandler::cmCTestUpdateHandler()
  59. {
  60. }
  61. //----------------------------------------------------------------------
  62. void cmCTestUpdateHandler::Initialize()
  63. {
  64. this->Superclass::Initialize();
  65. this->UpdateCommand = "";
  66. this->UpdateType = e_CVS;
  67. }
  68. //----------------------------------------------------------------------
  69. int cmCTestUpdateHandler::DetermineType(const char* cmd, const char* type)
  70. {
  71. cmCTestOptionalLog(this->CTest, DEBUG,
  72. "Determine update type from command: " << cmd << " and type: " << type <<
  73. std::endl, this->Quiet);
  74. if ( type && *type )
  75. {
  76. cmCTestOptionalLog(this->CTest, DEBUG, "Type specified: " << type <<
  77. std::endl, this->Quiet);
  78. std::string stype = cmSystemTools::LowerCase(type);
  79. if ( stype.find("cvs") != std::string::npos )
  80. {
  81. return cmCTestUpdateHandler::e_CVS;
  82. }
  83. if ( stype.find("svn") != std::string::npos )
  84. {
  85. return cmCTestUpdateHandler::e_SVN;
  86. }
  87. if ( stype.find("bzr") != std::string::npos )
  88. {
  89. return cmCTestUpdateHandler::e_BZR;
  90. }
  91. if ( stype.find("git") != std::string::npos )
  92. {
  93. return cmCTestUpdateHandler::e_GIT;
  94. }
  95. if ( stype.find("hg") != std::string::npos )
  96. {
  97. return cmCTestUpdateHandler::e_HG;
  98. }
  99. if ( stype.find("p4") != std::string::npos )
  100. {
  101. return cmCTestUpdateHandler::e_P4;
  102. }
  103. }
  104. else
  105. {
  106. cmCTestOptionalLog(this->CTest, DEBUG,
  107. "Type not specified, check command: " << cmd << std::endl, this->Quiet);
  108. std::string stype = cmSystemTools::LowerCase(cmd);
  109. if ( stype.find("cvs") != std::string::npos )
  110. {
  111. return cmCTestUpdateHandler::e_CVS;
  112. }
  113. if ( stype.find("svn") != std::string::npos )
  114. {
  115. return cmCTestUpdateHandler::e_SVN;
  116. }
  117. if ( stype.find("bzr") != std::string::npos )
  118. {
  119. return cmCTestUpdateHandler::e_BZR;
  120. }
  121. if ( stype.find("git") != std::string::npos )
  122. {
  123. return cmCTestUpdateHandler::e_GIT;
  124. }
  125. if ( stype.find("hg") != std::string::npos )
  126. {
  127. return cmCTestUpdateHandler::e_HG;
  128. }
  129. if ( stype.find("p4") != std::string::npos )
  130. {
  131. return cmCTestUpdateHandler::e_P4;
  132. }
  133. }
  134. return cmCTestUpdateHandler::e_UNKNOWN;
  135. }
  136. //----------------------------------------------------------------------
  137. //clearly it would be nice if this were broken up into a few smaller
  138. //functions and commented...
  139. int cmCTestUpdateHandler::ProcessHandler()
  140. {
  141. // Make sure VCS tool messages are in English so we can parse them.
  142. cmCLocaleEnvironmentScope fixLocale;
  143. static_cast<void>(fixLocale);
  144. // Get source dir
  145. const char* sourceDirectory = this->GetOption("SourceDirectory");
  146. if ( !sourceDirectory )
  147. {
  148. cmCTestLog(this->CTest, ERROR_MESSAGE,
  149. "Cannot find SourceDirectory key in the DartConfiguration.tcl"
  150. << std::endl);
  151. return -1;
  152. }
  153. cmGeneratedFileStream ofs;
  154. if ( !this->CTest->GetShowOnly() )
  155. {
  156. this->StartLogFile("Update", ofs);
  157. }
  158. cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
  159. " Updating the repository: " << sourceDirectory << std::endl,
  160. this->Quiet);
  161. if(!this->SelectVCS())
  162. {
  163. return -1;
  164. }
  165. cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " Use "
  166. << cmCTestUpdateHandlerUpdateToString(this->UpdateType)
  167. << " repository type"
  168. << std::endl;, this->Quiet);
  169. // Create an object to interact with the VCS tool.
  170. cmsys::auto_ptr<cmCTestVC> vc;
  171. switch (this->UpdateType)
  172. {
  173. case e_CVS: vc.reset(new cmCTestCVS(this->CTest, ofs)); break;
  174. case e_SVN: vc.reset(new cmCTestSVN(this->CTest, ofs)); break;
  175. case e_BZR: vc.reset(new cmCTestBZR(this->CTest, ofs)); break;
  176. case e_GIT: vc.reset(new cmCTestGIT(this->CTest, ofs)); break;
  177. case e_HG: vc.reset(new cmCTestHG(this->CTest, ofs)); break;
  178. case e_P4: vc.reset(new cmCTestP4(this->CTest, ofs)); break;
  179. default: vc.reset(new cmCTestVC(this->CTest, ofs)); break;
  180. }
  181. vc->SetCommandLineTool(this->UpdateCommand);
  182. vc->SetSourceDirectory(sourceDirectory);
  183. // Cleanup the working tree.
  184. vc->Cleanup();
  185. //
  186. // Now update repository and remember what files were updated
  187. //
  188. cmGeneratedFileStream os;
  189. if(!this->StartResultingXML(cmCTest::PartUpdate, "Update", os))
  190. {
  191. cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open log file"
  192. << std::endl);
  193. return -1;
  194. }
  195. std::string start_time = this->CTest->CurrentTime();
  196. unsigned int start_time_time =
  197. static_cast<unsigned int>(cmSystemTools::GetTime());
  198. double elapsed_time_start = cmSystemTools::GetTime();
  199. bool updated = vc->Update();
  200. std::string buildname = cmCTest::SafeBuildIdField(
  201. this->CTest->GetCTestConfiguration("BuildName"));
  202. cmXMLWriter xml(os);
  203. xml.StartDocument();
  204. xml.StartElement("Update");
  205. xml.Attribute("mode", "Client");
  206. xml.Attribute("Generator",
  207. std::string("ctest-") + cmVersion::GetCMakeVersion());
  208. xml.Element("Site", this->CTest->GetCTestConfiguration("Site"));
  209. xml.Element("BuildName", buildname);
  210. xml.Element("BuildStamp", this->CTest->GetCurrentTag() + "-" +
  211. this->CTest->GetTestModelString());
  212. xml.Element("StartDateTime", start_time);
  213. xml.Element("StartTime", start_time_time);
  214. xml.Element("UpdateCommand", vc->GetUpdateCommandLine());
  215. xml.Element("UpdateType",
  216. cmCTestUpdateHandlerUpdateToString(this->UpdateType));
  217. vc->WriteXML(xml);
  218. int localModifications = 0;
  219. int numUpdated = vc->GetPathCount(cmCTestVC::PathUpdated);
  220. if(numUpdated)
  221. {
  222. cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
  223. " Found " << numUpdated << " updated files\n", this->Quiet);
  224. }
  225. if(int numModified = vc->GetPathCount(cmCTestVC::PathModified))
  226. {
  227. cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
  228. " Found " << numModified << " locally modified files\n", this->Quiet);
  229. localModifications += numModified;
  230. }
  231. if(int numConflicting = vc->GetPathCount(cmCTestVC::PathConflicting))
  232. {
  233. cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
  234. " Found " << numConflicting << " conflicting files\n", this->Quiet);
  235. localModifications += numConflicting;
  236. }
  237. cmCTestOptionalLog(this->CTest, DEBUG, "End" << std::endl, this->Quiet);
  238. std::string end_time = this->CTest->CurrentTime();
  239. xml.Element("EndDateTime", end_time);
  240. xml.Element("EndTime", static_cast<unsigned int>(cmSystemTools::GetTime()));
  241. xml.Element("ElapsedMinutes",
  242. static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start)/6)/10.0);
  243. xml.StartElement("UpdateReturnStatus");
  244. if(localModifications)
  245. {
  246. xml.Content("Update error: "
  247. "There are modified or conflicting files in the repository");
  248. cmCTestLog(this->CTest, ERROR_MESSAGE,
  249. " There are modified or conflicting files in the repository"
  250. << std::endl);
  251. }
  252. if(!updated)
  253. {
  254. xml.Content("Update command failed:\n");
  255. xml.Content(vc->GetUpdateCommandLine());
  256. cmCTestLog(this->CTest, HANDLER_OUTPUT, " Update command failed: "
  257. << vc->GetUpdateCommandLine() << "\n");
  258. }
  259. xml.EndElement(); // UpdateReturnStatus
  260. xml.EndElement(); // Update
  261. xml.EndDocument();
  262. return updated? numUpdated : -1;
  263. }
  264. //----------------------------------------------------------------------
  265. int cmCTestUpdateHandler::DetectVCS(const char* dir)
  266. {
  267. std::string sourceDirectory = dir;
  268. cmCTestOptionalLog(this->CTest, DEBUG, "Check directory: "
  269. << sourceDirectory << std::endl, this->Quiet);
  270. sourceDirectory += "/.svn";
  271. if ( cmSystemTools::FileExists(sourceDirectory.c_str()) )
  272. {
  273. return cmCTestUpdateHandler::e_SVN;
  274. }
  275. sourceDirectory = dir;
  276. sourceDirectory += "/CVS";
  277. if ( cmSystemTools::FileExists(sourceDirectory.c_str()) )
  278. {
  279. return cmCTestUpdateHandler::e_CVS;
  280. }
  281. sourceDirectory = dir;
  282. sourceDirectory += "/.bzr";
  283. if ( cmSystemTools::FileExists(sourceDirectory.c_str()) )
  284. {
  285. return cmCTestUpdateHandler::e_BZR;
  286. }
  287. sourceDirectory = dir;
  288. sourceDirectory += "/.git";
  289. if ( cmSystemTools::FileExists(sourceDirectory.c_str()) )
  290. {
  291. return cmCTestUpdateHandler::e_GIT;
  292. }
  293. sourceDirectory = dir;
  294. sourceDirectory += "/.hg";
  295. if ( cmSystemTools::FileExists(sourceDirectory.c_str()) )
  296. {
  297. return cmCTestUpdateHandler::e_HG;
  298. }
  299. sourceDirectory = dir;
  300. sourceDirectory += "/.p4";
  301. if ( cmSystemTools::FileExists(sourceDirectory.c_str()) )
  302. {
  303. return cmCTestUpdateHandler::e_P4;
  304. }
  305. sourceDirectory = dir;
  306. sourceDirectory += "/.p4config";
  307. if ( cmSystemTools::FileExists(sourceDirectory.c_str()) )
  308. {
  309. return cmCTestUpdateHandler::e_P4;
  310. }
  311. return cmCTestUpdateHandler::e_UNKNOWN;
  312. }
  313. //----------------------------------------------------------------------
  314. bool cmCTestUpdateHandler::SelectVCS()
  315. {
  316. // Get update command
  317. this->UpdateCommand = this->CTest->GetCTestConfiguration("UpdateCommand");
  318. // Detect the VCS managing the source tree.
  319. this->UpdateType = this->DetectVCS(this->GetOption("SourceDirectory"));
  320. if (this->UpdateType == e_UNKNOWN)
  321. {
  322. // The source tree does not have a recognized VCS. Check the
  323. // configuration value or command name.
  324. this->UpdateType = this->DetermineType(this->UpdateCommand.c_str(),
  325. this->CTest->GetCTestConfiguration("UpdateType").c_str());
  326. }
  327. // If no update command was specified, lookup one for this VCS tool.
  328. if (this->UpdateCommand.empty())
  329. {
  330. const char* key = 0;
  331. switch (this->UpdateType)
  332. {
  333. case e_CVS: key = "CVSCommand"; break;
  334. case e_SVN: key = "SVNCommand"; break;
  335. case e_BZR: key = "BZRCommand"; break;
  336. case e_GIT: key = "GITCommand"; break;
  337. case e_HG: key = "HGCommand"; break;
  338. case e_P4: key = "P4Command"; break;
  339. default: break;
  340. }
  341. if (key)
  342. {
  343. this->UpdateCommand = this->CTest->GetCTestConfiguration(key);
  344. }
  345. if (this->UpdateCommand.empty())
  346. {
  347. std::ostringstream e;
  348. e << "Cannot find UpdateCommand ";
  349. if (key)
  350. {
  351. e << "or " << key;
  352. }
  353. e << " configuration key.";
  354. cmCTestLog(this->CTest, ERROR_MESSAGE, e.str() << std::endl);
  355. return false;
  356. }
  357. }
  358. return true;
  359. }