Subversion Repositories DevTools

Rev

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