cmCTestUpdateHandler.cxx 12 KB

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