#! /usr/bin/perl
#
# $Header: //sapdb/TOOLSRC/develop/sys/src/BuildPackage/New.pm#5 $
# $DateTime: 2002/03/08 15:32:18 $
# $Change: 17731 $
#
# Desc: tool to build several sap db packages

package BuildPackage::New;

use File::Copy;
use Getopt::Long;
use BuildPackage::GetFilesFromCDImages; # needed for XML stuff -> getting PCR 32/64 bit
use BuildPackage::Tools;
use BuildPackage::PackDefs;
use BuildPackage::Vars;

sub start{
	local @ARGV=@_;
	my @argbuf = @ARGV;
	
	my %opt_ctrl=(
			'h' => \$opt_help,
			'help' => \$opt_help,
			'profile=s' => \$opt_profile,
			'package=s' => \$opt_package,
			'format=s' => \$opt_format,
			'ignore_errors' => \$opt_ignore_errors,
			'single_pcr' => \$opt_single_pcr,
			'finalize' => \$opt_finalize,
			'ftp' => \$opt_ftp
	);
	
	Getopt::Long::Configure ('no_pass_through');
	if(!GetOptions(%opt_ctrl) or $opt_help){
		msg ("Usage: buildPackage [-h] [-ftp] [-profile <profile>] [-package <package list>] [-format tgz|sar] [-finalize]\n\n");
		exit 0;
	}
	
	
	# tiny helper functions
	sub timestamp{
		my($sec,$min,$hour,$day,$mon,$year)=localtime(time);
		$mon++;
		$sec="0$sec" if(length($sec)==1);
		$min="0$min" if(length($min)==1);
		$hour="0$hour" if(length($hour)==1);
		$day="0$day" if(length($day)==1);
		$mon="0$mon" if(length($mon)==1);
		$year=$year+1900;
		return "$year$mon$day$hour$min$sec";
	}

	-d "$WRK/fast/install" or makedir("$WRK/fast/install",0775);
	my $count = '';
	while(1){
		$logfilename="$WRK/fast/install/buildpackage_".timestamp.$count.'.log';
		-f $logfilename or last;
		$count++ unless $count eq ''; 
		$count = 0 if $count eq '';
	}
	
	open(LOG, ">$logfilename") || err ("cannot create logfile\n");
	msg("call: ".join(' ',@argbuf)."\n");
	sub err{
		my ($text)=@_;
		if($opt_ignore_errors){
			print STDERR "ERR: $text";
			print LOG "ERR: $text";
		}
		else{
			print LOG "ERR: $text";
			close(LOG);
			print STDERR $text;
			exit -1;
		}
	}

	sub msg{
		my ($text)=@_;
		print LOG $text;	
		print $text;
	}

	
	if($opt_ftp){
		SetVars({'USE_FTP' => 1},\&err);
	}


	BuildPackage::Tools::setErrMsgHandler(\&err);
	BuildPackage::Tools::setMsgHandler(\&msg);
	
	sub existInList{
		my ($packname,@packages)=@_;
		foreach my $hrPack (@packages){
			$packname eq ${%$hrPack}{'name'} and return 1; 
		}
		return 0;
	}
	
		
	#sub copyPCR{
	#	BuildPackageOld::OldPCR();
	#}	


	my @packages;
	
	#
	#define replacements -> for replacing strings in signature file and package script
	#	
	
	my %replacements = (
		'§RELEASE' => "$MAJ.$MIN.$COR.$BUILD",
		'§APORELEASE' => "$APO_REL.$APO_BUILD",
		'§LC_RELEASE' => "$LC_RELEASE",
		'§PACKVERS' => "$RUNTIME_VERSION", # used for names/pathes of PCR and SDK packages 
		'§BIT' => $BIT,
		'§SOEXT' => '.'.$SOEXT,
		'§EXEXT' => $EXEEXT
	);
	
	
	#foreach my $sym (keys(%BuildPackage::New::)){
	#	local *value = $BuildPackage::New::{$sym};
	#	defined $value and print "$sym = $value\n";
	#} 	

		
	#
	# select packages to build
	# with profile option
	#
	
	if($opt_profile){
		my @profiles = split(',',$opt_profile);
		foreach my $profile (@profiles){
			exists $profiles{$profile} or err ("no such profile: \"".$profile."\"\n");
			my @prof_pack;
			foreach my $pack (@{$profiles{$profile}}){
				defined $pack or next;
				my $found = 0;
				foreach my $packref (@allpackages){
					if($pack eq ${%$packref}{'name'}){
						$found=1;
						existInList($pack,@packages) and last;
						push @packages,$packref;
						last;
					}
				}
				if($found){
					push @prof_pack,$pack;
				}
				else{
					err("no such package: \"$pack\"\n");
				}
			}
			msg ("found for \"$profile\":\n");
			foreach my $packnam (@prof_pack){
				msg ("\t$packnam\n");
			}
			msg ("\n");
		}
		if ($APOMAKE and $opt_profile ne 'APO LiveCache'){
			err("APO COM MAKE ENVIRONMENT: profile \"APO LiveCache\" allowed only\n");
		}
		if(!$APOMAKE and $opt_profile =~ /APO\s*LiveCache/){
			err("NO APO COM MAKE ENVIRONMENT: profile \"APO LiveCache\" not allowed\n");
		}
			
	}

	#
	# select packages to build
	# with package option
	#
	
	if($opt_package){
		my @packs = split(',',$opt_package);
		foreach my $pack (@packs){
			my $found = 0;
			foreach my $packref (@allpackages){
				if($pack eq ${%$packref}{'name'}){
					push @packages,$packref;
						$found=1;
					last;
				}
			}
			$found || err("no such package: \"$pack\"\n");
		}
		if ($APOMAKE and $opt_package ne 'APO COM'){
			err("APO COM MAKE ENVIRONMENT: package \"APO COM\" allowed only\n");
		}
		if(!$APOMAKE and $opt_package =~ /APO\s*COM/){
			err("NO APO COM MAKE ENVIRONMENT: package \"APO COM\" not allowed\n");
		}
	}
	
	


	#
	# select all packages to build if no option set
	#
	if($#packages == -1){
		@packages=@allpackages;
	}
	
	
	# print out packages
	msg ("try to build following packages: \n");
	foreach $hrPack (@packages){
		msg ("\t".${%$hrPack}{'name'}."\n");
		if(!$APOMAKE and ${%$hrPack}{'name'} =~ /APO\s*COM/){
			err("NO APO COM MAKE ENVIRONMENT: package \"APO COM\" not allowed\n");
		}
		if ($APOMAKE and ${%$hrPack}{'name'} ne 'APO COM'){
			err("APO COM MAKE ENVIRONMENT: package \"APO COM\" allowed only\n");
		}
	}
	msg ("\n"); 


	my $packpath = $PACKAGEPATH.'/packages';

	if($APOMAKE){
		$packpath = "$LC_POOL_DIR/$LC_BUILD_SELECT/sys/src/lcsrc/packages";
	}



	#
	# test needed files:
	# 
	
	my $include_pcr = 0;
	foreach my $package (@packages){
		foreach my $file (${%$package}{'filelist'},${%$package}{'script'},'PACKAGEDATA'){
			-f $packpath.'/'.${%$package}{'subdir'}.'/'.$file || err($packpath.'/'.${%$package}{'subdir'}.'/'.$file.' [package "'.${%$package}{'name'}."\"] not found\n");
		}
		$include_pcr = 1 if ${%$package}{'name'} =~ /^PCR/;
	}

	my @oldpcr_packages = (); 
	
	if($include_pcr && !$opt_single_pcr){
		# copy pcr packages
		BuildPackage::GetFilesFromCDImages::setErrMsgHandler(\&err);
		BuildPackage::GetFilesFromCDImages::setMsgHandler(\&msg);
		my @files = grep {/\.TGZ$/} getFiles("$MAJ.$MIN.$COR.$BUILD",$OWN);
		push(@oldpcr_packages,@files)
	}
	
	
	#
	# get niping for APO COM package
	#

	if($APOMAKE && defined $LC_ROOT){
		my $src = "$LC_POOL_DIR/$LC_BUILD_SELECT/sys/src/lcsrc/sap/niping$EXEEXT";
		my $dst = "$INSTROOT/sap/niping$EXEEXT";
		if($^O=~/mswin/i){
			my $winsrc = $src;
			my $windst = $dst;
			$winsrc=~s/\//\\/g;
			$windst=~s/\//\\/g;
			`copy $winsrc $windst`;
		}
		else{
			`cp -p $src $dst`;
		}
		-f $dst or err("cannot copy $src -> $dst\n");
	}


	#
	# build packages
	#
	
	foreach my $package (@packages){
		
		#
		# make sure that there is no old stuff 
		#

		-d $BUILDROOT and (deltree($BUILDROOT) or err("cannot remove buildroot\n"));
		makedir($BUILDROOT,0775) or err("cannot create buildroot\n");
		
		#	
		# copy and change script and signature 
		#
		
		foreach my $file (${%$package}{'script'},'PACKAGEDATA'){
			open(IN,$packpath.'/'.${%$package}{'subdir'}.'/'.$file) or err('cannot open '.$packpath.'/'.${%$package}{'subdir'}."/$file\n");
			open (OUT,">$BUILDROOT/$file") or err("cannot create $BUILDROOT/$file\n");
			while(<IN>){
				chomp;
				foreach my $string (keys(%replacements)){
					s/$string/$replacements{$string}/g;
				}
				print OUT "$_\n" or err("cannot write into $BUILDROOT/$file\n");
			}
			close(IN);
			close(OUT);	
		}
	
		
		# call special package function if exists, at the moment only for pcr packages needed
		#exists ${%$package}{'specialFunc'} and &{${%$package}{'specialFunc'}}($package); 

		#
		# copy files, generate md5sums and change filelist (attach checksums)
		#
		
		open(IN,$packpath.'/'.${%$package}{'subdir'}.'/'.${%$package}{'filelist'}) or err('cannot open '.$packpath.'/'.${%$package}{'subdir'}.'/'.${%$package}{'filelist'}."\n");
		open(OUT,">$BUILDROOT/".${%$package}{'filelist'}) or err("cannot create $BUILDROOT/".${%$package}{'filelist'}."\n");
		while(<IN>){
			chomp;
			/^#/ && next;
			
			my $src = $_;
			if(exists ${%{${%$package}{'FileMappings'}}}{$_}){
				$src = ${%{${%$package}{'FileMappings'}}}{$_};
			}
			
			if(${%$package}{'name'} eq 'APO COM'){
				$src = "sap/$src";
			}
				
			$src = "$USR/$src";
			
			my $dst="$BUILDROOT/$_";
			my $dir = $dst;
			$dir=~s/\/[^\/]*$//;
			-d $dir or makedir($dir,0775) or err("cannot create directory $dir\n");
			
			if($^O=~/mswin/i){
				my $winsrc = $src;
				my $windst = $dst;
				$winsrc=~s/\//\\/g;
				$windst=~s/\//\\/g;
				`copy $winsrc $windst`;
			}
			else{
				`cp -p $src $dst`;
			}
			-f $dst or err("cannot copy $src -> $dst\n");
			my $md5sum=getMD5Sum($dst) or err("cannot get md5sum of $dst\n");
			print OUT "\"$_\" $md5sum\n" or err("cannot write into $BUILDROOT/".${%$package}{'filelist'}."\n");
		}
		close(IN);
		close(OUT);
		chdir("$BUILDROOT") or err("cannot change into directory $BUILDROOT\n");
		my $tarname="$PACKAGEPATH/".${%$package}{'archive'};
		
		# 
		# generate list of files and folders to pack
		# -> sequencing is important for performance of installer
		#
		
		my $packlist = 'PACKAGEDATA '.${%$package}{'script'}.' ' .${%$package}{'filelist'};
		opendir(DH,'.') || err("cannot open directory: $!\n");
		my @content = readdir(DH);
		close(DH);
		foreach (@content){
			(/^PACKAGEDATA$/ or /^${%$package}{'script'}$/ or /^${%$package}{'filelist'}$/ or /^\.{1,2}$/) and next;
			$packlist="$packlist $_"; 
		}
		
		#
		# pack archive
		#
		
		msg ("pack archive $tarname\n"); 
		#print "COMMAND: tar -cvpzf $tarname $packlist\n";
		if($^O =~ /mswin/i){
			do_cmd("tar -cvp $packlist | gzip -c -9 >$tarname");
		}
		else{
			do_cmd("gtar -cvpzf $tarname $packlist");
		}
		$? == 0 or err("tar error while packing \"".${%$package}{'name'}."\"\n");
		-f $tarname or err("no archive \"$tarname\" produced\n");
		chdir('..'); # leave buildroot
	}

	exit 0 unless $opt_profile;
	
	
	#
	# build liveCache + APO COM package
	#
	
	if ($APOMAKE && $opt_profile eq 'APO LiveCache'){
		my $lc_package = "$LC_POOL_DIR/$LC_BUILD_SELECT/$LC_PACK_NAME"; 
		-f $lc_package || err ("no liveCache ($lc_package) found\n");
		if($^O =~ /mswin/i){
			$lc_package =~ s/\//\\/g;
		}
		
		#
		# make sure that there is no old stuff 
		#
		
		-d $BUILDROOT and (deltree($BUILDROOT) or err("cannot remove buildroot\n"));
		makedir($BUILDROOT,0775) or err("cannot create buildroot\n");
		chdir($BUILDROOT) || err("cannot change into buildroot\n");
		do_cmd("SAPCAR -xvf $lc_package");
		copy("$WRK/fast/install/APOCOM.TGZ",$BUILDROOT) || err ("cannot copy APO COM package\n");
		my $package_name = $LC_PACK_NAME;
		$package_name =~ s/server/apo${APO_SHORT_VERS}_livecache/;
		do_cmd("SAPCAR -cvf $WRK/fast/install/$package_name *");
		-f "$WRK/fast/install/$package_name" &&
		msg("package $WRK/fast/install/$package_name successfully packed\n");
		
		
		if($opt_finalize){
		
			#
			# find free pool slot
			#

			my $new_dir;
			my $num_str;

		
			if(-d $APO_POOL_DIR){ 
				opendir(DH,$APO_POOL_DIR) or err("cannot open dir $APO_POOL_DIR\n");
				my @pool = sort grep {/^\d{3}$/} readdir(DH);
				closedir(DH);
				if($#pool == -1){
					$num_str = '000';
				}
				else{
					while(1){
						my $top = pop @pool;			
						if(-f "$APO_POOL_DIR/$top/$package_name"){
							my $num = $top + 1;
							$num_str = 0 x (3 - length($num)) . $num;			
							last;
						}
						if($#pool == -1){
							$num_str = '000';
							last;
						}		
					}
				}
			}
			else{
				$num_str = '000';
			}
			
			
			$new_dir = "$APO_POOL_DIR/$num_str";
	
	
	
			#
			# copy package into pool directotry
			#
			
			
			msg("copy $WRK/fast/install/$package_name -> $new_dir/$package_name\n");
			-d $new_dir or makedir($new_dir,0775) or err("cannot create directory $new_dir\n");
			copy("$WRK/fast/install/$package_name",$new_dir) || err("cannot copy: $!");		
			
			#
			# change latest link
			#
				
			my $link_name = "$APO_POOL_DIR/LastBuild"; 
			-l $link_name and (unlink($link_name) or err("cannot remove $link_name\n"));
				
			chdir($APO_POOL_DIR) or err("cannot change into $APO_POOL_DIR\n");
			symlink($num_str,'LastBuild') or err("cannot create \"LastBuild\"\n"); 
		
			
		}
		close(LOG);
		exit 0;
	
	}	
	
	
	#
	# build packages without APO COM
	#
	
	my $PACKNAME = $opt_profile;
	if(exists $profile_in_name{$opt_profile}){
		$PACKNAME = $profile_in_name{$opt_profile};
	}
	
	
	
	$PACKNAME =~ tr/[A-Z]/[a-z]/;
	$PACKNAME =~ s/\s/_/g;
	
	my $name_COR = $COR;
	my $name_BUILD = $BUILD;
	$name_COR =~ s/^0*//;
	$name_COR eq '' and $name_COR = '0';
	$name_BUILD =~ s/^0*//;
	$name_BUILD eq '' and $name_BUILD = '0';
	
	
	$packagename="sapdb-$PACKNAME-$OS-".$BIT."bit-$ARCH-".$MAJ.'_'.$MIN.'_'.$name_COR.'_'.$name_BUILD;
	my $package_name = $packagename.'.sar'; 

	my $packages;
	foreach my $package (@packages){
		$packages .= ' '.${%$package}{'archive'};
    }

	my $ext='tgz';
	my $exec_ext;
	$exec_ext = '.exe' if ($^O =~ /mswin/i);
	my $errtxt;
	if($opt_format eq 'sar' || $EM_MAKE){
		$ext='sar';
		chdir($PACKAGEPATH) or err("cannot change into dir $PACKAGEPATH\n");
		$packagename="$PACKAGEPATH/$packagename.$ext";
		my $cmd = "SAPCAR -cvf $packagename SDBRUN$exec_ext SDBINST$exec_ext ";
		$cmd .= "SDBUPD$exec_ext " if($packages =~ /SAPDBKRN.TGZ/);
		$cmd .= "SDBINST.TGZ $packages ".join(' ',@oldpcr_packages); 
		if($^O =~ /mswin/i){
			$cmd .= (exists $ENV{'BIT64'} || 
					($MAJ >= 7 && $MIN >= 4 && $COR >= 3) || 
					($MAJ >= 7 && $MIN >= 4 && $COR == 2 && $BUILD >= 4) || 
					($MAJ >= 7 && $MIN >= 4 && $COR == 1 && $BUILD >= 20)) ? ' perl56.dll' : ' perl.dll';
		}
		do_cmd($cmd);
		$? == 0 || err("sapcar error: $!\n");
	}
	else{
		$packagename="$PACKAGEPATH/$packagename.$ext";
		my $tar = 'gtar';
		$tar = 'tar' if $^O =~ /mswin/i;
		my $cmd = "$tar -cvpzf $packagename SDBRUN$exec_ext SDBINST$exec_ext "; 
		$cmd .= "SDBUPD$exec_ext " if($packages =~ /SAPDBKRN.TGZ/);
		$cmd .= "SDBINST.TGZ $packages ".join(' ',@oldpcr_packages); 
		
		if($^O =~ /mswin/i){
			$cmd .= (exists $ENV{'BIT64'} || 
					($MAJ >= 7 && $MIN >= 4 && $COR >= 3) || 
					($MAJ >= 7 && $MIN >= 4 && $COR == 2 && $BUILD >= 4) || 
					($MAJ >= 7 && $MIN >= 4 && $COR == 1 && $BUILD >= 20))  ? ' perl56.dll' : ' perl.dll';
		}
		do_cmd($cmd);
		$? == 0 || err("tar error: $!\n");
	
	} 
	if(-f $packagename){
		msg ("packed $packagename successfully\n");
	}
	else{
		msg ("cannot pack mainpackage: $errtxt\n");
	}
	if($opt_finalize){
		
		if($EM_MAKE){
			if($opt_profile eq 'Server'){
			
				#
				# find free pool slot
				#
	
				my $new_dir;
				my $num_str;
				
				if(-d $LC_POOL_DIR){
					opendir(DH,$LC_POOL_DIR) or err("cannot open dir $LC_POOL_DIR\n");
					my @pool = sort grep {/^\d{3}$/} readdir(DH);
					closedir(DH);
					if($#pool == -1){
						$num_str = '000';
					}
					else{
						while(1){
							my $top = pop @pool;			
							if(-f "$LC_POOL_DIR/$top/$package_name"){
								my $num = $top + 1;
								$num_str = 0 x (3 - length($num)) . $num;			
								last;
							}
							if($#pool == -1){
								$num_str = '000';
								last;
							}		
						}
					}
				}
				else{
					$num_str = '000';
				}
				$new_dir = "$LC_POOL_DIR/$num_str";

						
				#
				# copy package into pool directotry
				#
		
				msg("copy $WRK/fast/install/$package_name -> $new_dir/$package_name\n");
				-d $new_dir or makedir($new_dir,0775) or err("cannot create directory $new_dir\n");
				copy("$WRK/fast/install/$package_name",$new_dir) || err("cannot copy: $!");		
				
				
				
				#
				# copy java tests
				#
				
				my $test_files = 'jtest/jtinstall.pl '.
								 'jtest/ir_testframe_lib.sar '.
								 'jtest/jr_testframe_dep.sar '.
								 'jtest/jr_testframe_ind.sar';

				do_cmd("gtar -C $OWN/test -cpO $test_files | gtar -xpf- -C $new_dir");	
				
				
				#
				# copy dbmcli
				#

				do_cmd("gtar -C $OWN/usr/bin -cpO dbmcli | gtar -xpf- -C $new_dir");	
				
				#
				# copy VERSIONS
				#
				
				do_cmd("gtar -C $OWN/usr/etc -cpO VERSIONS | gtar -xpf- -C $new_dir");	

												
								
				#
				# copy incl/ and lib/directory
				#
				
				$new_dir .= '/sys/src/lcsrc'; 

				-d $new_dir || makedir ($new_dir,0775) || err("cannot create $new_dir\n");

				my $liboms = "$LIBPATH/liboms.$SOEXT";
					
				do_cmd("gtar -C $OWN/usr -cpO incl pgm/idl2xml pgm/xml2ispc $liboms | gtar -xpf- -C $new_dir");	
			
				
				
				#
				# copy apo package data
				#
												
				do_cmd("gtar -C $WRK/fast/install -cpO  packages/apocom | gtar -xpf- -C $new_dir");	
				
				
				#
				# copy niping
				#

				do_cmd("gtar -C $OWN/usr -cpO  sap/niping$EXEEXT | gtar -xpf- -C $new_dir");	
				
				
				#
				# change latest link
				#
				
				my $link_name = "$LC_POOL_DIR/LastBuild"; 
		
				-l $link_name and (unlink($link_name) or err("cannot remove $link_name\n"));
				
				chdir($LC_POOL_DIR) or err("cannot change into $LC_POOL_DIR\n");
				symlink($num_str,'LastBuild') or err("cannot create \"LastBuild\"\n"); 
		
			}
			close(LOG);
			exit 0;									
		}
		
		if($USE_FTP){
			err("no ftp access rights to put package to CD-Images\n");
		}
		
		msg("copy $packagename.$ext to CD-Images\n");
		my $ospath;
		if(exists $ENV{'BIT64'} or $^O =~ /osf/i){
			$ospath = $OS64_PATH;
		}
		else{
			$ospath = $OS32_PATH;
		}
		my $cmd;
		if($^O =~ /mswin/i){
			$cmd = "copy $packagename.$ext \\\\$image_server\\DB_REL\\$MAJ$MIN$COR$BUILD\\$ospath\\$packagename.$ext";
		}
		else{
			$cmd = "rem cp $packagename.$ext $image_server:d:/DB_REL/$MAJ$MIN$COR$BUILD/$ospath/$packagename.$ext";
		}
		do_cmd($cmd);
		$? == 0 || err("cannot copy archive to CD-Images: $errtext");
	}
}

close(LOG);
1;






