Rev 2429 | Rev 5709 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
######################################################################### Copyright (C) 1998-2012 Vix Technology, All rights reserved## Module name : gen_cots.pl# Module type : Makefile system# Compiler(s) : Perl# Environment(s): jats## Description : Create a buildable package based on a COTS package# or other package image.## Designed to simplify the process of version controlling# handcrafted packages that have been dropped into dpkg_archive## Supports clearcase and subversion## Usage: See Embedded documentation below# jats gen_cots ...##......................................................................#require 5.006_001;use Cwd;use strict;use warnings;use JatsError;use FileUtils;use File::Basename;use File::Find;use File::Copy;use File::Path;use JatsSvn qw(:All);use JatsSystem;use JatsProperties;use File::Temp qw/ tempfile tempdir /;use Pod::Usage; # required for help supportuse Getopt::Long;use Cwd;#-------------------------------------------------------------------------------# Global variables#my $VERSION = "1.0.0"; # Update thismy $GBE_DPKG = $ENV{ GBE_DPKG };my %subdirs;my %files;my $DESTDIR = 'src'; # 'src'my $last_result;my @error_list;my $vob_dir = '';my $vob_name = '';my $src_dir;my $svnSession;my $svnPackageName;my $svnPackageExists;my $svnRmRef = '';## Options#my $opt_debug = $ENV{'GBE_DEBUG'}; # Allow global debugmy $opt_verbose = $ENV{'GBE_VERBOSE'}; # Allow global verbosemy $opt_help = 0;my $opt_manual = 0;my $opt_label;my $opt_vob;my $opt_test;my $opt_keep;my $opt_subdir;my $opt_image;my $opt_repository;#-------------------------------------------------------------------------------# Function : Mainline Entry Point## Description : Parse Options# Perform Sanity Checks# Perform operation# Cleanup## Inputs : Command Line arguments#my $result = GetOptions ("help+" => \$opt_help, # flag, multiple use allowed"manual" => \$opt_manual, # flag"verbose:+" => \$opt_verbose, # flag, multiple use allowed"label=s" => \$opt_label, # String"vob=s" => \$opt_vob, # String"test" => \$opt_test, # Flag"keep" => \$opt_keep, # Flag"subdir=s" => \$opt_subdir, # string"image=s" => \$opt_image, # string"repository=s" => \$opt_repository, # string);## UPDATE THE DOCUMENTATION AT THE END OF THIS FILE !!!### Process help and manual options#pod2usage(-verbose => 0, -message => "Version: $VERSION") if ($opt_help == 1 || ! $result);pod2usage(-verbose => 1) if ($opt_help == 2 );pod2usage(-verbose => 2) if ($opt_manual || ($opt_help > 2));pod2usage(-verbose => 0, -message => "Version: $VERSION") if ( $#ARGV < 0 );## Configure the error reporting process now that we have the user options#ErrorConfig( 'name' =>'gen_cots','verbose' => $opt_verbose,);## Init the file uitilites#InitFileUtils();## Sanity test user options#Error ("Can only specify either -vob or -repository.") if ( $opt_vob && $opt_repository );Error ("ClearCase mode only supported on WINDOWS, not $::ScmHost") if ( $opt_vob && $::ScmHost ne 'WIN' );Error ("No DPK_ARCHIVE") unless ( $GBE_DPKG );Error ("Must specify -vob, -repository or -keep") unless ( $opt_vob || $opt_repository || $opt_keep);Error ("Need two arguments: package and version") unless ( $#ARGV eq 1 );## Determine base image# Either from dpkg_archive or user image#if ( $opt_image ){$src_dir = AbsPath($opt_image);Error("Image directory is not present: $src_dir") unless ( -d $src_dir );}else{## Ensure that the package source in dpkg_archive can be found#$src_dir = "$GBE_DPKG/$ARGV[0]/$ARGV[1]";Message ( "Testing $src_dir" );Error ("Package not found: $src_dir" ) unless ( -d $src_dir );Message ("Found source package");}## Determine target path with the VOB/Repository# Will be taken from the package name, unless provided#$opt_subdir = $ARGV[0] unless ( $opt_subdir );$opt_subdir =~ tr~\\/~/~s;## Create a TEMP working area# Needs to work on both Unix and Windows#my $dest_root = tempdir( 'GenCots_XXXX',TMPDIR => 1, CLEANUP => !$opt_keep );my $dest_dir = "$dest_root/$opt_subdir";Verbose ("Work Dir: $dest_dir");Error( "Temp Directory not found: $dest_root") unless ( -d $dest_root);Error( "Temp Workspace should not exist: $dest_dir") if ( -d $dest_dir);## Generate a label, if the user has not already specified one#if ( $opt_vob || $opt_repository ){$opt_label = "$ARGV[0]_$ARGV[1]"unless ( $opt_label );Verbose ("Label: $opt_label");}## Ensure VOBS/REPO and Labels are good#ClearCaseValidate() if ($opt_vob);SubversionValidate() if ($opt_repository);## Generate the package to be retained# Create jats build files and copy of required data#generatePackage();## Transfer the image into the target VCS System#ClearCaseImport() if ($opt_vob);SubversionImport() if ($opt_repository);## Remove the created directory#if ( $opt_keep ){Warning ("KEEP temp directory: $dest_root");}else{Message ("Delete temp directory");rmtree( $dest_root );}## All done# Report data to the user to use in Release Manager#if ( $opt_vob || $opt_repository ){Message ("\n");Message ("Release Manager information");if ( $opt_vob ){Message ("Package path : /$vob_name/$opt_subdir");Message ("Label : $opt_label");Message ("VCS Tag : CC::/${vob_name}/${opt_subdir}::${opt_label}");}else{$svnRmRef =~ m~(.*)::(.*)~;my $rmPath = $1 || 'Unknown';my $rmTag = $2 || 'Unknown';Message ("Source Path : $rmPath");Message ("Tag : $rmTag");Message ("VCS Tag : SVN::$svnRmRef");}Warning ("Test Mode: Not Version Control System changes made") if ( $opt_test );}exit 0;#-------------------------------------------------------------------------------# Function : generatePackage## Description : Craete a jats build package### Inputs : All global## Returns :#sub generatePackage{## Transfer source to target and remove generated files#mkpath ($dest_dir,$opt_verbose);Error( "Cannot create target directory") unless ( -d $dest_dir);Message ("Transfer package to local directory");File::Find::find( \&CopyDir, $src_dir );## Create a build.pl file based on a template#Message ("Create build.pl");open (BUILD, ">", "$dest_dir/build.pl" );while ( <DATA> ){chomp;last if ( /^__ENDBUILD/ );## Substitute values#s~__PACKAGENAME__~$ARGV[0]~g;s~__PACKAGEVERSION__~$ARGV[1]~g;if ( m/__BUILDNAME__/ ){if ( $ARGV[1] =~ m~^\d+\.\d+\.\d+[\s.]+(\w+)$~ ){print BUILD "BuildName ( '$ARGV[0]', '$ARGV[1]' );\n";}elsif ( $ARGV[1] =~ m~^(.*)\.+(\D+)$~ ){my $ver = $1;my $prj = $2;print BUILD "BuildName ( '$ARGV[0]', '$ver', '$prj', '--RelaxedVersion' );\n";}else{print BUILD "BuildName ( '$ARGV[0]', '$ARGV[1]', '--RelaxedVersion' );\n";print "Buildname: '$ARGV[0]', '$ARGV[1]'\n";}next;}print BUILD "$_\n";}close (BUILD);## Create a makefile.pl based on a template#Message ("Create src/makefile.pl");mkdir "$dest_dir/src";open (MAKE, ">", "$dest_dir/src/makefile.pl" );while ( <DATA> ){chomp;last if ( /^__ENDMAKE/ );## Substitute values#s~__PACKAGENAME__~$ARGV[0]~g;s~__PACKAGEVERSION__~$ARGV[1]~g;if ( /__PACKAGEFILE__/ ){unless ( $DESTDIR ){foreach my $file ( sort keys %files ){print MAKE "PackageFile ( '*', '../$file', '--StripDir' );\n";}} else {foreach my $file ( sort keys %files ){print MAKE "PackageFile ( '*', '$file' );\n";}}foreach my $subdir ( sort keys %subdirs ){print MAKE "PackageFile ( '*', '--DirTree=$subdir' );\n";}next;}print MAKE "$_\n";}close (MAKE);}#-------------------------------------------------------------------------------# Function : CopyDir## Description : Find callback function used to copy the archive## Inputs :## Returns :#sub CopyDir{my $item = $File::Find::name;my $base = File::Basename::basename($item);## Skip generated files#return if ( $base =~ m/^descpkg$/ );return if ( $base =~ m/^RELEASE_NOTES_/ );return if ( $base =~ m/^built\./ );## Don't process directories#return if ( -d $item );## Calculate target directory#my $sdl = length ($src_dir);my $target = $dest_dir . '/' . $DESTDIR . substr ( $item, $sdl );## Determinate top level package directories#my $rootdir = substr ( $item, 1 + $sdl );$rootdir =~ s~/.*~~;if ( $rootdir eq $base ){$files{$base} = 1;} else {$subdirs{$rootdir} = 1;}my $tdir = $target;$tdir =~ s~/[^/]+$~~;# print "================$item, $base, $tdir, $target, $rootdir\n";mkpath ($tdir, 0) unless ( -d $tdir );Verbose( "Transfer: $target");File::Copy::copy( "$item", "$target") || Error("Copy Fault: $item, $target");}#-------------------------------------------------------------------------------# Function : ClearCaseValidate## Description : Validate the ClearCase VOB and label## Inputs : Globals## Returns : Nothing#sub ClearCaseValidate{## Validate / locate the target VOB#locate_vob();## Ensure that the label is not locked# The user will not be able to move the label if it is already locked#my $label_exists = 0;Verbose ("Check label exists");ClearCmd ("describe -short lbtype:$opt_label@/$vob_name" ) unless $opt_test;$label_exists = 1 unless( $opt_test || grep ( /Label type not found/, @error_list ));Verbose ("Check label: $label_exists");if ( $label_exists ){Verbose ("Check label not locked");ClearCmd ("describe -fmt %[locked]p lbtype:$opt_label@/$vob_name" );unless ( $last_result && $last_result =~ m~unlocked~ ){Error("Label is locked: $opt_label");}}}#-------------------------------------------------------------------------------# Function : SubversionValidate## Description : Validate the Subversion Repository and label## Inputs : Globals## Returns : Nothing#sub SubversionValidate{## Ensure that the created label will be acceptable#$opt_label = SvnIsaSimpleLabel ($opt_label);## Prevent the user from creating paths that are too deep# Don't want repos that contain hidden packages#Error ("Created repository structure will be too deep")if ( ($opt_subdir =~ tr~/~~) >= 2 );## Create a subversion session# Ensure that the repository exists#$svnPackageName = $opt_repository . '/' . $opt_subdir;$svnSession = NewSessionByUrl ( $svnPackageName, 0 );my $rv = $svnSession->SvnValidateTarget ('target' => $svnSession->Full(),'test' => 1,);if ( $rv ){## Package exists within the Repo# Ensure its a valid package$svnSession->SvnValidatePackageRoot();$svnPackageExists = 1;$rv = $svnSession->SvnValidateTarget ('target' => $svnSession->BranchName( $opt_label, 'tags' ),'test' => 1,);if ( $rv ){Warning ("Target label already exists in the repository","It will be replaced" );}}}#-------------------------------------------------------------------------------# Function : ClearCaseImport## Description : Import the generated package into ClearCase# Label and all# The clearcase command will adjust the target directory# to match the source## Inputs :## Returns :#sub ClearCaseImport{## Determine the target directory within the VOB# This is the source directory tree, with the last element removed#my $target_path = "";if ( $opt_subdir =~ m~/~ ){$target_path = $opt_subdir;$target_path =~ s~/[^/]*$~~;$target_path = '/' . $target_path;}Message ("Import to clearcase vob: $opt_vob");my $cmd = "clearfsimport.exe -nsetevent -rec -rmname";$cmd .= " -preview" if $opt_test;$cmd .= " -mklabel $opt_label";$cmd .= " -c \"Package snapshot $ARGV[0]_$ARGV[1]\"";$cmd .= " $dest_dir $opt_vob$target_path";Verbose($cmd);@error_list = ();open(CMD, "$cmd 2>&1 |") || Error( "can't run command: $!");while (<CMD>){## Filter output from the user#chomp;Verbose($_);push @error_list, $_ if ( m~Error:~ );}close(CMD);if ( @error_list ){ReportError ($_) foreach ( @error_list );Error("Problem encountered saving package image");}## Apply label to all directories upto the root of the VOB# The label will have been applied to the TIP#Verbose ("Label package path");my $lpath = $opt_vob;foreach ( split ('/', $target_path) ){$lpath = $lpath . '/' . $_;Verbose ("Label package path: $lpath");ClearCmd ("mklabel -replace $opt_label $lpath" ) unless $opt_test;Error ("Program Terminated") if ( @error_list );}## Lock the label#Message ("Locking label: $opt_label");ClearCmd ("lock lbtype:$opt_label\@/$vob_name" ) unless $opt_test;Error ("Program Terminated") if ( @error_list );}#-------------------------------------------------------------------------------# Function : SubversionImport## Description : Import the generated package into Subversion# Label and all## Inputs :## Returns :#sub SubversionImport{return if ( $opt_test );unless ($svnPackageExists){## Create the package if it does not already exist# This is the simple process#$svnSession->{PRINTDATA} = 0;$svnSession->SvnCreatePackage ('import' => $dest_dir,'label' => $opt_label,'new' => 1,'printdata' => $opt_verbose,);$svnRmRef = $svnSession->SvnTag();}else{## Package exists# Hard bit: Need to merge the existing trunk with this version# and label the entire lot# We already have a program to do that.#my $workdir = "$dest_root/SvnImport";my $datafile = "$dest_root/svnData.txt";my $rv = JatsTool ('jats_svn', 'import',"-package=$svnPackageName","-dir=$dest_dir","-label=$opt_label","-datafile=$datafile","workspace=$workdir","-replace","-printfiles=$opt_verbose");if ( $rv ){Error ("Error importing package");}if ( -f $datafile ){my $rmData = JatsProperties::New($datafile);$svnRmRef = $rmData->getProperty('subversion.tag');}}unless ( $svnRmRef ){Error ('Failed to determin RM Reference');;}}#-------------------------------------------------------------------------------# Function : locate_vob## Description : Locate the target VOB# This is a bit tricky as it makes a few assumptions# 1) That clearcase dynamic views are mounted through the "o" drive# This appears to be a standard(ish) configuration.## 2) There must be a dynamic view on the machine that does have the# required VOB mounted## Note: Assumes that the user is NOT trying to place the package# into a subdir of the VOB.## Inputs : None## Returns : Global: $opt_vob#sub locate_vob{## If the user has specified an absolute path then use the users VOB#$opt_vob =~ tr~\\/~/~s;if ( $opt_vob =~ m~[A-Za-z]\:/~ || $opt_vob =~ m~/~ ){Error ("User VOB does not exist: $opt_vob") unless ( -d $opt_vob );$opt_vob =~ m~(.*/)(.*)~;$vob_dir = $1;$vob_name = $2;return;}## Scan for a dynamic view#Message ("Scanning for suitable dynamic view");my @search_list = glob ("O:/*");my $found_vob;foreach my $dir ( @search_list ){my $test_vob = "$dir/$opt_vob";Verbose ("Testing vob: $test_vob" );next if ( $dir =~ m~solaris~i ); # Take the hintnext if ( $dir =~ '/administration_view$' ); # Known read-only VOBif ( -d $test_vob ){$found_vob = $dir;last;}}Error ("Cannot find a suitable view with the $opt_vob VOB mounted") unless ( $found_vob );$vob_dir = $found_vob;$vob_name = $opt_vob;$opt_vob = "$vob_dir/$vob_name";Message ("Using VOB: $opt_vob");}#-------------------------------------------------------------------------------# Function : ClearCmd## Description : Similar to the system command# Does allow standard output and standard error to be captured# to a log file## Used since I was having problems with calling other programs# and control-C. It could hang the terminal session.## Inputs :## Returns :#sub ClearCmd{my( $cmd ) = @_;Verbose2 "cleartool $cmd";@error_list = ();open(CMD, "cleartool $cmd 2>&1 |") || Error "can't run command: $!";while (<CMD>){chomp;$last_result = $_;Verbose ( "cleartool resp:" . $_);push @error_list, $_ if ( m~Error:~ );}close(CMD);Verbose2 "Exit Status: $?";return $? / 256;}########################################################################## The following text contains two templates used in the creation# of a build.pl and a makefile.pl## The text is read and keywords are processed#__DATA__######################################################################### Copyright (C) 1998-2012 Vix Technology, All rights reserved## Module name : build.pl# Module type : JATS Build File# Environment(s): JATS Build System## Description: build.pl for package __PACKAGENAME__#.........................................................................##.. Build system#$MAKELIB_PL = "$ENV{ GBE_TOOLS }/makelib.pl";$BUILDLIB_PL = "$ENV{ GBE_TOOLS }/buildlib.pl";require "$BUILDLIB_PL";require "$MAKELIB_PL";#.. Product configuration#BuildPlatforms ( 'GENERIC' );__BUILDNAME__ BuildName ( '__PACKAGENAME__', '__PACKAGEVERSION__' );BuildInterface ( 'interface' );## Specify subdirectories to process#BuildSubDir ( 'src' );## Generate FilesBuildDescpkg ();BuildMake ();__ENDBUILD######################################################################### Copyright (C) 1998-2012 Vix Technology, All rights reserved## Module name : Makefile.pl# Module type : JATS Make File# Environment(s): JATS Build System## Description: makefile.pl for package __PACKAGENAME__##.........................................................................#die "Usage: Makefile.pl rootdir Makelib.pl\n"unless( $#ARGV+1 >= 2 );require "$ARGV[1]";## Build platform definitions ..#Platform( '*' );############################################################################# Define the source files##.............................................................................# Packaging definitions#__PACKAGEFILE__ PackageFile ( '*', '--DirTree=jar' );#..#Src ( '*' , 'descpkg' );PackageFile ( '*' , 'descpkg' );#.............................................................................# Finally generate the makefile#MakefileGenerate();#.. Successful termination1;__ENDMAKE#-------------------------------------------------------------------------------# Documentation#=pod=head1 NAMEgen_cots - Create a buildable package from dpkg_archive and place it underversion control=head1 SYNOPSISjats gen_cots package version [-vob=aa|-repo=aa|-keep]Options:-help - brief help message-help -help - Detailed help message-man - Full documentation-vob=vvv - VOB to use, may be a full path.-repository=path - Subversion Repository-keep - Keep the creating dpkg_archive image-label=name - Specify a label for the versions source-subdir=nnn - Named subdir in VOB-test - Do not perform operations that modify Version Control-image=path - Path to alternate source image=head1 OPTIONS=over 8=item B<-help>Print a brief help message and exits.=item B<-help -help>Print a detailed help message with an explanation for each option.=item B<-man>Prints the manual page and exits.=item B<-label=name>This option specifies an alternate label for the checked in source. Thedefault label is based on package and version.=item B<-vob=vvv>This option invokes the ClearCase mode of operation. The generated codewill be checked into ClearCase. This is only available under Windows.This option specifies the VOB into which the saved package will be placed.There are two ways that this option may be used.=over 8=item 1Simply name the VOB. (ie: COTS) The script will locate a dynamic view on theusers machine that contains the view. This is done by scanning dynamic views inthe "O:" drive.=item 2The full path to a VOB, including driver is provided. (ie: z:/COTS). This willprevent the script from locating the VOB. It will use the named view.=back=item B<-repository=path>This option invokes the Subversion mode of operation. The generated codewill be checked into Subversion.The argument is the path to the base of the package. The package namewill be appended by this program.=item B<-keep>If this option is selected then the program will retain the working directorythat it has created.If neither -vob or -repository is used, then this option must be provided.=item B<-subdir=name>This option specifies the name of a subdirectory in which the package will be created.The default name it taken from the package name.=item B<-test>This option will suppress the Version Control operations.No files will be checked in and the label will not be locked.=item B<-image=path>If this option is specified then the package will be created using thespecified source path, otherwise the package will be extracted from dpkg_archive.This option allows a locally created image to be stored as a COTS packagebefore it is placed in dpkg_archive.=back=head1 DESCRIPTIONThis program will create a version controlled and JATS buildable package froma dpkg_archive package version.In doing this the program will:=over 8=item *Create a temporary directory in the users current directory. This willbe used to contain a copy of the package.=item *Transfer the named package and version into the temp directory. The files willbe transferred in the a 'src' directory within the temp directory.=item *Create JATS build.pl and makefile.pls to support the creation of thepackage. The build.pl file will contain the package name and the packageversion.=item *Transfer the entire image into the named ClearCase VOB or Subversion Repository.The files will be labeled and the Version Control System target modified tomimic the temp directory view.=item *Lock the label used to mark the files (ClearCase Only).=item *Remove the temp work space.=item *Display information to be entered into Release Manager.=back=head1 EXAMPLE=head2 ClearCasejats etool gen_cots -vob=z:/COTS mos_api 5.6.0.crThis will take the version 5.6.0.cr of the mos_api package from dpkg_archiveplace it under version control within the COTS vob and add files to allow thedpkg_archive package to be recreated in an JATS buildable manner.=head2 Subversionjats etool gen_cots -repository=AUPERASVN01/COTS mos_api 5.6.0.crThis will take the version 5.6.0.cr of the mos_api package from dpkg_archiveplace it under version control within the COTS Repository and add files to allowthe dpkg_archive package to be recreated in an JATS buildable manner.=cut