Subversion Repositories DevTools

Rev

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