Subversion Repositories DevTools

Rev

Rev 7046 | Rev 7088 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
6914 dpurdie 1
package com.erggroup.buildtool.ripple;
2
 
3
import java.sql.SQLException;
4
import java.util.ArrayList;
5
import java.util.Collections;
6
import java.util.Iterator;
7
import java.util.List;
8
import java.util.ListIterator;
9
 
7033 dpurdie 10
import org.slf4j.Logger;
11
import org.slf4j.LoggerFactory;
6914 dpurdie 12
 
13
import com.erggroup.buildtool.ripple.BuildFile.BuildFileState;
14
import com.erggroup.buildtool.ripple.ReleaseManager.BuildReason;
15
import com.erggroup.buildtool.smtp.CreateUrls;
16
import com.erggroup.buildtool.smtp.Smtpsend;
17
import com.erggroup.buildtool.utilities.StringAppender;
18
import com.erggroup.buildtool.utilities.XmlBuilder;
19
 
20
/**Plans release impact by generating a set of Strings containing build file content.
21
 */
22
public class RippleEngine
23
{
24
 
25
    /**configured mail server
26
     * @attribute
27
     */
28
    private String mMailServer = "";
29
 
30
    /**configured mail sender user
31
     * @attribute
32
     */
33
    private String mMailSender = "";
34
 
35
    /**configured global email target
36
     * @attribute
37
     */
38
    private String mMailGlobalTarget = "";
39
 
40
    /** Vector of email addresses for global and project wide use
41
     *  Most emails will be sent to this list of email recipients
42
     */
43
    public List<String> mMailGlobalCollection = new ArrayList<String>();
44
 
45
    /**name associated with the baseline
46
     * @attribute
47
     */
48
    public String mBaselineName = "";
49
 
50
    /**Collection of build exceptions associated with the baseline
51
     * Used to determine (and report) what change in build exceptions happens as part of planRelease
52
     * Daemon centric
53
     * @aggregation shared
54
     * @attribute
55
     */
56
    ArrayList<BuildExclusion> mBuildExclusionCollection = new ArrayList<BuildExclusion>();
57
 
58
    /**Logger
59
     * @attribute
60
     */
7033 dpurdie 61
    private static final Logger mLogger = LoggerFactory.getLogger(RippleEngine.class);
6914 dpurdie 62
 
63
    /** Escrow information - commands to set up escrow
64
     * @attribute
65
     */
66
    private String mEscrowSetup;
67
 
68
    /** Escrow information - Raw data (May not be used)
69
     * @attribute
70
     */
71
    private String mEscrowRawData;
72
 
7082 dpurdie 73
    /** Collections of packages
6914 dpurdie 74
     */
75
    private ArrayList<Package> mPackageCollection = new ArrayList<Package>();
7082 dpurdie 76
    private ArrayList<Package> mPackageCollectionWip = new ArrayList<Package>();
77
    private ArrayList<Package> mPackageCollectionTest = new ArrayList<Package>();
78
    private ArrayList<Package> mPackageCollectionRipple = new ArrayList<Package>();
79
    private ArrayList<Package> mPackageCollectionAll = new ArrayList<Package>();
80
 
6914 dpurdie 81
 
82
    /**index to current String item
83
     * @attribute
84
     */
85
    private int mBuildIndex;
86
 
87
    /**Database abstraction
88
     * @attribute
89
     */
90
    ReleaseManager mReleaseManager;
91
 
92
    /**Baseline identifier (rtag_id for a release manager baseline, bom_id for deployment manager baseline)
93
     * @attribute
94
     */
95
    private int mBaseline;
96
 
97
    /** Escrow Only: SBOM_ID
98
     */
99
    private int mSbomId;
100
 
101
    /** RTAG_ID
102
     *  Set from mBaseline
103
     */
104
    private int mRtagId;
105
 
106
    /**When true, mBuildCollection contains one item based on a release manager rtag_id and contains a daemon property
107
     * When false, mBuildCollection contains at least one item based on a deployment manager bom_id
108
     * Will be accessed by the Package class to calculate its mAlias
109
     * @attribute
110
     */
111
    public boolean mDaemon;
112
 
113
    /**collection of build file content in String form
114
     * @attribute
115
     */
116
    private ArrayList<BuildFile> mBuildCollection = new ArrayList<BuildFile>();
117
 
118
    /** List of packages that we plan to build
119
     * Used to provide feedback into RM
120
     * Only the first entry is about to be built as we re-plan every cycle
121
     */
7082 dpurdie 122
    private ArrayList<PlannedPackage> mBuildOrder = new ArrayList  <PlannedPackage>();
6914 dpurdie 123
    /**Warning message
124
     * @attribute
125
     */
126
    private static final String mAnyBuildPlatforms = "Warning. The following package versions are not reproducible on any build platform: ";
127
 
128
    /**Flag to control output to standard out
129
     * @attribute
130
     */
131
    private boolean mAnyBuildPlatformsFlag = true;
132
 
133
    /**Warning message
134
     * @attribute
135
     */
136
    private static final String mAssocBuildPlatforms = "Warning. The following package versions are not reproducible on the build platforms associated with this baseline: ";
137
 
138
    /**Flag to control output to standard out
139
     * @attribute
140
     */
141
    private boolean mAssocBuildPlatformsFlag = true;
142
 
143
    /**Warning message
144
     * @attribute
145
     */
146
    private static final String mNotInBaseline = "Warning. The following package versions are not reproducible as they are directly dependent upon package versions not in the baseline: ";
147
 
148
    /**Flag to control output to standard out
149
     * @attribute
150
     */
151
    private boolean mNotInBaselineFlag = true;
152
 
153
    /**Warning message
154
     * @attribute
155
     */
156
    private static final String mDependent = "Warning. The following package versions are not reproducible as they are directly/indirectly dependent upon not reproducible package versions: ";
157
 
158
    /**Flag to control output to standard out
159
     * @attribute
160
     */
161
    private boolean mDependentFlag = true;
162
 
163
    /**Warning message
164
     * @attribute
165
     */
166
    private static final String mCircularDependency = "Warning. The following package versions are not reproducible as they have circular dependencies: ";
167
 
168
    /**Flag to control output to standard out
169
     * @attribute
170
     */
171
    private boolean mCircularDependencyFlag = true;
172
 
173
    /** String used to terminate lines
174
     * @attribute
175
     */
176
    private static final  String mlf = System.getProperty("line.separator");
177
 
178
    /** XML File Prefix
179
     */
180
    private static final String mXmlHeader = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>" + mlf;
181
 
182
    /**RippleEngine constructor
183
     * @param releaseManager  - Associated releaseManager instance
184
     * @param rtagId         - Release Identifier
185
     * @param isDaemon        - Mode of operation. False: Escrow, True: Daemon
186
     */
187
    public RippleEngine(ReleaseManager releaseManager, int rtagId, boolean isDaemon)
188
    {
7044 dpurdie 189
        mLogger.debug("RippleEngine rtag_id {} isDaemon {}", rtagId, isDaemon);
6914 dpurdie 190
        mReleaseManager = releaseManager;
191
        mBaseline = rtagId;
192
        mRtagId = rtagId;
193
        mDaemon = isDaemon;
194
        mReleaseManager.setDaemonMode(mDaemon);
195
    }
196
 
197
    /**
198
     * getRtagId
7044 dpurdie 199
     * @return The rtagId of the Release attached to this instance of the RippleEngine
6914 dpurdie 200
     */
201
    public int getRtagId()
202
    {
203
        return mRtagId;
204
    }
205
 
206
    /**Plan what is to be built
207
     * 	<br>Discards all build file content
208
     * 	<br>Generates new build file content
209
     * 
210
     * @param lastBuildActive 		- False. Daemon Mode. The last build was a dummy. 
211
     *                                This planning session may not result in a build
212
     *                              - True. Daemon Mode. The last build was not a dummy.
213
     *                                There is a very good chance that this planning session
214
     *                                will result in a build, so it is given priority to connect 
215
     *                                to the database.	
216
     */
217
    public void planRelease(final boolean lastBuildActive) throws SQLException, Exception
218
    {
7044 dpurdie 219
        mLogger.warn("planRelease mDaemon {}", mDaemon);
6914 dpurdie 220
 
221
        mBuildCollection.clear();
222
        mPackageCollection.clear();
7082 dpurdie 223
        mPackageCollectionRipple.clear();
224
        mPackageCollectionTest.clear();
225
        mPackageCollectionWip.clear();
6914 dpurdie 226
        mBuildOrder.clear();
227
        mEscrowRawData = "";
228
        mEscrowSetup = "";
229
        Phase phase = new Phase("Plan");
230
 
231
        // use finally block in planRelease to ensure the connection is released
232
        try
233
        {
234
            phase.setPhase("connectForPlanning");
235
            mReleaseManager.connectForPlanning(lastBuildActive);
236
 
237
            if ( mDaemon )
238
            {
239
                // claim the mutex
240
                mLogger.warn("planRelease claimMutex");
241
                phase.setPhase("claimMutex");
242
                mReleaseManager.claimMutex();
243
 
244
                // Populate the mBuildExclusionCollection
245
                //
246
                // Builds are either 'Directly excluded' or 'Indirectly excluded'
247
                // Direct excludes result from:
248
                //      User request
249
                //      Build failure
250
                //      Inability to build package
251
                // Indirectly excluded packages result from have a build dependency on a package
252
                // that is directly excluded.
253
                //  
254
                // In the following code we will extract from the Database all build exclusions
255
                // We will then add 'Relevant' entries to mBuildExclusionCollection
256
                // and delete, from the database those that are no longer relevant - ie indirectly excluded
257
                // items where the root cause is no longer in the set.
258
                phase.setPhase("mBuildExclusionCollection");
259
                mBuildExclusionCollection.clear();
260
                ArrayList<BuildExclusion> tempBuildExclusionCollection = new ArrayList<BuildExclusion>();
261
 
262
                mLogger.debug("planRelease queryBuildExclusions");
263
                mReleaseManager.queryBuildExclusions(tempBuildExclusionCollection, mBaseline);
264
 
265
                // only populate mBuildExclusionCollection with tempBuildExclusionCollection entries which have a relevant root_pv_id
266
                // The entry is relevant if:
267
                //     It is for a directly excluded package,other than a RippleStop
268
                //     It is for an indirectly excluded package AND the reason for exclusion still exists
269
                //
270
 
271
                for (Iterator<BuildExclusion> it = tempBuildExclusionCollection.iterator(); it.hasNext(); )
272
                {
273
                    BuildExclusion buildExclusion = it.next();
274
 
275
                    if ( buildExclusion.isRelevant(tempBuildExclusionCollection) )
276
                    {
277
                        mBuildExclusionCollection.add(buildExclusion);
278
                    }
279
                    else
280
                    {
281
                        // Remove the indirectly excluded entry as its root cause
282
                        // is no longer present.
283
                        buildExclusion.includeToBuild(mReleaseManager, mBaseline);
284
                    }
285
                }
286
            }
287
 
288
            //-----------------------------------------------------------------------
289
            //	Query package versions
290
            //
291
            phase.setPhase("queryPackageVersions");
292
            mLogger.debug("planRelease queryPackageVersions");
293
            mReleaseManager.queryPackageVersions(this, mPackageCollection, mBaseline);
7082 dpurdie 294
            mReleaseManager.queryWips(this, mPackageCollectionWip, mBaseline);
295
            mReleaseManager.queryTest(this, mPackageCollectionTest, mBaseline);
296
            mReleaseManager.queryRipples(this, mPackageCollectionRipple, mBaseline);
297
            mPackageCollectionAll.addAll(mPackageCollection);
298
            mPackageCollectionAll.addAll(mPackageCollectionWip);
299
            mPackageCollectionAll.addAll(mPackageCollectionTest);
300
            mPackageCollectionAll.addAll(mPackageCollectionRipple);
301
 
302
            // Sort the collection by PVID
303
            //      Unit Test output order is known
304
            //      May assist in creating repeatable build orders
305
            //
306
            Collections.sort(mPackageCollectionAll, Package.SeqComparator);
6914 dpurdie 307
 
308
            //------------------------------------------------------------------------
309
            //    Process packages collected
310
            //    Determine and tag those we can't build
311
            phase.setPhase("processPackages");
312
            processPackages();
313
 
314
            //-----------------------------------------------------------------------
315
            //    At this point we have tagged all the packages that we cannot build
316
            //    Now we can determine what we are building
317
            phase.setPhase("planBuildOrder");
318
            mLogger.debug("planRelease process Remaining");
319
            planBuildOrder();
320
 
321
            //  Report excluded packages and the build plan
322
            //  This is being done with the MUTEX being held, but the 
323
            //  trade off is the cost of getting a connection.
324
            //
325
            if ( mDaemon )
326
            {
327
                phase.setPhase("Report Change");
328
                reportChange();
329
                phase.setPhase("Report Plan");            
330
                reportPlan();
331
            }
332
 
333
            //
334
            //	Generate the build Files
335
            //
336
            phase.setPhase("generateBuildFiles");
337
            generateBuildFiles();
338
        }
339
        finally
340
        {
341
            mLogger.debug("planRelease finally");
342
            // this block is executed regardless of what happens in the try block
343
            // even if an exception is thrown
344
            // ensure the SELECT FOR UPDATE is released
345
            try
346
            {
347
                if ( mDaemon )
348
                {
349
                    // attempt to release the SELECT FOR UPDATE through a commit
350
                    // a commit must be done in the normal case
351
                    // a commit may as well be done in the Exception case
352
                    // in the case of a SQLException indicating database connectivity has been lost
353
                    // having a go at the commit is superfluous
354
                    // as the SELECT FOR UPDATE will have been released upon disconnection
355
                    phase.setPhase("releaseMutex");
356
                    mReleaseManager.releaseMutex();
357
                }
358
            }
359
            finally
360
            {
361
                // ensure disconnect under all error conditions
362
                phase.setPhase("disconnectForPlanning");
363
                mReleaseManager.disconnectForPlanning(lastBuildActive);
364
            }
365
        }
366
 
7044 dpurdie 367
        mLogger.warn("planRelease mDaemon {} returned", mDaemon);
6914 dpurdie 368
        phase.setPhase("EndPlan");
369
    }
370
 
371
    /** Process packages that have been collected as a part of the plan
372
     * @param phase
373
     * @throws SQLException
374
     * @throws Exception
375
     */
376
    private void processPackages() throws SQLException, Exception {
377
 
378
        // Deal with test builds here as they may impact upon package attributes
7082 dpurdie 379
        //    eg: dependency collection and build standard differences
6914 dpurdie 380
        //    Note: Done before mPackageDependencyCollection is setup
381
        //
382
        if ( mDaemon )
383
        {
7082 dpurdie 384
            // Process test builds - they are in their own collection
385
            for (Iterator<Package> it = mPackageCollectionTest.iterator(); it.hasNext(); )
6914 dpurdie 386
            {
387
                Package p = it.next();
7082 dpurdie 388
                mLogger.info("planRelease package test build {}", p.mAlias);
6914 dpurdie 389
 
7082 dpurdie 390
                //
391
                //    Cannot test build an SDK based package or a Pegged Package
392
                //        Remove the test build request from the database
393
                //        Send a warning email
394
                //
395
                if(p.mIsPegged || p.mIsSdk)
6914 dpurdie 396
                {
397
                    // package has yet to be processed
398
                    if (  p.mTestBuildInstruction > 0 )
399
                    {
7044 dpurdie 400
                        mLogger.info("planRelease package test build {}", p.mName);
6914 dpurdie 401
 
7082 dpurdie 402
                    mLogger.error("planRelease Daemon Instruction (testBuild) of {} package deleted: {}", reason, p.mAlias);
403
                    mReleaseManager.markDaemonInstCompleted( p.mTestBuildInstruction );
404
                    emailRejectedDaemonInstruction("Cannot 'Test Build' a " + reason + " package",p);
405
                }
6914 dpurdie 406
 
7044 dpurdie 407
                            mLogger.error("planRelease Daemon Instruction of {} package deleted: {}", reason, p.mName);
6914 dpurdie 408
                            mReleaseManager.markDaemonInstCompleted( p.mTestBuildInstruction );
409
                            emailRejectedDaemonInstruction("Cannot 'Test Build' a " + reason + " package",p);
410
                        }
411
 
412
                        // force patch for test build numbering
413
                        p.mDirectlyPlanned = true;
414
                        p.mChangeType.setPatch();
415
                        p.mRequiresSourceControlInteraction = false;
416
                        p.mBuildReason = BuildReason.Test;
417
                        rippleIndirectlyPlanned(p);
418
 
419
                        // put the mTestBuildAttributes to work
420
                        p.mVcsTag = p.mTestBuildVcsTag;
421
                        p.mId = p.mTestBuildPvId;
422
                        p.setTestEmail();
423
                        p.setTestDependencyCollection();
424
                        p.setTestBuildStandardCollection();
425
                        p.mHasAutomatedUnitTests = p.mTestBuildHasAutomatedUnitTests;
426
                    }
427
                }
428
            }
429
        }
430
 
431
        // Set up mPackageDependencyCollection on each package
432
        //    Examine the dependencies by alias and convert this to a 'package' selected from the released package set
7082 dpurdie 433
        mLogger.debug("planRelease setup setPackageDependencyCollection");
434
        for (Iterator<Package> it = mPackageCollectionAll.iterator(); it.hasNext(); )
6914 dpurdie 435
        {
436
            Package p = it.next();
437
 
438
            for (Iterator<String> it2 = p.mDependencyCollection.iterator(); it2.hasNext(); )
439
            {
440
                String alias = it2.next();
441
                Package dependency = findPackage(alias);
442
                p.mPackageDependencyCollection.add(dependency);
443
            }
7082 dpurdie 444
        }    
6914 dpurdie 445
 
7082 dpurdie 446
        // Detect and deal with circular dependencies
447
        // Examine all packages under consideration
448
        //
6914 dpurdie 449
        mLogger.debug("planRelease deal with circular dependencies");
7082 dpurdie 450
        for (Iterator<Package> it = mPackageCollectionAll.iterator(); it.hasNext(); )
6914 dpurdie 451
        {
452
            Package p = it.next();
453
 
7082 dpurdie 454
            if ( p.hasCircularDependency( mPackageCollectionAll ) )
6914 dpurdie 455
            {
7044 dpurdie 456
                mLogger.info("planRelease circular dependency detected {}", p.mAlias);
6914 dpurdie 457
 
458
                //  Force this package to be marked as having a circular dependency - even if its been excluded
459
                p.mBuildFile = 0;
460
 
7082 dpurdie 461
                // Exclude the package
6914 dpurdie 462
                // max 50 chars
7082 dpurdie 463
                rippleBuildExclude(p, p.mId, "Package has circular dependency", -6);
6914 dpurdie 464
 
465
                // take the package out of the build
466
                p.mBuildFile = -6;
7044 dpurdie 467
                mLogger.info("planRelease set mBuildFile to -6 for package {}", p.mAlias );
6914 dpurdie 468
                standardOut(mCircularDependency, p.mAlias, mCircularDependencyFlag);
469
                mCircularDependencyFlag = false;
470
            }
471
        }
472
 
473
        // Scan for packages with missing dependencies
474
        //    ie: The dependent package is not in the package Collection
475
        mLogger.debug("planRelease use the fully built mPackageDependencyCollection");
7082 dpurdie 476
        for (Iterator<Package> it = mPackageCollectionAll.iterator(); it.hasNext(); )
6914 dpurdie 477
        {
478
            Package p = it.next();
479
 
480
            if ( mDaemon )
481
            {
482
                //  Daemon Mode Only
483
                //  Not interested in the dependencies of a pegged package or a package provided from an SDK.
484
                //  Such packages will be deemed to not have missing dependencies
485
                if (p.mIsPegged || p.mIsSdk)
486
                {
487
                    continue;
488
                }
489
            }
490
 
491
            for (Iterator<String> it2 = p.mDependencyCollection.iterator(); it2.hasNext(); )
492
            {
493
                String alias = it2.next();
494
                Package dependency = findPackage(alias);
495
 
496
                if (dependency == ReleaseManager.NULL_PACKAGE)
497
                {
7044 dpurdie 498
                    mLogger.info("planRelease dependency is not in the baseline {}", alias);
6914 dpurdie 499
                    // exclude all dependent packages
500
                    // max 50 chars
7082 dpurdie 501
                    rippleBuildExclude(p, p.mId, "Package build dependency not in the release", -4);
6914 dpurdie 502
 
503
                    // take the package out of the build
504
                    p.mBuildFile = -4;
7044 dpurdie 505
                    mLogger.info("planRelease set mBuildFile to -4 for package {}", p.mAlias );
6914 dpurdie 506
                    standardOut(mNotInBaseline, p.mAlias, mNotInBaselineFlag);
507
                    mNotInBaselineFlag = false;
508
                    break;
509
                }
510
            }
511
        }
512
 
7082 dpurdie 513
        // Detect packages with no build standard and exclude them from the build
6914 dpurdie 514
        mLogger.debug("planRelease process packages which are not reproducible");
7082 dpurdie 515
        for (Iterator<Package> it = mPackageCollectionAll.iterator(); it.hasNext(); )
6914 dpurdie 516
        {
517
            Package p = it.next();
518
 
519
            if (p.mBuildFile == 0)
520
            {
521
                if ( mDaemon )
522
                {
523
                    //  Daemon Mode Only
524
                    //  Not interested in the reproducibility of a pegged package or a package provided from an SDK.
525
                    //  Such packages will be deemed to be reproducible - but out side of this release
526
                    if (p.mIsPegged || p.mIsSdk)
527
                    {
528
                        continue;
529
                    }
530
                }
531
 
7082 dpurdie 532
                // Does the package have a build standard. If not then we can't reproduce it.
533
                // Escrow - Assume the package is provided
534
                // Daemon - Exclude this package, but not its consumers. If the package is available then we can use it.
6914 dpurdie 535
                if (!p.isReproducible())
536
                {
537
                    // for escrow build purposes, exclude all dependent package versions
7044 dpurdie 538
                    mLogger.info("planRelease package not reproducible {}" ,p.mName);
6914 dpurdie 539
                    // max 50 chars
7082 dpurdie 540
                    rippleBuildExclude(p, p.mId, "Package has no build environment", -1);
6914 dpurdie 541
 
542
                    // package is not reproducible, discard
543
                    p.mBuildFile = -1;
7044 dpurdie 544
                    mLogger.info("planRelease set mBuildFile to -1 for package {}", p.mAlias );
6914 dpurdie 545
                    standardOut(mAnyBuildPlatforms, p.mAlias, mAnyBuildPlatformsFlag);
546
                    mAnyBuildPlatformsFlag = false;
547
                }
548
            }
549
        }
550
 
7082 dpurdie 551
        //    Process packages which are not reproducible on the configured set of build machines.
6914 dpurdie 552
        //
553
        //    Test each package and determine if the package contains a buildStandard that
554
        //    can be processed by one of the machines in the build set
555
        //
556
        //    ie: Package: Win32:Production and we have a BM with a class of 'Win32'
557
        //
558
        //    Only exclude the failing package and not its dependents
559
        //    May be legitimate in the release
560
        //
561
        mLogger.debug("planRelease process packages which are not reproducible2");
7082 dpurdie 562
        for (Iterator<Package> it = mPackageCollectionAll.iterator(); it.hasNext(); )
6914 dpurdie 563
        {
564
            Package p = it.next();
565
 
566
            if (p.mBuildFile == 0)
567
            {
568
                if ( mDaemon )
569
                {
570
                    //  Daemon Mode Only
571
                    //  Not interested in the reproducibility of a pegged package or a package provided from an SDK.
572
                    //  Such packages will be deemed to be reproducible - but out side of this release
573
                    if (p.mIsPegged || p.mIsSdk)
574
                    {
575
                        continue;
576
                    }
577
                }
578
 
579
                // package has yet to be processed
580
                // assume it does not need to be reproduced for this baseline
581
                //
582
                //    For each machineClass in the buildset
583
                boolean reproduce = false;
584
 
585
                for (Iterator<String> it2 = mReleaseManager.mReleaseConfigCollection.mMachineClasses.iterator(); it2.hasNext(); )
586
                {
587
                    String machineClass = it2.next();
588
 
589
                    if ( p.canBeBuildby(machineClass))
590
                    {
591
                        reproduce = true;
7044 dpurdie 592
                        mLogger.info("planRelease package built on {} {}", machineClass, p.mAlias );
6914 dpurdie 593
                        break;
594
                    }
595
                }
596
 
597
                if ( !reproduce )
598
                {
7044 dpurdie 599
                    mLogger.info("planRelease package not reproducible on the build platforms configured for this baseline {}", p.mName);
6914 dpurdie 600
 
7082 dpurdie 601
                    // Exclude the package
602
                    // max 50 chars
603
                    rippleBuildExclude(p, p.mId, "Package not built for configured platforms", -2);
6914 dpurdie 604
 
605
                    // package is not reproducible on the build platforms configured for this baseline, discard
606
                    p.mBuildFile = -2;
7044 dpurdie 607
                    mLogger.info("planRelease set mBuildFile to -2 for package {}", p.mAlias );
6914 dpurdie 608
                    standardOut(mAssocBuildPlatforms, p.mAlias, mAssocBuildPlatformsFlag);
609
                    mAssocBuildPlatformsFlag = false;
610
                }
611
            }
612
        }      
613
 
7082 dpurdie 614
        if (mDaemon )
6914 dpurdie 615
        {
616
 
617
                for (Iterator<Package> it1 = mPackageCollection.iterator(); it1.hasNext(); )
618
                {
619
                    Package p = it1.next();
620
 
621
                    // ensure only root cause, non test build, build exclusions are excluded
622
                    // mBuildExclusionCollection is at this point based on
623
                    // relevant (direct and indirect) excluded pv's in the database
624
                    if ( be.compare(p.mId) && be.isARootCause() && p.mTestBuildInstruction == 0 && p.mForcedRippleInstruction == 0 )
625
                    {
626
                        // package is not reproducible, discard
627
                        rippleBuildExclude( p, p.mId, null, it, be, true );
628
                        p.mBuildFile = -3;
7044 dpurdie 629
                        mLogger.info("planRelease set mBuildFile to -3 for package {}", p.mAlias );
6914 dpurdie 630
                        break;
631
                    }
632
                }
633
            }
634
 
635
            //  Daemon Mode Only
636
            //  Process packages which need to be ripple built
637
            mLogger.debug("planRelease process packages which need to be ripple built");
638
            for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
639
            {
640
                Package p = it.next();
641
 
642
                if (p.mBuildFile == 0)
643
                {
644
                    //  Not interested in a pegged package or a package provided from an SDK.
645
                    //  Such packages are not rippled
646
                    if (p.mIsPegged || p.mIsSdk)
647
                    {
648
                        continue;
649
                    }
650
 
7082 dpurdie 651
                    //    Examine this packages dependencies
652
                    //    If one of them does not exist in the 'official release' set then
653
                    //    the package needs to be built against the official release set
654
                    //    and we can't build any of its dependent packages
655
                    Iterator<Integer> it2 = p.mDependencyIDCollection.iterator();
656
                    Iterator<Package> it3 = p.mPackageDependencyCollection.iterator();
657
                    while ( it2.hasNext() && it3.hasNext() )
6914 dpurdie 658
                    {
659
                        // a WIP exists on the package, or it is a Test Build
660
                        // exclude all dependent package versions
7044 dpurdie 661
                        mLogger.info("planRelease package has WIP {}", p.mName);
6914 dpurdie 662
                        if ( p.mBuildReason == null)
663
                            p.mBuildReason = BuildReason.NewVersion;
664
                        rippleIndirectlyPlanned(p);
665
                    }
666
                    else
667
                    {
668
                        //    Examine this packages dependencies
669
                        //    If one of them does not exist in the 'official release' set then
670
                        //    the package needs to be built against the official release set
671
                        //    and we can't build any of its dependent packages
672
                        Iterator<Integer> it2 = p.mDependencyIDCollection.iterator();
673
                        Iterator<Package> it3 = p.mPackageDependencyCollection.iterator();
674
                        while ( it2.hasNext() && it3.hasNext() )
675
                        {
7082 dpurdie 676
                            // not advisory, ie: has ripple build impact
677
                            if ( !isInRelease(dpvId) )
6914 dpurdie 678
                            {
7082 dpurdie 679
                                // the package is out of date
680
                                // exclude all dependent package versions
681
                                mLogger.info("planRelease package out of date {}", p.mName);
682
                                p.mBuildReason = BuildReason.Ripple;
683
                                rippleIndirectlyPlanned(p);
684
 
685
                                //  This package needs to be rippled
686
                                //  If this package has a rippleStop marker of 's', then we cannot
687
                                //  build this package at the moment.
688
                                //  Packages that depend on this package have been excluded
689
                                //  We need to exclude this one too
690
                                //
691
                                if (p.mRippleStop == 's' || p.mRippleStop == 'w') 
6914 dpurdie 692
                                {
693
                                    // the package is out of date
694
                                    // exclude all dependent package versions
7044 dpurdie 695
                                    mLogger.info("planRelease package out of date {}", p.mName);
6914 dpurdie 696
                                    p.mBuildReason = BuildReason.Ripple;
697
                                    rippleIndirectlyPlanned(p);
698
 
699
                                    //  This package needs to be rippled
700
                                    //  If this package has a rippleStop marker of 's', then we cannot
701
                                    //  build this package at the moment.
702
                                    //  Packages that depend on this package have been excluded
703
                                    //  We need to exclude this one too
704
                                    //
705
                                    if (p.mRippleStop == 's' || p.mRippleStop == 'w') 
706
                                    {
707
                                        // Package marked as a rippleStop
708
                                        // max 50 chars
709
                                        rippleBuildExclude(p, -2, "Ripple Required." + " Waiting for user", null, null, false);
710
 
711
                                        // package is unBuildable, mark reason and discard
712
                                        p.mBuildFile = -11;
713
 
714
                                        if (p.mRippleStop == 's' ) {
715
                                            // Need to flag to users that the package build is waiting user action
7044 dpurdie 716
                                            mLogger.info("planRelease Ripple Required. Stopped by flag {}", p.mName);
6914 dpurdie 717
                                            mReleaseManager.setRippleStopWait(mRtagId,p);
718
                                        }
719
                                    }
720
                                }
7082 dpurdie 721
 
722
                                break;
6914 dpurdie 723
                            }
724
                        }
725
                    }
726
                }
727
            }
728
 
729
            //  Daemon Mode Only
730
            //  Process packages which do not exist in the archive
731
            //  For unit test purposes, assume all packages exist in the archive if released
732
            mLogger.debug("planRelease process packages which do not exist in the archive");
7046 dpurdie 733
            if ( mReleaseManager.mUseDatabase )
6914 dpurdie 734
            {
735
                for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
736
                {
737
                    Package p = it.next();
738
 
739
                    if (p.mBuildFile == 0)
740
                    {
741
                        // package has yet to be processed
742
                        if (!p.mDirectlyPlanned && !p.mIndirectlyPlanned && p.mForcedRippleInstruction == 0)
743
                        {
744
                            // check package version archive existence
745
                            if (!p.existsInDpkgArchive())
746
                            {
747
                                if (! p.mIsBuildable)
748
                                {
749
                                    //  Package does not exist in dpkg_archive and it has been flagged as unbuildable
750
                                    //  This may be because is Unbuildable or Manually built
7044 dpurdie 751
                                    mLogger.info("planRelease Unbuildable package not found in archive {}", p.mName);
6914 dpurdie 752
                                    // max 50 chars
7082 dpurdie 753
                                    rippleBuildExclude(p, p.mId, "Unbuildable" + " package not found in archive", -10);
6914 dpurdie 754
 
755
                                }
756
                                //  Not interested in a pegged package or a package provided from an SDK.
757
                                //  Such packages are not rippled
758
                                else if (p.mIsPegged || p.mIsSdk)
759
                                {
760
                                    String reason;
761
                                    reason = (p.mIsPegged) ? "Pegged" : "SDK";
762
 
763
                                    //  Pegged packages or packages provided from an SDK MUST exist in dpkg_archive
764
                                    //  They will not be built within the context of this release. It is the responsibility
765
                                    //  of another release to build them.
7044 dpurdie 766
                                    mLogger.info("planRelease {} package not found in archive {}", reason, p.mName);
6914 dpurdie 767
                                    // max 50 chars
7082 dpurdie 768
                                    rippleBuildExclude(p, p.mId, reason + " package not found in archive", -7);
6914 dpurdie 769
                                }
770
                                else if (p.mForcedRippleInstruction == 0)
771
                                {
772
                                    //  [JATS-331] Unable to rebuild package with Advisory Ripple dependencies
773
                                    //    Examine this packages dependencies
774
                                    //    If one of them does not exist in the 'official release' set then
775
                                    //    the package cannot be rebuilt in this release.
776
                                    for (Iterator<Integer> it2 = p.mDependencyIDCollection.iterator() ; it2.hasNext() ;)
777
                                    {
778
                                        Integer dpvId = it2.next();
779
                                        if ( !isInRelease(dpvId) )
780
                                        {
781
                                            // This package cannot be rebuilt as one of its dependents is NOT in this release
782
                                            // exclude all dependent package versions
783
 
7044 dpurdie 784
                                            mLogger.info("planRelease package not found in archive. Cannot be rebuilt due to {}", p.mName);
6914 dpurdie 785
                                            // max 50 chars
7082 dpurdie 786
                                            rippleBuildExclude(p, p.mId, "Package cannot be rebuilt in this release", -4);
6914 dpurdie 787
                                            break;
788
                                        }
789
                                    }
790
 
791
                                    //  The package has not been excluded from the build
792
                                    if (p.mBuildFile == 0)
793
                                    {
7044 dpurdie 794
                                        mLogger.info("planRelease package not found in archive {}", p.mName);
6914 dpurdie 795
                                        // DEVI 47395 the cause of this build is not WIP or ripple induced,
796
                                        // it simply does not exist in the archive (has been removed)
797
                                        // prevent source control interaction
798
                                        p.mRequiresSourceControlInteraction = false;
799
                                        p.mBuildReason = BuildReason.Restore;
800
                                        rippleIndirectlyPlanned(p);
801
                                    }
802
                                }
803
                            }
804
                        }
805
                    }
806
                }
807
            }
808
 
809
            //  Daemon Mode Only
7082 dpurdie 810
            //  Detect bad forced ripples requests and reject them
6914 dpurdie 811
            mLogger.debug("planRelease process forced ripples");
7082 dpurdie 812
            for (Iterator<Package> it = mPackageCollectionRipple.iterator(); it.hasNext(); )
6914 dpurdie 813
            {
814
                Package p = it.next();
815
 
816
                if (p.mBuildFile == 0)
817
                {
7082 dpurdie 818
                    //
819
                    //    Cannot force a ripple on an SDK based package or a Pegged Package
820
                    //        Remove the daemon instruction from the database
821
                    //        Send a warning email
822
                    //
823
                    if(p.mIsPegged || p.mIsSdk)
6914 dpurdie 824
                    {
7082 dpurdie 825
                        String reason;
826
                        reason = (p.mIsPegged) ? "Pegged" : "SDK Based";
6914 dpurdie 827
 
7044 dpurdie 828
                            mLogger.error("planRelease Daemon Instruction of {} package deleted: {}", reason, p.mName);
6914 dpurdie 829
                            mReleaseManager.markDaemonInstCompleted( p.mForcedRippleInstruction );
830
                            emailRejectedDaemonInstruction("Cannot 'Ripple' a " + reason + " package",p);
831
 
832
                            p.mBuildFile = -8; 
833
                        }
834
                        else
835
                        {
7044 dpurdie 836
                            mLogger.info("planRelease package forced ripple {}", p.mName);
6914 dpurdie 837
                            p.mBuildReason = BuildReason.Ripple;
838
                            rippleIndirectlyPlanned(p);
839
                        }
840
                    }
841
                }
842
            }
843
 
844
            //  Daemon Mode Only
845
            //  Mark Pegged and SDK packages as not to be built
7082 dpurdie 846
            //  Mark RippleStoped packages as not to be build
6914 dpurdie 847
            //  Have previously detected conflicts between pegged/sdk packages and daemon instructions
848
            //
849
            mLogger.debug("planRelease remove pegged and SDK packages from the build set");
850
            for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
851
            {
852
                Package p = it.next();
853
 
854
                if (p.mBuildFile == 0)
855
                {
7082 dpurdie 856
                    String reason = null;
857
 
858
                    //  Not interested in a pegged package or a package provided from an SDK or packages with an active RippleStop
6914 dpurdie 859
                    //  Such packages are not built
860
                    if (p.mIsPegged || p.mIsSdk)
861
                    {
862
                        String reason;
863
                        reason = (p.mIsPegged) ? "Pegged" : "SDK";
864
 
7044 dpurdie 865
                        mLogger.info("planRelease {} not built in this release {}", reason, p.mName);
6914 dpurdie 866
                        p.mBuildFile = -8;
7082 dpurdie 867
                    } else if (p.mIsSdk) {
868
                        reason = "SDK";
869
                        p.mBuildFile = -8;
870
                    } else if (p.mRippleStop == 's' || p.mRippleStop == 'w') {
871
                        reason = "RippleStop";
872
                        p.mBuildFile = -11;
6914 dpurdie 873
                    }
7082 dpurdie 874
 
875
                    if (reason != null)
876
                    {
877
                        mLogger.info("planRelease {} not built in this release {}", reason, p.mName);
878
                    }
6914 dpurdie 879
                }
880
            }
881
 
882
            //  Daemon Mode Only
883
            //  Locate Test Build Requests that cannot be satisfied - will not be built due to
884
            //  errors in dependent packages. Report the error to the user and remove the request
885
            //
7082 dpurdie 886
            for (Iterator<Package> it = mPackageCollectionTest.iterator(); it.hasNext(); )
887
            {
888
                Package p = it.next();
889
 
890
                if (p.mBuildFile < 0)
891
                {
892
                    String reason;
893
                    switch (p.mBuildFile)
894
                    {
895
                    case -1:  reason = "Not reproducible"; break;
896
                    case -2:  reason = "Not reproducible on configured build platforms"; break;
897
                    case -3:  reason = "Marked as 'Do not ripple'"; break;
898
                    case -4:  reason = "Dependent on a package not in the release"; break;
899
                    case -5:  reason = "Indirectly dependent on a package not reproducible in the release"; break;
900
                    case -6:  reason = "Has a circular dependency"; break;
901
                    case -7:  reason = "Pegged or SDK package not in dpkg_archive"; break;
902
                    case -8:  reason = "Is a Pegged or SDK package"; break;
903
                    case -9:  reason = "Rejected Daemon Instruction"; break;
904
                    case -10: reason = "Unbuildable package not in dpkg_archive"; break;
905
                    case -11: reason = "Marked as 'RippleStop'"; break;
906
                    default:  reason = "Unknown reason. Code:" + p.mBuildFile; break;
907
                    }
908
                    mLogger.error("planRelease Test Build of an unbuildable of package deleted: {}", p.mName);
909
                    mReleaseManager.markDaemonInstCompleted( p.mTestBuildInstruction );
910
                    emailRejectedDaemonInstruction(reason,p);
911
                }
912
            }
913
 
914
            //  Daemon Mode Only
915
            //  Examine the build candidates and verify that a new version number can be calculated for each
916
            //  version that we need to build.
917
            //
918
            //  If we can't generate a new version number, then this is considered to be a build failure
919
            //  The package will be excluded and the user will be emailed
920
            //
921
            ArrayList<Package> testVersions = new ArrayList<Package>();
922
            testVersions.addAll(mPackageCollectionWip);
923
            testVersions.addAll(mPackageCollectionRipple);
924
            testVersions.addAll(mPackageCollectionTest);
925
 
6914 dpurdie 926
            for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
927
            {
928
                Package p = it.next();
7082 dpurdie 929
                if (p.mBuildFile >= 0 &&  p.mBuildReason != null) {
930
                    testVersions.add(p);
931
                }
932
            }
933
 
934
            for (Iterator<Package> it = testVersions.iterator(); it.hasNext(); )
935
            {
936
                Package p = it.next();
6914 dpurdie 937
 
7082 dpurdie 938
                if ( p.mBuildFile >= 0 )
6914 dpurdie 939
                {
7082 dpurdie 940
                    int pvApplied = p.applyPV(mReleaseManager);
941
 
942
                    if ( pvApplied == 1 )
6914 dpurdie 943
                    {
944
                        String reason;
945
                        switch (p.mBuildFile)
946
                        {
947
                        case -1: reason = "Not reproducible"; break;
948
                        case -2: reason = "Not reproducible on configured build platforms"; break;
949
                        case -3: reason = "Marked as 'Do not ripple'"; break;
950
                        case -4: reason = "Dependent on a package not in the release"; break;
951
                        case -5: reason = "Indirectly dependent on a package not reproducible in the release"; break;
952
                        case -6: reason = "Has a circular dependency"; break;
953
                        case -7: reason = "Pegged or SDK package not in dpkg_archive"; break;
954
                        case -8: reason = "Is a Pegged or SDK package"; break;
955
                        case -9: reason = "Rejected Daemon Instruction"; break;
956
                        case -10: reason = "Unbuildable package not in dpkg_archive"; break;
957
                        case -11: reason = "Marked as 'RippleStop'"; break;
958
                        default: reason = "Unknown reason. Code:" + p.mBuildFile; break;
959
                        }
7044 dpurdie 960
                        mLogger.error("planRelease Test Build of an unbuildable of package deleted: {}", p.mName);
6914 dpurdie 961
                        mReleaseManager.markDaemonInstCompleted( p.mTestBuildInstruction );
962
                        emailRejectedDaemonInstruction(reason,p);
963
                    }
7082 dpurdie 964
                    else if ( pvApplied == 2 )
965
                    {
966
                        // max 50 chars
967
                        rippleBuildExclude(p, p.mId, "Package has reached ripple field limitations", -5);
968
                    }
969
                    else if ( pvApplied == 3 )
970
                    {
971
                        // max 50 chars
972
                        rippleBuildExclude(p, p.mId, "Package has invalid change type", -5);
973
                    }
6914 dpurdie 974
                }
975
            }
7082 dpurdie 976
 
6914 dpurdie 977
        }
978
        else
979
        {
980
            // escrow reporting only
981
            // Report packages that are not reproducible
982
            //
983
            //  Note: I don't believe this code can be executed
984
            //        The -3 is only set in daemon mode
985
            for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
986
            {
987
                Package p = it.next();
988
 
989
                if (p.mBuildFile == -3)
990
                {
991
                    standardOut(mDependent, p.mAlias, mDependentFlag);
992
                    mDependentFlag = false;
993
                }
994
            }
995
        }
996
    }
7082 dpurdie 997
 
6914 dpurdie 998
    /** Plan the build order.
7082 dpurdie 999
         *  Assumes that a great deal of work has been done.
1000
         *  This is a stand alone method to contain the work
1001
         *  
1002
         * @throws Exception
1003
         * @throws SQLException
1004
         */
1005
        private void planBuildOrder() throws Exception, SQLException 
1006
        {
1007
 
1008
    //TODO - Planning is not working well
1009
    /**
1010
     * Current status
1011
     * The selection of the package to build next is deeply flawed
1012
     * Currently it will select a directly planned package over a ripple - (perhaps that is good)
1013
     * 
1014
     * Currently on the buildPlan of the 'selected' package is included in the BuildOrder
1015
     * 
1016
     * The current algorithm is based on time - but all packages have zero build time ( in UTF )
1017
     * Even if this is fixed the algorithm is broken as we will select the complete build with the shortest time
1018
     * which will be the ripple of a leaf package ( perhaps that is good )
1019
     * 
1020
     * Also:
1021
     *      [Done] Need to include all packages that we can now build into the final build plan, not just the first one and its build tree
1022
     * 
1023
     *      [Done-ish]Need to generate a single package set - so that WIPS and others replace those in the final build set
1024
     *      [Done]Remove duplicates from the complete package set
1025
     *      
1026
     *      [Being Done] Need more test cases
1027
     *      
1028
     *      [Done, in the UTF] Need to report all build options, not just the selected one
1029
     *                         Data to RM may need some more info
1030
     *      
1031
     *      Cleanup the ANT build file - don't list all the release dependencies, just those needed to build the current package
1032
     *      Chances are - all we need is the new package version number
1033
     *      
1034
     *      [Fixed] If a WIP on a package that has circular dependencies is added, then the WIP will be excluded. This prevents the problem being fixed.
1035
     *              Should not exclude a WIP of a package with a circular dependency
6914 dpurdie 1036
     */
7082 dpurdie 1037
 
1038
            // Process remaining packages which are need to be reproduced for this baseline.
1039
            //    Determine the build file for each package
1040
            //    For daemon builds:
1041
            //      Determine the next package that can be built now
1042
            //          Sounds simple - doesn't it
1043
            //      Set its mBuildNumber to 1, all remaining reproducible packages to 2
1044
            //    For escrow builds:
1045
            //      Determine the package versions that can be built in the build iteration
1046
            //      Set their mBuildNumber to the build iteration
1047
            //      Increment the build iteration and repeat until all package versions 
1048
            //      that need to be reproduced have been assigned a build iteration        
1049
 
1050
            //
1051
            //  Generate a plan for the packages that are in the current release
1052
            //  These may be the result of a ripple going through the system 
1053
            //  or a rebuild of a missing package or the result of a merge.
1054
            //
1055
            //  This will provide our basic plan, before we consider adding new packages to the
1056
            //  mix, such as those from user WIPS and RIPPLE requests.
1057
            //  
1058
            PlanResults basicPlan = planCollection("Basic", mPackageCollection, true);
1059
 
1060
            //  Have not considered any of the WIP or RIPPLE packages
1061
            //  If any of them are in the basic plan, then we can ignore them as we will build them
1062
            //  when we build the basic plan
1063
            //
1064
            //  Determine a set of packages that will not be included if we build the basic plan
1065
            //
1066
            //  At the moment - lets assume there are none
1067
            //  What do we do ?
1068
            //      Select the first request
1069
            //      Replace the package in the released collection
1070
            //      Run the plan algorithm
1071
            //      Restore the release collection
1072
            //
1073
            if ( mDaemon )
1074
            {
1075
                //
1076
                //  Need to consider the TEST requests
1077
                //      - Valid requests will be placed first on the build order
1078
                //
1079
                mBuildOrder.clear();
1080
                for (Iterator<Package> it = mPackageCollectionTest.iterator(); it.hasNext(); )
1081
                {
1082
                    Package p = it.next();
1083
                    if (p.mBuildFile >= 0)
1084
                    {
1085
                        mBuildOrder.add( new PlannedPackage(p,0 ) );
1086
                    }
1087
                }
1088
 
1089
                //  First attempt
1090
                //  Insert all the WIPs and RIPPLES into the buildset. 
1091
                //  Generate a plan and see how much the time is extended.
1092
                //
1093
                //  Don't modify mPackageCollection, although data in the 'Package' in the underlying packages may change
1094
 
1095
                PlanResults fullPlan = postRipplePlan("Full", basicPlan, true);
1096
 
1097
                //  Decide with plan to use
1098
                //  At the moment we have, at most two.
1099
                //      - (basic) Current Release ripples
1100
                //      - (full) Current Release + All WIPS and RIPPLES
1101
                //
1102
                //  If we have both then if the full plan is < 20% longer than the basic plan, use the full plan
1103
                //  Otherwise we use basic plan FOLLOWED by the a MODIFIED full plan (one without the natural ripples)
1104
                //  Add the planned packages into the buildOrder
1105
 
1106
                if( !basicPlan.planCollection.isEmpty() && !fullPlan.planCollection.isEmpty() )
1107
                {
1108
                    mLogger.info("Two plan selection: {} {}, {} <= {}", basicPlan.planTime,fullPlan.planTime, basicPlan.planTime * 12, fullPlan.planTime * 10);
1109
                    if ( (basicPlan.planTime * 12) <= (fullPlan.planTime * 10) )
1110
                    {
1111
                        //  Use the basic plan FOLLOWED by a plan that does not include
1112
                        //      Ripples done by the basic plan
1113
                        //      WIPs/RIPPLES done in the course of doing the basic plan
1114
 
1115
                        mBuildOrder.addAll(basicPlan.planCollection);
1116
                        fullPlan = postRipplePlan("Full-Ripples", basicPlan, false);
1117
                        mBuildOrder.addAll(fullPlan.planCollection);
1118
 
1119
                    } else {
1120
                        //  Use the full plan
1121
                        mBuildOrder.addAll(fullPlan.planCollection);
1122
                    }
1123
                } else if (!basicPlan.planCollection.isEmpty() ) {
1124
                    // Use the basic plan
1125
                    mBuildOrder.addAll(basicPlan.planCollection);
1126
 
1127
                } else if ( !fullPlan.planCollection.isEmpty() ) {
1128
                    // Use the full plan
1129
                    mBuildOrder.addAll(fullPlan.planCollection);
1130
 
1131
                } else {
1132
                    // Do not have a plan
1133
                    // May have tests requests
1134
                }
1135
 
1136
                //  Now have an mBuildOrder
1137
                //  Mark the first package in the build order as the one to be built
1138
                //
1139
                Package build = ReleaseManager.NULL_PACKAGE;
1140
                if (!mBuildOrder.isEmpty()) {
1141
                    build = mBuildOrder.get(0).mPkg;
1142
                    build.mBuildFile = 1;
1143
 
1144
                    if ( build.mForcedRippleInstruction > 0 )
1145
                    {
1146
                        mReleaseManager.markDaemonInstCompleted( build.mForcedRippleInstruction );
1147
                    }
1148
 
1149
                    if ( build.mTestBuildInstruction > 0 )
1150
                    {
1151
                        mReleaseManager.markDaemonInstInProgress( build.mTestBuildInstruction );
1152
                    }
1153
 
1154
                    //  Now that we know which package we are building
1155
                    //      Set the previously calculated nextVersion as the packages version number
1156
                    //      Claim the version number to prevent other builds from using it. Even if doing a test build
1157
                    //
1158
                    if (build.mNextVersion != null)
1159
                    {
1160
                        mReleaseManager.claimVersion(build.mPid, build.mNextVersion + build.mExtension, mBaseline);
1161
                        build.mVersion = build.mNextVersion;
1162
                    }
1163
                }
1164
 
1165
                //
1166
                //  Massage the package collection
1167
                //      Replace WIP/TEST/RIPPLE so that the mPackageCollection is a collection of packages we would like in the release
1168
                //      Don't replace those that we can't build due to errors
1169
                //  
6914 dpurdie 1170
 
7082 dpurdie 1171
                //         Update packages in the basicPlan
1172
                //         Update / Add packages to the fullPlan
1173
                //
1174
                ArrayList<Package> buildCandidates = new ArrayList<Package>();
1175
                buildCandidates.addAll(mPackageCollectionTest);
1176
                buildCandidates.addAll(mPackageCollectionWip);
1177
                buildCandidates.addAll(mPackageCollectionRipple);
1178
 
1179
                for (Iterator<Package> it = buildCandidates.iterator(); it.hasNext(); )
1180
                {
1181
                    Package p = it.next();
1182
                    if ( p.mBuildFile >= 0 )
1183
                    {
1184
                        Package pReleased = findPackage(p.mAlias);
1185
                        if ( pReleased != ReleaseManager.NULL_PACKAGE)
1186
                        {
1187
                            int index = mReleaseManager.findPackageLastIndex;
1188
                            mPackageCollection.set(index, p);
1189
                            p.mIsNotReleased = false;
1190
                        }
1191
                        else
1192
                        {
1193
                            mPackageCollection.add(p);
1194
                            p.mIsNotReleased = false;
1195
                        }
1196
                    }
1197
                }
1198
 
1199
                //
1200
                //  Report packages that are indirectly excluded
1201
                //  ie: They will not be built because one, or more, of there dependents is not buildable
1202
                //
1203
                mLogger.debug("planBuildOrder process packages which are not ripple buildable");
1204
 
1205
                 for (ListIterator<BuildExclusion> it = mBuildExclusionCollection.listIterator(); it.hasNext(); )
1206
                 {
1207
                     BuildExclusion be = it.next();
1208
 
1209
                     for (Iterator<Package> it1 = mPackageCollection.iterator(); it1.hasNext(); )
1210
                     {
1211
                         Package p = it1.next();
1212
 
1213
                         // ensure only root cause, non test build, build exclusions are excluded
1214
                         // mBuildExclusionCollection is at this point based on
1215
                         // relevant (direct and indirect) excluded pv's in the database
1216
 
1217
                         if ( be.compare(p.mId) && be.isARootCause() && p.mTestBuildInstruction == 0 && p.mForcedRippleInstruction == 0 )
1218
                         {
1219
                             // package is not reproducible, discard it and its consumers
1220
                             //
1221
                             mLogger.info("Excluded Package {}, {}", p.mAlias, be );                                     
1222
 
1223
                             ArrayList<Package> toExclude = new ArrayList<Package>();
1224
                             toExclude.addAll(usedByAnyPackages(p, mPackageCollection ));
1225
 
1226
                             //  Process packages that we need to exclude indirectly
1227
                             //
1228
                             while ( ! toExclude.isEmpty())
1229
                             {
1230
                                 Package pkg = toExclude.remove(0);
1231
 
1232
                                 // If this package has not been excluded (for whatever reason), than add it
1233
                                 boolean found = false;
1234
                                 for (Iterator<BuildExclusion> it2 = mBuildExclusionCollection.iterator(); it2.hasNext(); )
1235
                                 {
1236
                                     BuildExclusion buildExclusion = it2.next();
1237
                                     if (buildExclusion.compare(pkg.mId) )
1238
                                     {
1239
                                         found = true;
1240
                                         if  ( buildExclusion.isImported() )
1241
                                         {
1242
                                             // An exclusion for this package already exists
1243
                                             // If it was 'imported' from the database then 
1244
                                             // mark it as processed so that it will be persisted
1245
                                             //
1246
                                             // Otherwise it will be a new one
1247
                                             //
1248
                                             buildExclusion.setProcessed();
1249
                                         }
1250
                                         break;
1251
                                     }
1252
                                 }
1253
 
1254
                                 if (!found)
1255
                                 {
1256
                                     BuildExclusion buildExclusion = new BuildExclusion(pkg.mId, p.mId, null, p.mTestBuildInstruction);
1257
                                     it.add(buildExclusion);
1258
                                     mLogger.info("Indirectly Excluded Package {}", pkg.mAlias);  
1259
 
1260
                                     ArrayList<Package> usedBy = usedByAnyPackages(p, mPackageCollectionAll );
1261
                                     toExclude.addAll(usedBy);
1262
                                 }
1263
                             }
1264
                         }
1265
                     }
1266
                 }
1267
 
1268
                //
1269
                //  To fit in with the old algorithm ( ie: could be improved )
1270
                //  Insert marks into all packages
1271
                //  Not sure exactly why - Its used in the generation of the ant build file
1272
                //                     Want to set mNoBuildReason, mBuildFile
1273
                //
1274
                //      Package we have selected to build: 0     , 1
1275
                //      Package we could have built      : 0     , 2
1276
                //      Packages we can't build          : reason, 3
1277
                //      Packages that are OK             : 3     , 3
1278
                //      ????                             : 0     , 3
1279
 
1280
                for (Iterator<Package> it = mPackageCollectionAll.iterator(); it.hasNext(); )
1281
                {
1282
                    Package p = it.next();
1283
                    if (p == build ) {
1284
                        p.mNoBuildReason = 0;
1285
                        p.mBuildFile = 1;
1286
                    } 
1287
                    else if ( p.mBuildFile < 0 )
1288
                    {
1289
                        p.mNoBuildReason = p.mBuildFile;
1290
                        p.mBuildFile = 3;
1291
                    }
1292
                    else if (p.mBuildReason != null)
1293
                    {
1294
                        p.mNoBuildReason = 0;
1295
                        p.mBuildFile = 2;
1296
                    }
1297
                    else
1298
                    {
1299
                        p.mNoBuildReason = 0;
1300
                        p.mBuildFile = 3;
1301
                    }
1302
                }
1303
 
1304
            }
1305
            else
1306
            {
1307
                //  Escrow
1308
                //  The basic plan is the escrow build order
1309
                mBuildOrder = basicPlan.planCollection;
1310
            }
1311
 
1312
            mLogger.error("Final Plan");
1313
            for (Iterator<PlannedPackage> it = mBuildOrder.iterator(); it.hasNext(); )
1314
            {
1315
                PlannedPackage p = it.next();
1316
                mLogger.error("Plan: {} {} {}", p.mBuildLevel, p.mPkg.mAlias, p.mPkg.mId);
1317
            }
1318
 
1319
 
1320
        }
1321
 
1322
    /** Internal class to contain intermediate results
1323
     */
1324
    class PlanResults {
1325
        int planTime = 0;
1326
        ArrayList<PlannedPackage> planCollection = new ArrayList<PlannedPackage>(); 
1327
    }
1328
 
1329
    /**
1330
     * Process a collection of packages and generate a collection of package plans
1331
     * A package plan is a collection of packages that can be built
1332
     *      The first item in the list is a package that can be built right now
1333
     *      Other items in the list will be packages that can be built now or will need to be built as the result
1334
     *      of a ripple
1335
     *      
1336
     * The method will be called multiple times so that we can evaluate different plans
1337
     * The underling packages will have data and flags that will need to be rested before a calculation      
1338
     *
1339
     * @param name - Name of the plan
1340
     * @param packageCollection - Base collection of packages to plan
1341
     * @param mode - true: Include 'Ripples'
1342
     * 
1343
     * @return
1344
     */
1345
    private PlanResults planCollection(String name, ArrayList<Package> packageCollection, boolean mode)
1346
    {
1347
        ArrayList<PlannedPackage> ripplePlan = new ArrayList<PlannedPackage>();
1348
        PlanResults results = new PlanResults();
1349
 
1350
        //  Reset flags used in the calculations
1351
        Package.resetProcessed(packageCollection);
6914 dpurdie 1352
 
7082 dpurdie 1353
        //  Exclude all packages that cannot be built and all packages that depend on them
1354
        //      First find packages to be directly excluded
1355
        ArrayList<Package>exclude = new ArrayList<Package>();
1356
        for (Iterator<Package> it = packageCollection.iterator(); it.hasNext(); )
6914 dpurdie 1357
        {
7082 dpurdie 1358
            Package p = it.next();
1359
            if ( p.mBuildFile == -8 ) {
1360
 
1361
                //  Mark SDK or Pegged so that we don't build them, but can build their dependents
1362
                p.mProcessed = true;
1363
                p.mIsProcessed = true;
1364
                mLogger.error("SDK/Peg Exclude: {}", p);
1365
 
1366
            } else if (p.mBuildFile < 0 ) {
1367
                exclude.add(p);
1368
                mLogger.error("Direct Exclude: {}", p);
1369
 
1370
            }
6914 dpurdie 1371
        }
1372
 
7082 dpurdie 1373
        //  Exclude packages that have failed to be built
1374
        //      These are recorded in mBuildExclusionCollection
1375
        for (ListIterator<BuildExclusion> it = mBuildExclusionCollection.listIterator(); it.hasNext(); )
1376
        {
1377
            BuildExclusion be = it.next();
1378
            if ( be.isABuildError() )
1379
            {
1380
                for (Iterator<Package> it1 = packageCollection.iterator(); it1.hasNext(); )
1381
                {
1382
                    Package p = it1.next();
1383
                    if (p.mBuildFile >= 0 && p.mId == be.mId) {
1384
                        p.mBuildFile  = -3;
1385
                        exclude.add(p);
1386
                        break;
1387
                    }
1388
                }
1389
            }
1390
        }
1391
 
1392
 
1393
        //  Process the list of packages to be excluded
1394
        //  Add to the list packages that depend on the excluded package that have not already been excluded
1395
        while( !exclude.isEmpty() )
1396
        {
1397
            Package p = exclude.remove(0);
1398
            p.mProcessed = true;
1399
            p.mIsProcessed = true;
1400
            mLogger.error("planCollection package not buildable {}", p.mName);
1401
 
1402
            for (Iterator<Package> it1 = packageCollection.iterator(); it1.hasNext(); )
1403
            {
1404
                Package pkg = it1.next();
1405
                if (pkg.mProcessed) {
1406
                    continue;
1407
                }
1408
 
1409
                for (Iterator<String> it = pkg.mDependencyCollection.iterator(); it.hasNext(); )
1410
                {
1411
                    String alias = it.next();
1412
                    if ( p.mAlias.compareTo( alias ) == 0 ) {
1413
                        exclude.add(pkg);
1414
                    }
1415
                }
1416
            }
1417
        }
1418
 
1419
        //  Now have a collection of packages with those that we cannot build have been marked
1420
        //  Process the list and determine packages that we can build right now
1421
        //      ie: they have not been excluded, have not already been discovered and do not depend on any package in the collection
1422
        //      Continue to do this until all packages have been extracted
1423
        //      Allocate build levels as we go
1424
        //
6914 dpurdie 1425
        boolean allProcessed = false;
7082 dpurdie 1426
        int buildLevel = 1;
6914 dpurdie 1427
 
1428
        do
1429
        {
7082 dpurdie 1430
            //
1431
            //  Create the mBuildOrder collection
1432
            //      Same for both Daemon and Escrow modes
1433
            //      Will have package build order and build level
6914 dpurdie 1434
            boolean allDependenciesProcessed = true;
1435
            do
1436
            {
1437
                allDependenciesProcessed = true;
7082 dpurdie 1438
                for (Iterator<Package> it = packageCollection.iterator(); it.hasNext(); )
6914 dpurdie 1439
                {
1440
                    Package p = it.next();
7082 dpurdie 1441
 
1442
                    //  Skip packages that have been processed - have determined build order, or cannot build
1443
                    if (p.mIsProcessed) {
1444
                        continue;
1445
                    }
6914 dpurdie 1446
 
7082 dpurdie 1447
                    // Package yet to be processed and
1448
                    //      Daemon mode: Could be built
1449
                    //      Escrow mode: Can be reproduced
1450
                    boolean canBeBuiltNow = true;
1451
                    boolean allDependenciesForThisPackageProcessed = true;
1452
 
1453
                    //  Scan the packages dependencies
1454
                    for ( Iterator<Package> it2 = p.mPackageDependencyCollection.iterator(); it2.hasNext(); )
6914 dpurdie 1455
                    {
1456
                        // Daemon: Flag packages with no build requirement as processed
1457
                        // Escrow: Flag packages with a foreign build environment as processed
1458
                        p.mProcessed = true;
7044 dpurdie 1459
                        mLogger.info("planRelease package has no build requirement {}", p.mName);            
6914 dpurdie 1460
                    }
1461
                    else if ( ( p.mBuildFile == 0 ) && ( (mDaemon && ( p.mDirectlyPlanned || p.mIndirectlyPlanned ) ) || ( !mDaemon ) ) )
1462
                    {
1463
                        // package yet to be processed and
1464
                        //  Daemon mode: Has a build requirement
1465
                        //  Escrow mode: Can be reproduced
1466
                        boolean canBeBuiltNow = true;
1467
                        boolean allDependenciesForThisPackageProcessed = true;
1468
 
7082 dpurdie 1469
                        if ( !dependency.mProcessed )
6914 dpurdie 1470
                        {
1471
                            Package dependency = it2.next();
1472
 
1473
                            if ( !dependency.mProcessed )
1474
                            {
1475
                                //  If all the dependencies have been processed, then we can potentially build this package
1476
                                //  If any of them have not been processed, then cannot calculate canBeBuiltNow until this 
1477
                                //  dependency has been processed
1478
                                allDependenciesForThisPackageProcessed = false;
1479
                                allDependenciesProcessed = false;
1480
                            }
1481
                            else if (  (  mDaemon && ( dependency.mDirectlyPlanned ) || ( dependency.mIndirectlyPlanned ) ) 
1482
                                    || ( !mDaemon && ( ( dependency.mBuildFile == 0 ) ||
1483
                                                           ( dependency.mBuildFile == buildFile &&
1484
                                                           ( !p.haveSameBuildStandards(dependency)  ) ) ) ) )
1485
                            {
1486
                                // Daemon mode:
1487
                                //    This processed dependency has a build requirement - so can't build
1488
                                // Escrow mode: This package cannot be built now if
1489
                                //    This processed dependency has not been assigned to a build iteration or
1490
                                //    This processed dependency has been assigned to this build iteration, but the 
1491
                                //    build standards of the package and this dependency prevent the package being
1492
                                //    built in this iteration.   
1493
                                canBeBuiltNow = false;
7044 dpurdie 1494
                                mLogger.info("planRelease package cannot be built in this iteration {}", p.mName);
6914 dpurdie 1495
                                break;
1496
                            }
1497
                        }
7082 dpurdie 1498
                        else if (  (  mDaemon && (   dependency.mBuildFile == 0 ) ||  (dependency.mBuildFile == buildLevel)) 
1499
                                || ( !mDaemon && ( ( dependency.mBuildFile == 0 ) ||
1500
                                                       ( dependency.mBuildFile == buildLevel &&
1501
                                                       ( !p.haveSameBuildStandards(dependency)  ) ) ) ) )
1502
                        {
1503
                            // Can be built - yet
1504
                            // Daemon mode:
1505
                            //    This processed dependency has not been assigned to a build iteration
1506
                            //    This processed dependency has been assigned to this build iteration
1507
                            // Escrow mode: This package cannot be built now if
1508
                            //    This processed dependency has not been assigned to a build iteration or
1509
                            //    This processed dependency has been assigned to this build iteration, but the 
1510
                            //    build standards of the package and this dependency prevent the package being
1511
                            //    built in this iteration.   
1512
                            canBeBuiltNow = false;
1513
                            mLogger.info("planRelease package cannot be built in this iteration {}", p.mName);
1514
                            break;
1515
                        }
1516
                    }
6914 dpurdie 1517
 
7082 dpurdie 1518
                    //  All dependencies have been processed. May be able to build this package
1519
                    //      Add the package to the build order list
1520
                    //
1521
                    if (allDependenciesForThisPackageProcessed)
1522
                    {
1523
                        p.mProcessed = true;
1524
                        if ( canBeBuiltNow )
6914 dpurdie 1525
                        {
1526
                            p.mProcessed = true;
1527
 
1528
                            if ( mDaemon )
1529
                            {
1530
                                mBuildOrder.add(p);
1531
                                if ( canBeBuiltNow )
1532
                                {
1533
                                    // flag package with build requirement, may get down graded to future build requirement
1534
                                    p.mBuildFile = 1;
7044 dpurdie 1535
                                    mLogger.info("planRelease set mBuildFile to 1 for package {}", p.mAlias );
6914 dpurdie 1536
                                }
1537
                                else
1538
                                {
1539
                                    // flag package with future build requirement
1540
                                    p.mBuildFile = 2;
7044 dpurdie 1541
                                    mLogger.info("planRelease set mBuildFile to 2 for package {}", p.mAlias );
6914 dpurdie 1542
                                }
1543
                            }
1544
                            else
1545
                            {
1546
                                // Escrow Mode
1547
                                if ( canBeBuiltNow )
1548
                                {
1549
                                    mBuildOrder.add(p);
1550
                                    p.mBuildFile = buildFile;
7044 dpurdie 1551
                                    mLogger.info("planRelease set mBuildFile to {} for package {}",buildFile, p.mAlias );
6914 dpurdie 1552
                                }
1553
                            }
1554
                        }
1555
                    }
1556
                }
1557
            } while( !allDependenciesProcessed );
7082 dpurdie 1558
 
1559
            //  Have process all the packages that we can at the moment
1560
            //      Examine all the packages in the collection to see if there are more that need to be extracted
1561
            //      These will be done at a different build-level
1562
            //  
1563
            allProcessed = true;
1564
            for (Iterator<Package> it = packageCollection.iterator(); it.hasNext(); )
1565
            {
1566
                Package p = it.next();
1567
                if ( !  p.mIsProcessed )
1568
                {
1569
                    // more build files are required
1570
                    allProcessed = false;
1571
                    mLogger.info("planRelease more build files are required for {}", p.mName);
1572
                    break;
1573
                }
1574
            }
6914 dpurdie 1575
 
7082 dpurdie 1576
            buildLevel++;
1577
            if (buildLevel % 500 == 0 ) {
1578
                mLogger.error("planRelease. Too many build levels {}", buildLevel);
1579
            }
1580
        } while( !allProcessed );
1581
 
1582
        //  Now we have a collection packages that we can build right now
1583
        //      The packages currently have a build level set into mBuildFile
1584
        //
1585
        if (mDaemon)
1586
        {
1587
            //  Determine if we have a reason to build anything in this collection of buildable packages
1588
            //  Reset the calculated buildLevel - It will be calculated again
6914 dpurdie 1589
            //
7082 dpurdie 1590
            ArrayList<PlannedPackage> toBuild = new ArrayList<PlannedPackage>();
1591
            for (Iterator<PlannedPackage> it = results.planCollection.iterator(); it.hasNext(); )
6914 dpurdie 1592
            {
7082 dpurdie 1593
                PlannedPackage p = it.next();
1594
                p.mBuildLevel = 0;
1595
 
1596
                if (p.mPkg.mBuildReason != null) {
1597
                    if (mode || ( !mode && p.mPkg.mBuildReason != BuildReason.Ripple ))
6914 dpurdie 1598
                    {
1599
                        p.mBuildFile = buildFile;
7044 dpurdie 1600
                        mLogger.info("planRelease 2 set mBuildFile to {} for package {}", buildFile, p.mAlias );
6914 dpurdie 1601
 
1602
                        if ( buildFile == 1 )
1603
                        {
1604
                            int pvApplied = p.applyPV(mReleaseManager, mBaseline);
1605
 
1606
                            if ( pvApplied == 1 )
1607
                            {
1608
                                // max 50 chars
1609
                                rippleBuildExclude(p, p.mId, "Package has non standard versioning", null, null, true);
1610
                            }
1611
                            else if ( pvApplied == 2 )
1612
                            {
1613
                                // max 50 chars
1614
                                rippleBuildExclude(p, p.mId, "Package has reached ripple field limitations", null, null, true);
1615
                            }
1616
                            else if ( pvApplied == 3 )
1617
                            {
1618
                                // max 50 chars
1619
                                rippleBuildExclude(p, p.mId, "Package has invalid change type", null, null, true);
1620
                            }
1621
                            else
1622
                            {
1623
                                //    Have found a package to build
1624
                                //        Prevent finding others
1625
                                buildFile = 2;
1626
 
1627
                                if ( p.mForcedRippleInstruction > 0 )
1628
                                {
1629
                                    mReleaseManager.markDaemonInstCompleted( p.mForcedRippleInstruction );
1630
                                }
1631
 
1632
                                if ( p.mTestBuildInstruction > 0 )
1633
                                {
1634
                                    mReleaseManager.markDaemonInstInProgress( p.mTestBuildInstruction );
1635
                                }
1636
                            }
1637
                        }
1638
                        else
1639
                        {
7044 dpurdie 1640
                            mLogger.info("planRelease package has future (downgraded) build requirement {} {}", p.mName, buildFile);              
6914 dpurdie 1641
                        }
1642
                    }
1643
                }
1644
            }
7082 dpurdie 1645
 
1646
            //  Need (would like to) build stuff
1647
            //  Determine the packages that we need to build and the time that it will take
1648
            //
1649
            if ( !toBuild.isEmpty() )
6914 dpurdie 1650
            {
7082 dpurdie 1651
                results.planTime = 0;
1652
 
1653
 
1654
                //  Need to add elements to the end of the list while processing
1655
                //  Sum the buildTimes of the packages that we add to the list
1656
                while ( ! toBuild.isEmpty())
6914 dpurdie 1657
                {
7082 dpurdie 1658
                    PlannedPackage pkg = toBuild.remove(0);
1659
 
1660
                    if (pkg.mBuildLevel > 100 ) {
1661
                        mLogger.error("Circular dependency detected - not handled well");
1662
                        break;
1663
                    }
1664
 
1665
                    if ( ! ripplePlan.contains( pkg ))
6914 dpurdie 1666
                    {
7082 dpurdie 1667
                        ripplePlan.add(pkg);
1668
                        results.planTime += pkg.mPkg.mBuildTime;
6914 dpurdie 1669
                    }
7082 dpurdie 1670
 
1671
                    ArrayList<PlannedPackage> usedBy = usedByPackages(pkg, results.planCollection, pkg.mBuildLevel + 1);
1672
                    toBuild.addAll(usedBy);
6914 dpurdie 1673
                }
7082 dpurdie 1674
 
1675
                //  Sort the packages by buildOrder and buildTime
1676
                Collections.sort(ripplePlan, PlannedPackage.BuildOrderComparitor);
1677
 
1678
                mLogger.info("Plan Build {} Time: {}", name, results.planTime);
1679
                for (Iterator<PlannedPackage> it = ripplePlan.iterator(); it.hasNext(); )
1680
                {
1681
                    PlannedPackage p = it.next();
1682
                    mLogger.info("Plan: {} {}", p.mBuildLevel, p.mPkg.mAlias);
1683
                }
1684
            }
1685
 
1686
            //  Daemon mode: Returning calculated plan
1687
            results.planCollection = ripplePlan;
1688
        }
1689
 
1690
        return results;
1691
    }
6914 dpurdie 1692
 
7082 dpurdie 1693
    /** Generate a plan based on a modified set of packages
1694
     * 
1695
     * @param name      - Name of the plan
1696
     * @param basicPlan - basicPlan
1697
     * @param mode      - True: Include natural ripples and WIPS/RIPPLES that would have been done
1698
     *                          as a part of the basic plan
1699
     * @return
1700
     */
1701
    private PlanResults postRipplePlan(String name, PlanResults basicPlan, boolean mode) {
6914 dpurdie 1702
 
7082 dpurdie 1703
        ArrayList<Package> fullPlanCollection = new ArrayList<Package>(mPackageCollection);
1704
        ArrayList<Package> buildCandidates = new ArrayList<Package>();
1705
        buildCandidates.addAll(mPackageCollectionWip);
1706
        buildCandidates.addAll(mPackageCollectionRipple);
1707
 
1708
        if ( !buildCandidates.isEmpty() )
1709
        {
1710
            for (Iterator<Package> it = buildCandidates.iterator(); it.hasNext(); )
1711
            {
1712
                Package p = it.next();
1713
                if (p.mBuildFile >= 0)
6914 dpurdie 1714
                {
7082 dpurdie 1715
                    if (!mode)
6914 dpurdie 1716
                    {
1717
                        // at this point...
1718
                        // only 1 package with a build requirement has a mBuildFile of 1,
1719
                        // all other packages with a build requirement have an mBuildFile of 2
1720
                        // give packages with no build requirement, reproducible or not, an mBuildFile of 3
1721
                        p.mNoBuildReason = p.mBuildFile;
1722
                        p.mBuildFile = 3;
7044 dpurdie 1723
                        mLogger.info("planRelease 1 set mBuildFile to 3 for package {}", p.mAlias );
6914 dpurdie 1724
                    }
7082 dpurdie 1725
 
1726
                    mLogger.info("Test Plan with {}", p.mAlias);
1727
                    Package foundInRelease = mReleaseManager.findPackage(p.mAlias, fullPlanCollection);
1728
                    int foundIndex = mReleaseManager.findPackageLastIndex;
1729
                    if (foundInRelease == ReleaseManager.NULL_PACKAGE)
1730
                    {
1731
                        fullPlanCollection.add(p);
1732
                    }
1733
                    else
1734
                    {
1735
                        fullPlanCollection.set(foundIndex, p);
1736
                    }
1737
 
1738
                    Package.resetCircularDependency (fullPlanCollection);
1739
                    if ( p.hasCircularDependency( fullPlanCollection ) )
1740
                    {
1741
                        mLogger.info("planRelease circular dependency detected {}", p.mAlias);
1742
 
1743
                        //  Force this package to be marked as having a circular dependency - even if its been excluded
1744
                        p.mBuildFile = 0;
1745
 
1746
                        // Exclude the package
1747
                        // max 50 chars
1748
                        rippleBuildExclude(p, p.mId, "Package has circular dependency", -6);
1749
                    }
6914 dpurdie 1750
                }
1751
            }
7082 dpurdie 1752
 
1753
        }
1754
        return planCollection(name, fullPlanCollection, mode);
1755
    }
1756
 
1757
    /** 
1758
     *  Calculate a collection of packages that actively use the named package
1759
     *  A consumer package does NOT use the named package,
1760
     *      If the consumer is an SDK or is Pegged
1761
     *      If the consumer is marked as advisoryRipple
1762
     *      If the consumer cannot be built
1763
     *   
1764
     * @param pkg - Package to process
1765
     * @param planCollection - collection of packages to scan
1766
     * @param rippleOrder - Set the ripple oder, if >= 0
1767
     *
1768
     * @return A collection of packages that actively 'use' the specified package
1769
 
1770
     */
1771
    private ArrayList<PlannedPackage> usedByPackages(PlannedPackage pkg, ArrayList<PlannedPackage> planCollection, int rippleOrder) {
1772
 
1773
        ArrayList<PlannedPackage> usedBy = new ArrayList<PlannedPackage>();
1774
 
1775
        for (Iterator<PlannedPackage> it = planCollection.iterator(); it.hasNext(); )
1776
        {
1777
            PlannedPackage p = it.next();
1778
 
1779
            //  Is this package 'actively used' in the current build
1780
            if (p.mPkg.mBuildFile >= 0)
6914 dpurdie 1781
            {
7082 dpurdie 1782
                for (Iterator<String> it2 = p.mPkg.mDependencyCollection.iterator(); it2.hasNext(); )
6914 dpurdie 1783
                {
1784
                    Package p = it.next();
1785
 
1786
                    if ( p.mBuildFile == 0 )
1787
                    {
1788
                        // more build files are required
1789
                        allProcessed = false;
7044 dpurdie 1790
                        mLogger.info("planRelease more build files are required for {}", p.mName);
6914 dpurdie 1791
                        break;
1792
                    }
1793
                }
7082 dpurdie 1794
            }
1795
        }
1796
 
1797
        return usedBy;
1798
    }
1799
 
1800
    /** 
1801
     *  Calculate a collection of packages that use the named package
1802
     *   
1803
     * @param pkg - Package to process
1804
     * @param pkgCollection - collection of packages to scan
1805
     *
1806
     * @return A collection of packages that actively 'use' the specified package
6914 dpurdie 1807
 
7082 dpurdie 1808
     */
1809
    private ArrayList<Package> usedByAnyPackages(Package pkg, ArrayList<Package> pkgCollection) {
1810
 
1811
        ArrayList<Package> usedBy = new ArrayList<Package>();
1812
 
1813
        for (Iterator<Package> it = pkgCollection.iterator(); it.hasNext(); )
1814
        {
1815
            Package p = it.next();
1816
 
1817
            for (Iterator<String> it2 = p.mDependencyCollection.iterator(); it2.hasNext(); )
1818
            {
1819
                String alias = it2.next();
1820
                if (  pkg.mAlias.compareTo( alias ) == 0  ) {
1821
                    usedBy.add(p);
1822
                    break;
1823
                }
6914 dpurdie 1824
            }
7082 dpurdie 1825
        }
1826
 
1827
        return usedBy;
6914 dpurdie 1828
    }
1829
 
1830
    /** Determine if a given PVID is a member of the current release.
1831
     *  Used to determine if a package dependency is out of date
1832
     * 
1833
     * @param dpvId
1834
     * @return true - specified pvid is a full member of the Release
1835
     */
1836
    private boolean isInRelease(Integer dpvId) {
1837
 
7082 dpurdie 1838
        boolean inRelease = false;
6914 dpurdie 1839
 
7082 dpurdie 1840
        for ( Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
6914 dpurdie 1841
        {
7082 dpurdie 1842
            Package p = it.next();
6914 dpurdie 1843
 
7082 dpurdie 1844
            if ( p.mId == dpvId )
6914 dpurdie 1845
            {
7082 dpurdie 1846
                inRelease = ! p.mIsNotReleased;
6914 dpurdie 1847
                break;
1848
            }
1849
        }
7082 dpurdie 1850
        return inRelease;
6914 dpurdie 1851
    }
1852
 
1853
 
7082 dpurdie 1854
    /** Reports what change in build exceptions happens as part of planRelease
1855
     * 
1856
     *  There are three types of exceptions
1857
     *      PlanError - These may be removed, if the error was not seen in the last plan
1858
     *      BuildErrors - These we persist
1859
     *      IndirectErrors - Packages that depend on a Plan or Build errors
6914 dpurdie 1860
     */
1861
    public void reportChange() throws SQLException, Exception
1862
    {
1863
        int counter = 0;
1864
        for (Iterator<BuildExclusion> it = mBuildExclusionCollection.iterator(); it.hasNext(); )
1865
        {
1866
            BuildExclusion buildExclusion = it.next();
1867
 
7082 dpurdie 1868
            //  Skip 'Processed' entries
1869
            //  These will be the result of a PlanError that we have seen again
1870
            //
1871
            //  PlanErrors - Add/Remove as detected
1872
            //  BuildErrors - Persist. 
1873
            //  IndirectErrors - Add/Remove as detected
1874
            //  
1875
 
1876
            if ( !buildExclusion.isABuildError() )
6914 dpurdie 1877
            {
7032 dpurdie 1878
                if (buildExclusion.isImported() && ! buildExclusion.isARootCause() ) {
1879
                    // Remove from the exclusion list
1880
                    buildExclusion.includeToBuild(mReleaseManager, mBaseline);
7044 dpurdie 1881
                    mLogger.error("reportChange remove unused exclusion: {}", buildExclusion.info());
7032 dpurdie 1882
                } else {
1883
                    // Exclude and notify
1884
                    buildExclusion.excludeFromBuild(mReleaseManager, mBaseline);
1885
                    buildExclusion.email(this, mPackageCollection);
1886
                    counter++;
1887
                }
6914 dpurdie 1888
            }
1889
        }
7044 dpurdie 1890
        mLogger.error("reportChange exclusion count: {}", counter);
6914 dpurdie 1891
    }
1892
 
1893
    /**reports the build plan
1894
     */
1895
    public void reportPlan() throws SQLException, Exception
1896
    {
1897
        mReleaseManager.reportPlan(mRtagId, mBuildOrder);
1898
    }
1899
 
1900
    /**Returns the first build file from the collection
1901
     * The build file will be flagged as empty if none exists
1902
     */
1903
    public BuildFile getFirstBuildFileContent()
1904
    {
1905
        mLogger.debug("getFirstBuildFileContent");
1906
 
1907
        mBuildIndex = -1;
1908
        return getNextBuildFileContent();
1909
    }
1910
 
1911
    /**Returns next build file from the collection
1912
     * The build file will be flagged as empty if none exists
1913
     */
1914
    public BuildFile getNextBuildFileContent()
1915
    {
1916
        mLogger.debug("getNextBuildFileContent");
1917
        BuildFile retVal = null;
1918
 
1919
        try
1920
        {
1921
            mBuildIndex++;
1922
            retVal = mBuildCollection.get( mBuildIndex );
1923
        }
1924
        catch( IndexOutOfBoundsException e )
1925
        {
1926
            // Ignore exception. retVal is still null.
1927
        }
1928
 
1929
        if (retVal == null)
1930
        {
1931
            retVal = new BuildFile();
1932
        }
1933
 
7044 dpurdie 1934
        mLogger.debug("getNextBuildFileContent returned {}", retVal.state.name() );
6914 dpurdie 1935
        return retVal;
1936
    }
1937
 
1938
 
1939
    /**collects meta data associated with the baseline
1940
     * this is sufficient to send an indefinite pause email notification 
1941
     *  
1942
     * Escrow: Used once to collect information about the SBOM and associated Release 
1943
     *         mBaseline is an SBOMID 
1944
     * Daemon: Used each build cycle to refresh the information 
1945
     *          mBaseline is an RTAGID
1946
     */
1947
    public void collectMetaData() throws SQLException, Exception
1948
    {
1949
        Phase phase = new Phase("cmd");
7044 dpurdie 1950
        mLogger.debug("collectMetaData mDaemon {}", mDaemon);
6914 dpurdie 1951
 
1952
        try
1953
        {
1954
            phase.setPhase("connect");
1955
            mReleaseManager.connect();
1956
 
1957
            if (! mDaemon)
1958
            {
1959
                mSbomId = mBaseline;
1960
                phase.setPhase("queryRtagIdForSbom");
1961
                mRtagId = mReleaseManager.queryRtagIdForSbom(mBaseline);
1962
                if (mRtagId == 0)
1963
                {
7033 dpurdie 1964
                    mLogger.error("SBOM does not have a matching Release. Cannot be used as a base for an Escrow"); 
6914 dpurdie 1965
                    throw new Exception("rtagIdForSbom show stopper. SBOM does not have an associated Release");
1966
                }
1967
            }
1968
 
1969
            phase.setPhase("queryReleaseConfig");
1970
            mReleaseManager.queryReleaseConfig(mRtagId);
1971
 
1972
            if (mDaemon)
1973
            {
1974
                phase.setPhase("queryMailServer");
1975
                setMailServer(mReleaseManager.queryMailServer());
1976
                phase.setPhase("queryMailSender");
1977
                setMailSender(mReleaseManager.queryMailSender());
1978
                phase.setPhase("queryGlobalAddresses");
1979
                setMailGlobalTarget(mReleaseManager.queryGlobalAddresses());
1980
                phase.setPhase("queryProjectEmail");
1981
                mMailGlobalCollection = mReleaseManager.queryProjectEmail(mBaseline);
1982
                phase.setPhase("mMailGlobalTarget");
1983
                mMailGlobalCollection.add(0,getMailGlobalTarget());
1984
            }
1985
            phase.setPhase("queryBaselineName");
1986
            mBaselineName = mReleaseManager.queryBaselineName(mBaseline);
1987
            phase.setPhase("Done");
1988
        }
1989
        finally
1990
        {
1991
            // this block is executed regardless of what happens in the try block
1992
            // even if an exception is thrown
1993
            // ensure disconnect
1994
            mReleaseManager.disconnect();
1995
        }
1996
    }
1997
 
1998
    /**
1999
     * Find Package by package alias
7082 dpurdie 2000
     * Searches the released package collection
6914 dpurdie 2001
     * @param   alias               - alias of package to locate
2002
     * @return  Package with the matching mAlias or NULL_PACKAGE if no package has the mAlias
2003
     */
2004
    public Package findPackage(String alias)
2005
    {
2006
        mLogger.debug("findPackage");
2007
 
2008
        Package retVal = mReleaseManager.findPackage(alias, mPackageCollection);
2009
 
7044 dpurdie 2010
        mLogger.info("findPackage returned {}", retVal.mName);
6914 dpurdie 2011
        return retVal;
2012
    }
7082 dpurdie 2013
 
6914 dpurdie 2014
    /**
7082 dpurdie 2015
     * Sets the mBuildFile to the specified value for the package
2016
     * Does not handle dependent packages - this will be done later  
2017
     *  
7032 dpurdie 2018
     * @param p             The package being excluded 
2019
     * @param rootPvId      The PVID of the package that is causing the exclusion. Null or -ve values are special
2020
     *                      This package is the root cause, -2: Excluded by Ripple Stop 
2021
     * @param rootCause     Text message. Max 50 characters imposed by RM database 
7082 dpurdie 2022
     * @param reason        New value for mBuildFile
6914 dpurdie 2023
     */
7082 dpurdie 2024
    private void rippleBuildExclude(Package p, int rootPvId, String rootCause, int reason )
6914 dpurdie 2025
    {
2026
        mLogger.debug("rippleBuildExclude");
7082 dpurdie 2027
 
6914 dpurdie 2028
        if ( p.mBuildFile == 0 || p.mBuildFile == 1 )
2029
        {
2030
            p.mBuildFile = -5;
7044 dpurdie 2031
            mLogger.info("rippleBuildExclude set mBuildFile to -5 for package {}", p.mAlias );
6914 dpurdie 2032
 
7082 dpurdie 2033
                if ( buildExclusion.compare(p.mId, rootPvId, rootCause))
2034
                {
2035
                    buildExclusion.setProcessed();
2036
                    found = true;
2037
                    break;
2038
                }
6914 dpurdie 2039
            }
7082 dpurdie 2040
 
2041
            if (!found)
6914 dpurdie 2042
            {
7082 dpurdie 2043
                // Entry not found in the mBuildExclusionCollection. Its a new error
2044
                // 
2045
                // Mark all occurrences for this package as processed
2046
                // These will be superseded by a new build exclusion entry
6914 dpurdie 2047
                for (Iterator<BuildExclusion> it = mBuildExclusionCollection.iterator(); it.hasNext(); )
2048
                {
2049
                    BuildExclusion buildExclusion = it.next();
2050
 
7082 dpurdie 2051
                    if ( buildExclusion.compare(p.mId))
6914 dpurdie 2052
                    {
7032 dpurdie 2053
                        buildExclusion.setProcessed();
6914 dpurdie 2054
                    }
2055
                }
2056
 
7082 dpurdie 2057
                //  Add the new build exclusion to a list
2058
                BuildExclusion buildExclusion = new BuildExclusion(p.mId, rootPvId, rootCause, p.mTestBuildInstruction);
2059
                mBuildExclusionCollection.add(buildExclusion);
6914 dpurdie 2060
            }
7082 dpurdie 2061
        }
6914 dpurdie 2062
 
2063
            //  Locate ALL packages that depend on this package and exclude them too
2064
            //  This process will be recursive
2065
            //    Not sure that this it is efficient 
2066
            //  Only ripple a build exclusion through for non test builds
2067
            //
2068
            if ( p.mTestBuildInstruction == 0 && dependentToo)
2069
            {
2070
                for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
2071
                {
2072
                    Package pkg = it.next();
2073
 
2074
                    if ( pkg != p )
2075
                    {
2076
                        for (Iterator<Package> it2 = pkg.mPackageDependencyCollection.iterator(); it2.hasNext(); )
2077
                        {
2078
                            Package dependency = it2.next();
2079
 
2080
                            if ( dependency == p )
2081
                            {
2082
                                rippleBuildExclude( pkg, rootPvId, null, list, null, dependentToo );
2083
                                break;
2084
                            }
2085
                        }
2086
                    }
2087
                }
2088
            }
2089
        }
7044 dpurdie 2090
        mLogger.info("rippleBuildExclude set {} {}", p.mName, p.mBuildFile);
6914 dpurdie 2091
    }
2092
 
2093
    /**Simple XML string escaping
2094
     * 
2095
     * @param xml		- String to escape
2096
     * @return		- A copy of the string with XML-unfriendly characters escaped 
2097
     */
2098
    public static String escapeXml( String xml )
2099
    {
2100
        xml = xml.replaceAll("&", "&amp;");
2101
        xml = xml.replaceAll("<", "&lt;");
2102
        xml = xml.replaceAll(">", "&gt;");
2103
        xml = xml.replaceAll("\"","&quot;");
2104
        xml = xml.replaceAll("'", "&apos;");
2105
        xml = xml.replaceAll("\\$", "\\$\\$");
2106
 
2107
        return xml;
2108
    }
2109
 
2110
    /** Quote a string or a string pair
2111
     *  If two strings are provided, then they will be joined with a comma.
2112
     *   
2113
     * @param text		- First string to quote
2114
     * @param text2		- Optional, second string
2115
     * @return A string of the form 'text','text2'
2116
     */
2117
    public static String quoteString(String text, String text2)
2118
    {
2119
        String result;
2120
        result =  "\'" + text + "\'";
2121
        if (text2 != null )
2122
        {
2123
            result +=  ",\'" + text2 + "\'";  
2124
        }
2125
        return result;
2126
    }
2127
 
2128
    /** Generate build file information
2129
     * 
2130
     */
2131
    private void generateBuildFiles() 
2132
    {
2133
 
2134
        // persist the build files
2135
        boolean allProcessed = false;
2136
        int buildFile = 1;
2137
        StringBuilder rawData = new StringBuilder();
2138
        StringBuilder setUp = new StringBuilder();
2139
 
2140
        mLogger.debug("generateBuildFiles");
2141
 
2142
        if ( mDaemon )
2143
        {
2144
            // all interesting packages in daemon mode match the following filter
2145
            buildFile = 3;
2146
        }
2147
 
2148
        //-----------------------------------------------------------------------
2149
        //    Generate the build file
2150
        do
2151
        {
2152
            BuildFile buildEntry = new  BuildFile();
2153
            buildEntry.state = BuildFileState.Dummy;
2154
            XmlBuilder xml = generateBuildFileHeader();
2155
 
2156
 
2157
            //	Generate properties for each package in this build level or lower build levels
2158
            //	The properties link the packageAlias to the PackageName and PackageVersion
2159
            //
2160
            //	[DEVI 54816] In escrow mode all unreproducible packages are included 
2161
            for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
2162
            {
2163
                Package p = it.next();
2164
 
2165
                if ( ( ( p.mBuildFile > 0 ) && ( p.mBuildFile <= buildFile ) ) || ( !mDaemon && p.mBuildFile == -2 ) )
2166
                {
2167
                    xml.addProperty(p.mAlias, p.mName + " " + p.mVersion + p.mExtension);
2168
                }
2169
            }
2170
 
2171
            //	UTF Support
2172
            //	Insert additional info into the build file to provide extra checking
2173
            //
7046 dpurdie 2174
            if ( ! mReleaseManager.mUseDatabase )
6914 dpurdie 2175
            {
2176
                // UTF Support
2177
                // Insert per-package planning information
2178
                //
2179
                xml.addComment("mPackageCollection");
2180
                for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
2181
                {
2182
                    Package p = it.next();
2183
                    generatePackageInfo(xml, p);
2184
                }
2185
 
7082 dpurdie 2186
                xml.addComment("mPackageCollectionWip");
2187
                for (Iterator<Package> it = mPackageCollectionWip.iterator(); it.hasNext(); )
2188
                {
2189
                    Package p = it.next();
2190
                    if (p.mIsNotReleased )
2191
                        generatePackageInfo(xml, p);
2192
                }
2193
 
2194
                xml.addComment("mPackageCollectionTest");
2195
                for (Iterator<Package> it = mPackageCollectionTest.iterator(); it.hasNext(); )
2196
                {
2197
                    Package p = it.next();
2198
                    if (p.mIsNotReleased )
2199
                        generatePackageInfo(xml, p);
2200
                }
2201
 
2202
                xml.addComment("mPackageCollectionTestRipple");
2203
                for (Iterator<Package> it = mPackageCollectionRipple.iterator(); it.hasNext(); )
2204
                {
2205
                    Package p = it.next();
2206
                    if (p.mIsNotReleased )
2207
                        generatePackageInfo(xml, p);
2208
                }
2209
 
6914 dpurdie 2210
                // UTF Support
2211
                // Insert build exclusion information
2212
                xml.addComment("mBuildExclusionCollection");
2213
                for (Iterator<BuildExclusion> it = mBuildExclusionCollection.iterator(); it.hasNext(); )
2214
                {
2215
                    BuildExclusion buildExclusion = it.next();
2216
                    {
7082 dpurdie 2217
                        xml.addComment(buildExclusion.toString());
6914 dpurdie 2218
                    }
2219
                }
7082 dpurdie 2220
            }
2221
 
2222
            // UTF Support (Also while trailing the changes)
2223
            // Insert build Plan
2224
            if (mDaemon)
2225
            {
2226
                xml.addComment("mBuildOrder");
2227
                for (Iterator<PlannedPackage> it = mBuildOrder.iterator(); it.hasNext(); )
6914 dpurdie 2228
                {
7082 dpurdie 2229
                    PlannedPackage p = it.next();
2230
                    String comment =
2231
                            "pvid="+ p.mPkg.mId +
2232
                            " order=" + p.mBuildLevel +
2233
                            " time=" + p.mPkg.mBuildTime +
2234
                            " name=\"" + p.mPkg.mAlias + "\"";
2235
                    xml.addComment(comment);
6914 dpurdie 2236
                }
2237
            }
2238
 
2239
            //  Generate Taskdef information
2240
            generateTaskdef(xml);
2241
 
2242
            //
2243
            //  Insert known Machine Information
2244
            //  Escrow usage: 
2245
            //      Map machType to machClass
2246
            //  Also serves as a snapshot of the required build configuration
2247
            //  ie: machine types and buildfilters
2248
            //
2249
            if (!mDaemon)
2250
            {
2251
                generateMachineInfo(xml, null);
2252
            }
2253
 
2254
            //
2255
            //	Generate target rules for each package to be built within the current build file
2256
            //
2257
            boolean daemonHasTarget = false;
2258
 
7082 dpurdie 2259
            for (Iterator<Package> it = mPackageCollectionAll.iterator(); it.hasNext(); )
6914 dpurdie 2260
            {
2261
                Package p = it.next();
2262
 
2263
                if ( p.mBuildFile > 0 && p.mBuildFile <= buildFile )
2264
                {
2265
                    generateTarget(xml, buildEntry, p, buildFile);
2266
 
2267
                    if ( p.mBuildFile == 1 )
2268
                    {
2269
                        daemonHasTarget = true;
2270
 
2271
                        // Retain information about the target package
2272
                        buildEntry.mPkgId = p.mPid;
2273
                        buildEntry.mPvId = p.mId;
2274
                    }
2275
                }
2276
 
2277
                //	Generate escrow extraction commands
2278
                //	Only done on the first pass though the packages
2279
                //
2280
                if ( !mDaemon && buildFile == 1 )
2281
                {
2282
                    setUp.append("jats jats_vcsrelease -extractfiles"
2283
                                + " \"-label=" + p.mVcsTag + "\""
2284
                                + " \"-view=" + p.mAlias + "\""
2285
                                + " -root=. -noprefix"
2286
                                + mlf );
2287
                }
2288
 
2289
                //	Generate escrow raw CSV data
2290
                //	Note: I don't think this data is used at all
2291
 
2292
                if ( !mDaemon && ( p.mBuildFile == buildFile))
2293
                {
2294
                    StringAppender machines = new StringAppender(",");
2295
                    for (Iterator<BuildStandard> it1 = p.mBuildStandardCollection.iterator(); it1.hasNext();)
2296
                    {
2297
                        BuildStandard bs = it1.next();
2298
                        machines.append(bs.mMachClass);
2299
                    }
2300
 
2301
                    rawData.append(p.mAlias + "," +
2302
                                    buildFile + "," +
2303
                                    machines +
2304
                                    mlf);
2305
                }
2306
            }
2307
 
2308
            if ( mDaemon && !daemonHasTarget )
2309
            {
2310
                // must have AbtTestPath, AbtSetUp, AbtTearDown, and AbtPublish targets
2311
                XmlBuilder target = xml.addNewElement("target");
2312
                target.addAttribute("name", "AbtTestPath");
2313
 
2314
                target = xml.addNewElement("target");
2315
                target.addAttribute("name", "AbtSetUp");
2316
 
2317
                target = xml.addNewElement("target");
2318
                target.addAttribute("name", "AbtTearDown");
2319
 
2320
                target = xml.addNewElement("target");
2321
                target.addAttribute("name", "AbtPublish");
2322
            }
2323
 
2324
            generateDefaultTarget( xml, buildFile);
2325
 
2326
            //	Convert the Xml structure into text and save it in the build file
2327
            //	Add this build file to the mBuildCollection
2328
            buildEntry.content = mXmlHeader + xml.toString();
2329
            mBuildCollection.add(buildEntry);
2330
 
2331
            // are more build files required
2332
            allProcessed = true;
2333
 
2334
            if (!mDaemon)
2335
            {
2336
                // this is escrow mode centric
7082 dpurdie 2337
                for (Iterator<Package> it = mPackageCollectionAll.iterator(); it.hasNext(); )
6914 dpurdie 2338
                {
2339
                    Package p = it.next();
2340
 
2341
                    if ( p.mBuildFile > buildFile )
2342
                    {
2343
                        // more build files are required
2344
                        allProcessed = false;
7044 dpurdie 2345
                        mLogger.info("planRelease reiterating package has no build requirement {} {} {}",p.mName, p.mBuildFile,  buildFile);
6914 dpurdie 2346
                        break;
2347
                    }
2348
                } 
2349
 
2350
                buildFile++;
2351
            }
2352
 
2353
        } while( !allProcessed );
2354
 
2355
        //	Save additional escrow data
2356
        if ( !mDaemon )
2357
        {
2358
            mEscrowSetup = setUp.toString();
2359
            mEscrowRawData = rawData.toString();
2360
        }
2361
    }
2362
 
2363
    /**returns a build file header for the mBaseline
2364
     */
2365
    private XmlBuilder generateBuildFileHeader()
2366
    {
2367
        mLogger.debug("generateBuildFileHeader");
2368
        XmlBuilder element = new XmlBuilder("project");
2369
 
2370
        element.addAttribute("name", "mass");
2371
        element.addAttribute("default", "full");
2372
        element.addAttribute("basedir", ".");
2373
 
2374
        if ( mDaemon )
2375
        {
2376
            element.addProperty("abt_mail_server", getMailServer());
2377
            element.addProperty("abt_mail_sender", getMailSender()); 
2378
            element.addProperty("abt_rtag_id", mBaseline);
2379
            element.addProperty("abt_daemon", mReleaseManager.currentTimeMillis());
2380
            element.makePropertyTag("abt_packagetarball", true);
2381
            element.makePropertyTag("abt_usetestarchive", !ReleaseManager.getUseMutex());
2382
 
7082 dpurdie 2383
            for (Iterator<Package> it = mPackageCollectionAll.iterator(); it.hasNext(); )
6914 dpurdie 2384
            {
2385
                Package p = it.next();
2386
 
2387
                if ( p.mBuildFile == 1 )
2388
                {
2389
                    element.addProperty("abt_package_name", p.mName);
2390
                    element.addProperty("abt_package_version", p.mVersion + p.mExtension);
2391
                    element.addProperty("abt_package_extension", p.mExtension);
2392
                    element.addProperty("abt_package_location", getBuildLocation(p));
2393
                    element.addProperty("abt_package_ownerlist", p.emailInfoNonAntTask(this));
2394
                    element.addProperty("abt_package_build_info", buildInfoText(p));
2395
 
2396
                    // depends in the form 'cs','25.1.0000.cr';'Dinkumware_STL','1.0.0.cots'
2397
                    StringAppender depends = new StringAppender(";");
2398
 
2399
                    for (Iterator<Package> it3 = p.mPackageDependencyCollection.iterator(); it3.hasNext(); )
2400
                    {
2401
                        Package depend = it3.next();
2402
                        depends.append( quoteString(depend.mName, depend.mVersion + depend.mExtension) );
2403
                    }
2404
 
2405
                    element.addProperty("abt_package_depends", depends.toString());
2406
                    element.addProperty("abt_is_ripple", p.mDirectlyPlanned ? "0" : "1");
2407
                    element.addProperty("abt_build_reason", p.mBuildReason.toString());
2408
                    element.addProperty("abt_package_version_id", p.mId);
2409
                    element.addProperty("abt_does_not_require_source_control_interaction", ! p.mRequiresSourceControlInteraction ? "true" : "false" );
2410
                    element.addProperty("abt_test_build_instruction", p.mTestBuildInstruction);
2411
                }
2412
            }
2413
        }
2414
        else
2415
        {
2416
            //    Escrow Mode
2417
            element.addProperty("abt_rtag_id", mRtagId);
2418
            element.addProperty("abt_sbom_id", mSbomId);
2419
        }
2420
 
2421
        element.addProperty("abt_release", escapeXml(mBaselineName));
2422
        element.addProperty("abt_buildtool_version", mReleaseManager.getMajorVersionNumber() );
2423
 
2424
        element.addNewElement("condition")
2425
        .addAttribute("property", "abt_family")
2426
        .addAttribute("value", "windows")
2427
        .addNewElement("os")
2428
        .addAttribute("family", "windows");
2429
        element.addProperty("abt_family", "unix");
2430
 
2431
        return element;
2432
    }
2433
 
2434
    /** Add task def XML items taskdef for the abt ant task
2435
     * @param xml 	- xml item to extend
2436
     */
2437
    private void generateTaskdef(XmlBuilder xml)
2438
    {
2439
        mLogger.debug("generateTaskdef");
2440
        xml.addNewElement("taskdef")
2441
        .addAttribute("name", "abt")
2442
        .addAttribute("classname", "com.erggroup.buildtool.abt.ABT");
2443
 
2444
        xml.addNewElement("taskdef")
2445
        .addAttribute("name", "abtdata")
2446
        .addAttribute("classname", "com.erggroup.buildtool.abt.ABTData");
2447
    }
2448
 
2449
    /** returns the command abtdata items
2450
     *  <br>Common machine information
2451
     *  <br>Common email address
2452
     *  
2453
     *  
2454
     *  @param	xml - Xml element to extend   
2455
     *  @param    p - Package (May be null)
2456
     */
2457
    private void generateMachineInfo(XmlBuilder xml, Package p)
2458
    {
2459
        XmlBuilder element = xml.addNewElement("abtdata");
2460
        element.addAttribute("id", "global-abt-data");
2461
 
2462
        //
2463
        //  Iterate over all the machines and create a nice entry
2464
        //
2465
        for (Iterator<ReleaseConfig> it = mReleaseManager.mReleaseConfigCollection.mReleaseConfig.iterator(); it.hasNext(); )
2466
        {
2467
            ReleaseConfig rc = it.next();
2468
            element.addElement(rc.getMachineEntry());
2469
        }
2470
 
2471
        //
2472
        //  Now the email information
2473
        //
2474
        if ( p != null)
2475
        {
2476
            p.emailInfo(this, element);
2477
        }
2478
    }
2479
 
2480
    /** Generate package information
2481
     *  Only when running unit tests
2482
     *  
2483
     * @param xml	- An xml element to append data to
2484
     * @param p	- Package to process
2485
     */
2486
    private void generatePackageInfo (XmlBuilder xml, Package p)
2487
    {
7082 dpurdie 2488
        StringBuilder comment = new StringBuilder();
2489
        StringBuilder deps = new StringBuilder();
2490
 
2491
        String joiner = "";
2492
        for (Iterator<String> it2 = p.mDependencyCollection.iterator(); it2.hasNext(); )
2493
        {
2494
            String alias = it2.next();
2495
            deps.append(joiner).append(alias); 
2496
            joiner = ",";
2497
        }
2498
 
2499
        comment.append("pvid=").append(p.mId);
2500
        comment.append(" name=").append('"').append(p.mAlias).append('"');
2501
        comment.append(" reason=").append(p.mNoBuildReason);
2502
        comment.append(" buildFile=").append(p.mBuildFile);
2503
        comment.append(" directlyPlanned=").append(p.mDirectlyPlanned);
2504
        comment.append(" indirectlyPlanned=").append(p.mIndirectlyPlanned);
2505
        comment.append(" depends=[").append(deps).append("]");
6914 dpurdie 2506
 
7082 dpurdie 2507
        xml.addComment(comment.toString());            
6914 dpurdie 2508
    }
2509
 
2510
    /**returns an ant target for the passed Package
2511
     * in daemon mode:
2512
     *  packages are categorized with one of three mBuildFile values:
2513
     *   1 the package to be built by this buildfile
2514
     *   2 the packages with a future build requirement
2515
     *   3 the packages with no build requirement
2516
     *  the returned target depends on this categorization and will have
2517
     *   1 full abt info
2518
     *   2 full dependency info to determine future build ordering but no abt info (will not build this package)
2519
     *   3 only a name attribute (will not build this package)
2520
     * in escrow mode:
2521
     *  if the passed Package's mBuildFile is different (less than) the passed build file,
2522
     *  the returned target have only a name attribute (will not build this package)
2523
     *   
2524
     * @param xml - Xml element to extend
2525
     * @param buildEntry - Record build type (dummy/generic/not generic)
2526
     * @param p - Package to process
2527
     * @param buildFile - buildfile level being processed
2528
     */
2529
    private void generateTarget(XmlBuilder xml, BuildFile buildEntry, Package p, int buildFile)
2530
    {
2531
        mLogger.debug("generateTarget");
2532
 
2533
        //---------------------------------------------------------------------
2534
        //  Generate the AbtData - common machine and email information
2535
        //  Only used by the daemon builds
2536
        //
2537
        if ( mDaemon && p.mBuildFile == 1 )
2538
        {
2539
            generateMachineInfo(xml, p );
2540
        }
2541
 
2542
        //-------------------------------------------------------------------------
2543
        //  Generate the <target name=... /> construct
2544
        //  There are two types
2545
        //      1) Simple dummy place holder. Just has the PackageName.PackageExt
2546
        //      2) Full target. Has all information to build the package including
2547
        //              AbtSetUp, AbtTearDown and AbtPublish targets
2548
        //
2549
 
2550
        if ( !mDaemon && ( p.mBuildFile < buildFile ) )
2551
        {
2552
            XmlBuilder target = xml.addNewElement("target");
2553
            target.addAttribute("name", p.mAlias);
2554
        }
2555
        else
2556
        {
2557
            if (!mDaemon) 
2558
            {
2559
                //  Escrow Only:
2560
                //  Generate the 'wrapper' target
2561
                //  This is used to ensure that the required dependencies have been built - I think
2562
                //
2563
                StringAppender dependList = new StringAppender(",");
2564
                if ( !p.mPackageDependencyCollection.isEmpty() )
2565
                {
2566
                    for (Iterator<Package> it = p.mPackageDependencyCollection.iterator(); it.hasNext(); )
2567
                    {
2568
                        Package dependency = it.next();
2569
                        if ( !mDaemon && dependency.mBuildFile == -2 )
2570
                        {
2571
                            // ignore targets which build in foreign environments in escrow mode
2572
                            continue;
2573
                        }
2574
                        dependList.append(dependency.mAlias);
2575
                    }
2576
                }
2577
 
2578
                XmlBuilder target = xml.addNewElement("target").isExpanded();
2579
                target.addAttribute("name", p.mAlias + ".wrap");
2580
 
2581
                if (dependList.length() > 0)
2582
                {
2583
                    target.addAttribute("depends", dependList.toString() );
2584
                }
2585
 
2586
                if ( !mDaemon )
2587
                {
2588
                    boolean hasDependenciesBuiltInThisIteration = false;
2589
                    if ( ( !p.mPackageDependencyCollection.isEmpty()) )
2590
                    {
2591
                        for (Iterator<Package> it = p.mPackageDependencyCollection.iterator(); it.hasNext(); )
2592
                        {
2593
                            Package dependency = it.next();
2594
 
2595
                            if ( dependency.mBuildFile == buildFile )
2596
                            {
2597
                                hasDependenciesBuiltInThisIteration = true;
2598
                                break;
2599
                            }
2600
                        }
2601
                    }
2602
 
2603
                    if ( hasDependenciesBuiltInThisIteration )
2604
                    {
2605
                        XmlBuilder condition = target.addNewElement("condition");
2606
                        condition.addAttribute("property",  p.mAlias + ".build");
2607
 
2608
                        XmlBuilder and = condition.addNewElement("and");
2609
 
2610
                        for (Iterator<Package> it = p.mPackageDependencyCollection.iterator(); it.hasNext(); )
2611
                        {
2612
                            Package dependency = it.next();
2613
 
2614
                            if ( dependency.mBuildFile == buildFile )
2615
                            {
2616
                                XmlBuilder or = and.addNewElement("or");
2617
 
2618
                                XmlBuilder equal1 = or.addNewElement("equals");
2619
                                equal1.addAttribute("arg1", "${" + dependency.mAlias + ".res}");
2620
                                equal1.addAttribute("arg2", "0");
2621
 
2622
                                XmlBuilder equal2 = or.addNewElement("equals");
2623
                                equal2.addAttribute("arg1", "${" + dependency.mAlias + ".res}");
2624
                                equal2.addAttribute("arg2", "257");
2625
                            }
2626
                        }
2627
                    }
2628
                    else
2629
                    {
2630
                        target.addProperty(p.mAlias + ".build", "");
2631
                    }
2632
                }
2633
            }
2634
 
2635
 
2636
            //
2637
            //  Generate the 'body' of the target package
2638
            //  Escrow Mode: Always
2639
            //  Daemon Mode: Only for the one target we are building
2640
            //                  Simplifies the XML
2641
            //                  Reduces noise in the logs
2642
            //              Don't add target dependencies. 
2643
            //                  We are only building one target and the 
2644
            //                  dependency management has been done way before now.
2645
            //                  All it does is makes the logs noisy.
2646
            //
2647
            if ( ( mDaemon && p.mBuildFile == 1 ) || !mDaemon )
2648
            {
2649
                XmlBuilder target = xml.addNewElement("target").isExpanded();
2650
                target.addAttribute("name", p.mAlias);
2651
 
2652
                if ( !mDaemon )
2653
                {
2654
                    target.addAttribute("depends",  p.mAlias + ".wrap");
2655
                    target.addAttribute("if",p.mAlias + ".build");
2656
                }
2657
 
2658
                if ( mDaemon && p.mBuildFile == 1 )
2659
                {
2660
                    target.addProperty(p.mAlias + "pkg_id",p.mPid);
2661
                    target.addProperty(p.mAlias + "pv_id",p.mId);
2662
                }
2663
 
2664
                target.addProperty(p.mAlias + "packagename",p.mName);        		
2665
                target.addProperty(p.mAlias + "packageversion",p.mVersion);
2666
                target.addProperty(p.mAlias + "packageextension",p.mExtension);
2667
                target.addProperty(p.mAlias + "packagevcstag",p.mVcsTag);
2668
 
2669
                target.makePropertyTag(p.mAlias + "directchange", p.mDirectlyPlanned); 
2670
                target.makePropertyTag(p.mAlias + "doesnotrequiresourcecontrolinteraction", ! p.mRequiresSourceControlInteraction);
2671
 
2672
                buildEntry.state = BuildFile.BuildFileState.NonGeneric;
2673
                if ( p.isGeneric() )
2674
                {
2675
                    buildEntry.state = BuildFile.BuildFileState.Generic;
2676
                    target.makePropertyTag(p.mAlias + "generic", true); 
2677
                }
2678
 
2679
                target.addProperty(p.mAlias + "loc", getBuildLocation(p));
2680
                target.makePropertyTag(p.mAlias + "unittests", p.mHasAutomatedUnitTests && mDaemon);
2681
 
2682
                //    Add our own task and associated information
2683
                //
2684
                XmlBuilder abt = target.addNewElement("abt").isExpanded();
2685
 
2686
                for (Iterator<Package> it = p.mPackageDependencyCollection.iterator(); it.hasNext(); )
2687
                {
2688
                    Package dependency = it.next();
2689
                    XmlBuilder depend = abt.addNewElement("depend");
2690
                    depend.addAttribute("package_alias", "${" + dependency.mAlias + "}");
2691
                }
2692
 
2693
                buildInfo(abt,p);
2694
 
2695
                if ( mDaemon && p.mBuildFile == 1 )
2696
                {
2697
                    //    AbtTestPath
2698
                    target = xml.addNewElement("target").isExpanded();
2699
                    target.addAttribute("name", "AbtTestPath");
2700
                    target.addProperty("AbtTestPathpackagevcstag", p.mVcsTag);
2701
                    target.addProperty("AbtTestPathpackagename", p.mName);
2702
                    abt = target.addNewElement("abt").isExpanded();
2703
                    buildInfo(abt, p);
2704
 
2705
 
2706
                    //    AbtSetUp
2707
                    target = xml.addNewElement("target").isExpanded();
2708
                    target.addAttribute("name", "AbtSetUp");
2709
                    target.addProperty("AbtSetUppackagevcstag", p.mVcsTag);
2710
                    target.addProperty("AbtSetUppackagename", p.mName);
2711
 
2712
                    abt = target.addNewElement("abt").isExpanded();
2713
                    buildInfo(abt, p);
2714
 
2715
                    //    AbtTearDown
2716
                    target = xml.addNewElement("target").isExpanded();
2717
                    target.addAttribute("name", "AbtTearDown");
2718
                    target.addProperty("AbtTearDownpackagevcstag", p.mVcsTag);
2719
                    target.addProperty("AbtTearDownpackagename", p.mName);
2720
                    target.addProperty("AbtTearDownpackageversion", p.mVersion);
2721
                    target.addProperty("AbtTearDownpackageextension", p.mExtension);
2722
                    target.makePropertyTag(p.mAlias + "generic", p.isGeneric());
2723
 
2724
                    abt = target.addNewElement("abt").isExpanded();
2725
                    buildInfo(abt, p);
2726
 
2727
 
2728
                    //  AbtPublish
2729
                    target = xml.addNewElement("target").isExpanded();
2730
                    target.addAttribute("name", "AbtPublish");
2731
 
2732
                    target.addProperty("AbtPublishpackagevcstag", p.mVcsTag);
2733
                    target.addProperty("AbtPublishpackagename", p.mName);
2734
                    target.addProperty("AbtPublishpackageversion", p.mVersion);
2735
                    target.addProperty("AbtPublishpackageextension", p.mExtension);
2736
                    target.makePropertyTag("AbtPublishdirectchange", p.mDirectlyPlanned);
2737
                    target.makePropertyTag("AbtPublishdoesnotrequiresourcecontrolinteraction", ! p.mRequiresSourceControlInteraction);
2738
                    target.makePropertyTag("AbtPublishgeneric", p.isGeneric());
2739
                    target.addProperty("AbtPublishloc", getBuildLocation(p));
2740
 
2741
                    abt = target.addNewElement("abt").isExpanded();
2742
                    buildInfo(abt, p);
2743
 
2744
                }
2745
            }
2746
        }
2747
    }
2748
 
2749
    /** Extends the xml object. Adds ant default target for the current build iteration
2750
     * @param xml - The XmlBuilder Object to extend
2751
     * @param buildFile - The current build file level. This differs for Daemon and Escrow mode. In Daemon mode it will not be a '1' 
2752
     */
2753
    private void generateDefaultTarget(XmlBuilder xml, int buildFile)
2754
    {
2755
        mLogger.debug("generateDefaultTarget");
2756
 
2757
        XmlBuilder target = xml.addNewElement("target").isExpanded();
2758
        target.addAttribute("name", "fullstart");
2759
 
2760
        if (buildFile == 1)
2761
        {
2762
            antEcho(target, "${line.separator}" + mAnyBuildPlatforms + "${line.separator}${line.separator}");
7082 dpurdie 2763
            for (Iterator<Package> it = mPackageCollectionAll.iterator(); it.hasNext(); )
6914 dpurdie 2764
            {
2765
                Package p = it.next();
2766
 
2767
                if ( p.mBuildFile == -1 )
2768
                {
2769
                    antEcho(target, "${line.separator}" + p.mAlias + "${line.separator}");
2770
                }
2771
            }
2772
 
2773
            antEcho(target, "${line.separator}" + mAssocBuildPlatforms + "${line.separator}${line.separator}");
7082 dpurdie 2774
            for (Iterator<Package> it = mPackageCollectionAll.iterator(); it.hasNext(); )
6914 dpurdie 2775
            {
2776
                Package p = it.next();
2777
 
2778
                if ( p.mBuildFile == -2 )
2779
                {
2780
                    antEcho(target, "${line.separator}" + p.mAlias + "${line.separator}");
2781
                }
2782
            }
2783
 
2784
            antEcho(target, "${line.separator}" + mNotInBaseline + "${line.separator}${line.separator}");
7082 dpurdie 2785
            for (Iterator<Package> it = mPackageCollectionAll.iterator(); it.hasNext(); )
6914 dpurdie 2786
            {
2787
                Package p = it.next();
2788
 
2789
                if ( p.mBuildFile == -4 )
2790
                {
2791
                    antEcho(target, "${line.separator}" + p.mAlias + "${line.separator}");
2792
                }
2793
            }
2794
 
2795
            antEcho(target, "${line.separator}" + mDependent + "${line.separator}${line.separator}");
7082 dpurdie 2796
            for (Iterator<Package> it = mPackageCollectionAll.iterator(); it.hasNext(); )
6914 dpurdie 2797
            {
2798
                Package p = it.next();
2799
 
2800
                if ( p.mBuildFile == -5 )
2801
                {
2802
                    antEcho(target, "${line.separator}" + p.mAlias + "${line.separator}");
2803
                }
2804
            }
2805
        }
2806
 
2807
        if ( !mDaemon )
2808
        {
2809
            antEcho(target, "${line.separator}Build Started:${line.separator}${line.separator}");
2810
        }
2811
 
2812
        //
2813
        //	Create a comma separated list of all the required targets
2814
        //      Escrow : All packages
2815
        //      Daemon : Just the package being built
2816
        //
2817
        StringAppender dependList = new StringAppender(",");
2818
        dependList.append("fullstart");
7082 dpurdie 2819
        for (Iterator<Package> it = mPackageCollectionAll.iterator(); it.hasNext(); )
6914 dpurdie 2820
        {
2821
            Package p = it.next();
2822
 
2823
            if ( ( p.mBuildFile > 0 ) && ( p.mBuildFile <= buildFile ) )
2824
            {
2825
                if ((mDaemon && p.mBuildFile == 1) || !mDaemon)
2826
                {
2827
                    dependList.append(p.mAlias);                    
2828
                }
2829
            }
2830
        }
2831
 
2832
        target = xml.addNewElement("target").isExpanded();
2833
        target.addAttribute("name", "full");
2834
        target.addAttribute("depends", dependList.toString());
2835
 
2836
        if ( !mDaemon )
2837
        {
2838
            antEcho(target, "${line.separator}Build Finished${line.separator}");
2839
        }
2840
    }
2841
 
2842
    /** Internal helper function to create an ant 'echo statement
2843
     *  Many of the parameters are fixed
2844
     */
2845
    private void antEcho( XmlBuilder xml, String message)
2846
    {
2847
        XmlBuilder msg = xml.addNewElement("echo");
2848
        msg.addAttribute("message", message);
2849
        msg.addAttribute("file", "publish.log");
2850
        msg.addAttribute("append", "true");
2851
    }
2852
 
2853
    /**sets the mIndirectlyPlanned true for the package and all dependent packages
2854
     */
2855
    private void rippleIndirectlyPlanned(Package p)
2856
    {
2857
        mLogger.debug("rippleIndirectlyPlanned");
2858
        if ( !p.mIndirectlyPlanned && p.mBuildFile == 0 )
2859
        {
2860
            p.mIndirectlyPlanned = true;
2861
 
7082 dpurdie 2862
            for (Iterator<Package> it = mPackageCollectionAll.iterator(); it.hasNext(); )
6914 dpurdie 2863
            {
2864
                Package pkg = it.next();
2865
 
2866
                if ( pkg != p )
2867
                {
2868
                    for (Iterator<Package> it2 = pkg.mPackageDependencyCollection.iterator(); it2.hasNext(); )
2869
                    {
2870
                        Package dependency = it2.next();
2871
 
2872
                        if ( dependency == p )
2873
                        {
2874
                            rippleIndirectlyPlanned( pkg );
2875
                            break;
2876
                        }
2877
                    }
2878
                }
2879
            }
2880
        }
7044 dpurdie 2881
        mLogger.info("rippleIndirectlyPlanned set {} {}", p.mName, p.mIndirectlyPlanned);    
6914 dpurdie 2882
    }
2883
 
2884
    /**accessor method
2885
     */
2886
    public String getEscrowSetUp()
2887
    {
2888
        mLogger.debug("getEscrowSetUp");
2889
        String retVal = mEscrowSetup;
2890
 
7044 dpurdie 2891
        mLogger.debug("getEscrowSetUp returned {}", retVal);
6914 dpurdie 2892
        return retVal;
2893
    }
2894
 
2895
    /**accessor method
2896
     */
2897
    public String getRawData()
2898
    {
2899
        mLogger.debug("getRawData");
2900
        String retVal = mEscrowRawData;
2901
 
7044 dpurdie 2902
        mLogger.debug("getRawData returned {}", retVal);
6914 dpurdie 2903
        return retVal;
2904
    }
2905
 
2906
    /**Get the build loc (location)
2907
     * This is package specific and will depend on the build mode (Escrow/Daemon)
2908
     * 
2909
     * @param	p - Package being built
2910
     * @return A string that describes the build location
2911
     */
2912
    private String getBuildLocation(Package p)
2913
    {
2914
        mLogger.debug("locationProperty");
2915
        String location = "";
2916
 
2917
        if (mDaemon)
2918
        {
2919
            // Daemon: Start in root of view/workspace
2920
            location += mBaseline;
2921
        }
2922
        else
2923
        {
2924
            // Escrow: mAlias used with jats -extractfiles -view
2925
            location += p.mAlias;
2926
        }
2927
 
2928
        //
2929
        //  Always use '/' as a path separator - even if user has specified '\'
2930
        //  Ant can handle it.
2931
        //
2932
        location = location.replace('\\', '/');
2933
        return location;
2934
    }
2935
 
2936
    /**Adds package build into as XML elements 
2937
     * @param	  xml 	- Xml element to extend
2938
     * @param   p       - Package to process
2939
     */
2940
    private void buildInfo(XmlBuilder xml, Package p)
2941
    {
2942
        mLogger.debug("buildInfo");
2943
 
2944
        //
2945
        // Create the xml build information
2946
        // <platform gbe_machtype="linux_i386" type="jats" arg="all"/>
2947
        //
2948
        for (Iterator<BuildStandard> it = p.mBuildStandardCollection.iterator(); it.hasNext();)
2949
        {
2950
            BuildStandard bs = it.next();
2951
            bs.getBuildStandardXml(xml);
2952
        }
2953
    }
2954
 
2955
    /**returns the buildInfo as a single line of text
2956
     * Used for reporting purposes only
2957
     * @param   p       - Package to process
2958
     * 
2959
     */
2960
    public String buildInfoText(Package p)
2961
    {
2962
        mLogger.debug("buildInfoText");
2963
 
2964
        StringAppender result = new StringAppender (";");
2965
 
2966
        //
2967
        //  Create platform:standards
2968
        //      
2969
        for (Iterator<BuildStandard> it = p.mBuildStandardCollection.iterator(); it.hasNext(); )
2970
        {
2971
            BuildStandard bs = it.next();
2972
 
2973
            if ( bs.isActive() )
2974
            {
2975
                String info = bs.getBuildStandardText();
2976
                result.append(info);
2977
            }
2978
        }
2979
 
7044 dpurdie 2980
        mLogger.info("buildInfoText returned {}", result);
6914 dpurdie 2981
        return result.toString();
2982
    }
2983
 
2984
    /**prints to standard out in escrow mode only
2985
     * <br>Prints a title and information. The title is only printed once.
2986
     * 
2987
     * @param header - The message title to display, if printMessage is true
2988
     * @param text - A package name. Really just the 2nd line of the message
2989
     * @param printHeader -  Controls the printing of the message argument
2990
     */
2991
    private void standardOut(final String header, final String text, boolean printHeader)
2992
    {
2993
        mLogger.debug("standardOut");
2994
        if (!mDaemon)
2995
        {
2996
            if ( printHeader )
2997
            {
2998
                System.out.println(header);
2999
            }
3000
 
3001
            System.out.println(text);
3002
        }
3003
    }
3004
 
3005
 
3006
    /**
3007
     *  Email users about a rejected daemon instruction
3008
     *  @param  reason  - Reason for the rejection
3009
     *  @param  pkg     - Package to be affected by the instruction
3010
     *  
3011
     */
3012
    public void emailRejectedDaemonInstruction(String reason, Package p)
3013
    {
3014
        mLogger.debug("emailRejectedDaemonInstruction");
3015
 
3016
        //  Email Subject
3017
        String subject = "BUILD FAILURE of Daemon Instruction on package " + p.mAlias;
3018
 
3019
        // Email Body
3020
        String mailBody = "The build system reject the the Daemon Instruction";
3021
        mailBody += "<br>Reason: " + reason; 
3022
 
3023
        mailBody += "<p>Release: " + mBaselineName 
3024
                +  "<br>Package: " + p.mAlias 
3025
                +  "<br>Rm Ref: " + CreateUrls.generateRmUrl(getRtagId(), p.mId); 
3026
 
3027
        mailBody += "<p><hr>";
3028
 
3029
        String target = p.emailInfoNonAntTask(this);
3030
 
7044 dpurdie 3031
        mLogger.error("emailRejectedDaemonInstruction Server: {}", getMailServer());
3032
        mLogger.error("emailRejectedDaemonInstruction Sender: {}", getMailSender());
3033
        mLogger.error("emailRejectedDaemonInstruction Target: {}", target);
6914 dpurdie 3034
 
3035
        try
3036
        {
3037
            //    
7082 dpurdie 3038
            Smtpsend.send(getMailServer(),  // mailServer
3039
                    getMailSender(),        // source
3040
                    target,                 // target
3041
                    getMailSender(),        // cc
3042
                    null,                   // bcc
3043
                    subject,                // subject
3044
                    mailBody,               // body
3045
                    null                    // attachment
6914 dpurdie 3046
                    );
3047
        } catch (Exception e)
3048
        {
7044 dpurdie 3049
            mLogger.warn("Email Failure: emailRejectedDaemonInstruction:{}", e.getMessage());
6914 dpurdie 3050
        }
3051
    }
3052
 
3053
    /**
3054
     * @return the mMailServer
3055
     */
3056
    public String getMailServer() {
3057
        return mMailServer;
3058
    }
3059
 
3060
    /**
3061
     * @param mMailServer the mMailServer to set
3062
     */
3063
    public void setMailServer(String mMailServer) {
3064
        this.mMailServer = mMailServer;
3065
    }
3066
 
3067
    /**
3068
     * @return the mMailSender
3069
     */
3070
    public String getMailSender() {
3071
        return mMailSender;
3072
    }
3073
 
3074
    /**
3075
     * @param mMailSender the mMailSender to set
3076
     */
3077
    public void setMailSender(String mMailSender) {
3078
        this.mMailSender = mMailSender;
3079
    }
3080
 
3081
    /**
3082
     * @return the mMailGlobalTarget
3083
     */
3084
    public String getMailGlobalTarget() {
3085
        return mMailGlobalTarget;
3086
    }
3087
 
3088
    /**
3089
     * @param mMailGlobalTarget the mMailGlobalTarget to set
3090
     */
3091
    public void setMailGlobalTarget(String mMailGlobalTarget) {
3092
        this.mMailGlobalTarget = mMailGlobalTarget;
3093
    }
3094
 
3095
}