Subversion Repositories DevTools

Rev

Rev 7033 | Rev 7082 | 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.io.File;
4
import java.sql.SQLException;
5
import java.util.ArrayList;
6
import java.util.HashMap;
7
import java.util.Iterator;
8
import java.util.LinkedHashSet;
9
import java.util.Vector;
10
import java.util.Comparator;
11
 
7033 dpurdie 12
import org.slf4j.Logger;
13
import org.slf4j.LoggerFactory;
6914 dpurdie 14
 
15
import com.erggroup.buildtool.ripple.ReleaseManager.BuildReason;
16
import com.erggroup.buildtool.smtp.CreateUrls;
17
import com.erggroup.buildtool.smtp.Smtpsend;
18
import com.erggroup.buildtool.utilities.MutableInt;
19
import com.erggroup.buildtool.utilities.XmlBuilder;
20
import com.erggroup.buildtool.utilities.utilities;
21
 
22
public class Package
23
{
24
    /**
25
     * name of package, must not contain spaces
26
     * 
27
     * @attribute
28
     */
29
    String mName = new String();
30
 
31
    /**
32
     * package scope
33
     * 
34
     * @attribute
35
     */
36
    String mExtension = new String();
37
 
38
    /**
39
     * instance identifier
40
     * 
41
     * @attribute
42
     */
43
    public String mVersion = new String();
44
 
45
    /**
46
     * Version string as specified by the user. Used with a ripple type of 'F'
47
     */
48
    String mFixedVersion = new String();
49
 
50
    /**
51
     * unique identifier 
52
     *      daemon builds = mName + mExtension
53
     *      escrow builds = mName + mVersion + mExtension
54
     * 
55
     * @attribute
56
     */
57
    public String mAlias = new String();
58
 
59
    /**
60
     * Version Control System Tag
61
     * 
62
     * @attribute
63
     */
64
    String mVcsTag = new String();
65
 
66
    /**
67
     * build standards
68
     * 
69
     * @attribute
70
     */
71
    public Vector<BuildStandard> mBuildStandardCollection = new Vector<BuildStandard>();
72
 
73
    /**
74
     * GBE_MACHTYPE used to build generic packages for this baseline only has
75
     * meaning in the daemon build, not the escrow build accessed by
76
     * BuildStandard::getPlatform, getBuildStandard
77
     * 
78
     * @attribute
79
     */
80
    public static String mGenericMachtype = System.getenv("GBE_MACHTYPE");
81
 
82
    /**
83
     * build dependencies by package alias
84
     * 
85
     * @attribute
86
     */
87
    public Vector<String> mDependencyCollection = new Vector<String>();
88
 
89
    /**
90
     * primary package version key pv_id in database
91
     * 
92
     * @attribute
93
     */
94
    public int mId;
95
 
96
    /**
97
     * indication of the nature of change
98
     * 
99
     * @attribute
100
     */
101
    Package.VersionNumberingStandard mChangeType = new VersionNumberingStandard();
102
 
103
    /**
104
     * determines what field is rippled on a package version whose dependencies
105
     * have changed
106
     * 
107
     * @attribute
108
     */
109
    Package.VersionNumberingStandard mRippleField = new VersionNumberingStandard();
110
 
111
    /**
112
     * interested owners
113
     * 
114
     * @attribute
115
     */
116
    private Vector<String> mBuildFailureEmailCollection = new Vector<String>();
117
 
118
    /**
119
     * when true will trigger unit tests as part of the package build phase in
120
     * daemon mode
121
     * 
122
     * @attribute
123
     */
124
    public boolean mHasAutomatedUnitTests = false;
125
 
126
    /**
127
     * when true, do not ripple this package through packages which are
128
     * dependent upon it in daemon mode
129
     * 
130
     * @attribute
131
     */
132
    public boolean mAdvisoryRipple = false;
133
 
134
    /**
135
     * Pegged packages will:
136
     *   - Not be rippled
137
     *   - Not be test buildable
138
     *   - Dependencies will not be considered
139
     *   Daemon Mode:
140
     *      Are not built in this release
141
     *      Are imported with out consideration as to their dependencies
142
     *      Must exist in dpkg_archive - will not be built if not present
143
     *   Escrow Mode:
144
     *      Have no special consideration
145
     *      The package and its dependencies will be built
146
     *
147
     * Packages imported into the release from an SDK will be treated as if they were
148
     * pegged by the built system.
149
     * 
150
     */
151
    public boolean mIsPegged = false;
152
    public boolean mIsSdk = false;
153
 
154
    /**
155
     * Unbuildable packages will not be candidates for a ripple or a rebuild
156
     * If they do not exist in dpkg_archive, then then will cause an error
157
     */
158
    public boolean mIsBuildable = true;
159
 
160
    /**
161
     * determines the build file the package is built in, or not
162
     * @param   1 Post Plan: build file - Result of planning
163
     * @param   2 Post Plan: Future build requirement
164
     * @param   3 Post Plan: Package has no build requirement
165
     * @param   0 not yet processed (initial value) 
166
     * @param  -1 not reproducible
167
     * @param  -2 escrow: not reproducible on the build platforms configured for this release
168
     * @param  -3 daemon: do not ripple
169
     * @param  -4 directly dependent on package versions not in the baseline
170
     * @param  -5 indirectly dependent on package versions which are not reproducible due to detected fault
171
     * @param  -6 circular dependency
172
     * @param  -7 Pegged or SDK Imported package not in dpkg_archive
173
     * @param  -8 Pegged or SDK Imported package
174
     * @param  -9 Rejected Daemon Instruction
175
     * @param  -10 UnBuildable Package not in dpkg_archive
176
     * @param  -11 Marked as RippleStop
177
     * 
178
     */
179
    int mBuildFile = 0;
180
 
181
    /** Retained reason the package will not be built
182
     *  Save negative values as mBuildFile
183
     * @attribute
184
     */
185
    int mNoBuildReason = 0;
186
 
187
    /**
188
     * build dependencies by package
189
     * Calculated from information in mDependencyCollection
190
     * 
191
     * @attribute
192
     */
193
    Vector<Package> mPackageDependencyCollection = new Vector<Package>();
194
 
195
    /**
196
     * used for escrow build purposes set true when a package has been processed
197
     * 
198
     * @attribute
199
     */
200
    boolean mProcessed = false;
201
 
202
    /**
203
     * Reason that a package is being built
204
     */
205
    public BuildReason mBuildReason = null;
206
 
207
    /**
208
     * set true for WIP package versions only used in daemon mode
209
     * 
210
     * @attribute
211
     */
212
    public boolean mDirectlyPlanned = false;
213
 
214
    /**
215
     * set true when it is determined to be ripple built
216
     * 
217
     * @attribute
218
     */
219
    boolean mIndirectlyPlanned = false;
220
 
221
    /**
222
     * non zero instruction number when it is determined to be ripple built by force
223
     * 
224
     * @attribute
225
     */
226
    int mForcedRippleInstruction = 0;
227
 
228
    /**
229
     * test build - non zero instruction number when it is determined to be test built
230
     * 
231
     * @attribute
232
     */
233
    int mTestBuildInstruction = 0;
234
 
235
    /**
236
     * test build - Package PVID
237
     * 
238
     * @attribute
239
     */
240
    int mTestBuildPvId = -1;
241
 
242
    /**
243
     * test build email destination
244
     * Used by all daemon instructions to retain instigator of the instruction 
245
     * 
246
     * @attribute
247
     */
248
    String mTestBuildEmail;
249
 
250
    /**
251
     * test build - Version Control System Tag
252
     * 
253
     * @attribute
254
     */
255
    String mTestBuildVcsTag = new String();
256
 
257
    /**
258
     * test build - build standards
259
     * 
260
     * @attribute
261
     */
262
    Vector<BuildStandard> mTestBuildStandardCollection = new Vector<BuildStandard>();
263
 
264
    /**
265
     * test build - build dependencies by package alias
266
     * 
267
     * @attribute
268
     */
269
    Vector<String> mTestBuildDependencyCollection = new Vector<String>();
270
 
271
    /** 
272
     * test build - package has build dependencies
273
     */
274
	public boolean mTestBuildHasAutomatedUnitTests;
275
 
276
    /**
277
     * build dependencies by pv_id (-1 or not used for planned dependencies)
278
     * 
279
     * @attribute
280
     */
281
    public Vector<Integer> mDependencyIDCollection = new Vector<Integer>();
282
 
283
    /**
284
     * unique pkg_id in the database used for querying package version existence
285
     * in the database in daemon mode
286
     * 
287
     * @attribute
288
     */
289
    public int mPid;
290
 
291
    /**
292
     * maximum major number supported for determining ripple number
293
     * 
294
     * @attribute
295
     */
296
    int mMajorLimit;
297
 
298
    /**
299
     * maximum minor number supported for determining ripple number
300
     * 
301
     * @attribute
302
     */
303
    int mMinorLimit;
304
 
305
    /**
306
     * maximum patch number supported for determining ripple number
307
     * 
308
     * @attribute
309
     */
310
    int mPatchLimit;
311
 
312
    /**
313
     * maximum build number number supported for determining ripple number
314
     * 
315
     * @attribute
316
     */
317
    int mBuildLimit;
318
 
319
    /**
320
     * Logger
321
     * 
322
     * @attribute
323
     */
7033 dpurdie 324
    private static final Logger mLogger = LoggerFactory.getLogger(Package.class);
6914 dpurdie 325
 
326
    /**
327
     * dpkg archive location - The writable dpkg_archive
328
     * 
329
     * @attribute
330
     */
331
    public static String mGbeDpkg = System.getenv("GBE_DPKG");
332
 
333
    /**
334
     *  A physically close replica of dpkg_archive
335
     *  Is not writable 
336
     */
337
    public static final String mGbeDpkgReplica = System.getenv("GBE_DPKG_REPLICA");
338
 
339
    /**
340
     * Exception message used upon detection an archive does not exist Seems
341
     * this is a rare but transient and recoverable scenario
342
     * 
343
     * @attribute
344
     */
345
    public static final String mRecoverable = "dpkg_archive does not exist, recovery will be attempted";
346
 
347
    /**
348
     * true if the package exists in the package archive (dpkg_archive)
349
     * 
350
     * @attribute
351
     */
352
    private boolean mArchivalExistence = true;
353
 
354
    /**
355
     * when true will trigger source control interaction eg labelling
356
     * 
357
     * @attribute
358
     */
359
    public boolean mRequiresSourceControlInteraction = true;
360
 
361
    /**
362
     * when true has been checked for circular dependency
363
     * 
364
     * @attribute
365
     */
366
    boolean mCheckedCircularDependency = false;
367
 
368
    /**
369
     * when true has circular dependency, or in the process of detecting a circular dependency
370
     * 
371
     * @attribute
372
     */
373
    boolean mHasCircularDependency = false;
374
 
375
    /**
376
     * Bread crumb used to detect circular dependencies
377
     * 0 - Normal state
378
     * 1 - Crumb has been set
379
     * 2 - Crumb is a part of a circular dependency
380
     * 3 - Crumb is the start/end of the loop
381
     */
382
    int mBreadCrumb = 0;
383
 
384
    /**
385
     * Planned packages (WIPS) need calculate a new version number
386
     * This should be based on the Version of the package that the WIP was based upon
387
     */
388
	public String mPrevVersion;
389
 
390
	/** Used to preserve the basic ordering of the package list(s)
391
	 *  Only valid for the duration of the comparison sorts
392
	 */
393
	int mSeqId;
394
 
395
	/** Indicates that the package not be ripple built at this time
396
	 *  Sequence is:
397
	 *     User sets to 's'
398
	 *     This buildtool will set to 'w' when a ripple has been detected
399
	 *     User resets to NULL when the ripple can be resumed. This is stored as an 'n'
400
	 * 
401
	 */
402
    public char mRippleStop;
7046 dpurdie 403
 
404
    /** The duration (seconds) of the last build of this package
405
     *  Used to estimate the cost of building the package
406
     *  A WIP packages gets the buildTime of the package its based upon
407
     */
408
    public int mBuildTime;
6914 dpurdie 409
 
410
    /**
411
     * Constructor
412
     * Used to create planned packages. In these packages the change_type is significant
413
     * 
414
     * @param pkg_id	   Package Name Identifier
415
     * @param pv_id        Package Version Id
416
     * @param pkg_name     Package Name
417
     * @param pkg_version  Package Version
418
     * @param v_ext        Package Suffix
419
     * @param alias        Package Alias
420
     * @param pkg_vcs_tag  Vcs Tag
421
     * @param ripple_field Ripple Field
422
     * @param change_type  Change Type
423
     */
424
    public Package(int pkg_id, int pv_id, String pkg_name, String pkg_version, String v_ext, String alias, String pkg_vcs_tag,
425
            char ripple_field, char change_type)
426
    {
427
        mLogger.debug("Package 1: pv_id " + pv_id + " pkg_name " + pkg_name + " v_ext " + v_ext + " alias " + alias
428
                + " pkg_vcs_tag " + pkg_vcs_tag + " change_type " + change_type);
429
        mId = pv_id;
430
        mName = pkg_name;
431
        mPid = pkg_id;
432
        mVersion = "0.0.0000";
433
        mExtension = v_ext;
434
        mAlias = alias;
435
        mVcsTag = pkg_vcs_tag;
436
 
437
        // Remove the package suffix from package_version to create the fixed version number
438
        mFixedVersion = pkg_version;
439
        mFixedVersion = mFixedVersion.substring(0, mFixedVersion.length() - mExtension.length());
440
 
441
        // a ripple_field of 'L' indicates this package has limited version numbering
442
        if (change_type == 'M') {
443
            mChangeType.setMajor(ripple_field == 'L' ? true : false);
444
 
445
        } else if (change_type == 'N') {
446
            mChangeType.setMinor(ripple_field == 'L' ? true : false);
447
 
448
        } else if (change_type == 'P') {
449
            mChangeType.setPatch(ripple_field == 'L' ? true : false);
450
 
451
        } else if (change_type == 'F') {
452
            mChangeType.setFixed();
453
 
454
        } else {
455
            mChangeType.setUnknown();
456
        }
457
    }
458
 
459
    /**
460
     * Constructor
461
     * Used to create existing packages, in these packages the ripple_field is significant
462
     * 
463
     * @param pkg_id	   Package Name Identifier
464
     * @param pv_id        Package Version Id
465
     * @param pkg_name     Package Name
466
     * @param pkg_version  Package Version
467
     * @param v_ext        Package Suffix
468
     * @param alias        Package Alias
469
     * @param pkg_vcs_tag  Vcs Tag
470
     * @param ripple_field Ripple Field
471
     */
472
    public Package(int pkg_id,int pv_id, String pkg_name, String pkg_version, String v_ext, String alias, String pkg_vcs_tag,
473
            char ripple_field)
474
    {
475
        mLogger.debug("Package 2: pv_id " + pv_id + " pkg_name " + pkg_name + " pkg_version " + pkg_version + " v_ext "
476
                + v_ext + " alias " + alias + " pkg_vcs_tag " + pkg_vcs_tag + " ripple_field " + ripple_field);
477
        mId = pv_id;
478
        mName = pkg_name;
479
        mPid = pkg_id;
480
        mVersion = pkg_version;
481
        int endindex = mVersion.length() - v_ext.length();
482
 
483
        if (endindex > 0)
484
        {
485
            mVersion = mVersion.substring(0, endindex);
486
        }
487
 
488
        mExtension = v_ext;
489
        mAlias = alias;
490
        mVcsTag = pkg_vcs_tag;
491
 
492
        // setBuild is the default
493
        if (ripple_field == 'M') {
494
            mRippleField.setMajor();
495
 
496
        } else if (ripple_field == 'm') {
497
            mRippleField.setMinor();
498
 
499
        } else if (ripple_field == 'p') {
500
            mRippleField.setPatch();
501
 
502
        } else if (ripple_field == 'L') {
503
            mRippleField.setLimit();
504
        }
505
    }
506
 
507
    /**
508
     * constructor
509
     */
510
    Package()
511
    {
512
        mLogger.debug("Package 3");
513
        mId = 0;
514
        mName = "null";
515
        mExtension = "null";
516
        mAlias = "null";
517
        mVcsTag = "null";
518
    }
519
 
520
    /**
521
     * Constructor for test build purposes
522
     * Used when a test build package does not exist in the current package set
523
     * 
524
     */
525
    Package(int pkg_id, int pv_id, String pkg_name, String v_ext, String alias, String pkg_vcs_tag, int testBuildInstruction, String email)
526
    {
527
        mLogger.debug("Package 4: pkg_name " + pkg_name + " v_ext " + v_ext + " alias " + alias + " pkg_vcs_tag "
528
                + pkg_vcs_tag);
529
        // don't need pv_id
530
        mId = -1;
531
        mName = pkg_name;
532
        mPid = pkg_id;
533
        // avoid interaction with real versions
534
        mVersion = "0.0.0000";
535
        mExtension = v_ext;
536
        mAlias = alias;
537
        mTestBuildInstruction = testBuildInstruction;
538
        mTestBuildEmail = email;
539
        mTestBuildVcsTag = pkg_vcs_tag;
540
        mTestBuildPvId = pv_id;
541
        mTestBuildHasAutomatedUnitTests = false;
542
 
543
    }
544
 
545
    /**
546
     * constructor for unit test purposes
547
     */
548
    public Package(ReleaseManager rm, String version, int majorLimit, int minorLimit, int patchLimit, int buildNumberLimit)
549
    {
550
        mId = -1;
551
        mRippleField.setLimit();
552
        mVersion = version;
553
        mMajorLimit = majorLimit;
554
        mMinorLimit = minorLimit;
555
        mPatchLimit = patchLimit;
556
        mBuildLimit = buildNumberLimit;
557
 
558
        if (version.endsWith(".cots"))
559
        {
560
            mExtension = ".cots";
561
            mVersion = version.substring(0, version.length() - 5);
562
            mChangeType.setMajor(false);
563
            mChangeType.setMinor(false);
564
            mChangeType.setPatch(true);
565
            mRippleField.setBuild();
566
        }
567
 
568
        try
569
        {
570
            mId = applyPV(rm, 0);
571
        } catch (Exception e)
572
        {
573
        }
574
    }
575
 
576
    /**
577
     * accessor for unit test purposes
578
     */
579
    public int getId()
580
    {
581
        return mId;
582
    }
583
 
584
    /**
585
     * accessor for unit test purposes
586
     */
587
    public String getVersion()
588
    {
589
        return mVersion;
590
    }
591
 
592
 
593
    /** Set the sequence of all packages in the list
594
     *  Used so that the UnitTestComparator function can preserve the
595
     *  basic ordering of the list 
596
     */
597
    public static void setSequence(ArrayList<Package> al)
598
    {
599
        int seq = 1;
600
        for (Iterator<Package> it = al.iterator(); it.hasNext(); )
601
        {
602
            Package p = it.next();
603
            p.mSeqId = seq++;
604
        }
605
    }
606
 
607
    /** Comparator for sorting unit tests
608
     *      Used to sort a list of packages such that the package with the lowest mTestBuildInstruction
609
     *      is at the head of the list.
610
     *      
611
     *      Packages without a unit test are sorted by mSeqId to preserve the basic 
612
     *      ordering of the list. 
613
     */
614
    public static final Comparator<Package> UnitTestComparator = new Comparator<Package>() {
615
 
616
        /**
617
         * Returns -ve: p1 is less than p2
618
         *           0: p1 = p2
619
         *         +ve: p1 > p2
620
         */
621
        public int compare (Package p1, Package p2) {
622
            // Both are test builds
623
            if (p1.mTestBuildInstruction > 0 && p2.mTestBuildInstruction > 0)
624
                return p1.mTestBuildInstruction - p2.mTestBuildInstruction;
625
 
626
            // Neither is a test build
627
            if (p1.mTestBuildInstruction == 0 && p2.mTestBuildInstruction == 0)
628
                return p1.mSeqId - p2.mSeqId;
629
 
630
            // Only one is a test build
631
            if (p1.mTestBuildInstruction > 0)
632
                return -1;
633
 
634
            return 1;
635
        }
636
    };
637
 
638
    /**
639
     * returns true if mBuildStandardCollection is not empty
640
     */
641
    boolean isReproducible()
642
    {
643
        mLogger.debug("isReproducible on Package " + mName);
644
        boolean retVal = ! mBuildStandardCollection.isEmpty();
645
        mLogger.info("isReproducible returned " + retVal);
646
        return retVal;
647
    }
648
 
649
 
650
    /**
651
     * returns true if at least one of its BuildStandards has mGeneric true
652
     */
653
    boolean isGeneric()
654
    {
655
        mLogger.debug("isGeneric on Package " + mName);
656
        boolean retVal = false;
657
        for (Iterator<BuildStandard> it = mBuildStandardCollection.iterator(); it.hasNext();)
658
        {
659
            BuildStandard buildStandard = it.next();
660
 
661
            if (buildStandard.isGeneric())
662
            {
663
                retVal = true;
664
                break;
665
            }
666
        }
667
 
668
        mLogger.info("isGeneric returned " + retVal);
669
        return retVal;
670
    }
671
 
672
    /**
673
     * Returns true if at least one of the packages build standards can be 
674
     * built in the named machine class. 
675
     *  
676
     * Used to determine if the package can be built with the current buildset 
677
     * by iteration over all machine classes in the buildset. 
678
     */
679
    boolean canBeBuildby(String machineClass)
680
    {
681
        mLogger.debug("canBeBuildby on Package " + mName);
682
        boolean retVal = false;
683
        for (Iterator<BuildStandard> it = mBuildStandardCollection.iterator(); it.hasNext();)
684
        {
685
            BuildStandard buildStandard = it.next();
686
 
687
            if (buildStandard.isGeneric())
688
            {
689
                retVal = true;
690
                break;
691
            }
692
 
693
            if (buildStandard.mMachClass.equals(machineClass))
694
            {
695
                retVal = true;
696
                break;
697
            }
698
        }
699
 
700
        mLogger.info("canBeBuildby returned " + retVal);
701
        return retVal;
702
    }
703
 
704
    /**
705
     * Compare the build standards of two packages 
706
     * Used only in escrow mode 
707
     * Used to compare a package and its dependents (one by one) 
708
     *  
709
     * Returns true if the parent (this) package  can be built in the same escrow 
710
     * build iteration as the dependent package. 
711
     *  
712
     * This is a complex decision and has a few built in assumptions. 
713
     *  
714
     * If the dependent package is 'generic' then the parent package can be built 
715
     *  
716
     * If the parent package is generic then is can only be built if the dependent is 
717
     * also generic. Otherwise we must assume that the parent package is an agregator 
718
     * package and requires artifacts from the dependent package built by all of its 
719
     * required build machines. 
720
     *  
721
     * If both packages are not generic, then if the build standards of the parent and the 
722
     * dependent are identical then 
723
     *  
724
     *      If we have one build standard, we can build the parent in this iteration as
725
     *      the dependent package has been completely built.
726
     *  
727
     *      If we have more than one build standard ( but they are identical ) then we
728
     *      ASSUME that we can build the parent in this iteration. The assumption is that
729
     *      there is no mixing between build machines. ie: Windows consumer users Windows
730
     *      artifacts and the Linux consumer uses Linux artifacts ...
731
     *  
732
     * If both packages are not generic and the build standards are not identical, then 
733
     * things get hard. The safest solution is to assume the parent cannot be built in this 
734
     * iteration. This is not a bad assumption. 
735
     *  
736
     */
737
    boolean haveSameBuildStandards(Package d)
738
    {
739
        HashMap<String, Boolean> standardSet = new HashMap<String, Boolean>();
740
        boolean isGeneric = false;
741
        boolean isGeneric_d = false;
742
        boolean isIdentical = true;
743
 
744
        // Scan the build standards of the parent package and create a hash map for each machine
745
        // class required by the parent. Also determine if the parent is generic.
746
        for (Iterator<BuildStandard> it = mBuildStandardCollection.iterator(); it.hasNext();)
747
        {
748
            BuildStandard bs = it.next();
749
            standardSet.put(bs.mMachClass, false);
750
 
751
            if (bs.isGeneric())
752
            {
753
                isGeneric = true;
754
                break;
755
            }
756
        }
757
 
758
        // Scan the build standards in the dependent package and remove items from the map
759
        // If it was not in the map then the dependent package builds for platforms that the
760
        // parent package does not - thus the build standards cannot be identical
761
        // Also determine if the dependent is generic.
762
        for (Iterator<BuildStandard> it = d.mBuildStandardCollection.iterator(); it.hasNext();)
763
        {
764
            BuildStandard bs = it.next();
765
             if (bs.isGeneric())
766
             {
767
             isGeneric_d = true;
768
             break;
769
             }
770
 
771
            Boolean value = standardSet.remove(bs.mMachClass);
772
            if (value == null)
773
            {
774
                isIdentical = false;
775
                break;
776
            }
777
        }
778
 
779
        //
780
        // If there are any items left in the map then the parent package builds on machines
781
        // that the dependent does not. The two are not identical.
782
 
783
        if (!standardSet.isEmpty())
784
        {
785
            isIdentical = false;
786
        }
787
 
788
        // If dependent is generic, then it will be build on the first platform in this iteration
789
        // All is good
790
 
791
        if( isGeneric_d)
792
            return true;
793
 
794
        //  If I am generic and the dependent is generic, then I can be built at this time
795
        // 
796
        //  Will not reach here as we have already said that if dependenbt is generic, then all is good
797
        //  if (isGeneric_d && isGeneric)
798
        //  {
799
        //      return true;
800
        //  }
801
 
802
 
803
        //  If I am generic then I must wait for ALL dependent to be built on all platforms
804
        //  Thus I can't be built this round
805
        //
806
        if (isGeneric)
807
            return false;
808
 
809
        //
810
        //  If the two sets of build standards don't have generic, BUT are identical
811
        //  the we can assume that there is no cross breading. and that windows bits build from windows bits
812
        //  and solaris bits build from solaris
813
        //
814
        if (isIdentical)
815
            return true;
816
 
817
        //  The two sets of build standards are not an exact match
818
        //  Cheap solution: Assume that I can't be built this round
819
        //  Possible solution: If I am a subset of the dependent - then I can be built
820
        //                     If I am a superset of the dependent - then ???
821
        return false;
822
 
823
    }
824
 
825
    /**
826
     * Applies the required version number change
827
     * 
828
     * @param releaseManager    Release Manager instance to work against
829
     * @param rtag_id           Release Identifier
830
     * 
831
     * @return 0 on success
832
     *         1 on cannot work with non standard versioning
833
     *         2 on ripple field limitations prevent a ripple build
834
     *         3 on Invalid Change Type
835
     * @exception Exception
836
     */
837
    int applyPV(ReleaseManager releaseManager, int rtag_id) throws Exception
838
    {
839
        String logInfo = "applyPV," + mName;
840
        mLogger.debug("applyPV on Package " + mName);
841
        //
842
        // Four scenarios, only applyPV for 3 of them
843
        // mDirectlyPlanned mIndirectlyPlanned mArchivalExistence mForcedRipple
844
        // Action
845
        // WIP/test build exists: true true don't care don't care applyPV
846
        // Package version is out of date: false true true don't care applyPV
847
        // Forced ripple: false true don't care > 0 applyPV
848
        // Package version does not exist: false true false = 0 do not applyPV
849
        //
850
        if (!mDirectlyPlanned && mIndirectlyPlanned && !mArchivalExistence && mForcedRippleInstruction == 0)
851
        {
852
            // the package has an mIndirectlyPlanned flag set true in daemon
853
            // mode because the package does not exist in an archive
854
            // do not apply a different package version
855
            mLogger.info("applyPV. Rebuild Package " + mName);
856
            releaseManager.claimVersion(mPid, mVersion + mExtension, rtag_id);
857
            mLogger.info("applyPv returned 0");
858
            return 0;
859
        }
860
 
861
        // override - no longer doing a rebuild - version number change from this point on
862
        if (mTestBuildInstruction == 0)
863
        {
864
            mRequiresSourceControlInteraction = true;
865
        }
866
 
867
        //	Force test builds to use a sensible version number
868
        if (mTestBuildInstruction > 0 )
869
        {
870
        	mChangeType.resetData();		// Resolve conflict via build numbers
871
        	mRippleField.setBuild();
872
        	mVersion = "99.99.98999";		// Such that rippling build number will goto 99.99.99000
873
        }
874
 
875
        //
876
        // Detect invalid change type
877
        // Flagged when package instance is created
878
        //
879
        if (mChangeType.mUnknown)
880
        {
881
            mLogger.info("Package Version specified on Package " + mName + "New Version:" + mVersion);
882
            mLogger.info("applyPv returned 3");
883
            return 3;
884
        }
885
 
886
        // If we are not calculating the new package version because the user
887
        // has fixed the version of the package. We are given the new package version.
888
        if (mChangeType.mFixed)
889
        {
890
            // mVersion is already setup
891
 
892
            mVersion = mFixedVersion;
893
            mLogger.info("Package Version specified on Package " + mName + "New Version:" + mVersion);
894
            releaseManager.claimVersion(mPid, mVersion + mExtension, rtag_id);
895
            mLogger.info("applyPv returned 0");
896
            return 0;
897
        }
898
 
899
        // We need to calculate the new version number
900
        //
901
        MutableInt major = new MutableInt(0);
902
        MutableInt minor = new MutableInt(0);
903
        MutableInt patch = new MutableInt(1000);
904
 
905
        // Planned packages have a previous version number to be used as the bases for the
906
        // calculation. Ripples won't.
907
        //
908
        if (mPrevVersion != null)
909
        {
910
        	mVersion = mPrevVersion;
911
        }
912
        String[] field = mVersion.split("\\D");
913
        String nonStandardCotsVersion = "";
914
        logInfo += ", Prev:" + mVersion;
915
 
916
        if (field.length == 3)
917
        {
918
            major.value = Integer.parseInt(field[0]);
919
            minor.value = Integer.parseInt(field[1]);
920
            patch.value = Integer.parseInt(field[2]);
921
        } 
922
        else
923
        {
924
            //
925
            // Can ripple a .cots package under very controlled conditions
926
            // Its ends with a .patchBuild field
927
            // Package is marked as ripple via build number
928
            // Change type of Major and Minor are not allowed
929
            //
930
            if (!mChangeType.mMajor && !mChangeType.mMinor && mRippleField.mBuild && mExtension.compareTo(".cots") == 0
931
                    && field.length > 0)
932
            {
933
                // DEVI 52782
934
                // allow and work with (ripple build) versions a.b.c.d....xxxx
935
                // where xxxx.length > 3
936
                String patchStr = field[field.length - 1];
937
                int patchLen = patchStr.length();
938
 
939
                // check patchStr is the last (at least 4) digits
940
                if (patchLen > 3
941
                        && mVersion.substring(mVersion.length() - patchLen, mVersion.length()).compareTo(patchStr) == 0)
942
                {
943
                    patch.value = Integer.parseInt(patchStr);
944
                    nonStandardCotsVersion = mVersion.substring(0, mVersion.length() - patchLen);
945
                }
946
            }
947
 
948
            if (nonStandardCotsVersion.length() == 0)
949
            {
950
                // cannot work with non standard versioning
951
                mLogger.error("applyPV cannot work with non standard versioning");
952
                mLogger.info("applyPv returned 1");
953
                return 1;
954
            }
955
        }
956
 
957
        if (nonStandardCotsVersion.length() == 0 && patch.value < 1000 && field[2].substring(0, 1).compareTo("0") != 0)
958
        {
959
            mLogger.info("applyPV accomodate old style mVersion of the form 1.0.1");
960
            patch.value = patch.value * 1000;
961
        }
962
 
963
        // mChangeType overrides mRippleField
964
        do
965
        {
966
            if (mChangeType.mMajor)
967
            {
968
                logInfo += ",CT Major";
969
                if (!incrementFieldsAccordingToLimits(4, major, minor, patch))
970
                {
971
                    mLogger.info("applyPv returned 2");
972
                    return 2;
973
                }
974
            } else if (mChangeType.mMinor)
975
            {
976
                logInfo += ",CT Minor";
977
                if (!incrementFieldsAccordingToLimits(3, major, minor, patch))
978
                {
979
                    mLogger.info("applyPv returned 2");
980
                    return 2;
981
                }
982
            } else if (mChangeType.mPatch)
983
            {
984
                logInfo += ",CT Patch";
985
                if (!incrementFieldsAccordingToLimits(2, major, minor, patch))
986
                {
987
                    mLogger.info("applyPv returned 2");
988
                    return 2;
989
                }
990
            } else
991
            {
992
                if (mRippleField.mMajor)
993
                {
994
                    logInfo += ",R Major";
995
                    major.value++;
996
                    mLogger.info("applyPV mRippleField.mMajor " + major.value);
997
                    minor.value = 0;
998
                    patch.value = 0;
999
                } else if (mRippleField.mMinor)
1000
                {
1001
                    logInfo += ",R Minor";
1002
                    minor.value++;
1003
                    mLogger.info("applyPV mRippleField.mMinor " + minor.value);
1004
                    patch.value = 0;
1005
                } else if (mRippleField.mPatch)
1006
                {
1007
                    logInfo += ",R Patch";
1008
                    patch.value = ((patch.value / 1000) + 1) * 1000; 
1009
                    mLogger.info("applyPV mRippleField.mPatch " + patch.value);
1010
                } else if (mRippleField.mBuild)
1011
                {
1012
                    logInfo += ", R Build";
1013
                    patch.value++;
1014
                    mLogger.info("applyPV mRippleField.mBuild " + patch.value);
1015
                } else
1016
                {
1017
                    if (!incrementFieldsAccordingToLimits(1, major, minor, patch))
1018
                    {
1019
                        mLogger.info("applyPv returned 2");
1020
                        return 2;
1021
                    }
1022
                }
1023
            }
1024
 
1025
            if (nonStandardCotsVersion.length() == 0)
1026
            {
1027
                mVersion = String.valueOf(major.value) + "." + String.valueOf(minor.value) + ".";
1028
            } else
1029
            {
1030
                mVersion = nonStandardCotsVersion;
1031
            }
1032
 
1033
            if (patch.value < 10)
1034
            {
1035
                mVersion += "000";
1036
            } else if (patch.value < 100)
1037
            {
1038
                mVersion += "00";
1039
            } else if (patch.value < 1000)
1040
            {
1041
                mVersion += "0";
1042
            }
1043
 
1044
            mVersion += String.valueOf(patch.value);
1045
        } while (exists(releaseManager, rtag_id));
1046
 
1047
        logInfo += ", Claim:" + mVersion;
1048
        releaseManager.claimVersion(mPid, mVersion + mExtension, rtag_id);
7033 dpurdie 1049
        mLogger.error(logInfo);
6914 dpurdie 1050
        mLogger.info("applyPv returned 0");
1051
        return 0;
1052
    }
1053
 
1054
    /**
1055
     * increments fields according to mRippleField.mLimit if necessary will
1056
     * apply it to the field passed as follows 1 = build 2 = patch 3 = minor
1057
     * other = major returns true on success false on ripple field limitations
1058
     * prevent a ripple build
1059
     */
1060
    private boolean incrementFieldsAccordingToLimits(int field, MutableInt major, MutableInt minor, MutableInt patch)
1061
    {
1062
        boolean retVal = true;
1063
 
1064
        if (!mChangeType.mLimit && !mRippleField.mLimit)
1065
        {
1066
            // simple case
1067
            // no need to take field limits into consideration
1068
            switch (field)
1069
            {
1070
            case 1:
1071
                // unreachable
1072
                // the only scenario involving build number manipulation
1073
                // involves the mRippleField.mLimit being set
1074
                retVal = false;
1075
                break;
1076
            case 2:
1077
                do
1078
                {
1079
                    patch.value++;
1080
                } while ((patch.value / 1000) * 1000 != patch.value);
1081
                mLogger.info("incrementFieldsAccordingToLimits patch " + patch.value);
1082
                break;
1083
            case 3:
1084
                minor.value++;
1085
                mLogger.info("incrementFieldsAccordingToLimits minor " + minor.value);
1086
                patch.value = 0;
1087
                break;
1088
            default:
1089
                major.value++;
1090
                mLogger.info("incrementFieldsAccordingToLimits major " + major.value);
1091
                minor.value = 0;
1092
                patch.value = 0;
1093
            }
1094
        } else
1095
        {
1096
            // take field limits into consideration
1097
            boolean changeOccurred = false;
1098
            boolean incrementField = true;
1099
 
1100
            switch (field)
1101
            {
1102
            case 1:
1103
                if (mBuildLimit != 0)
1104
                {
1105
                    // increment or reset the patch build number
1106
                    int buildNumber = patch.value - (patch.value / 1000) * 1000;
1107
 
1108
                    if (buildNumber < mBuildLimit)
1109
                    {
1110
                        // can increment the patch build number
1111
                        patch.value++;
1112
                        mLogger.info("incrementFieldsAccordingToLimits mRippleField.mLimit build number " + patch.value);
1113
                        changeOccurred = true;
1114
                        incrementField = false;
1115
                    } else
1116
                    {
1117
                        if (mPatchLimit == 0)
1118
                        {
1119
                            // reset the patch number and patch build number
1120
                            patch.value = 0;
1121
                        }
1122
                    }
1123
                }
1124
                // no break by design
1125
            case 2:
1126
                if (mPatchLimit != 0 && incrementField)
1127
                {
1128
                    // increment or reset the patch number
1129
                    if ((patch.value / 1000) < mPatchLimit)
1130
                    {
1131
                        do
1132
                        {
1133
                            patch.value++;
1134
                        } while ((patch.value / 1000) * 1000 != patch.value);
1135
 
1136
                        mLogger.info("incrementFieldsAccordingToLimits mRippleField.mLimit patch " + patch.value);
1137
                        changeOccurred = true;
1138
                        incrementField = false;
1139
                    } else
1140
                    {
1141
                        // reset the patch number and patch build number
1142
                        patch.value = 0;
1143
                    }
1144
                }
1145
                // no break by design
1146
            case 3:
1147
                if (mMinorLimit != 0 && incrementField)
1148
                {
1149
                    // increment or reset the minor number
1150
                    if (minor.value < mMinorLimit)
1151
                    {
1152
                        minor.value++;
1153
                        patch.value = 0;
1154
                        mLogger.info("incrementFieldsAccordingToLimits mRippleField.mLimit minor " + minor.value);
1155
                        changeOccurred = true;
1156
                        incrementField = false;
1157
                    } else
1158
                    {
1159
                        // reset the minor number
1160
                        minor.value = 0;
1161
                    }
1162
                }
1163
                // no break by design
1164
            default:
1165
                if (mMajorLimit != 0 && incrementField)
1166
                {
1167
                    // increment or reset the major number
1168
                    if (major.value < mMajorLimit)
1169
                    {
1170
                        // increment the major number
1171
                        changeOccurred = true;
1172
                        major.value++;
1173
                        minor.value = 0;
1174
                        patch.value = 0;
1175
                        mLogger.info("incrementFieldsAccordingToLimits mRippleField.mLimit major " + major.value);
1176
                    }
1177
                }
1178
            }
1179
 
1180
            if (!changeOccurred)
1181
            {
1182
                // unable to increment a field due to field limitations
1183
                mLogger.error("incrementFieldsAccordingToLimits ripple field limitations prevent a ripple build");
1184
                mLogger.info("incrementFieldsAccordingToLimits returned false");
1185
                retVal = false;
1186
            }
1187
        }
1188
 
1189
        return retVal;
1190
    }
1191
 
1192
    /**
1193
     * Check if a Package Version exists in dpkg_archive or the Release Manager Database
1194
     * 
1195
     * @param releaseManager Release Manager Instance
1196
     * @param rtag_id        Release Tag Identifier
1197
     * 
1198
     * @return True if the Package Version exists within the Release Manager Database
1199
     * @exception Exception
1200
     */
1201
    private boolean exists(ReleaseManager releaseManager, int rtag_id) throws Exception
1202
    {
1203
        mLogger.debug("exists on Package " + mName + " version " + mVersion + " extension " + mExtension);
1204
        boolean retVal = false;
1205
 
7046 dpurdie 1206
        if (!releaseManager.mUseDatabase)
6914 dpurdie 1207
        {
1208
            mLogger.info("exists !releaseManager.mUseDatabase");
1209
        }
1210
        else
1211
        {
1212
            //  Check Package Archive
1213
            retVal = existsInDpkgArchive();
1214
            if (!retVal)
1215
            {
1216
                //  Check Release Manager Database
1217
                retVal = releaseManager.queryPackageVersions(mPid, mVersion + mExtension);
1218
            }
1219
        }
1220
 
1221
        mLogger.info("exists returned " + retVal);
1222
        return retVal;
1223
    }
1224
 
1225
 
1226
    /**
1227
     * Check to see if a package exists in dpkg_archive
1228
     * 
1229
     * @return true if the version exists in dpkg_archive
1230
     * @exception Exception Thrown if dpkg_archive does not exist. The 'cause' of 'mRecoverable' is special and
1231
     *                      will be trapped later to determine if this is a recoverable exception.
1232
     */
1233
    boolean existsInDpkgArchive() throws Exception
1234
    {
1235
        mLogger.debug("existsInDpkgArchive on " + mName);
1236
        boolean retVal = false;
1237
        String name = utilities.catDir(mName, mVersion + mExtension );
1238
 
1239
        //  If a replica exists, then check it first
1240
        //  If we are configured with a replica its because access to the main archive is slow
1241
        //  and we want this check to be fast
1242
        //
1243
        if (mGbeDpkgReplica != null && mGbeDpkgReplica.length() > 0)
1244
        {
1245
            File dpkg = new File(mGbeDpkgReplica);
1246
            if (!dpkg.exists())
1247
            {
7033 dpurdie 1248
                mLogger.error("existsInDpkgArchive. mGbeDpkgReplica not accessable. " + mRecoverable);
6914 dpurdie 1249
                throw new Exception(mRecoverable);
1250
            }
1251
 
1252
            if( utilities.freshFileExists(utilities.catDir(mGbeDpkgReplica, name) ) )
1253
            {
1254
                mLogger.info("existsInDpkgArchive mGbeDpkgReplica");
1255
                retVal = true;
1256
            }
1257
        }
1258
 
1259
        //  Check (possibly remote) dpkg_archive for files existence if it was not found locally
1260
        //
1261
        if ( !retVal )
1262
        {
1263
 
1264
            //  If the package archive does not exist at the moment, then we have a network issue
1265
            //  This is a recoverable error
1266
 
1267
            File dpkg = new File(mGbeDpkg);
1268
            if (!dpkg.exists())
1269
            {
7033 dpurdie 1270
                mLogger.error("existsInDpkgArchive. mGbeDpkg not accessable. " + mRecoverable);
6914 dpurdie 1271
                throw new Exception(mRecoverable);
1272
            }
1273
 
1274
            if( utilities.freshFileExists(utilities.catDir(mGbeDpkg, name) ) )
1275
            {
1276
                mLogger.info("existsInDpkgArchive mGbeDpkg");
1277
                retVal = true;
1278
            }
1279
        }
1280
 
1281
        mArchivalExistence = retVal;
1282
        mLogger.info("existsInDpkgArchive returned " + retVal);
1283
        return retVal;
1284
    }
1285
 
1286
    /**
1287
     * returns true if the required package archives (dpkg_archive) exist
1288
     * attempt to recover from their transient loss
1289
     */
1290
    public static boolean recover()
1291
    {
1292
        mLogger.debug("recover");
1293
        boolean retVal = false;
1294
 
1295
        String Release = mGbeDpkg;
1296
        if (Release != null)
1297
        {
1298
            if ( utilities.freshFileExists(mGbeDpkg) )
1299
            {
1300
                retVal = true;
7033 dpurdie 1301
                mLogger.error("recover: dpkg_archive access has been restored");
6914 dpurdie 1302
            }
1303
        }
1304
 
1305
        mLogger.info("recover returned " + retVal);
1306
        return retVal;
1307
    }
1308
 
1309
    /**
1310
     * Returns a data structure of unique email addresses
1311
     * Uses the Global Email Collection and the packages own failure email collection
1312
     */
1313
    private LinkedHashSet<String>buildEmailList(RippleEngine rippleEngine)
1314
    {
1315
        //  Create a single list of email targets ensuring only one instance of each email address
1316
        //  ie: Remove duplicates, null and empty strings
1317
        LinkedHashSet<String> hs = new LinkedHashSet<String>();
1318
 
1319
        // Global and Project Wide emails
1320
        for (Iterator<String> it = rippleEngine.mMailGlobalCollection.iterator(); it.hasNext();)
1321
        {
1322
            String item = it.next();
1323
            if (item != null && item.length() > 0) 
1324
            {
1325
                hs.add(item);
1326
            }
1327
        }
1328
 
1329
        // Package specific collection
1330
        for (Iterator<String> it = mBuildFailureEmailCollection.iterator(); it.hasNext();)
1331
        {
1332
            String item = it.next();
1333
            if (item != null && item.length() > 0) 
1334
            {
1335
                hs.add(item);
1336
            }
1337
        }
1338
 
1339
        return hs;
1340
    }
1341
 
1342
    /**
1343
     * Add email information in a form suitable for creating an Ant file
1344
     * @param   rippleEngine    - Ripple Engine Instance
1345
     * @param   xml             - An XmlBuilder element to extend
1346
     */
1347
    void emailInfo(RippleEngine rippleEngine, XmlBuilder xml)
1348
    {
1349
 
1350
        //  Create a single list of email targets ensuring only one instance of each email address
1351
        //  ie: Remove duplicates
1352
        LinkedHashSet<String> hs = buildEmailList(rippleEngine);
1353
 
1354
        for (Iterator<String> it = hs.iterator(); it.hasNext();)
1355
        {
1356
            String email = it.next();
1357
            XmlBuilder entry = xml.addNewElement("owner");
1358
            entry.addAttribute("email", email);
1359
        }
1360
    }
1361
 
1362
    /**
1363
     * Returns email information in a form suitable for direct use
1364
     * @param   rippleEngine Current Release Manager context
1365
     * @return  A comma separated list of user names. May return a 'null' String
1366
     */
1367
    String emailInfoNonAntTask(RippleEngine rippleEngine)
1368
    {
1369
        //  Create a single list of email targets ensuring only one instance of each email address
1370
        //  ie: Remove duplicates
1371
        LinkedHashSet<String> hs = buildEmailList(rippleEngine);
1372
 
1373
        String retVal = null;
1374
        for (Iterator<String> it = hs.iterator(); it.hasNext();)
1375
        {
1376
            String email = it.next();
1377
 
1378
            if (retVal == null)
1379
            {
1380
                retVal = new String();
1381
            } else
1382
            {
1383
                retVal += ",";
1384
            }
1385
            retVal += email;
1386
        }
1387
 
1388
        return retVal;
1389
    }
1390
 
1391
    /**
1392
     * Adds email to mBuildFailureEmailCollection.
1393
     * Do not worry about multiple entries. These will be handled when the data is extracted
1394
     * @param   email   - Email address
1395
     */
1396
    public void addEmail(String email)
1397
    {
1398
        mBuildFailureEmailCollection.add(email);
1399
    }
1400
 
1401
    /**
1402
     * Transfer the Test Build Email information to the packages email list
1403
     */
1404
    void setTestEmail()
1405
    {
1406
        mBuildFailureEmailCollection.clear();
1407
        addEmail(mTestBuildEmail);
1408
    }
1409
 
1410
    /**
1411
     * Transfer the Test Build Dependency information to the packages dependency collection
1412
     */
1413
    void setTestDependencyCollection()
1414
    {
1415
        // does not worry about mPackageDendencyCollection by design
1416
        mDependencyCollection.clear();
1417
 
1418
        for (Iterator<String> it = mTestBuildDependencyCollection.iterator(); it.hasNext();)
1419
        {
1420
            String dependency = it.next();
1421
            mDependencyCollection.add(dependency);
1422
        }
1423
    }
1424
 
1425
    /**
1426
     * Transfer the Test Build Build Standard information to the packages build standard collection
1427
     */
1428
    void setTestBuildStandardCollection()
1429
    {
1430
        mBuildStandardCollection.clear();
1431
 
1432
        for (Iterator<BuildStandard> it = mTestBuildStandardCollection.iterator(); it.hasNext();)
1433
        {
1434
            BuildStandard buildStandard = it.next();
1435
            mBuildStandardCollection.add(buildStandard);
1436
        }
1437
    }
1438
 
1439
    /**
1440
     * End of Processing for a Test Build
1441
     *     - sends email notification
1442
     *     - marks the instruction complete in the database
1443
     */
1444
    public void completeTestBuild(RippleEngine rippleEngine, boolean success) throws SQLException, Exception
1445
    {
1446
        mLogger.debug("completeTestBuild");
1447
 
1448
        if (mTestBuildInstruction == 0)
1449
        {
1450
            mLogger.info("completeTestBuild. Not Build Instruction");
1451
            return;
1452
        }
1453
 
1454
        //  Email Subject
1455
        String subject = (success == true ? "TEST BUILD COMPLETED SUCCESSFULLY" : "TEST BUILD FAILED") 
1456
                + " on package "
1457
                + mAlias;
1458
 
1459
        // Email Body
1460
        String mailBody = "";
1461
        if ( success != true)
1462
        {
1463
            mailBody += "Test build issues are identified in preceding build failure email.<p>"; 
1464
        }
1465
        mailBody += "Release: " + rippleEngine.mBaselineName + "<br>" 
1466
                  + "Package: " + mAlias + "<br>" 
1467
                  + "Rm Ref: " + CreateUrls.generateRmUrl(rippleEngine.getRtagId(), mId) + "<br>" 
1468
                  + "VcsTag: " + mVcsTag + "<br>"
1469
                  + "Build dependencies:<br>";
1470
 
1471
        String indentString = "&nbsp;&nbsp;&nbsp;&nbsp;";
1472
 
1473
        for (Iterator<Package> it3 = mPackageDependencyCollection.iterator(); it3.hasNext();)
1474
        {
1475
            Package depend = it3.next();
1476
 
1477
            String dependsExtension = depend.mExtension;
1478
            String dependsVersion = depend.mVersion;
1479
 
1480
            if (dependsExtension.length() > 0)
1481
            {
1482
                dependsVersion += dependsExtension;
1483
            }
1484
            mailBody += indentString + RippleEngine.quoteString(depend.mName, dependsVersion) + "<br>";
1485
        }
1486
 
1487
        mailBody += "<br>Build standards:<br>";
1488
 
1489
        for (Iterator<BuildStandard> it = mBuildStandardCollection.iterator(); it.hasNext();)
1490
        {
1491
            BuildStandard bs = it.next();
1492
 
1493
            String bsText = bs.getBuildStandardText();
1494
            if (bsText.length() > 0)
1495
            {
1496
                mailBody += indentString + bsText + "<br>";
1497
            }
1498
        }
1499
 
1500
        mailBody += "<p><hr>";
1501
        try
1502
        {
1503
            String target = emailInfoNonAntTask(rippleEngine);
7033 dpurdie 1504
            mLogger.error("completeTestBuildEmail Server: " + rippleEngine.getMailServer());
1505
            mLogger.error("completeTestBuildEmail Sender: " + rippleEngine.getMailSender());
1506
            mLogger.error("completeTestBuildEmail Target: " + target);
6914 dpurdie 1507
 
1508
            Smtpsend.send(rippleEngine.getMailServer(), // mailServer
1509
                    rippleEngine.getMailSender(),       // source
1510
                    target,                         // target
1511
                    rippleEngine.getMailSender(),       // cc
1512
                    null,                           // bcc
1513
                    subject,                        // subject
1514
                    mailBody,                       // body
1515
                    null                            // attachment
1516
            );
1517
        } catch (Exception e)
1518
        {
1519
            mLogger.warn("Email Failure: completeTestBuild:" + e.getMessage());
1520
        }
1521
 
1522
        // Update the Release Manager Database
1523
        rippleEngine.mReleaseManager.markDaemonInstCompleted(mTestBuildInstruction);
7033 dpurdie 1524
        mLogger.error("completeTest. Returning");
6914 dpurdie 1525
    }
1526
 
1527
 
1528
    /**
1529
     * Returns true if the package is a part of a circular dependency
1530
     * 
1531
     * If the package depends on a package with a circular dependency then the function
1532
     * will return false.
1533
     */
1534
    public boolean hasCircularDependency(RippleEngine ripEng)
1535
    {
1536
        mLogger.debug("hasCircularDependency: " + mAlias);
1537
        boolean retVal = detectCircularDependency(mAlias, ripEng, null);
1538
        mLogger.info("hasCircularDependency returned " + retVal);
1539
        return retVal;
1540
    }
1541
 
1542
    /**
1543
     * Returns true is a part of a circular dependency
1544
     * Will examine all the packages sub dependencies and mark those that do have a
1545
     * circular dependency.
1546
     * 
1547
     * This process works by descending the dependency tree and dropping a bread crumb
1548
     * If the bread crumb is seen during the decent, then a circle has been detected and
1549
     * the package (with the bread crumb) will be marked as having a circular dependency
1550
     * 
1551
     *  Assumes that the caller will walk ALL packages and flag those with a circular
1552
     *  dependence AND those that depend on that package.
1553
     * 
1554
     */
1555
    private boolean detectCircularDependency(String alias, RippleEngine ripEng, Package parent)
1556
    {
1557
        mLogger.debug("detectCircularDependency");
1558
        boolean retVal = false;
1559
 
1560
        // if this package has yet to be checked for circular dependency
1561
        if (!mCheckedCircularDependency)
1562
        {
1563
            // Will be set as we drill down through dependencies
1564
            // If we see this marker (bread crumb) then we have a loop
1565
            if (mBreadCrumb != 0)
1566
            {
1567
                mBreadCrumb = 3;
1568
 
1569
                mHasCircularDependency = true;
1570
                if(parent != null && parent.mBreadCrumb != 3 )
1571
                {
1572
                    parent.mBreadCrumb = 2;
1573
                }
1574
            }
1575
            else
1576
            {
1577
                // Mark this package as potentially having a circular dependency
1578
                // Will now drill down and see if we hit a marker
1579
                mBreadCrumb = 1;
1580
 
1581
                // Recurse down the dependencies and sub dependencies
1582
                for (Iterator<String> it2 = mDependencyCollection.iterator(); it2.hasNext();)
1583
                {
1584
                    String dependencyAlias = it2.next();
1585
                    Package dependency = ripEng.findPackage(dependencyAlias);
1586
                    dependency.detectCircularDependency(alias, ripEng, this);
1587
                }
1588
 
1589
                if (mBreadCrumb == 2)
1590
                {
1591
                    mHasCircularDependency = true;
1592
                    if(parent != null && parent.mBreadCrumb != 3 )
1593
                    {
1594
                        parent.mBreadCrumb = 2;
1595
                    }
1596
                }
1597
                mBreadCrumb = 0;
1598
            }
1599
 
1600
            // Flag package as having been examined
1601
            mCheckedCircularDependency = true;
1602
        } 
1603
 
1604
        // return the persisted circular dependency outcome
1605
        retVal = mHasCircularDependency;
1606
        mLogger.info("detectCircularDependency 2 returned " + retVal);
1607
        return retVal;
1608
    }
1609
 
1610
    /**
1611
     * entity class supporting the ERG version numbering standard:
1612
     * <major>.<minor>.<patch/build> patch/build is at least a 4 digit number
1613
     * whose last 3 digits represent the build
1614
     */
1615
    public class VersionNumberingStandard
1616
    {
1617
        /**
1618
         * in terms of the mChangeType Package field, when true indicates the
1619
         * contract of the package has changed in a non backwardly compatible
1620
         * manner in terms of the mRippleField Package field, when true indicates
1621
         * the major version number will be incremented
1622
         * 
1623
         * @attribute
1624
         */
1625
        private boolean mMajor = false;
1626
 
1627
        /**
1628
         * in terms of the mChangeType Package field, when true indicates the
1629
         * contract of the package has changed in a backwardly compatible manner
1630
         * in terms of the mRippleField Package field, when true indicates the
1631
         * minor version number will be incremented
1632
         * 
1633
         * @attribute
1634
         */
1635
        private boolean mMinor = false;
1636
 
1637
        /**
1638
         * in terms of the mChangeType Package field, when true indicates the
1639
         * contract of the package has not changed, but the package has changed
1640
         * internally in terms of the mRippleField Package field, when true
1641
         * indicates the minor version number will be incremented
1642
         * 
1643
         * @attribute
1644
         */
1645
        private boolean mPatch = false;
1646
 
1647
        /**
1648
         * in terms of the mChangeType Package field, when true indicates the
1649
         * package has not changed, its dependencies potentially have in terms
1650
         * of the mRippleField Package field, when true indicates the build
1651
         * number will be incremented
1652
         * 
1653
         * @attribute
1654
         */
1655
        private boolean mBuild = true;
1656
 
1657
        /**
1658
         * in terms of the mChangeType Package field, when true indicates the
1659
         * major, minor, and patch number will be incremented according to field
1660
         * limits in terms of the mRippleField Package field, when true indicates
1661
         * the major, minor, patch and build number will be incremented
1662
         * according to field limits
1663
         * 
1664
         * @attribute
1665
         */
1666
        private boolean mLimit = false;
1667
 
1668
        /**
1669
         * in terms of the mChangeType Package field, when true indicates the
1670
         * package version number will not be rippled. The user will have fixed
1671
         * the version number. This is only application to WIP packages
1672
         * 
1673
         * @attribute
1674
         */
1675
        private boolean mFixed = false;
1676
 
1677
        /**
1678
         * in terms of the mChangeType Package field, when true indicates the
1679
         * method of rippling a package version number is not known.
1680
         * 
1681
         * @attribute
1682
         */
1683
        private boolean mUnknown = false;
1684
 
1685
        /**
1686
         * constructor
1687
         */
1688
        private VersionNumberingStandard()
1689
        {
1690
            mLogger.debug("VersionNumberingStandard");
1691
        }
1692
 
1693
        /**
1694
         * Reset all values to a known state
1695
         * 
1696
         */
1697
        void resetData()
1698
        {
1699
            mBuild = false;
1700
            mMajor = false;
1701
            mMinor = false;
1702
            mPatch = false;
1703
            mLimit = false;
1704
            mFixed = false;
1705
            mUnknown = false;
1706
        }
1707
 
1708
        /**
1709
         * sets mBuild true, mMajor false, mMinor false, mPatch false, mLimit
1710
         * false
1711
         */
1712
        void setBuild()
1713
        {
1714
            mLogger.debug("setBuild");
1715
            resetData();
1716
            mBuild = true;
1717
        }
1718
 
1719
        /**
1720
         * sets mBuild false, mMajor true, mMinor false, mPatch false, mLimit
1721
         * false
1722
         */
1723
        void setMajor()
1724
        {
1725
            mLogger.debug("setMajor");
1726
            resetData();
1727
            mMajor = true;
1728
        }
1729
 
1730
        /**
1731
         * sets mBuild false, mMajor true, mMinor false, mPatch false, mLimit
1732
         * limit
1733
         */
1734
        void setMajor(boolean limit)
1735
        {
1736
            mLogger.debug("setMajor " + limit);
1737
            resetData();
1738
            mMajor = true;
1739
            mLimit = limit;
1740
        }
1741
 
1742
        /**
1743
         * sets mBuild false, mMajor false, mMinor true, mPatch false, mLimit
1744
         * false
1745
         */
1746
        void setMinor()
1747
        {
1748
            mLogger.debug("setMinor");
1749
            resetData();
1750
            mMinor = true;
1751
        }
1752
 
1753
        /**
1754
         * sets mBuild false, mMajor false, mMinor true, mPatch false, mLimit
1755
         * limit
1756
         */
1757
        void setMinor(boolean limit)
1758
        {
1759
            mLogger.debug("setMinor " + limit);
1760
            resetData();
1761
            mMinor = true;
1762
            mLimit = limit;
1763
        }
1764
 
1765
        /**
1766
         * sets mBuild false, mMajor false, mMinor false, mPatch true, mLimit
1767
         * false
1768
         */
1769
        void setPatch()
1770
        {
1771
            mLogger.debug("setPatch");
1772
            resetData();
1773
            mPatch = true;
1774
        }
1775
 
1776
        /**
1777
         * sets mBuild false, mMajor false, mMinor false, mPatch true, mLimit
1778
         * limit
1779
         */
1780
        void setPatch(boolean limit)
1781
        {
1782
            mLogger.debug("setPatch");
1783
            resetData();
1784
            mPatch = true;
1785
            mLimit = limit;
1786
        }
1787
 
1788
        /**
1789
         * sets mBuild false, mMajor false, mMinor false, mPatch false, mLimit
1790
         * true
1791
         */
1792
        void setLimit()
1793
        {
1794
            mLogger.debug("setPatch");
1795
            resetData();
1796
            mLimit = true;
1797
        }
1798
 
1799
        /**
1800
         * sets parameters to indicate that the change type is Fixed. The
1801
         * version number is set by the user and a ripple will not be calculated
1802
         */
1803
        void setFixed()
1804
        {
1805
            mLogger.debug("setFixed");
1806
            resetData();
1807
            mFixed = true;
1808
        }
1809
 
1810
        /**
1811
         * Sets parameters to indicate that the change type is not known
1812
         * 
1813
         */
1814
        void setUnknown()
1815
        {
1816
            resetData();
1817
            mUnknown = true;
1818
        }
1819
 
1820
    }
1821
 
1822
}