#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#

#-----------------------------------------------------------------------------

=head1   buildkit 

 xCAT/PCM Kit Build utilities

This script is designed to run on a non-xCAT system so that Kits can be
built on any product build machine.

=cut

BEGIN
{
    $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
    $::XCATDIR  = $ENV{'XCATDIR'}  ? $ENV{'XCATDIR'}  : '/etc/xcat';
    $::XCATSHARE = $::XCATROOT . '/share/xcat';
}

if ($^O =~ /^aix/i) {
    print "ERROR - the buildkit command is not supported on AIX \n";
    exit 1;
}

use lib "$::XCATROOT/lib/perl";
require xCAT::BuildKitUtils;
use Getopt::Long;
use strict;
use Cwd;
use Cwd 'abs_path';
use File::Path;
use File::Basename;

#-----------------------------------------------------------------------------
# Main

$::progname      = "buildkit";
$::buildkit_conf = "buildkit.conf";
$::kit_conf      = "kit.conf";
$::current_dir   = cwd();

# this code will build a kit using framework 1.
$::KITFRAMEWORK = "2";

# this code is compatible with other kits that are at framework 0 or 1.
$::COMPATIBLE_KITFRAMEWORKS = "0,1,2";

%::buildkit_def = (
    kit => { basename => {
            description     => 'The kit base name (e.g., kit-lsf)',
            value_desc      => 'Must be: Generic Name String',
            mandatory       => 1,
            cp_to_kitconfig => 1 },
        description => {
            description     => 'The kit description',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 1 },
        version => {
            description     => 'The kit version (e.g., 9.0)',
            value_desc      => 'Must be: Generic Name String',
            mandatory       => 1,
            cp_to_kitconfig => 1 },
        release => {
            description     => 'The kit release (e.g., 1)',
            value_desc      => 'Must be: Generic Name String',
            mandatory       => 0,
            cp_to_kitconfig => 1 },
        ostype => {
            description     => 'The kit OS type (e.g., Linux)',
            value_desc      => 'Must be: OS Type String',
            mandatory       => 1,
            cp_to_kitconfig => 1 },
        osbasename => {
            description     => 'The kit OS basename',
            value_desc      => 'Must be: Generic Name String',
            mandatory       => 0,
            cp_to_kitconfig => 0 },
        osmajorversion => {
            description     => 'The kit OS majorversion',
            value_desc      => 'Must be: Generic Name String',
            mandatory       => 0,
            cp_to_kitconfig => 0 },
        osminorversion => {
            description     => 'The kit OS minorversion',
            value_desc      => 'Must be: Generic Name String',
            mandatory       => 0,
            cp_to_kitconfig => 0 },
        osarch => {
            description     => 'The kit OS architecture',
            value_desc      => 'Must be: Generic Name String',
            mandatory       => 0,
            cp_to_kitconfig => 0 },
        isinternal => {
            description => 'Flag to say if this Kit is used for internal use only.  It is only used for information purposes.',
            value_desc      => 'Must be: empty string or boolean string',
            mandatory       => 0,
            cp_to_kitconfig => 1 },
        kitdeployparams => {
            description => 'The path to the Kit Deployment Parameters file.',
            value_desc  => 'Must be: empty string or relative path string',
            mandatory   => 0,
            base_dir    => 'other_files',
            cp_to_kitconfig => 2 },    # 2 = rename with KIT_KITNAME_ on cp
        kitlicense => {
            description => 'The Kit license string to be built into all kitcomponent packages.',
            value_desc      => 'any string',
            mandatory       => 1,
            cp_to_kitconfig => 0 },
        kittarfilename => {
            description     => 'The filename to use for the generated kit.',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 0 },
        vendor => {
            description => 'The Vendor value to use when building the rpms.',
            value_desc  => 'any string',
            mandatory   => 0,
            cp_to_kitconfig => 0 },
        packager => {
            description => 'The Packager value to use when building the rpms.',
            value_desc  => 'any string',
            mandatory   => 0,
            cp_to_kitconfig => 0 },
        url => {
            description     => 'The URL value to use when building the rpms.',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 0 } },
    kitrepo => { kitrepoid => {
            description => 'The Kit Package Repository ID.  (e.g., rhels-6.2-x86_64)',
            value_desc      => 'Must be: Generic Name String, unique in kit',
            mandatory       => 1,
            cp_to_kitconfig => 0 },
        osbasename => {
            description     => 'The OS distro base name (e.g., rhels)',
            value_desc      => 'Must be OS Name String',
            mandatory       => 1,
            cp_to_kitconfig => 1 },
        osmajorversion => {
            description     => 'The OS distro major version (e.g., 6)',
            value_desc      => 'Must be Generic Number String',
            mandatory       => 1,
            cp_to_kitconfig => 1 },
        osminorversion => {
            description     => 'The OS distro minor version (e.g., 3)',
            value_desc      => 'Must be Generic Number String',
            mandatory       => 0,
            cp_to_kitconfig => 1 },
        osarch => {
            description     => 'The OS distro architecture (e.g., x86_64)',
            value_desc      => 'Must be OS Arch String',
            mandatory       => 1,
            cp_to_kitconfig => 1 },
        compat_osbasenames => {
            description => 'Comma-separated list of compatible OS base names. ',
            value_desc  => 'Must be Empty String or list of OS Name Strings',
            mandatory   => 0,
            cp_to_kitconfig => 1 } },
    kitcomponent => { basename => {
            description => 'The component name.  It is used as the meta-package name.',
            value_desc      => 'any string',
            mandatory       => 1,
            cp_to_kitconfig => 1 },
        description => {
            description => 'The component description.  The description is added to the meta-package.',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 1 },
        version => {
            description => 'The component version (e.g., 9.0).  It is used as the meta-package version.',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 1 },
        release => {
            description => 'The component release number (e.g., 1).  It is used as the meta-package release number.',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 1 },
        serverroles => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 1,
            cp_to_kitconfig => 1 },
        kitrepoid => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 1,
            cp_to_kitconfig => 0 },
        kitcompdeps => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 1 },
        ospkgdeps => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 0 },
        kitpkgdeps => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 1 },
        non_native_pkgs => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 0 },
        driverpacks => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 1 },
        exlist => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 0,
            base_dir        => 'other_files',
            cp_to_kitconfig => 2 },
        preinstall => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 0 },
        postinstall => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 0 },
        preuninstall => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 0 },
        postuninstall => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 0 },
        preupgrade => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 0 },
        postupgrade => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 0 },
        postbootscripts => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 0,
            base_dir        => 'scripts',
            cp_to_kitconfig => 2 },
        genimage_postinstall => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 0,
            base_dir        => 'scripts',
            cp_to_kitconfig => 2 } },
    kitpackage => { filename => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 1,
            cp_to_kitconfig => 0 },
        kitrepoid => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 1,
            cp_to_kitconfig => 0 },
        rpm_spec => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 0 },
        rpm_srcdir => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 0 },
        rpm_srctarball => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 0 },
        rpm_srpm => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 0 },
        rpm_prebuiltdir => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 0 },
        isexternalpkg => {
            description     => 'tbd',
            value_desc      => 'any string',
            mandatory       => 0,
            cp_to_kitconfig => 0 } }
);


my $args = join ' ', @ARGV;
$::command = "$0 $args";
Getopt::Long::Configure("bundling");
$Getopt::Long::ignorecase = 0;

# parse the options
if (
    !GetOptions(
        'h|help'           => \$::HELP,
        'v|version'        => \$::VERSION,
        'V|verbose'        => \$::VERBOSE,
        'n|noprerequisite' => \$::PREREQUISITE,
        'p|pkgdir=s'       => \$::PKGDIR,
        'k|kitversion=s'   => \$::KITVERSION,
        'r|kitrelease=s'   => \$::KITRELEASE,
        'l|kitloc=s'       => \$::KITLOC,
        'for=s'            => \$::FOROSVERSARCH,
    )
  )
{
    &usage;
    exit(1);
}

# display the usage if -h or --help is specified
if ($::HELP)
{
    &usage;
    exit(0);
}

my $debianflag = 0;
my $dpkg_flag  = '-uc -us';
my $tempstring = xCAT::BuildKitUtils->osver();
if ($tempstring =~ /debian/ || $tempstring =~ /ubuntu/) {
    $debianflag = 1;
}

# This is an undocumented flag to support our local build team
#   to allow building Ubuntu kits on our RH build machines.
#   It requires RH rpms such as dep, fakeroot, perl-File-DesktopEntry,
#   perl-File-BaseDir, and html2text to be installed on the build server
#   for this to work.  To use this flag:
#      buildkit --for ubuntu buildrepo <reponame>
#      buildkit --for ubuntu buildtar
if ($::FOROSVERSARCH) {
    if ($::FOROSVERSARCH =~ /debian/ || $::FOROSVERSARCH =~ /ubuntu/) {
        $debianflag = 1;
        $dpkg_flag .= ' -A -d';
    }
}

# display the version statement if -v or --version is specified
if ($::VERSION)
{
    my $versioncmd = "rpm -q --qf \"%{NAME}:  %{VERSION}-%{RELEASE} \n\" xCAT-buildkit";
    my $message = "Error quering xCAT-buildkit rpm.  Version info is not available. \n";
    if ($debianflag) {

        $versioncmd = "dpkg-query --show -f='\${binary:Package}:  \${Version}\n' xcat-buildkit";
        $message = "Error quering xcat-buildkit package. Version info is not available. \n";
    }
    if (system($versioncmd)) {

        # non-zero return from system call
        print $message;
        exit 1;
    }

    # add framework info to output
    print "\tkitframework = $::KITFRAMEWORK\n";
    print "\tcompatible_frameworks = $::COMPATIBLE_KITFRAMEWORKS\n";

    exit 0;
}

my $arg = shift(@ARGV);
if (!$arg) {
    &usage;
    exit(0);
}

# set kit location
if ($::KITLOC) {
    $::workdir     = $::KITLOC;
    $::current_dir = $::workdir;
} else {
    $::workdir = $::current_dir;
}

$::full_buildkit_conf = $::workdir . "/" . $::buildkit_conf;
$::build_dir          = $::workdir . "/build";
$::deploy_dir = $::build_dir;   #kitname appended by validate_bldkitconf routine
$::base_repodir = $::build_dir . "/kit_repodir";

while ($arg) {
    my $command = $arg;
    $command =~ tr/A-Z/a-z/;    # convert to lowercase
    if ($command eq 'create') {
        $::KIT_CREATE = shift(@ARGV);
        if ($::KITLOC) {
            $::workdir     = dirname($::KITLOC);
            $::current_dir = $::workdir;
        }
        if (!$::KIT_CREATE) {
            print "The Kit basename was not specified for the buildkit create command.\n";
            &usage;
            exit 1;
        }
    } elsif ($command eq 'chkconfig') {
        $::KIT_CHKCONFIG = 1;
    } elsif ($command eq 'buildrepo') {
        $::KIT_BUILDREPO = shift(@ARGV);
        if (!$::KIT_BUILDREPO) {
            print "The Kit package repository name was not specified for buildkit buildrepo command.\n";
            &usage;
            exit 1;
        }
    } elsif ($command eq 'listrepo') {
        $::KIT_LISTREPO = 1;
    } elsif ($command eq 'cleanrepo') {
        $::KIT_CLEANREPO = shift(@ARGV);
        if (!$::KIT_CLEANREPO) {
            print "kit package repository name not specified for buildkit cleanrepo command \n";
            &usage;
            exit 1;
        }
    } elsif ($command eq 'buildtar') {
        $::KIT_BUILDTAR = 1;
    } elsif ($command eq 'cleantar') {
        $::KIT_CLEANTAR = 1;
    } elsif ($command eq 'cleanall') {
        $::KIT_CLEANALL = 1;
    } elsif ($command eq 'addpkgs') {
        $::KIT_ADDPKGS = shift(@ARGV);
        if (!($::KIT_ADDPKGS)) {
            print "Missing parameter:  the <kit tarfile> name  must be specified when using the \'buildkit addpkgs\' command.\n";
            &usage;
            exit(1);
        }
        if (!($::PKGDIR)) {
            print "Missing option:  the -p <pkgdir> option must be specified with \'buildkit addpkgs\' command. \n";
            &usage;
            exit(1);
        }
    } else {
        print "The buildkit command $arg is not recognized.\n";
        &usage;
        exit(1);
    }
    $arg = shift(@ARGV);
}

my $rc = 0;
if ($::KIT_CREATE) {
    $rc = &kit_create;
}
if ($::KIT_CHKCONFIG) {
    unless ($rc = &kit_chkconfig) {
        print "No errors were found in Kit Build File $::full_buildkit_conf. \n";
    }
}
if ($::KIT_LISTREPO) {
    unless ($rc = &kit_chkconfig) { $rc = &kit_listrepo; }
}
if ($::KIT_BUILDREPO) {
    unless ($rc = &kit_chkconfig) { $rc = &kit_buildrepo; }
}
if ($::KIT_CLEANREPO) {
    unless ($rc = &kit_chkconfig) { $rc = &kit_cleanrepo; }
}
if ($::KIT_BUILDTAR) {
    unless ($rc = &kit_chkconfig) { $rc = &kit_buildtar; }
}
if ($::KIT_CLEANTAR) {
    unless ($rc = &kit_chkconfig) { $rc = &kit_cleantar; }
}
if ($::KIT_CLEANALL) {
    unless ($rc = &kit_chkconfig) { $rc = &kit_cleanall; }
}
if ($::KIT_ADDPKGS) { $rc = &kit_addpkgs; }

exit $rc;

#####################################
#  subroutines
#####################################

#-----------------------------------------------------------------------------

=head3    usage 
	
	Displays message for -h option

=cut

#-----------------------------------------------------------------------------
sub usage
{
    print "Usage:  
    buildkit [-?│-h│--help] [-v│--version]

    To build a new Kit

    buildkit [-V│--verbose] <subcommand> [<kit_name>] [<repo_name>│all] 
       [-l│--kitloc <directory>]

    To add packages to an existing Kit.

    buildkit [-V│--verbose] addpkgs <kit_tarfile> [-p│--pkgdir <package_direc-
       tory_list>] [-k│--kitversion <version>] [-r│--kitrelease <release] 
       [-l│--kitloc <kit location>]

    This tool is used to build and manage a Kit package.                          
    The options are:                                                          
        -h         - Provide usage info.                                      
        -k         - Kit version.
        -l         - Location of kit files. (Including kit name.)
        -p         - RPM package directory locations.
        -r         - Kit release.
        -v         - Provide the version info.                                
        command    - Several commands are supported. See the list below.      
        -V         - Verbose mode. Outputs additional debug messages.         
                                                                              
    Supported subcommands:                                                       
     create <kit basename> - creates a new Kit with the specified basename    
     chkconfig             - checks the Kit build file                        
     listrepo              - lists the Kit package repositories in the Kit    
                             build file, and their build status               
     buildrepo <reponame>  - builds the specified Kit package repository      
     buildrepo all         - builds all the Kit package repositories      
     cleanrepo <reponame>  - deletes the build files for the specified Kit    
                             package repository                               
     cleanrepo  all        - deletes the build files for all Kit package      
                             repositories                                     
     buildtar              - builds the Kit tarfile                           
     cleantar              - deletes the Kit deployment directory and Kit     
                             tarfile                   
     cleanall              - equivalent to buildkit cleanrepo all and
                                            buildkit cleantar
     addpkgs -p <pkgdir> <kit tarfile> 
                           - add product package rpms to a shipped tarfile
                             named kitname.NEEDS_PRODUCT_PKGS.tar.bz2
     \n";
}

#-----------------------------------------------------------------------------

=head3    kit_create
	
   buildkit create

=cut

#-----------------------------------------------------------------------------

sub kit_create

{
    # create Kit directory in pwd
    my $kitname = $::KIT_CREATE;
    my $kitdir;
    if ($::KITLOC) {
        $kitdir = $::KITLOC;
    } else {
        $kitdir = $::workdir . "/$kitname";
    }

    if (-d $kitdir) {
        print "Another directory already exists with the name $kitdir.  Not able to create new Kit. \n";
        exit 1;
    }
    if (!mkdir($kitdir)) {
        print "Error creating Kit directory $kitdir.  Verify that the current user has privileges to create the directory. \n";
        exit 1;
    }

    # Recursive copy the shipped template directory to the Kit directory
    if (system("cp -fRp $::XCATSHARE/kits/kit_template/* $kitdir")) {

        # non-zero return from system call
        print "Error copying sample Kit template files from $::XCAT_SHARE/kits/kit_template to $kitdir \n";
        exit 1;
    }

    if (&edit_bldkitconf($kitdir . "/" . $::buildkit_conf, $kitname)) {
        exit 1;
    }

    print "Kit template for $kitname created in $kitdir directory \n";
    return 0;
}

#-----------------------------------------------------------------------------

=head3    kit_chkconfig
	
   buildkit chkconfig

=cut

#-----------------------------------------------------------------------------

sub kit_chkconfig

{
    if ($::CHKCONFIG_DONE) { return 0; }
    my $bldkitconf = $::full_buildkit_conf;

    my $chkrc = &load_bldkitconf($bldkitconf);
    if ($chkrc != 0) { return 1; }

    $chkrc = &validate_bldkitconf();
    if ($chkrc != 0) { return 1; }

    $::CHKCONFIG_DONE = 1;
    return 0;
}

#-----------------------------------------------------------------------------

=head3    kit_buildrepo
	
   buildkit buildrepo

=cut

#-----------------------------------------------------------------------------

sub kit_buildrepo
{
    my $rc     = 0;
    my $repoid = $::KIT_BUILDREPO;

    if (!$debianflag) {

        # Check if createrepo exists or not.  Fail at the beginning.
        #- don't use specific path - may not be correct in build env
        my $rcmd = "createrepo -h > /dev/null";
        if (system($rcmd )) {
            print "Error: the createrepo command does not seem to be installed.  Make sure createrepo is installed before running the buildkit command. \n";
            return 1;
        }
    }

    $repoid =~ s/\s+//g;
    $repoid =~ tr/A-Z/a-z/;    # convert to lowercase
    if ($repoid ne 'all') {
        return &kit_buildrepo1($::KIT_BUILDREPO);
    } else {
        foreach my $kr (@{ $::bldkit_config->{kitrepo}{entries} }) {
            if (&kit_buildrepo1($kr->{kitrepoid})) { return 1; }
        }
    }
    return $rc;
}

#-----------------------------------------------------------------------------

=head3    kit_buildrepo1
	
          

=cut

#-----------------------------------------------------------------------------
sub kit_buildrepo1
{
    my $rc     = 0;
    my $repoid = shift;
    $repoid =~ s/\s+//g;
    my $repodir = $::base_repodir;
    my $srcdir  = $::workdir . "/source_packages/";
    my $basedir = $repodir;
    my $repo;

    # find the repo
    my $found = 0;
    foreach my $kr (@{ $::bldkit_config->{kitrepo}{entries} }) {
        if ($kr->{kitrepoid} eq $repoid) {
            $found = 1;
            $repo  = $kr;
            if (&validate_os($kr)) {
                print "The buildrepo operation will continue, but errors may occur.  You may need to run this command on a host with the same OS.\n";
            }
            $repodir .= "/$kr->{kitreponame}";
            last;
        }
    }
    if (!$found) {
        print "The specified Kit Package Repository \"$repoid\" does not exist in the Kit Build File. \n";
        return 1;
    }

    # Create repo build directory
    if ((!-d $repodir) && (!mkpath($repodir))) {
        print "Error creating build repository directory $repodir.\n";
        return 1;
    }

    # Build kitpackages first
    my $kitrepohash;
    foreach my $kr (@{ $::bldkit_config->{kitrepo}{entries} }) {
        $kitrepohash->{ $kr->{kitrepoid} } = $kr->{kitreponame};
    }

    foreach my $kp (@{ $::bldkit_config->{kitpackage}{entries} }) {

        # For this kitrepo?
        my $found = 0;
        foreach my $kprid (split(/,/, $kp->{kitrepoid})) {
            $kprid =~ s/\s+//g;
            if ($repoid eq $kprid) {
                $found = 1;
                last;
            }
        }
        if (!$found) { next; }

        # is this package already built?
        my $rpm = "$repodir/$kp->{filename}";
        if (-r $rpm) { next; }

        my $kprid;
        my $rpm_built;
        foreach $kprid (split(/,/, $kp->{kitrepoid})) {
            if ($repoid eq $kprid) {
                next;
            }
            if ((-d "$basedir/$kitrepohash->{$kprid}") and (-f "$basedir/$kitrepohash->{$kprid}/$kp->{filename}")) {
                $rpm_built = $kitrepohash->{$kprid};
                last;
            }
        }


        # determine build method
        if ($kp->{isexternalpkg} eq 'yes') {
            if ($::VERBOSE) { print "skipping build of external kitpackage $kp->{filename} \n"; }
            next;
        } else {
            if ($::VERBOSE) { print "building kitpackage $kp->{filename} \n"; }
        }
        if (defined($kp->{rpm_prebuiltdir})) {

            # simply copy the file to the build directory
            my $full_prebuiltrpm = $srcdir . $kp->{rpm_prebuiltdir} . "/" . $kp->{filename};

            if ($rpm_built) {
                if (system("cd $repodir;ln -sf ../$rpm_built/$kp->{filename} $kp->{filename}")) {

                    # non-zero return from system call
                    print "Error create symlink for prebuilt rpm $kp->{filename} to Kit Build directory. \n";
                    return;
                }
            } else {
                if (system("cp -fp $full_prebuiltrpm $repodir")) {

                    # non-zero return from system call
                    print "Error copying prebuilt rpm $kp->{filename} to Kit Build directory. \n";
                    return 1;
                }
            }
        } elsif (defined($kp->{rpm_srpm})) {

            # run rpmbuild --rebuild on the source rpm
            print "SKIPPING BUILD FOR KIT PACKAGE   $kp->{filename} \n";
            print "TBD - only buildrepo for prebuilt rpms is available at this time \n\n";
        } elsif (defined($kp->{rpm_srctarball}) &&
            defined($kp->{rpm_spec})) {

            # run rpmbuild
            print "SKIPPING BUILD FOR KIT PACKAGE   $kp->{filename} \n";
            print "TBD - only buildrepo for prebuilt rpms is available at this time \n\n";
        } elsif (defined($kp->{rpm_srcdir}) &&
            defined($kp->{rpm_spec})) {

            # build tarfile and run rpmbuild
            print "SKIPPING BUILD FOR KIT PACKAGE   $kp->{filename} \n";
            print "TBD - only buildrepo for prebuilt rpms is available at this time \n\n";
        } else {
            print "Cannot determine build method for Kit Package $kp->{filename}.  Verify that your Kit Build File is correct. \n";
            return 1;
        }
    }

    # Build kitcomponent preppackages and metapackages
    if ($debianflag) {
        foreach my $kc (@{ $::bldkit_config->{kitcomponent}{entries} }) {
            if ($repoid ne $kc->{kitrepoid}) { next; }
            my $debname = "$repodir/" . &comppkgname($kc);
            if (-r $debname) { next; }
            if ($::VERBOSE) { print "building kitcomponent package for $kc->{basename} \n"; }
            if (&build_kitcomp_debian($kc)) {
                print "Error building kitcomponent metapackage for $kc->{basename} \n";
                return 1;
            }
        }

        if (system("cd $repodir;dpkg-scanpackages . > Packages")) {
            print "Error building the repository meta-data with the dpkg-scanpackages command \n";
            return 1;
        }
    }
    else {
        foreach my $kc (@{ $::bldkit_config->{kitcomponent}{entries} }) {

            # Check if this kitcomponent is in the requested repo
            if ($repoid ne $kc->{kitrepoid}) { next; }

            # Check if already built
            my $rpm = "$repodir/" . &comppkgname($kc);
            if (-r $rpm) { next; }

            # Build it
            if ($::VERBOSE) { print "building kitcomponent metapackage for $kc->{basename} \n"; }
            if (&build_kitcomp($kc)) {
                print "Error building kitcomponent metapackage for $kc->{basename} \n";
                return 1;
            }
        }

        # run createrepo
        my $cr_opts = '';
        if (($repo->{osbasename} =~ m/rh|RH|centos|CentOS/) &&
            ($repo->{osmajorversion} eq '5')) {
            $cr_opts = '-s md5';
        }
        if (system("createrepo $cr_opts $repodir")) {
            print "Error building the repository meta-data with the createrepo command \n";
            return 1;
        }
    }
    return 0;
}

#-----------------------------------------------------------------------------

=head3    kit_listrepo
	
   buildkit listrepo

=cut

#-----------------------------------------------------------------------------
sub kit_listrepo
{
    # print "Kit Repository:  Status \n";
    foreach my $kr (@{ $::bldkit_config->{kitrepo}{entries} }) {
        my $rc     = 0;
        my $status = "NOT DONE";
        unless ($rc = &validate_repo($kr)) { $status = "DONE"; }
        print "$kr->{kitrepoid}:  $status \n";
    }

    return 0;
}

#-----------------------------------------------------------------------------

=head3    kit_cleanrepo
	
   buildkit cleanrepo

=cut

#-----------------------------------------------------------------------------
sub kit_cleanrepo
{
    my $repoid     = $::KIT_CLEANREPO;
    my $tmp_repoid = $repoid;
    $tmp_repoid =~ tr/A-Z/a-z/;    # convert to lowercase

    if (($tmp_repoid eq 'all') &&
        -d $::base_repodir) {
        if (system("rm -Rf $::base_repodir ")) {
            print "Error removing contents of $::base_repodir \n";
            return 1;
        } else {
            print "Contents of $::base_repodir has been successfully removed. \n";
        }
    } else {
        my $got_one = 0;
        foreach my $kr (@{ $::bldkit_config->{kitrepo}{entries} }) {
            if ($repoid eq $kr->{kitrepoid}) {
                my $repodir = $::base_repodir . '/' . $kr->{kitreponame};
                if (-d $repodir) {
                    if (system("rm -Rf $repodir ")) {
                        print "Error removing directory $repodir \n";
                        return 1;
                    } else {
                        print "Kit repository $kr->{kitrepoid} has been removed. \n";
                    }
                } else {
                    print "Kit repository $kr->{kitrepoid} directory $repodir does not exist.  Nothing to remove for this repository. \n";
                }
                $got_one = 1;
                last;
            }
        }
        if (!$got_one) {
            print "Kit repository $repoid does not exist.\n";
            return 1;
        }
    }
    if (-d "$::workdir/rpmbuild") {
        system("rm -Rf $::workdir/rpmbuild ");
    }
    if (-d "$::workdir/tmp") {
        system("rm -Rf $::workdir/tmp ");
    }
    if (-d "$::workdir/debbuild") {
        system("rm -Rf $::workdir/debbuild");
    }

    return 0;
}

#-----------------------------------------------------------------------------

=head3    kit_buildtar
	
   buildkit buildtar

=cut

#-----------------------------------------------------------------------------
sub kit_buildtar
{
    foreach my $kr (@{ $::bldkit_config->{kitrepo}{entries} }) {
        if (&validate_repo($kr)) {
            print "Kit Repository $kr->{kitrepoid} not built.  Run: \n";
            print "    buildkit buildrepo $kr->{kitrepoid}          \n";
            return 1;
        }
    }

    if (&create_kitconf) {
        print "Error creating kit configuration file \n";
        return 1;
    }

    if ($::HAVE_EXTERNAL_PKG or $::HAVE_NON_NATIVE_PKGS) {
        if (&create_PARTIAL_builddir) {
            print "Error creating PARTIAL kit build directory contents \n";
            return 1;
        }
    } else {
        if (&create_builddir) {
            print "Error creating kit build directory contents \n";
            return 1;
        }
    }

    if (!-d "$::deploy_dir/repos") {
        symlink "$::build_dir/kit_repodir", "$::deploy_dir/repos";
    }

    # build the tarfile
    my $extpkgs = '';
    if ($::HAVE_EXTERNAL_PKG or $::HAVE_NON_NATIVE_PKGS) {
        $extpkgs = '.NEED_PRODUCT_PKGS';
    }
    my $kitname     = $::bldkit_config->{kit}{entries}[0]->{kitname};
    my $kitfilename = $kitname;
    if (defined($::bldkit_config->{kit}{entries}[0]->{kittarfilename})) {
        $kitfilename = $::bldkit_config->{kit}{entries}[0]->{kittarfilename};
        $kitfilename =~ s/tar\.bz2\s*$//;
    }
    $kitfilename = $kitfilename . $extpkgs . ".tar.bz2";

    my $tarfile = $::deploy_dir . "/" . $kitfilename;

    my $dir   = dirname($::deploy_dir);
    my $bidir = "$dir/build_input";

    #It is for partial kit.
    if ($::HAVE_EXTERNAL_PKG or $::HAVE_NON_NATIVE_PKGS) {
        if (-d "$bidir") {
            if (system("cd $::deploy_dir; cd ..; cp -r build_input $kitname")) {
                print "Error: Could not copy building tarfile $tarfile \n";
                return 1;
            }
        }
    } else {

        #If it is complete kit and there is build_input directory in deploy_dir
        #If there is tmp rpmbuild source_packages
        #delete them from complete kit build_input
        if (-d "$bidir") {
            if (system("cd $::deploy_dir; cd ..; rm -fr build_input/tmp")) {
                print "Error:Could not delete build_input/tmp \n";
            }
            if (system("cd $::deploy_dir; cd ..; rm -fr build_input/rpmbuild")) {
                print "Error:Could not delete build_input/tmp \n";
            }
            if (system("cd $::deploy_dir; cd ..; rm -fr build_input/source_packages")) {
                print "Error:Could not delete build_input/source_packages \n";
            }
            if (system("cd $::deploy_dir; cd ..; cp -fr build_input $kitname")) {
                print "Error: Could not copy building tarfile $tarfile \n";
                return 1;
            }
        } else {

            #If kit build dir is new created
            #partial kit is never created before
            #make sure there is build_input dir in complete kit dir
            if (system("cd $::deploy_dir; mkdir -p build_input")) {
                print "Error creating kit build directory contents \n";
                return 1;
            }
            if (system("cd $::deploy_dir; cp -fp $::workdir/buildkit.conf build_input")) {
                print "Error creating kit build directory contents \n";
                return 1;
            }
            if (system("cd $::deploy_dir; cp -frp $::workdir/other_files build_input")) {
                print "Error creating kit build directory contents \n";
                return 1;
            }
            if (system("cd $::deploy_dir; cp -frp $::workdir/plugins build_input")) {
                print "Error creating kit build directory contents \n";
                return 1;
            }
            if (system("cd $::deploy_dir; cp -frp $::workdir/scripts build_input")) {
                print "Error creating kit build directory contents \n";
                return 1;
            }
        }
    }

    print "Creating tar file $::current_dir/$kitfilename.\n";

    if (system("cd $::deploy_dir; cd ..; tar -cjhf $tarfile $kitname/*")) {
        print "Error building tarfile $tarfile \n";
        return 1;
    }

    system("mv $tarfile $::current_dir");
    print "Kit tar file $::current_dir/$kitfilename successfully built. \n";
    return 0;
}

#-----------------------------------------------------------------------------

=head3    kit_cleantar
	
   buildkit cleantar

    Remove tar files from the kit location directory.

    This removes all tar files - not just the last one created!

    Also clean up several other files/dirs

=cut

#-----------------------------------------------------------------------------
sub kit_cleantar
{
    my $basename = $::bldkit_config->{kit}{entries}[0]->{basename};
    my $rmfiles  = "$basename\*tar.bz2";

    my $tarfile = "$::workdir/$rmfiles";

    if ($rmfiles) {
        if (system("rm -f $tarfile ")) {
            print "Error removing kit tar files in $::workdir.\n";
        } else {
            print "Kit tar files have been successfully removed from $::workdir.\n";
        }
    }

    if (-d $::deploy_dir) {
        if (system("rm -Rf $::deploy_dir ")) {
            print "Error removing contents of $::deploy_dir \n";
        } else {
            print "Removed $::deploy_dir.\n";
        }
    }
    if (-d "$::workdir/rpmbuild") {
        if (system("rm -Rf $::workdir/rpmbuild ")) {

            #  print "Error removing $::workdir/rpmbuild\n";
        } else {
            print "Removed $::workdir/rpmbuild\n";
        }
    }
    if (-d "$::workdir/tmp") {
        if (system("rm -Rf $::workdir/tmp ")) {

            #  print "Error removing $::workdir/tmp \n";
        } else {
            print "Removed $::workdir/tmp \n";
        }
    }
    if (-d "$::workdir/debbuild") {
        if (system("rm -Rf $::workdir/debbuild")) {

            #  print "Error removing $::workdir/debbuild.\n";
        } else {
            print "Removed $::workdir/debbuild\n";
        }
    }
    return 0;
}

#-----------------------------------------------------------------------------

=head3    kit_cleanall
	
   buildkit cleanall

=cut

#-----------------------------------------------------------------------------
sub kit_cleanall
{
    print "Running buildkit cleanall... \n";

    &kit_cleantar;

    if (-d $::build_dir) {
        if (system("rm -Rf $::build_dir/* ")) {
            print "Error removing contents of $::build_dir \n";
        } else {
            print "All $::build_dir contents have been successfully removed \n";
        }
    }
    if (-d "$::workdir/rpmbuild") {
        system("rm -Rf $::workdir/rpmbuild ");
    }
    if (-d "$::workdir/tmp") {
        system("rm -Rf $::workdir/tmp ");
    }
    if (-d "$::workdir/debbuild") {
        system("rm -Rf $::workdir/debbuild");
    }

    return 0;
}

#-----------------------------------------------------------------------------

=head3    edit_bldkitconf
	
   edit the shipped template buildkit.conf file to insert initial values
   for the new kit
=cut

#-----------------------------------------------------------------------------
sub edit_bldkitconf
{
    my $bldkitconf = shift;
    my $kitname    = shift;

    # read in the buildkit.conf file
    my $CF;
    unless (open($CF, "<", $bldkitconf)) {
        print "The Kit build file $bldkitconf does not exist. \n";
        return 1;
    }
    if ($::VERBOSE) {
        print "Reading kit configuration file $bldkitconf \n";
    }
    my @lines = <$CF>;
    close $CF;

    my $osinfo    = xCAT::BuildKitUtils->osver();
    my $kitrepoid = $osinfo;
    $kitrepoid =~ s/\,//;
    my ($osbasename,     $osmore)         = split(/\,/, $osinfo);
    my ($osmajorversion, $osminorversion) = split(/\./, $osmore);
    my $osarch = `uname -p`;
    chomp($osarch);
    my $kitcomponent_basename = $kitname . "_compute";

    if ($debianflag == 1) {
        if ($osarch eq "ppc64le") {
            $osarch = "ppc64el";
        }
        $kitcomponent_basename = $kitname . "-compute";
    }

    for (@lines) {
        s/<<<INSERT_kitbasename_HERE>>>/$kitname/;
        s/<<<INSERT_kitrepoid_HERE>>>/$kitrepoid/;
        s/<<<INSERT_osbasename_HERE>>>/$osbasename/;
        s/<<<INSERT_osmajorversion_HERE>>>/$osmajorversion/;
        s/<<<INSERT_osminorversion_HERE>>>/$osminorversion/;
        s/<<<INSERT_osarch_HERE>>>/$osarch/;
        s/<<<INSERT_kitcomponent_basename_HERE>>>/$kitcomponent_basename/;
        if ($debianflag) {
            s/(filename=.*?)\-(.*)\.noarch\.rpm/$1_$2_all.deb/;
        }
        if ($osbasename =~ /rh/) {
            s/.*<<<INSERT_compatible_HERE_>>>/  compat_osbasenames=centos/;
        }
    }

    # Write the buildkit.conf back out
    my $NCF;
    unless (open($NCF, ">$bldkitconf")) {
        return 1;
    }
    if ($::VERBOSE) {
        print "Inserted initial values into $bldkitconf \n";
    }
    print $NCF @lines;
    close($NCF);

    return 0;
}

#-----------------------------------------------------------------------------

=head3    load_bldkitconf
	
   load the kitbuild.conf file into a global data structure and 
   verify that the general syntax is correct.

=cut

#-----------------------------------------------------------------------------
sub load_bldkitconf
{
    my $bldkitconf = shift;

    # read in the buildkit.conf file
    my $CF;
    unless (open($CF, "<", $bldkitconf)) {
        print "The Kit build file $bldkitconf does not exist in the current directory. \n";
        return 1;
    }
    if ($::VERBOSE) {
        print "Reading kit configuration file $bldkitconf \n";
    }
    my @lines = <$CF>;
    close $CF;

    my $current_section = 'no section';
    my %current_entry;
    my $syntax_error = '';
    my $bad_line     = '';
    my $line_number  = 0;
    foreach my $l (@lines) {
        $line_number++;

        # skip blank and comment lines
        next if ($l =~ /^\s*$/ || $l =~ /^\s*#/);

        # process a real line
        # new section?
        if ($l =~ /^\s*(\w+)\s*:/) {
            my $section = $1;
            if (defined($::buildkit_def{$section})) {
                if (($section eq 'kit') &&
                    ($::bldkit_config->{$section}{'exists'})) {
                    $syntax_error = "More than one \"$section:\" section exists ";
                    $bad_line = $l;
                    last;
                }
                $::bldkit_config->{$section}{'exists'} = 1;
                push(@{ $::bldkit_config->{$current_section}{'entries'} }, {%current_entry});
                $current_section = $section;
                undef %current_entry;
                next;
            }
        }
        if ($l =~ /^\s*(\w+)\s*=\s*(.*)\s*/) {
            my $attr      = $1;
            my $val       = $2;
            my $orig_attr = $attr;
            my $orig_val  = $val;
            $attr =~ s/^\s*//;       # Remove any leading whitespace
            $attr =~ s/\s*$//;       # Remove any trailing whitespace
            $attr =~ tr/A-Z/a-z/;    # Convert to lowercase
            $val =~ s/^\s*//;
            $val =~ s/\s*$//;

            if (defined($::buildkit_def{$current_section}{$attr})) {
                if ($val ne '') { $current_entry{$attr} = $val; }
            } else {
                if ($current_section eq 'no section') {
                    $syntax_error = "No section specified for attribute $attr.";
                } else {
                    my $valid_attrs = join(', ', (keys(%{ $::buildkit_def{$current_section} })));
                    $syntax_error = "Attribute \"$attr\" is not valid for section \"$current_section\". Valid attributes are: $valid_attrs.\n";
                }
                $bad_line = $l;
                last;
            }

        } else {
            $syntax_error = "Invalid line format";
            $bad_line     = $l;
            last;

        }
    }

    # Need at least one kit and one kitrepo section
    if (!$syntax_error) {
        if (!($::bldkit_config->{'kit'}{'exists'})) {
            $syntax_error = "No \"kit:\" section found.  At least one section required. ";
            $bad_line = '<end of file>';
        } elsif (!($::bldkit_config->{'kitrepo'}{'exists'})) {
            $syntax_error = "No \"kitrepo:\" section found.  At least one section required. ";
            $bad_line = '<end of file>';
        } else {
            push(@{ $::bldkit_config->{$current_section}{'entries'} }, {%current_entry});
        }
    }

    if ($syntax_error) {
        print "Error processing file $bldkitconf \n";
        print "Syntax error found on line $line_number:\n";
        print "$bad_line \n";
        print "$syntax_error \n";
        print "\n";
        print "The Kit build file does not have the correct format. \n";
        print "The format should be: \n";
        print "    <section name>:   \n";
        print "        <attr>=<val>  \n";
        print "        <attr>=<val>  \n";
        print "        ...           \n";
        print "    <section name>:   \n";
        print "        <attr>=<val>  \n";
        print "        <attr>=<val>  \n";
        print "        ...           \n";
        print "The valid section names are: kit, kitrepo, kitcomponent, kitpackages. \n";
        print "There must be exactly one kit, and must be at least one kitrepo section. \n";
        return 1;
    }

    # Check for mandatory attributes
    foreach my $s (keys %{$::bldkit_config}) {
        if (!defined($::buildkit_def{$s})) { next; }
        foreach my $se (@{ $::bldkit_config->{$s}{entries} }) {
            foreach my $a (keys %{ $::buildkit_def{$s} }) {
                if (($::buildkit_def{$s}{$a}->{mandatory}) &&
                    (!defined($se->{$a}))) {
                    print "The \"$a\" mandatory attribute must be defined in the \"$s\" section of the Kit build file \n";
                    return 1;
                }
            }
        }
    }

    #use Data::Dumper;
    #print Dumper($::bldkit_config);

    return 0;
}

#-----------------------------------------------------------------------------

=head3    validate_bldkitconf
	
   validate the loaded buildkit configuration data

=cut

#-----------------------------------------------------------------------------
sub validate_bldkitconf
{
    my $kitname      = $::bldkit_config->{kit}{entries}[0]->{basename};
    my $full_kitname = $kitname;
    $full_kitname .= '-' . $::bldkit_config->{kit}{entries}[0]->{version};
    if (defined($::bldkit_config->{kit}{entries}[0]->{release})) {
        $full_kitname .= '-' . $::bldkit_config->{kit}{entries}[0]->{release};
    }
    my $short_kitname = $full_kitname;
    if (defined($::bldkit_config->{kit}{entries}[0]->{osbasename})) {
        $full_kitname .= '-' . $::bldkit_config->{kit}{entries}[0]->{osbasename};
    }
    if (defined($::bldkit_config->{kit}{entries}[0]->{osmajorversion})) {
        if (!defined($::bldkit_config->{kit}{entries}[0]->{osbasename})) {
            print "Error:  Kit osmajorversion attribute was specified but Kit osbasename was not set. \n";
            return 1;
        }
        $full_kitname .= '-' . $::bldkit_config->{kit}{entries}[0]->{osmajorversion};
    }
    if (defined($::bldkit_config->{kit}{entries}[0]->{osminorversion})) {
        my $kitminor = $::bldkit_config->{kit}{entries}[0]->{osminorversion};
        unless ($kitminor =~ /^\d/) {
            $kitminor = split /<=|>=|==|<|>|=/, $::bldkit_config->{kit}{entries}[0]->{osminorversion};
        }
        if ((!defined($::bldkit_config->{kit}{entries}[0]->{osbasename})) ||
            (!defined($::bldkit_config->{kit}{entries}[0]->{osmajorversion}))) {
            print "Error:  Kit osminorversion attribute was specified but either Kit osbasename or Kit osmajorversion were not set. \n";
            return 1;
        }
        $full_kitname .= '-' . $kitminor;
    }
    if (defined($::bldkit_config->{kit}{entries}[0]->{osarch})) {
        $full_kitname .= '-' . $::bldkit_config->{kit}{entries}[0]->{osarch};
    }
    $::bldkit_config->{kit}{entries}[0]->{kitname} = $full_kitname;
    $::deploy_dir .= "/" . $full_kitname;

    # Make sure each kit kitdeployparams file exists
    if (defined($::bldkit_config->{kit}{entries}[0]->{kitdeployparams})) {
        my $kd_file = $::workdir . "/other_files/" . $::bldkit_config->{kit}{entries}[0]->{kitdeployparams};
        if (!-r $kd_file) {
            print "Kit Deployment Parameters file $kd_file does not exist or is not readable\n";
            return 1;
        }
        if (&edit_deployparams($kd_file, 1)) { return 1; }
    }

    # Make sure each kitrepo has unique distro info
    my $kr_count = scalar @{ $::bldkit_config->{kitrepo}{entries} };
    if ($kr_count > 1) {
        foreach my $kri (0 .. $kr_count - 2) {
            foreach my $kri2 ($kri + 1 .. $kr_count - 1) {
                my $kr  = $::bldkit_config->{kitrepo}{entries}[$kri];
                my $kr2 = $::bldkit_config->{kitrepo}{entries}[$kri2];
                if ($kr->{kitrepoid} eq $kr2->{kitrepoid}) {
                    print "There are two or more kitrepo sections with the same kitrepoid \"$kr->{kitrepoid}\". \n";
                    return 1;
                }
                if (($kr->{osbasename} eq $kr2->{osbasename}) &&
                    ($kr->{osmajorversion} eq $kr2->{osmajorversion}) &&
                    ($kr->{osarch} eq $kr2->{osarch})) {
                    if ((defined($kr->{osminorversion}) &&
                            defined($kr2->{osminorversion}) &&
                            ($kr->{osminorversion} eq $kr2->{osminorversion})) ||
                        (!defined($kr->{osminorversion}) &&
                            !defined($kr2->{osminorversion}))) {
                        print "There are two or more kitrepo sections which are defined with the same OS name, major/minor version, and architecture. \n";
                        return 1;
                    }
                }
            }
        }
    }

    #  Kitcomponent version/release are now optional -
    #        default to kit version/release
    foreach my $kc (@{ $::bldkit_config->{kitcomponent}{entries} }) {
        if (!defined($kc->{version})) {
            $kc->{version} = $::bldkit_config->{kit}{entries}[0]->{version};
        }
        if (!defined($kc->{release})) {
            if (!defined($::bldkit_config->{kit}{entries}[0]->{release})) {
                print "Kitcomponent $kc->{basename} does not have a release specified and there is no Kit release value set to use as a default.  \n";
                return 1;
            } else {
                $kc->{release} = $::bldkit_config->{kit}{entries}[0]->{release};
            }
        }

    }

    # Make sure each kitcomponent has unique basename/repoid
    # If same basename, make sure version/release are same, too
    my $kc_count = scalar @{ $::bldkit_config->{kitcomponent}{entries} };
    if ($kc_count > 1) {
        foreach my $kci (0 .. $kc_count - 2) {
            foreach my $kci2 ($kci + 1 .. $kc_count - 1) {
                if ($::bldkit_config->{kitcomponent}{entries}[$kci]->{basename}
                    eq $::bldkit_config->{kitcomponent}{entries}[$kci2]->{basename}) {
                    if ($::bldkit_config->{kitcomponent}{entries}[$kci]->{kitrepoid}
                        eq $::bldkit_config->{kitcomponent}{entries}[$kci2]->{kitrepoid}) {

                        print "Two or more kitcomponents are defined with the same basename \"$::bldkit_config->{kitcomponent}{entries}[$kci]->{basename}\" and the same repoid \"$::bldkit_config->{kitcomponent}{entries}[$kci]->{kitrepoid}\". \n";
                        return 1;
                    }
                    if (($::bldkit_config->{kitcomponent}{entries}[$kci]->{version}
                            ne $::bldkit_config->{kitcomponent}{entries}[$kci2]->{version}) ||
                        ($::bldkit_config->{kitcomponent}{entries}[$kci]->{release}
                            ne $::bldkit_config->{kitcomponent}{entries}[$kci2]->{release})
                      ) {
                        print "Two or more kitcomponents are defined with the same basename \"$::bldkit_config->{kitcomponent}{entries}[$kci]->{basename}\" but with different version or release. \n";
                        return 1;
                    }
                }
            }
        }
    }

    #  Kitrepo checks
    foreach my $kr (@{ $::bldkit_config->{kitrepo}{entries} }) {
        my $reponame = $short_kitname;
        if ((defined($::bldkit_config->{kit}{entries}[0]->{osbasename})) &&
            ($::bldkit_config->{kit}{entries}[0]->{osbasename} ne
                $kr->{osbasename})) {
            print "Warning:  Kit osbasename is set to \"$::bldkit_config->{kit}{entries}[0]->{osbasename}\", but this does not match kitrepo $kr->{kitrepoid} osbasename \"$kr->{osbasename}\".  Processing will continue, but verify that you do not have an error in your buildkit configuration file. \n";
        }
        $reponame .= '-' . $kr->{osbasename};
        if ((defined($::bldkit_config->{kit}{entries}[0]->{osmajorversion})) &&
            ($::bldkit_config->{kit}{entries}[0]->{osmajorversion} ne
                $kr->{osmajorversion})) {
            print "Warning:  Kit osmajorversion is set to \"$::bldkit_config->{kit}{entries}[0]->{osmajorversion}\", but this does not match kitrepo $kr->{kitrepoid} osmajorversion \"$kr->{osmajorversion}\".  Processing will continue, but verify that you do not have an error in your buildkit configuration file. \n";
        }
        $reponame .= '-' . $kr->{osmajorversion};
        if (defined($kr->{osminorversion})) {
            my $krminor = $kr->{osminorversion};
            unless ($krminor =~ /^\d/) {
                $krminor = split /<=|>=|==|<|>|=/, $kr->{osminorversion};
            }
            if ((defined($::bldkit_config->{kit}{entries}[0]->{osminorversion})) &&
                ($::bldkit_config->{kit}{entries}[0]->{osminorversion} ne
                    $kr->{osminorversion})) {
                print "Warning:  Kit osminorversion is set to \"$::bldkit_config->{kit}{entries}[0]->{osminorversion}\", but this does not match kitrepo $kr->{kitrepoid} osminorversion \"$kr->{osminorversion}\".  Processing will continue, but verify that you do not have an error in your buildkit configuration file. \n";
            }
            $reponame .= '.' . $krminor;
            $::bldkit_config->{kit}{entries}[0]->{osminorversion} = $krminor;            
        }
        if ((defined($::bldkit_config->{kit}{entries}[0]->{osarch})) &&
            ($::bldkit_config->{kit}{entries}[0]->{osarch} ne
                $kr->{osarch})) {
            print "Warning:  Kit osarch is set to \"$::bldkit_config->{kit}{entries}[0]->{osarch}\", but this does not match kitrepo $kr->{kitrepoid} osarch \"$kr->{osarch}\".  Processing will continue, but verify that you do not have an error in your buildkit configuration file. \n";
        }
        $reponame .= '-' . $kr->{osarch};
        $kr->{kitreponame} = $reponame;
    }

    #  Kitcomponent checks
    foreach my $kc (@{ $::bldkit_config->{kitcomponent}{entries} }) {

        # Make sure all kitcomponent kitrepoids are defined
        my $found = 0;
        my %repo;
        if ($debianflag) {
            if ($kc->{basename} =~ /_/) {
                print "Kit Component basename can not contain underscore.\n";
                return 1;
            }
        }
        foreach my $kr (@{ $::bldkit_config->{kitrepo}{entries} }) {
            if ($kc->{kitrepoid} eq $kr->{kitrepoid}) {
                $found             = 1;
                %repo              = %{$kr};
                $kc->{kitreponame} = $kr->{kitreponame};
                push(@{ $kr->{packages} }, &comppkgname($kc, $kr));
                last;
            }
        }
        if (!$found) {
            print "Kit Repository \"$kc->{kitrepoid}\" required by the Kit Component \"$kc->{basename}\" not defined in the Kit Build file.\n";
            return 1;
        }

        # Create full kitcomponent name
        my $compname = $kc->{basename};
        $compname .= '-' . $kc->{version};
        $compname .= '-' . $kc->{release};
        $compname .= '-' . $repo{osbasename};
        $compname .= '-' . $repo{osmajorversion};
        if (defined($repo{osminorversion})) {
            my $minorversion = $repo{osminorversion};
            unless ($minorversion =~ /^\d/) {
                $minorversion = split /<=|>=|==|<|>|=/, $repo{osminorversion};
            }
            $compname .= '.' . $minorversion;
        }
        $compname .= '-' . $repo{osarch};
        $kc->{kitcompname} = $compname;

        # Make sure all kitcomponent kitpkgdeps are defined
        if (defined($kc->{kitpkgdeps})) {
            foreach my $d (split(/,/, $kc->{kitpkgdeps})) {
                $d =~ s/\s+//g;
                $d =~ s/^([\w\.\-]+)[<>=]*.*$/$1/;
                my $found = 0;
                foreach my $kp (@{ $::bldkit_config->{kitpackage}{entries} }) {
                    if ($kp->{filename} =~ /^$d[\.\-]?/) {
                        foreach my $kprid (split(/,/, $kp->{kitrepoid})) {
                            $kprid =~ s/\s+//g;
                            if ($kc->{kitrepoid} eq $kprid) {
                                $found = 1;
                                last;
                            }
                        }
                    }
                    if ($found) { last; }
                }
                if (!$found) {
                    print "Kit Package \"$d\" required by the Kit Component \"$kc->{basename}\" was not found in the Kit Component\'s repository \"$kc->{kitrepoid}\".\n";
                    return 1;
                }
            }
        }

        # Make sure all kitcomponent driverpacks are defined
        if (defined($kc->{driverpacks})) {
            my @drvs = split(/,/, $kc->{driverpacks});
            foreach my $d (@drvs) {
                $d =~ s/\s+//g;
                my $found = 0;
                foreach my $kp (@{ $::bldkit_config->{kitpackage}{entries} }) {
                    if ($kp->{filename} eq $d) {
                        foreach my $kprid (split(/,/, $kp->{kitrepoid})) {
                            $kprid =~ s/\s+//g;
                            if ($kc->{kitrepoid} eq $kprid) {
                                $found = 1;
                                last;
                            }
                        }
                    }
                    if ($found) { last; }
                }
                if (!$found) {
                    print "Driver package \"$d\" required by the Kit Component \"$kc->{basename}\" was not found in the Kit Component\'s repository \"$kc->{kitrepoid}\".\n";
                    return 1;
                }
            }
        }

        # Make sure files exist
        if (defined($kc->{exlist})) {
            my $ck_file = $::workdir . "/other_files/" . $kc->{exlist};
            if (!-r $ck_file) {
                print "Exclude List file $ck_file defined in Kit Componenet \"$kc->{basename}\" does not exist or is not readable\n";
                return 1;
            }
        }
        if (defined($kc->{preinstall})) {
            my $ck_file = $::workdir . "/scripts/" . $kc->{preinstall};
            if (!-r $ck_file) {
                print "Pre-Install script $ck_file defined in Kit Componenet \"$kc->{basename}\" does not exist or is not readable\n";
                return 1;
            }
        }
        if (defined($kc->{postinstall})) {
            my $ck_file = $::workdir . "/scripts/" . $kc->{postinstall};
            if (!-r $ck_file) {
                print "Post-Install script $ck_file defined in Kit Componenet \"$kc->{basename}\" does not exist or is not readable\n";
                return 1;
            }
        }
        if (defined($kc->{preuninstall})) {
            my $ck_file = $::workdir . "/scripts/" . $kc->{preuninstall};
            if (!-r $ck_file) {
                print "Pre-Uninstall script $ck_file defined in Kit Componenet \"$kc->{basename}\" does not exist or is not readable\n";
                return 1;
            }
        }
        if (defined($kc->{postuninstall})) {
            my $ck_file = $::workdir . "/scripts/" . $kc->{postuninstall};
            if (!-r $ck_file) {
                print "Post-Uninstall script $ck_file defined in Kit Componenet \"$kc->{basename}\" does not exist or is not readable\n";
                return 1;
            }
        }
        if (defined($kc->{preupgrade})) {
            my $ck_file = $::workdir . "/scripts/" . $kc->{preupgrade};
            if (!-r $ck_file) {
                print "Pre-Upgrade script $ck_file defined in Kit Componenet \"$kc->{basename}\" does not exist or is not readable\n";
                return 1;
            }
        }
        if (defined($kc->{postupgrade})) {
            my $ck_file = $::workdir . "/scripts/" . $kc->{postupgrade};
            if (!-r $ck_file) {
                print "Post-Upgrade script $ck_file defined in Kit Componenet \"$kc->{basename}\" does not exist or is not readable\n";
                return 1;
            }
        }
        if (defined($kc->{genimage_postinstall})) {
            foreach my $script (split(/\,/, $kc->{genimage_postinstall})) {
                $script =~ s/\s+//g;
                my $ck_file = $::workdir . "/scripts/" . $script;
                if (!-r $ck_file) {
                    print "genimage_postinstall script $ck_file defined in Kit Componenet \"$kc->{basename}\" does not exist or is not readable\n";
                    return 1;
                }
            }
        }
        if (defined($kc->{postbootscripts})) {
            foreach my $script (split(/\,/, $kc->{postbootscripts})) {
                $script =~ s/\s+//g;
                my $ck_file = $::workdir . "/scripts/" . $script;
                if (!-r $ck_file) {
                    print "Postboot script $ck_file defined in Kit Componenet \"$kc->{basename}\" does not exist or is not readable\n";
                    return 1;
                }
            }
        }
        if (defined($kc->{non_native_pkgs})) {
            if ($kc->{non_native_pkgs} =~ /EXTERNALPKGS/) {
                $::NON_NATIVE_PKGS->{ $kc->{kitcompname} } = 1;
                $::HAVE_NON_NATIVE_PKGS = 1;
            }
        }
    }

    #  Kitpackage checks
    foreach my $kp (@{ $::bldkit_config->{kitpackage}{entries} }) {

        # determine if valid build method
        if ((defined($kp->{isexternalpkg})) ||
            (defined($kp->{rpm_prebuiltdir}))) {
            if ((defined($kp->{rpm_srpm})) ||
                (defined($kp->{rpm_srctarball})) ||
                (defined($kp->{rpm_spec}))       ||
                (defined($kp->{rpm_srcdir}))) {
                print "Cannot determine build method for Kit Package $kp->{filename}.  Conflicting attributes were specified.\n";
                return 1;
            }
            if (!(defined($kp->{isexternalpkg}))) { $kp->{isexternalpkg} = 'no'; }
            my $orig_isext = $kp->{isexternalpkg};
            $kp->{isexternalpkg} =~ s/\s+//g;
            $kp->{isexternalpkg} =~ tr/A-Z/a-z/;    # convert to lowercase
            if ($kp->{isexternalpkg} eq '0') { $kp->{isexternalpkg} = 'no'; }
            if ($kp->{isexternalpkg} eq '1') { $kp->{isexternalpkg} = 'yes'; }
            if (($kp->{isexternalpkg} ne 'yes') &&
                ($kp->{isexternalpkg} ne 'no')) {
                print "Error in definition for Kit Package $kp->{filename}.  Invalid attribute value \'isexternalpkg=$orig_isext\'.  Valid values are \'no\'|\'0\' or \'yes\'|\'1\'.\n";
                return 1;
            }
            if (($kp->{isexternalpkg} eq 'yes')) {
                $::HAVE_EXTERNAL_PKG = 1;
            }
            if (($kp->{isexternalpkg} eq 'yes') &&
                (defined($kp->{rpm_prebuiltdir}))) {
                print "Error in definition for Kit Package $kp->{filename}.  Do not specify \'isexternalpkg=$orig_isext\' with 'rpm_prebuiltdir'.\n";
                return 1;
            }
        } elsif (defined($kp->{rpm_srpm})) {
            if ((defined($kp->{rpm_prebuiltdir})) ||
                (defined($kp->{rpm_srctarball})) ||
                (defined($kp->{rpm_spec}))       ||
                (defined($kp->{rpm_srcdir}))) {
                print "Cannot determine build method for Kit Package $kp->{filename}.  Conflicting attributes were specified.\n";
                return 1;
            }
        } elsif (defined($kp->{rpm_srctarball}) &&
            defined($kp->{rpm_spec})) {
            if ((defined($kp->{rpm_prebuiltdir})) ||
                (defined($kp->{rpm_srpm})) ||
                (defined($kp->{rpm_srcdir}))) {
                print "Cannot determine build method for Kit Package $kp->{filename}.  Conflicting attributes were specified.\n";
                return 1;
            }
        } elsif (defined($kp->{rpm_srcdir}) &&
            defined($kp->{rpm_spec})) {
            if ((defined($kp->{rpm_prebuiltdir})) ||
                (defined($kp->{rpm_srpm})) ||
                (defined($kp->{rpm_srctarball}))) {
                print "Cannot determine build method for Kit Package $kp->{filename}.  Conflicting attributes were specified.\n";
                return 1;
            }
        } else {
            print "Cannot determine build method for Kit Package $kp->{filename}.  Verify that your Kit Build File is correct. \n";
            return 1;
        }

        # Make sure all kitpackage kitrepoids are defined
        foreach my $kprid (split(/,/, $kp->{kitrepoid})) {
            my $found = 0;
            $kprid =~ s/\s+//g;
            foreach my $kr (@{ $::bldkit_config->{kitrepo}{entries} }) {
                if ($kprid eq $kr->{kitrepoid}) {
                    $found = 1;
                    $kp->{kitreponame} .= "," . $kr->{kitreponame};
                    if (!($kp->{isexternalpkg} eq 'yes')) {
                        push(@{ $kr->{packages} }, $kp->{filename});
                    }
                    last;
                }
            }
            if (!$found) {
                print "Kit Repository \"$kprid\" required by the Kit Package \"$kp->{filename}\" is not defined in the Kit Build file.\n";
                return 1;
            }
        }
        $kp->{kitreponame} =~ s/^,//;
        if (!$::NEW_PARTIAL_KIT) {

            # Make sure files exist
            if (defined($kp->{rpm_spec})) {
                my $ck_file = $::workdir . "/source_packages/" . $kp->{rpm_spec};
                if (!-r $ck_file) {
                    print "RPM spec file $ck_file defined in Kit Package \"$kp->{filename}\" does not exist or is not readable\n";
                    return 1;
                }
            }
            if (defined($kp->{rpm_srcdir})) {
                my $ck_dir = $::workdir . "/source_packages/" . $kp->{rpm_srcdir};
                if (!-d $ck_dir) {
                    print "RPM source directory $ck_dir defined in Kit Package \"$kp->{filename}\" does not exist or is not readable\n";
                    return 1;
                }
            }
            if (defined($kp->{rpm_srctarball})) {
                my $ck_file = $::workdir . "/source_packages/" . $kp->{rpm_srctarball};
                if (!-r $ck_file) {
                    print "RPM source tarfile $ck_file defined in Kit Package \"$kp->{filename}\" does not exist or is not readable\n";
                    return 1;
                }
            }
            if (defined($kp->{rpm_srpm})) {
                my $ck_file = $::workdir . "/source_packages/" . $kp->{rpm_srpm};
                if (!-r $ck_file) {
                    print "Source RPM $ck_file defined in Kit Package \"$kp->{filename}\" does not exist or is not readable\n";
                    return 1;
                }
            }
            if (defined($kp->{rpm_prebuiltdir})) {
                my $ck_dir = $::workdir . "/source_packages/" . $kp->{rpm_prebuiltdir};
                if (!-d $ck_dir) {
                    print "Pre-built RPM directory $ck_dir defined in Kit Package \"$kp->{filename}\" does not exist or is not readable\n";
                    return 1;
                }
                my $ck_file = $ck_dir . "/" . $kp->{filename};
                if (system("ls $ck_file > /dev/null")) {

                    #            if (! -r $ck_file ) {
                    print "Pre-built rpm $ck_file defined in Kit Package \"$kp->{filename}\" does not exist or is not readable\n";
                    return 1;
                }
            }
        }
    }

    #use Data::Dumper;
    #print Dumper($::bldkit_config->{kitrepo});
    return 0;
}

#-----------------------------------------------------------------------------

=head3    comppkgname
	
   build a metapkg rpm filename for this kitcomponent
      input:  kitcomponent hash
              kitrepo hash that this kitcomponent belongs to

=cut

#-----------------------------------------------------------------------------
sub comppkgname
{
    my $comp = shift;

    my $pkgname = $comp->{basename};
    if ($debianflag) {
        $pkgname .= '_' . $comp->{version};
        $pkgname .= '-' . $comp->{release};
        $pkgname .= '_all.deb';
    }
    else {
        $pkgname .= '-' . $comp->{version};
        $pkgname .= '-' . $comp->{release};
        $pkgname .= '.noarch.rpm';
    }
    return $pkgname;
}

#-----------------------------------------------------------------------------

=head3    validate_repo
	
   validate whether a kit repo has been built
   input:  repo hash
   returns rc:
            0 - repo status is DONE
            1 - repo status is NOT DONE
  verbose mode displays message for first rpm not built

=cut

#-----------------------------------------------------------------------------
sub validate_repo
{
    my $repo = shift;

    my $repodir = $::base_repodir . "/" . $repo->{kitreponame};
    if (!-d $repodir) {
        if ($::VERBOSE) {
            print "\n$repodir does not exist.  No rpms have been built for this kitrepo. \n";
        }
        return 1;
    }

    # Make sure each repo pkg exists
    foreach my $pkg (@{ $repo->{packages} }) {

        # skip check for kit component meta rpm if it includes
        #   external non-native pkgs
        my $skip_check = 0;
        foreach my $kc (@{ $::bldkit_config->{kitcomponent}{entries} }) {
            if ($repo->{kitrepoid} eq $kc->{kitrepoid}) {
                my $kitpkgname = comppkgname($kc);
                if (($kitpkgname eq $pkg) &&
                    ($::NON_NATIVE_PKGS->{ $kc->{kitcompname} })) {
                    $skip_check = 1;
                    last;
                }
            }
        }
        if (!$skip_check) {
            my $pkg_filename = $repodir . '/' . $pkg;
            if (system("ls $pkg_filename > /dev/null")) {
                if ($::VERBOSE) {
                    print "\nFile $pkg in directory $repodir does not exist or is not readable. \n";
                }
                return 1;
            }
        }
    }
    return 0;
}

#-----------------------------------------------------------------------------

=head3    validate_os
	
   validate whether a kit repo matches the current OS
   input:  repo hash
   returns rc:
            0 - match
            1 - no match
  verbose mode displays message for mismatch details

=cut

#-----------------------------------------------------------------------------
sub validate_os
{
    my $repo = shift;

    my $osinfo = xCAT::BuildKitUtils->osver();
    my ($osbasename,     $osmore)         = split(/\,/, $osinfo);
    my ($osmajorversion, $osminorversion) = split(/\./, $osmore);
    my $osarch = `uname -p`;
    chomp($osarch);

    if ($debianflag == 1) {
        if ($osarch eq "ppc64le") {
            $osarch = "ppc64el";
        }
    }
    $osinfo =~ s/\,//;
    my $repo_osinfo = "$repo->{osbasename}$repo->{osmajorversion}";
    my $minorversion;
    if (defined($repo->{osminorversion})) {
        $minorversion = $repo->{osminorversion};
        unless ($minorversion =~ /^\d/) {
            $minorversion = split /<=|>=|==|<|>|=/, $repo->{osminorversion};
        }
        $repo_osinfo .= ".$minorversion";
    }
    $repo_osinfo .= "-$repo->{osarch} ";
    my $mismatch_msg = "The local host is running $osinfo-$osarch.  This does not match the Kit Repository \"$repo->{kitrepoid}\" data:  $repo_osinfo";
    if (defined($repo->{compat_osbasenames})) {
        $mismatch_msg .= " or the compatible OS distros: $repo->{compat_osbasenames} ";
    }


    my $compat_match = 0;
    if ($repo->{osbasename} ne $osbasename) {
        if (defined($repo->{compat_osbasenames})) {
            foreach my $cos (split(/,/, $repo->{compat_osbasenames})) {
                if ($cos eq $osbasename) {
                    $compat_match = 1;
                    last;
                }
            }
        }
        if (!$compat_match) {
            print "$mismatch_msg \n";
            if ($::VERBOSE) {
                print "\n Local OS basename $osbasename does not match repository.\n";
            }
            return 1;
        }
    }
    if (($repo->{osmajorversion} ne $osmajorversion) &&
        (!$compat_match)) {
        print "$mismatch_msg \n";
        if ($::VERBOSE) {
            print "\n Local OS major version $osmajorversion does not match repository.\n";
        }
        return 1;
    }
    if (defined($repo->{osminorversion})) {
        if (($minorversion ne $osminorversion) &&
            (!$compat_match)) {
            print "$mismatch_msg \n";
            if ($::VERBOSE) {
                print "\n Local OS minor version $osminorversion does not match repository.\n";
            }
            return 1;
        }
    }
    if ($repo->{osarch} ne $osarch) {
        print "$mismatch_msg \n";
        if ($::VERBOSE) {
            print "\n Local OS arch $osarch does not match repository.\n";
        }
        return 1;
    }
    return 0;
}

#-----------------------------------------------------------------------------

=head3    build_kitcomp
	
   build a metapkg rpm for this kitcomponent
      input:  kitcomponent hash

=cut

#-----------------------------------------------------------------------------
sub build_kitcomp
{
    my $comp = shift;
    my %repo;
    my $rpmbuild_dir = $::workdir . "/rpmbuild";
    my $tmpdir       = $::workdir . "/tmp/$comp->{kitcompname}";
    my $kcmetaname   = comppkgname($comp);

    # If this kitcomponent has external non-native pkgs,
    #    skip the meta rpm build
    if (defined($::NON_NATIVE_PKGS) &&
        defined($::NON_NATIVE_PKGS->{ $comp->{kitcompname} }) &&
        $::NON_NATIVE_PKGS->{ $comp->{kitcompname} }) {
        if ($::VERBOSE) {
            print "Kit component $comp->{kitcompname} has external non-native packages.  Skipping rpm build for $kcmetaname. \n";
        }
        return 0;
    }

    # find the kitrepo hash for this component
    foreach my $kr (@{ $::bldkit_config->{kitrepo}{entries} }) {
        if ($comp->{kitrepoid} eq $kr->{kitrepoid}) {
            %repo = %{$kr};
            last;
        }
    }
    my $repodir = $::base_repodir . "/" . $repo{kitreponame};

    # Fix the kitpkgdeps value for this kitcomponent
    #   For any kitpkgdep that has an rpm file in the repo,
    #   specifically reference it's version-release
    if (&update_kitcomp_kitpkgdeps($comp, $repodir)) { return 1; }

    $::VALID_PRER_COMPONENT = 0;

    if (!$::PREREQUISITE) {
        if ($comp->{ospkgdeps} || $comp->{preinstall} || $comp->{preupgrade}) {
            if (&gen_kitcomp_spec($comp, \%repo, 'PREREQUISITE')) { return 1; }

            # run the rpmbuild command
            my $curdir = $::workdir;
            my $cmd    = "rm -Rf $curdir/rpmbuild";
            system($cmd);
            my $avoiderr = $rpmbuild_dir . "/BUILDROOT/prep_" . $comp->{basename};
            $avoiderr .= "-$comp->{version}-$comp->{release}.$repo{osarch}";
            mkpath($avoiderr);
            $avoiderr = $rpmbuild_dir . "/BUILD/";
            mkpath($avoiderr);
            $avoiderr = $rpmbuild_dir . "/SRPMS/";
            mkpath($avoiderr);
            $avoiderr = $rpmbuild_dir . "/RPMS/noarch/";
            mkpath($avoiderr);

            # Read the kit component prerequisite rpm name

            my $specfile = $::workdir . "/tmp/$comp->{kitcompname}-prep.spec";
            my $rpmbuild_cmd = "rpmbuild --define \"_topdir $rpmbuild_dir\" -ba $specfile";

            #  don't want debug info  - 3845
            #            if (!$::VERBOSE) {
            $rpmbuild_cmd .= ' --quiet ';

            #            }
            if (system($rpmbuild_cmd)) {
                print "Error running rpmbuild command for kit component $comp->{kitcompname} meta package\n";
                return 1;
            }
            my @built_rpms = `find $rpmbuild_dir/RPMS -name "*.rpm"`;
            foreach my $rpm (@built_rpms) {
                chomp($rpm);
                if (system("cp -fp $rpm $repodir")) {
                    print "Error copying rpm $rpm to build repo directory $repodir \n";
                    return 1;
                }
            }

            $::VALID_PRER_COMPONENT = 1;

        }

        if (&gen_kitcomp_spec($comp, \%repo, 'METARPM')) { return 1; }
    } else {

        # Create spec file for this kit component
        if (&gen_kitcomp_spec($comp, \%repo, 'ALL')) { return 1; }
    }

    # run the rpmbuild command
    my $curdir = $::workdir;
    my $cmd    = "rm -Rf $curdir/rpmbuild";
    system($cmd);
    my $avoiderr = $rpmbuild_dir . "/BUILDROOT/" . $comp->{basename};
    $avoiderr .= "-$comp->{version}-$comp->{release}.$repo{osarch}";
    mkpath($avoiderr);
    $avoiderr = $rpmbuild_dir . "/BUILD/";
    mkpath($avoiderr);
    $avoiderr = $rpmbuild_dir . "/SRPMS/";
    mkpath($avoiderr);
    $avoiderr = $rpmbuild_dir . "/RPMS/noarch/";
    mkpath($avoiderr);

    # Read the kit component meta rpm name

    my $specfile = $::workdir . "/tmp/$comp->{kitcompname}.spec";
    my $rpmbuild_cmd = "rpmbuild --define \"_topdir $rpmbuild_dir\" -ba $specfile";

    # Copy in any non-native packages
    if (defined($comp->{non_native_pkgs})) {
        mkpath($tmpdir);
        mkpath("$rpmbuild_dir/SOURCES");
        my $sourcedir = $::workdir . "/source_packages";

        foreach my $pkgfile (split(/,/, $comp->{non_native_pkgs})) {
            my $pkg_file;
            my ($key, $value) = split /:/, $pkgfile;
            if ("$key" =~ /EXTERNALPKGS/) {
                $pkg_file = $value;
            } else {
                $pkg_file = $key;
            }

            $cmd = "cp -p $sourcedir/$pkg_file $tmpdir";
            if (system($cmd)) {
                print "Error copying non-native package file $sourcedir/$pkg_file to $tmpdir\n";
                return 1;
            }
        }
        $cmd = "cd $tmpdir/..;mv $comp->{kitcompname} $comp->{basename}; tar -czf $rpmbuild_dir/SOURCES/$comp->{basename}.tar.gz $comp->{basename};mv $comp->{basename} $comp->{kitcompname}";
        if (system($cmd)) {
            print "Error creating tarfile $rpmbuild_dir/SOURCES/$comp->{kitreponame}-$comp->{kitcompname}.tar from $sourcedir/*";
            return 1;
        }
    }

    # - don't want debug info - 3845
    #    if (!$::VERBOSE) {
    $rpmbuild_cmd .= ' --quiet ';

    #    }

    if (system($rpmbuild_cmd)) {
        print "Error running rpmbuild command for kit component $comp->{kitcompname} meta package\n";
        return 1;
    }
    my @built_rpms = `find $rpmbuild_dir/RPMS -name "*.rpm"`;
    foreach my $rpm (@built_rpms) {
        chomp($rpm);
        if (system("cp -fp $rpm $repodir")) {
            print "Error copying rpm $rpm to build repo directory $repodir \n";
            return 1;
        }
    }
    return 0;
}

#-----------------------------------------------------------------------------

=head3   update_kitcomp_kitpkgdeps 
	
      Update the kitcomponent kitpkgdeps string
        For any kitpkgdep that does not explicitly specify a version-release
        comparison string and for which an rpm exists in the repo,
        query the rpm for its version-release info and set an explicit
        comparison string.
      Reason we need to do all this:  We need to force yum/zypper to update
        the product rpms.  A simple package name in the kitcomponent meta rpm
        REQUIRES entry will not cause the product to get updated if an older 
        version is already installed.  Need to explicitly require this version
        and release of the product package.
      input:  kitcomponent hash
              kitrepo directory

=cut

#-----------------------------------------------------------------------------
sub update_kitcomp_kitpkgdeps
{
    my $comp    = shift;
    my $repodir = shift;

    if (defined($comp->{kitpkgdeps})) {

        # we have some rpms listed in buildkit.conf file
        my $new_kitpkgdeps = '';
        foreach my $d (split(/,/, $comp->{kitpkgdeps})) {
            $d =~ s/\s+//g;
            my $d_short = $d;

            # strip off everything after ">="
            $d_short =~ s/^([\w\.\-]+)[<>=]*.*$/$1/;

            # if they are the same then there was no v/r info provided
            if ($d_short eq $d) {

                # no version-release comparisons specified for this kitpkgdep
                # do we have this rpm file?
                # get a list of any matches
                my $lscmd = "cd $repodir; /bin/ls $d-\[0-9\]\*.rpm 2>/dev/null";
                my @rpmlist = `$lscmd`;

                if (scalar(@rpmlist) == 0) {
                    next;
                }

                # get the newest version there is
                my $newestrpm = xCAT::BuildKitUtils->get_latest_version($repodir, \@rpmlist);

                if (!$newestrpm) {
                    print "Error: Could not determine the latest version of rpm $d contained in $repodir. \n";
                    next;
                }

                # get the Version and release values for this rpm
                my $cmd = "rpm -q --qf \"%{NAME} >= %{VERSION}-%{RELEASE}\" -p $repodir/$newestrpm 2>/dev/null";
                if ($::VERBOSE) {
                    print "running rpm query to get version-release info: \n $cmd \n";
                }

                my $new_d = `$cmd`;
                if (!$new_d) {
                    print "Error: Could not determine the latest version of rpm $d. \n";
                    next;
                }

                chomp($new_d);
                if ($::VERBOSE) {
                    print "output: \n \'$new_d\' \n";
                }
                if ($new_d ne '') {
                    $new_kitpkgdeps .= "$new_d,";
                } else {
                    $new_kitpkgdeps .= "$d,";
                }
            } else {
                $new_kitpkgdeps .= "$d,";
            }
        }

        $new_kitpkgdeps =~ s/(\,)*$//;
        $comp->{kitpkgdeps} = $new_kitpkgdeps;
    }

    return 0;
}

#-----------------------------------------------------------------------------

=head3    gen_kitcomp_spec

   generate the rpm spec file for the kitcomponent  metapkg rpm 
      input:  kitcomponent hash
              kitrepo hash

=cut

#-----------------------------------------------------------------------------
sub gen_kitcomp_spec
{
    my $comp      = shift;
    my $repo      = shift;
    my $level     = shift;
    my $scriptdir = $::workdir . "/scripts/";
    my $tmpdir    = $::workdir . "/tmp/";

    # read in the template spec file
    my $spec_template = $::XCATSHARE . "/kits/kitcomponent.spec.template";
    my $SF;
    unless (open($SF, "<", $spec_template)) {
        print "Error attempting to open the xCAT Kit Component template file $spec_template. \n";
        return 1;
    }
    if ($::VERBOSE) {
        print "Reading the xCAT Kit Component template file $spec_template. \n";
    }
    my @lines = <$SF>;
    close $SF;

    my $kitname     = $::bldkit_config->{kit}{entries}[0]->{basename};
    my $kitcompname = $comp->{kitcompname};

    my ($prescript, $postscript, $preupscript, $postupscript, $preunscript, $postunscript, $nonnativepkgs, $sourcetar, $setup, $files) = ' ';
    if ($level eq 'PREREQUISITE' || $level eq 'ALL') {
        if (defined($comp->{preinstall})) {
            $prescript = &load_script("$scriptdir$comp->{preinstall}");
            $prescript = "if [ \"\$1\" = \"1\" ] ; then\n" . $prescript . "\nfi"; }
        if (defined($comp->{preupgrade})) {
            $preupscript = &load_script("$scriptdir$comp->{preupgrade}");
            $preupscript = "if [ \"\$1\" = \"2\" ] ; then\n" . $preupscript . "\nfi"; }
    }
    if ($level eq 'METARPM' || $level eq 'ALL') {
        if (defined($comp->{preuninstall})) {
            $preunscript = &load_script("$scriptdir$comp->{preuninstall}"); }
        if (defined($comp->{postinstall})) {
            $postscript = &load_script("$scriptdir$comp->{postinstall}");
            $postscript = "if [ \"\$1\" = \"1\" ] ; then\n" . $postscript . "\nfi"; }
        if (defined($comp->{postupgrade})) {
            $postupscript = &load_script("$scriptdir$comp->{postupgrade}");
            $postupscript = "if [ \"\$1\" = \"2\" ] ; then\n" . $postupscript . "\nfi"; }
        if (defined($comp->{postuninstall})) {
            $postunscript = &load_script("$scriptdir$comp->{postuninstall}"); }
        if (defined($comp->{non_native_pkgs})) {
            $nonnativepkgs = "\n";
            $nonnativepkgs .= "mkdir -p \$RPM_BUILD_ROOT/opt/xcat/kits/$kitname/$kitcompname \n";
            $nonnativepkgs .= "cp -a * \$RPM_BUILD_ROOT/opt/xcat/kits/$kitname/$kitcompname  \n";
            $sourcetar = "Source: $comp->{basename}.tar.gz";
            $setup     = "\%setup -q -n $comp->{basename}";
            $files     = "/opt/xcat/kits";
        }
    }

    #  remove lines that correspond to optional tags that have no values
    #     in this instance.   Adding lines to the spec file that have
    #     no values will cause a build error.
    my @newlines;
    foreach my $l (@lines) {
        chomp;

        # don't add vendor,packager,url to spec file unless we have a value
        if ($l =~ /INSERT_vendor_HERE/) {
            if (!$::bldkit_config->{kit}{entries}[0]->{vendor}) {
                next;
            }
        }
        if ($l =~ /INSERT_packager_HERE/) {
            if (!$::bldkit_config->{kit}{entries}[0]->{packager}) {
                next;
            }
        }
        if ($l =~ /INSERT_url_HERE/) {
            if (!$::bldkit_config->{kit}{entries}[0]->{url}) {
                next;
            }
        }
        push @newlines, $l;
    }
    @lines = @newlines;

    if ($level eq 'ALL') {
        for (@lines) {
            chomp;
            s/<<<INSERT_kitbasename_HERE>>>/$kitname/;
            s/<<<INSERT_kitcomponent_basename_HERE>>>/$comp->{basename}/;
            s/<<<INSERT_kitcomponent_version_HERE>>>/$comp->{version}/;
            s/<<<INSERT_kitcomponent_release_HERE>>>/$comp->{release}/;
s/<<<INSERT_kit_license_HERE>>>/$::bldkit_config->{kit}{entries}[0]->{kitlicense}/;
s/<<<INSERT_vendor_HERE>>>/$::bldkit_config->{kit}{entries}[0]->{vendor}/;
s/<<<INSERT_packager_HERE>>>/$::bldkit_config->{kit}{entries}[0]->{packager}/;
            s/<<<INSERT_url_HERE>>>/$::bldkit_config->{kit}{entries}[0]->{url}/;
            s/<<<INSERT_kitcomponent_ospkgdeps_HERE>>>/$comp->{ospkgdeps}/;
            s/<<<INSERT_kitcomponent_kitpkgdeps_HERE>>>/$comp->{kitpkgdeps}/;
            s/<<<INSERT_kitcomponent_kitcompdeps_HERE>>>/$comp->{kitcompdeps}/;
            s/<<<INSERT_kitcomponent_desc_HERE>>>/$comp->{description}/;
            s/<<<INSERT_kitcomponent_non_native_pkgs_HERE>>>/$nonnativepkgs/;
            s/<<<INSERT_kitcomponent_sourcetar_HERE>>>/$sourcetar/;
            s/<<<INSERT_kitcomponent_setup_HERE>>>/$setup/;
            s/<<<INSERT_kitcomponent_files_HERE>>>/$files/;
            s/<<<INSERT_kitcomponent_preinstall_script_HERE>>>/$prescript/;
            s/<<<INSERT_kitcomponent_postinstall_script_HERE>>>/$postscript/;
            s/<<<INSERT_kitcomponent_preupgrade_script_HERE>>>/$preupscript/;
            s/<<<INSERT_kitcomponent_postupgrade_script_HERE>>>/$postupscript/;
            s/<<<INSERT_kitcomponent_preuninstall_script_HERE>>>/$preunscript/;
s/<<<INSERT_kitcomponent_postuninstall_script_HERE>>>/$postunscript/;
        }
    } elsif ($level eq 'PREREQUISITE') {
        for (@lines) {
            chomp;
            s/<<<INSERT_kitbasename_HERE>>>/$kitname/;
            s/<<<INSERT_kitcomponent_basename_HERE>>>/prep_$comp->{basename}/;
            s/<<<INSERT_kitcomponent_version_HERE>>>/$comp->{version}/;
            s/<<<INSERT_kitcomponent_release_HERE>>>/$comp->{release}/;
s/<<<INSERT_kit_license_HERE>>>/$::bldkit_config->{kit}{entries}[0]->{kitlicense}/;
s/<<<INSERT_vendor_HERE>>>/$::bldkit_config->{kit}{entries}[0]->{vendor}/;
s/<<<INSERT_packager_HERE>>>/$::bldkit_config->{kit}{entries}[0]->{packager}/;
            s/<<<INSERT_url_HERE>>>/$::bldkit_config->{kit}{entries}[0]->{url}/;
            s/<<<INSERT_kitcomponent_ospkgdeps_HERE>>>/$comp->{ospkgdeps}/;
            s/<<<INSERT_kitcomponent_kitpkgdeps_HERE>>>//;
            s/<<<INSERT_kitcomponent_kitcompdeps_HERE>>>//;
            s/<<<INSERT_kitcomponent_desc_HERE>>>/$comp->{description}/;
            s/<<<INSERT_kitcomponent_non_native_pkgs_HERE>>>//;
            s/<<<INSERT_kitcomponent_sourcetar_HERE>>>//;
            s/<<<INSERT_kitcomponent_setup_HERE>>>//;
            s/<<<INSERT_kitcomponent_files_HERE>>>//;
            s/<<<INSERT_kitcomponent_preinstall_script_HERE>>>/$prescript/;
            s/<<<INSERT_kitcomponent_postinstall_script_HERE>>>//;
            s/<<<INSERT_kitcomponent_preupgrade_script_HERE>>>/$preupscript/;
            s/<<<INSERT_kitcomponent_postupgrade_script_HERE>>>//;
            s/<<<INSERT_kitcomponent_preuninstall_script_HERE>>>/$preunscript/;
            s/<<<INSERT_kitcomponent_postuninstall_script_HERE>>>//;
        }

    } elsif ($level eq 'METARPM') {
        for (@lines) {
            chomp;
            s/<<<INSERT_kitbasename_HERE>>>/$kitname/;
            s/<<<INSERT_kitcomponent_basename_HERE>>>/$comp->{basename}/;
            s/<<<INSERT_kitcomponent_version_HERE>>>/$comp->{version}/;
            s/<<<INSERT_kitcomponent_release_HERE>>>/$comp->{release}/;
s/<<<INSERT_kit_license_HERE>>>/$::bldkit_config->{kit}{entries}[0]->{kitlicense}/;
s/<<<INSERT_vendor_HERE>>>/$::bldkit_config->{kit}{entries}[0]->{vendor}/;
s/<<<INSERT_packager_HERE>>>/$::bldkit_config->{kit}{entries}[0]->{packager}/;
            s/<<<INSERT_url_HERE>>>/$::bldkit_config->{kit}{entries}[0]->{url}/;
            s/<<<INSERT_kitcomponent_ospkgdeps_HERE>>>//;
            s/<<<INSERT_kitcomponent_kitpkgdeps_HERE>>>/$comp->{kitpkgdeps}/;

            #Update kitcompdeps for prep_<kitcomponent>
            if ($::VALID_PRER_COMPONENT) {
s/<<<INSERT_kitcomponent_kitcompdeps_HERE>>>/$comp->{kitcompdeps},prep_$comp->{basename}/;
            } else {
s/<<<INSERT_kitcomponent_kitcompdeps_HERE>>>/$comp->{kitcompdeps}/;
            }
            s/<<<INSERT_kitcomponent_desc_HERE>>>/$comp->{description}/;
            s/<<<INSERT_kitcomponent_non_native_pkgs_HERE>>>/$nonnativepkgs/;
            s/<<<INSERT_kitcomponent_sourcetar_HERE>>>/$sourcetar/;
            s/<<<INSERT_kitcomponent_setup_HERE>>>/$setup/;
            s/<<<INSERT_kitcomponent_files_HERE>>>/$files/;
            s/<<<INSERT_kitcomponent_preinstall_script_HERE>>>//;
            s/<<<INSERT_kitcomponent_postinstall_script_HERE>>>/$postscript/;
            s/<<<INSERT_kitcomponent_preupgrade_script_HERE>>>//;
            s/<<<INSERT_kitcomponent_postupgrade_script_HERE>>>/$postupscript/;
            s/<<<INSERT_kitcomponent_preuninstall_script_HERE>>>/$preunscript/;
s/<<<INSERT_kitcomponent_postuninstall_script_HERE>>>/$postunscript/;
        }
    }

    # Write the generated spec file
    mkpath($tmpdir);

    my $fn;
    my $NSF;
    if ($level eq 'PREREQUISITE') {
        $fn = $comp->{kitcompname} . "-prep.spec"
    } else {
        $fn = $comp->{kitcompname} . ".spec"
    }
    unless (open($NSF, ">$tmpdir$fn")) {
        return 1;
    }
    if ($::VERBOSE) {
        print "Created kitcomponent spec file \'$tmpdir$fn\'\n";

    }
    foreach my $line (@lines) {
        print $NSF $line, "\n";
    }

    close($NSF);
    return 0;
}

#-----------------------------------------------------------------------------

=head3   build_kitcomp_debian 



=cut

#-----------------------------------------------------------------------------
sub build_kitcomp_debian {
    my $comp = shift;
    my %repo;
    my $debbuilddir = $::workdir . "/debbuild/" . $comp->{kitcompname};
    my $kcmetaname  = comppkgname($comp);

    #If this kitcomponent has external non-native pkgs,
    #skip the meta package build
    if (defined($::NON_NATIVE_PKGS) &&
        defined($::NON_NATIVE_PKGS->{ $comp->{kitcompname} }) &&
        $::NON_NATIVE_PKGS->{ $comp->{kitcompname} }) {
        if ($::VERBOSE) {
            print "Kit component $comp->{kitcompname} has external non-native packages.  Skipping rpm build for $kcmetaname. \n";
        }
        return 0;
    }

    # find the kitrepo hash for this component
    foreach my $kr (@{ $::bldkit_config->{kitrepo}{entries} }) {
        if ($comp->{kitrepoid} eq $kr->{kitrepoid}) {
            %repo = %{$kr};
            last;
        }
    }


    #run the dpkg-buildpackage command
    my $curdir = $::workdir;
    my $cmd    = "rm -Rf $debbuilddir";
    system($cmd);
    mkpath($debbuilddir);

    $::VALID_PREP_COMPONENT = 0;

    if (!$::PREREQUISITE) {
        if ($comp->{ospkgdeps} || $comp->{preinstall} || $comp->{preupgrade} || $comp->{preuninstall}) {

            #Create debian directory for this kit component preppackage

            if (&gen_kitcomp_debdir_prep($comp, \%repo)) { return 1; }
            $::VALID_PREP_COMPONENT = 1;

            # build prep deb
            my $prep_compversion = $comp->{version} . "-" . $comp->{release};
            my $prep_buildstring = "Prep Kit component build package.";
            my $prep_debbuilddir = $::workdir . "/debbuild/" . "prep-" . $comp->{kitcompname};
            my $prep_debianbuildcmd = "cd $prep_debbuilddir;debchange -v $prep_compversion -b -c debian/changelog $prep_buildstring;dpkg-buildpackage $dpkg_flag";

            if (system($prep_debianbuildcmd)) {
                print "Error running \"dpkg-buildpackage $dpkg_flag\" command for kit component prep-$comp->{kitcompname} meta package\n";
                return 1;
            }
        }

        #Create debian directory for this kit component metapackage

        if (&gen_kitcomp_debdir($comp, \%repo, 'METADEB')) { return 1; }

    } else {

        #Create debian directory for this kit component

        if (&gen_kitcomp_debdir($comp, \%repo, 'ALL')) { return 1; }

    }



    if (defined($comp->{non_native_pkgs})) {
        my $sourcedir = $::workdir . "/source_packages";

        foreach my $pkgfile (split(/,/, $comp->{non_native_pkgs})) {
            my $pkg_file;
            my ($key, $value) = split /:/, $pkgfile;
            if ("$key" =~ /EXTERNALPKGS/) {
                $pkg_file = $value;
            } else {
                $pkg_file = $key;
            }

            $cmd = "cp -p $sourcedir/$pkg_file $debbuilddir";
            if (system($cmd)) {
                print "Error copying non-native package file $sourcedir/$pkg_file to debbuilddir\n";
                return 1;
            }
        }
    }
    my $compversion = $comp->{version} . "-" . $comp->{release};
    my $buildstring = "\'Kit component build package.\'";
    my $debianbuildcmd = "cd $debbuilddir;debchange -v $compversion -b -c debian/changelog $buildstring;dpkg-buildpackage $dpkg_flag";
    if (!$::NON_NATIVE_PKGS->{ $comp->{kitcompname} }) {
        if (system($debianbuildcmd)) {
            print "Error running \"dpkg-buildpackage $dpkg_flag\" command for kit component $comp->{kitcompname} meta package\n";
            return 1;
        }
        my $repodir   = $::base_repodir . "/" . $repo{kitreponame};
        my @builtdebs = `find $::workdir/debbuild -maxdepth 1 -name "*.deb"`;
        foreach my $deb (@builtdebs) {
            chomp($deb);
            if (system("cp -fp $deb $repodir")) {
                print "Error copying package $deb to build repo directory $repodir \n";
                return 1;
            }
        }
    }
    return 0;
}


#-----------------------------------------------------------------------------

=head3   gen_kitcomp_debdir_prep



=cut

#-----------------------------------------------------------------------------
sub gen_kitcomp_debdir_prep {
    my $comp      = shift;
    my $repo      = shift;
    my $scriptdir = $::workdir . "/scripts/";
    my $combuilddir = $::workdir . "/debbuild/" . "prep-" . $comp->{kitcompname};

    #copy the debian dir template to the build path
    mkpath("$combuilddir/debian");
    my $cmd = "cp -Rf " . $::XCATSHARE . "/kits/debian_template/* $combuilddir/debian/";
    system($cmd);

    my $kitname     = $::bldkit_config->{kit}{entries}[0]->{basename};
    my $kitcompname = "prep-" . $comp->{kitcompname};
    my $upgradeflag = "pre-" . $comp->{basename} . ".tmp";

    my ($prescript, $postscript, $preupscript, $postupscript, $preunscript, $postunscript, $nonnativepkgs) = '';
    if (defined($comp->{preinstall})) {
        $prescript = &load_script("$scriptdir$comp->{preinstall}");
    }
    if (defined($comp->{preupgrade})) {
        $preupscript = &load_script("$scriptdir$comp->{preupgrade}");
    }
    if (defined($comp->{preuninstall})) {
        $preunscript = &load_script("$scriptdir$comp->{preuninstall}");
    }

    #replace all special sub string in all files under debian
    unless (opendir(DH, "${combuilddir}/debian/")) {
        print "Can not open the xCAT Kit Component debian dir: ${combuilddir}/debian/";
        return 1;
    }

    foreach (readdir(DH)) {
        my $file = "${combuilddir}/debian/$_";
        if (-d $file) {
            next;
        }

        unless (open(FH, "<", $file)) {
            print "Error attempting to open the xCAT Kit Component ${kitcompname}'s debian template file $file.\n";
            close(DH);
            return 1;
        }

        if ($::VERBOSE) {
            print "Reading the xCAT Kit Component ${kitcompname}'s debian template file $file. \n";
        }
        my @lines = <FH>;
        close(FH);
        my $prep_comp_name = "prep-" . $comp->{basename};
        for (@lines) {
            chomp;
            s/<<<INSERT_kitcomponent_basename_HERE>>>/$prep_comp_name/;
            s/<<<INSERT_kitcomponent_ospkgdeps_HERE>>>/$comp->{ospkgdeps}/;
            s/<<<INSERT_kitcomponent_kitpkgdeps_HERE>>>//;
            s/<<<INSERT_kitcomponent_kitcompdeps_HERE>>>//;
            s/<<<INSERT_kitcomponent_desc_HERE>>>/$comp->{description}/;
            s/<<<INSERT_kitcomponent_upgrade_flag_HERE>>>/$upgradeflag/;
            s/<<<INSERT_kitcomponent_preinstall_script_HERE>>>/$prescript/;
            s/<<<INSERT_kitcomponent_postinstall_script_HERE>>>//;
            s/<<<INSERT_kitcomponent_preupgrade_script_HERE>>>/$preupscript/;
            s/<<<INSERT_kitcomponent_postupgrade_script_HERE>>>//;
            s/<<<INSERT_kitcomponent_preuninstall_script_HERE>>>/$preunscript/;
            s/<<<INSERT_kitcomponent_postuninstall_script_HERE>>>//;

        }
        my $joined_lines = join("\n", @lines);
        @lines = split(/\\n/, $joined_lines);

        open(FH, ">", $file);
        if ($::VERBOSE) {
            print "Created kitcomponent ${kitcompname}'s build file under debian dir $file";
        }
        print FH @lines;
        close(FH);
    }
    closedir(DH);

    return 0;
}



#-----------------------------------------------------------------------------

=head3   gen_kitcomp_debdir



=cut

#-----------------------------------------------------------------------------
sub gen_kitcomp_debdir {
    my $comp        = shift;
    my $repo        = shift;
    my $level       = shift;
    my $scriptdir   = $::workdir . "/scripts/";
    my $combuilddir = $::workdir . "/debbuild/" . $comp->{kitcompname};

    #copy the debian dir template to the build path
    mkpath("$combuilddir/debian");
    my $cmd = "cp -Rf " . $::XCATSHARE . "/kits/debian_template/* $combuilddir/debian/";
    system($cmd);

    my $kitname     = $::bldkit_config->{kit}{entries}[0]->{basename};
    my $kitcompname = $comp->{kitcompname};
    my $upgradeflag = $comp->{basename} . ".tmp";

    my ($prescript, $postscript, $preupscript, $postupscript, $preunscript, $postunscript, $nonnativepkgs) = '';

    if ($level eq 'METADEB' || $level eq 'ALL')
    {
        if (defined($comp->{postinstall})) {
            $postscript = &load_script("$scriptdir$comp->{postinstall}");
        }

        if (defined($comp->{postupgrade})) {
            $postupscript = &load_script("$scriptdir$comp->{postupgrade}");
        }
        if (defined($comp->{postuninstall})) {
            $postunscript = &load_script("$scriptdir$comp->{postuninstall}");
        }
        if (defined($comp->{non_native_pkgs})) {
            $nonnativepkgs = "\n";
            $nonnativepkgs .= "mkdir -p \$RPM_BUILD_ROOT/opt/xcat/kits/$kitname/$kitcompname \n";
            $nonnativepkgs .= "cp -a * \$RPM_BUILD_ROOT/opt/xcat/kits/$kitname/$kitcompname  \n";
        }
    }
    if ($level eq 'ALL')
    {
        if (defined($comp->{preinstall})) {
            $prescript = &load_script("$scriptdir$comp->{preinstall}");
        }
        if (defined($comp->{preupgrade})) {
            $preupscript = &load_script("$scriptdir$comp->{preupgrade}");
        }
        if (defined($comp->{preuninstall})) {
            $preunscript = &load_script("$scriptdir$comp->{preuninstall}");
        }
    }


    #replace all special sub string in all files under debian
    unless (opendir(DH, "${combuilddir}/debian/")) {
        print "Can not open the xCAT Kit Component debian dir: ${combuilddir}/debian/";
        return 1;
    }

    foreach (readdir(DH)) {
        my $file = "${combuilddir}/debian/$_";
        if (-d $file) {
            next;
        }

        unless (open(FH, "<", $file)) {
            print "Error attempting to open the xCAT Kit Component ${kitcompname}'s debian template file $file.\n";
            close(DH);
            return 1;
        }

        if ($::VERBOSE) {
            print "Reading the xCAT Kit Component ${kitcompname}'s debian template file $file. \n";
        }
        my @lines = <FH>;
        close(FH);
        my $prepcomp = "prep-" . $comp->{basename};
        for (@lines) {
            chomp;
            s/<<<INSERT_kitcomponent_basename_HERE>>>/$comp->{basename}/;
            s/<<<INSERT_kitcomponent_ospkgdeps_HERE>>>/$comp->{ospkgdeps}/;
            s/<<<INSERT_kitcomponent_kitpkgdeps_HERE>>>/$comp->{kitpkgdeps}/;
            if ($::VALID_PREP_COMPONENT) {
s/<<<INSERT_kitcomponent_kitcompdeps_HERE>>>/$comp->{kitcompdeps},$prepcomp/;
            }
            else
            {
s/<<<INSERT_kitcomponent_kitcompdeps_HERE>>>/$comp->{kitcompdeps}/;
            }

            s/<<<INSERT_kitcomponent_desc_HERE>>>/$comp->{description}/;
            s/<<<INSERT_kitcomponent_upgrade_flag_HERE>>>/$upgradeflag/;
            s/<<<INSERT_kitcomponent_preinstall_script_HERE>>>/$prescript/;
            s/<<<INSERT_kitcomponent_postinstall_script_HERE>>>/$postscript/;
            s/<<<INSERT_kitcomponent_preupgrade_script_HERE>>>/$preupscript/;
            s/<<<INSERT_kitcomponent_postupgrade_script_HERE>>>/$postupscript/;
            s/<<<INSERT_kitcomponent_preuninstall_script_HERE>>>/$preunscript/;
s/<<<INSERT_kitcomponent_postuninstall_script_HERE>>>/$postunscript/;
        }
        my $joined_lines = join("\n", @lines);
        @lines = split(/\\n/, $joined_lines);

        open(FH, ">", $file);
        if ($::VERBOSE) {
            print "Created kitcomponent ${kitcompname}'s build file under debian dir $file";
        }
        print FH @lines;
        close(FH);
    }
    closedir(DH);

    if (defined($comp->{non_native_pkgs})) {
        unless (open(FH, ">", "${combuilddir}/debian/dir")) {
            print "Error attempting to open the xCAT Kit Component ${kitcompname}'s debian file dir.\n";
            return 1;
        }
        print FH "opt/xcat/kits/$kitname/$kitcompname/";
        close(FH);

        unless (open(FH, ">", "${combuilddir}/debian/install")) {
            print "Error attempting to open the xCAT Kit Component ${kitcompname}'s debian file dir.\n";
            return 1;
        }
        foreach my $pkgfile (split(/,/, $comp->{non_native_pkgs})) {
            my $pkgname = '';
            my ($key, $value) = split /:/, $pkgfile;
            if ("$key" =~ /EXTERNALPKGS/) {
                $pkgname = $value;
            } else {
                $pkgname = $key;
            }
            print FH "$pkgname opt/xcat/kits/$kitname/$kitcompname/ \n";
        }
        close(FH);
    }
    return 0;
}

#-----------------------------------------------------------------------------

=head3    load_script
	
   load a kitcomponent script into a single return string 
     with imbedded newline chars
      input:  fullpath of scriptname

=cut

#-----------------------------------------------------------------------------
sub load_script
{
    my $scriptname = shift;
    my $SF;
    unless (open($SF, "<", $scriptname)) {
        print "Error attempting to open the file $scriptname. \n";
        return;
    }
    if ($::VERBOSE) {
        print "Reading the file $scriptname. \n";
    }
    my @lines = <$SF>;
    close $SF;

    my $script_contents = join('', @lines);
    return $script_contents;
}

#-----------------------------------------------------------------------------

=head3    create_kitconf
	
  Create the kit configuration file to put into the kit tar file.

=cut

#-----------------------------------------------------------------------------
sub create_kitconf
{
    # Build kit config file entries from buildkit config input
    my $kitname = $::bldkit_config->{kit}{entries}[0]->{kitname};
    foreach my $s (keys %{$::bldkit_config}) {
        if (!defined($::buildkit_def{$s})) { next; }
        if ($s eq 'kitpackage')            { next; }
        my $li = 0;
        foreach my $se (@{ $::bldkit_config->{$s}{entries} }) {
            $::kit_config->{$s}{entries}[$li]->{kitname} = $kitname;

            # copy all defined attrs over
            foreach my $a (keys %{ $::buildkit_def{$s} }) {
                if (($::buildkit_def{$s}{$a}->{cp_to_kitconfig} eq '1') &&
                    (defined($se->{$a}))) {
                    if ($s eq 'kitcomponent') {
                        if ($a eq 'kitpkgdeps') {
                            my $value;
                            foreach my $d (split(/,/, $se->{$a})) {
                                $d =~ s/\s+//g;
                                $d =~ s/^([\w\.\-]+)[<>=]*.*$/$1/;
                                $value .= "$d,";
                            }
                            $value =~ s/(\,)*$//;
                            $se->{$a} = $value;
                        }
                    }
                    $::kit_config->{$s}{entries}[$li]->{$a} = $se->{$a};
                }

                # cp_to_kitconfig=2 means copy the file to the new kit
                # but only do the copy if this is a final kit build
                if (($::buildkit_def{$s}{$a}->{cp_to_kitconfig} eq '2') &&
                    (defined($se->{$a}))  &&
                    !$::HAVE_EXTERNAL_PKG && !$::HAVE_NON_NATIVE_PKGS) {
                    my $prefix = "$kitname";
                    if ($s eq 'kitcomponent') {
                        $prefix = "$::bldkit_config->{$s}{entries}[$li]->{kitcompname}";
                        if (($a eq 'postbootscripts') ||
                            ($a eq 'genimage_postinstall')) {
                            $prefix = "KIT_" . $prefix;
                        }
                        if (!($::kit_config->{$s}{entries}[$li]->{$a} =
                                &cp_to_builddir($a, $se->{$a}, $::workdir . '/' . $::buildkit_def{$s}{$a}->{base_dir}, $prefix, $::bldkit_config->{$s}{entries}[$li]))) {
                            return 1;
                        }
                    } else {
                        if (!($::kit_config->{$s}{entries}[$li]->{$a} =
                                &cp_to_builddir($a, $se->{$a}, $::workdir . '/' . $::buildkit_def{$s}{$a}->{base_dir}, $prefix))) {
                            return 1;
                        }
                    }
                }
            }

            # Handle special attrs, these 3 attributes did not defined in the buildkit.conf, special cases.
            if ($s eq 'kitrepo') {
                $::kit_config->{$s}{entries}[$li]->{kitreponame} =
                  $se->{kitreponame};
            } elsif ($s eq 'kitcomponent') {
                $::kit_config->{$s}{entries}[$li]->{kitcompname} =
                  $se->{kitcompname};
                $::kit_config->{$s}{entries}[$li]->{kitreponame} =
                  $se->{kitreponame};
                if (!$::PREREQUISITE and ($se->{ospkgdeps} || $se->{preinstall} || $se->{preupgrade} || $se->{preuninstall})) {
                    if ($debianflag) {
                        $::kit_config->{$s}{entries}[$li]->{prerequisite} =
                          "prep-" . $se->{basename};
                    } else {
                        $::kit_config->{$s}{entries}[$li]->{prerequisite} =
                          "prep_" . $se->{basename};
                    }
                }
            }
            $li++;
        }
    }

    # Handle external packages
    if ($::HAVE_EXTERNAL_PKG) {
        foreach my $kp (@{ $::bldkit_config->{kitpackage}{entries} }) {
            if ($kp->{isexternalpkg} eq 'yes') {
                my %current_entry;
                $current_entry{filename}    = $kp->{filename};
                $current_entry{kitreponame} = $kp->{kitreponame};
                push(@{ $::kit_config->{EXTERNALPKG}{'entries'} }, {%current_entry});
            }
        }
    }


    # Handle non_native_pkgs
    foreach my $kc (@{ $::bldkit_config->{kitcomponent}{entries} }) {
        if ($::NON_NATIVE_PKGS->{ $kc->{kitcompname} }) {
            my @nativefiles;
            foreach my $pkgfile (split(/,/, $kc->{non_native_pkgs})) {
                my ($key, $value) = split /:/, $pkgfile;
                if ("$key" =~ /EXTERNALPKGS/) {
                    push(@nativefiles, $value);
                }
            }

            my %current_entry;
            $current_entry{filename}    = join ',', @nativefiles;
            $current_entry{kitcompname} = $kc->{kitcompname};
            $current_entry{basename}    = $kc->{basename};
            $current_entry{kitreponame} = $kc->{kitreponame};
            push(@{ $::kit_config->{NONNATIVEPKGS}{'entries'} }, {%current_entry});
        }
    }


    #  Write Kit Config File
    my @lines;
    my $li = 0;
    $lines[ $li++ ] = "# Kit Configuration File for $kitname generated by buildkit\n";
    $lines[ $li++ ] = "kitbuildinfo: \n";
    my $xCAT_buildkit_version = '';
    if ($debianflag) {
        $xCAT_buildkit_version = `dpkg-query --show -f='\${Version}' xcat-buildkit`;
    }
    else {
        $xCAT_buildkit_version = `rpm -q --qf \"%{VERSION}-%{RELEASE}\" xCAT-buildkit`;
    }
    $lines[ $li++ ] = "   xCAT_version =  $xCAT_buildkit_version \n";
    $lines[ $li++ ] = "   build_date =  " . localtime() . "\n";
    $lines[ $li++ ] = "   kitframework =  $::KITFRAMEWORK \n";
    $lines[ $li++ ] = "   compatible_kitframeworks =  $::COMPATIBLE_KITFRAMEWORKS \n";

    foreach my $s ('kit', 'kitrepo', 'kitcomponent', 'EXTERNALPKG', 'NONNATIVEPKGS') {
        foreach my $se (@{ $::kit_config->{$s}{entries} }) {
            $lines[ $li++ ] = "$s: \n";
            foreach my $a (keys %{$se}) {
                $lines[ $li++ ] = "    $a = $se->{$a} \n";
            }
        }
    }

    if ((!-d $::deploy_dir) && (!mkpath($::deploy_dir))) {
        print "Error creating build directory $::deploy_dir.\n";
        return;
    }

    my $full_kit_conf = $::deploy_dir . "/" . $::kit_conf;
    my $NCF;
    unless (open($NCF, ">$full_kit_conf")) {
        return 1;
    }
    if ($::VERBOSE) {
        print "Wrote new kit configuration file $full_kit_conf \n";
    }
    print $NCF @lines;
    close($NCF);

    return 0;
}

#-----------------------------------------------------------------------------

=head3    cp_to_builddir
	
   Copy specified files into the build directory renaming as indicated
   and substituting strings if needed

=cut

#-----------------------------------------------------------------------------
sub cp_to_builddir
{
    my $type     = shift;
    my $files    = shift;
    my $from_dir = shift;
    my $prefix   = shift;
    my $kitcomp  = shift;

    my $copied_files;
    my $other_files = $::deploy_dir . "/other_files";
    if ((!-d $other_files) && (!mkpath($other_files))) {
        print "Error creating build directory $other_files.\n";
        return;
    }
    foreach my $file (split(/\,/, $files)) {
        $file =~ s/\s+//g;
        my $from_file      = $from_dir . "/" . $file;
        my $from_file_base = basename($file);
        my $to_file_base   = $prefix . "_" . $from_file_base;
        my $to_file        = $other_files . "/" . $to_file_base;

        # Read in the file
        my $FF;
        unless (open($FF, "<", $from_file)) {
            print "The Kit file $from_file could not be read. \n";
            return 1;
        }
        my @lines = <$FF>;
        for (@lines) {
s/<<<buildkit_WILL_INSERT_kit_name_HERE>>>/$::bldkit_config->{kit}{entries}[0]->{kitname}/g;
s/<<<buildkit_WILL_INSERT_kit_basename_HERE>>>/$::bldkit_config->{kit}{entries}[0]->{basename}/g;
s/<<<buildkit_WILL_INSERT_kit_version_HERE>>>/$::bldkit_config->{kit}{entries}[0]->{version}/g;
s/<<<buildkit_WILL_INSERT_kit_release_HERE>>>/$::bldkit_config->{kit}{entries}[0]->{release}/g;
            if (defined($kitcomp)) {
s/<<<buildkit_WILL_INSERT_kitcomponent_name_HERE>>>/$kitcomp->{kitcompname}/g;
s/<<<buildkit_WILL_INSERT_kitcomponent_basename_HERE>>>/$kitcomp->{basename}/g;
s/<<<buildkit_WILL_INSERT_kitcomponent_version_HERE>>>/$kitcomp->{version}/g;
s/<<<buildkit_WILL_INSERT_kitcomponent_release_HERE>>>/$kitcomp->{release}/g;
            }
        }

        # Write the file back out
        my $TF;
        unless (open($TF, ">$to_file")) {
            print "Error copying file $from_file to build directory $other_files \n";
            return 1;
        }
        if ($::VERBOSE) {
            print "Copied $from_file to $to_file replacing kit and kitcomponent strings as needed. \n";
        }
        print $TF @lines;
        close($TF);

        $copied_files .= ",$to_file_base";

        if (($type eq 'postbootscripts') ||
            ($type eq 'genimage_postinstall')) {
            system("chmod 755 $to_file");
        }
    }
    $copied_files =~ s/^\,//;
    return $copied_files;
}

#-----------------------------------------------------------------------------

=head3    create_builddir
	
   Create the build directory and copy in all required files for building
   the kit tar file.

=cut

#-----------------------------------------------------------------------------
sub create_builddir
{
    my $kitname = $::bldkit_config->{kit}{entries}[0]->{kitname};

    # Note:
    #    - repos already created and validated
    #    - kit.conf file already created
    #    - exlists, postbootscripts, and deployparams already copied

    # copy plugins to build dir and edit to insert correct plugin and kit names
    my $plugin_dir = $::deploy_dir . "/plugins";
    if (-d "$::workdir/plugins") {
        if ((!-d $plugin_dir) && (!mkpath($plugin_dir))) {
            print "Error creating build directory $plugin_dir.\n";
            return 1;
        }

        foreach my $plugin (<$::workdir/plugins/*.pm>) {
            my $plugin_base = basename($plugin);
            my $mod_kitname = $kitname;
            $mod_kitname =~ s/\-/\_/g;
            $mod_kitname =~ s/\./\_/g;
            my $to_plugin = $plugin_dir . "/" . $mod_kitname . "_" . $plugin_base;

            if (system("cp -fp $plugin $to_plugin")) {

                # non-zero return from system call
                print "Error copying plugin file $plugin to build directory $plugin_dir \n";
                return 1;
            }
            if (&edit_plugin($to_plugin)) { return 1; }
        }
    }

    # copy docs to build dir
    if (-d "$::workdir/docs") {
        if (system("cp -fRp $::workdir/docs $::deploy_dir")) {

            # non-zero return from system call
            print "Error copying doc files $::workdir/docs to build directory $::deploy_dir \n";
            return 1;
        }
    }

    # Edit deploy params file to make sure correct format for xCAT
    if (defined($::kit_config->{kit}{entries}[0]->{kitdeployparams})) {
        my $kd_file = $::deploy_dir . "/other_files/" . $::kit_config->{kit}{entries}[0]->{kitdeployparams};
        if (&edit_deployparams($kd_file)) { return 1; }
    }

    if ($::HAVE_EXTERNAL_PKG or $::HAVE_NON_NATIVE_PKGS) {

        # Copy the kitcomponent meta rpm spec if there is external non_native_pkgs.
        if ($debianflag) {
            foreach my $comp (keys %{$::NON_NATIVE_PKGS}) {
                my $kitrepo;
                foreach my $kc (@{ $::bldkit_config->{kitcomponent}{entries} }) {
                    if ($comp eq $kc->{kitcompname}) {
                        $kitrepo = $kc->{kitreponame}
                    }
                }
                mkpath("$::deploy_dir/tmp/");
                my $cmd = "cp -fRP $::workdir/debbuild/$comp $::deploy_dir/tmp/$comp";
                if (system("$cmd")) {
                    print "Error copying kitcomponent meta debian build file $::workdir/debbuild/$comp to build directory $::deploy_dir \n";
                    return 1;
                }
            }
        }

        # Copy over the original buildkit.conf file and input files
        # to help make addpkgs processing easier later
        mkpath("$::deploy_dir/build_input/");
        if (system("cp -fp $::full_buildkit_conf $::deploy_dir/build_input")) {

            # non-zero return from system call
            print "Error copying buildkit config file $::full_buildkit_conf to build directory $::deploy_dir/build_input \n";
            return 1;
        }
    }
    return 0;
}

#-----------------------------------------------------------------------------

=head3    create_PARTIAL_builddir
	
   Create the build directory for a PARTIAL kit (needs external pkgs)
   and copy in all required files for building the kit tar file.
   This includes most build input without editting files since 
   they will need to be generated at addpkgs time.

=cut

#-----------------------------------------------------------------------------
sub create_PARTIAL_builddir
{
    my $kitname = $::bldkit_config->{kit}{entries}[0]->{kitname};

    # Note:
    #    - repos already created and validated
    #    - kit.conf file already created
    #    - exlists, postbootscripts, and deployparams already copied

    # copy docs to build dir
    if (-d "$::workdir/docs") {
        if (system("cp -fRp $::workdir/docs $::deploy_dir")) {

            # non-zero return from system call
            print "Error copying doc files $::workdir/docs to build directory $::deploy_dir \n";
            return 1;
        }
    }

    # Copy over the original buildkit.conf file and input files
    # to help make addpkgs processing easier later
    mkpath("$::deploy_dir/build_input/");
    if (system("cp -fp $::full_buildkit_conf $::deploy_dir/build_input")) {

        # non-zero return from system call
        print "Error copying buildkit config file $::full_buildkit_conf to build directory $::deploy_dir/build_input \n";
        return 1;
    }
    if (-d "$::workdir/other_files") {
        if (system("cp -fpR $::workdir/other_files $::deploy_dir/build_input")) {

            # non-zero return from system call
            print "Error copying $::workdir/otherfiles to build directory $::deploy_dir/build_input \n";
            return 1;
        }
    }
    if (-d "$::workdir/plugins") {
        if (system("cp -fpR $::workdir/plugins $::deploy_dir/build_input")) {

            # non-zero return from system call
            print "Error copying $::workdir/plugins to build directory $::deploy_dir/build_input \n";
            return 1;
        }
    }
    if (-d "$::workdir/scripts") {
        if (system("cp -fpR $::workdir/scripts $::deploy_dir/build_input")) {

            # non-zero return from system call
            print "Error copying $::workdir/scripts to build directory $::deploy_dir/build_input \n";
            return 1;
        }
    }

    # Copy over any provided non-native packages
    my $to_source_dir = "$::deploy_dir/build_input/source_packages";
    mkpath("$to_source_dir");
    foreach my $kc (@{ $::bldkit_config->{kitcomponent}{entries} }) {
        if (defined($kc->{non_native_pkgs})) {
            my $sourcedir = $::workdir . "/source_packages";
            foreach my $pkgfile (split(/,/, $kc->{non_native_pkgs})) {
                my $pkg_file;
                my ($key, $value) = split /:/, $pkgfile;
                if ("$key" =~ /EXTERNALPKGS/) {
                    next;
                } else {
                    $pkg_file = $key;
                }

                my $cmd = "cp -p $sourcedir/$pkg_file $to_source_dir";
                if (system($cmd)) {
                    print "Error copying non-native package file $sourcedir/$pkg_file to $to_source_dir \n";
                    return 1;
                }
            }
        }
    }

    return 0;
}

#-----------------------------------------------------------------------------

=head3    edit_deployparams
	
   Edit the kit deployment parameters to make sure it has correct
   syntax for xCAT otherpkglist support 
   

=cut

#-----------------------------------------------------------------------------
sub edit_deployparams
{
    my $file          = shift;
    my $validate_only = shift;

    # read in the file
    my $DF;
    unless (open($DF, "<", $file)) {
        print "The Kit deployment parameters file $file could not be read. \n";
        return 1;
    }
    my @lines = <$DF>;
    close $DF;

    # Edit the files
    my $changed = 0;
    my @new_lines;
    my $ln = 0;
    foreach my $l (@lines) {
        $ln++;

        # skip blank lines
        if ($l =~ /^\s*$/) {
            push(@new_lines, $l);
            next;
        }

        # #ENV lines
        $l =~ s/^\s+//;    # compress leading blanks
        if ($l =~ /^\#ENV\:/) {
            if (!($l =~ /\#\s*$/)) {
                chomp $l;
                $l .= "#\n";
                $changed = 1;
            }
            push(@new_lines, $l);
            next;
        }

        # skip all other comments
        if ($l =~ /^\s*#/) {
            push(@new_lines, $l);
            next;
        }

        #  Add #ENV if not specified
        if ($l =~ /^\w*\s*\=/) {
            chomp $l;
            $l       = "#ENV: $l #";
            $changed = 1;
            push(@new_lines, $l);
            next;
        }

        # Syntax error
        print "Syntax error in kit deployment parameters file $file \n";
        print "line $ln:  \n";
        print "$l \n";
        return 1;
    }

    # Write the file back out
    if ($changed && !$validate_only) {
        my $NDF;
        unless (open($NDF, ">$file")) {
            return 1;
        }
        if ($::VERBOSE) {
            print "Editted kit deployment parameters file $file \n";
        }
        print $NDF @lines;
        close($NDF);
    }
    return 0;
}

#-----------------------------------------------------------------------------

=head3    edit_plugin
	
   Edit the kit plugin file to insert the full kit name
   

=cut

#-----------------------------------------------------------------------------
sub edit_plugin
{
    my $file    = shift;
    my $kitname = $::bldkit_config->{kit}{entries}[0]->{kitname};

    # convert dashes to underscore since the kitname is used as perl pkg names
    # in the plugin and this causes perl syntax errors
    my $mod_kitname = $kitname;
    $mod_kitname =~ s/\-/\_/g;
    $mod_kitname =~ s/\./\_/g;

    # read in the file
    my $PF;
    unless (open($PF, "<", $file)) {
        print "The Kit plugin file $file could not be read. \n";
        return 1;
    }
    my @lines = <$PF>;
    close $PF;

    for (@lines) {
        s/<<<buildkit_WILL_INSERT_kitname_HERE>>>/$kitname/g;
        s/<<<buildkit_WILL_INSERT_modified_kitname_HERE>>>/$mod_kitname/g;
    }

    # Write the plugin back out
    my $NPF;
    unless (open($NPF, ">$file")) {
        return 1;
    }
    if ($::VERBOSE) {
        print "Inserted kitname values into $file \n";
    }
    print $NPF @lines;
    close($NPF);

    return 0;
}

#-----------------------------------------------------------------------------

=head3    kit_addpkgs
	
   buildkit addpkgs

=cut

#-----------------------------------------------------------------------------
sub kit_addpkgs
{
    # add RPM pkgs to an existing kit tarfile
    my $kittarfile = $::KIT_ADDPKGS;
    my $kitbfname  = basename($kittarfile);
    $kitbfname =~ s/.tar.bz2$//;
    $kitbfname =~ s/.NEED_PRODUCT_PKGS$//;
    my $tmpdir_base = "/tmp/$kitbfname";

    #  - could be list of pkgdir s
    my @pkgdirlist = split(",", $::PKGDIR);

    print "$tmpdir_base\n";
    # Cleanup - should have been removed when last command ran
    #            - but just in case
    system("rm -Rf $tmpdir_base");

    # the tar file may not be in the current dir
    $kittarfile = "$::workdir/$kittarfile";

    if (!(-r $kittarfile)) {
        print "The Kit tar file $kittarfile could not be read. \n";
        return 1;
    }
    $kittarfile = abs_path($kittarfile);

    foreach my $rpmdir (@pkgdirlist) {
        if (!(-d $rpmdir)) {
            print "The package directory $rpmdir could not be read. \n";
            return 1;
        }
    }

    # Create work directory
    if ((!-d $tmpdir_base) && (!mkpath($tmpdir_base))) {
        print "Error creating temporary work directory $tmpdir_base\n";
        return 1;
    }

    print "Extracting tar file $kittarfile. Please wait.\n";

    if (system("cd $tmpdir_base; tar -jxf $kittarfile ")) {
        print "Error extracting tarfile $kittarfile \n";

        # Cleanup
        system("rm -Rf $tmpdir_base");
        return 1;
    }

    my $tmp_kit_conf = `find $tmpdir_base -name kit.conf`;
    chomp($tmp_kit_conf);
    my $tmpdir = dirname($tmp_kit_conf);

    # read in the file
    my $CKF;
    unless (open($CKF, "<", $tmp_kit_conf)) {
        print "The Kit configuration file $tmp_kit_conf could not be read or was not included in the kit tar file. \n";

        # Cleanup
        system("rm -Rf $tmpdir_base");
        return 1;
    }
    my @lines = <$CKF>;
    close $CKF;

    $::PREREQUISITE = 1;
    foreach my $l (@lines) {

        # skip blank and comment lines
        if ($l =~ /^\s*$/ || $l =~ /^\s*#/) {
            next;
        }
        if ($l =~ /prerequisite/) {
            $::PREREQUISITE = 0;
        }
    }

    #
    # check contents of kit.conf to make sure the framework
    #       is compatible with this codes framework
    $::kitframework = &check_framework(\@lines);
    if (!defined($::kitframework)) {
        return 1;
    }

    # if this in not a partial kit then the framework must be 2 or greater
    my $kit_name = basename($kittarfile);
    if ((!($kit_name =~ /NEED_PRODUCT_PKGS/)) && ($::kitframework < 2)) {
        print "This kit cannot be updated.  To update a complete kit the kit framework\n value must be greater than or equal to 2.  You can use the\n\t\'lskit -F <full path tar file>\' \ncommand to check the framework value of the kit.\n";
        return 1;
    }

    ###  Check if this is a new partial kit built with xCAT 2.8.1 or newer
    if (-d "$tmpdir/build_input") {
        system("mv $tmpdir/build_input $tmpdir_base");
        return &NEW_kit_addpkgs($tmpdir_base, $tmpdir);
    }

    ###  OLD KITS BUILT PRIOR TO xCAT 2.8.1
    ###    this code will eventually become obsolete and should be removed
    ###    do not update
    if (defined($::KITVERSION) || defined($::KITRELEASE)) {
        print "kitversion and kitrelease substitution is not supported for this incomplete kit.  Run \"buildkit addpkgs\" without the \"-k|--kitversion\" and \"-r| --kitrelease\" options. \n";
        exit 1;
    }

    my $rpmdir = $::PKGDIR;

    my $ext_filename           = '';
    my $ext_reponames          = '';
    my $non_native_filename    = '';
    my $non_native_kitcompname = '';
    my $non_native_basename    = '';
    my $non_native_kitreponame = '';
    my %create_repodata_list;
    my @new_lines;
    my $section     = '';
    my $kitname     = '';
    my $kitbasename = '';
    my $kitversion  = '';
    my $kitostype   = '';

    foreach my $l (@lines) {

        # skip blank and comment lines
        if ($l =~ /^\s*$/ || $l =~ /^\s*#/) {
            push(@new_lines, $l);
            next;
        }

        # new section?
        if ($l =~ /^\s*(\w+)\s*:/) {
            $section = $1;
            if ($section eq 'EXTERNALPKG') {
                $ext_filename  = '';
                $ext_reponames = '';
                next;
            }
            if ($section eq 'NONNATIVEPKGS') {
                $non_native_filename    = '';
                $non_native_kitcompname = '';
                $non_native_basename    = '';
                $non_native_kitreponame = '';
                next;
            }
            push(@new_lines, $l);
            next;
        }
        if ($l =~ /^\s*(\w+)\s*=\s*(.*)\s*/) {
            my $attr      = $1;
            my $val       = $2;
            my $orig_attr = $attr;
            my $orig_val  = $val;
            $attr =~ s/^\s*//;       # Remove any leading whitespace
            $attr =~ s/\s*$//;       # Remove any trailing whitespace
            $attr =~ tr/A-Z/a-z/;    # Convert to lowercase
            $val =~ s/^\s*//;
            $val =~ s/\s*$//;


            if ($section eq 'kit') {
                if ($attr eq 'basename') { $kitbasename = $val; }
                if ($attr eq 'version')  { $kitversion  = $val; }
                if ($attr eq 'ostype')   { $kitostype   = $val; }
                if (($kitbasename ne '') && ($kitversion ne '') &&
                    ($kitostype ne '')) {
                    $kitname = "$kitbasename-$kitversion-$kitostype";
                }
            }

            if ($section eq 'EXTERNALPKG') {
                if ($attr eq 'filename') {
                    $ext_filename = $val;
                } elsif ($attr eq 'kitreponame') {
                    $ext_reponames = $val;
                } else {
                    next;
                }
                if (($ext_filename ne '') && ($ext_reponames ne '')) {
                    my $fromfile = $rpmdir . "/" . $ext_filename;
                    if (system("ls $fromfile > /dev/null")) {
                        print "The product package file $ext_filename could not be read from the package directory $rpmdir. \n";

                        # Cleanup
                        system("rm -Rf $tmpdir_base");
                        return 1;
                    }
                    foreach my $repo (split(/,/, $ext_reponames)) {
                        my $repodir = $tmpdir . "/repos/" . $repo;
                        if (!-d ($repodir) && (!mkpath($repodir))) {
                            print "Error creating repository directory $repodir\n";

                            # Cleanup
                            system("rm -Rf $tmpdir_base");
                            return 1;
                        }
                        if (system("cp -fp $fromfile $repodir")) {
                            print "Error copying package file $fromfile to $repodir \n";

                            # Cleanup
                            system("rm -Rf $tmpdir_base");
                            return 1;
                        }
                        $create_repodata_list{$repodir} = 1;
                    }
                }
                next;
            }

            if ($section eq 'NONNATIVEPKGS') {
                if ($attr eq 'filename') {
                    $non_native_filename = $val;
                } elsif ($attr eq 'kitcompname') {
                    $non_native_kitcompname = $val;
                } elsif ($attr eq 'basename') {
                    $non_native_basename = $val;
                } elsif ($attr eq 'kitreponame') {
                    $non_native_kitreponame = $val;
                } else {
                    next;
                }
                if (($non_native_filename ne '')
                    && ($non_native_kitcompname ne '')
                    && ($non_native_basename ne '')
                    && ($non_native_kitreponame ne '')) {

                    #find out the useful dir
                    my $tdir       = $tmpdir . "/tmp/";
                    my $source_dir = "$tdir/$non_native_kitcompname";
                    my $spec       = "$tdir/$non_native_kitcompname.spec";
                    if (!-d "$tdir" or !-d "$source_dir") {
                        print "Error open kitcomponent rpm build direcotry $tdir or $tdir/$non_native_kitcompname \n";

                        # Cleanup
                        system("rm -Rf $tmpdir_base");
                        return 1;
                    }

                    #copy the nan_native_pkgs to the source dir
                    foreach my $tepmfilename (split(/,/, $non_native_filename)) {

                        #the $non_native_filename may contain several pkgs, can check and copy at the same time
                        my $fromfile = $rpmdir . "/" . $tepmfilename;
                        if (system("ls $fromfile > /dev/null")) {
                            print "The product package file $non_native_filename could not be read from the package directory $rpmdir. \n";
                            system("rm -Rf $tmpdir_base");
                            return 1;
                        }
                        if (system("cp -fp $fromfile $tdir/$non_native_kitcompname")) {
                            print "Error copying package file $fromfile to $tdir/$non_native_kitcompname \n";

                            # Cleanup
                            system("rm -Rf $tmpdir_base");
                            return 1;
                        }
                    }

                    #for debian/ubuntu
                    my $repodir = $tmpdir . "/repos/" . $non_native_kitreponame;
                    if ($debianflag) {
                        my $debbuildcmd = "cd $source_dir;dpkg-buildpackage $dpkg_flag";
                        if (system($debbuildcmd)) {
                            print "error running debian build cmd for kit component $non_native_basename meta package.\n";
                            return 1;
                        }
                        my @debs = `find $tdir -maxdepth 1 -name "*.deb"`;
                        foreach my $debname (@debs) {
                            chomp($debname);
                            if (system("mv -f $debname $repodir")) {
                                print "Error copying package $debname to build repo directory $repodir. \n";
                                return 1;
                            }
                        }
                    }
                    else {
                        if (!-r "$spec") {
                            print "Error open kitcomponent rpm build spec $tdir/$non_native_kitcompname.spec \n";

                            # Cleanup
                            system("rm -Rf $tmpdir_base");
                            return 1;
                        }
                        my $rpmbuild_dir = $tmpdir . "/rpmbuild";
                        my $cmd          = "rm -Rf $rpmbuild_dir";
                        system($cmd);

                        my $avoiderr = $rpmbuild_dir . "/BUILDROOT/";
                        mkpath($avoiderr);
                        $avoiderr = $rpmbuild_dir . "/BUILD/";
                        mkpath($avoiderr);
                        $avoiderr = $rpmbuild_dir . "/SRPMS/";
                        mkpath($avoiderr);
                        $avoiderr = $rpmbuild_dir . "/RPMS/noarch/";
                        mkpath($avoiderr);

                        unless (open(SF, "<", $spec)) {
                            print "Error attempting to open spec $spec of kitcomponent $non_native_basename. \n";
                            return 1;
                        }

                        mkpath("$rpmbuild_dir/SOURCES");
                        $cmd = "cd $source_dir/..;mv $non_native_kitcompname $non_native_basename; tar -czf $rpmbuild_dir/SOURCES/$non_native_basename.tar.gz $non_native_basename;mv $non_native_basename $non_native_kitcompname;";
                        if (system($cmd)) {
                            print "Error creating tarfile $rpmbuild_dir/SOURCES/$non_native_basename.tar from $source_dir/*";
                            return 1;
                        }
                        my $rpmbuild_cmd = "rpmbuild --define \"_topdir $rpmbuild_dir\" -ba $spec";
                        if (!$::VERBOSE) {
                            $rpmbuild_cmd .= ' --quiet ';
                        }
                        if (system($rpmbuild_cmd)) {
                            print "Error running rpmbuild command for kit component $non_native_basename meta package\n";
                            return 1;
                        }

                        # Copy the built meta rpm to repo
                        my @built_rpms = `find $rpmbuild_dir/RPMS -name "*.rpm"`;
                        foreach my $rpm (@built_rpms) {
                            chomp($rpm);
                            if (system("cp -fp $rpm $repodir")) {
                                print "Error copying rpm $rpm to build repo directory $repodir \n";
                                return 1;
                            }
                        }
                    }
                    $create_repodata_list{$repodir} = 1;
                }
                next;
            }

            push(@new_lines, $l);
        }
    }

    # Re-write kit.conf with EXTERNALPKG and NONNATIVEPKGS sections removed
    my $NCF;
    unless (open($NCF, ">$tmp_kit_conf")) {
        return 1;
    }
    print $NCF @new_lines;
    close($NCF);

    # Clean up RPMBUILD and tmp in kit directory
    my $cmd = "rm -Rf $tmpdir/tmp";
    system("$cmd");
    unless ($debianflag) {
        $cmd = "rm -Rf $tmpdir/rpmbuild";
        system("$cmd");
    }

    # Run createrepo for each updated directory
    foreach my $repo (keys(%create_repodata_list)) {
        my $createrepocmd = '';
        if ($debianflag) {
            $createrepocmd = "cd $repo;dpkg-scanpackages . > Packages";
        }
        else {
            $createrepocmd = "createrepo $repo";
        }
        if (system($createrepocmd )) {
            print "Error running $createrepocmd. \n";

            # Cleanup
            system("rm -Rf $tmpdir_base");
            return 1;
        }
    }

    # Create new tar file in current directory
    my $new_tarfile = $::workdir . '/' . $kitbfname . '.tar.bz2';
    if (system("cd $tmpdir; cd ..; tar -cjhf $new_tarfile $kitname/*")) {
        print "Error building tarfile $new_tarfile \n";

        # Cleanup
        system("rm -Rf $tmpdir_base");
        return 1;
    }
    print "Kit tar file $new_tarfile successfully built \n";

    # Cleanup
    system("rm -Rf $tmpdir_base");
    return 0;
}

#-----------------------------------------------------------------------------

=head3    NEW_kit_addpkgs
	
   buildkit addpkgs

=cut

#-----------------------------------------------------------------------------
sub NEW_kit_addpkgs
{
    # add RPM pkgs to an existing kit tarfile
    my $tmpdir_base = shift;
    my $tmpdir      = shift;

    # - could be list of pkgdir dirs
    my @pkgdirlist = split(",", $::PKGDIR);

    $::NEW_PARTIAL_KIT    = 1;
    $::workdir            = "$tmpdir_base/build_input";
    $::full_buildkit_conf = $::workdir . "/" . $::buildkit_conf;
    $::deploy_dir = $tmpdir_base; #kitname appended by validate_bldkitconf routine

    my $tmp_buildkit_conf = `find $tmpdir_base -name $::buildkit_conf`;

    chomp($tmp_buildkit_conf);
    if ($tmp_buildkit_conf ne $::full_buildkit_conf) {
        print "$tmp_buildkit_conf should match $::full_buildkit_conf  .... error??? \n";
    }

    my $loadrc = &load_bldkitconf($tmp_buildkit_conf);
    if ($loadrc != 0) {
        print "Error reading buildkit config file $tmp_buildkit_conf \n";
        return 1;
    }

    if (defined($::KITVERSION)) {
        $::bldkit_config->{kit}{entries}[0]->{version} = $::KITVERSION;
    }
    if (defined($::KITRELEASE)) {
        $::bldkit_config->{kit}{entries}[0]->{release} = $::KITRELEASE;
    }

    my $chkrc = &validate_bldkitconf();
    if ($chkrc != 0) {
        print "Error validating buildkit config file $tmp_buildkit_conf \n";
        return 1;
    }

    if ($tmpdir ne $::deploy_dir) {
        if (system("mv $tmpdir $::deploy_dir ")) {
            print "Error moving $tmpdir to $::deploy_dir \n";
            return 1;
        }
    }
    $::build_dir    = $::deploy_dir;
    $::base_repodir = "$::deploy_dir/repos";
    my $kitname = $::bldkit_config->{kit}{entries}[0]->{kitname};

    # Handle external packages
    if ($::HAVE_EXTERNAL_PKG) {
        foreach my $kp (@{ $::bldkit_config->{kitpackage}{entries} }) {
            if ($kp->{isexternalpkg} eq 'yes') {
                my $ext_filename  = $kp->{filename};
                my $ext_reponames = $kp->{kitreponame};
                my $files;
                if ($debianflag) {
                    $files = xCAT::BuildKitUtils->find_latest_pkg_deb(\@pkgdirlist, $ext_filename);
                }
                else {
                    $files = xCAT::BuildKitUtils->find_latest_pkg(\@pkgdirlist, $ext_filename);
                }
                if (!defined($files)) {
                    print "Error: The product package file $ext_filename was not found in the package directory(s) @pkgdirlist.\n";

                    # Cleanup
                    system("rm -Rf $tmpdir_base");
                    return 1;
                }

                my @fromfiles = @$files;

                foreach my $repo (split(/,/, $ext_reponames)) {
                    my $repodir = $::base_repodir . "/" . $repo;
                    if (!-d ($repodir) && (!mkpath($repodir))) {
                        print "Error creating repository directory $repodir\n";

                        # Cleanup
                        system("rm -Rf $tmpdir_base");
                        return 1;
                    }

                    foreach my $fromfile (@fromfiles) {
                        if (system("cp -fp $fromfile $repodir")) {
                            print "Error copying package file $fromfile to $repodir \n";

                            # Cleanup
                            system("rm -Rf $tmpdir_base");
                            return 1;
                        }
                    }
                    if ($::VERBOSE) {
                        print "Copied @fromfiles\n to $repodir\n";
                    }
                }
            }
        }
    }

    # Handle non_native_pkgs
    # Comma-separated list of non-native package
    #   paths that will be included as files in this kit
    #   component.
    #  these are not RPMs!
    my $to_source_dir = "$::workdir/source_packages";
    mkpath("$to_source_dir");
    foreach my $kc (@{ $::bldkit_config->{kitcomponent}{entries} }) {
        if ($::NON_NATIVE_PKGS->{ $kc->{kitcompname} }) {
            my @nativefiles;
            foreach my $pkgfile (split(/,/, $kc->{non_native_pkgs})) {
                my ($key, $value) = split /:/, $pkgfile;
                if ("$key" =~ /EXTERNALPKGS/) {

                    #the $non_native_filename may contain several pkgs, can check and copy at the same time
                    foreach my $nnpkg (split(/,/, $value)) {
                        my $found = 0;
                        foreach my $pdir (@pkgdirlist) {
                            my $fromfile = $pdir . "/" . $nnpkg;
                            if (system("ls $fromfile > /dev/null")) {
                                next;
                            } else {
                                $found++;
                                if (system("cp -fp $fromfile $to_source_dir")) {
                                    print "Error copying package file $fromfile to $to_source_dir \n";

                                    # Cleanup
                                    system("rm -Rf $tmpdir_base");
                                    next;
                                } else {
                                    if ($::VERBOSE) {
                                        print "Copied $fromfile to $to_source_dir\n";
                                    }
                                }
                            }
                        }
                        if (!$found) {
                            print "Could not find $nnpkg.\n";
                        }
                    }
                }
            }
        }
    }

    # Turn off external pkg flags and build the kit component meta pkgs
    $::HAVE_EXTERNAL_PKG    = '';
    $::HAVE_NON_NATIVE_PKGS = '';
    $::NON_NATIVE_PKGS      = {};

    foreach my $kc (@{ $::bldkit_config->{kitcomponent}{entries} }) {
        my $rc = 0;
        if ($debianflag) {
            $rc = &build_kitcomp_debian($kc);
        }
        else {
            $rc = &build_kitcomp($kc);
        }
        if ($rc) {
            print "Error building kitcomponent metapackage for $kc->{basename} \n";
            return 1;
        }
    }

    # run createrepo
    foreach my $kr (@{ $::bldkit_config->{kitrepo}{entries} }) {
        my $repodir = "$::base_repodir/$kr->{kitreponame}";
        if (-d $repodir) {
            my $cr_opts = '';
            if (($kr->{osbasename} =~ m/rh|RH|centos|CentOS/) &&
                ($kr->{osmajorversion} eq '5')) {
                $cr_opts = '-s md5';
            }
            my $repocmd = "";
            if ($debianflag) {
                $repocmd = "cd $repodir;dpkg-scanpackages . > Packages";
            }
            else {
                $repocmd = "createrepo $cr_opts $repodir";
            }
            if (system($repocmd )) {
                print "Error building the repository meta-data with the createrepo command \n";
                return 1;
            }
        }
    }


    #When using -k -r, there are useless repodir
    #delete useless repo dir
    my $kitrepodirby = $::base_repodir;
    my $cmdby        = "/bin/ls $kitrepodirby 2>/dev/null";
    my $outputby     = `$cmdby`;
    my @allrepolist  = split(/\n/, $outputby);
    my @dellist;

    foreach my $reponame (@allrepolist)
    {
        my $match = 0;
        foreach my $kr (@{ $::bldkit_config->{kitrepo}{entries} })
        {
            my $repodirname = "$kr->{kitreponame}";

            if (${repodirname} eq ${reponame})
            {
                ${match}++;
            }
        }
        if (${match} == 0)
        {
            push(@dellist, $reponame);
        }
    }

    foreach my $del (@dellist)
    {
        my $delrepodir = $::base_repodir . "/" . $del;
        if (-d $delrepodir)
        {
            my $delcmd = "rm -Rf $delrepodir";
            if (system($delcmd))
            {
                print "Failed to delete useless repo directory \n";
            }
        }
    }


    # Build the full kit tar file
    my $buildtar_rc = &kit_buildtar;

    # clean out the tmp dir
    system("rm -Rf $tmpdir_base");

    if ($buildtar_rc) {
        print "Error building full kit tarfile \n";
        return 1;
    }
    return 0;
}

#-----------------------------------------------------------------------------

=head3    check_framework

    Check the compatible frameworks of the kit to see if it is
	compatible with the running code.

    If one of the compatible frameworks of the kit matches one of the 
        compatible frameworks of the running code then we're good.

    NOTE:  compatible_kitframeworks are the kitframeworks that I can add
        and kit frameworks that I can be added to. 

    Returns:
        0 - kit framework value
        undef - error

    Example:
        my $kitframework = &check_framework(\@lines);

=cut

#-----------------------------------------------------------------------------
sub check_framework
{
    my $lines = shift;

    my @kitconflines = @$lines;

    my $kitbasename;
    my $kitcompat;
    my $kitframework;
    my $section = '';
    foreach my $l (@kitconflines) {

        # skip blank and comment lines
        if ($l =~ /^\s*$/ || $l =~ /^\s*#/) {
            next;
        }

        if ($l =~ /^\s*(\w+)\s*:/) {
            $section = $1;
            next;
        }

        if ($l =~ /^\s*(\w+)\s*=\s*(.*)\s*/) {
            my $attr = $1;
            my $val  = $2;
            $attr =~ s/^\s*//;       # Remove any leading whitespace
            $attr =~ s/\s*$//;       # Remove any trailing whitespace
            $attr =~ tr/A-Z/a-z/;    # Convert to lowercase
            $val =~ s/^\s*//;
            $val =~ s/\s*$//;

            if ($section eq 'kitbuildinfo') {
                if ($attr eq 'compatible_kitframeworks') {
                    $kitcompat = $val;
                }
                if ($attr eq 'kitframework') {
                    $kitframework = $val;
                }
            }
            if ($section eq 'kit') {
                if ($attr eq 'basename') { $kitbasename = $val; }
            }
        }
    }

    if (!$kitcompat) {
        print "Warning: Could not determine the kit compatible framework values for \'$kitbasename\' from the kit.conf file. Continuing for now.\n";
        return 0;
    }

    my @kit_compat_list = split(',', $kitcompat);
    my @my_compat_list  = split(',', $::COMPATIBLE_KITFRAMEWORKS);

    foreach my $myfw (@my_compat_list) {
        chomp $myfw;
        foreach my $kitfw (@kit_compat_list) {
            chomp $kitfw;

            if ($myfw eq $kitfw) {
                return $kitframework;
            }
        }
    }
    print "Error: The kit named \'$kitbasename\' is not compatible with this version of the buildkit command.  \'$kitbasename\' is compatible with \'$kitcompat\' and the buildkit command is compatible with \'$::COMPATIBLE_KITFRAMEWORKS\'\n";
    return undef;
}
