cmCTest.cxx 59.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*=========================================================================

  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.

=========================================================================*/
17
#include "CTest/Curl/curl/curl.h"
Andy Cedilnik's avatar
Andy Cedilnik committed
18

19
#include "cmCTest.h"
Ken Martin's avatar
Ken Martin committed
20
21
22
23
24
#include "cmake.h"
#include "cmMakefile.h"
#include "cmLocalGenerator.h"
#include "cmGlobalGenerator.h"
#include <cmsys/Directory.hxx>
25
#include "cmGlob.h"
Andy Cedilnik's avatar
Andy Cedilnik committed
26
#include "cmDynamicLoader.h"
27
#include "cmGeneratedFileStream.h"
28

Ken Martin's avatar
Ken Martin committed
29
#include "cmCTestBuildHandler.h"
30
#include "cmCTestConfigureHandler.h"
Ken Martin's avatar
Ken Martin committed
31
#include "cmCTestCoverageHandler.h"
32
#include "cmCTestMemCheckHandler.h"
Ken Martin's avatar
Ken Martin committed
33
#include "cmCTestScriptHandler.h"
Ken Martin's avatar
Ken Martin committed
34
#include "cmCTestTestHandler.h"
Ken Martin's avatar
Ken Martin committed
35
#include "cmCTestUpdateHandler.h"
36

37
#include "cmCTestSubmit.h"
38
#include "cmVersion.h"
Andy Cedilnik's avatar
Andy Cedilnik committed
39

40
41
42
#include <cmsys/RegularExpression.hxx>
#include <cmsys/Process.h>

43
#include <stdlib.h> 
44
#include <math.h>
Andy Cedilnik's avatar
Andy Cedilnik committed
45
#include <float.h>
Andy Cedilnik's avatar
Andy Cedilnik committed
46
47

#include <memory> // auto_ptr
48

49
50
#define DEBUGOUT std::cout << __LINE__ << " "; std::cout
#define DEBUGERR std::cerr << __LINE__ << " "; std::cerr
51

52
struct tm* cmCTest::GetNightlyTime(std::string str, 
Ken Martin's avatar
Ken Martin committed
53
54
                                   bool verbose, 
                                   bool tomorrowtag)
Andy Cedilnik's avatar
Andy Cedilnik committed
55
56
57
{
  struct tm* lctime;
  time_t tctime = time(0);
58
59
60
  if ( verbose )
    {
    std::cout << "Determine Nightly Start Time" << std::endl;
61
    std::cout << "   Specified time: " << str.c_str() << std::endl;
62
    }
Andy Cedilnik's avatar
Andy Cedilnik committed
63
64
65
66
67
68
69
  //Convert the nightly start time to seconds. Since we are
  //providing only a time and a timezone, the current date of
  //the local machine is assumed. Consequently, nightlySeconds
  //is the time at which the nightly dashboard was opened or
  //will be opened on the date of the current client machine.
  //As such, this time may be in the past or in the future.
  time_t ntime = curl_getdate(str.c_str(), &tctime);
70
71
72
73
  if ( verbose )
    {
    std::cout << "   Get curl time: " << ntime << std::endl;
    }
Andy Cedilnik's avatar
Andy Cedilnik committed
74
  tctime = time(0);
75
76
  if ( verbose )
    {
77
    std::cout << "   Get the current time: " << tctime << std::endl;
78
79
80
    }

  const int dayLength = 24 * 60 * 60;
Andy Cedilnik's avatar
Andy Cedilnik committed
81
  //std::cout << "Seconds: " << tctime << std::endl;
82
  while ( ntime > tctime )
Andy Cedilnik's avatar
Andy Cedilnik committed
83
84
85
86
87
88
    {
    // If nightlySeconds is in the past, this is the current
    // open dashboard, then return nightlySeconds.  If
    // nightlySeconds is in the future, this is the next
    // dashboard to be opened, so subtract 24 hours to get the
    // time of the current open dashboard
89
    ntime -= dayLength;
Andy Cedilnik's avatar
Andy Cedilnik committed
90
    //std::cout << "Pick yesterday" << std::endl;
91
92
93
94
95
    if ( verbose )
      {
      std::cout << "   Future time, subtract day: " << ntime << std::endl;
      }
    }
96
  while ( tctime > (ntime + dayLength) )
97
98
99
100
    {
    ntime += dayLength;
    if ( verbose )
      {
101
      std::cout << "   Past time, add day: " << ntime << std::endl;
102
      }
Andy Cedilnik's avatar
Andy Cedilnik committed
103
104
    }
  //std::cout << "nightlySeconds: " << ntime << std::endl;
105
106
107
108
109
  if ( verbose )
    {
    std::cout << "   Current time: " << tctime
              << " Nightly time: " << ntime << std::endl;
    }
110
111
  if ( tomorrowtag )
    {
112
113
    std::cout << "Use future tag, Add a day" << std::endl;
    ntime += dayLength;
114
    }
Andy Cedilnik's avatar
Andy Cedilnik committed
115
116
117
118
  lctime = gmtime(&ntime);
  return lctime;
}

Ken Martin's avatar
Ken Martin committed
119
std::string cmCTest::CleanString(const std::string& str)
120
{
121
122
  std::string::size_type spos = str.find_first_not_of(" \n\t\r\f\v");
  std::string::size_type epos = str.find_last_not_of(" \n\t\r\f\v");
123
124
125
126
127
128
129
130
131
132
133
  if ( spos == str.npos )
    {
    return std::string();
    }
  if ( epos != str.npos )
    {
    epos = epos - spos + 1;
    }
  return str.substr(spos, epos);
}

134
std::string cmCTest::CurrentTime()
135
136
{
  time_t currenttime = time(0);
137
138
139
  struct tm* t = localtime(&currenttime);
  //return ::CleanString(ctime(&currenttime));
  char current_time[1024];
Andy Cedilnik's avatar
Andy Cedilnik committed
140
141
142
143
144
145
146
147
  if ( m_ShortDateFormat )
    {
    strftime(current_time, 1000, "%b %d %H:%M %Z", t);
    }
  else
    {
    strftime(current_time, 1000, "%a %b %d %H:%M:%S %Z %Y", t);
    }
148
  //std::cout << "Current_Time: " << current_time << std::endl;
Ken Martin's avatar
Ken Martin committed
149
  return cmCTest::MakeXMLSafe(cmCTest::CleanString(current_time));
150
151
152
153
154
155
}


std::string cmCTest::MakeXMLSafe(const std::string& str)
{
  cmOStringStream ost;
156
157
  // By uncommenting the lcnt code, it will put newline every 120 characters
  //int lcnt = 0;
Bill Hoffman's avatar
Bill Hoffman committed
158
  for (std::string::size_type  pos = 0; pos < str.size(); pos ++ )
159
    {
160
    unsigned char ch = str[pos];
161
162
163
164
165
    if ( ch == '\r' )
      {
      // Ignore extra CR characters.
      }
    else if ( (ch > 126 || ch < 32) && ch != 9  && ch != 10 && ch != 13 )
166
      {
167
      char buffer[33];
168
      sprintf(buffer, "&lt;%d&gt;", (int)ch);
169
      //sprintf(buffer, "&#x%0x;", (unsigned int)ch);
170
      ost << buffer;
171
      //lcnt += 4;
172
173
174
175
176
177
178
179
      }
    else
      {
      switch ( ch )
        {
        case '&': ost << "&amp;"; break;
        case '<': ost << "&lt;"; break;
        case '>': ost << "&gt;"; break;
180
181
182
        case '\n': ost << "\n"; 
          //lcnt = 0; 
          break;
183
184
        default: ost << ch;
        }
185
      //lcnt ++;
186
      }
187
188
189
190
191
    //if ( lcnt > 120 )
    //  {
    //  ost << "\n";
    //  lcnt = 0;
    //  }
192
193
194
195
    }
  return ost.str();
}

Andy Cedilnik's avatar
Andy Cedilnik committed
196
197
198
199
std::string cmCTest::MakeURLSafe(const std::string& str)
{
  cmOStringStream ost;
  char buffer[10];
200
  for ( std::string::size_type pos = 0; pos < str.size(); pos ++ )
Andy Cedilnik's avatar
Andy Cedilnik committed
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
    {
    unsigned char ch = str[pos];
    if ( ( ch > 126 || ch < 32 ||
           ch == '&' ||
           ch == '%' ||
           ch == '+' ||
           ch == '=' || 
           ch == '@'
          ) && ch != 9 )
      {
      sprintf(buffer, "%02x;", (unsigned int)ch);
      ost << buffer;
      }
    else
      {
      ost << ch;
      }
    }
  return ost.str();
}

222
223
cmCTest::cmCTest() 
{ 
224
  m_ForceNewCTestProcess   = false;
225
  m_TomorrowTag            = false;
Bill Hoffman's avatar
Bill Hoffman committed
226
  m_BuildNoCMake           = false;
Bill Hoffman's avatar
Bill Hoffman committed
227
  m_BuildNoClean           = false;
228
  m_BuildTwoConfig         = false;
Ken Martin's avatar
Ken Martin committed
229
  m_Verbose                = false;
230
  m_ProduceXML             = false;
Ken Martin's avatar
Ken Martin committed
231
232
233
  m_ShowOnly               = false;
  m_RunConfigurationScript = false;
  m_TestModel              = cmCTest::EXPERIMENTAL;
234
  m_InteractiveDebugMode   = true;
Ken Martin's avatar
Ken Martin committed
235
  m_TimeOut                = 0;
236
  m_CompressXMLFiles       = false;
237
238
239
240
241
  int cc; 
  for ( cc=0; cc < cmCTest::LAST_TEST; cc ++ )
    {
    m_Tests[cc] = 0;
    }
Andy Cedilnik's avatar
Andy Cedilnik committed
242
  m_ShortDateFormat        = true;
Ken Martin's avatar
Ken Martin committed
243

244
245
246
247
248
249
250
251
252
253
254
255
256
  m_TestingHandlers["build"]     = new cmCTestBuildHandler;
  m_TestingHandlers["coverage"]  = new cmCTestCoverageHandler;
  m_TestingHandlers["script"]    = new cmCTestScriptHandler;
  m_TestingHandlers["test"]      = new cmCTestTestHandler;
  m_TestingHandlers["update"]    = new cmCTestUpdateHandler;
  m_TestingHandlers["configure"] = new cmCTestConfigureHandler;
  m_TestingHandlers["memcheck"]  = new cmCTestMemCheckHandler;

  cmCTest::t_TestingHandlers::iterator it;
  for ( it = m_TestingHandlers.begin(); it != m_TestingHandlers.end(); ++ it )
    {
    it->second->SetCTestInstance(this);
    }
Ken Martin's avatar
Ken Martin committed
257
258
259
260
}

cmCTest::~cmCTest() 
{ 
261
262
263
264
265
266
  cmCTest::t_TestingHandlers::iterator it;
  for ( it = m_TestingHandlers.begin(); it != m_TestingHandlers.end(); ++ it )
    {
    delete it->second;
    it->second = 0;
    }
267
268
}

269
int cmCTest::Initialize(const char* binary_dir)
270
{
271
272
273
274
275
  if(!m_InteractiveDebugMode)
    {
    this->BlockTestErrorDiagnostics();
    }
  
276
277
278
  m_BinaryDir = binary_dir;
  cmSystemTools::ConvertToUnixSlashes(m_BinaryDir);
  if ( !this->ReadCustomConfigurationFileTree(m_BinaryDir.c_str()) )
279
280
281
    {
    return 0;
    }
282
  this->UpdateCTestConfiguration();
283
  if ( m_ProduceXML )
284
    {
285
    std::string testingDir = m_BinaryDir + "/Testing";
286
287
288
289
290
291
    if ( cmSystemTools::FileExists(testingDir.c_str()) )
      {
      if ( !cmSystemTools::FileIsDirectory(testingDir.c_str()) )
        {
        std::cerr << "File " << testingDir << " is in the place of the testing directory"
                  << std::endl;
292
        return 0;
293
294
295
296
297
298
299
300
        }
      }
    else
      {
      if ( !cmSystemTools::MakeDirectory(testingDir.c_str()) )
        {
        std::cerr << "Cannot create directory " << testingDir
                  << std::endl;
301
        return 0;
302
303
304
305
306
307
        }
      }
    std::string tagfile = testingDir + "/TAG";
    std::ifstream tfin(tagfile.c_str());
    std::string tag;
    time_t tctime = time(0);
308
309
310
311
    if ( m_TomorrowTag )
      {
      tctime += ( 24 * 60 * 60 );
      }
312
    struct tm *lctime = gmtime(&tctime);
313
    if ( tfin && cmSystemTools::GetLineFromStream(tfin, tag) )
314
315
316
317
318
319
320
321
322
      {
      int year = 0;
      int mon = 0;
      int day = 0;
      int hour = 0;
      int min = 0;
      sscanf(tag.c_str(), "%04d%02d%02d-%02d%02d",
             &year, &mon, &day, &hour, &min);
      if ( year != lctime->tm_year + 1900 ||
Andy Cedilnik's avatar
Andy Cedilnik committed
323
           mon != lctime->tm_mon+1 ||
324
325
326
327
           day != lctime->tm_mday )
        {
        tag = "";
        }
328
329
330
331
332
333
334
335
336
      std::string tagmode;
      if ( cmSystemTools::GetLineFromStream(tfin, tagmode) )
        {
        if ( tagmode.size() > 4 && !( m_Tests[cmCTest::START_TEST] || m_Tests[ALL_TEST] ))
          {
          m_TestModel = cmCTest::GetTestModelFromString(tagmode.c_str());
          }
        }
      tfin.close();
337
      }
Andy Cedilnik's avatar
Andy Cedilnik committed
338
    if ( tag.size() == 0 || m_Tests[cmCTest::START_TEST] || m_Tests[ALL_TEST])
339
      {
Andy Cedilnik's avatar
Andy Cedilnik committed
340
341
      //std::cout << "TestModel: " << this->GetTestModelString() << std::endl;
      //std::cout << "TestModel: " << m_TestModel << std::endl;
342
343
      if ( m_TestModel == cmCTest::NIGHTLY )
        {
344
        lctime = cmCTest::GetNightlyTime(m_DartConfiguration["NightlyStartTime"],
345
          m_Verbose,
346
          m_TomorrowTag);
347
        }
348
349
350
      char datestring[100];
      sprintf(datestring, "%04d%02d%02d-%02d%02d",
              lctime->tm_year + 1900,
Andy Cedilnik's avatar
Andy Cedilnik committed
351
              lctime->tm_mon+1,
352
353
354
355
356
357
358
359
              lctime->tm_mday,
              lctime->tm_hour,
              lctime->tm_min);
      tag = datestring;
      std::ofstream ofs(tagfile.c_str());
      if ( ofs )
        {
        ofs << tag << std::endl;
360
        ofs << this->GetTestModelString() << std::endl;
361
362
        }
      ofs.close();
363
364
      std::cout << "Create new tag: " << tag << " - " 
        << this->GetTestModelString() << std::endl;
365
366
367
      }
    m_CurrentTag = tag;
    }
368
  return 1;
369
370
}

371
bool cmCTest::UpdateCTestConfiguration()
372
{
373
374
375
376
377
378
  std::string fileName = m_BinaryDir + "/DartConfiguration.tcl";
  if ( !cmSystemTools::FileExists(fileName.c_str()) )
    {
    std::cerr << "Cannot find file: " << fileName.c_str() << std::endl;
    return false;
    }
379
  // parse the dart test file
380
  std::ifstream fin(fileName.c_str());
381
382
  if(!fin)
    {
383
    return false;
384
385
386
387
388
389
390
391
    }

  char buffer[1024];
  while ( fin )
    {
    buffer[0] = 0;
    fin.getline(buffer, 1023);
    buffer[1023] = 0;
Ken Martin's avatar
Ken Martin committed
392
    std::string line = cmCTest::CleanString(buffer);
393
394
395
396
397
398
399
400
401
402
    if(line.size() == 0)
      {
      continue;
      }
    while ( fin && (line[line.size()-1] == '\\') )
      {
      line = line.substr(0, line.size()-1);
      buffer[0] = 0;
      fin.getline(buffer, 1023);
      buffer[1023] = 0;
Ken Martin's avatar
Ken Martin committed
403
      line += cmCTest::CleanString(buffer);
404
405
406
407
408
409
410
411
412
413
414
      }
    if ( line[0] == '#' )
      {
      continue;
      }
    std::string::size_type cpos = line.find_first_of(":");
    if ( cpos == line.npos )
      {
      continue;
      }
    std::string key = line.substr(0, cpos);
Ken Martin's avatar
Ken Martin committed
415
    std::string value = cmCTest::CleanString(line.substr(cpos+1, line.npos));
416
417
418
    m_DartConfiguration[key] = value;
    }
  fin.close();
419
  if ( m_ProduceXML )
420
421
    {
    m_TimeOut = atoi(m_DartConfiguration["TimeOut"].c_str());
422
    m_CompressXMLFiles = cmSystemTools::IsOn(m_DartConfiguration["CompressSubmission"].c_str());
423
    }
424
  return true;
425
426
}

427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
void cmCTest::BlockTestErrorDiagnostics()
{
  cmSystemTools::PutEnv("DART_TEST_FROM_DART=1");
  cmSystemTools::PutEnv("DASHBOARD_TEST_FROM_CTEST=1");
#if defined(_WIN32)
  SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); 
#endif
}

void cmCTest::SetTestModel(int mode)
{
  m_InteractiveDebugMode = false;
  m_TestModel = mode;
}

442
bool cmCTest::SetTest(const char* ttype, bool report)
443
444
445
446
447
{
  if ( cmSystemTools::LowerCase(ttype) == "all" )
    {
    m_Tests[cmCTest::ALL_TEST] = 1;
    }
Andy Cedilnik's avatar
Andy Cedilnik committed
448
449
450
451
  else if ( cmSystemTools::LowerCase(ttype) == "start" )
    {
    m_Tests[cmCTest::START_TEST] = 1;
    }
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
  else if ( cmSystemTools::LowerCase(ttype) == "update" )
    {
    m_Tests[cmCTest::UPDATE_TEST] = 1;
    }
  else if ( cmSystemTools::LowerCase(ttype) == "configure" )
    {
    m_Tests[cmCTest::CONFIGURE_TEST] = 1;
    }
  else if ( cmSystemTools::LowerCase(ttype) == "build" )
    {
    m_Tests[cmCTest::BUILD_TEST] = 1;
    }
  else if ( cmSystemTools::LowerCase(ttype) == "test" )
    {
    m_Tests[cmCTest::TEST_TEST] = 1;
    }
  else if ( cmSystemTools::LowerCase(ttype) == "coverage" )
    {
    m_Tests[cmCTest::COVERAGE_TEST] = 1;
    }
472
  else if ( cmSystemTools::LowerCase(ttype) == "memcheck" )
473
    {
474
    m_Tests[cmCTest::MEMCHECK_TEST] = 1;
475
    }
476
477
478
479
  else if ( cmSystemTools::LowerCase(ttype) == "notes" )
    {
    m_Tests[cmCTest::NOTES_TEST] = 1;
    }
Andy Cedilnik's avatar
Andy Cedilnik committed
480
481
482
483
  else if ( cmSystemTools::LowerCase(ttype) == "submit" )
    {
    m_Tests[cmCTest::SUBMIT_TEST] = 1;
    }
484
485
  else
    {
486
487
488
489
    if ( report )
      {
      std::cerr << "Don't know about test \"" << ttype << "\" yet..." << std::endl;
      }
490
491
492
493
494
495
496
497
498
    return false;
    }
  return true;
}

void cmCTest::Finalize()
{
}

Ken Martin's avatar
Ken Martin committed
499
 
500

Ken Martin's avatar
Ken Martin committed
501
bool cmCTest::OpenOutputFile(const std::string& path, 
502
503
                     const std::string& name, cmGeneratedFileStream& stream,
                     bool compress)
Ken Martin's avatar
Ken Martin committed
504
{
505
  std::string testingDir = m_BinaryDir + "/Testing";
Ken Martin's avatar
Ken Martin committed
506
  if ( path.size() > 0 )
507
    {
Ken Martin's avatar
Ken Martin committed
508
    testingDir += "/" + path;
509
    }
Ken Martin's avatar
Ken Martin committed
510
  if ( cmSystemTools::FileExists(testingDir.c_str()) )
511
    {
Ken Martin's avatar
Ken Martin committed
512
    if ( !cmSystemTools::FileIsDirectory(testingDir.c_str()) )
513
      {
Ken Martin's avatar
Ken Martin committed
514
515
516
517
      std::cerr << "File " << testingDir 
                << " is in the place of the testing directory"
                << std::endl;
      return false;
518
      }
519
    }
Ken Martin's avatar
Ken Martin committed
520
  else
521
    {
Ken Martin's avatar
Ken Martin committed
522
    if ( !cmSystemTools::MakeDirectory(testingDir.c_str()) )
523
      {
Ken Martin's avatar
Ken Martin committed
524
525
526
      std::cerr << "Cannot create directory " << testingDir
                << std::endl;
      return false;
527
528
      }
    }
Ken Martin's avatar
Ken Martin committed
529
  std::string filename = testingDir + "/" + name;
530
  stream.Open(filename.c_str());
Ken Martin's avatar
Ken Martin committed
531
  if( !stream )
532
    {
Ken Martin's avatar
Ken Martin committed
533
534
    std::cerr << "Problem opening file: " << filename << std::endl;
    return false;
535
    }
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
  if ( compress )
    {
    if ( m_CompressXMLFiles )
      {
      stream.SetCompression(true);
      }
    }
  return true;
}

bool cmCTest::AddIfExists(tm_VectorOfStrings& files, const char* file)
{
  if ( this->CTestFileExists(file) )
    {
    files.push_back(file);
    }
  else
    {
    std::string name = file;
    name += ".gz";
    if ( this->CTestFileExists(name.c_str()) )
      {
      files.push_back(name.c_str());
      }
    else
      {
      return false;
      }
    }
Ken Martin's avatar
Ken Martin committed
565
  return true;
566
567
}

Ken Martin's avatar
Ken Martin committed
568
int cmCTest::SubmitResults()
569
{
570
  cmGeneratedFileStream ofs;
Ken Martin's avatar
Ken Martin committed
571
  this->OpenOutputFile("Temporary", "LastSubmit.log", ofs);
572

Ken Martin's avatar
Ken Martin committed
573
574
575
576
  cmCTest::tm_VectorOfStrings files;
  std::string prefix = this->GetSubmitResultsPrefix();
  // TODO:
  // Check if test is enabled
577
578
579
580
581
  this->AddIfExists(files, "Update.xml");
  this->AddIfExists(files, "Configure.xml");
  this->AddIfExists(files, "Build.xml");
  this->AddIfExists(files, "Test.xml");
  if ( this->AddIfExists(files, "Coverage.xml") )
582
    {
Ken Martin's avatar
Ken Martin committed
583
    cmCTest::tm_VectorOfStrings gfiles;
584
    std::string gpath = m_BinaryDir + "/Testing/" + m_CurrentTag;
Ken Martin's avatar
Ken Martin committed
585
586
587
588
    std::string::size_type glen = gpath.size() + 1;
    gpath = gpath + "/CoverageLog*";
    //std::cout << "Globbing for: " << gpath.c_str() << std::endl;
    if ( cmSystemTools::SimpleGlob(gpath, gfiles, 1) )
589
      {
Ken Martin's avatar
Ken Martin committed
590
591
      size_t cc;
      for ( cc = 0; cc < gfiles.size(); cc ++ )
592
        {
Ken Martin's avatar
Ken Martin committed
593
594
595
        gfiles[cc] = gfiles[cc].substr(glen);
        //std::cout << "Glob file: " << gfiles[cc].c_str() << std::endl;
        files.push_back(gfiles[cc]);
596
597
        }
      }
Ken Martin's avatar
Ken Martin committed
598
    else
599
      {
Ken Martin's avatar
Ken Martin committed
600
      std::cerr << "Problem globbing" << std::endl;
601
602
      }
    }
603
604
605
  this->AddIfExists(files, "DynamicAnalysis.xml");
  this->AddIfExists(files, "Purify.xml");
  this->AddIfExists(files, "Notes.xml");
606

Ken Martin's avatar
Ken Martin committed
607
  if ( ofs )
608
    {
Ken Martin's avatar
Ken Martin committed
609
610
611
612
    ofs << "Upload files:" << std::endl;
    int cnt = 0;
    cmCTest::tm_VectorOfStrings::iterator it;
    for ( it = files.begin(); it != files.end(); ++ it )
613
      {
Ken Martin's avatar
Ken Martin committed
614
615
      ofs << cnt << "\t" << it->c_str() << std::endl;
      cnt ++;
616
617
      }
    }
Ken Martin's avatar
Ken Martin committed
618
619
620
621
622
623
624
  std::cout << "Submit files (using " << m_DartConfiguration["DropMethod"] << ")"
    << std::endl;
  cmCTestSubmit submit;
  submit.SetVerbose(m_Verbose);
  submit.SetLogFile(&ofs);
  if ( m_DartConfiguration["DropMethod"] == "" ||
    m_DartConfiguration["DropMethod"] ==  "ftp" )
625
    {
Ken Martin's avatar
Ken Martin committed
626
627
628
629
630
631
632
    ofs << "Using drop method: FTP" << std::endl;
    std::cout << "  Using FTP submit method" << std::endl;
    std::string url = "ftp://";
    url += cmCTest::MakeURLSafe(m_DartConfiguration["DropSiteUser"]) + ":" + 
      cmCTest::MakeURLSafe(m_DartConfiguration["DropSitePassword"]) + "@" + 
      m_DartConfiguration["DropSite"] + 
      cmCTest::MakeURLSafe(m_DartConfiguration["DropLocation"]);
633
    if ( !submit.SubmitUsingFTP(m_BinaryDir+"/Testing/"+m_CurrentTag, 
Ken Martin's avatar
Ken Martin committed
634
        files, prefix, url) )
635
      {
Ken Martin's avatar
Ken Martin committed
636
637
638
      std::cerr << "  Problems when submitting via FTP" << std::endl;
      ofs << "  Problems when submitting via FTP" << std::endl;
      return 0;
639
      }
Ken Martin's avatar
Ken Martin committed
640
    if ( !submit.TriggerUsingHTTP(files, prefix, m_DartConfiguration["TriggerSite"]) )
641
      {
Ken Martin's avatar
Ken Martin committed
642
643
644
      std::cerr << "  Problems when triggering via HTTP" << std::endl;
      ofs << "  Problems when triggering via HTTP" << std::endl;
      return 0;
645
      }
Ken Martin's avatar
Ken Martin committed
646
647
648
    std::cout << "  Submission successfull" << std::endl;
    ofs << "  Submission succesfull" << std::endl;
    return 1;
649
    }
Ken Martin's avatar
Ken Martin committed
650
  else if ( m_DartConfiguration["DropMethod"] == "http" )
651
    {
Ken Martin's avatar
Ken Martin committed
652
653
654
655
    ofs << "Using drop method: HTTP" << std::endl;
    std::cout << "  Using HTTP submit method" << std::endl;
    std::string url = "http://";
    if ( m_DartConfiguration["DropSiteUser"].size() > 0 )
656
      {
Ken Martin's avatar
Ken Martin committed
657
658
      url += m_DartConfiguration["DropSiteUser"];
      if ( m_DartConfiguration["DropSitePassword"].size() > 0 )
659
        {
Ken Martin's avatar
Ken Martin committed
660
        url += ":" + m_DartConfiguration["DropSitePassword"];
661
        }
Ken Martin's avatar
Ken Martin committed
662
      url += "@";
663
      }
Ken Martin's avatar
Ken Martin committed
664
    url += m_DartConfiguration["DropSite"] + m_DartConfiguration["DropLocation"];
665
    if ( !submit.SubmitUsingHTTP(m_BinaryDir+"/Testing/"+m_CurrentTag, files, prefix, url) )
666
      {
Ken Martin's avatar
Ken Martin committed
667
668
669
      std::cerr << "  Problems when submitting via HTTP" << std::endl;
      ofs << "  Problems when submitting via HTTP" << std::endl;
      return 0;
670
      }
Ken Martin's avatar
Ken Martin committed
671
    if ( !submit.TriggerUsingHTTP(files, prefix, m_DartConfiguration["TriggerSite"]) )
Andy Cedilnik's avatar
Andy Cedilnik committed
672
      {
673
      std::cerr << "  Problems when triggering via HTTP" << std::endl;
Andy Cedilnik's avatar
Andy Cedilnik committed
674
      ofs << "  Problems when triggering via HTTP" << std::endl;
Andy Cedilnik's avatar
Andy Cedilnik committed
675
676
      return 0;
      }
Andy Cedilnik's avatar
Andy Cedilnik committed
677
    std::cout << "  Submission successfull" << std::endl;
Andy Cedilnik's avatar
Andy Cedilnik committed
678
    ofs << "  Submission succesfull" << std::endl;
Andy Cedilnik's avatar
Andy Cedilnik committed
679
680
    return 1;
    }
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
  else if ( m_DartConfiguration["DropMethod"] == "xmlrpc" )
    {
    ofs << "Using drop method: XML-RPC" << std::endl;
    std::cout << "  Using XML-RPC submit method" << std::endl;
    std::string url = m_DartConfiguration["DropSite"];
    prefix = m_DartConfiguration["DropLocation"];
    if ( !submit.SubmitUsingXMLRPC(m_BinaryDir+"/Testing/"+m_CurrentTag, files, prefix, url) )
      {
      std::cerr << "  Problems when submitting via XML-RPC" << std::endl;
      ofs << "  Problems when submitting via XML-RPC" << std::endl;
      return 0;
      }
    std::cout << "  Submission successfull" << std::endl;
    ofs << "  Submission succesfull" << std::endl;
    return 1;
    }
697
  else if ( m_DartConfiguration["DropMethod"] == "scp" )
Andy Cedilnik's avatar
Andy Cedilnik committed
698
    {
Ken Martin's avatar
Ken Martin committed
699
700
    std::string url;
    if ( m_DartConfiguration["DropSiteUser"].size() > 0 )
701
      {
Ken Martin's avatar
Ken Martin committed
702
      url += m_DartConfiguration["DropSiteUser"] + "@";
703
      }
Ken Martin's avatar
Ken Martin committed
704
705
706
    url += m_DartConfiguration["DropSite"] + ":" + m_DartConfiguration["DropLocation"];
    
    if ( !submit.SubmitUsingSCP(m_DartConfiguration["ScpCommand"],
707
        m_BinaryDir+"/Testing/"+m_CurrentTag, files, prefix, url) )
708
      {
Ken Martin's avatar
Ken Martin committed
709
710
711
      std::cerr << "  Problems when submitting via SCP" << std::endl;
      ofs << "  Problems when submitting via SCP" << std::endl;
      return 0;
712
      }
Ken Martin's avatar
Ken Martin committed
713
714
    std::cout << "  Submission successfull" << std::endl;
    ofs << "  Submission succesfull" << std::endl;
715
    }
716
717
718
719
720
  else
    {
    std::cout << "   Unknown submission method: \"" << m_DartConfiguration["DropMethod"] << "\"" << std::endl;
    return 0;
    }
721

Ken Martin's avatar
Ken Martin committed
722
723
724
725
726
  return 0;
}

bool cmCTest::CTestFileExists(const std::string& filename)
{
727
  std::string testingDir = m_BinaryDir + "/Testing/" + m_CurrentTag + "/" +
Ken Martin's avatar
Ken Martin committed
728
729
730
731
732
733
734
735
736
737
738
    filename;
  return cmSystemTools::FileExists(testingDir.c_str());
}

std::string cmCTest::GetSubmitResultsPrefix()
{
  std::string name = m_DartConfiguration["Site"] +
    "___" + m_DartConfiguration["BuildName"] +
    "___" + m_CurrentTag + "-" +
    this->GetTestModelString() + "___XML___";
  return name;
739
740
}

741
742
743
744
745
746
747
748
749
cmCTestGenericHandler* cmCTest::GetHandler(const char* handler)
{
  cmCTest::t_TestingHandlers::iterator it = m_TestingHandlers.find(handler);
  if ( it == m_TestingHandlers.end() )
    {
    return 0;
    }
  return it->second;
}
Ken Martin's avatar
Ken Martin committed
750

751
752
753
754
755
756
757
758
759
int cmCTest::ExecuteHandler(const char* shandler)
{
  cmCTestGenericHandler* handler = this->GetHandler(shandler);
  if ( !handler )
    {
    return -1;
    }
  return handler->ProcessHandler(); 
}
Ken Martin's avatar
Ken Martin committed
760

761
762
763
764
765
int cmCTest::ProcessTests()
{
  int res = 0;
  bool notest = true;
  int cc;
Andy Cedilnik's avatar
Andy Cedilnik committed
766
  int update_count = 0;
767
768
769
770
771
772
773
774
775
776
777

  for ( cc = 0; cc < LAST_TEST; cc ++ )
    {
    if ( m_Tests[cc] )
      {
      notest = false;
      break;
      }
    }
  if ( m_Tests[UPDATE_TEST] || m_Tests[ALL_TEST] )
    {
778
779
780
    cmCTestGenericHandler* uphandler = this->GetHandler("update");
    uphandler->SetOption("SourceDirectory", this->GetDartConfiguration("SourceDirectory").c_str());
    update_count = uphandler->ProcessHandler(); 
Andy Cedilnik's avatar
Andy Cedilnik committed
781
782
    if ( update_count < 0 )
      {
Ken Martin's avatar
Ken Martin committed
783
      res |= cmCTest::UPDATE_ERRORS;
Andy Cedilnik's avatar
Andy Cedilnik committed
784
785
786
787
788
      }
    }
  if ( m_TestModel == cmCTest::CONTINUOUS && !update_count )
    {
    return 0;
789
790
791
    }
  if ( m_Tests[CONFIGURE_TEST] || m_Tests[ALL_TEST] )
    {
Andy Cedilnik's avatar
Andy Cedilnik committed
792
    if (this->GetHandler("configure")->ProcessHandler() < 0)
793
      {
Ken Martin's avatar
Ken Martin committed
794
      res |= cmCTest::CONFIGURE_ERRORS;
795
      }
796
797
798
    }
  if ( m_Tests[BUILD_TEST] || m_Tests[ALL_TEST] )
    {
799
    this->UpdateCTestConfiguration();
Andy Cedilnik's avatar
Andy Cedilnik committed
800
    if (this->GetHandler("build")->ProcessHandler() < 0)
801
      {
Ken Martin's avatar
Ken Martin committed
802
      res |= cmCTest::BUILD_ERRORS;
803
      }
804
805
806
    }
  if ( m_Tests[TEST_TEST] || m_Tests[ALL_TEST] || notest )
    {
807
    this->UpdateCTestConfiguration();
Andy Cedilnik's avatar
Andy Cedilnik committed
808
    if (this->GetHandler("test")->ProcessHandler() < 0)
809
      {
Ken Martin's avatar
Ken Martin committed
810
      res |= cmCTest::TEST_ERRORS;
811
      }
812
813
814
    }
  if ( m_Tests[COVERAGE_TEST] || m_Tests[ALL_TEST] )
    {
815
    this->UpdateCTestConfiguration();
Andy Cedilnik's avatar
Andy Cedilnik committed
816
    if (this->GetHandler("coverage")->ProcessHandler() < 0)
Andy Cedilnik's avatar
Andy Cedilnik committed
817
818
819
      {
      res |= cmCTest::COVERAGE_ERRORS;
      }
820
    }
821
  if ( m_Tests[MEMCHECK_TEST] || m_Tests[ALL_TEST] )
822
    {
823
    this->UpdateCTestConfiguration();
Andy Cedilnik's avatar
Andy Cedilnik committed
824
    if (this->GetHandler("memcheck")->ProcessHandler() < 0)
825
      {
Ken Martin's avatar
Ken Martin committed
826
      res |= cmCTest::MEMORY_ERRORS;
827
      }
828
    }
829
830
  if ( !notest )
    {
831
    std::string notes_dir = m_BinaryDir + "/Testing/Notes";
832
833
834
835
    if ( cmSystemTools::FileIsDirectory(notes_dir.c_str()) )
      {
      cmsys::Directory d;
      d.Load(notes_dir.c_str());
836
837
      unsigned long kk;
      for ( kk = 0; kk < d.GetNumberOfFiles(); kk ++ )
838
        {
839
        const char* file = d.GetFile(kk);
840
841
842
843
844
845
846
847
848
849
850
851
852
853
        std::string fullname = notes_dir + "/" + file;
        if ( cmSystemTools::FileExists(fullname.c_str()) &&
          !cmSystemTools::FileIsDirectory(fullname.c_str()) )
          {
          if ( m_NotesFiles.size() > 0 )
            {
            m_NotesFiles += ";";
            }
          m_NotesFiles += fullname;
          m_Tests[NOTES_TEST] = 1;
          }
        }
      }
    }
854
855
856
857
858
859
860
861
  if ( m_Tests[NOTES_TEST] || m_Tests[ALL_TEST] )
    {
    this->UpdateCTestConfiguration();
    if ( m_NotesFiles.size() )
      {
      this->GenerateNotesFile(m_NotesFiles.c_str());
      }
    }
Andy Cedilnik's avatar
Andy Cedilnik committed
862
863
  if ( m_Tests[SUBMIT_TEST] || m_Tests[ALL_TEST] )
    {
864
    this->UpdateCTestConfiguration();
Andy Cedilnik's avatar
Andy Cedilnik committed
865
866
    this->SubmitResults();
    }
867
868
  return res;
}
869
870
871
872
873

std::string cmCTest::GetTestModelString()
{
  switch ( m_TestModel )
    {
874
875
876
877
  case cmCTest::NIGHTLY:
    return "Nightly";
  case cmCTest::CONTINUOUS:
    return "Continuous";
878
879
880
    }
  return "Experimental";
}
881

882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
int cmCTest::GetTestModelFromString(const char* str)
{
  if ( !str )
    {
    return cmCTest::EXPERIMENTAL;
    }
  std::string rstr = cmSystemTools::LowerCase(str);
  if ( strncmp(rstr.c_str(), "cont", 4) == 0 )
    {
    return cmCTest::CONTINUOUS;
    }
  if ( strncmp(rstr.c_str(), "nigh", 4) == 0 )
    {
    return cmCTest::NIGHTLY;
    }
  return cmCTest::EXPERIMENTAL;
}

900
int cmCTest::RunMakeCommand(const char* command, std::string* output,
901
  int* retVal, const char* dir, bool verbose, int timeout, std::ofstream& ofs)
902
903
904
905
906
907
908
{
  std::vector<cmStdString> args = cmSystemTools::ParseArguments(command);

  if(args.size() < 1)
    {
    return false;
    }
909

910
911
  std::vector<const char*> argv;
  for(std::vector<cmStdString>::const_iterator a = args.begin();
912
    a != args.end(); ++a)
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
    {
    argv.push_back(a->c_str());
    }
  argv.push_back(0);

  if ( output )
    {
    *output = "";
    }

  cmsysProcess* cp = cmsysProcess_New();
  cmsysProcess_SetCommand(cp, &*argv.begin());
  cmsysProcess_SetWorkingDirectory(cp, dir);
  cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
  cmsysProcess_SetTimeout(cp, timeout);
  cmsysProcess_Execute(cp);
929

930
931
  std::string::size_type tick = 0;
  std::string::size_type tick_len = 1024;
932
  std::string::size_type tick_line_len = 50;
933
934
935
936
937

  char* data;
  int length;
  if ( !verbose )
    {
938
    std::cout << "   Each . represents " << tick_len << " bytes of output" << std::endl;
939
940
    std::cout << "    " << std::flush;
    }
941
  while(cmsysProcess_WaitForData(cp, &data, &length, 0))
942
943
944
    {
    if ( output )
      {
Bill Hoffman's avatar
Bill Hoffman committed
945
946
947
948
949
950
951
      for(int cc =0; cc < length; ++cc)
        {
        if(data[cc] == 0)
          {
          data[cc] = '\n';
          }
        }
952

953
      output->append(data, length);
954
      if ( !verbose )
955
        {
956
        while ( output->size() > (tick * tick_len) )
957
          {
958
959
960
961
962
963
964
965
          tick ++;
          std::cout << "." << std::flush;
          if ( tick % tick_line_len == 0 && tick > 0 )
            {
            std::cout << "  Size: ";
            std::cout << int((output->size() / 1024.0) + 1) << "K" << std::endl;
            std::cout << "    " << std::flush;
            }
966
          }
967
968
969
970
971
        }
      }
    if(verbose)
      {
      std::cout.write(data, length);
972
      std::cout.flush();
973
974
975
976
      }
    if ( ofs )
      {
      ofs.write(data, length);
977
      ofs.flush();
978
979
980
      }
    }
  std::cout << " Size of output: ";
981
  std::cout << int(output->size() / 1024.0) << "K" << std::endl;
982

983
  cmsysProcess_WaitForExit(cp, 0);
984

985
986
987
  int result = cmsysProcess_GetState(cp);

  if(result == cmsysProcess_State_Exited)
988
    {
989
    *retVal = cmsysProcess_GetExitValue(cp);
990
    }
991
992
993
994
995
996
997
998
999
1000
  else if(result == cmsysProcess_State_Exception)
    {
    *retVal = cmsysProcess_GetExitException(cp);
    std::cout << "There was an exception: " << *retVal << std::endl;
    }
  else if(result == cmsysProcess_State_Expired)
    {
    std::cout << "There was a timeout" << std::endl;
    } 
  else if(result == cmsysProcess_State_Error)
1001
    {
1002
1003
    *output += "\n*** ERROR executing: ";
    *output += cmsysProcess_GetErrorString(cp);
1004
    }
1005

1006
  cmsysProcess_Delete(cp);
1007

1008
1009
  return result;
}
1010

Ken Martin's avatar
Ken Martin committed
1011
1012
1013
int cmCTest::RunTest(std::vector<const char*> argv, 
                     std::string* output, int *retVal,
                     std::ostream* log)
Andy Cedilnik's avatar
Andy Cedilnik committed
1014
{
Ken Martin's avatar
Ken Martin committed
1015
1016
  if(cmSystemTools::SameFile(argv[0], m_CTestSelf.c_str()) && 
     !m_ForceNewCTestProcess)
1017
1018
    {
    cmCTest inst;
1019
    inst.m_ConfigType = m_ConfigType;
1020
    inst.m_TimeOut = m_TimeOut;
1021
    std::vector<std::string> args;
Bill Hoffman's avatar
Bill Hoffman committed
1022
    for(unsigned int i =0; i < argv.size(); ++i)
1023
1024
1025
1026
1027
1028
      {
      if(argv[i])
        {
        args.push_back(argv[i]);
        }
      }
1029
1030
1031
1032
    if ( *log )
      {
      *log << "* Run internal CTest" << std::endl;
      }
1033
1034
    std::string oldpath = cmSystemTools::GetCurrentWorkingDirectory();
    
1035
    *retVal = inst.Run(args, output);
1036
1037
1038
1039
    if ( *log )
      {
      *log << output->c_str();
      }
1040
1041
    cmSystemTools::ChangeDirectory(oldpath.c_str());
    
1042
1043
1044
1045
1046
1047
1048
    if(m_Verbose)
      {
      std::cout << "Internal cmCTest object used to run test.\n";
      std::cout <<  *output << "\n";
      }
    return cmsysProcess_State_Exited;
    }
1049
  std::vector<char> tempOutput;
Andy Cedilnik's avatar
Andy Cedilnik committed
1050
1051
1052
1053
1054
1055
1056
  if ( output )
    {
    *output = "";
    }

  cmsysProcess* cp = cmsysProcess_New();
  cmsysProcess_SetCommand(cp, &*argv.begin());
1057
  //  std::cout << "Command is: " << argv[0] << std::endl;
Andy Cedilnik's avatar
Andy Cedilnik committed
1058
1059
1060
1061
1062
1063
  if(cmSystemTools::GetRunCommandHideConsole())
    {
    cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
    }
  cmsysProcess_SetTimeout(cp, m_TimeOut);
  cmsysProcess_Execute(cp);
1064

Andy Cedilnik's avatar
Andy Cedilnik committed
1065
1066
  char* data;
  int length;
1067
  while(cmsysProcess_WaitForData(cp, &data, &length, 0))
Andy Cedilnik's avatar
Andy Cedilnik committed
1068
1069
1070
    {
    if ( output )
      {
1071
      tempOutput.insert(tempOutput.end(), data, data+length);
Andy Cedilnik's avatar
Andy Cedilnik committed
1072
      }
1073
1074
1075
1076
1077
    if ( m_Verbose )
      {
      std::cout.write(data, length);
      std::cout.flush();
      }