Subversion Repositories DevTools

Rev

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

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