Subversion Repositories DevTools

Rev

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