| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406 | /*=========================================================================  Program:   CMake - Cross-Platform Makefile Generator  Module:    $RCSfile$  Language:  C++  Date:      $Date$  Version:   $Revision$  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.     This software is distributed WITHOUT ANY WARRANTY; without even      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      PURPOSE.  See the above copyright notices for more information.=========================================================================*/#include "cmCTestUpdateHandler.h"#include "cmCTest.h"#include "cmake.h"#include "cmMakefile.h"#include "cmLocalGenerator.h"#include "cmGlobalGenerator.h"//#include <cmsys/RegularExpression.hxx>#include <cmsys/Process.h>// used for sleep#ifdef _WIN32#include "windows.h"#endif#include <stdlib.h> #include <math.h>#include <float.h>//----------------------------------------------------------------------cmCTestUpdateHandler::cmCTestUpdateHandler(){  m_Verbose = false;   m_CTest = 0;}//----------------------------------------------------------------------//clearly it would be nice if this were broken up into a few smaller//functions and commented...int cmCTestUpdateHandler::UpdateDirectory(cmCTest *ctest_inst){  m_CTest = ctest_inst;    int count = 0;  std::string::size_type cc, kk;  std::string cvsCommand = m_CTest->GetDartConfiguration("CVSCommand");  if ( cvsCommand.size() == 0 )    {    std::cerr << "Cannot find CVSCommand key in the DartConfiguration.tcl" << std::endl;    return -1;    }  std::string cvsOptions = m_CTest->GetDartConfiguration("CVSUpdateOptions");  if ( cvsOptions.size() == 0 )    {    std::cerr << "Cannot find CVSUpdateOptions key in the DartConfiguration.tcl" << std::endl;    return -1;    }  std::string sourceDirectory = m_CTest->GetDartConfiguration("SourceDirectory");  if ( sourceDirectory.size() == 0 )    {    std::cerr << "Cannot find SourceDirectory  key in the DartConfiguration.tcl" << std::endl;    return -1;    }  std::string extra_update_opts;  if ( m_CTest->GetTestModel() == cmCTest::NIGHTLY )    {    struct tm* t = cmCTest::GetNightlyTime(m_CTest->GetDartConfiguration("NightlyStartTime"),      m_Verbose, m_CTest->GetTomorrowTag());    char current_time[1024];    sprintf(current_time, "%04d-%02d-%02d %02d:%02d:%02d UTC",      t->tm_year + 1900,      t->tm_mon + 1,      t->tm_mday,      t->tm_hour,      t->tm_min,      t->tm_sec);    std::string today_update_date = current_time;       extra_update_opts += "-D \"" + today_update_date +"\"";    //std::cout << "Update: " << extra_update_opts << std::endl;    }  std::string command = cvsCommand + " -z3 update " + cvsOptions +    " " + extra_update_opts;  std::ofstream os;   if ( !m_CTest->OpenOutputFile(m_CTest->GetCurrentTag(), "Update.xml", os) )    {    std::cerr << "Cannot open log file" << std::endl;    }  std::string start_time = m_CTest->CurrentTime();  double elapsed_time_start = cmSystemTools::GetTime();  std::string goutput;  int retVal = 0;  bool res = true;  std::ofstream ofs;  if ( !m_CTest->GetShowOnly() )    {    res = cmSystemTools::RunSingleCommand(command.c_str(), &goutput,       &retVal, sourceDirectory.c_str(),      m_Verbose, 0 /*m_TimeOut*/);    if ( m_CTest->OpenOutputFile("Temporary", "LastUpdate.log", ofs) )      {      ofs << goutput << std::endl;;       }    }  else    {    std::cout << "Update with command: " << command << std::endl;    }  os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"     << "<Update mode=\"Client\" Generator=\"ctest-" << CMake_VERSION_FULL << "\">\n"     << "\t<Site>" << m_CTest->GetDartConfiguration("Site") << "</Site>\n"     << "\t<BuildName>" << m_CTest->GetDartConfiguration("BuildName")     << "</BuildName>\n"     << "\t<BuildStamp>" << m_CTest->GetCurrentTag() << "-"     << m_CTest->GetTestModelString() << "</BuildStamp>" << std::endl;  os << "\t<StartDateTime>" << start_time << "</StartDateTime>\n"     << "\t<UpdateCommand>" << m_CTest->MakeXMLSafe(command)     << "</UpdateCommand>\n"     << "\t<UpdateReturnStatus>";  int failed = 0;  if ( !res || retVal )    {    os << "Update error: ";    os << m_CTest->MakeXMLSafe(goutput);    std::cerr << "Update with command: " << command << " failed" << std::endl;    failed = 1;    }  os << "</UpdateReturnStatus>" << std::endl;  if ( !failed )    {    std::vector<cmStdString> lines;    cmSystemTools::Split(goutput.c_str(), lines);    std::cout << "Updated; gathering version information" << std::endl;    cmsys::RegularExpression date_author("^date: +([^;]+); +author: +([^;]+); +state: +[^;]+;");    cmsys::RegularExpression revision("^revision +([^ ]*) *$");    cmsys::RegularExpression end_of_file("^=============================================================================$");    cmsys::RegularExpression end_of_comment("^----------------------------$");    std::string current_path = "<no-path>";    bool first_file = true;    cmCTestUpdateHandler::AuthorsToUpdatesMap authors_files_map;    int num_updated = 0;    int num_modified = 0;    int num_conflicting = 0;    for ( cc= 0 ; cc < lines.size(); cc ++ )      {      const char* line = lines[cc].c_str();      char mod = line[0];      if ( line[1] == ' ' && mod != '?' )        {        if ( mod != 'M' && mod != 'C' )          {          count ++;          }        const char* file = line + 2;        //std::cout << "Line" << cc << ": " << mod << " - " << file << std::endl;        std::string logcommand = cvsCommand + " -z3 log -N " + file;        //std::cout << "Do log: " << logcommand << std::endl;        std::string output;        res = cmSystemTools::RunSingleCommand(logcommand.c_str(), &output,           &retVal, sourceDirectory.c_str(),          m_Verbose, 0 /*m_TimeOut*/);        if ( ofs )          {          ofs << output << std::endl;          }        if ( res && retVal == 0)          {          //std::cout << output << std::endl;          std::vector<cmStdString> ulines;          cmSystemTools::Split(output.c_str(), ulines);          std::string::size_type sline = 0;          std::string srevision1 = "Unknown";          std::string sdate1     = "Unknown";          std::string sauthor1   = "Unknown";          std::string semail1    = "Unknown";          std::string comment1   = "";          std::string srevision2 = "Unknown";          std::string sdate2     = "Unknown";          std::string sauthor2   = "Unknown";          std::string comment2   = "";          std::string semail2    = "Unknown";          bool have_first = false;          bool have_second = false;          for ( kk = 0; kk < ulines.size(); kk ++ )            {            const char* clp = ulines[kk].c_str();            if ( !have_second && !sline && revision.find(clp) )              {              if ( !have_first )                {                srevision1 = revision.match(1);                }              else                {                srevision2 = revision.match(1);                }              }            else if ( !have_second && !sline && date_author.find(clp) )              {              sline = kk + 1;              if ( !have_first )                {                sdate1 = date_author.match(1);                sauthor1 = date_author.match(2);                }              else                {                sdate2 = date_author.match(1);                sauthor2 = date_author.match(2);                }              }            else if ( sline && end_of_comment.find(clp) || end_of_file.find(clp))              {              if ( !have_first )                {                have_first = true;                }              else if ( !have_second )                {                have_second = true;                }              sline = 0;              }            else if ( sline )              {              if ( !have_first )                {                comment1 += clp;                comment1 += "\n";                }              else                {                comment2 += clp;                comment2 += "\n";                }              }            }          if ( mod == 'M' )            {            comment1 = "Locally modified file\n";            }          if ( mod == 'C' )            {            comment1 = "Conflict while updating\n";            }          std::string path = cmSystemTools::GetFilenamePath(file);          std::string fname = cmSystemTools::GetFilenameName(file);          if ( path != current_path )            {            if ( !first_file )              {              os << "\t</Directory>" << std::endl;              }            else              {              first_file = false;              }            os << "\t<Directory>\n"              << "\t\t<Name>" << path << "</Name>" << std::endl;            }          if ( mod == 'C' )            {            num_conflicting ++;            os << "\t<Conflicting>" << std::endl;            }          else if ( mod == 'M' )            {            num_modified ++;            os << "\t<Modified>" << std::endl;            }          else            {            num_updated ++;            os << "\t<Updated>" << std::endl;            }          if ( srevision2 == "Unknown" )            {            srevision2 = srevision1;            }          os << "\t\t<File Directory=\"" << path << "\">" << fname             << "</File>\n"            << "\t\t<Directory>" << path << "</Directory>\n"            << "\t\t<FullName>" << file << "</FullName>\n"            << "\t\t<CheckinDate>" << sdate1 << "</CheckinDate>\n"            << "\t\t<Author>" << sauthor1 << "</Author>\n"            << "\t\t<Email>" << semail1 << "</Email>\n"            << "\t\t<Log>" << cmCTest::MakeXMLSafe(comment1) << "</Log>\n"            << "\t\t<Revision>" << srevision1 << "</Revision>\n"            << "\t\t<PriorRevision>" << srevision2 << "</PriorRevision>"            << std::endl;          if ( srevision2 != srevision1 )            {            os              << "\t\t<Revisions>\n"              << "\t\t\t<Revision>" << srevision1 << "</Revision>\n"              << "\t\t\t<PreviousRevision>" << srevision2 << "</PreviousRevision>\n"              << "\t\t\t<Author>" << sauthor1<< "</Author>\n"              << "\t\t\t<Date>" << sdate1 << "</Date>\n"              << "\t\t\t<Comment>" << cmCTest::MakeXMLSafe(comment1) << "</Comment>\n"              << "\t\t\t<Email>" << semail1 << "</Email>\n"              << "\t\t</Revisions>\n"              << "\t\t<Revisions>\n"              << "\t\t\t<Revision>" << srevision2 << "</Revision>\n"              << "\t\t\t<PreviousRevision>" << srevision2 << "</PreviousRevision>\n"              << "\t\t\t<Author>" << sauthor2<< "</Author>\n"              << "\t\t\t<Date>" << sdate2 << "</Date>\n"              << "\t\t\t<Comment>" << cmCTest::MakeXMLSafe(comment2) << "</Comment>\n"              << "\t\t\t<Email>" << semail2 << "</Email>\n"              << "\t\t</Revisions>" << std::endl;            }          if ( mod == 'C' )            {            os << "\t</Conflicting>" << std::endl;            }          else if ( mod == 'M' )            {            os << "\t</Modified>" << std::endl;            }          else            {            os << "\t</Updated>" << std::endl;            }          cmCTestUpdateHandler::UpdateFiles *u = &authors_files_map[sauthor1];          cmCTestUpdateHandler::StringPair p;          p.first = path;          p.second = fname;          u->push_back(p);          current_path = path;          }        }      }    if ( num_updated )      {      std::cout << "Found " << num_updated << " updated files" << std::endl;      }    if ( num_modified )      {      std::cout << "Found " << num_modified << " locally modified files"         << std::endl;      }    if ( num_conflicting )      {      std::cout << "Found " << num_conflicting << " conflicting files"         << std::endl;      }    if ( !first_file )      {      os << "\t</Directory>" << std::endl;      }    cmCTestUpdateHandler::AuthorsToUpdatesMap::iterator it;    for ( it = authors_files_map.begin();      it != authors_files_map.end();      it ++ )      {      os << "\t<Author>\n"        << "\t\t<Name>" << it->first << "</Name>" << std::endl;      cmCTestUpdateHandler::UpdateFiles *u = &(it->second);      for ( cc = 0; cc < u->size(); cc ++ )        {        os << "\t\t<File Directory=\"" << (*u)[cc].first << "\">"          << (*u)[cc].second << "</File>" << std::endl;        }      os << "\t</Author>" << std::endl;      }    }  //std::cout << "End" << std::endl;  std::string end_time = m_CTest->CurrentTime();  os << "\t<EndDateTime>" << end_time << "</EndDateTime>\n"     << "<ElapsedMinutes>" <<     static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start)/6)/10.0      << "</ElapsedMinutes>"     << "</Update>" << std::endl;    if ( ofs )    {    ofs.close();    }  if (! res || retVal )    {    std::cerr << "Error(s) when updating the project" << std::endl;    std::cerr << "Output: " << goutput << std::endl;    return -1;    }  return count;}
 |