Subversion Repositories DevTools

Rev

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