Subversion Repositories DevTools

Rev

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