Subversion Repositories DevTools

Rev

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