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

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

=head1   buildkit 

 xCAT/PCM Kit Build utilities

    usage: buildkit [-h|-v] [command [-V]]

    This tool is used to create and build a new Kit.

    The options are:
        -h                - Provide usage info.
        -v                - Provide the version info.
        command           - Several commands are supported. See the list below.
        -V                - Verbose mode. Outputs additional debug messages.

    Supported commands:
     create <kit basename> - creates a new Kit with the specified basename
     chkconfig             - checks the Kit build file
     buildrepo <reponame>  - builds the specified Kit package repository 
     buildrepo all         - builds all the Kit package repositories
     listrepo              - lists the Kit package repositories in the Kit
                             build file, and their build status
     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
     cleanall               - equivalent to buildkit cleanrepo all and
                                            buildkit cleantar
     addpkgs -p <packagedir> <kit tarfile>
                           - used by customer to add external product
                             packages when they are not built into the 
                             shipped kit tar file

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 - buildkit is not supported on AIX \n";
        exit 1;
# if AIX - make sure we include perl 5.8.2 in INC path.
#       Needed to find perl dependencies shipped in deps tarball.
#	unshift(@INC, qw(/usr/opt/perl5/lib/5.8.2/aix-thread-multi /usr/opt/perl5/lib/5.8.2 /usr/opt/perl5/lib/site_perl/5.8.2/aix-thread-multi /usr/opt/perl5/lib/site_perl/5.8.2));
}

use lib "$::XCATROOT/lib/perl";
require xCAT::BuildKitUtils;
use Getopt::Long;
use Expect;
use Socket;
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";
$::workdir = cwd();
$::full_buildkit_conf = $::workdir."/".$::buildkit_conf;
$::build_dir = $::workdir."/build";
$::deploy_dir = $::build_dir; #kitname appended by validate_bldkitconf routine
%::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},
              ostype => {
               description=>'The kit OS type (e.g., Linux)',
               value_desc=>'Must be: OS Type String',
               mandatory=>1,
               cp_to_kitconfig=>1},
              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} },
    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=>1,
               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=>1,
               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,
                'p|pkgdir=s'   => \$::PKGDIR,
    )
  )
{
    &usage;
    exit(1);
}

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

# display the version statement if -v or --version is specified
if ($::VERSION)
{
    print "The version option is not supported for this command.  Query the xCAT-buildkit rpm for version information. \n"; 
    exit 0;
}

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

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

while ($arg) {
    my $command = $arg;
    $command =~ tr/A-Z/a-z/;   # convert to lowercase
    if ( $command eq 'create' ) { 
        $::KIT_CREATE=shift(@ARGV); 
        if ( ! $::KIT_CREATE ) {
          print "kit basename not specified for 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 "kit package repository name 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:  <kit tarfile>  must be specified with \'buildkit addpkgs\' \n";
            &usage;
            exit (1); 
        }
        if (!($::PKGDIR)){
            print "Missing option:  -p <pkgdir> must be specified with \'buildkit addpkgs\' \n";
            &usage;
            exit (1); 
        }
    } else {
        print "buildkit command $arg 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|-v] [command [-V]]                                    
                                                                              
    This tool is used to create and build a new Kit.                          
                                                                              
    The options are:                                                          
        -h         - Provide usage info.                                      
        -v         - Provide the version info.                                
        command    - Several commands are supported. See the list below.      
        -V         - Verbose mode. Outputs additional debug messages.         
                                                                              
    Supported commands:                                                       
     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=$::workdir."/$kitname";
    if ( -d $kitdir ) {
        print "Another directory alredy exists with the name $kitname in the current working directory.  Not able to create new Kit directory $kitdir. \n";
        exit 1;
    }
    if ( ! mkdir($kitdir) ) {
       print "Error creating Kit directory $kitdir.  Verify that the current user has write privileges in the current working 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";
}

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

=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;
    $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; }
        }
    }

}

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

=head3    kit_buildrepo1
	
          

=cut

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

sub kit_buildrepo1

{

    my $rc = 0;
    my $repoid = shift;
    $repoid =~ s/\s+//g;
    my $repodir = $::build_dir."/kit_repodir";
    my $srcdir =  $::workdir."/source_packages/";
    my $basedir = $repodir;
    
    # find the repo
    my $found = 0;
    foreach my $kr (@{$::bldkit_config->{kitrepo}{entries}}) {
        if ( $kr->{kitrepoid} eq $repoid ) {
            $found = 1;
            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;
            }
        }
              

        if ($::VERBOSE) { print "building kitpackage $kp->{filename} \n";}
        # determine build method
        if ($kp->{isexternalpkg} eq 'yes') { next; }
        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 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 metapackage for $kc->{basename} \n";}
            if (&build_kitcomp_debian($kc)) {
                print "Error building kitcomponent metapackage for $kc->{basename} \n";
                return 1;
            }
        }
        if ( system("dpkg-scanpackages $repodir > $repodir/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
        if ( system("createrepo $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') ) { 
          if ( system("rm -Rf $::build_dir/kit_repodir/* ") ) {
              print "Error removing contents of $::build_dir/kit_repodir \n";
              return 1;
          } else {
              print "Contents of $::build_dir/kit_repodir has been successfully removed. \n";
          }
    } else {
        foreach my $kr (@{$::bldkit_config->{kitrepo}{entries}}) {
          if ($repoid eq $kr->{kitrepoid}) {
            my $repodir = $::build_dir.'/kit_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";
            }
            last; 
          }
        }
    }
    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 (&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";
    }

    #Copy rpm spec to kit in case kitcomponent meta rpm is not built because of external non_native_pkgs


    # 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*$//;
    }
    my $tarfile = $::build_dir."/".$kitfilename.$extpkgs.".tar.bz2";
    if ( system("cd $::build_dir; tar -cjhf $tarfile $kitname/*") ) {
         print "Error building tarfile $tarfile \n";
         return 1;
    }
    print "Kit tar file $tarfile successfully built \n";
    
}

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

=head3    kit_cleantar
	
   buildkit cleantar

=cut

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

sub kit_cleantar

{

    my $kitfilename = $::bldkit_config->{kit}{entries}[0]->{kitname};
    if ( defined($::bldkit_config->{kit}{entries}[0]->{kittarfilename}) ) {
        $kitfilename = $::bldkit_config->{kit}{entries}[0]->{kittarfilename};
        $kitfilename =~ s/tar\.bz2\s*$//;
    }
    my $tarfile = `find $::build_dir -name $kitfilename.*tar.bz2`;
    chomp ($tarfile);
    if ( -r $tarfile ) {
        if ( system("rm -f $tarfile ") ) {
            print "Error removing kit tar file $tarfile \n";
        } else {
            print "Kit tar file $tarfile has been successfully removed \n";
        }
    }
    if ( -d $::deploy_dir ) {
        if ( system("rm -Rf $::deploy_dir ") ) {
            print "Error removing contents of $::deploy_dir \n";
        } else {
            print "All $::deploy_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");
    }
    

}


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

=head3    kit_cleanall
	
   buildkit cleanall

=cut

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

sub kit_cleanall

{

    print "running buildkit cleanall... \n";
    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");
    }

}

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

=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`;
    my $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/;
        }
    }

    # 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} ) ) {
                $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\" mandadory 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};
    $full_kitname .= '-'.$::bldkit_config->{kit}{entries}[0]->{ostype};
    $::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;
                 }
            }
          }
        }
    }
   
    # 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 = $full_kitname;
        $reponame .= '_'.$kr->{osbasename};
        $reponame .= '-'.$kr->{osmajorversion};
        if (defined($kr->{osminorversion})){
          $reponame .= '.'.$kr->{osminorversion};
        }
        $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 contaion 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}) ) {
            $compname .= '.'.$repo{osminorversion};
        }
        $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;
          }
        }
      }
    }
   
    #  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/^,//;
      # 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 $repo = 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';
    }
  #  $pkgname .= '-'.$repo->{osmajorversion};
  #  if (defined($repo->{osminorversion})) {
  #    $pkgname .= '.'.$repo->{osminorversion};
  #  }
  #  $pkgname .= '-'.$repo->{osarch};
  #  $pkgname .= '.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 = $::build_dir."/kit_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;
    }
 
    foreach my $pkg (@{$repo->{packages}}){
        foreach my $kc (@{$::bldkit_config->{kitcomponent}{entries}}) {
            if ($repo->{kitrepoid} eq $kc->{kitrepoid}) {
                my $kitpkgname = comppkgname($kc);
                if ($kitpkgname ne $pkg) {
                    next;
                }
                if ($kc->{non_native_pkgs} =~ /EXTERNALPKGS/) {
                    $::NON_NATIVE_PKG->{$kc->{kitcompname}} = 1;
                    last;
                }

                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);
    $osinfo =~ s/\,//;
    my $repo_osinfo = "$repo->{osbasename}$repo->{osmajorversion}";
    if (defined($repo->{osminorversion})){
        $repo_osinfo .= ".$repo->{osminorversion}";
    }
    $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 ( ($repo->{osminorversion} 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}";

    # find the kitrepo hash for this component
    foreach my $kr (@{$::bldkit_config->{kitrepo}{entries}}) {
        if ($comp->{kitrepoid} eq $kr->{kitrepoid}) { 
            %repo = %{$kr}; 
            last;                    
        }
    }
 
    # Create spec file for this kit component
    if ( &gen_kitcomp_spec($comp,\%repo) ) { 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 $kcmetaname = comppkgname($comp);
 
    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";

        if ($comp->{non_native_pkgs} =~ /EXTERNALPKGS/) {
            $::NON_NATIVE_PKGS->{$comp->{kitcompname}}{$kcmetaname} = 1;
        }
        foreach my $pkgfile (split(/,/, $comp->{non_native_pkgs})) {
            my $pkg_file;
            my ($key,$value) = split /:/,$pkgfile;
            if ("$key" =~ /EXTERNALPKGS/) {
                next;
            } 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;
            }
        }
        if ( !$::NON_NATIVE_PKGS->{$comp->{kitcompname}}{$kcmetaname} ) {
            $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;
            }
        }
    }
    if (!$::VERBOSE) {
        $rpmbuild_cmd .= ' --quiet ';
    }
    if ( !$::NON_NATIVE_PKGS->{$comp->{kitcompname}}{$kcmetaname} ) {
        if ( system($rpmbuild_cmd) ) {
            print "Error running rpmbuild command for kit component $comp->{kitcompname} meta package\n";
            return 1;
        }
        my $repodir = $::build_dir."/kit_repodir/".$repo{kitreponame};
        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    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 $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 (defined($comp->{preinstall})) {
        $prescript = &load_script("$scriptdir$comp->{preinstall}"); 
        $prescript = "if [ \"\$1\" = \"1\" ] ; then\n" . $prescript . "\nfi";}
    if (defined($comp->{postinstall})) {
        $postscript = &load_script("$scriptdir$comp->{postinstall}"); 
        $postscript = "if [ \"\$1\" = \"1\" ] ; then\n" . $postscript . "\nfi"; }
    if (defined($comp->{preupgrade})) {
        $preupscript = &load_script("$scriptdir$comp->{preupgrade}");
        $preupscript = "if [ \"\$1\" = \"2\" ] ; then\n" . $preupscript . "\nfi";}
    if (defined($comp->{postupgrade})) {
        $postupscript = &load_script("$scriptdir$comp->{postupgrade}");
        $postupscript = "if [ \"\$1\" = \"2\" ] ; then\n" . $postupscript . "\nfi";}
    if (defined($comp->{preuninstall})) {
        $preunscript = &load_script("$scriptdir$comp->{preuninstall}"); }
    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";
    }


    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_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/;
    }

    # Write the generated spec file 
    my $joined_lines = join("\n",@lines);
    @lines = split(/\\n/,$joined_lines);
    mkpath($tmpdir);
    my $NSF;
    unless ( open( $NSF, ">$tmpdir/$comp->{kitcompname}.spec" ) ) {
        return 1;
    }
    if ($::VERBOSE) {
        print "Created kitcomponent spec file $tmpdir/$comp->{basename}.spec \n";
    }
    print $NSF @lines;
    close($NSF);

    return 0;
}

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

=head3   build_kitcomp_debian 



=cut

#-----------------------------------------------------------------------------
sub build_kitcomp_debian{
    my $comp = shift;
    my %repo;
    my $debbuilddir = $::workdir."/debbuild/".$comp->{kitcompname};
    
    # 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);

    #Create debian directory for this kit component
    if ( &gen_kitcomp_debdir($comp,\%repo) ) { return 1; }

    my $kcmetaname = comppkgname($comp);
    my $compversion = $comp->{version} . "-" . $comp->{release};
    my $buildstring = "Kit component build package.";
    my $debianbuildcmd = "cd $debbuilddir;dch -v $compversion -b -c debian/changelog $buildstring;dpkg-buildpackage -uc -us";
    if ( !$::NON_NATIVE_PKGS->{$comp->{kitcompname}}{$kcmetaname} ) {
        if ( system($debianbuildcmd) ) {
            print "Error running \"dpkg-buildpackage -uc -us\" command for kit component $comp->{kitcompname} meta package\n";
            return 1;
        }
        my $repodir = $::build_dir."/kit_repodir/".$repo{kitreponame};
        my @builtdebs = `find $::workdir/debbuild -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



=cut

#-----------------------------------------------------------------------------
sub gen_kitcomp_debdir{
    my $comp = shift;
    my $repo = 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 (defined($comp->{preinstall})) {
        $prescript = &load_script("$scriptdir$comp->{preinstall}"); 
    }
    if (defined($comp->{postinstall})) {
        $postscript = &load_script("$scriptdir$comp->{postinstall}"); 
    }
    if (defined($comp->{preupgrade})) {
        $preupscript = &load_script("$scriptdir$comp->{preupgrade}");
    }
    if (defined($comp->{postupgrade})) {
        $postupscript = &load_script("$scriptdir$comp->{postupgrade}");
    }
    if (defined($comp->{preuninstall})) {
        $preunscript = &load_script("$scriptdir$comp->{preuninstall}"); 
    }
    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";
    }

    #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 debian template file $file.\n";
            close(DH);
            return 1;
        }

        if ($::VERBOSE){
            print "Reading the xCAT Kit Component debian template file $file. \n";
        }
        my @lines = <FH>;
        close(FH);
        for(@lines) {
            chomp;
            s/<<<INSERT_kitcomponent_basename_HERE>>>/$comp->{basename}/;
            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_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 build file under debian dir $file";
        }
        print FH @lines;
        close(FH);
    }
    closedir(DH);
    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('\n', @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};
          }
          if (( $::buildkit_def{$s}{$a}->{cp_to_kitconfig} eq '2' ) &&
              ( defined ($se->{$a}) ) ) {
            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)) ) {
              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};
        }
        $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 ($kc->{non_native_pkgs} =~ /EXTERNALPKGS/) {
        foreach my $pkgfile (split(/,/, $kc->{non_native_pkgs})) {
          my ($key,$value) = split /:/,$pkgfile;
          if ("$key" =~ /EXTERNALPKGS/) {
            $::HAVE_NON_NATIVE_PKGS = 1;
            my %current_entry;
            $current_entry{filename} = $value;
            $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++] = "# ".localtime()."\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

=cut

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

sub cp_to_builddir

{

    my $type = shift;
    my $files = shift;
    my $from_dir = shift;
    my $prefix = 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;
        if ( system("cp -fp $from_file $to_file") ) {
            # non-zero return from system call
            print "Error copying file $from_file to build directory $other_files \n";
            return;
         }        
        $copied_files .= ",$to_file_base";
 
        if ($type eq 'postbootscripts') {
            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 $to_plugin = $plugin_dir."/".$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;} 
    }

    # Copy the kitcomponent meta rpm spec if there is external non_native_pkgs.
    foreach my $comp (keys %{$::NON_NATIVE_PKG}) {
        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/tmp/$comp.spec $::deploy_dir/tmp/$comp.spec";
        if ( system("$cmd") ) {
            print "Error copying kitcomponent spec $::workdir/tmp/$kitrepo-$comp.spec to build directory $::deploy_dir \n";
            return 1;
        }
        $cmd = "cp -fRp $::workdir/tmp/$comp $::deploy_dir/tmp/$comp";
        if ( system("$cmd") ) {
            print "Error copying kitcomponent meta rpm build file $::workdir/tmp/$kitrepo-$comp to build directory $::deploy_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};

    # 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;
    }

    # 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 $rpmdir = $::PKGDIR;
    my $kitbfname = basename($kittarfile);
    $kitbfname =~ s/.tar.bz2$//;
    $kitbfname =~ s/.NEED_PRODUCT_PKGS$//;
    my $tmpdir = "/tmp/buildkit_workdir/$kitbfname";

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

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

    if ( system("cd $tmpdir; tar -jxf $kittarfile ") ) {
         print "Error extracting tarfile $kittarfile \n";
         # Cleanup
         system ("rm -Rf /tmp/buildkit_workdir");
         return 1;
    }

    my $tmp_kit_conf = `find $tmpdir -name kit.conf`;
    chomp($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 /tmp/buildkit_workdir");
        return 1;
    }
    my @lines = <$CKF>;
    close $CKF;

    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 /tmp/buildkit_workdir");
                    return 1;
                  }
                  foreach my $repo (split(/,/, $ext_reponames)) {
                    my $repodir = $tmpdir."/".$kitname."/repos/".$repo;
                    if ( ! -d ($repodir) && (! mkpath($repodir)) ) {
                      print "Error creating repository directory $repodir\n";
                      # Cleanup
                      system ("rm -Rf /tmp/buildkit_workdir");
                      return 1;
                    }
                    if (system("cp -fp $fromfile $repodir")) {
                      print "Error copying package file $fromfile to $repodir \n";
                      # Cleanup
                      system ("rm -Rf /tmp/buildkit_workdir");
                      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 '')) {
                my $fromfile = $rpmdir."/".$non_native_filename;
                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 /tmp/buildkit_workdir");
                  return 1;
                }

                my $tdir = $tmpdir."/".$kitname."/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 /tmp/buildkit_workdir");
                  return 1;
                }

                if (!-r "$spec") {
                  print "Error open kitcomponent rpm build spec $tdir/$non_native_kitcompname.spec \n";
                  # Cleanup
                  system ("rm -Rf /tmp/buildkit_workdir");
                  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 /tmp/buildkit_workdir");
                  return 1;
                }
                my $rpmbuild_dir = $tmpdir."/".$kitname."/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 $repodir = $tmpdir."/".$kitname."/repos/".$non_native_kitreponame;
                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/$kitname/tmp";
    system("$cmd");
    $cmd = "rm -Rf $tmpdir/$kitname/rpmbuild";
    system("$cmd");

    # Run createrepo for each updated directory
    foreach my $repo (keys(%create_repodata_list)) {
      if (system("createrepo $repo")) {
        print "Error running createrpo command for $repo \n";
        # Cleanup
        system ("rm -Rf /tmp/buildkit_workdir");
        return 1;
      }
    }

    # Create new tar file in current directory
    my $new_tarfile = $::workdir.'/'.$kitbfname.'.tar.bz2';
    if ( system("cd $tmpdir; tar -cjhf $new_tarfile $kitname/*") ) {
         print "Error building tarfile $new_tarfile \n";
         # Cleanup
         system ("rm -Rf /tmp/buildkit_workdir");
         return 1;
    }
    print "Kit tar file $new_tarfile successfully built \n";
  
    # Cleanup
    system ("rm -Rf /tmp/buildkit_workdir");

}



