Subversion Repositories DevTools

Rev

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