########################################################################
# COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.
#
# Module name   : rmMerge_migrate_package.pl
# Module type   : JATS Utility
# Compiler(s)   : Perl
# Environment(s): jats
#
# Description   : Migrate a package-version from the Pulse RM to the one-true RM (old)
#
# Usage         : See POD at the end of this file
#
#......................................................................#

require 5.008_002;
use strict;
use warnings;

use Pod::Usage;
use Getopt::Long;
use JatsError;
use JatsRmApi;
use JatsSystem;
use FileUtils;
use ConfigurationFile;
use JatsProperties;
use File::Copy;
use DBI;
my $RM_DB;


my $oldRMWrite = ['OLD', 'jdbc:oracle:thin:@auawsards001:1521:RELEASEM', 'RELEASE_MANAGER', 'ske2k0se'];
my $oldRMCred  = ['OLD', 'jdbc:oracle:thin:@auawsards001:1521:RELEASEM', 'RM_READONLY', 'RM_READONLY'];
my $newRMCred  = ['NEW', 'jdbc:oracle:thin:@auawsards002:1521:RELEASEM', 'RM_READONLY', 'Tp8WmmDKMq2Z'];

my $newDpkg = '/net/auawsaarc002/export/devl/dpkg_archive';
my $oldDpkg = '/export/devl/dpkg_archive';

my $VERSION = 1.0;
my $opt_help=0;
my $opt_verbose=0;
my $opt_debug=0;
my $opt_reuseRm;
my $opt_justRm;
my $opt_test = 0;
my $opt_history;
my $opt_nohistory;
my $opt_relabel;
my $opt_placekeeper;
my $opt_autoPlacekeeper;
my $opt_base=0;
my $opt_after;

my $pname;
my $pversion;

my $SplitPvid = 1150630;
my $newData;
my $oldData;
my $mergeData;
my $newView;
my $tipView;
my $newRmData;
my %newSvnData;
my %oldSvnData;
my $isaNewPackage;
my $afterPvid;

my $dirOut = 'migrate';
my $dirWork = catdir( $dirOut, 'work');
my $dirLog  = catdir ($dirOut, 'log');

mkdir ($dirOut);
mkdir ($dirWork);
mkdir ($dirLog);


#-------------------------------------------------------------------------------
# Function        : Mainline Entry Point
#
# Description     :
#
# Inputs          :
#
my $result = GetOptions (
                "help:+"        => \$opt_help,
                "manual:3"      => \$opt_help,
                "verbose:+"     => \$opt_verbose,
                "debug:+"       => \$opt_debug,
                "reuseRm!"      => \$opt_reuseRm,
                "justRm!"       => \$opt_justRm,
                "test:+"        => \$opt_test,
                "historyTo:s"   => \$opt_history,
                "nohistory"     => \$opt_nohistory,
                "relabel!"      => \$opt_relabel,
                "placekeeper!"  => \$opt_placekeeper,
                "autoplacekeeper!"  => \$opt_autoPlacekeeper,
                "base:+"         => \$opt_base,
                "after:s"       => \$opt_after,
                );

                #
                #   UPDATE THE DOCUMENTATION AT THE END OF THIS FILE !!!
                #

#
#   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_help > 2 );
pod2usage(-verbose => 0, -message => "Version: $VERSION") if ( $#ARGV != 1 );

#
#   Configure the error reporting rmMerge_process now that we have the user options
#
ErrorConfig( 'name'    =>'MIGRATE',
             'verbose' => $opt_verbose,
             'debug' => $opt_debug,
             'on_exit' => \&cleanup
            );

$pname = $ARGV[0];  
$pversion = $ARGV[1];
InitFileUtils();
testPath($newDpkg);
testPath($oldDpkg);
Message ("Migrating: $pname $pversion");
MassageVersion();

#
#   Lots of sanity testing
#       Make sure it has not already been transferred
#       Locate the marked package merge point
#
$newData = checkVersion($newRMCred);
Error ("Package does not exist in Pulse RM ") unless $newData;

$oldData = checkVersion($oldRMCred);
Error ("Package already exist in Old RM ") if $oldData && !$opt_reuseRm;
Error ("Package does not exist in Old RM ") if ! $oldData && $opt_reuseRm;

if ($opt_after) {
    if ($opt_after eq $pversion) {
        Warning("Attempt to insert after myself - after option ignored");
        $opt_after = undef;
    } else {
        $afterPvid = checkVersionExists($oldRMCred, $pname, $opt_after);
        Error ("Named (after) version does not exist: $opt_after") unless $afterPvid;
    }
}

checkDependentPackages() unless $opt_placekeeper;
findMergePoint();
Error("Just testing the dependencies and insertion point") if ($opt_test == 1);

unless ($opt_reuseRm) {
    # Serialse the package data
    $newRmData = catfile( $dirLog, join('.', $pname, $pversion, 'rminfo', 'txt'));
    unlink $newRmData;
    Message ("Caputure Rm Data: $newRmData") ;
    my $rv = JatsCmd('eprog', 'rmMerge_suck.pl', $pname, $pversion, '-outfile', $newRmData);
    Error ("rmMerge_suck - failed") if $rv;
    Error ("Extracted data not found - $newRmData") unless -f $newRmData;

    # Insert new package into the old Release Manager
    Message("Create package in Release Manager");
    my @args;
    unless ($isaNewPackage) {
        Error("Internal: Merge Version not found") unless ( $mergeData->[3] );
        push @args, '-previous', $mergeData->[3];
    } else {
        push @args, '-newPackage';
    }
    push (@args ,'-placekeeper') if $opt_placekeeper;
    push (@args ,'-placekeeper') if $opt_placekeeper;
    push (@args, '-toHistory', $opt_history) if $opt_history;
    push (@args, $opt_nohistory ? '-noHistory' : '-history');
    $rv = JatsCmd('eprog', 'rmMerge_spit.pl', $pname, $pversion, '-infile', $newRmData, @args );
    Error("Package data not inserting into Release Manager") if $rv;

    # Add the package to a 'dummy' Release
    addToRelease();
}
Error("Stopped after RM import") if $opt_justRm;


# Now migrate the package into Subversion
#   Extract the new version - may already have been done
svnInsertNewPackage();

# Transfer the dpkg_archive objects
#
dpkgTransfer();

cleanup();

#-------------------------------------------------------------------------------
# Function        : MassageVersion 
#
# Description     : Massage the provided version number. MAy set it to the base ripple
#
# Inputs          : 
#
# Returns         : 
#
sub MassageVersion
{
    return unless $opt_base;
    if ($pversion =~ m~(.*)(\.\d+)(\d{3})(\.[\w]+)~) {
        my ($p1,$p2,$p3,$p4) = ($1,$2,$3,$4);
        $p3 = '000';
        $p2 = '.0' if $opt_base > 1;
        $pversion = $p1 . $p2 . '000' . $p4;
        Message ("Base Non Ripple: $pname $pversion");

    } else {
        Error ("Cannot massage: $pversion");
    }
}

#-------------------------------------------------------------------------------
# Function        : addToRelease 
#
# Description     : Add the package to a 'dummy' release
#                   The rtagId is 38670 - temp and will be deleted one day
#
# Inputs          : 
#
# Returns         : 
#
sub addToRelease 
{
    my $user = 3768;            # buildadm
    my $rtagId = 38670;         # Known Release 

    #
    #   Determine the PVID of the new package
    #
    $oldData = checkVersion($oldRMCred);
    Error("Internal: Can't find added package in Release Manager") unless $oldData;

    Message ("addToRelease");
    my $m_sqlstr =  "BEGIN RELEASE_MANAGER.PK_RELEASE.ADD_PACKAGE ( $oldData->[0], 1723, $rtagId, $user );   END;";
    getDataFromRm('addToRelease', $m_sqlstr, $oldRMWrite);

    #   Force the Release Icons to be rebuilt
    $m_sqlstr =  "BEGIN RELEASE_MANAGER.TOUCH_RELEASE ( $rtagId ); END;";
    getDataFromRm('addToRelease', $m_sqlstr, $oldRMWrite);
}

#-------------------------------------------------------------------------------
# Function        : dpkgTransfer 
#
# Description     : Transfer the generated package
#                   It may not exist 
#
# Inputs          : 
#
# Returns         : 
#
sub dpkgTransfer
{
    #
    #   Ensure the package exists in the 'pulse' dpkg_archive
    #
    my $srcDir = catdir($newDpkg, $pname, $pversion);
    unless (-d $srcDir) {
        Warning("Package not found in dpkg_archive", $srcDir);
        return;
    }

    my $dstDir = catdir ($oldDpkg, $pname);
    my $dstPkg = catdir ($oldDpkg, $pname, $pversion);
    Message("Source: $srcDir") ;
    Message("Target: $dstDir");
    Error ("Package already exists: $dstPkg ") if -x $dstPkg;
    if ( ! -d $dstDir) {
        Message ("Create Package directory: $pname, $dstDir");
        mkdir $dstDir;
    }
    testPath( $dstDir );
    System ('--Show','cp', '-a', $srcDir, $dstDir);
    Error("Package not copied") unless -d $dstPkg;
     
    #   Need to set the facl stuff - its not done by the 'cp' command 
    System('setfacl', '-R', '-x', 'user:releasem',$dstPkg);
    System('setfacl', '-R', '-x', 'user:buildadm',$dstPkg);
    System('setfacl', '-R', '-x', 'group:ccperdev',$dstPkg);
    System('setfacl', '-R', '-m', 'default:user:buildadm:rwx','-m','default:user::rwx','-m','mask::r-x',$dstPkg);
    System('setfacl', '-R', '-m', 'user::r-X,group::r-X,other::r-X',$dstPkg);
}

#-------------------------------------------------------------------------------
# Function        : testPath 
#
# Description     : Test that a directory exists
#
# Inputs          : $path
#
# Returns         : Returns PATH
#                   Will not return on error
#
sub testPath
{
    my ($path) = @_;
    Debug("Testing: $path");
    return $path if -d $path;
    Error ("Path not found: $path");
}

#-------------------------------------------------------------------------------
# Function        : svnInsertNewPackage 
#
# Description     : Insert the new package version into subversion
#
# Inputs          : 
#
# Returns         : 
#
sub svnInsertNewPackage
{
    my $rv;
    #
    #   Get data about the new version of the package
    #   The information has already been inserting into the RM database
    #
    getReleaseData(\%newSvnData, $newRMCred);
    getReleaseData(\%oldSvnData, $oldRMCred);
#    DebugDumpData("newSvnData", \%newSvnData);
#    DebugDumpData("oldSvnData", \%oldSvnData);

    #
    #   Extract the 'new' package files into a known area
    #   Don't need the .svn info - just the files
    #   This may have been done in previous step
    #       Locate is stored in $newView
    #
    checkoutNewPackage();
    Error ("Internal. Source package not found: $newView") unless ( $newView  && -d $newView) ;

    #
    #   Extract the 'old' package files into a known area
    #   Need svn info
    #   Need to massage the newVcs to extract the tip of the package in the old system
    #       Assume its in the same location
    #       Assume we are simply appending the new version to the tip of the old version
    #       
    my $tipName = join('_', $pname, $pversion, 'tip');
    my $tipVcs = $isaNewPackage ? $oldSvnData{VCS_TAG}: $mergeData->[4];
    $tipVcs =~ s~::AUPERASVN0X~::AUPERASVN01~;
    $tipVcs =~ s~\@.*~~;

    my $svnUrl = $tipVcs;
    $svnUrl =~ m~^SVN::(.*)::~;
    $svnUrl = $1;

    my $pkgBase = $svnUrl;
    $pkgBase =~ s~/[^/]*$~~;
    $pkgBase =~ s~/branches$~~;

    $tipView = catdir($dirWork,$tipName );

    #
    #   Determine if we need to branch this view
    #   Do this before we create the view
    #       If branching - then do an extact extract
    #       Else - do a tip extract
    #
    my $mustBranch = 0;   
    my $branchname;
    my $pkgext = $mergeData->[2];
    if ($pkgext =~ m~PulseImport.Branch.(.*)~) {
        $branchname = $1;
Debug0("Import to branch: $branchname");
        my $coBranch = 'trunk';
        if ($mergeData->[4] =~ m~/branches::(.*)~ ){
            $coBranch = $1;
            $coBranch =~ s~\@.*~~;
        }
Debug0("View is on: $coBranch");
       $mustBranch = ($branchname ne $coBranch);
    }

    RmDirTree($tipView);
    if ($isaNewPackage) {
        JatsToolPrint ( 'jats_svn', 'create', $pkgBase );
    }
    Message("Extract Tip: $tipVcs");
    JatsCmdPrint('-logfile', catfile($dirLog, $tipName.'.log'),'jats_vcsrelease.pl', '-extract', '-noprefix', 
                    '-root',$dirWork, 
                    '-view', $tipName ,
                    '-label', $tipVcs, 
                    $mustBranch ? '-devMode=Work' : '-devMode=Tip' );

    #
    #   Need to branch this view
    #       Check for branch existence - error if it doesnt exist
    #
    if ($mustBranch) {
        SystemConfig ('ExitOnError' => 0);
        $rv = JatsToolPrint ( 'jats_svnlabel', '-check', '-packagebase', $pkgBase, '-branch', $branchname );
        if ($rv) {
            Message ("Create Branch: $branchname");
            $rv  = JatsToolPrint ( 'jats_svn', 'branch', $branchname, '-path', AbsPath($tipView) );
            Error("Cannot create branch: $branchname") if $rv;
        } else {
            Message ("Switch to branch: $branchname");
            $rv  = JatsToolPrint ( 'jats_svn', 'switch', $branchname, '-path', AbsPath($tipView) );
            Error("Cannot switch to branch: $branchname") if $rv;
        }
        SystemConfig ('ExitOnError' => 1);
    }

    #
    #   Use the 'jats svn import' utility
    #       It will do most of the hard work as it was developed to support the ClearCase to Subversion migration
    #
    my $dataFile = catfile($dirLog, "${pname}_${pversion}.dat");

    my @args;
    #push (@args, '-replace') if $opt_replace;

    if ($oldSvnData{COMMENTS}) {
        push @args, '-log', $oldSvnData{COMMENTS}
    }

    if ($oldSvnData{MODIFIER_NAME}) {
        push @args, '-author', $oldSvnData{MODIFIER_NAME}
    }

    my $created = $oldSvnData{MODIFIED_STAMP};
    if ( $created )
    {
        $created =~ s~ ~T~;
        $created .= '00000Z';
        push @args, '-date', $created;
    }

    if ($opt_relabel) {
        push @args, '-replace';
    }
    Message("Subverion Merge Package");
    $rv = JatsCmdPrint ('-logfile', catfile($dirLog, "${pname}_${pversion}.import.log"), 'jats_svn', 'import', $pkgBase, '-reuse', '-workspace', $tipView,
                   '-dir' , $newView, '-datafile' ,  $dataFile, '-label', "${pname}_${pversion}", @args);
    Error ("Could not import package from OLD RM") if $rv;

    #
    #   Extract the Release Manager tag
    #   Needs to be inserted into the database
    #   
    my $data;
    if ( -f $dataFile  )
    {
        my $rmData = JatsProperties::New($dataFile);
        if ( $rmData->getProperty('subversion.tag') ) {
            $data->{rmRef} = 'SVN::' . $rmData->getProperty('subversion.tag');
        } else {
            Warning ("Property files has no subversion.tag");
        }
        $data->{fileCount}    = $rmData->getProperty('files.base', 0);
        $data->{filesRemoved} = $rmData->getProperty('files.removed',0);
        $data->{filesAdded}   = $rmData->getProperty('files.added',0);
    }

    unless ( $data->{rmRef}  )
    {
        $data->{errStr} = 'Failed to determine Rm Reference';
        Error ($data->{errStr});
    }
    intoReleaseManager( $oldSvnData{PV_ID}, "${pname}_${pversion}", $data->{rmRef}, $oldRMCred);
}

#-------------------------------------------------------------------------------
# Function        : JatsToolPrint
#
# Description     : Print and Execuate a JatsTool command
#
# Inputs          : 
#
# Returns         : 
#

sub JatsToolPrint
{
    Information ("Command: @_");
    return JatsTool @_;
}
sub JatsCmdPrint
{
    Information ("Command: @_");
    return JatsCmd @_;
}

#-------------------------------------------------------------------------------
# Function        : intoReleaseManager
#
# Description     : Update VCS tags in RM
#
# Inputs          : $pvid           - PVId
#                   $pvname         - Package Version (text)
#                   $tag            - New Tag
#
# Returns         : 
#
sub intoReleaseManager
{
    my ($pvid, $pvname, $new_tag, $rmRef ) = @_;
    my $user = 3768;            # buildadm

    Message ("Update SVN tag: $pvid, $pvname  - $new_tag");
    my $m_sqlstr =  "begin release_manager.PK_RMAPI.update_vcs_details($pvid, '$new_tag', $user); end;";
    getDataFromRm('intoReleaseManager', $m_sqlstr, $rmRef);
}

#-------------------------------------------------------------------------------
# Function        : getReleaseData 
#
# Description     : Get some essential data
#
# Inputs          : dataRef
#                   RmCredentails 
#
# Returns         : 
#
sub getReleaseData
{
    my ($dataRef, $rmRef) = @_;

    my $m_sqlstr = <<"SQL_END";
        SELECT
            pv.pv_id,
            pv.src_path,
            pv.pkg_label,
            release_manager.PK_RMAPI.return_vcs_tag(PV_ID) as vcsTag,
            pv.comments,
            u.user_name,
            pv.modified_stamp
        FROM
            package_versions pv,
            packages p,
            users u
        WHERE
            p.pkg_id = pv.pkg_id
            AND p.pkg_name = ':pname'
            AND pv.pkg_version = ':pversion'
            AND pv.modifier_id = u.user_id
SQL_END
    $m_sqlstr =~ s~:pname~$pname~g;
    $m_sqlstr =~ s~:pversion~$pversion~g;
    my $data = getDataFromRm('getReleaseData', $m_sqlstr, $rmRef, {oneRow => 1, error =>  "getReleaseData: No data found"  });

    $dataRef->{PV_ID}           = $data->[0]; 
    $dataRef->{SRC_PATH}        = $data->[1]; 
    $dataRef->{PKG_LABEL}       = $data->[2]; 
    $dataRef->{VCS_TAG}         = $data->[3]; 
    $dataRef->{COMMENTS}        = $data->[4]; 
    $dataRef->{MODIFIER_NAME}   = $data->[5]; 
    $dataRef->{MODIFIED_STAMP}  = $data->[6]; 
}

#-------------------------------------------------------------------------------
# Function        : checkDependentPackages 
#
# Description     : Check that ALL dependent packages of the 'new' version exist
#                   in the old Release Manager 
#
# Inputs          : 
#
# Returns         : Will not return if dependencies are missing 
#
sub checkDependentPackages
{
    #
    #   Determine the package dependencies
    #
    my $m_sqlstr = <<"END_SQL";
SELECT
    p2.pkg_name,
    pv2.pkg_version
FROM
    package_versions pv,
    package_versions pv2,
    packages p,
    packages p2,
    package_dependencies pd
WHERE
    p.pkg_id = pv.pkg_id
    AND p.pkg_name = '$pname'
    AND pv.pkg_version = '$pversion'
    and pv.pv_id = pd.pv_id
    and pd.dpkg_id = p2.pkg_id
    and pd.dpv_id = pv2.pv_id
END_SQL
    my $data = getDataFromRm('checkDependentPackages', $m_sqlstr, $newRMCred);
    return unless $data;

    #
    #   Examine each dependency
    #
    foreach my $entry ( @{$data}) {
        Verbose("Check for: $entry->[0], $entry->[1]");
        my $pvid = checkVersionExists($oldRMCred, $entry->[0], $entry->[1]);
        unless ($pvid) {
            if ($opt_autoPlacekeeper) {
                Warning("Required Dependency not found: $entry->[0], $entry->[1]", "Others not tested");
                $opt_placekeeper = 1;
                last;
            } else {
                ReportError("Required Dependency not found: $entry->[0], $entry->[1]");
            }
        }
    }
    ErrorDoExit();

}

#-------------------------------------------------------------------------------
# Function        : cleanup 
#
# Description     : Cleanup created stuff
#
# Inputs          : 
#
# Returns         : 
#
sub cleanup
{
    Message("Cleanup");
    #Debug0("Leaving: newView", $newView);
    #Debug0("Leaving: tipView", $tipView);
    RmDirTree($newView);
    RmDirTree($tipView);
}

#-------------------------------------------------------------------------------
# Function        : findMergePoint 
#
# Description     : Determine the point at which the package will be inserted into the old RM
#                   This may have been marked in the OLD rm database
#
# Inputs          : 
#
# Returns         : 
# 
sub findMergePoint
{
    my $m_sqlstr;

    #
    #   Use merge point specifed by 'after'
    #   
    if ($opt_after) {
        $m_sqlstr = <<"END_SQL";
    SELECT
        pv.pv_id,
        pv.pkg_id,
        pv.pkg_idext,
        pv.pkg_version,
        release_manager.PK_RMAPI.return_vcs_tag(PV_ID)
    FROM
        release_manager.package_versions pv,
        release_manager.packages p
    WHERE
      pv.pv_id = $afterPvid
END_SQL
        my $data = getDataFromRm('findMergePoint', $m_sqlstr, $oldRMCred, {oneRow => 1, error => "findMergePoint-After. No RMdata", sql => 0});
        $mergeData = $data;
        Message("Merge Point specified by user - after $opt_after");
        return;
    }


    #
    # Determine if a branchpoint has been marked on the package
    #
    $m_sqlstr = <<"END_SQL";
    SELECT * FROM (
        SELECT
            pv.pv_id,
            pv.pkg_id,
            pv.pkg_idext,
            pv.pkg_version,
            release_manager.PK_RMAPI.return_vcs_tag(PV_ID)
        FROM
            release_manager.package_versions pv,
            release_manager.packages p
        WHERE
            p.pkg_id = pv.pkg_id
            AND p.pkg_name = '$pname'
            AND pv.pkg_idext IS NOT NULL
        ORDER by pv.pv_id desc  )
    WHERE ROWNUM = 1
END_SQL

    my $data = getDataFromRm('findMergePoint', $m_sqlstr, $oldRMCred, {oneRow => 1, data => 0});
    if ($data) {
        $mergeData = $data;
        Message("Merge Point specified in Release Manager");
    } else {

        #
        #   Merge point has not been marked
        #       If the package name does not exist, then its a new package
        $m_sqlstr = <<"END_SQL";
    SELECT
        count(*)
    FROM
        release_manager.packages p, package_versions pv
    WHERE
        p.pkg_name = '$pname'
        and pv.pkg_id = p.pkg_id
        and pv.v_ext = '$newData->[5]'
END_SQL
       $data = getDataFromRm('findMergePoint', $m_sqlstr, $oldRMCred, {oneRow => 1, sql => 0});
       unless ($data && $data->[0] > 0 ) {
           #
           #   Package does not exist at all in Release Manager
           #   Flag new package creation
           #
           $isaNewPackage = 1;
           Message("New Package: $pname");
           $mergeData->[2] = '';
           $mergeData->[4] = '';
           return;
       }

        #   See if we can guess it.
        #       Get the most recent (non-ripple) package-version
        #       See how much it differs from the new version
        #
        $m_sqlstr = <<"END_SQL";
    SELECT
        pv.pv_id,
        pv.pkg_id,
        pv.pkg_idext,
        pv.pkg_version,
        release_manager.PK_RMAPI.return_vcs_tag(PV_ID)
    FROM
        release_manager.package_versions pv,
        release_manager.packages p
    WHERE
        p.pkg_id = pv.pkg_id
        AND p.pkg_name = '$pname'
        and pv.build_type = 'A'
    ORDER by pv.pv_id desc
END_SQL
        my $data = getDataFromRm('findMergePoint', $m_sqlstr, $oldRMCred, {oneRow => 1, error => "findMergePoint. No RMdata", sql => 0});

        #
        #   If the 'most recent' version is before the split, then nothing has changed in the old system
        #   We can determine the merge point.
        #
        if ($data->[0] < $SplitPvid ) {
            Message("Most Recent version is before split");
            if ( my $baseVersion = checkForBaseVersion( $data->[0], $data->[3]) ) {
                $data = $baseVersion;
            }
            $mergeData = $data;

        } else {

           if ( my $baseVersion = checkForBaseVersion( $data->[0], $data->[3]) ) {
               if ($baseVersion && $baseVersion->[0] < $SplitPvid ) {
                   $mergeData = $baseVersion;
               }
           }

           unless ($mergeData) {
               checkoutNewPackage();
               checkoutTipPackage($data);
               my $rv = checkPkgDiffs($newView, $tipView);
               if ($rv eq 'd') {
                   $mergeData = $data;
                }
           }
       }
    }
    Error("Cannot determine package merge point") unless $mergeData;
    Message ("Insert Package after: $mergeData->[3], $mergeData->[2], $mergeData->[4]")
#DebugDumpData("mergeData", $mergeData);
}

#-------------------------------------------------------------------------------
# Function        : checkForBaseVersion 
#
# Description     : Determine the previous non-ripple version of a package version
#                   Designed to backtrack to allow insertion at base of package
#
# Inputs          : $tpvid - pvid of test version
#                   $tversion   - Version to test
#
# Returns         : 
#
sub checkForBaseVersion
{
    my ($tpvid, $tversion) = @_;

    my $m_sqlstr = <<"END_SQL";
SELECT pv_id, pkg_version
 FROM ( SELECT * 
  FROM
    (SELECT pv.build_type,pv.last_pv_id AS raw_last_pvid ,pv_id,pv.pkg_version,DECODE(pv.pv_id, pv.last_pv_id, NULL, pv.last_pv_id) AS last_pv_id, comments, to_char(pv.modified_stamp, 'DD-MON-YYYY HH24:MM') as modified_stamp, u.user_name
    FROM release_manager.package_versions pv, users u
    WHERE u.user_id = pv.modifier_id and pv.PKG_ID IN (SELECT pkg_id FROM release_manager.package_versions pv WHERE pv.pv_id = $tpvid )
    )
    START WITH pv_id =  $tpvid
    CONNECT BY nocycle prior last_pv_id = pv_id
  ) WHERE build_type != 'Y'
END_SQL
       my $data = getDataFromRm('checkForBaseVersion', $m_sqlstr, $oldRMCred, {oneRow => 1, dump => 0});
       return undef unless $data;

       $m_sqlstr = <<"END_SQL";
       SELECT
           pv.pv_id,
           pv.pkg_id,
           pv.pkg_idext,
           pv.pkg_version,
           release_manager.PK_RMAPI.return_vcs_tag(PV_ID)
       FROM
           release_manager.package_versions pv
       WHERE
           pv.pv_id = $data->[0]
END_SQL
          $data = getDataFromRm('checkForBaseVersion', $m_sqlstr, $oldRMCred, {oneRow => 1, dump => 0});
          Message ("Base Version for $tversion is $data->[3]") if $data;
          return $data;
}


#-------------------------------------------------------------------------------
# Function        : checkPkgDiffs 
#
# Description     : Determine how different two package-versions are
#
# Inputs          : $newView
#                   $tipView    
#
# Returns         : d - Only build file diffs
#                   D - More than just build file diffs
#
sub checkPkgDiffs
{
    my $rCode;
    my ($newView, $tipView) = @_;
    my $rv = System('--Shell','diff', '-rq', '--exclude=build.pl', $newView, $tipView, '>/dev/null');
    if ($rv == 0) {
        $rCode = 'd';
    } else {
        $rCode = 'D';
    }
    print("TipBuildDiff: $rCode\n");
   return $rCode;
}

#-------------------------------------------------------------------------------
# Function        : checkoutNewPackage 
#
# Description     : Checkout the Pulse package 
#
# Inputs          : 
#
# Returns         : 
#
sub checkoutNewPackage
{
    return if $newView;
    my $newName = join('_', $pname, $pversion, 'new');
    my $newVcs = $newData->[4];
    $newView = catdir($dirWork,$newName );

    RmDirTree($newView);

    Message("Extract $pname $pversion, $newVcs, $newView");

    JatsCmd('-logfile', catfile($dirLog, $newName.'.log'),'jats_vcsrelease.pl', '-extractfiles', '-noprefix', '-root',$dirWork, '-view', $newName ,'-label', $newVcs );
}

#-------------------------------------------------------------------------------
# Function        : checkoutTipPackage 
#
# Description     : Checkout the Tip package from the old RM
#
# Inputs          : 
#
# Returns         : 
#
sub checkoutTipPackage
{
    my ($pkgData) = @_;

    my $tipName = join('_', $pname, $pversion, 'tip');
    my $tipVcs = $pkgData->[4];
    $tipView = catdir($dirWork,$tipName );

    RmDirTree($tipView);

    print("Extract $pname $pversion, $tipVcs, $tipView\n");

    JatsCmd('-logfile', catfile($dirLog, $tipName.'.log'),'jats_vcsrelease.pl', '-extractfiles', '-noprefix', '-root',$dirWork, '-view', $tipName ,'-label', $tipVcs, '-devMode=Tip' );
}


#-------------------------------------------------------------------------------
# Function        : checkVersion 
#
# Description     : Determine if the version exists in a RM instance 
#
# Inputs          : rmRef           - Ref to RM credentials 
#
# Returns         : Not found - undef
#                   Founf - nice data
#
sub checkVersion
{
    my ($rmRef) = @_;

    my $m_sqlstr = <<"END_SQL";
   SELECT
        pv.pv_id,
        pv.pkg_id,
        pv.pkg_idext,
        pv.pkg_version,
        release_manager.PK_RMAPI.return_vcs_tag(PV_ID),
        pv.v_ext
   FROM release_manager.package_versions pv, release_manager.packages p
        where p.pkg_id = pv.pkg_id
        and p.pkg_name = '$pname'
        and pv.pkg_version = '$pversion'
END_SQL

    my $data = getDataFromRm('checkVersion', $m_sqlstr, $rmRef, {oneRow => 1});
    return undef unless $data;
    return $data;
}

#-------------------------------------------------------------------------------
# Function        : checkVersionExists 
#
# Description     : Determine if the version exists in a RM instance 
#
# Inputs          : rmRef           - Ref to RM credentials 
#                   $pname
#                   $pversion
#
# Returns         : Not found - undef
#                   Found - pvid
#
sub checkVersionExists
{
    my ($rmRef, $pname, $pversion) = @_;

    my $m_sqlstr = <<"END_SQL";
   SELECT
        pv.pv_id
   FROM release_manager.package_versions pv, release_manager.packages p
        where p.pkg_id = pv.pkg_id
        and p.pkg_name = '$pname'
        and pv.pkg_version = '$pversion'
END_SQL

    my $data = getDataFromRm('checkVersionExists', $m_sqlstr, $rmRef, {oneRow => 1});
    return undef unless $data;
    return $data->[0];
}


#-------------------------------------------------------------------------------
# Function        : getDataFromRm 
#
# Description     : Get an array of data from RM 
#
# Inputs          : $name           - Query Name
#                   $m_sqlstr       - Query
#                   $rmRef          - Ref to RM
#                   $options        - Ref to a hash of options
#                                       sql     - show sql
#                                       data    - show data
#                                       dump    - show results
#                                       oneRow  - Only feth one row
#                                       error   - Must find data
#                                       
# Returns         : 
#
sub getDataFromRm
{
    my ($name,$m_sqlstr, $rmRef, $options ) = @_;
    my @row;
    my $data;

    if (ref $options ne 'HASH') {
        $options = {}; 
    }

    $ENV{GBE_RM_LOCATION} = $rmRef->[1];
    $ENV{GBE_RM_USERNAME} = $rmRef->[2];
    $ENV{GBE_RM_PASSWORD} = $rmRef->[3];
    connectRM(\$RM_DB, $opt_verbose);

    if ($options->{sql}) {
        Message("$name: $m_sqlstr")
    }
    my $sth = $RM_DB->prepare($m_sqlstr);
    if ( defined($sth) )
    {
        if ( $sth->execute( ) ) {
            if ( $sth->rows ) {
                while ( @row = $sth->fetchrow_array ) {
                    if ($options->{data}) {
                        Message ("$name: @row");
                    }
                    #Debug0("$name: @row");
                    push @{$data}, [@row];

                    last if $options->{oneRow};
                }
            }
            $sth->finish();
        } else {
            Error("Execute failure:$name: $m_sqlstr", $sth->errstr() );
        }
    } else {
        Error("Prepare failure:$name" );
    }
    disconnectRM(\$RM_DB);

    if (!$data && $options->{error}) {
        Error( $options->{error} );
    }

    if ($data && $options->{oneRow}) {
        $data = $data->[0];
    }
 
    if ($options->{dump}) {
        DebugDumpData("$name", $data);
    }
    return $data;
}


#-------------------------------------------------------------------------------
#   Documentation
#

=pod

=for htmltoc    GENERAL::ClearCase::

=head1 NAME

rmMerge_migrate_package - Migrate a package between Release Manager instances

=head1 SYNOPSIS

jats rmMerge_migrate_package [options] PackageName PackageVersion

 Options:
    -help              - brief help message
    -help -help        - Detailed help message
    -man               - Full documentation
    -verbose[=n]       - Enable additional output
    -[no]test          - Test Dependecies and insertion point
    -[no]history       - Do not impoty history
    -historyTo=txt     - Stop history import at named version
    -relabel           - Allow SVN label to be replaced
    -placekeeper       - Mark as a placekeeper
    -autoPlaceKeeper   - Mark as a placekeeper if dependencies are missing
    -base              - Use non-ripple version of package-version
    -after=version     - Insert after namd version

=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<-versbose[=n]>

Enable additional output

=back

=head1 EXAMPLE

jats eprog rmMerge_migrate_package PackageName PackageVersion

=cut



