Subversion Repositories DevTools

Rev

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

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