1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmCTestUpdateHandler.cxx,v $
6 Date: $Date: 2009-03-20 18:19:56 $
7 Version: $Revision: 1.64 $
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"
34 #include <cmsys/auto_ptr.hxx>
36 //#include <cmsys/RegularExpression.hxx>
37 #include <cmsys/Process.h>
48 //----------------------------------------------------------------------
49 static const char* cmCTestUpdateHandlerUpdateStrings
[] =
56 static const char* cmCTestUpdateHandlerUpdateToString(int type
)
58 if ( type
< cmCTestUpdateHandler::e_UNKNOWN
||
59 type
>= cmCTestUpdateHandler::e_LAST
)
61 return cmCTestUpdateHandlerUpdateStrings
[cmCTestUpdateHandler::e_UNKNOWN
];
63 return cmCTestUpdateHandlerUpdateStrings
[type
];
66 class cmCTestUpdateHandlerLocale
69 cmCTestUpdateHandlerLocale();
70 ~cmCTestUpdateHandlerLocale();
72 std::string saveLCMessages
;
75 cmCTestUpdateHandlerLocale::cmCTestUpdateHandlerLocale()
77 const char* lcmess
= cmSystemTools::GetEnv("LC_MESSAGES");
80 saveLCMessages
= lcmess
;
82 // if LC_MESSAGES is not set to C, then
83 // set it, so that svn/cvs info will be in english ascii
84 if(! (lcmess
&& strcmp(lcmess
, "C") == 0))
86 cmSystemTools::PutEnv("LC_MESSAGES=C");
90 cmCTestUpdateHandlerLocale::~cmCTestUpdateHandlerLocale()
92 // restore the value of LC_MESSAGES after running the version control
94 if(saveLCMessages
.size())
96 std::string put
= "LC_MESSAGES=";
97 put
+= saveLCMessages
;
98 cmSystemTools::PutEnv(put
.c_str());
102 cmSystemTools::UnsetEnv("LC_MESSAGES");
106 //----------------------------------------------------------------------
107 cmCTestUpdateHandler::cmCTestUpdateHandler()
111 //----------------------------------------------------------------------
112 void cmCTestUpdateHandler::Initialize()
114 this->Superclass::Initialize();
115 this->UpdateCommand
= "";
116 this->UpdateType
= e_CVS
;
119 //----------------------------------------------------------------------
120 int cmCTestUpdateHandler::DetermineType(const char* cmd
, const char* type
)
122 cmCTestLog(this->CTest
, DEBUG
, "Determine update type from command: " << cmd
123 << " and type: " << type
<< std::endl
);
126 cmCTestLog(this->CTest
, DEBUG
, "Type specified: " << type
<< std::endl
);
127 std::string stype
= cmSystemTools::LowerCase(type
);
128 if ( stype
.find("cvs") != std::string::npos
)
130 return cmCTestUpdateHandler::e_CVS
;
132 if ( stype
.find("svn") != std::string::npos
)
134 return cmCTestUpdateHandler::e_SVN
;
139 cmCTestLog(this->CTest
, DEBUG
, "Type not specified, check command: "
140 << cmd
<< std::endl
);
141 std::string stype
= cmSystemTools::LowerCase(cmd
);
142 if ( stype
.find("cvs") != std::string::npos
)
144 return cmCTestUpdateHandler::e_CVS
;
146 if ( stype
.find("svn") != std::string::npos
)
148 return cmCTestUpdateHandler::e_SVN
;
151 return cmCTestUpdateHandler::e_UNKNOWN
;
154 //----------------------------------------------------------------------
155 //clearly it would be nice if this were broken up into a few smaller
156 //functions and commented...
157 int cmCTestUpdateHandler::ProcessHandler()
159 // Make sure VCS tool messages are in English so we can parse them.
160 cmCTestUpdateHandlerLocale fixLocale
;
161 static_cast<void>(fixLocale
);
164 const char* sourceDirectory
= this->GetOption("SourceDirectory");
165 if ( !sourceDirectory
)
167 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
168 "Cannot find SourceDirectory key in the DartConfiguration.tcl"
173 cmGeneratedFileStream ofs
;
174 if ( !this->CTest
->GetShowOnly() )
176 this->StartLogFile("Update", ofs
);
179 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
180 "Updating the repository" << std::endl
);
182 // Make sure the source directory exists.
183 if(!this->InitialCheckout(ofs
))
188 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Updating the repository: "
189 << sourceDirectory
<< std::endl
);
191 if(!this->SelectVCS())
196 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " Use "
197 << cmCTestUpdateHandlerUpdateToString(this->UpdateType
)
198 << " repository type"
201 // Create an object to interact with the VCS tool.
202 cmsys::auto_ptr
<cmCTestVC
> vc
;
203 switch (this->UpdateType
)
205 case e_CVS
: vc
.reset(new cmCTestCVS(this->CTest
, ofs
)); break;
206 case e_SVN
: vc
.reset(new cmCTestSVN(this->CTest
, ofs
)); break;
207 default: vc
.reset(new cmCTestVC(this->CTest
, ofs
)); break;
209 vc
->SetCommandLineTool(this->UpdateCommand
);
210 vc
->SetSourceDirectory(sourceDirectory
);
212 // Cleanup the working tree.
216 // Now update repository and remember what files were updated
218 cmGeneratedFileStream os
;
219 if(!this->StartResultingXML(cmCTest::PartUpdate
, "Update", os
))
221 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Cannot open log file"
225 std::string start_time
= this->CTest
->CurrentTime();
226 unsigned int start_time_time
=
227 static_cast<unsigned int>(cmSystemTools::GetTime());
228 double elapsed_time_start
= cmSystemTools::GetTime();
230 bool updated
= vc
->Update();
232 os
<< "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
233 << "<Update mode=\"Client\" Generator=\"ctest-"
234 << cmVersion::GetCMakeVersion() << "\">\n"
235 << "\t<Site>" << this->CTest
->GetCTestConfiguration("Site") << "</Site>\n"
236 << "\t<BuildName>" << this->CTest
->GetCTestConfiguration("BuildName")
238 << "\t<BuildStamp>" << this->CTest
->GetCurrentTag() << "-"
239 << this->CTest
->GetTestModelString() << "</BuildStamp>" << std::endl
;
240 os
<< "\t<StartDateTime>" << start_time
<< "</StartDateTime>\n"
241 << "\t<StartTime>" << start_time_time
<< "</StartTime>\n"
242 << "\t<UpdateCommand>" << cmXMLSafe(vc
->GetUpdateCommandLine())
243 << "</UpdateCommand>\n"
244 << "\t<UpdateType>" << cmXMLSafe(
245 cmCTestUpdateHandlerUpdateToString(this->UpdateType
))
246 << "</UpdateType>\n";
250 int localModifications
= 0;
251 int numUpdated
= vc
->GetPathCount(cmCTestVC::PathUpdated
);
254 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
255 " Found " << numUpdated
<< " updated files\n");
257 if(int numModified
= vc
->GetPathCount(cmCTestVC::PathModified
))
259 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
260 " Found " << numModified
<< " locally modified files\n");
261 localModifications
+= numModified
;
263 if(int numConflicting
= vc
->GetPathCount(cmCTestVC::PathConflicting
))
265 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
266 " Found " << numConflicting
<< " conflicting files\n");
267 localModifications
+= numConflicting
;
270 cmCTestLog(this->CTest
, DEBUG
, "End" << std::endl
);
271 std::string end_time
= this->CTest
->CurrentTime();
272 os
<< "\t<EndDateTime>" << end_time
<< "</EndDateTime>\n"
273 << "\t<EndTime>" << static_cast<unsigned int>(cmSystemTools::GetTime())
275 << "<ElapsedMinutes>" <<
276 static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start
)/6)/10.0
277 << "</ElapsedMinutes>\n"
278 << "\t<UpdateReturnStatus>";
279 if(localModifications
)
281 os
<< "Update error: There are modified or conflicting files in the "
283 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
284 " There are modified or conflicting files in the repository"
289 cmCTestLog(this->CTest
, ERROR_MESSAGE
, " Update command failed: "
290 << vc
->GetUpdateCommandLine() << "\n");
292 os
<< "</UpdateReturnStatus>" << std::endl
;
293 os
<< "</Update>" << std::endl
;
297 //----------------------------------------------------------------------
298 bool cmCTestUpdateHandler::InitialCheckout(std::ostream
& ofs
)
300 // Use the user-provided command to create the source tree.
301 if(const char* command
= this->GetOption("InitialCheckout"))
303 // Use a generic VC object to run and log the command.
304 cmCTestVC
vc(this->CTest
, ofs
);
305 vc
.SetSourceDirectory(this->GetOption("SourceDirectory"));
306 if(!vc
.InitialCheckout(command
))
311 if(!this->CTest
->InitializeFromCommand(this->Command
))
313 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
314 " Fatal Error in initialize: "
316 cmSystemTools::SetFatalErrorOccured();
323 //----------------------------------------------------------------------
324 int cmCTestUpdateHandler::DetectVCS(const char* dir
)
326 std::string sourceDirectory
= dir
;
327 cmCTestLog(this->CTest
, DEBUG
, "Check directory: "
328 << sourceDirectory
.c_str() << std::endl
);
329 sourceDirectory
+= "/.svn";
330 if ( cmSystemTools::FileExists(sourceDirectory
.c_str()) )
332 return cmCTestUpdateHandler::e_SVN
;
334 sourceDirectory
= dir
;
335 sourceDirectory
+= "/CVS";
336 if ( cmSystemTools::FileExists(sourceDirectory
.c_str()) )
338 return cmCTestUpdateHandler::e_CVS
;
340 return cmCTestUpdateHandler::e_UNKNOWN
;
343 //----------------------------------------------------------------------
344 bool cmCTestUpdateHandler::SelectVCS()
346 // Get update command
347 this->UpdateCommand
= this->CTest
->GetCTestConfiguration("UpdateCommand");
349 // Detect the VCS managing the source tree.
350 this->UpdateType
= this->DetectVCS(this->GetOption("SourceDirectory"));
351 if (this->UpdateType
== e_UNKNOWN
)
353 // The source tree does not have a recognized VCS. Check the
354 // configuration value or command name.
355 this->UpdateType
= this->DetermineType(this->UpdateCommand
.c_str(),
356 this->CTest
->GetCTestConfiguration("UpdateType").c_str());
359 // If no update command was specified, lookup one for this VCS tool.
360 if (this->UpdateCommand
.empty())
363 switch (this->UpdateType
)
365 case e_CVS
: key
= "CVSCommand"; break;
366 case e_SVN
: key
= "SVNCommand"; break;
371 this->UpdateCommand
= this->CTest
->GetCTestConfiguration(key
);
373 if (this->UpdateCommand
.empty())
376 e
<< "Cannot find UpdateCommand ";
381 e
<< " configuration key.";
382 cmCTestLog(this->CTest
, ERROR_MESSAGE
, e
.str() << std::endl
);