Subversion Repositories DevTools

Rev

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

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