Subversion Repositories DevTools

Rev

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