1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmCTestUpdateHandler.cxx,v $
6 Date: $Date: 2009-07-10 15:07:57 $
7 Version: $Revision: 1.67 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
18 #include "cmCTestUpdateHandler.h"
22 #include "cmMakefile.h"
23 #include "cmLocalGenerator.h"
24 #include "cmGlobalGenerator.h"
25 #include "cmVersion.h"
26 #include "cmGeneratedFileStream.h"
27 #include "cmXMLParser.h"
28 #include "cmXMLSafe.h"
30 #include "cmCTestVC.h"
31 #include "cmCTestCVS.h"
32 #include "cmCTestSVN.h"
33 #include "cmCTestBZR.h"
34 #include "cmCTestGIT.h"
35 #include "cmCTestHG.h"
37 #include <cmsys/auto_ptr.hxx>
39 //#include <cmsys/RegularExpression.hxx>
40 #include <cmsys/Process.h>
51 //----------------------------------------------------------------------
52 static const char* cmCTestUpdateHandlerUpdateStrings
[] =
62 static const char* cmCTestUpdateHandlerUpdateToString(int type
)
64 if ( type
< cmCTestUpdateHandler::e_UNKNOWN
||
65 type
>= cmCTestUpdateHandler::e_LAST
)
67 return cmCTestUpdateHandlerUpdateStrings
[cmCTestUpdateHandler::e_UNKNOWN
];
69 return cmCTestUpdateHandlerUpdateStrings
[type
];
72 class cmCTestUpdateHandlerLocale
75 cmCTestUpdateHandlerLocale();
76 ~cmCTestUpdateHandlerLocale();
78 std::string saveLCMessages
;
81 cmCTestUpdateHandlerLocale::cmCTestUpdateHandlerLocale()
83 const char* lcmess
= cmSystemTools::GetEnv("LC_MESSAGES");
86 saveLCMessages
= lcmess
;
88 // if LC_MESSAGES is not set to C, then
89 // set it, so that svn/cvs info will be in english ascii
90 if(! (lcmess
&& strcmp(lcmess
, "C") == 0))
92 cmSystemTools::PutEnv("LC_MESSAGES=C");
96 cmCTestUpdateHandlerLocale::~cmCTestUpdateHandlerLocale()
98 // restore the value of LC_MESSAGES after running the version control
100 if(saveLCMessages
.size())
102 std::string put
= "LC_MESSAGES=";
103 put
+= saveLCMessages
;
104 cmSystemTools::PutEnv(put
.c_str());
108 cmSystemTools::UnsetEnv("LC_MESSAGES");
112 //----------------------------------------------------------------------
113 cmCTestUpdateHandler::cmCTestUpdateHandler()
117 //----------------------------------------------------------------------
118 void cmCTestUpdateHandler::Initialize()
120 this->Superclass::Initialize();
121 this->UpdateCommand
= "";
122 this->UpdateType
= e_CVS
;
125 //----------------------------------------------------------------------
126 int cmCTestUpdateHandler::DetermineType(const char* cmd
, const char* type
)
128 cmCTestLog(this->CTest
, DEBUG
, "Determine update type from command: " << cmd
129 << " and type: " << type
<< std::endl
);
132 cmCTestLog(this->CTest
, DEBUG
, "Type specified: " << type
<< std::endl
);
133 std::string stype
= cmSystemTools::LowerCase(type
);
134 if ( stype
.find("cvs") != std::string::npos
)
136 return cmCTestUpdateHandler::e_CVS
;
138 if ( stype
.find("svn") != std::string::npos
)
140 return cmCTestUpdateHandler::e_SVN
;
142 if ( stype
.find("bzr") != std::string::npos
)
144 return cmCTestUpdateHandler::e_BZR
;
146 if ( stype
.find("git") != std::string::npos
)
148 return cmCTestUpdateHandler::e_GIT
;
150 if ( stype
.find("hg") != std::string::npos
)
152 return cmCTestUpdateHandler::e_HG
;
157 cmCTestLog(this->CTest
, DEBUG
, "Type not specified, check command: "
158 << cmd
<< std::endl
);
159 std::string stype
= cmSystemTools::LowerCase(cmd
);
160 if ( stype
.find("cvs") != std::string::npos
)
162 return cmCTestUpdateHandler::e_CVS
;
164 if ( stype
.find("svn") != std::string::npos
)
166 return cmCTestUpdateHandler::e_SVN
;
168 if ( stype
.find("bzr") != std::string::npos
)
170 return cmCTestUpdateHandler::e_BZR
;
172 if ( stype
.find("git") != std::string::npos
)
174 return cmCTestUpdateHandler::e_GIT
;
176 if ( stype
.find("hg") != std::string::npos
)
178 return cmCTestUpdateHandler::e_HG
;
181 return cmCTestUpdateHandler::e_UNKNOWN
;
184 //----------------------------------------------------------------------
185 //clearly it would be nice if this were broken up into a few smaller
186 //functions and commented...
187 int cmCTestUpdateHandler::ProcessHandler()
189 // Make sure VCS tool messages are in English so we can parse them.
190 cmCTestUpdateHandlerLocale fixLocale
;
191 static_cast<void>(fixLocale
);
194 const char* sourceDirectory
= this->GetOption("SourceDirectory");
195 if ( !sourceDirectory
)
197 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
198 "Cannot find SourceDirectory key in the DartConfiguration.tcl"
203 cmGeneratedFileStream ofs
;
204 if ( !this->CTest
->GetShowOnly() )
206 this->StartLogFile("Update", ofs
);
209 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
210 "Updating the repository" << std::endl
);
212 // Make sure the source directory exists.
213 if(!this->InitialCheckout(ofs
))
218 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Updating the repository: "
219 << sourceDirectory
<< std::endl
);
221 if(!this->SelectVCS())
226 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Use "
227 << cmCTestUpdateHandlerUpdateToString(this->UpdateType
)
228 << " repository type"
231 // Create an object to interact with the VCS tool.
232 cmsys::auto_ptr
<cmCTestVC
> vc
;
233 switch (this->UpdateType
)
235 case e_CVS
: vc
.reset(new cmCTestCVS(this->CTest
, ofs
)); break;
236 case e_SVN
: vc
.reset(new cmCTestSVN(this->CTest
, ofs
)); break;
237 case e_BZR
: vc
.reset(new cmCTestBZR(this->CTest
, ofs
)); break;
238 case e_GIT
: vc
.reset(new cmCTestGIT(this->CTest
, ofs
)); break;
239 case e_HG
: vc
.reset(new cmCTestHG(this->CTest
, ofs
)); break;
240 default: vc
.reset(new cmCTestVC(this->CTest
, ofs
)); break;
242 vc
->SetCommandLineTool(this->UpdateCommand
);
243 vc
->SetSourceDirectory(sourceDirectory
);
245 // Cleanup the working tree.
249 // Now update repository and remember what files were updated
251 cmGeneratedFileStream os
;
252 if(!this->StartResultingXML(cmCTest::PartUpdate
, "Update", os
))
254 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Cannot open log file"
258 std::string start_time
= this->CTest
->CurrentTime();
259 unsigned int start_time_time
=
260 static_cast<unsigned int>(cmSystemTools::GetTime());
261 double elapsed_time_start
= cmSystemTools::GetTime();
263 bool updated
= vc
->Update();
265 os
<< "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
266 << "<Update mode=\"Client\" Generator=\"ctest-"
267 << cmVersion::GetCMakeVersion() << "\">\n"
268 << "\t<Site>" << this->CTest
->GetCTestConfiguration("Site") << "</Site>\n"
269 << "\t<BuildName>" << this->CTest
->GetCTestConfiguration("BuildName")
271 << "\t<BuildStamp>" << this->CTest
->GetCurrentTag() << "-"
272 << this->CTest
->GetTestModelString() << "</BuildStamp>" << std::endl
;
273 os
<< "\t<StartDateTime>" << start_time
<< "</StartDateTime>\n"
274 << "\t<StartTime>" << start_time_time
<< "</StartTime>\n"
275 << "\t<UpdateCommand>" << cmXMLSafe(vc
->GetUpdateCommandLine())
276 << "</UpdateCommand>\n"
277 << "\t<UpdateType>" << cmXMLSafe(
278 cmCTestUpdateHandlerUpdateToString(this->UpdateType
))
279 << "</UpdateType>\n";
283 int localModifications
= 0;
284 int numUpdated
= vc
->GetPathCount(cmCTestVC::PathUpdated
);
287 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
288 " Found " << numUpdated
<< " updated files\n");
290 if(int numModified
= vc
->GetPathCount(cmCTestVC::PathModified
))
292 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
293 " Found " << numModified
<< " locally modified files\n");
294 localModifications
+= numModified
;
296 if(int numConflicting
= vc
->GetPathCount(cmCTestVC::PathConflicting
))
298 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
299 " Found " << numConflicting
<< " conflicting files\n");
300 localModifications
+= numConflicting
;
303 cmCTestLog(this->CTest
, DEBUG
, "End" << std::endl
);
304 std::string end_time
= this->CTest
->CurrentTime();
305 os
<< "\t<EndDateTime>" << end_time
<< "</EndDateTime>\n"
306 << "\t<EndTime>" << static_cast<unsigned int>(cmSystemTools::GetTime())
308 << "<ElapsedMinutes>" <<
309 static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start
)/6)/10.0
310 << "</ElapsedMinutes>\n"
311 << "\t<UpdateReturnStatus>";
312 if(localModifications
)
314 os
<< "Update error: There are modified or conflicting files in the "
316 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
317 " There are modified or conflicting files in the repository"
322 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Update command failed: "
323 << vc
->GetUpdateCommandLine() << "\n");
325 os
<< "</UpdateReturnStatus>" << std::endl
;
326 os
<< "</Update>" << std::endl
;
330 //----------------------------------------------------------------------
331 bool cmCTestUpdateHandler::InitialCheckout(std::ostream
& ofs
)
333 // Use the user-provided command to create the source tree.
334 if(const char* command
= this->GetOption("InitialCheckout"))
336 // Use a generic VC object to run and log the command.
337 cmCTestVC
vc(this->CTest
, ofs
);
338 vc
.SetSourceDirectory(this->GetOption("SourceDirectory"));
339 if(!vc
.InitialCheckout(command
))
344 if(!this->CTest
->InitializeFromCommand(this->Command
))
346 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
347 " Fatal Error in initialize: "
349 cmSystemTools::SetFatalErrorOccured();
356 //----------------------------------------------------------------------
357 int cmCTestUpdateHandler::DetectVCS(const char* dir
)
359 std::string sourceDirectory
= dir
;
360 cmCTestLog(this->CTest
, DEBUG
, "Check directory: "
361 << sourceDirectory
.c_str() << std::endl
);
362 sourceDirectory
+= "/.svn";
363 if ( cmSystemTools::FileExists(sourceDirectory
.c_str()) )
365 return cmCTestUpdateHandler::e_SVN
;
367 sourceDirectory
= dir
;
368 sourceDirectory
+= "/CVS";
369 if ( cmSystemTools::FileExists(sourceDirectory
.c_str()) )
371 return cmCTestUpdateHandler::e_CVS
;
373 sourceDirectory
= dir
;
374 sourceDirectory
+= "/.bzr";
375 if ( cmSystemTools::FileExists(sourceDirectory
.c_str()) )
377 return cmCTestUpdateHandler::e_BZR
;
379 sourceDirectory
= dir
;
380 sourceDirectory
+= "/.git";
381 if ( cmSystemTools::FileExists(sourceDirectory
.c_str()) )
383 return cmCTestUpdateHandler::e_GIT
;
385 sourceDirectory
= dir
;
386 sourceDirectory
+= "/.hg";
387 if ( cmSystemTools::FileExists(sourceDirectory
.c_str()) )
389 return cmCTestUpdateHandler::e_HG
;
391 return cmCTestUpdateHandler::e_UNKNOWN
;
394 //----------------------------------------------------------------------
395 bool cmCTestUpdateHandler::SelectVCS()
397 // Get update command
398 this->UpdateCommand
= this->CTest
->GetCTestConfiguration("UpdateCommand");
400 // Detect the VCS managing the source tree.
401 this->UpdateType
= this->DetectVCS(this->GetOption("SourceDirectory"));
402 if (this->UpdateType
== e_UNKNOWN
)
404 // The source tree does not have a recognized VCS. Check the
405 // configuration value or command name.
406 this->UpdateType
= this->DetermineType(this->UpdateCommand
.c_str(),
407 this->CTest
->GetCTestConfiguration("UpdateType").c_str());
410 // If no update command was specified, lookup one for this VCS tool.
411 if (this->UpdateCommand
.empty())
414 switch (this->UpdateType
)
416 case e_CVS
: key
= "CVSCommand"; break;
417 case e_SVN
: key
= "SVNCommand"; break;
418 case e_BZR
: key
= "BZRCommand"; break;
419 case e_GIT
: key
= "GITCommand"; break;
420 case e_HG
: key
= "HGCommand"; break;
425 this->UpdateCommand
= this->CTest
->GetCTestConfiguration(key
);
427 if (this->UpdateCommand
.empty())
430 e
<< "Cannot find UpdateCommand ";
435 e
<< " configuration key.";
436 cmCTestLog(this->CTest
, ERROR_MESSAGE
, e
.str() << std::endl
);