[leaf-commits] src/bering-uclibc4/buildtool buildimage.pl, NONE, 1.1

david M brooke <[email protected]>
Newsgroups gmane.linux.leaf.cvs
Message-ID <[email protected]>
Update of /cvsroot/leaf/src/bering-uclibc4/buildtool
In directory sfp-cvsdas-2.v30.ch3.sourceforge.com:/tmp/cvs-serv11477

Added Files:
	buildimage.pl 
Log Message:
Initial commit of buildimage.pl

--- NEW FILE: buildimage.pl ---
#!/usr/bin/perl
#
#  Script to create a Bering-uClibc disk image from existing packages
#
#  Copyright (C) 2010 David M Brooke, [email protected]
#  Based on buildpacket.pl by Martin Hejl
#
#  This software is distributed under the GNU General Public Licence,
#  please see the file COPYING
#
#  $Header: /cvsroot/leaf/src/bering-uclibc4/buildtool/buildimage.pl,v 1.1 2010/09/25 19:52:54 davidmbrooke Exp $
#
use strict;
use warnings;
use Config::General;
use Getopt::Long;
use Date::Format;
use File::Spec;
use File::Temp;
use File::Copy;
use Carp;

my %configHash = ( );
my $label;
my $image;
my $verbose;
my $debug;
my $Usage =
qq{Usage: $0 --image=ImgDir --relver=VersionLabel [--verbose]
   image    Parent directory for buildimage.cfg, under buildtool/image
            e.g. Bering-uClibc-isolinux-std
   relver   String to append to image name to show release version
            e.g. 4.0beta1
   verbose  [Optional] Report progress during execution
};

sub createTempDir( );
sub cleanTempDir( );
sub system_exec( $;$$ );
sub createDirUnlessItExists( $ );
sub copyFilesToTempDir( $$ );
sub copyFilesWithSearchAndReplace( $$@ );


# Process command line arguments
GetOptions( "verbose!" => \$verbose,
	    "image=s"  => \$image,
	    "relver=s"  => \$label,
	    "debug!"   => \$debug ) or die $Usage;

die $Usage unless defined( $image );
die $Usage unless defined( $label );
$configHash{ '{VERSION}' } = $label;

my $baseDir = File::Spec->rel2abs( File::Basename::dirname( $0 ) );

# Fetch the buildtool config
my $btConfig = new Config::General(
    "-ConfigFile" => File::Spec->catfile(
        $baseDir,
	'conf',
	'buildtool.conf' ),
    "-LowerCaseNames" => 1,
    "-ExtendedAccess" => 1 );

# Fetch the global config (e.g. conf/sources.cfg)
my $glConfig = new Config::General(
    "-ConfigFile" => File::Spec->catfile(
        $baseDir,
        $btConfig->value( 'globalconffile' ) ),
    "-LowerCaseNames" => 1,
    "-ExtendedAccess" => 1 );

# Fetch the image specific config
my $imConfig = new Config::General(
    "-ConfigFile" => File::Spec->catfile(
        $baseDir,
        $btConfig->value( 'image_dir' ),
	$image,
	$btConfig->value( 'buildimage_config' ) ),
    "-LowerCaseNames" => 1,
    "-ExtendedAccess" => 1 );

my $sourceDir = File::Spec->canonpath(
    File::Spec->catdir(
        $baseDir,
	$btConfig->value('source_dir') ) );

my $stagingDir = File::Spec->canonpath(
    File::Spec->catdir(
        $baseDir,
	$btConfig->value('staging_dir') ) );

# Generate date label
$configHash{ '{DATE}' } = time2str( "%Y-%m-%d", time );
print "Build Date is:\t\t$configHash{ '{DATE}' }\n" if $verbose;

# Extract kernel version from source tree
my $kver;
open( FH, "<".$sourceDir."/linux/linux/.config" );
while ( <FH> )
{ if ( /version: (.*)/ ) { $kver = $1; last; } }
close( FH );
print "Kernel Version is:\t$kver\n" if $verbose;

# Create directory to hold image contents
my $tmpDir = createTempDir( );

# Always create full modules.tgz
print "Creating modules.tgz...\n" if $verbose;
system_exec( "cd $stagingDir/lib/modules/$kver ; tar -czf $tmpDir/modules.tgz * --exclude=build --exclude=source", "Error building modules.tgz" );

## Extract name of image to build from config file
#my @names = keys( %{ $imConfig->value( 'image' ) } );
#if ( scalar @names < 1 || scalar @names > 1 )
#{
    #die "Exactly one Image name required in config file";
#}
#my $imgName = $names[0];

# Extract name and type of image to build from config file
my $imageStruc = $imConfig->value( 'image' );
my $imgName = $imageStruc->{ 'imagename' };
die "ImageName is not specified in config file" unless defined $imgName;
print "Image name:\t\t$imgName\n" if $verbose;
my $imgType = $imageStruc->{ 'imagetype' };
die "ImageType is not specified in config file" unless defined $imgType;
print "Image type:\t\t$imgType\n" if $verbose;

# Extract configuration variables from config file
# Populate global configHash with Search-And-Replace Key:Value
while ( my ( $key, $value ) = each( %{ $imageStruc->{ 'config' } } ) )
{
    my $ucKey = $key;
    $ucKey =~ tr/[a-z]/[A-Z]/;
    $configHash{ $ucKey } = $value;
}

# Process <Contents> block from config file
my $imageContents = $imageStruc->{ 'contents' };

# Should be exactly one <Kernel> block
my $imageKernel = $imageContents->{ 'kernel' };
die "<Kernel> entry not present in config file" unless defined $imageKernel;
copyFilesToTempDir(
    $imageKernel->{ 'source' },
    $imageKernel->{ 'filename' } );
# Capture path to kernel to use in sys/isolinux.cfg
$configHash{ '{KERNEL}' } = "/".$imageKernel->{ 'filename' } ;

# Should be multiple <File> blocks
# Don't even bother coping with the case of a single <File> block
foreach my $fileStruc ( @{ $imageContents->{ 'file' } } )
{
    print "DEBUG - Processing block for <File> ",$fileStruc->{ 'filename' },"\n" if $debug;
    # Do we need to Search-And-Replace strings in this file? 
    if ( defined( $fileStruc->{ 'searchandreplace' } ) )
    {
    	# Yes; need to Search-And-Replace for this file entry
	# We have an ARRAY if there is >1 SearchAndReplace entry for this file
	if ( ref( $fileStruc->{ 'searchandreplace' } ) eq 'ARRAY' )
	{
	    print "DEBUG - Processing multiple S&R strings\n" if $debug;
	    my @sAndR = @{ $fileStruc->{ 'searchandreplace' } };
            copyFilesWithSearchAndReplace( 
	        $fileStruc->{ 'source' },
		$fileStruc->{ 'filename' },
		@sAndR );
	}
	# We have a SCALAR if there is 1 SearchAndReplace entry for this file
	else
	{
	    print "DEBUG - Processing single S&R strings\n" if $debug;
	    my @sAndR = ( $fileStruc->{ 'searchandreplace' } );
	    copyFilesWithSearchAndReplace( 
		$fileStruc->{ 'source' },
		$fileStruc->{ 'filename' },
		@sAndR );
	}
    }
    else
    {
	# No; no need to Search-And-Replace for this entry - just copy file
	copyFilesToTempDir(
	        $fileStruc->{ 'source' },
		$fileStruc->{ 'filename' } );
    }
}

# Complete the processing depending on the image type specified
if ( $imgType eq "syslinux" )
{
    print "Performing SYSLINUX processing...\n" if $verbose;
    my $fileName = File::Spec->catfile(
	$baseDir,
        $btConfig->value( 'image_dir' ),
	$image,
	$imgName."_".$label.".tar.gz" );
    system_exec( "cd $tmpDir ; tar -czf $fileName .", "Error creating image tarfile: $!" );
}
elsif ( $imgType eq "isolinux" )
{
    print "Performing ISOLINUX processing...\n" if $verbose;
    my $fileName = File::Spec->catfile(
	$baseDir,
        $btConfig->value( 'image_dir' ),
	$image,
	$imgName."_".$label.".iso" );

    # Summary of mkisofs arguments:
    #  -o		Name of generated image file
    #  -v		Verbose messages
    #  -b		El Torito boot image filename
    #  -no-emul-boot	CD-ROM is not a disk image; do not emulate a disk
    #  -c             	Name of boot catalog  file to be generated by mkisofs
    #  -boot-load-size	Number of 512-byte sectors to load in no-emul mode
    #  -boot-info-table	Include a table of the image file layout
    #  -l		Allow long (31-character) filenames
    #  -R		Use Rock Ridge extensions
    #  -r		Use standard values for file ownership and permissions
    #  .		Create image of current directory
    system_exec( "cd $tmpDir ; mkisofs -o $fileName -v -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -l -R -r .", "Error running mkisofs: $!" );

}
else
{
    die "Unsupported image type $imgType\n";
}

# Tidyup
cleanTempDir( );

# End of main


sub createTempDir( )
{
    my $tempDIR;
    eval
    {
        $tempDIR = File::Temp::tempdir(
	    'BUILDIMAGE_STAGING_XXXX',
	    'TMPDIR' => 1 );
    };
    if ( $@ ne '' )
    {
        confess( "Unable to create temporary directory. $@" );
    }
    print "Temporary directory:\t$tempDIR\n" if $verbose;
    return( $tempDIR );
}

sub cleanTempDir( )
{
    print "Cleaning up dir $tmpDir\n" if $verbose;
    confess( "Temp dir undefined" ) unless defined( $tmpDir );
    confess( "Will not delete root dir" ) if File::Spec->canonpath( $tmpDir ) eq File::Spec->rootdir( );
    system( "rm -rf $tmpDir" );
    rmdir( $tmpDir );
}

sub system_exec( $;$$ )
{
    my ( $command, $error_message, $no_cleanup ) = @_;
    $no_cleanup = 0 unless defined( $no_cleanup );
    $error_message = "$command failed " unless defined( $error_message );
    print "Executing $command\n" if $verbose;
    my $retVal = system( $command );
    if ( $retVal>>8 != 0 )
    { 
        cleanTempDir( ) unless $no_cleanup;
	confess( "$error_message $!" );
    }
}

sub createDirUnlessItExists( $ )
{
    my ( $path ) = @_;
    while ( ! ( -e $path ) )
    {
	my @dirs = File::Spec->splitdir( $path );
	my $dirToCreate = "";
	foreach my $dir ( @dirs )
	{
	    $dirToCreate = File::Spec->catdir( $dirToCreate, $dir );
	    if ( ! ( -e $dirToCreate ) )
	    {
	        print "Creating directory $dirToCreate\n" if $verbose;
		mkdir( $dirToCreate ) or confess( "creating dir " . $path . " failed. $!" );
	    }
	}
    }
}

sub copyFilesToTempDir( $$ )
{
    my ( $source, $target ) = @_;
    my $absSource = File::Spec->catdir( $baseDir, $source );
    my $absTarget = File::Spec->catdir( $tmpDir, $target );
    # Check for '*' in Source
    if ( $absSource =~ /\*/ )
    {
	# Source contains '*' so Target _must_ be a directory
	createDirUnlessItExists( $absTarget );
	system_exec( "cp -r $absSource $absTarget", "Failed to copy files: $!" );
    }
    else
    {
	# Source does not contain '*' so Target is a file
	# Might still need to create the directory for that file
	my $destDir = File::Basename::dirname( $absTarget );
	createDirUnlessItExists( $destDir );
	system_exec( "cp -r $absSource $absTarget", "Failed to copy files: $!" );
    }
}

sub copyFilesWithSearchAndReplace( $$@ )
{
    my ( $source, $target, @sAndR ) = @_;
    my $absSource = File::Spec->catdir( $baseDir, $source );
    my $absTarget = File::Spec->catdir( $tmpDir, $target );
    # Check for '*' in Source
    if ( $absSource =~ /\*/ )
    {
	# Source contains '*' so Target _must_ be a directory
	createDirUnlessItExists( $absTarget );
	die "Copying multiple files with SearchAndReplace is not currently supported. Sorry.";
    }
    else
    {
	# Source does not contain '*' so Target is a file
	# Might still need to create the directory for that file
	my $destDir = File::Basename::dirname( $absTarget );
	createDirUnlessItExists( $destDir );
        open( IFH, "<".$absSource ) or confess( "Error: $!" );
        open( OFH, ">".$absTarget ) or confess( "Error: $!" );
        while ( <IFH> )
	{
	    foreach my $string ( @sAndR )
	    {
	        s/$string/$configHash{ $string }/;
	    }
	    print OFH;
	}
        close( OFH );
        close( IFH );
    }
}


exit;

__END__

=pod

=head1 NAME

buildimage.pl - create a Bering-uClibc disk image

=head1 SYNOPSIS

B<buildimage.pl> --image=ImgDir --relver=VersionLabel [--verbose]

   image    Parent directory for buildimage.cfg, under buildtool/image
            e.g. Bering-uClibc-isolinux-std
   relver   String to append to image name to show release version
            e.g. 4.0beta1
   verbose  [Optional] Report progress during execution

=head1 DESCRIPTION

B<buildimage.pl> creates a Bering-uClibc disk image based on parameter
settings defined in a configuration file (buildimage.cfg) located within a
sub-directory of buildtool/image. The name of this sub-directory is specified
with the "--image" command-line argument.

The disk image can be for SYSLINUX (suitable for writing to a flash drive)
or can use ISOLINUX. The choice between these is specified in buildimage.cfg.

For SYSLINUX, the "image" is a .tar.gz file which needs to be extracted
onto suitably prepared media.
For ISOLINUX the "image" is a .iso file which can be burned to a CD-R.

Note that the name of the image file is based on the ImageName field in the
configuration file which may be different from the --image argument.

=head1 SEE ALSO

http://sourceforge.net/apps/mediawiki/leaf/index.php?title=Bering-uClibc_4.x_-_Developer_Guide_-_Building_an_Image

=cut

# vi: set ai sw=4 wm=5 fo=cql:


------------------------------------------------------------------------------
Start uncovering the many advantages of virtual appliances
and start using them to simplify application deployment and
accelerate your shift to cloud computing.
http://p.sf.net/sfu/novell-sfdev2dev
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.