Subversion Repositories DevTools

Rev

Rev 5709 | Blame | Compare with Previous | Last modification | View Log | RSS feed

########################################################################
# COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.
#
# Module name   : cc2svn_procdata.pl
# Module type   : Makefile system
# Compiler(s)   : Perl
# Environment(s): jats
#
# Description   : Get all packages that are used in all releases
#                 Post process data collected in 23a
#
#
#......................................................................#

require 5.006_001;
use strict;
use warnings;
use JatsError;
use JatsEnv;
use JatsSystem;
use Getopt::Long;
use Pod::Usage;                             # required for help support
use JatsRmApi;
use ConfigurationFile;
use HTML::Table;
use JatsSvn;

use DBI;
our $GBE_RM_URL;
our $GBE_DM_URL;

my $VERSION = "1.2.3";                      # Update this
my $opt_verbose = 1;
my $opt_help = 0;
my $opt_manual;
my $opt_usedby;
my $opt_allpackages;

#
#   Package information
#
our %ScmReleases;
our %ScmPackages;
our %ScmPkgNames;
our %ScmSuffixes;
our %ScmAllPackages;
our %ScmAllBomProjects;
our %ScmSboms;
our %Protected;

################################################################################
#   Data structure to help create links in all the files
#       BadVcs_$pvid
#       Repo_$repo
#       Package_$name
#
my $currentSection;
my %htmlData = (
    S0 =>  {file => 'PackageConversion.html'                  , title => 'Master Index'                     , tag => '', 'noHeader' => 0 },
    S1 =>  {file => 'PackageConversion_IR.html'               , title => 'Inlcuded Releases'                , tag => '' },
    S2 =>  {file => 'PackageConversion_ER.html'               , title => 'Excluded Releases'                , tag => '' },
    S3 =>  {file => 'PackageConversion_PkgIndex.html'         , title => 'Complete Package Index'           , tag => '' },
    S4 =>  {file => 'PackageConversion_PkgDetails.html'       , title => 'Package Conversion Details'       , tag => 'Package' },
    S5 =>  {file => 'PackageConversion_BadVersions.html'      , title => 'Bad Package Versions'             , tag => 'BadVcs' },
    S6 =>  {file => 'PackageConversion_BadVersionsPrj.html'   , title => 'Bad Package Versions By Project'  , tag => '' },
    S7 =>  {file => 'PackageConversion_MultiplePackages.html' , title => 'MultiplePackages'                 , tag => '' },
    S8 =>  {file => 'PackageConversion_RepoIndex.html'        , title => 'Repository Index'                 , tag => '' },
    S9 =>  {file => 'PackageConversion_RepoMap.html'          , title => 'Repository Mapping'               , tag => 'Repo' },
    SA =>  {file => 'PackageConversion_unMapped.html'         , title => 'Unmapped Packages'                , tag => '' },
    SB =>  {file => 'PackageConversion_SvnPkgs.html'          , title => 'Packages in Subversion'           , tag => '' },
    SC =>  {file => 'PackageConversion_NonSvnPkgs.html'       , title => 'Packages not in Subversion'       , tag => '' },
    SD =>  {file => 'PackageConversion_Issues.html'           , title => 'Packages with known issues'       , tag => '' },
);

#-------------------------------------------------------------------------------
# Function        : Main Entry
#
# Description     :
#
# Inputs          :
#
# Returns         :
#
my $result = GetOptions (
                "help+"         => \$opt_help,          # flag, multiple use allowed
                "manual"        => \$opt_manual,        # flag
                "verbose+"      => \$opt_verbose,       # flag
                "usedby:s"      => \$opt_usedby,        # pvid used by which releases
                'allpackages+'  => \$opt_allpackages
                );

#
#   Process help and manual options
#
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
pod2usage(-verbose => 1)  if ($opt_help == 2 );
pod2usage(-verbose => 2)  if ($opt_manual || ($opt_help > 2));


ErrorConfig( 'name'    =>'CC2SVN_PROCDATA' );
readInputData();

#
#   Report Releases that use a package
#
if ( $opt_usedby )
{
    foreach my $pvid ($opt_usedby , @ARGV )
    {
        my ($releases, $ireleases) = usedBy($pvid);
        my (@text, @itext);

        foreach ( sort {$ScmReleases{$a}{name} cmp $ScmReleases{$b}{name} } @$releases )
        {
            push @text, "$ScmReleases{$_}{pName} :: $ScmReleases{$_}{name}";
        }

        foreach ( @$ireleases )
        {
            push @text, "$ScmReleases{$_}{pName} :: $ScmReleases{$_}{name}";
        }

        unshift @text  ,"Used Directly by:" if ( @text );
        unshift @itext ,"Used Indirectly by:" if ( @itext );
        Message("Package: $ScmPackages{$pvid}{'name'} Version: $ScmPackages{$pvid}{'version'}", @text, @itext);
    }
    exit 0;
}

##
##   Generate a list of essential package-versions
##
#{
#    my $file = "EssentialPackages.txt";
#    my $count = 0;
#    Message("Create Essential Package List", $file);
#    open ( my $fh, '>', $file ) || Error ("Cannot open $file", "Error: $!");
#    foreach ( sort { $a <=> $b } keys %ScmPackages )
#    {
#        print $fh "$_\n";
#        $count++;
#    }
#    close $fh;
#    Message("Essential Packages: $count");
#}

#
#   Attempt to classify each package
#   Create a structure for each package
#
my %PackageSet;
my %PackageData;
my %Views;
my %Vobs;
my %ReleasePackages;

getBadLabelData();
getProtectedPackages();

#
#   Remove packages that we don't need
#
my $deleteCount = keys %ScmPackages;
unless ( $opt_allpackages )
{
    foreach ( keys %ScmPackages )
    {
        next if ( $ScmPackages{$_}{NamedProject} );
        delete $ScmPackages{$_};
    }
}

Message ("Create Package Sets");
my $badCount = 0;
foreach ( keys %ScmPackages )
{
    my $pkgid = $ScmPackages{$_}{pkgid};
    unless ( $pkgid )
    {
        $badCount++;
        next;
    }

    push @{$PackageSet{$pkgid}}, $_;
    $ScmPkgNames{$ScmPackages{$_}{name}} = $pkgid;

    my ($vob, $path) = extractVob($_);
    if ($vob)
    {
        next if ( $ScmPackages{$_}{BadVob} );
        $Vobs{$vob}++;
        push @{$PackageData{$pkgid}{vobs}{$vob}}, $_ ;
        push @{$PackageData{$pkgid}{vobPath}{$path}}, $_  if ($path);
        $PackageData{$pkgid}{vobResolver}{$vob} = $path;

        if ( $vob eq 'SVN' )
        {
            delete $ScmPackages{$_}{BadCCView} ;
        }
    }

    my $view = $ScmPackages{$_}{view};
    if ( $view )
    {
        foreach my $v ( keys %{$view} )
        {
            my $saneName = $v;
            $saneName = 'PRODUCTS' if ( $v eq 'AUTO_PRODUCTS' );
            $saneName = 'COTS' if ( $v eq '3RDPARTY_PRODUCTS' );
            next if ( $v eq 'MISC' );
            $Views{$saneName}++;
            $PackageData{$pkgid}{view}{$saneName} += $view->{$v};
        }
    }

    #
    #   Find youngest package
    #       - Most recently modified
    #       - Not a ripple
    #       - Not created by buildadm (3768)
    #
    if ( (! exists $PackageData{$pkgid}{youngAge} ) || ( $ScmPackages{$_}{Age} < $PackageData{$pkgid}{youngAge} ) )
    {
        $PackageData{$pkgid}{youngAge} = $ScmPackages{$_}{Age};
    }

    if ( (! exists $PackageData{$pkgid}{youngAgeNonRipple} ) || ( $ScmPackages{$_}{Age} < $PackageData{$pkgid}{youngAgeNonRipple} ) )
    {
        unless ( $ScmPackages{$_}{isaRipple} )
        {
            $PackageData{$pkgid}{youngAgeNonRipple} = $ScmPackages{$_}{Age};
        }
    }

    if ( (! exists $PackageData{$pkgid}{nonBuildadm} ) || ( $ScmPackages{$_}{Age} < $PackageData{$pkgid}{nonBuildadm} ) )
    {
        unless ( $ScmPackages{$_}{Creator} == '3768' )
        {
            $PackageData{$pkgid}{nonBuildadm} = $ScmPackages{$_}{Age};
        }
    }
    

    $PackageData{$pkgid}{name} = $ScmPackages{$_}{name} ;

    #
    #   Accumulate Release data
    #
    my $mname = $ScmPackages{$_}{'name'} . ($ScmPackages{$_}{'suffix'} || '');
    my $name = $ScmPackages{$_}{'name'};
    foreach my $rtag_id ( @{$ScmPackages{$_}{'release'}} )
    {
        unless ( $ScmReleases{$rtag_id}{'excluded'} )
        {
            $ReleasePackages{$rtag_id}{mname}{$mname}{count}++;
            $ReleasePackages{$rtag_id}{name}{$name}{count}++;
            push @{$ReleasePackages{$rtag_id}{mname}{$mname}{pvid}}, $_;
            push @{$ReleasePackages{$rtag_id}{name}{$name}{pvid}}, $_ ;
        }
    }
}
Warning ("Bad Package Data entries: " . $badCount ) if $badCount;

#
#   Tag packages with BadVob and MultiVob
#
foreach my $pkgid ( keys %PackageSet )
{
    ($PackageData{$pkgid}{type}, @{$PackageData{$pkgid}{suffixes}} ) = smartPackageType ($pkgid);
    my @vobs = keys %{$PackageData{$pkgid}{vobs}};
#    $PackageData{$pkgid}{isSVN} = 1 if ( @vobs == 1 && $vobs[0] eq 'SVN' );
#    $PackageData{$pkgid}{isSVN} = 1 if ( (exists ($PackageData{$pkgid}{vobs}{SVN})) && $PackageData{$pkgid}{vobs}{SVN});



    $PackageData{$pkgid}{isSVN} = 1 if ( exists $ScmAllPackages{$pkgid} && $ScmAllPackages{$pkgid}{inSvn} );
    $PackageData{$pkgid}{MultiVob} = 1 if ( @vobs > 1 );
    $PackageData{$pkgid}{BadVob} = 1 if ( grep {$_ eq 'BAD'} @vobs   );
}

#
#   Map packages into Repos
#
my %Repos_lowercase;
my %Repos;
my %RepoSubIndex;
Message ("Mapping Vobs to Repo");
foreach my $pkgid ( keys %PackageSet )
{
    my $repo = mapPackage($pkgid);
    Error ("Unmapped package: $PackageData{$pkgid}{name}" ) unless ( $repo );

    my $repo_lc = lc $repo;

    if (exists $Repos_lowercase{$repo_lc} && $Repos_lowercase{$repo_lc} ne $repo )
    {
        Error ("Package mapping: Mapped to Repo with same name, but different case",
               "Package: $PackageData{$pkgid}{name}",
               "Mapped repo   : $repo",
               "Already mapped: $Repos_lowercase{$repo_lc}");
    }

    $Repos_lowercase{$repo_lc} = $repo;
    $PackageData{$pkgid}{mappedRepo} = $repo;
    push @{$Repos{$repo}}, $pkgid;

    if ( $repo eq 'SVN' )
    {
        my %RepoList;
        foreach my $pvid ( @{$PackageSet{$pkgid}} )
        {
            my $repo = $ScmPackages{$pvid}{'vcstag'};
            if ( $repo =~ m~SVN::AUPERASVN01/(.*)/(.*?)(/tags/|/branches/|/trunk)~i )
            {
                my $repo = $1;
                unless( exists $RepoList{$repo} )
                {
                    $RepoList{$repo} = 1 ;
                    $PackageData{$pkgid}{mappedRepo} = $repo;
                    push @{$Repos{$repo}}, $pkgid;
                }
            }
        }

    }
}

foreach ( keys %Repos )
{
    @{$Repos{$_}} = sort{ uc($PackageData{$a}{name}) cmp uc($PackageData{$b}{name}) } @{$Repos{$_}};
    my $base = $_;
    my $index = '-';
    if (m~^(.*?)/(.*)~ )
    {
        $base = $1;
        $index = $2;
    }
    push @{$RepoSubIndex{$base}{$index}}, @{$Repos{$_}};
    @{$Repos{$base}} = () unless ( exists $Repos{$base} );
}
#DebugDumpData("RepoSubIndex", \%RepoSubIndex);
#DebugDumpData("Repos", \%Repos);

#
#   Create a list of Packages
#
my $totalPackageCount = 0;
{
    my $file = "PackageNames.txt";
    Message("Create Package Name List", $file);
    open ( my $fh, '>', $file ) || Error ("Cannot open $file", "Error: $!");

    foreach ( sort {$PackageData{$a}{name} cmp $PackageData{$b}{name} } keys %PackageData )
    {
        print $fh "$PackageData{$_}{name}\n";
        $totalPackageCount++;

    }
    close $fh;
    Message("Unique Package Names: $totalPackageCount");
#    DebugDumpData("PackageData", \%PackageData);
}

#
#   Determine Releases that have multiple versions of a package
#   ie: xxxx.cr and xxxxx.ssw
#



##=pod
###
###   Display MutiVob Packages
###
##    foreach my $pkgid (  keys %PackageData )
##    {
##        next unless ( $PackageData{$pkgid}{MultiVob}  );
##        Message("Multi VOB package: $PackageData{$pkgid}{name}");
##        foreach my $vob ( keys %{$PackageData{$pkgid}{vobs}} )
##        {
##            Message("    $vob");
##            foreach my $pvid ( @{$PackageData{$pkgid}{vobs}{$vob}} )
##            {
##                Message ("        $ScmPackages{$pvid}{'version'}, $ScmPackages{$pvid}{'vcstag'}");
##            }
##        }
###DebugDumpData("DATA",$PackageData{$pkgid} );
##    }
##=cut

##=pod
##    foreach my $pkgid (  keys %PackageData )
##    {
##        next unless ( $PackageData{$pkgid}{isSVN}  );
##        Message("Fully SVN Converted: $PackageData{$pkgid}{name}");
##    }
##=cut
    
##=pod
##    my @BadTags;
##    foreach my $pvid (  keys %ScmPackages )
##    {
##        next unless ( $ScmPackages{$pvid}{BadVob}  );
##        push @BadTags, $pvid;
##    }
##
##    Message("Bad VcsTag packages: ". scalar @BadTags);
##    foreach my $pvid ( @BadTags )
##    {
##        Message ("    $pvid, $ScmPackages{$pvid}{'name'}, $ScmPackages{$pvid}{'version'}, $ScmPackages{$pvid}{'vcstag'}");
##    }
##=cut

    generateHTML();
    generateImportData();
    exit 0;

#-------------------------------------------------------------------------------
# Function        : generateImportData
#
# Description     : Generate data to be used by the importPackage util.
#                   Will provide Target Repo
#
# Inputs          : Nothing
#
# Returns         : 
#
sub generateImportData
{
    my %Data;
    Message("Generate Data for utilties");
    {
        my $file = "cc2svn.repo.txt";
        Message ("Create: $file");
        my $fh = ConfigurationFile::New( $file );

        foreach my $pkgid ( sort {$PackageData{$a}{name} cmp $PackageData{$b}{name} } keys %PackageData )
        {
            my $repo = $PackageData{$pkgid}{mappedRepo};
            my $name = $PackageData{$pkgid}{name};
            my $svn = $PackageData{$pkgid}{isSVN} ? 'SVN' : '---';

            my $youngest = $PackageData{$pkgid}{youngAge};
            my $youngestNonRipple = $PackageData{$pkgid}{youngAgeNonRipple} || 0;
            my $youngestNonBuildadm = $PackageData{$pkgid}{nonBuildadm} || 0;

            $youngest =  int($youngest);
            $youngestNonRipple =  int($youngestNonRipple) || '9999';
            $youngestNonBuildadm = int($youngestNonBuildadm) || '9999';

            my $txt = sprintf ("Last:%5d, User:%5d, NonR:%5d, $svn", $youngest, $youngestNonBuildadm, $youngestNonRipple);
           $txt .= sprintf (" :: %40s -repo=%s", $name, $repo );
            $fh->WriteLn($txt);

            #
            #   Save in a readable form too
            #
            $Data{$name}{repo} = $repo;
            $Data{$name}{SVN} = 1 if $PackageData{$pkgid}{isSVN};
            $Data{$name}{youngest} = $youngest;
            $Data{$name}{ynr} = $youngestNonRipple;
            $Data{$name}{ynb} = $youngestNonBuildadm;
            $Data{$name}{protected} = $Protected{$PackageData{$pkgid}{name}}{mode} if exists $Protected{$PackageData{$pkgid}{name}};
        }
        $fh->Close();
    }

    my $file = "cc2svn.repo.dat";
    Message ("Create: $file");
    my $fh = ConfigurationFile::New( $file );
    $fh->DumpData(
        "\n# Repo Mapping.\n#\n",
        "ScmRepoMap", \%Data );

    $fh->Close();
}

#-------------------------------------------------------------------------------
# Function        : generateHTMLHeader
#
# Description     : Create an HTML Header
#
# Inputs          : $section        - Section tag
#
# Returns         : Handle to use
#
sub generateHTMLHeader
{
    my ($section) = @_;
    my $handle;

    Error ("Bad HTML section id: $section") unless ( exists $htmlData{$section} );
    $currentSection = $section;
    my $fname = $htmlData{$section}{file};
    my $title = $htmlData{$section}{title};
    Message("Generating: $title");

    open ($handle, '>', $fname) || Error ("Cannot create HTML: $fname");
    print $handle <<"HEADER";
<!DOCTYPE $handle PUBLIC "-//W3C//DTD $handle 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>$title</title>
<script type="text/javascript">
function click_expandingMenuHeader(obj,sectionName)
{ 
var x=document.getElementById("cssprop_" + sectionName).parentNode.className;
if (x.indexOf("expandingMenuNotSelected")>-1)
        {
        x=x.replace("expandingMenuNotSelected","expandingMenuSelected");
        document.getElementById("cssprop_" + sectionName).parentNode.className=x;
        document.getElementById("cssprop_" + sectionName).style.display="block";
        }
else
        {
        x=x.replace("expandingMenuSelected","expandingMenuNotSelected");
        document.getElementById("cssprop_" + sectionName).parentNode.className=x;
        document.getElementById("cssprop_" + sectionName).style.display="none";
        }
}

function flipStyleByName(style, prop, val, val2)
{
    var mysheet=document.styleSheets[0];
    var myrules=mysheet.cssRules? mysheet.cssRules: mysheet.rules
    for (i=0; i<myrules.length; i++)
    {
        if(myrules[i].selectorText.toLowerCase()==style)
        {
            targetrule=myrules[i];

            targetflag = 'ddpStuff.' + style
            targetrule[targetflag] = ! targetrule[targetflag];
            val = targetrule[targetflag] ? val : val2;

            targetrule.style.setProperty(prop, val,'important');
            break;
        }
    }
}

</script>
<style TYPE="text/css">

.nonEssential {}
.essential {}

.expandingMenu
{
xwidth:165px;
overflow:hidden;
}

.expandingMenuHeader
{
padding-left:12px;
margin-bottom:2px;
cursor:pointer;
}

.expandingMenuItem
{
width:145px;
padding-left:12px;
margin-bottom:3px;
}

.expandingMenuGroup {
xwidth:160px;
border:1px solid #d4d4d4;
margin-bottom:4px;
padding-top:4px;
padding-bottom:4px;
background-color:#f8f8f8;
}

.expandingMenuSelected {
background-image:url(http://www.w3schools.com/images/minus_arrow.gif);
background-repeat:no-repeat;
background-position:1px 3px;
}

.expandingMenuNotSelected {
background-image:url(http://www.w3schools.com//images/plus_arrow.gif);
background-repeat:no-repeat;
background-position:1px 3px;
}

.packageTitle {
    background-color:#FFFF99;
}

.listTitle {
    text-align:left;
    vertical-align:top;
}

.paddedTable {
    border-spacing: 10px 0px;
}
</style>
</head>

HEADER
    print $handle "<body>\n";
    print $handle "<p>Generated: " . localtime() . "\n";

    #
    #   Generate an index
    #
    print $handle htmlH1(anchor("Index", 'Index'));

    print $handle "<dl>";
    foreach my $section ( sort keys %htmlData )
    {
        my $fname = $htmlData{$section}{file};
        my $title = $htmlData{$section}{title};
        
        print $handle "<dd>" . hRef("$fname"            ,$title);

    }
    print $handle "</dl>\n";

    unless ( $htmlData{$section}{noHeader} )
    {
        print $handle htmlH1('<hr>' . $title);
    }

    return $handle;
}

#-------------------------------------------------------------------------------
# Function        : generateHTMLTail
#
# Description     : 
#
# Inputs          : 
#
# Returns         : 
#
sub generateHTMLTail
{
    my ($handle) = @_;
    print $handle "</body>\n";
    print $handle "</html>\n";
    close $handle;

    $currentSection = '';
}


#-------------------------------------------------------------------------------
# Function        : generateHTML
#
# Description     : 
#                   Create per package data
#                   Create a nice HTML file so that it can be hyperlinked
#
# Inputs          : 
#
# Returns         : 
#

sub generateHTML
{
    my @PackageOrder;
    EnvImport('GBE_RM_URL');
    EnvImport('GBE_DM_URL');
    my $t;
    Message("Generate HTML");
    my $HTML = generateHTMLHeader ('S0');
    print $HTML "This page is a simple index into the other pages that contain the Clearcase to Subversion converstion details.\n";

    #
    #   BOM Projects
    #
#    {
#        print $HTML header('BOMIndex', 'Included BOM Projects');
#        print $HTML "BOM Projects included in processing. All branches and and SBOMS scanned for essential packages and versions\n";
#
#        print $HTML "<dl>\n";
#        foreach my $project_id ( sort {$ScmAllBomProjects{$a}{project_name} cmp $ScmAllBomProjects{$b}{project_name} } keys %ScmAllBomProjects )
#        {
#            print $HTML "<dd>" . linkBomProject($project_id,$ScmAllBomProjects{$project_id}{project_name});
#        }
#        print $HTML "</dl>\n";
#    }

    #
    #   Release List
    #
    my %Projects;
    push @{$Projects{$ScmReleases{$_}{'pName'}}}, $_ foreach ( keys %ScmReleases );


    $HTML = generateHTMLHeader ('S1');
    print $HTML "Releases that will be considered in the conversion process.\n";
    print $HTML "<br>Releases are scanned for packages and versions that are used.\n";
    print $HTML "<dl>\n";
    foreach ( sort keys %Projects )
    {
        foreach my $rtagid ( sort {$ScmReleases{$a}{name} cmp $ScmReleases{$b}{name}} @{$Projects{$_}} )
        {
            next if ( $ScmReleases{$rtagid}{'excluded'} );
            print $HTML "<dd>" . linkRelease($rtagid);
        }
    }
    print $HTML "</dl>\n";
    generateHTMLTail($HTML);


    $HTML = generateHTMLHeader ('S2');
    print $HTML "Releases that will NOT be considered in the conversion process. These are releases that have been specificly excluded.\n";
    print $HTML "<dl>\n";
    foreach ( sort keys %Projects )
    {
        foreach my $rtagid ( sort {$ScmReleases{$a}{name} cmp $ScmReleases{$b}{name}} @{$Projects{$_}} )
        {
            next unless ( $ScmReleases{$rtagid}{'excluded'} );
            print $HTML "<dd>" . linkRelease($rtagid);
        }
    }
    print $HTML "</dl>\n";
    generateHTMLTail($HTML);


    my $currentChar = '';
    undef $t;
    @PackageOrder = ();
    $HTML = generateHTMLHeader ('S3');
    print $HTML "Complete list of packages. This includes 'Essential Packages' and packages that ";
    print $HTML "are present in Release Manager, but are not currently used.";
    print $HTML "<br><button type=\"button\" onclick=\"flipStyleByName('.nonessential', 'display', 'none', '')\" >Show/Hide non Essential</button>";
    print $HTML "<button type=\"button\" onclick=\"flipStyleByName('.essential', 'display', 'none', '')\" >Show/Hide Essential</button>";
    
    foreach my $pkgid ( sort {lc($ScmAllPackages{$a}{name}) cmp lc($ScmAllPackages{$b}{name}) } keys %ScmAllPackages )
    {
        my $thisChar = uc(substr($ScmAllPackages{$pkgid}{name}, 0, 1 ));
        if ( $thisChar ne $currentChar )
        {
            print $HTML $t->getTable if ( $t );
            $t = new HTML::Table();

            endExpander($HTML) if ($currentChar);
            startExpander($HTML, "Letter2$thisChar", $thisChar);
            $currentChar = $thisChar;
        }
        my $packageRef;
        my $version_tree = '';
        my $import_log = '';
        my $marker = '';
        my $class;
        unless ( exists $PackageData{$pkgid} )
        {
            $packageRef = $ScmAllPackages{$pkgid}{name};
            $marker = 'Not being converted at this time';
            $class = 'nonEssential';
        }
        else
        {
            push @PackageOrder, $pkgid;
            $packageRef = linkPackageDetails($pkgid);
            $version_tree = linkImage($pkgid, '(Version Tree)');
            $import_log = linkImportLog( $pkgid, '(Import Log)');

            $marker = 'Converted to SVN'
                if ( $PackageData{$pkgid}{isSVN} );
            $class = 'essential';
        }
        $t->addRow($packageRef, linkPkg($pkgid, '(Release Manager)'),$version_tree, $import_log, $marker);
        $t->setRowClass  (-1, $class);
    }
    print $HTML $t->getTable if ( $t );
    endExpander($HTML) if ($currentChar);
    generateHTMLTail($HTML);

    #
    #   Package Details
    #
    $HTML = generateHTMLHeader ('S4');
    $t = new HTML::Table( -border=>1 );
    foreach my $pkgid ( @PackageOrder )
    {
        my @badVobs;
        $t->addRow('&nbsp;');
        $t->setRowClass  (-1, 'packageTitle');
        $t->setCellColSpan(-1, 1, 2);
        
        $t->addRow( anchor("$PackageData{$pkgid}{name}", 'Name:'), linkPkg($pkgid) . linkImage($pkgid, ' (Version Tree)') . linkImportLog( $pkgid, ' (Import Log)' ) );
#        $t->setRowHead(-1,1);
        
        my $t2 = new HTML::Table( -border=>0, -padding=>0, -spacing=>0 );
        foreach my $pvid ( sort {$ScmPackages{$a}{fullVersion} cmp $ScmPackages{$b}{fullVersion} } @{$PackageSet{$pkgid}} )
        {
            my @markers;
            if ( $ScmPackages{$pvid}{BadVob} || $ScmPackages{$pvid}{BadCCView}  ) {
                push @markers, hRef( "#BadVcs_$pvid", ' -Bad Tag');
            }

            if ( $ScmPackages{$pvid}{sbomOsid} || $ScmPackages{$pvid}{sbomBase}  ) {
                push @markers, 'SBOM';
            }
            

            $t2->addRow( linkPvid($pvid, undef, 1), "@markers" );

            push @badVobs,$pvid if ($ScmPackages{$pvid}{BadVob});
        }
        $t->addRow("Versions used:", $t2->getTable);
        $t->addRow("Type:", $PackageData{$pkgid}{type});
        $t->addRow("Projects:",join (',', @{$PackageData{$pkgid}{suffixes}} ));

        my $youngest = $PackageData{$pkgid}{youngAge};
        my $youngestNonRipple = $PackageData{$pkgid}{youngAgeNonRipple} || 0;
        my $youngestNonBuildadm = $PackageData{$pkgid}{nonBuildadm} || 0;

        $youngest = int($youngest);
        $youngestNonRipple = int($youngestNonRipple) || '-';
        $youngestNonBuildadm = int($youngestNonBuildadm) || '-';

        $t->addRow("Youngest:", "$youngestNonRipple Days (NonRipple). $youngestNonBuildadm Days (NonBuildadm). $youngest Days (any Build)" );
        $t->addRow("Views:", join (',', keys %{$PackageData{$pkgid}{view}}));

        if ( $PackageData{$pkgid}{MultiVob} )
        {
            my $t2 = new HTML::Table( -border=>0, -padding=>0, -spacing=>0, -class=>'paddedTable' );
            foreach my $vob ( keys %{$PackageData{$pkgid}{vobs}} )
            {
                $t2->addRow($vob);
                $t2->setRowHead(-1,1);
                $t2->setCellColSpan(-1, 1, 3);
                foreach my $pvid ( @{$PackageData{$pkgid}{vobs}{$vob}} )
                {
                    $t2->addRow('&nbsp;', linkPvid($pvid, undef, 1), "$ScmPackages{$pvid}{'vcstag'}" );
                }
            }
            $t2->setColClass (1, 'listTitle' );
            $t->addRow("MultiVobs:", $t2->getTable);
        }
        else
        {
            $t->addRow("Vobs:", join (',', keys %{$PackageData{$pkgid}{vobs}}));
        }

        if ( $PackageData{$pkgid}{MultiVob} )
        {
            my $t2 = new HTML::Table( -border=>0, -padding=>0, -spacing=>0, -class=>'paddedTable' );
            foreach my $vob ( keys %{$PackageData{$pkgid}{vobPath}} )
            {
                $t2->addRow($vob);
                $t2->setRowHead(-1,1);
                $t2->setCellColSpan(-1, 1, 2);
                foreach my $pvid ( @{$PackageData{$pkgid}{vobPath}{$vob}} )
                {
                    $t2->addRow('&nbsp;', linkPvid($pvid, undef, 1) );
                }
            }
            $t2->setColClass (1, 'listTitle' );
            $t->addRow("Paths:", $t2->getTable);
        }
        else
        {
            $t->addRow("Paths:", join (',', keys %{$PackageData{$pkgid}{vobPath}}));
        }
        

        if ( @badVobs )
        {
            my $t2 = new HTML::Table( -border=>0, -padding=>0, -spacing=>0, -class=>'paddedTable' );
            foreach my $pvid ( @badVobs )
            {
                $t2->addRow(linkPvid($pvid), "&nbsp;", $ScmPackages{$pvid}{'vcstag'} );
            }
            $t->addRow("Bad VCS:", $t2->getTable );
        }

        my $repo = $PackageData{$pkgid}{mappedRepo};
        my %RepoList;
        foreach my $pvid ( @{$PackageSet{$pkgid}} )
        {
            my $repo = $ScmPackages{$pvid}{'vcstag'};
            if ( $repo =~ m~SVN::(.*)(/tags/|/branches/|/trunk)~i )
            {
                $RepoList{$1} = svnLink($1) unless exists $RepoList{$1};
            }
        }
        my $txt = join( '<br>', values %RepoList);
        $txt = ' : ' . $txt if ( $txt );
        $t->addRow("Repo:", hRef("#Repo_$repo", $repo). $txt );
        if ( exists $Protected{$PackageData{$pkgid}{name}} )
        {
            my $entry = $Protected{$PackageData{$pkgid}{name}};
            my $comment = $entry->{comment} || '';
            my $t2 = new HTML::Table( -border=>0, -padding=>0, -spacing=>0, -class=>'paddedTable' );

            $t2->addRow($entry->{mode}, $comment );
            $t->addRow("Protected:", $t2->getTable);
        }
    }
    $t->setColClass (1, 'listTitle' );
    print $HTML $t->getTable;
    generateHTMLTail($HTML);
    #
    #   Bad Package information
    #
    my %BadByProject;
    my $last_proj_id = 0;

    $HTML = generateHTMLHeader ('S5');
    print $HTML "These package-versions cannot be reproduced from ClearCase. This may be due to\n";
    print $HTML "<dl><dd>Invalid Release Manager information";
    print $HTML "<dd>Incorrect Release Manager Data";
    print $HTML "<dd>ClearCase label and Path do not result in a view with files";
    print $HTML "</dl>";
    $t = new HTML::Table( -border=>1 );
    $t->addRow( 'Package Version','VCS Tag' );
    $t->setRowHead(1,1);
    foreach my $pvid ( sort {lc($ScmPackages{$a}{name}) cmp lc($ScmPackages{$b}{name}) } keys %ScmPackages )
    {
        next unless ( $ScmPackages{$pvid}{BadVob} || $ScmPackages{$pvid}{BadCCView} );

        my $t2 = new HTML::Table( -border=>0, -padding=>0, -spacing=>0, -class=>'paddedTable' );
        $t2->addRow($ScmPackages{$pvid}{'vcstag'});

        my ($users, $iusers) = usedBy($pvid);
        if ( @$users )
        {
            $t2->addRow("Used Directly by:");
            $t2->addRow(linkRelease($_, $pvid)) foreach ( @$users );
            push @{$BadByProject{$_}{direct}}, $pvid foreach ( @$users );
        }

        if ( @$iusers )
        {
            $t2->addRow("Used Indirectly by:");
            $t2->addRow(linkRelease($_, $pvid)) foreach ( @$iusers );
            push @{$BadByProject{$_}{indirect}}, $pvid foreach ( @$iusers );
        }
        $t->addRow( anchor("$pvid",linkPvid($pvid)), $t2->getTable );
    }
    $t->setColClass (1, 'listTitle' );
    print $HTML $t->getTable;
    generateHTMLTail($HTML);

    #
    #   Bad package vesrions by project
    #
    $HTML = generateHTMLHeader ('S6');
    $t = new HTML::Table( -border=>1 );
    $t->addRow( 'Release','Package');
    $t->setRowHead(1,1);
    $last_proj_id = 0;

    sub sortReleases
    {
        my $rv = ( lc($ScmReleases{$a}{pName}) cmp lc($ScmReleases{$b}{pName}));
        unless ($rv )
        {
            $rv = (lc($ScmReleases{$a}{'rtag_id'}) cmp lc($ScmReleases{$b}{'rtag_id'}));
        }
        return $rv;
    }

    foreach my $rtag_id ( sort sortReleases keys %BadByProject  )
    {
        if ( $last_proj_id != $ScmReleases{$rtag_id}{proj_id} )
        {
            $last_proj_id = $ScmReleases{$rtag_id}{proj_id};
            $t->addRow( $ScmReleases{$rtag_id}{pName});
            $t->setCellColSpan(-1, 1, 2);
        }

        my $t2 = new HTML::Table(-border=>0, -padding=>0, -spacing=>0, -class=>'paddedTable' );

        if ( $BadByProject{$rtag_id}{direct} )
        {
                $t2->addRow('Directly uses:' );
                foreach my $pvid (@{$BadByProject{$rtag_id}{direct}})
                {
                    $t2->addRow( linkPvid($pvid, $rtag_id) , $ScmPackages{$pvid}{'vcstag'} );
                }
        }

        if ( $BadByProject{$rtag_id}{indirect} )
        {
            $t2->addRow('Indirectly uses:' );
            foreach my $pvid (@{$BadByProject{$rtag_id}{indirect}})
            {
                $t2->addRow( linkPvid($pvid, $rtag_id) , $ScmPackages{$pvid}{'vcstag'} );
            }
        }
        $t->addRow(linkRelease($rtag_id, undef, 1), $t2->getTable  );
    }

    $t->setColClass (1, 'listTitle' );
    $t->setColHead(1,1);
    print $HTML $t->getTable;
    generateHTMLTail($HTML);

    #
    #   Releases that have multiple instances of the same package in them
    #
    $HTML = generateHTMLHeader ('S7');
    print $HTML "Releases that have multiple instances of the same package\n";
#DebugDumpData("ReleasePackages", \%ReleasePackages );

    $t = new HTML::Table( -border=>1 );
    $t->addRow( 'Release','Package');
    $t->setRowHead(1,1);
    $last_proj_id = 0;

    foreach my $rtag_id ( sort sortReleases keys %ReleasePackages )
    {
        my @multiples;
        foreach my $name ( keys %{$ReleasePackages{$rtag_id}{name}} )
        {
            if ( $ReleasePackages{$rtag_id}{name}{$name}{count} > 1 )
            {
                push @multiples, $name;
            }
        }
        next unless ( @multiples );

        if ( $last_proj_id != $ScmReleases{$rtag_id}{proj_id} )
        {
            $last_proj_id = $ScmReleases{$rtag_id}{proj_id};
            $t->addRow( $ScmReleases{$rtag_id}{pName});
            $t->setCellColSpan(-1, 1, 2);
        }

        my $t2 = new HTML::Table(-border=>0, -padding=>0, -spacing=>0, -class=>'paddedTable' );

        foreach my $name ( sort {uc($a) cmp uc($b) } @multiples )
        {
            $t2->addRow('Package: ' . linkFindPkgs($name, $rtag_id),  );
            $t2->setCellColSpan(-1, 1, 2);
            foreach my $pvid ( @{$ReleasePackages{$rtag_id}{name}{$name}{pvid}} )
            {
                $t2->addRow( '&nbsp;', linkPvid($pvid, $rtag_id) );
            }
        }

        $t->addRow(linkRelease($rtag_id, undef, 1), $t2->getTable  );
    }
    $t->setColClass (1, 'listTitle' );
    $t->setColHead(1,1);
    print $HTML $t->getTable;
    generateHTMLTail($HTML);
    

    $HTML = generateHTMLHeader ('S8');
    print $HTML "A summary of proposed Repostories and Paths\n";

    $t = new HTML::Table( -border=>0, -padding=>0, -spacing=>0, -class=>'paddedTable' );
    $t->addRow( 'Name','', 'Count', 'Warnings'  );
    $t->setCellColSpan(1, 1, 2);
    foreach my $repo ( sort {uc($a) cmp uc($b) } keys %RepoSubIndex )
    {
            next if ( $repo eq 'UNKNOWN' );
            next if ( $repo eq 'SVN' );
            my $count = '';
            if ( exists $RepoSubIndex{$repo}{'-'}   )
            {
                $count = @{$RepoSubIndex{$repo}{'-'}};
            }
            $t->addRow( hRef("#Repo_$repo", $repo), '', $count  );
            $t->setCellColSpan($t->getTableRows(), 1, 2);

            foreach my $path ( sort {uc($a) cmp uc($b) } keys %{$RepoSubIndex{$repo}} )
            {
                    next if ( $path eq '-' );
                    my $depth = $path =~ tr~/~~;
                    my $warn = ($depth > 2) ? ' - Deeply nested' : '';
                    my $count = (@{$RepoSubIndex{$repo}{$path}});
                    $warn .= ' - Only One Package' if ( $count < 2 );

                    $t->addRow( '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;', hRef("#Repo_$repo/$path", $path), $count, $warn);
            }

    }
    
    print $HTML $t->getTable;
    generateHTMLTail($HTML);



#DebugDumpData("RepoSubIndex", \%RepoSubIndex);
#DebugDumpData("Repos", \%Repos);
    
    #
    #   Repo back reference
    #
    $HTML = generateHTMLHeader ('S9');
    print $HTML "Proposed and Converted Repostories and Paths with package mapping and ClearCase Path\n";

    $t = new HTML::Table( -border=>1 );
    $t->addRow( 'Repository Path', 'Package Name,Original Vob Path(s),Last Build NonBuildadm [ANY]' );

    foreach my $repo ( sort {uc($a) cmp uc($b) } keys %Repos )
    {
        next if ( $repo eq 'SVN' );
        next if ( $repo eq 'UNKNOWN' );
        my @data;
        my $t1 = new HTML::Table( -border=>1,-width=>'100%', -style=>"border-collapse:collapse" );


        foreach my $pkgid ( @{$Repos{$repo}} )
        {
            #
            #   Flag packages that are
            #       1) Known to be BAD
            #       2) Held back
            #
            my $flag = '';
            if ( exists $Protected{$PackageData{$pkgid}{name}} )
            {
                if ( $Protected{$PackageData{$pkgid}{name}}{mode} eq 'Protected' )
                {
                    $flag = ' [P]';
                }
                else
                {
                    $flag = ' [B]';
                }
            }

            my $t2 = new HTML::Table( -border=>0,-padding=>0, -spacing=>0, -class=>'paddedTable' );
            foreach my $vob ( keys %{$PackageData{$pkgid}{vobPath}} )
            {
                    if ($PackageData{$pkgid}{isSVN} && $vob !~ m~^/~ )
                    {
                        $vob = svnLink($vob);
                        #$vob = "<span style=\"background-color:#B1FB17\">$vob</span>";
                    }
                    $t2->addRow( $vob );
            }
            my $t2Text = '';
            if ( $t2->getTableRows() )
            {
                $t2->setColClass (1, 'listTitle' );
                $t2Text = $t2->getTable();
            }
            my $youngest = $PackageData{$pkgid}{youngAge};
            my $youngestNonRipple = $PackageData{$pkgid}{youngAgeNonRipple} || 0;
            my $youngestNonBuildadm = $PackageData{$pkgid}{nonBuildadm} || 0;

            $youngest =  int($youngest);
            $youngestNonRipple =  int($youngestNonRipple) || '-';
            $youngestNonBuildadm = int($youngestNonBuildadm) || '-';
            
            $t1->addRow( linkPackageDetails($pkgid) . $flag, $t2Text, "$youngestNonBuildadm [$youngest]"  );
        }

        if ( $t1->getTableRows() )
        {
            $t1->setColWidth(1,'30%');
            $t1->setColClass (1, 'listTitle' );
            $t1->setColWidth(3,'10%');
        }
        $t->addRow( anchor("$repo",$repo), $t1->getTable() );

    }
    $t->setColClass (1, 'listTitle' );
    $t->setColHead(1,1);
    print $HTML $t->getTable;
    generateHTMLTail($HTML);
    
    #
    #   Highlight packages that have not been mapped to a Repo
    #
    $HTML = generateHTMLHeader ('SA');
    print $HTML "Packages that have not been mapped to a Repository\n";
    $t = new HTML::Table( -border=>1 );
    foreach my $pkgid ( @{$Repos{UNKNOWN}} )
    {
        my $flag_badCC;
        my $flag_multi;
        my $flag_badVob;

        $flag_multi  = 1 if $PackageData{$pkgid}{MultiVob};
        $flag_badVob = 1 if $PackageData{$pkgid}{BadVob};

        foreach my $pvid ( @{$PackageSet{$pkgid}} )
        {
            $flag_badCC  = 1 if ( $ScmPackages{$pvid}{BadCCView} );
            $flag_multi  = 1 if ( $ScmPackages{$pvid}{MultiVob} );
            $flag_badVob = 1 if ( $ScmPackages{$pvid}{BadVob} );
        }

        my @data;
        push @data, "Bad ClearCase View" if $flag_badCC;
        push @data, "Multiple Vobs" if $flag_multi;
        push @data, "Bad VcsTag" if $flag_badVob;
        $t->addRow( linkPackageDetails($pkgid), join( '<br>', @data) );
    }
    
    $t->setColClass (1, 'listTitle' );
    print $HTML $t->getTable;
    generateHTMLTail($HTML);

    #
    #   Packages already under Subversion
    #
    $HTML = generateHTMLHeader ('SB');
    print $HTML "Packages that are currently in Subversion\n";
    print $HTML "<br>Packages in Subversion   : ". scalar @{$Repos{SVN}} ."\n";
    print $HTML "<br>Total Packages to convert: ". $totalPackageCount ."\n";
    print $HTML "<p>" ,anchor("SVN",'SVN');

    $t = new HTML::Table( -border=>1 );
    foreach my $pkgid ( @{$Repos{SVN}} )
    {
        my %RepoList;
        foreach my $pvid ( @{$PackageSet{$pkgid}} )
        {
            my $repo = $ScmPackages{$pvid}{'vcstag'};
            if ( $repo =~ m~SVN::(.*)(/tags/|/branches/|/trunk)~i )
            {
                $RepoList{$1} = svnLink($1) unless exists $RepoList{$1};
            }
        }
        $t->addRow( linkPackageDetails($pkgid), join( '<br>', values %RepoList) );
    }
    print $HTML $t->getTable;


    #
    #   Packages NOT under Subversion
    #
    $HTML = generateHTMLHeader ('SC');
    print $HTML "Packages that are not currently in Subversion\n";
    print $HTML "<br>Does not include those with known issues - only those that we can migrate\n";
    print $HTML "<br>Packages in Subversion   : ". scalar @{$Repos{SVN}} ."\n";
    print $HTML "<br>Total Packages to convert: ". $totalPackageCount ."\n";
#    print $HTML "<p>" ,anchor("SVN",'SVN');

    $t = new HTML::Table( -border=>1 );
    $t->addRow( 'Package Name','Original Vob Path(s)','Last Build NonBuildadm [ANY]','Comment' );
    foreach my $pkgid ( @PackageOrder )
    {
        next if $PackageData{$pkgid}{isSVN};
        {
            #
            #   Flag packages that are
            #       1) Known to be BAD
            #       2) Held back
            #
            my $comment = '';
            my $flag = '';
            if ( exists $Protected{$PackageData{$pkgid}{name}} )
            {
                $comment = $Protected{$PackageData{$pkgid}{name}}{comment};

                if ( $Protected{$PackageData{$pkgid}{name}}{mode} eq 'Protected' )
                {
                    $flag = ' [P]';
                }
                else
                {
                    $flag = ' [B]';
                    next;
                }
            }

            my $t2 = new HTML::Table( -border=>0,-padding=>0, -spacing=>0, -class=>'paddedTable' );
            foreach my $vob ( keys %{$PackageData{$pkgid}{vobPath}} )
            {
                    if ($PackageData{$pkgid}{isSVN} && $vob !~ m~^/~ )
                    {
                        $vob = svnLink($vob);
                        #$vob = "<span style=\"background-color:#B1FB17\">$vob</span>";
                    }
                    $t2->addRow( $vob );
            }
            my $t2Text = '';
            if ( $t2->getTableRows() )
            {
                $t2->setColClass (1, 'listTitle' );
                $t2Text = $t2->getTable();
            }
            my $youngest = $PackageData{$pkgid}{youngAge};
            my $youngestNonRipple = $PackageData{$pkgid}{youngAgeNonRipple} || 0;
            my $youngestNonBuildadm = $PackageData{$pkgid}{nonBuildadm} || 0;

            $youngest =  int($youngest);
            $youngestNonRipple =  int($youngestNonRipple) || '-';
            $youngestNonBuildadm = int($youngestNonBuildadm) || '-';
            
            $t->addRow( linkPackageDetails($pkgid) . $flag, $t2Text, "$youngestNonBuildadm [$youngest]", $comment  );
        }
    }
    print $HTML $t->getTable;
    
    #
    #   Packages with known issues
    #
    $HTML = generateHTMLHeader ('SD');
    print $HTML "Packages that are not being migrated due to known issues\n";

    $t = new HTML::Table( -border=>1 );
    $t->addRow( "Protected Packages - Migration delayed");
    $t->setRowClass  (-1, 'packageTitle');
    $t->setCellColSpan(-1, 1, 2);
    foreach my $pkgname ( sort keys %Protected )
    {
        next unless ( $Protected{$pkgname}{mode} eq 'Protected' );
        my $pkgid =  $ScmPkgNames{$pkgname};
        my $txt = $pkgid ? linkPackageDetails($pkgid) : $pkgname;
        $t->addRow( $txt, $Protected{$pkgname}{comment});
    }

    $t->addRow( "Broken Packages - Migration not possible");
    $t->setRowClass  (-1, 'packageTitle');
    $t->setCellColSpan(-1, 1, 2);
    foreach my $pkgname ( sort keys %Protected )
    {
        next if ( $Protected{$pkgname}{mode} eq 'Protected' );
        my $pkgid =  $ScmPkgNames{$pkgname};
        my $txt = $pkgid ? linkPackageDetails($pkgid) : $pkgname;
        $t->addRow( $txt, $Protected{$pkgname}{comment});
    }
    
    print $HTML $t->getTable;
    

    generateHTMLTail($HTML);
Message ("Created: PackageConversion.html");
}

sub hRef
{
    my ($url, $text, $target) = @_;
    my $ttext = '';

    if ( $url =~ m~^#(.*?)_~ )
    {
        my $tag = $1;
        foreach my $section ( keys %htmlData )
        {
            if ( $htmlData{$section}{tag} eq $1 )
            {
                $url = $htmlData{$section}{file} . $url;
                $target = '_Page'.$section unless ( $target );
            }
        }
    }

    $ttext = ' TARGET="' . $target . '"' if ( defined $target );
    return ( '<a href="' . $url . '"' . $ttext . '>' . $text . '</a>' );
}

sub anchor
{
    my ($name, $text) = @_;
    my $prefix = '';
    if ( $currentSection )
    {
        $prefix = $htmlData{$currentSection}{tag};
        $prefix = $prefix . '_' if ( $prefix );
    }
    return ( '<a name="' . $prefix . $name . '">' . $text . '</a>' );
}


sub htmlH1
{
    my ($text) = @_;
    return '<h1>' . $text . '</h1>';
}

sub linkBomProject
{
    my ($projId, $text) = @_;
    my $ref = $GBE_DM_URL . "/Default.asp?proj_id=$projId";

    return hRef($ref, $text, '_packageData');
}


sub linkRelease
{
    my ($pkgid, $pvid, $mode) = @_;
    my $pkgid_ref = $GBE_RM_URL . "/fixed_issues.asp?rtag_id=$pkgid";
    $pkgid_ref .= "&pv_id=$pvid" if defined $pvid;

    my $text = '';
    $text .= "$ScmReleases{$pkgid}{pName} :: " unless ( $mode );
    $text .= $ScmReleases{$pkgid}{name};
    
    $text = hRef($pkgid_ref, $text, '_packageData');
}

sub linkPackageDetails
{
    my ($pkgid) = @_;
    my $name = $PackageData{$pkgid}{name};
    return hRef("#Package_${name}",$name);
}

sub linkPvid
{
    my ($pvid, $rtagid, $mode) = @_;
    my $pv_base = $GBE_RM_URL . "/fixed_issues.asp?pv_id=$pvid";
    $pv_base .= "&rtag_id=$rtagid" if ($rtagid);

    my $text = '';
    $text .= "$ScmPackages{$pvid}{'name'} " unless ( $mode );
    $text .= $ScmPackages{$pvid}{'version'};
    return hRef($pv_base, $text, '_packageData');
}

sub linkFindPkgs
{
    my ($name, $rtagid) = @_;
    my $pv_base = $GBE_RM_URL . "/find.asp?searchtype=1&keyword=$name&btn=Find&envtab=3&rtag_id=$rtagid";
    return hRef($pv_base, $name, '_packageData');
}

sub linkPkg
{
    my ($pkgid, $utext) = @_;
    my $rm_base = $GBE_RM_URL . "/view_by_version.asp?pkg_id=$pkgid";
    my $text = $utext ? $utext : $PackageData{$pkgid}{name};
    return hRef($rm_base, $text , '_packageData');
}

sub linkImage
{
    my ($pkgid, $utext) = @_;
    my $name = $PackageData{$pkgid}{name};
    my $ref = $name . '.svg';
    my $text = $utext ? $utext : $name;
    return hRef($ref, $text, '_packageImage');
}

sub linkImportLog
{
    my ($pkgid, $utext) = @_;
    my $name = $PackageData{$pkgid}{name};
    my $ref = $name . '.importlog';
    my $text = $utext ? $utext : $name;
    return hRef($ref, $text, '_packageLog');
}

sub svnLink
{
    my ($tag, $utext) = @_;
    my $text = $utext ? $utext : $tag;

    $tag =~ s~^SVN::~~;
    my $url = SvnPath2Url ($tag);
    return hRef($url, $text, '_SvnPage');
}



#-------------------------------------------------------------------------------
# Function        : startExpander
#                   endExpander
#
# Description     : Insert HTML code to start/end a Javascript expanding
#                   division.
#
# Inputs          : $name           - Unique name for the Section
#                   $text           - Header Text to be displayed
#
# Returns         : 
#
sub startExpander
{
    my ($HTML, $name, $text) = @_;
    print $HTML <<EXPANDER;
<div class="expandingMenu expandingMenuNotSelected">
    <div onclick='click_expandingMenuHeader(this,"$name")' class="expandingMenuHeader" >$text</div>
        <div id="cssprop_$name" class="expandingMenuGroup" style="display:none;">
EXPANDER
}

sub endExpander
{
    my ($HTML) = @_;
    print $HTML "</div></div>\n";
}


#    if ( 0 )
#    {
#        my $file = "TagList.txt";
#        my $count = 0;
#        Message("Create CC Tag  List", $file);
#        open ( my $fh, '>', $file ) || Error ("Cannot open $file", "Error: $!");
#        my %PackageNames;
#
#        foreach ( sort @taglist )
#        {
#            print $fh "$_\n";
#            $count++;
#        }
#        close $fh;
#        Message("Tags: $count");
#    }
    
    
#    DebugDumpData("VersionTags", \%VersionTags);
#    DebugDumpData("Vobs", \%Vobs);
    #print "VOBS: ", join ("\n", sort keys %Vobs), "\n";

#-------------------------------------------------------------------------------
# Function        : readInputData
#
# Description     : Write out data in a form to allow post processing
#
# Inputs          : 
#
# Returns         : 
#
sub readInputData
{

    my $fname = 'cc2svn.raw.txt';
    Message ("Reading: $fname");
    Error "Cannot locate $fname" unless ( -f $fname );
    require $fname;

    Error "Data in $fname is not valid\n"
        unless ( keys(%ScmReleases) >= 0 );

#    DebugDumpData("ScmReleases", \%ScmReleases );
#    DebugDumpData("ScmPackages", \%ScmPackages );
#    DebugDumpData("ScmSuffixes", \%ScmSuffixes );

    %ScmSuffixes = ();
}

##-------------------------------------------------------------------------------
## Function        : getVobMapping
##
## Description     : Read in Package to Repository Mapping
##
## Inputs          :
##
## Returns         : Populates
#                        #%VobMapping;                 # Vob -> Repo
#                        #%PackageMapping;             # Package -> Repo
#                        #%ViewMapping                 # View -> Repo
#sub getVobMapping
#{
#    my $fname = 'cc2svn.mapping.txt';
#    Message ("Reading: $fname");
#    Error "Cannot locate $fname" unless ( -f $fname );
#    require $fname;
#
#    Error "Data in $fname is not valid\n"
#        unless ( keys(%PackageMapping) >= 0 );
#
#    DebugDumpData("PackageMapping", \%PackageMapping );
#    DebugDumpData("VobMapping", \%VobMapping );
#    DebugDumpData("ViewMapping", \%ViewMapping );
#
#}


#-------------------------------------------------------------------------------
# Function        : mapPackage
#
# Description     : Attempt to map a package to a repo
#
# Inputs          : PackageId
#
# Returns         : RepoPatch
#
sub mapPackage
{
    my ($pkgid) = @_;
    my %Named = (
        'Release_Manager'                       => 'DevTools/ManagerSuite',
        'Access_Manager'                        => 'DevTools/ManagerSuite',
        'Deployment_Manager'                    => 'DevTools/ManagerSuite',
        'Production_Manager'                    => 'DevTools/ManagerSuite',
        'schema_utilities'                      => 'DevTools/ManagerSuite',
        'Release_Manager_Schema'                => 'DevTools/ManagerSuite',
        'Manager_Suite'                         => 'DevTools/ManagerSuite',
        'Manager_Suite_VM'                      => 'DevTools/ManagerSuite',

        'QtBuilder'                             => 'DevTools',
        'buildtool'                             => 'DevTools',
        'cabinet_packager'                      => 'DevTools',
        'core_devl'                             => 'DevTools',
        'debian_packager'                       => 'DevTools',
        'deployfiles'                           => 'DevTools',
        'dpkg_blat'                             => 'DevTools',
        'dpkg_management'                       => 'DevTools',
        'generate_release_notes'                => 'DevTools',
        'jants'                                 => 'DevTools',
        'linux_day0fs_tools'                    => 'DevTools',
        'manifest-tool'                         => 'DevTools',
        'nsis_packager'                         => 'DevTools',
        'nsis_library'                          => 'DevTools',
        'shellbuild'                            => 'DevTools',
        'wsdl-tools'                            => 'DevTools',
        'binflow'                               => 'DevTools',
        'zendguard_tools'                       => 'DevTools',
        'cpptasks'                              => 'DevTools/ant',
        'AdvisoryDependency'                    => 'DevTools/buildtool_tests',
        'CommonDependency'                      => 'DevTools/buildtool_tests',
        'GenericProduct'                        => 'DevTools/buildtool_tests',
        'LinuxCentricProduct'                   => 'DevTools/buildtool_tests',
        'CotsWithFunnyVersion'                  => 'DevTools/buildtool_tests',
        'xp_sequence'                           => 'MASS_Dev_Bus',
        'dmrc_windows_proxy'                    => 'MASS_Dev_Infra/Dmrc',
        'ExtDataImporter'                       => 'MASS_Dev_Infra/Dmrc',
        'inqshim'                               => 'MASS_Dev_Infra/Dmrc',
        'reports_gui'                           => 'MASS_Dev_Infra/Dmrc',

        'GenAppaCE'                             => 'DPG_SWCode/utilities',
        'JTerm'                                 => 'DPG_SWCode/utilities',

        'AtmelHAL'                              => 'MASS_Dev_Crypto',
        'Netbula'                               => 'COTS',
        'ObjectiveGrid'                         => 'COTS',
        'lmos'                                  => 'DPG_SWBase',
#        'daf_cd_transap'                        => 'DPG_SWBase',
        'basetypes'                             => 'MASS_Dev_Infra',
        'accesscontrol_ejb-api'                 => 'MASS_Dev_Infra/Security',
        'tp5000_MUG'                            => 'MREF_Package',
        'udman'                                 => 'MASS_Dev_Infra',
        'emvud'                                 => 'DPG_SWBase/emvud',
        'daf_mmi_ti'                            => 'DPG_SWBase',
        'daf_osa_mos'                           => 'DPG_SWBase/OSA',
        'mos_api'                               => 'MOS',
        'tp5700_Manifest'                       => 'MREF_Package',
#        'TRACS'                                 => 'ITSO_TRACS',
        'SSW_Validator'                         => 'ITSO_TRACS/SSW_validator',
        'itso_pcp_main'                         => 'ITSO_TRACS/itso_pcp',


        'jboss_config'                          => 'MASS_Dev_Bus/Business' ,
        'jboss_service'                         => 'MASS_Dev_Bus/Business' ,
        'pgres'                                 => 'ITSO_TRACS/DataManagement' ,
        'ERGcda_imports'                        => 'MREF_Package',
        'daf_dataman_extras'                    => 'DPG_SWCode/ProjectCD/seattle',
        'daf_paper_variables'                   => 'DPG_SWCode/ProjectCD',

        'XmlDocInterface'                       => 'MASS_Dev_Infra',
        'SPOS_IngenicoApp'                      => 'DPG_SWCode',

        'oracs'                                 => 'MASS_Dev_Bus/web',
        'oradacw'                               => 'MASS_Dev_Bus/web',
        'orabocw'                               => 'MASS_Dev_Bus/web',
        'MetrixOra'                             => 'MASS_Dev_Bus/web',
        
        # Kill single package subdirs
        'application'                           => 'MASS_Dev_Bus',
        'card'                                  => 'MASS_Dev_Bus',
        'cardholder'                            => 'MASS_Dev_Bus',
        'opman-database'                        => 'MASS_Dev_Bus',
        'product'                               => 'MASS_Dev_Bus',
        'VmtInterface'                          => 'MASS_Dev_Bus',
        'systemcd_ejb-api'                      => 'MASS_Dev_Bus/CBP',
        'boi'                                   => 'MASS_Dev_Bus/BOI',

        'mrviewer'                              => 'MASS_Dev_Infra/Reports',
        'cdss'                                  => 'MASS_Dev_Infra/Cdss',
        'InfraPSS'                              => 'MASS_Dev_Infra',


        'vsdev-proftpd-insecure'                => 'SmartSite',
        'obe'                                   => 'ITSO_TRACS/obe',
        'obme'                                  => 'ITSO_TRACS/obe',
        'linuxaudio'                            => 'LinuxDevices/libraries',


        #
        #   Packages from the LMOS Vob
        #   Too many rules - just hard code the lot of them
        #
        'rolff'                                 => 'DPG_SWBase/Dugite',
        'ftplinux'                              => 'UNKNOWN',

        'linux-app-framework'              => 'DPG_SWBase/linux-app-framework',
        'linux-app-upgrade'                => 'DPG_SWBase/linux-app-framework',
        'linux-app-example'                => 'DPG_SWBase/linux-app-framework',
        'linux-app-transfer'               => 'DPG_SWBase/linux-app-framework',

        'demo_cp6000'                      => 'LinuxDevices/apps',
        'ivaldemo'                         => 'LinuxDevices/apps',
        'linux-cotral-example'             => 'LinuxDevices/apps',
        'lmos_utest'                       => 'LinuxDevices/apps',
        'ublox-agps-example'               => 'LinuxDevices/apps',
        'fdt-ads5121'                      => 'LinuxDevices/bootstrap',
        'fdt-viper'                        => 'LinuxDevices/bootstrap',
        'linux-grub'                       => 'LinuxDevices/bootstrap',
        'romboot'                          => 'LinuxDevices/bootstrap',
        'u-boot'                           => 'LinuxDevices/bootstrap',
        'u-boot-cobra'                     => 'LinuxDevices/bootstrap',
        'u-boot-hk'                        => 'LinuxDevices/bootstrap',
        'u-boot_viper'                     => 'LinuxDevices/bootstrap',
        'uboot-cobra-tools'                => 'LinuxDevices/bootstrap',
        'uboot-viper-tools'                => 'LinuxDevices/bootstrap',
        'viper-platform-setup'             => 'LinuxDevices/bootstrap',
        'coalesce'                         => 'LinuxDevices/dams',
        'dams_eb5600'                      => 'LinuxDevices/dams',
        'dams_ival'                        => 'LinuxDevices/dams',
        'dams_pcp5700'                     => 'LinuxDevices/dams',
        'dams_tp5600'                      => 'LinuxDevices/dams',
        'demo_msp_lnx_viper'               => 'LinuxDevices/devkit',
        'devkit-tool'                      => 'LinuxDevices/devkit',
        'idp_lnx_viper'                    => 'LinuxDevices/devkit',
        'ival-devkit'                      => 'LinuxDevices/devkit',
        'linux_infra_eb5600'               => 'LinuxDevices/devkit',
        'linux_infra_tp5600'               => 'LinuxDevices/devkit',
        'drivers_api_viper'                => 'LinuxDevices/drivers',
        'gprsmodem-firmware'               => 'LinuxDevices/drivers',
        'linux_driver_csc_cobra'           => 'LinuxDevices/drivers',
        'linux_driver_csc_viper'           => 'LinuxDevices/drivers',
        'linux_driver_ip_over_rs485'       => 'LinuxDevices/drivers',
        'linux_drivers_api'                => 'LinuxDevices/drivers',
        'linux_drivers_cobra'              => 'LinuxDevices/drivers',
        'linux_drivers_eb5600'             => 'LinuxDevices/drivers',
        'linux_drivers_etx86'              => 'LinuxDevices/drivers',
        'linux_drivers_serpent-api'        => 'LinuxDevices/drivers',
        'linux_drivers_tp5600'             => 'LinuxDevices/drivers',
        'linux_drivers_viper'              => 'LinuxDevices/drivers',
        'svgalib'                          => 'LinuxDevices/drivers',
        'usb_gadget_host'                  => 'LinuxDevices/drivers',
        'viper-pic-firmware'               => 'LinuxDevices/drivers',
        'viper-tipsoc-firmware'            => 'LinuxDevices/drivers',
        'viper_csc'                        => 'LinuxDevices/drivers',
        'busybox_cobra'                    => 'LinuxDevices/filesystems',
        'cobra_day0fs_base'                => 'LinuxDevices/filesystems',
        'day0-cotral'                      => 'LinuxDevices/filesystems',
        'e2fsimage'                        => 'LinuxDevices/filesystems',
        'e2fsprogs'                        => 'LinuxDevices/filesystems',
        'ERGDay0UpgradeServer'             => 'LinuxDevices/filesystems',
        'linux_day0fs_base'                => 'LinuxDevices/filesystems',
        'linux_day0fs_cobra'               => 'LinuxDevices/filesystems',
        'linux_day0fs_cp6100_sl6087_fwup'  => 'LinuxDevices/filesystems',
        'linux_day0fs_eb5600'              => 'LinuxDevices/filesystems',
        'linux_day0fs_etx86'               => 'LinuxDevices/filesystems',
        'linux_day0fs_tp5600'              => 'LinuxDevices/filesystems',
        'linux_day0fs_viper'               => 'LinuxDevices/filesystems',
        'linux_day0fs_viper_demo'          => 'LinuxDevices/filesystems',
        'linux_day0fs_viper_dev'           => 'LinuxDevices/filesystems',
        'ERGviper-kernel'                  => 'LinuxDevices/kernel',
        'linux_kernel_bcp4600'             => 'LinuxDevices/kernel',
        'linux_kernel_cobra'               => 'LinuxDevices/kernel',
        'linux_kernel_eb5600'              => 'LinuxDevices/kernel',
        'linux_kernel_etx86'               => 'LinuxDevices/kernel',
        'linux_kernel_tp5600'              => 'LinuxDevices/kernel',
        'linux_kernel_viper'               => 'LinuxDevices/kernel',
        'libviper-mtp'                     => 'LinuxDevices/libraries',
        'libviper-sam'                     => 'LinuxDevices/libraries',
        'libviper-util'                    => 'LinuxDevices/libraries',
        'setMAC'                           => 'LinuxDevices/libraries',
        'support_serpent'                  => 'LinuxDevices/libraries',
        'support_serpent-api'              => 'LinuxDevices/libraries',
        'support_serpent-so'               => 'LinuxDevices/libraries',
        'viper_setmac'                     => 'LinuxDevices/libraries',
        'libviper-mcr'                     => 'LinuxDevices/mcr',
        'linux-mcrfirmware'                => 'LinuxDevices/mcr',
        'mcr400-firmware'                  => 'LinuxDevices/mcr',
        'mcr400_emulator'                  => 'LinuxDevices/mcr',
        'mcrdemo'                          => 'LinuxDevices/mcr',
        'alsa'                             => 'LinuxDevices/opensource',
        'can-utils'                        => 'LinuxDevices/opensource',
        'canbus-j1708-monitor'             => 'LinuxDevices/opensource',
        'dfbtool'                          => 'LinuxDevices/opensource',
        'directfb'                         => 'LinuxDevices/opensource',
        'expat-linux'                      => 'LinuxDevices/opensource',
        'freetype'                         => 'LinuxDevices/opensource',
        'gpsd'                             => 'LinuxDevices/opensource',
        'iniparser'                        => 'LinuxDevices/opensource',
        'iptables'                         => 'LinuxDevices/opensource',
        'irda-utils'                       => 'LinuxDevices/opensource',
        'libftdi'                          => 'LinuxDevices/opensource',
        'libid3tag'                        => 'LinuxDevices/opensource',
        'libjpeg'                          => 'LinuxDevices/opensource',
        'libmad'                           => 'LinuxDevices/opensource',
        'libmodbus'                        => 'LinuxDevices/opensource',
        'libmysql'                         => 'LinuxDevices/opensource',
        'linux-glibc'                      => 'LinuxDevices/opensource',
        'linux-glibc-dbg'                  => 'LinuxDevices/opensource',
        'lrzsz'                            => 'LinuxDevices/opensource',
        'madplay'                          => 'LinuxDevices/opensource',
        'mkimage'                          => 'LinuxDevices/opensource',
        'mtd-utils'                        => 'LinuxDevices/opensource',
        'ncurses'                          => 'LinuxDevices/opensource',
        'openntpd'                         => 'LinuxDevices/opensource',
        'oprofile'                         => 'LinuxDevices/opensource',
        'oprofile-dev'                     => 'LinuxDevices/opensource',
        'pmctst'                           => 'LinuxDevices/opensource',
        'popt'                             => 'LinuxDevices/opensource',
        'ppp'                              => 'LinuxDevices/opensource',
        'rsync'                            => 'LinuxDevices/opensource',
        'smcroute'                         => 'LinuxDevices/opensource',
        'sshpass'                          => 'LinuxDevices/opensource',
        'strace'                           => 'LinuxDevices/opensource',
        'tcpdump'                          => 'LinuxDevices/opensource',
        'tslib'                            => 'LinuxDevices/opensource',
        'AT91load'                         => 'LinuxDevices/programingUtils',
        'CobraLoad'                        => 'LinuxDevices/programingUtils',
        'ERGAT91load_bcp4600'              => 'LinuxDevices/programingUtils',
        'ERGAT91load_eb5600'               => 'LinuxDevices/programingUtils',
        'ERGAT91load_tp5600'               => 'LinuxDevices/programingUtils',
        'flash_copier_eb5600'              => 'LinuxDevices/programingUtils',
        'flash_copier_pcp5700'             => 'LinuxDevices/programingUtils',
        'flash_copier_tp5600'              => 'LinuxDevices/programingUtils',
        'SDCardCopy'                       => 'LinuxDevices/programingUtils',
        'ViperLoad'                        => 'LinuxDevices/programingUtils',
        'arm-926ejs-linux-gnueabi'         => 'LinuxDevices/toolchain',
        'binutils'                         => 'LinuxDevices/toolchain',
        'crosstool-ng'                     => 'LinuxDevices/toolchain',
        'gdb'                              => 'LinuxDevices/toolchain',
        'imageviewer'                      => 'LinuxDevices/utilities',
        'imgput'                           => 'LinuxDevices/utilities',
        'thrash'                           => 'LinuxDevices/utilities',
        'webviewer'                        => 'LinuxDevices/utilities',
        'haserl'                           => 'LinuxDevices/webserver',
        'lua'                              => 'LinuxDevices/webserver',
        'thttpd'                           => 'LinuxDevices/webserver',
        'compat-wireless'                  => 'LinuxDevices/wireless',
        'hostapd-experimental'             => 'LinuxDevices/wireless',
        'rt2571'                           => 'LinuxDevices/wireless',
        'rt2870-firmware'                  => 'LinuxDevices/wireless',
        'rt3070'                           => 'LinuxDevices/wireless',
        'wireless_tools'                   => 'LinuxDevices/wireless',
        'wpa-supplicant'                   => 'LinuxDevices/wireless',
        'zd1211-firmware'                  => 'LinuxDevices/wireless',

        # Plan to move these (and a few others too)
        'dropbear'                         => 'LinuxDevices/opensource',
        'debian_dpkg'                      => 'LinuxDevices/opensource',
        'openobex'                         => 'LinuxDevices/opensource',
        'dtc'                              => 'LinuxDevices/opensource',
        'linux_gnu_tools'                  => 'LinuxDevices/toolchain',
            'watchdog'                         => 'LinuxDevices/opensource',
            'zlib_linux'                       => 'LinuxDevices/opensource',
            'sktcat'                           => 'LinuxDevices/opensource',
            'mono'                             => 'LinuxDevices/opensource',
            'libpng'                           => 'LinuxDevices/opensource',

        'viper-support'                    => 'LinuxDevices/libraries',
        'linux_types'                      => 'LinuxDevices/libraries',

        'busybox'                          => 'LinuxDevices/filesystems',
        'day0-upgrade'                     => 'LinuxDevices/filesystems',
    );

    my %VobRename = (
        'LMOS'                      => 'LinuxDevices',
        'MANUFACTURING'             => 'Manufacturing',
        'MREF_Package'              => 'MREF_Package',
        'MASS_Dev'                  => 'MASS_Dev_Bus',
        's4k_tracs'                 => 'ITSO_TRACS',
        'MASS_Dev_Tools'            => 'DevTools',

        'GMPTE2005'                 => 'ITSO_TRACS',
        'GMPTE2005_obe'             => 'ITSO_TRACS/obe/dummyDir',
        'UK_ITSO_COMPLIANT'         => 'ITSO_TRACS',

        'MASS_Dev_Infra/security'   => 'MASS_Dev_Infra/Security',
        'MASS_Dev_Infra/web'        => 'MASS_Dev_Infra/Web',
        'MASS_Dev_Infra/cdss'       => 'MASS_Dev_Infra/Cdss',

        'TRACS/faresets'            => 'ITSO_TRACS/faresets',
        'ProjectCD'                 => 'DPG_SWCode/ProjectCD',

    );

    my %PreferredPath = (
        'MASS_Dev_Bus/Reports'      => 1,
        'MASS_Dev_Bus/CBP'          => 1,
        'MASS_Dev_Bus/Business'     => 1,
        'MASS_Dev_Bus/CIPP'         => 1,

        'MASS_Dev_Infra/ProjectSpecific' => 1,
    );

    # default is 1
    my %VobDepth = (
        'DPG_SWBase'                => 2,
        'ITSO_TRACS'                => 2,
        'ITSO_TRACS/Packages'       => 1,
        'MASS_Dev_Bus'              => 2,
        'MASS_Dev_Infra'            => 2,
        'MPR'                       => 2,
        'DPG_SWCode/ProjectCD'      => 3,
        'TRACS'                     => 2,
        'VIX-PAYMENTS'              => 2,
        'WINCE500'                  => 2,
        'DAMS_mos_diag'             => 2,
        'MASS_Dev_Bus/Financial'    => 3,
        'SmartSite'                 => 2,
    );

    return ('SVN') if ( $PackageData{$pkgid}{isSVN} );
    my $name = $PackageData{$pkgid}{name};

    # If only one VOB
    #
    my $path = '';
    unless ( $PackageData{$pkgid}{BadVob} || $PackageData{$pkgid}{MultiVob} )
    {
        my @paths = reverse sort keys %{$PackageData{$pkgid}{vobPath}};
        $path = $paths[0] if exists $paths[0];
    }

    #
    #   Some path cleanup
    #
    if ( $path )
    {
        $path =~ s~\s+~~i;
        $path =~ s~/build.pl$~~i;
        $path =~ s~/src$~~i;
        $path =~ s~DPC_SWCode/~DPG_SWCode/~i;
        $path =~ s~MASS_Dev/Bus/~MASS_Dev_Bus/~i;
        $path =~ s~MASS_Dev_Bus/Cbp/~MASS_Dev_Bus/CBP/~i;
        $path =~ s~MASS_Dev_Bus/WebServices~MASS_Dev_Bus/WebServices~i;
        $path =~ s~/Vastraffik/~/Vasttrafik/~;
        $path =~ s~/MREF_Package/ergpostmongui$~/MREF_Package/ergpostmongui~i;
    }
    
    #
    #   Brute force VOB renaming
    #
    foreach my $name ( keys %VobRename  )
    {
        my $newName = $VobRename{$name};
        $path =~ s~^/$name/~/$newName/~i;
        $path =~ s~^/$name$~/$newName~i;
    }

    $PackageData{$pkgid}{mappingPath} = $path;

    return $Named{$name}  if ( exists $Named{$name} );

    return 'DevTools/ant'  if ( $name =~ m~^ant~ );
    return 'DevTools/ant'  if ( $name =~ m~^jant~ );

    return 'MASS_Dev_Dataman' if ( $name =~ m~^dm_~ );

    return 'MPR/EMV/emvl2' if ( $name =~ m~^cp[sf]-~ );

    return 'COTS' if ( $PackageData{$pkgid}{type} eq 'COTS' && ! exists $PackageData{$pkgid}{vobs}{'LMOS'});
    
    #
    #   Must resolve Multivobs
    #
    if ( $PackageData{$pkgid}{MultiVob} )
    {
        $path = resolveMultiVob($name, $pkgid );
    }

    my $vob = '';
    my @pathBase;
    my @pathFull;
    $path =~ s~/$~~g;
    $path =~ s~^/~~g;
    @pathFull = split( '/', $path);
    $vob = $pathFull[0] || $path;
    push @pathFull, $vob unless ( @pathFull );

    @pathBase = @pathFull;
    delete $pathBase[-1];
    push @pathBase, $vob unless ( @pathBase );

#print "Full: @pathFull\n";
#print "Base: @pathBase\n";

    if ( $vob eq 'LinuxDevices' )
    {
        return 'UNKNOWN';
    }


    return 'MOS/images'  if (($vob eq 'COTS' || $vob eq 'MOS') &&  $name =~ m~^mos_~ && $name =~ m~\d\d\d\d~);

    return 'COTS' if ( $vob =~ m~^COTS_~ );
    return 'COTS' if ( $vob eq 'COTS' );

    return 'DPG_SWBase/Demos'  if ($vob eq 'DPG_SWBase' &&  $name =~ m~^demo_~ );
    return 'DPG_SWBase/Demos'  if ( $name =~ m~^qt_demo~ );

    return 'DPG_SWBase/daf_utils'  if ( $name =~ m~^time_ce~ );
    return 'DPG_SWBase/daf_utils'  if ( $name =~ m~^daf_utils~ );
    return 'DPG_SWBase/daf_utils'  if ( $name =~ m~^daf_bertlv~ );
    return 'DPG_SWBase'            if ( $name =~ m~^daf_br_compiler~ );
    return 'DPG_SWBase'            if ( $name =~ m~^hcp5000icons$~ );

    return 'DPG_SWBase/daf_components'  if ( $vob eq 'DPG_SWBase' && $name =~ m~^daf_component_~ );
    return 'DPG_SWBase/daf_transap'  if ( $path =~ m~/transap$~ || $path =~ m~/transap/~ );
#   return 'DPG_SWBase/daf'  if ( $vob eq 'DPG_SWBase' && $name =~ m~^daf_~ );
    return 'DPG_SWBase/IDC'  if ( $vob =~ m~DPG_SW~ && $name =~ m~^IDC~ );

    return 'DPG_SWCode/dac'  if ( $name =~ m~^dac_~ );
    return 'DPG_SWCode/ddu'  if ( $name =~ m~^ddu_~ );
    return 'DPG_SWCode/utilities'  if ( $vob eq 'DPG_SWCode' && $path =~ m/utilities/ );

    if ( $name =~ m~^VIX~ || $name =~ m~^ERG~ )
    {
        return 'MREF_Package'
            if ( $vob =~ m~^CORE~ || $vob =~ m~^MASS~ || $vob =~ m~^MREF~ );
    }

#    if ( $vob ne 'MREF_Package' )
#    {
#print "---- $name, $path\n" if ( $name =~ m~^VIX~ );
#print "---- $name, $path\n" if ( $name =~ m~^ERG~ );
#    }

    #
    #   ProjectCd is badly done
    #   Many packages are in named directories, some are not.
    #
    if ( defined $pathFull[1] && $pathFull[1] eq 'ProjectCD' )
    {
        push @pathBase, $pathFull[2] if ( defined $pathFull[2]  );
    }

    #
    #   Detect core_xxx packages
    #
    if ( $vob eq 'MASS_Dev_Infra' && $path =~ m~/core_~ )
    {
        return "$vob/Core";
    }

    return "UNKNOWN"
        unless ( $vob );

    #
    #   Can we map the package into a preferred path
    #
    foreach my $ppath ( sort keys %PreferredPath )
    {
        if ( $path =~ m~${ppath}(/|$)~i )
        {
#print "---- Preferred path: $name, $ppath\n";
            return $ppath;
        }

        #
        #   Try a little harder
        #
        foreach my $tpath  ( keys %{$PackageData{$pkgid}{vobPath}} )
        {
            if ( $tpath =~ m~${ppath}(/|$)~i )
            {
#print "---- Preferred path: $name, $ppath\n";
                return $ppath;
            }
        }
    }

    #
    #   Last resort
    #   Determine depth for this path
    #
    my $depth = 1;
    foreach ( reverse sort keys %VobDepth)
    {
        if ( $path =~ m~^$_~ )
        {
            $depth = $VobDepth{$_};
            last;
        }
    }

#print "--Joining: $name, $depth, @pathBase\n";
    return pathJoin($depth, $path, $name, @pathBase);
}

sub pathJoin
{
    my ($num, $path, $name, @data) = @_;
    my $val = '';
    my $char = '';
    for( my $ii = 0; $ii < $num; $ii++)
    {
        last unless ( defined $data[$ii] );
        $val = $val . $char . $data[$ii];
        $char = '/'
    }
#print "----$path, $name: $num, @data --> $val\n";
    return $val;
}


#-------------------------------------------------------------------------------
# Function        : resolveMultiVob
#
# Description     : Time to resolve multivob issues
#
# Inputs          : $name           - Package Name
#                   $pkgid          - Package ID
#
#
# Returns         : Resulved path
#
sub resolveMultiVob
{
    my ($name, $pkgid) = @_;
    my $path = '';

my %preferredVob = (
        'uiconv'        => 'DPG_SWBase',
        'gnupg'         => 'COTS',
    );


    my $pvob = $preferredVob{$name};
    unless ( defined $pvob )
    {
        if ( exists ($PackageData{$pkgid}{vobs}{MASS_Dataman}) && exists ($PackageData{$pkgid}{vobs}{MASS_Dev_Dataman})  )
        {
            $pvob = 'MASS_Dev_Dataman';
        }

        if ( exists ($PackageData{$pkgid}{vobs}{DPG_SWBase}) && exists ($PackageData{$pkgid}{vobs}{DPG_SWCode})  )
        {
            $pvob = 'DPG_SWCode';
        }

        if ( exists ($PackageData{$pkgid}{vobs}{MREF_Package}) )
        {
            $pvob = 'MREF_Package';
        }

        if ( exists ($PackageData{$pkgid}{vobs}{MASS_Dev}) && exists ($PackageData{$pkgid}{vobs}{MASS_Dev_Bus}))
        {
            $pvob = 'MASS_Dev_Bus';
        }

        if ( exists ($PackageData{$pkgid}{vobs}{s4k_obe}) && exists ($PackageData{$pkgid}{vobs}{GMPTE2005}))
        {
            $pvob = 'GMPTE2005';
        }

        if ( exists ($PackageData{$pkgid}{vobs}{s4k_obe}) && exists ($PackageData{$pkgid}{vobs}{GMPTE2005_obe}))
        {
            $pvob = 'GMPTE2005_obe';
        }

        if ( exists ($PackageData{$pkgid}{vobs}{TRACS}) && exists ($PackageData{$pkgid}{vobs}{GMPTE2005}))
        {
            $pvob = 'GMPTE2005';
        }
        
        if ( exists ($PackageData{$pkgid}{vobs}{MASS_Dev_Infra}) && exists ($PackageData{$pkgid}{vobs}{MASS_Dev_Tools}))
        {
            $pvob = 'MASS_Dev_Infra';
        }

        if ( exists ($PackageData{$pkgid}{vobs}{COTS}) && exists ($PackageData{$pkgid}{vobs}{MOS}))
        {
            $pvob = 'MOS';
        }
            
        if ( exists ($PackageData{$pkgid}{vobs}{COTS}) && exists ($PackageData{$pkgid}{vobs}{MPR}))
        {
            $pvob = 'MPR';
        }

        if ( exists ($PackageData{$pkgid}{vobs}{COTS}) && exists ($PackageData{$pkgid}{vobs}{COTS_Java}))
        {
            $pvob = 'COTS';
        }
    }

    if ( defined $pvob )
    {
        if ( exists $PackageData{$pkgid}{vobResolver}{$pvob} )
        {
            $path = $PackageData{$pkgid}{vobResolver}{$pvob} ;
        }
    }
    else
    {
        Message ("Unresolved multivob: $PackageData{$pkgid}{name}");
#DebugDumpData("DATA", \$PackageData{$pkgid} );
#exit 1;
    $path = 'UNKNOWN';
    }

    return $path;
}


#-------------------------------------------------------------------------------
# Function        : examineVcsTag
#
# Description     : Examine a VCS Tag and determine if it looks like rubbish
#
# Inputs          : Tag to examine
#
# Returns         : Badness
#
sub examineVcsTag
{
    my ($vcstag) = @_;
    my $bad = 0;
    if ( $vcstag =~ m~^CC::(.*?)(::(.+))?$~ )
    {
        my $path = $1  || '';
        my $label = $2 || '';
#print "$vcstag, $bad, $path, $label\n";
        $bad = 1 unless ( $label );
        $bad = 1 if ( $label =~ m~^N/A$~i || $label  =~ m~^na$~i );

        $bad = 1 unless ( $path );
        $bad = 1 if ( $path =~ m~^N/A$~i || $path  =~ m~^na$~i );
        $bad = 1 if ( $path =~ m~^/dpkg_archive~ || $path  =~ m~^dpkg_archive~ );
        $bad = 1 if ( $path =~ m~^/devl/~ || $path  =~ m~^devl/~ );
        $bad = 1 if ( $path =~ m~^CVS~ );
        $bad = 1 if ( $path =~ m~^http:~i );
        $bad = 1 if ( $path =~ m~^[A-Za-z]\:~ );
        $bad = 1 if ( $path =~ m~^//~ );
        $bad = 1 if ( $path =~ m~^/blade1/~ );
        $bad = 1 if ( $path =~ m~^/devl/~ );
        $bad = 1 if ( $path =~ m~^/*none~i );
        $bad = 1 if ( $path =~ m~^/*NoWhere~i );
        $bad = 1 if ( $path =~ m~^-$~i );
        $bad = 1 if ( $path =~ m~^cvsserver:~ );
        $bad = 1 if ( $path =~ m~,\s*module:~ );
        $bad = 1 if ( $path =~ m~[()]~ );
#        $bad = 1 unless ( $path =~ m~^/~ );
    }
    else
    {
        $bad = 1;
    }
    return $bad;
}

#-------------------------------------------------------------------------------
# Function        : usedBy
#
# Description     : Given a pvid, determine which release(s) need it
#
# Inputs          : $pvid
#
# Returns         : Nothing
#
sub usedBy
{
    my ($pvid) = @_;
    Error ("PVID is not an essential package") unless ( exists $ScmPackages{$pvid} );

    my @releases = @{$ScmPackages{$pvid}{'release'}} if exists($ScmPackages{$pvid}{'release'});
    my @users = @{$ScmPackages{$pvid}{'usedBy'}} if exists($ScmPackages{$pvid}{'usedBy'});

    while ( @users )
    {
        my $pv = pop @users;
        push @releases, @{$ScmPackages{$pv}{'release'}} if (exists $ScmPackages{$pv}{'release'});
        push @users, @{$ScmPackages{$pv}{'usedBy'}} if (exists($ScmPackages{$pv}{'usedBy'}));
    }

    my %releases;
    my %ireleases;
    my @dreleases = ();
    my @ireleases;
    foreach ( @releases )
    {
        if ( $ScmPackages{$pvid}{tlp}  )
        {
            next if ( exists $releases{$_} );
            push @dreleases, $_;
            $releases{$_} = 1;
        }
        else
        {
            next if ( exists $ireleases{$_} );
            push @ireleases, $_;
            $ireleases{$_} = 1;
        }
    }
    return \@dreleases, \@ireleases;
}

#-------------------------------------------------------------------------------
# Function        : smartPackageType
#
# Description     : Have a look at the projects in the package set and
#                   attempt to determine what sort of mechanism to use
#
# Inputs          : pkgid            - Package ID
#
# Returns         : Type, Array of suffixes
#
sub smartPackageType
{
    my ($pkgid) = @_;
    my %suffixes;

    #
    #   Suffixes for all packages
    #
    foreach  ( @{$PackageSet{$pkgid}} )
    {
        my $suffix = $ScmPackages{$_}{'suffix'};
        $suffixes{$suffix}++;
    }

    my $packageType = 'UNKNOWN';

    if ( exists $suffixes{'.cots'} ) {
        $packageType = 'COTS';

    } elsif ( exists $suffixes{'.tool'} ) {
        $packageType = 'TOOL';

    } elsif ( scalar (keys %suffixes ) == 1 ) {
        $packageType = 'SINGLE_PROJECT';

    } else {
        $packageType = 'MULTIPLE_PROJECT';
    }

    return $packageType, keys %suffixes;
}


#-------------------------------------------------------------------------------
# Function        : vcsCleanup
#
# Description     : Cleanup and rewrite a vcstag
#
#                   DUPLICATED IN:
#                       - cc2svn_procdata
#                       - cc2svn_importpackage
#
# Inputs          : vcstag
#
# Returns         : Cleaned up vcs tag
#
sub vcsCleanup
{
    my ($tag) = @_;
    $tag =~ tr~\\/~/~;                              # Force use of /
    $tag =~ s~/+$~~;                                # Trailing /
    if ( $tag =~ m~^CC::~ )
    {
        $tag =~ s~CC::/VOB:/~CC::/~;                # Kill stuff
        $tag =~ s~CC::load\s+~CC::~;                # Load rule
        $tag =~ s~CC::\s+~CC::~;                    # Leading white space
        $tag =~ s~CC::[A-Za-z]\:/~CC::/~;           # Leading driver letter
        $tag =~ s~CC::/+~CC::/~;                    # Multiple initial /'s
        $tag =~ s~/build.pl::~::~i;
        $tag =~ s~/src::~::~i;
        $tag =~ s~MASS_Dev_Bus/Cbp/~MASS_Dev_Bus/CBP/~i;
        $tag =~ s~MASS_Dev_Bus~MASS_Dev_Bus~i;
        $tag =~ s~/MASS_Dev/Infra~MASS_Dev_Infra~i;
        $tag =~ s~/MASS_Dev/Bus/web~/MASS_Dev_Bus/web~i;

        $tag =~ s~/Vastraffik/~/Vasttrafik/~;
        $tag =~ s~/MREF_Package/ergpostmongui$~/MREF_Package/ergpostmongui~i;
        $tag =~ s~DPC_SWCode/~DPG_SWCode/~i;
    }
    return $tag;
}

#-------------------------------------------------------------------------------
# Function        : extractVob
#
# Description     : Extract the VOB for a package
#
# Inputs          : $entry              - pvid
#
# Returns         : Vob Name
#
sub extractVob
{
    my ($entry) = @_;

    $ScmPackages{$entry}{'vcstag'} = vcsCleanup($ScmPackages{$entry}{'vcstag'});

    my $tag = $ScmPackages{$entry}{vcstag};
    my $package = $ScmPackages{$entry}{name};
    if ( $tag =~ m~^SVN::~ )
    {
        $tag =~ m~SVN::(.*)(/tags/|/branches/|/trunk)~;
        return 'SVN', $1;
    }
        
    if ( $tag !~ m~^CC::~ || examineVcsTag ($tag)){
        $ScmPackages{$entry}{BadVob} = 1;
        return undef;
    }

    $tag =~ m~^CC::(.*)::(.*)~;
    my $path = '/' . $1;
    $path =~ tr~\\/~/~s;
    my @pelements = split( m'/+', $path);
    my $vob = $pelements[1];
    unless ( $vob )
    {
        $ScmPackages{$entry}{BadVob} = 1;
        return undef;
    }

    $ScmPackages{$entry}{VobName} = $vob;
    $ScmPackages{$entry}{VobPath} = $path;
    return $vob, $path;
}

#-------------------------------------------------------------------------------
# Function        : getBadLabelData
#
# Description     : Read in a previous log file and determine versions that
#                   have already been examined
#
# Inputs          : 
#
# Returns         : 
#
sub getBadLabelData
{
    my $badFile = 'cc2svn_labeltest.bad.txt';
    Message ("Reading Bad Label: $badFile");
    open (my $fh, '<', $badFile ) || Error ("Cannot open $badFile");
    while ( <$fh> )
    {
        #
        #   Format of data is:
        #       pvid, $name:, $tag, $rv
        #
        chomp;
        next if ( m~^#~ );
        my @data = split (/\s*,\s*/, $_);
        next unless ( $data[0] );
        $ScmPackages{$data[0]}{BadCCView} = 1 if exists ($ScmPackages{$data[0]});
    }
    close $fh;
}

#-------------------------------------------------------------------------------
# Function        : getProtectedPackages
#
# Description     : Read in protected package data
#
# Inputs          : 
#
# Returns         : 
#
sub getProtectedPackages
{
    my $badFile = 'cc2svn_protected.txt';
    Message ("Reading Protected Package: $badFile");
    open (my $fh, '<', $badFile ) || Error ("Cannot open $badFile");
    my $section_comment;
    while ( <$fh> )
    {
        #
        #   Format of data is:
        #       packageName     - protected
        #      -packageName     - Known Broken
        #
        #   Line Comment is '#'
        #   Package Comment is delimted by White space
        #   Section Comment is [ comment ]
        #
        s~\s+$~~;
        s~^\s+~~;
        next if ( m~^#~ );
        if ( m~^\s*\[\s*(.*?)\s*\]~ )
        {
            $section_comment = $1;
            next;
        }

        $_ .= ' ';
        my @data = split (/ /, $_, 2);
        next unless ( $data[0] );
        my $name = $data[0];
        my $comment = $data[1];
        $comment =~ s~^\s+#~~;
        $comment =~ s~^\s+~~;
        $comment =~ s~\s+$~~;
        $comment = $comment || $section_comment;
        my $mode = 'Protected';
        if ( $name =~ m~^-(.*)~ )
        {
            $name = $1;
            $mode = 'Broken'
        }
        $Protected{$name}{mode} = $mode;
        $Protected{$name}{comment} = $comment if ( $comment );
    }
    close $fh;
#    DebugDumpData('%Protected', \%Protected );
}

#-------------------------------------------------------------------------------
#   Documentation
#

=pod

=for htmltoc    SYSUTIL::cc2svn::

=head1 NAME

cc2svn_procdata - Process CC2SVN Essential Package Data

=head1 SYNOPSIS

  jats cc2svn_procdata [options]

 Options:
    -help              - brief help message
    -help -help        - Detailed help message
    -man               - Full documentation
    -usedby=PVID       - Determine 'Releases' that use a specified PVID
    -allpackages       - Generate data for ALL packages

=head1 OPTIONS

=over 8

=item B<-help>

Print a brief help message and exits.

=item B<-help -help>

Print a detailed help message with an explanation for each option.

=item B<-man>

Prints the manual page and exits.

=item B<-usedby=PVID>

This option will alter the operation of the program. It will display the
releases that 'use' the specified PVID and then exit.

=back

=head1 DESCRIPTION

This program is a tool used in the conversion of ClearCase VOBS to subversion.

=over 8

=item *

It will process a datafile and generate infiormation used by other tools.

=item *

It will display suspect package versions.

=item *

It will generate an HTML file with a great deal of information about the
packages in the conversion.

=item *

It can backtrack a PVID and report the Release or Releases that need the package
version

=back

=cut