Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
814 mhunt 1
package com.erggroup.buildtool.daemon;
2
 
3
import com.erggroup.buildtool.daemon.ResumeTimerTask;
4
import com.erggroup.buildtool.ripple.ReleaseManager;
868 mhunt 5
import com.erggroup.buildtool.smtp.Smtpsend;
6
import com.erggroup.buildtool.ripple.RippleEngine;
814 mhunt 7
 
4280 dpurdie 8
 
814 mhunt 9
import java.io.BufferedReader;
10
import java.io.File;
11
import java.io.FileNotFoundException;
12
import java.io.FileOutputStream;
13
import java.io.FileWriter;
14
import java.io.FilenameFilter;
15
 
16
import java.io.IOException;
17
import java.io.PrintStream;
18
import java.io.StringReader;
19
 
20
import java.sql.SQLException;
21
 
22
import java.util.Date;
23
import java.util.Timer;
24
 
25
import org.apache.log4j.Logger;
26
import org.apache.tools.ant.BuildException;
27
import org.apache.tools.ant.DefaultLogger;
28
import org.apache.tools.ant.Project;
29
import org.apache.tools.ant.ProjectHelper;
30
 
31
/**Build Thread sub component
32
 */
33
public abstract class BuildThread
34
  extends Thread
35
{
36
  /**baseline identifier (which release manager release this BuildThread is dealing with)
37
   * @attribute
38
   */
39
  protected int mRtagId = 0;
40
 
41
  /**unique identifier of this BuildThread
42
   * @attribute
43
   */
44
  protected int mRconId = 0;
45
 
46
  /**
47
   * @aggregation composite
48
   */
49
  protected RunLevel mRunLevel;
50
 
51
  /**
52
   * @aggregation composite
53
   */
54
  protected ReleaseManager mReleaseManager;
55
 
896 mhunt 56
  /**unit test support
57
   * @attribute
58
   */
59
  protected String mUnitTest = "";
60
 
814 mhunt 61
  /**
62
   * @aggregation composite
63
   */
64
  protected static ResumeTimerTask mResumeTimerTask;
65
 
66
  /**
67
   * @aggregation composite
68
   */
69
  private static Timer mTimer;
70
 
71
  /**Synchroniser object
72
   * Use to Synchronize on by multiple threads
73
   * @attribute
74
   */
75
  static final Object mSynchroniser = new Object();
76
 
77
  /**BuildThread group
78
   * @attribute
79
   */
80
  public static final ThreadGroup mThreadGroup = new ThreadGroup("BuildThread");
81
 
82
  /**the advertised build file content when either
83
   * a) no package in the baseline has a build requirement
84
   * b) the next package in the baseline with a build requirement is generic
85
   * @attribute
86
   */
87
  protected static final String mDummyBuildFileContent = new String("<dummy/>");
88
 
89
  /**Set true when last build cycle was benign.
90
   * @attribute
91
   */
92
  protected boolean mSleep;
93
 
886 mhunt 94
  /**Set true when last build cycle caught SQLException or Exception.
95
   * @attribute
96
   */
97
  protected boolean mException;
98
 
854 mhunt 99
  /**Set true when ant error reported on any target.
100
   * @attribute
101
   */
102
  private boolean mErrorReported;
103
 
866 mhunt 104
  /**Logger
854 mhunt 105
   * @attribute
106
   */
866 mhunt 107
  private static final Logger mLogger = Logger.getLogger(BuildThread.class);
854 mhunt 108
 
866 mhunt 109
  /**Package name for reporting purposes.
814 mhunt 110
   * @attribute
111
   */
866 mhunt 112
  protected String mReportingPackageName;
814 mhunt 113
 
866 mhunt 114
  /**Package version for reporting purposes.
115
   * @attribute
116
   */
117
  protected String mReportingPackageVersion;
118
 
119
  /**Package extension for reporting purposes.
120
   * @attribute
121
   */
122
  protected String mReportingPackageExtension;
123
 
124
  /**Package location for reporting purposes.
125
   * @attribute
126
   */
127
  protected String mReportingPackageLocation;
128
 
129
  /**Package dependencies for reporting purposes.
130
   * @attribute
131
   */
132
  protected String mReportingPackageDepends;
133
 
134
  /**Is ripple flag for reporting purposes.
135
   * @attribute
136
   */
137
  protected String mReportingIsRipple;
138
 
139
  /**Package version identifier for reporting purposes.
140
   * @attribute
141
   */
142
  protected String mReportingPackageVersionId;
143
 
144
  /**Fully published flag for reporting purposes.
145
   * @attribute
146
   */
147
  protected String mReportingFullyPublished;
148
 
149
  /**New label for reporting purposes.
150
   * @attribute
151
   */
924 dpurdie 152
  protected String mReportingNewVcsTag;
866 mhunt 153
 
154
  /**Source control interaction for reporting purposes.
155
   * @attribute
156
   */
157
  protected String mReportingDoesNotRequireSourceControlInteraction;
158
 
908 mhunt 159
  /**Source control interaction for reporting purposes.
160
   * @attribute
161
   */
162
  protected String mReportingTestBuild;
163
 
866 mhunt 164
  /**Log file location for reporting purposes.
165
   * @attribute
166
   */
167
  protected String mReportingBuildFailureLogFile;
168
 
868 mhunt 169
  /**Non null determines to only gather metrics
170
   * @attribute
171
   */
172
  protected static final String mGbeGatherMetricsOnly = System.getenv("GBE_GATHER_METRICS");
173
 
896 mhunt 174
  /**Non null determines to only gather metrics
175
   * @attribute
176
   */
177
  protected boolean mRecoverable;
178
 
930 dpurdie 179
  /**Logger for the entire build process
924 dpurdie 180
  * @attribute
181
  */
182
  DefaultLogger mBuildLogger ;
183
 
814 mhunt 184
  /**constructor
185
   */
186
  BuildThread()
187
  {
188
    super(mThreadGroup, "");
189
    mLogger.debug("BuildThread");
190
    mSleep = false;
886 mhunt 191
    mException = false;
854 mhunt 192
    mErrorReported = false;
814 mhunt 193
    mReleaseManager = new ReleaseManager();
896 mhunt 194
    mRecoverable = false;
814 mhunt 195
 
196
    // no need to be synchronized - BuildThreads are instantiated in a single thread
197
    if ( mResumeTimerTask == null )
198
    {
199
      mResumeTimerTask = new ResumeTimerTask();
200
      mTimer = new Timer();
201
      mResumeTimerTask.setTimer(mTimer);
202
    }
203
  }
204
 
924 dpurdie 205
  /**Flags that a new build cycle is about to start
206
  *  Create a new logger to capture all the complete build log
207
  *  even though its done in stages we want a complete log.
208
  */
209
  void flagStartBuildCycle()
210
  {
211
    try
212
    {
213
      mBuildLogger = new DefaultLogger();
214
      PrintStream ps = new PrintStream(mRtagId + ".log");
215
      mBuildLogger.setOutputPrintStream(ps);
216
      mBuildLogger.setMessageOutputLevel(Project.MSG_INFO);
217
    }
218
    catch( FileNotFoundException e )
219
    {
220
      mLogger.error("BuildThread caught FileNotFoundException");
221
    }
222
  }
223
 
886 mhunt 224
  /**sleeps when mException is set
225
   */
226
  protected void sleepCheck()
227
  {
228
    if (mException)
229
    {
230
      try
231
      {
232
        Integer sleepTime = 300000;
233
        mLogger.warn("sleepCheck sleep " + sleepTime.toString() + " secs");
234
        Thread.sleep(sleepTime);
235
        mLogger.info("sleepCheck sleep returned");
236
      }
237
      catch(InterruptedException e)
238
      {
239
        mLogger.warn("sleepCheck sleep caught InterruptedException");
240
      }
241
 
242
    }
243
    mException = false;
244
  }
245
 
814 mhunt 246
  /**initially changes the run level to IDLE
247
   * determines if the BuildThread is still configured
248
   * a) determines if the BuildThread is running in scheduled downtime
249
   * b) determines if the BuildThread is directed to pause
250
   * changes the run level to PAUSED if a) or b) are true
251
   * throws ExitException when not configured
252
   * implements the sequence diagrams allowed to proceed, not allowed to proceed, exit
253
   */
868 mhunt 254
  protected void allowedToProceed(boolean master) throws ExitException, SQLException, Exception
814 mhunt 255
  {
256
    mLogger.debug("allowedToProceed");
886 mhunt 257
 
258
    try
259
    {
260
      mRunLevel = RunLevel.IDLE;
261
      mLogger.warn("allowedToProceed changing run level to IDLE for rcon_id " + mRconId);
916 mhunt 262
      mLogger.fatal("allowedToProceed calling mRunLevel.persist on IDLE");                      
886 mhunt 263
      mRunLevel.persist(mReleaseManager, mRconId);
896 mhunt 264
      if ( master )
265
      {
916 mhunt 266
        mLogger.fatal("allowedToProceed calling mReleaseManager.discardVersion");                      
896 mhunt 267
        mReleaseManager.discardVersion();
268
      }
916 mhunt 269
      mLogger.fatal("allowedToProceed calling mReleaseManager.clearCurrentPackageBeingBuilt");                      
886 mhunt 270
      mReleaseManager.clearCurrentPackageBeingBuilt(mRconId);      
271
    }
272
    catch(SQLException e)
273
    {
274
      mLogger.warn("allowedToProceed caught SQLException");
275
    }
814 mhunt 276
 
277
    if (mSleep)
278
    {
279
      try
280
      {
868 mhunt 281
        Integer sleepTime = 300000;
282
 
283
        if ( !master )
284
        {
285
          // sleep only 3 secs on slave
286
          sleepTime = 3000;
287
        }
288
        mLogger.warn("allowedToProceed sleep " + sleepTime.toString() + " secs no build requirement");
916 mhunt 289
        mLogger.fatal("allowedToProceed calling Thread.sleep for 3 secs");                      
868 mhunt 290
        Thread.sleep(sleepTime);
814 mhunt 291
        mLogger.info("allowedToProceed sleep returned");
292
      }
293
      catch(InterruptedException e)
294
      {
295
        mLogger.warn("allowedToProceed sleep caught InterruptedException");
296
      }
297
    }
298
 
299
    boolean proceed = false;
300
 
898 mhunt 301
    try
814 mhunt 302
    {
898 mhunt 303
      while ( !proceed )
814 mhunt 304
      {
916 mhunt 305
        mLogger.fatal("allowedToProceed calling mReleaseManager.connect");                      
898 mhunt 306
        mReleaseManager.connect();
916 mhunt 307
        mLogger.fatal("allowedToProceed calling mReleaseManager.queryReleaseConfig");                      
898 mhunt 308
        if ( !mReleaseManager.queryReleaseConfig(mRtagId, mRconId, BuildDaemon.mHostname, getMode()) )
309
        {
310
          mReleaseManager.disconnect();
311
          mLogger.warn("allowedToProceed queryReleaseConfig failed");
312
          throw new ExitException();
313
        }
814 mhunt 314
 
898 mhunt 315
        Date resumeTime = new Date( 0 );
916 mhunt 316
        mLogger.fatal("allowedToProceed calling mReleaseManager.queryRunLevelSchedule");                      
898 mhunt 317
        if ( !mReleaseManager.queryRunLevelSchedule(resumeTime, mRecoverable) )
814 mhunt 318
        {
898 mhunt 319
          mLogger.info("allowedToProceed scheduled downtime");
320
          mReleaseManager.disconnect();
321
          mRunLevel = RunLevel.PAUSED;
322
          mLogger.warn("allowedToProceed changing run level to PAUSED for rcon_id " + mRconId);
323
          mRunLevel.persist(mReleaseManager, mRconId);
324
 
325
          synchronized(mSynchroniser)
814 mhunt 326
          {
898 mhunt 327
            // contain the schedule and wait in the same synchronized block to prevent a deadlock
328
            // eg this thread calls schedule, timer thread calls notifyall, this thread calls wait (forever)
329
            try
814 mhunt 330
            {
898 mhunt 331
              if (mResumeTimerTask.isCancelled())
332
              {
333
                mResumeTimerTask = new ResumeTimerTask();
334
                mTimer = new Timer();
335
                mResumeTimerTask.setTimer(mTimer);
336
              }
337
              mLogger.warn("allowedToProceed schedule passed " + resumeTime.getTime());
338
              mTimer.schedule(mResumeTimerTask, resumeTime);
814 mhunt 339
            }
898 mhunt 340
            catch( IllegalStateException e )
814 mhunt 341
            {
898 mhunt 342
              // this may be thrown by schedule if already scheduled
343
              // it signifies another BuildThread has already scheduled the ResumeTimerTask
344
               mLogger.warn("allowedToProceed already scheduled");
814 mhunt 345
            }
898 mhunt 346
 
347
            try
348
            {
349
              mLogger.warn("allowedToProceed wait");
350
              mSynchroniser.wait();
351
              mLogger.warn("allowedToProceed wait returned");
352
 
353
              if ( mUnitTest.compareTo("unit test not allowed to proceed") == 0 )
354
              {
355
                throw new ExitException();
356
              }
357
            }
358
            catch( InterruptedException e )
359
            {
360
              mLogger.warn("allowedToProceed caught InterruptedException");
361
            }
814 mhunt 362
          }
898 mhunt 363
 
814 mhunt 364
        }
898 mhunt 365
        else
814 mhunt 366
        {
916 mhunt 367
          mLogger.fatal("allowedToProceed calling mReleaseManager.queryDirectedRunLevel");                      
898 mhunt 368
          if ( !mReleaseManager.queryDirectedRunLevel(mRconId) )
814 mhunt 369
          {
898 mhunt 370
            mLogger.info("allowedToProceed downtime");
371
            mReleaseManager.disconnect();
372
            mRunLevel = RunLevel.PAUSED;
373
            mLogger.warn("allowedToProceed changing run level to PAUSED for rcon_id " + mRconId);
374
            mRunLevel.persist(mReleaseManager, mRconId);
375
            try
376
            {
377
              // to do, sleep for periodicMs
378
              mLogger.warn("allowedToProceed sleep 5 mins directed downtime");
379
              Thread.sleep(300000);
380
              mLogger.info("allowedToProceed sleep returned");
381
            }
382
            catch (InterruptedException e)
383
            {
384
              mLogger.warn("allowedToProceed caught InterruptedException");
385
            }
814 mhunt 386
          }
898 mhunt 387
          else
814 mhunt 388
          {
898 mhunt 389
            mReleaseManager.disconnect();
390
            proceed = true;
814 mhunt 391
          }
392
        }
393
      }
394
    }
898 mhunt 395
    finally
396
    {
397
      // this block is executed regardless of what happens in the try block
398
      // even if an exception is thrown
399
      // ensure disconnect
916 mhunt 400
      mLogger.fatal("allowedToProceed calling mReleaseManager.disconnect");                      
898 mhunt 401
      mReleaseManager.disconnect();
402
    }
896 mhunt 403
 
404
    mRecoverable = false;
814 mhunt 405
  }
406
 
407
  /**periodically 
408
   * a) performs disk housekeeping
409
   * b) determines if a minimum threshold of disk space is available
894 mhunt 410
   * c) determines if a file can be touched
814 mhunt 411
   * changes the run level to CANNOT_CONTINUE if insufficient disk space
412
   * otherwise changes the run level to ACTIVE and returns
413
   * implements the sequence diagram check environment
414
   */
415
  protected void checkEnvironment() throws Exception
416
  {
417
    mLogger.debug("checkEnvironment");
418
    boolean exit = false;
419
 
420
    while( !exit )
421
    {
422
      housekeep();
423
 
424
      // attempt to exit
425
      exit = true;
426
 
894 mhunt 427
      if ( !hasSufficientDiskSpace() || !touch() )
814 mhunt 428
      {
894 mhunt 429
        mLogger.warn("checkEnvironment below disk free threshold or read only file system detected");
814 mhunt 430
        exit = false;
431
        mRunLevel = RunLevel.CANNOT_CONTINUE;
816 mhunt 432
        mLogger.warn("checkEnvironment changing run level to CANNOT_CONTINUE for rcon_id " + mRconId);
814 mhunt 433
        mRunLevel.persist(mReleaseManager, mRconId);
434
        try
435
        {
436
          // to do, sleep for periodicMs
896 mhunt 437
          if ( mUnitTest.compareTo("unit test check environment") != 0 )
814 mhunt 438
          {
439
            mLogger.warn("checkEnvironment sleep 5 mins below disk free threshold");
440
            Thread.sleep(300000);
441
            mLogger.info("checkEnvironment sleep returned");
442
          }
443
        }
444
        catch (InterruptedException e)
445
        {
446
          mLogger.warn("checkEnvironment caught InterruptedException");
447
        }
448
      }
449
    }
450
 
451
    mRunLevel = RunLevel.ACTIVE;    
816 mhunt 452
    mLogger.warn("checkEnvironment changing run level to ACTIVE for rcon_id " + mRconId);
814 mhunt 453
    mRunLevel.persist(mReleaseManager, mRconId);
454
  }
455
 
456
  /**performs disk housekeeping which involves deleting build directories > 5 days old
457
   * refer to the sequence diagram check environment
458
   */
459
  private void housekeep()
460
  {
461
    mLogger.debug("housekeep");
462
    FilenameFilter filter = new FilenameFilter()
463
    {
464
      public boolean accept(File file, String name)
465
      {
466
        mLogger.debug("accept " + name);
467
        boolean retVal = false;
468
 
469
        if ( file.isDirectory() && !name.startsWith( "." ) )
470
        {
471
          retVal = true;
472
        }
473
 
474
        mLogger.info("accept returned " + retVal);
475
        return retVal;
476
      }
477
    };
478
 
479
    try
480
    {
842 mhunt 481
      // DEVI 46729, 46730, solaris 10 core dumps implicate deleteDirectory
482
      // let each BuildThread look after its own housekeeping
854 mhunt 483
      File ocwd = new File( BuildDaemon.mGbeLog );
484
      File hcwd = new File( ocwd, BuildDaemon.mHostname );
485
      File cwd = new File( hcwd, String.valueOf( mRtagId ) );
842 mhunt 486
 
814 mhunt 487
      File[] children = cwd.listFiles( filter );
488
 
489
      if ( children != null )
490
      {
491
        for ( int child=0; child < children.length; child++ )
492
        {
854 mhunt 493
          // child is named uniquely to encapsulate a build
494
          // 5 days = 432,000,000 milliseconds
495
          if ( ( System.currentTimeMillis() - children[ child ].lastModified() ) > 432000000 )
814 mhunt 496
          {
854 mhunt 497
            // the directory is over 5 days old
498
            mLogger.warn("housekeep deleting directory " + children[ child ].getName());
896 mhunt 499
            if ( mUnitTest.compareTo("unit test check environment") != 0 )
814 mhunt 500
            {
854 mhunt 501
              deleteDirectory( children[ child ] );
814 mhunt 502
            }
503
          }
504
        }
505
      }
506
    }
507
    catch( SecurityException e )
508
    {
509
      // this can be thrown by lastModified
894 mhunt 510
      mLogger.warn("housekeep caught SecurityException");
814 mhunt 511
    }
512
 
513
  }
514
 
894 mhunt 515
  /**returns true if a file exists and can be deleted,
516
   * created and exists in the file system
517
   * this is to guard against read-only file systems
518
   */
519
  private boolean touch()
520
  {
521
    mLogger.debug("touch");
522
    boolean retVal = true;
523
 
524
    try
525
    {
526
      File touch = new File( String.valueOf( mRtagId ) + "touch" );
527
 
528
      if ( touch.exists() )
529
      {
530
        // delete it
531
        retVal = touch.delete();
532
      }
533
 
534
      if ( retVal )
535
      {
536
        // file does not exist
537
        retVal = touch.createNewFile();
538
      }
539
    }
540
    catch( SecurityException e )
541
    {
542
      // this can be thrown by exists, delete, createNewFile
543
      retVal = false;
544
      mLogger.warn("touch caught SecurityException");
545
    }
546
    catch( IOException e )
547
    {
548
      // this can be thrown by createNewFile
549
      retVal = false;
550
      mLogger.warn("touch caught IOException");
551
    }
552
 
553
    mLogger.info("touch returned " + retVal);
554
    return retVal;
555
  }
556
 
814 mhunt 557
  /**returns true if free disk space > 10G
558
   * this may become configurable if the need arises
559
   * refer to the sequence diagram check environment
560
   */
561
  private boolean hasSufficientDiskSpace()
562
  {
563
    mLogger.debug("hasSufficientDiskSpace");
564
    boolean retVal = true;
565
    long freeSpace = 0;
566
 
567
    try
568
    {
569
      File cwd = new File( "." );
570
 
571
      // 5G = 5368709120 bytes
886 mhunt 572
      // 1G = 1073741824 bytes - useful for testing
896 mhunt 573
      if ( mUnitTest.compareTo("unit test check environment") == 0 )
814 mhunt 574
      {
864 mhunt 575
        if ( ReleaseManager.mPersistedRunLevelCollection.size() == 0 )
814 mhunt 576
        {
577
          retVal = false;
578
        }
579
        else
580
        {
581
          retVal = true;
582
        }
583
      }
584
      else
585
      {
816 mhunt 586
        freeSpace = cwd.getUsableSpace();
814 mhunt 587
 
588
        if ( freeSpace < 5368709120L )
589
        {
816 mhunt 590
          mLogger.warn("hasSufficientDiskSpace on " + cwd.getAbsolutePath() + " freeSpace " + freeSpace);
814 mhunt 591
          retVal = false;
592
        }
593
      }
594
    }
595
    catch( SecurityException e )
596
    {
597
      // this can be thrown by getFreeSpace
598
       mLogger.warn("hasSufficientDiskSpace caught SecurityException");
599
    }
600
 
601
    mLogger.info("hasSufficientDiskSpace returned " + retVal + " " + freeSpace);
602
    return retVal;
603
  }
604
 
605
  /**abstract method
606
   */
607
  public abstract void run();
608
 
609
  /**deletes directory and all its files
610
   */
611
  protected void deleteDirectory(File directory)
612
  {
613
    mLogger.debug("deleteDirectory " + directory.getName());
614
    try
615
    {
616
      if ( directory.exists() )
617
      {
618
        FilenameFilter filter = new FilenameFilter()
619
        {
620
          public boolean accept(File file, String name)
621
          {
622
            mLogger.debug("accept " + name);
623
            boolean retVal = false;
624
 
840 mhunt 625
            if ( name.compareTo(".") != 0 && ( name.compareTo("..") != 0 ) )
814 mhunt 626
            {
627
              retVal = true;
628
            }
629
 
630
            mLogger.info("accept returned " + retVal);
631
            return retVal;
632
          }
633
        };
634
 
635
        File[] children = directory.listFiles( filter );
636
 
637
        if ( children != null )
638
        {
639
          for ( int child=0; child < children.length; child++ )
640
          {
641
            if ( children[ child ].isDirectory() )
642
            {
643
              deleteDirectory( children[ child ] );
644
            }
645
            else
646
            {
647
              children[ child ].delete();
648
            }
649
          }
650
        }
651
        directory.delete();
652
      }
653
    }
654
    catch( SecurityException e )
655
    {
656
      // this can be thrown by exists and delete
657
       mLogger.warn("deleteDirectory caught SecurityException");
658
    }
659
  }
660
 
661
  /**abstract method
662
   */
663
  protected abstract char getMode();
664
 
4280 dpurdie 665
  /**
814 mhunt 666
   * builds a buildFile from the buildFileContent
667
   * triggers ant to operate on the buildFile
668
   */
854 mhunt 669
  protected void deliverChange(String buildFileContent, String target, boolean master)
814 mhunt 670
  {
671
    mLogger.debug("deliverChange");
854 mhunt 672
 
902 mhunt 673
    // always perform a AbtSetUp and AbtTearDown
674
    if ( ( target == null && mErrorReported ) || ( target == "AbtPublish" && mErrorReported ) )
854 mhunt 675
    {
902 mhunt 676
      // AbtSetUp or the build failed
866 mhunt 677
      // the default target will inevitably fail and will generate further email if allowed to proceed
678
      // do not mask the root cause
854 mhunt 679
      return;
680
    }
681
 
814 mhunt 682
    File buildFile = new File(mRtagId + "build.xml");
862 mhunt 683
    boolean logError = true;
866 mhunt 684
    Project p = new Project();
814 mhunt 685
 
686
    try
687
    {
4280 dpurdie 688
      //    AbtSetUp
689
      //    Create the build's xml file
690
      //
814 mhunt 691
      if ( buildFileContent != null && target != null && target.compareTo("AbtSetUp") == 0 )
692
      {
693
        FileOutputStream buildFileOutputStream = new FileOutputStream(buildFile, false);
694
        buildFileOutputStream.close();
695
 
696
        StringReader buildFileContentStringReader = new StringReader(buildFileContent);
697
        BufferedReader buildFileBufferedReader = new BufferedReader(buildFileContentStringReader);
698
 
699
        // sanitise the buildFileContent
4280 dpurdie 700
        //      it may contain line.separators of "\n", "\r", or "\r\n" variety, 
701
        //      depending on the location of the ripple engine
814 mhunt 702
        String sanitisedBFC = new String();
703
        String lf = new String( System.getProperty("line.separator") );
704
        String line = new String();
705
 
706
        while( ( line = buildFileBufferedReader.readLine() ) != null)
707
        {
708
          sanitisedBFC += line + lf;
709
        }
710
        buildFileBufferedReader.close();
711
        FileWriter buildFileWriter = new FileWriter(buildFile);
712
        buildFileWriter.write(sanitisedBFC);
713
        buildFileWriter.close();
714
      }
715
 
866 mhunt 716
      mReportingPackageName = null;
717
      mReportingPackageVersion = null;
718
      mReportingPackageExtension = null;
719
      mReportingPackageLocation = null;
720
      mReportingPackageDepends = null;
721
      mReportingIsRipple = null;
722
      mReportingPackageVersionId = null;
723
      mReportingDoesNotRequireSourceControlInteraction = null;
908 mhunt 724
      mReportingTestBuild = null;
866 mhunt 725
      mReportingFullyPublished = null;
924 dpurdie 726
      mReportingNewVcsTag = null;
866 mhunt 727
 
728
      if ( buildFile.exists() )
814 mhunt 729
      {
866 mhunt 730
        p.setProperty("ant.file", buildFile.getAbsolutePath());
930 dpurdie 731
 
732
        // Add listener for logging the complete build process
733
        // If the daemon has been restarted, then the listener will not have been
734
        // set up - do don't add it. Perhaps we need a way to open an existing
735
        // logfile to append.
736
        if ( mBuildLogger != null )
737
        {
738
          p.addBuildListener(mBuildLogger);
739
        }
740
 
866 mhunt 741
        p.init();
742
        ProjectHelper pH = ProjectHelper.getProjectHelper();
743
        p.addReference("ant.projectHelper", pH);
744
 
745
        // parse can throw BuildException, this is serious
746
        pH.parse(p, buildFile);
747
        mLogger.warn("deliverChange ant launched on " + buildFile.getAbsolutePath());
748
 
749
        if ( target == null )
750
        {
751
          target = p.getDefaultTarget();
752
        }
753
        mLogger.warn("deliverChange ant launched against target " + target);
754
 
755
        // executeTarget can throw BuildException, this is not serious
756
        logError = false;
757
        // set up project properties for reporting purposes
758
        // this first group are hard coded in the build file
759
        mReportingPackageName = p.getProperty("abt_package_name");
760
        mReportingPackageVersion = p.getProperty("abt_package_version");
761
        mReportingPackageExtension = p.getProperty("abt_package_extension");
762
        mReportingPackageLocation = p.getProperty("basedir") + p.getProperty("abt_package_location");
763
        mReportingPackageDepends = p.getProperty("abt_package_depends");
764
        mReportingIsRipple = p.getProperty("abt_is_ripple");
765
        mReportingPackageVersionId = p.getProperty("abt_package_version_id");
766
        mReportingDoesNotRequireSourceControlInteraction = p.getProperty("abt_does_not_require_source_control_interaction");
908 mhunt 767
        mReportingTestBuild = p.getProperty("abt_test_build_instruction");
866 mhunt 768
 
769
        p.executeTarget(target);
770
        mLogger.warn("deliverChange ant returned");
771
 
814 mhunt 772
      }
773
    }
930 dpurdie 774
    //
775
    //  Catch exceptions
776
    //  Do not catch ALL exceptions. The MasterThread::run and SlaveThread::run
777
    //  relies on exceptions propergating upwards for the indefinite pause feature
778
    //
814 mhunt 779
    catch( BuildException e )
780
    {
862 mhunt 781
      if ( logError )
782
      {
783
        mLogger.error("deliverChange caught BuildException, the build failed " + e.getMessage());
784
      }
785
      else
786
      {
866 mhunt 787
        if ( mReportingBuildFailureLogFile == null )
788
        {
789
          mReportingBuildFailureLogFile = e.getMessage();
790
        }
791
        mLogger.debug("deliverChange caught BuildException, big deal, the build failed " + mReportingBuildFailureLogFile);
862 mhunt 792
      }
854 mhunt 793
 
794
      mErrorReported = true;
814 mhunt 795
    }
796
    catch( FileNotFoundException e )
797
    {
798
      mLogger.error("deliverChange caught FileNotFoundException");
799
    }
800
    catch( IOException e )
801
    {
802
      mLogger.error("deliverChange caught IOException");
803
    }
804
 
866 mhunt 805
    // this group are set at run time (by the AbtPublish target only)
806
    // they will be null for every other target,
807
    // and null if an error occurs in the AbtPublish target
808
    mReportingFullyPublished = p.getProperty("abt_fully_published");
924 dpurdie 809
    mReportingNewVcsTag = p.getProperty("abt_new_vcstag");
866 mhunt 810
 
814 mhunt 811
  }
812
 
930 dpurdie 813
  /**Extract source from Version Control
814 mhunt 814
   */
896 mhunt 815
  protected void setViewUp(String content, boolean master) throws SQLException, Exception
814 mhunt 816
  {
817
    mLogger.debug("setViewUp");
866 mhunt 818
    mReportingBuildFailureLogFile = null;
854 mhunt 819
    mErrorReported = false;
868 mhunt 820
 
821
    if ( !master && mGbeGatherMetricsOnly != null )
822
    {
823
      // do not run AbtSetUp on slave in metrics gathering mode
824
      return;
825
    }
826
 
814 mhunt 827
    // run ant on the AbtSetUp target
828
    deliverChange(content, "AbtSetUp", master);
829
  }
830
 
868 mhunt 831
  /**
832
   * indefinite pause notification
833
  */
834
   protected void indefinitePause(RippleEngine rippleEngine, String cause)
835
   {
836
     mLogger.debug("indefinitePause");
837
 
838
     String body =
839
     "Hostname: " + BuildDaemon.mHostname + "<p>" +
840
     "Release: " + rippleEngine.mBaselineName + "<p>" +
922 dpurdie 841
     "Cause: " + cause + "<p><hr>";
868 mhunt 842
 
843
     try
844
     {
845
       Smtpsend.send(
4280 dpurdie 846
       rippleEngine.mMailServer,        // mailServer
847
       rippleEngine.mMailSender,        // source
848
       rippleEngine.mGlobalTarget,      // target (list)
849
       null,                            // cc
850
       null,                            // bcc
868 mhunt 851
       "BUILD DAEMON INDEFINITE PAUSE", // subject
4280 dpurdie 852
       body,                            // body
853
       null                             // attachment
868 mhunt 854
       );
855
     }
856
     catch( Exception e )
857
     {
858
     }
859
   }
1361 dpurdie 860
 
861
    /**
862
     *  Nagios interface
863
     *      Returns true if the thread looks OK
864
    */
865
    boolean checkThread()
866
    {
867
      boolean retVal = true;
868
      if ( mRunLevel == RunLevel.CANNOT_CONTINUE )
869
      {
870
        retVal = false;
871
      }
2541 dpurdie 872
      else
873
      {
874
        retVal = checkThreadExtended();
875
      }
1361 dpurdie 876
 
4123 dpurdie 877
      mLogger.warn("checkThread returned " + retVal);
1361 dpurdie 878
      return retVal;
879
    }
2541 dpurdie 880
 
881
    /**
882
     * Nagios interface extension
883
     * This method should be overriden by classes that extend this class
884
     * If not overriden then the test indicates OK
885
     *
886
     *      Returns true if the thread looks OK
887
    */
888
    boolean checkThreadExtended()
889
    {
890
      return true;
891
    }
892
 
814 mhunt 893
}