#!/usr/bin/perl -w # # Project Builder main application # # $Id$ # # Copyright B. Cornec 2007 # Provided under the GPL v2 # Syntax: see at end use strict 'vars'; use Getopt::Long qw(:config auto_abbrev no_ignore_case); use Data::Dumper; use English; use File::Basename; use File::Copy; use File::stat; use File::Temp qw(tempdir); use Date::Manip; use POSIX qw(strftime); use lib qw (lib); use ProjectBuilder::Distribution; use ProjectBuilder::Version; use ProjectBuilder::Base; # Global variables my %opts; # CLI Options my $action; # action to realize my $test = "FALSE"; # Not used my $force = 0; # Force VE/VM rebuild my $option = ""; # Not used my @pkgs; # list of packages my $pbtag; # Global Tag variable my $pbver; # Global Version variable my $pbscript; # Name of the script my %pbver; # per package my %pbtag; # per package my $pbrev; # Global REVISION variable my $pbaccount; # Login to use to connect to the VM my $pbport; # Port to use to connect to the VM my $newver; # New version to create my $iso; # ISO image for the VM to create my @date = pb_get_date(); my $pbdate = strftime("%Y-%m-%d", @date); =pod =head1 NAME pb, aka project-builder.org - builds packages for your projects =head1 DESCRIPTION pb helps you build various packages directly from your project sources. Those sources could be handled by a CMS (Configuration Management System) such as Subversion, CVS, ... or being a simple reference to a compressed tar file. It's based on a set of configuration files, a set of provided macros to help you keeping build files as generic as possible. For example, a single .spec file should be required to generate for all rpm based distributions, even if you could also have multiple .spec files if required. =head1 SYNOPSIS pb [-vhq][-r pbroot][-p project][[-s script -a account -P port][-m mach-1[,...]]][-i iso] [ ...] pb [--verbose][--help][--man][--quiet][--revision pbroot][--project project][[--script script --account account --port port][--machine mach-1[,...]]][--iso iso] [ ...] =head1 OPTIONS =over 4 =item B<-v|--verbose> Print a brief help message and exits. =item B<-q|--quiet> Do not print any output. =item B<-h|--help> Print a brief help message and exits. =item B<--man> Prints the manual page and exits. =item B<-m|--machine machine1[,machine2,...]> Name of the Virtual Machines (VM) or Virtual Environments (VE) you want to build on (coma separated). All if none precised (or use the env variable PBV). =item B<-s|--script script> Name of the script you want to execute on the related VMs or VEs. =item B<-i|--iso iso_image> Name of the ISO image of the distribution you want to install on the related VMs. =item B<-a|--account account> Name of the account to use to connect on the related VMs. =item B<-P|--port port_number> Port number to use to connect on the related VMs.\n"; =item B<-p|--project project_name> Name of the project you're working on (or use the env variable PBPROJ) =item B<-r|--revision revision> Path Name of the project revision under the CMS (or use the env variable PBROOT) =item B<-V|--version new_version> New version of the project to create based on the current one. =back =head1 ARGUMENTS can be: =over 4 =item B Create tar files for the project under your CMS. CMS supported are SVN and CVS parameters are packages to build if not using default list =item B Create packages for your running distribution =item B cms2build + build2pkg =item B Send the tar files to a SSH host =item B cms2build + build2ssh =item B Send the packages built to a SSH host =item B Create packages in VMs, launching them if needed and send those packages to a SSH host once built VM type supported are QEMU =item B Create packages in VEs, creating it if needed and send those packages to a SSH host once built =item B cms2build + build2vm =item B cms2build + build2ve =item B Launch one virtual machine =item B Launch one virtual environment =item B Launch one virtual machine if needed and executes a script on it =item B Execute a script in a virtual environment =item B Create a new virtual machine =item B Create a new virtual environment =item B Setup a virtual machine for pb usage =item B Setup a virtual environment for pb usage =item B Create a new version of the project derived from the current one =item B Create a new project and a template set of configuration files under pbconf =back can be a list of packages, the keyword 'all' or nothing, in which case the default list of packages is taken (corresponding to the defpkgdir list of arguments in the configuration file). =head1 WEB SITES The main Web site of the project is available at L. Bug reports should be filled using the trac instance of the project at L. =head1 USER MAILING LIST None exists for the moment. =head1 CONFIGURATION FILES Each pb user may have a configuration in F<$HOME/.pbrc>. The values in this file may overwrite any other configuration file value. Here is an example of such a configuration file: # # Define for each project the URL of its pbconf repository # No default option allowed here as they need to be all different # # URL of the pbconf content # This is the format of a classical URL with the extension of additional schema such as # svn+ssh, cvs+ssh, ... # pbconfurl linuxcoe = cvs+ssh://:ext:bcornec@linuxcoe.cvs.sourceforge.net:/cvsroot/linuxcoe/pbconf # This is normaly defined in the project's configuration file # Url of the project # pburl linuxcoe = cvs+ssh://:ext:bcornec@linuxcoe.cvs.sourceforge.net:/cvsroot/linuxcoe # All these URLs needs to be defined here as the are the entry point # for how to build packages for the project # pbconfurl pb = svn+ssh://svn.project-builder.org/mondo/svn/pb/pbconf pbconfurl mondorescue = svn+ssh://svn.project-builder.org/mondo/svn/project-builder/mondorescue/pbconf pbconfurl collectl = svn+ssh://bruno@svn.mondorescue.org/mondo/svn/project-builder/collectl/pbconf pbconfurl netperf = svn+ssh://svn.mondorescue.org/mondo/svn/project-builder/netperf/pbconf # Under that dir will take place everything related to pb # If you want to use VMs/chroot/..., then use $ENV{'HOME'} to make it portable # to your VMs/chroot/... # if not defined then /var/cache pbdefdir default = $ENV{'HOME'}/project-builder pbdefdir pb = $ENV{'HOME'} pbdefdir linuxcoe = $ENV{'HOME'}/LinuxCOE/cvs pbdefdir mondorescue = $ENV{'HOME'}/mondo/svn # pbconfdir points to the directory where the CMS content of the pbconfurl is checked out # If not defined, pbconfdir is under pbdefdir/pbproj/pbconf pbconfdir linuxcoe = $ENV{'HOME'}/LinuxCOE/cvs/pbconf pbconfdir mondorescue = $ENV{'HOME'}/mondo/svn/pbconf # pbdir points to the directory where the CMS content of the pburl is checked out # If not defined, pbdir is under pbdefdir/pbproj # Only defined if we have access to the dev of the project pbdir linuxcoe = $ENV{'HOME'}/LinuxCOE/cvs pbdir mondorescue = $ENV{'HOME'}/mondo/svn # -daemonize doesn't work with qemu 0.8.2 vmopt default = -m 384 =head1 AUTHORS The Project-Builder.org team L lead by Bruno Cornec L. =head1 COPYRIGHT Project-Builder.org is distributed under the GPL v2.0 license described in the file C included with the distribution. =cut # --------------------------------------------------------------------------- # Old syntax #getopts('a:fhi:l:m:P:p:qr:s:vV:',\%opts); my ($projectbuilderver,$projectbuilderrev) = pb_version_init(); # Initialize the syntax string pb_syntax_init("pb (aka project-builder.org) Version $projectbuilderver-$projectbuilderrev\n"); GetOptions("help|?|h" => \$opts{'h'}, "man" => \$opts{'man'}, "verbose|v+" => \$opts{'v'}, "quiet|q" => \$opts{'q'}, "log-files|l=s" => \$opts{'l'}, "force|f" => \$opts{'f'}, "account|a=s" => \$opts{'a'}, "revision|r=s" => \$opts{'r'}, "script|s=s" => \$opts{'s'}, "machines|mock|m=s" => \$opts{'m'}, "port|P=i" => \$opts{'P'}, "project|p=s" => \$opts{'p'}, "iso|i=s" => \$opts{'i'}, "version|V=s" => \$opts{'V'}, ) || pb_syntax(-1,0); if (defined $opts{'h'}) { pb_syntax(0,1); } if (defined $opts{'man'}) { pb_syntax(0,2); } if (defined $opts{'v'}) { $debug = $opts{'v'}; pb_log(0,"Debug value: $debug\n"); } if (defined $opts{'f'}) { $force=1; } if (defined $opts{'q'}) { $debug=-1; } if (defined $opts{'l'}) { open(LOG,"> $opts{'l'}") || die "Unable to log to $opts{'l'}: $!"; $LOG = \*LOG; $debug = 0 if ($debug == -1); } pb_log_init($debug, $LOG); # Handle root of the project if defined if (defined $opts{'r'}) { $ENV{'PBROOTDIR'} = $opts{'r'}; } # Handle virtual machines if any if (defined $opts{'m'}) { $ENV{'PBV'} = $opts{'m'}; } if (defined $opts{'s'}) { $pbscript = $opts{'s'}; } if (defined $opts{'a'}) { $pbaccount = $opts{'a'}; die "option -a requires a -s script option" if (not defined $pbscript); } if (defined $opts{'P'}) { $pbport = $opts{'P'}; } if (defined $opts{'V'}) { $newver = $opts{'V'}; } if (defined $opts{'i'}) { $iso = $opts{'i'}; } # Get Action $action = shift @ARGV; die pb_syntax(-1,1) if (not defined $action); my ($filteredfiles, $supfiles, $defpkgdir, $extpkgdir); my $pbinit = undef; $pbinit = 1 if ($action =~ /^newproj$/); # Handles project name if any # And get global params ($filteredfiles, $supfiles, $defpkgdir, $extpkgdir) = pb_env_init($opts{'p'},$pbinit,$action); pb_log(0,"Project: $ENV{'PBPROJ'}\n"); pb_log(0,"Action: $action\n"); # Act depending on action if ($action =~ /^cms2build$/) { pb_cms2build(); } elsif ($action =~ /^build2pkg$/) { pb_build2pkg(); } elsif ($action =~ /^cms2pkg$/) { pb_cms2build(); pb_build2pkg(); } elsif ($action =~ /^build2ssh$/) { pb_build2ssh(); } elsif ($action =~ /^cms2ssh$/) { pb_cms2build(); pb_build2ssh(); } elsif ($action =~ /^pkg2ssh$/) { pb_pkg2ssh(); } elsif ($action =~ /^build2ve$/) { pb_build2v("ve"); } elsif ($action =~ /^build2vm$/) { pb_build2v("vm"); } elsif ($action =~ /^cms2ve$/) { pb_cms2build(); pb_build2v("ve"); } elsif ($action =~ /^cms2vm$/) { pb_cms2build(); pb_build2v("vm"); } elsif ($action =~ /^launchvm$/) { pb_launchv("vm",$ENV{'PBV'},0); } elsif ($action =~ /^launchve$/) { pb_launchv("ve",$ENV{'PBV'},0); } elsif ($action =~ /^script2vm$/) { pb_script2v($pbscript,"vm"); } elsif ($action =~ /^script2ve$/) { pb_script2v($pbscript,"ve"); } elsif ($action =~ /^newver$/) { pb_newver(); } elsif ($action =~ /^newve$/) { pb_launchv("ve",$ENV{'PBV'},1); } elsif ($action =~ /^newvm$/) { pb_launchv("vm",$ENV{'PBV'},1); } elsif ($action =~ /^setupve$/) { pb_setup_v("ve"); } elsif ($action =~ /^setupvm$/) { pb_setup_v("vm"); } elsif ($action =~ /^newproj$/) { # Nothing to do - already done in pb_env_init } elsif ($action =~ /^clean$/) { } else { pb_log(0,"\'$action\' is not available\n"); pb_syntax(-2,1); } sub pb_cms2build { my $pkg = pb_cms_get_pkg($defpkgdir,$extpkgdir); my @pkgs = @$pkg; my %pkgs; my ($scheme, $uri) = pb_cms_init($pbinit); my ($pkgv, $pkgt) = pb_conf_get_if("pkgver","pkgtag"); # declare packager for filtering my ($tmp) = pb_conf_get("pbpackager"); $ENV{'PBPACKAGER'} = $tmp->{$ENV{'PBPROJ'}}; foreach my $pbpkg (@pkgs) { $ENV{'PBPKG'} = $pbpkg; if ((defined $pkgv) && (defined $pkgv->{$pbpkg})) { $pbver = $pkgv->{$pbpkg}; } else { $pbver = $ENV{'PBPROJVER'}; } if ((defined $pkgt) && (defined $pkgt->{$pbpkg})) { $pbtag = $pkgt->{$pbpkg}; } else { $pbtag = $ENV{'PBPROJTAG'}; } $pbrev = $ENV{'PBREVISION'}; pb_log(0,"\n"); pb_log(0,"Management of $pbpkg $pbver-$pbtag (rev $pbrev)\n"); die "Unable to get env var PBDESTDIR" if (not defined $ENV{'PBDESTDIR'}); # Clean up dest if necessary. The export will recreate it my $dest = "$ENV{'PBDESTDIR'}/$pbpkg-$pbver"; pb_rm_rf($dest) if (-d $dest); # Export CMS tree for the concerned package to dest # And generate some additional files $OUTPUT_AUTOFLUSH=1; # computes in which dir we have to work my $dir = $defpkgdir->{$pbpkg}; $dir = $extpkgdir->{$pbpkg} if (not defined $dir); pb_log(2,"def:".Dumper($defpkgdir)." ext: ".Dumper($extpkgdir)." \n"); # Exporting from CMS pb_cms_export($uri,"$ENV{'PBDIR'}/$dir",$dest); # Get project info on authors and log file my $chglog = "$ENV{'PBROOTDIR'}/$pbpkg/pbcl"; $chglog = "$ENV{'PBROOTDIR'}/pbcl" if (! -f $chglog); $chglog = undef if (! -f $chglog); my $authors = "$ENV{'PBROOTDIR'}/$pbpkg/pbauthors"; $authors = "$ENV{'PBROOTDIR'}/pbauthors" if (! -f $authors); $authors = "/dev/null" if (! -f $authors); # Extract cms log history and store it if ((defined $chglog) && (! -f "$dest/NEWS")) { pb_log(2,"Generating NEWS file from $chglog\n"); copy($chglog,"$dest/NEWS") || die "Unable to create $dest/NEWS"; } pb_cms_log($scheme,"$ENV{'PBDIR'}/$dir",$dest,$chglog,$authors); my %build; my @pt; @pt = pb_conf_get_if("vmlist","velist"); my $tmpl = ""; if (defined $pt[0]->{$ENV{'PBPROJ'}}) { $tmpl .= $pt[0]->{$ENV{'PBPROJ'}}; } if (defined $pt[1]->{$ENV{'PBPROJ'}}) { # the 2 lists needs to be grouped with a ',' separated them if ($tmpl ne "") { $tmpl .= ","; } $tmpl .= $pt[1]->{$ENV{'PBPROJ'}} } foreach my $d (split(/,/,$tmpl)) { my ($name,$ver,$arch) = split(/-/,$d); chomp($arch); my ($ddir, $dver, $dfam, $dtype, $pbsuf) = pb_distro_init($name,$ver); pb_log(2,"DEBUG: distro tuple: ".Dumper($ddir, $dver, $dfam, $dtype, $pbsuf)."\n"); pb_log(2,"DEBUG Filtering PBDATE => $pbdate, PBTAG => $pbtag, PBVER => $pbver\n"); # Filter build files from the less precise up to the most with overloading # Filter all files found, keeping the name, and generating in dest # Find all build files first relatively to PBROOTDIR # Find also all specific files referenced in the .pb conf file my %bfiles = (); my %pkgfiles = (); $build{"$ddir-$dver"} = "yes"; if (-d "$ENV{'PBROOTDIR'}/$pbpkg/$dtype") { pb_list_bfiles("$ENV{'PBROOTDIR'}/$pbpkg/$dtype",$pbpkg,\%bfiles,\%pkgfiles,$supfiles); } elsif (-d "$ENV{'PBROOTDIR'}/$pbpkg/$dfam") { pb_list_bfiles("$ENV{'PBROOTDIR'}/$pbpkg/$dfam",$pbpkg,\%bfiles,\%pkgfiles,$supfiles); } elsif (-d "$ENV{'PBROOTDIR'}/$pbpkg/$ddir") { pb_list_bfiles("$ENV{'PBROOTDIR'}/$pbpkg/$ddir",$pbpkg,\%bfiles,\%pkgfiles,$supfiles); } elsif (-d "$ENV{'PBROOTDIR'}/$pbpkg/$ddir-$dver") { pb_list_bfiles("$ENV{'PBROOTDIR'}/$pbpkg/$ddir-$dver",$pbpkg,\%bfiles,\%pkgfiles,$supfiles); } else { $build{"$ddir-$dver"} = "no"; next; } pb_log(2,"DEBUG bfiles: ".Dumper(\%bfiles)."\n"); # Get all filters to apply my $ptr = pb_get_filters($pbpkg, $dtype, $dfam, $ddir, $dver); # Apply now all the filters on all the files concerned # destination dir depends on the type of file if (defined $ptr) { foreach my $f (values %bfiles,values %pkgfiles) { pb_filter_file_pb("$ENV{'PBROOTDIR'}/$f",$ptr,"$dest/pbconf/$ddir-$dver/".basename($f),$dtype,$pbsuf,$ENV{'PBPROJ'},$pbpkg,$pbver,$pbtag,$pbrev,$pbdate,$defpkgdir,$extpkgdir,$ENV{'PBPACKAGER'},$chglog); } } } my @found; my @notfound; foreach my $b (keys %build) { push @found,$b if ($build{$b} =~ /yes/); push @notfound,$b if ($build{$b} =~ /no/); } pb_log(0,"Build files generated for ".join(',',@found)."\n"); pb_log(0,"No Build files found for ".join(',',@notfound)."\n") if (@notfound); # Get the generic filter (all.pbf) and # apply those to the non-build files including those # generated by pbinit if applicable # Get only all.pbf filter my $ptr = pb_get_filters($pbpkg); my $liste =""; if (defined $filteredfiles->{$pbpkg}) { foreach my $f (split(/,/,$filteredfiles->{$pbpkg})) { pb_filter_file_inplace($ptr,"$dest/$f",$ENV{'PBPROJ'},$pbpkg,$pbver,$pbtag,$pbrev,$pbdate,$ENV{'PBPACKAGER'}); $liste = "$f $liste"; } } pb_log(2,"Files ".$liste."have been filtered\n"); # Prepare the dest directory for archive if (-x "$ENV{'PBROOTDIR'}/$pbpkg/pbinit") { pb_filter_file("$ENV{'PBROOTDIR'}/$pbpkg/pbinit",$ptr,"$ENV{'PBTMP'}/pbinit",$ENV{'PBPROJ'},$pbpkg,$pbver,$pbtag,$pbrev,$pbdate,$ENV{'PBPACKAGER'}); chmod 0755,"$ENV{'PBTMP'}/pbinit"; pb_system("cd $dest ; $ENV{'PBTMP'}/pbinit","Executing init script from $ENV{'PBROOTDIR'}/$pbpkg/pbinit"); } # Archive dest dir chdir "$ENV{'PBDESTDIR'}" || die "Unable to change dir to $ENV{'PBDESTDIR'}"; # Possibility to look at PBSRC to guess more the filename pb_system("tar cfz $pbpkg-$pbver.tar.gz $pbpkg-$pbver","Creating $pbpkg tar files compressed"); pb_log(0,"Under $ENV{'PBDESTDIR'}/$pbpkg-$pbver.tar.gz\n"); # Keep track of version-tag per pkg $pkgs{$pbpkg} = "$pbver-$pbtag"; # Final cleanup pb_rm_rf($dest) if (-d $dest); } # Keep track of per package version pb_log(2,"DEBUG pkgs: ".Dumper(%pkgs)."\n"); open(PKG,"> $ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb") || die "Unable to create $ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb"; foreach my $pbpkg (@pkgs) { print PKG "pbpkg $pbpkg = $pkgs{$pbpkg}\n"; } close(PKG); # Keep track of what is generated by default # We need to store the dir and info on version-tag # Base our content on the existing .pb file copy("$ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb","$ENV{'PBDESTDIR'}/pbrc"); open(LAST,">> $ENV{'PBDESTDIR'}/pbrc") || die "Unable to create $ENV{'PBDESTDIR'}/pbrc"; print LAST "pbroot $ENV{'PBPROJ'} = $ENV{'PBROOTDIR'}\n"; print LAST "pbprojver $ENV{'PBPROJ'} = $ENV{'PBPROJVER'}\n"; print LAST "pbprojtag $ENV{'PBPROJ'} = $ENV{'PBPROJTAG'}\n"; print LAST "pbpackager $ENV{'PBPROJ'} = $ENV{'PBPACKAGER'}\n"; close(LAST); } sub pb_build2pkg { # Get the running distro to build on my ($ddir, $dver, $dfam, $dtype, $pbsuf) = pb_distro_init(); pb_log(2,"DEBUG: distro tuple: ".join(',',($ddir, $dver, $dfam, $dtype, $pbsuf))."\n"); # Get list of packages to build # Get content saved in cms2build my $ptr = pb_get_pkg(); @pkgs = @$ptr; my ($pkg) = pb_conf_read("$ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb","pbpkg"); $pkg = { } if (not defined $pkg); chdir "$ENV{'PBBUILDDIR'}"; my $made = ""; # pkgs made during build foreach my $pbpkg (@pkgs) { my $vertag = $pkg->{$pbpkg}; # get the version of the current package - maybe different ($pbver,$pbtag) = split(/-/,$vertag); my $src="$ENV{'PBDESTDIR'}/$pbpkg-$pbver.tar.gz"; pb_log(2,"Source file: $src\n"); pb_log(2,"Working directory: $ENV{'PBBUILDDIR'}\n"); if ($dtype eq "rpm") { foreach my $d ('RPMS','SRPMS','SPECS','SOURCES','BUILD') { if (! -d "$ENV{'PBBUILDDIR'}/$d") { pb_mkdir_p("$ENV{'PBBUILDDIR'}/$d") || die "Please ensure that you can write into $ENV{'PBBUILDDIR'} to create $d\nchown the $ENV{'PBBUILDDIR'} directory to your uid"; } } # Remove in case a previous link/file was there unlink "$ENV{'PBBUILDDIR'}/SOURCES/".basename($src); symlink "$src","$ENV{'PBBUILDDIR'}/SOURCES/".basename($src) || die "Unable to symlink $src in $ENV{'PBBUILDDIR'}/SOURCES"; # We need to first extract the spec file my @specfile; @specfile = pb_extract_build_files($src,"$pbpkg-$pbver/pbconf/$ddir-$dver/","$ENV{'PBBUILDDIR'}/SPECS"); pb_log(2,"specfile: ".Dumper(\@specfile)."\n"); # set LANGUAGE to check for correct log messages $ENV{'LANGUAGE'}="C"; foreach my $f (@specfile) { if ($f =~ /\.spec$/) { pb_system("rpmbuild --define \'packager $ENV{'PBPACKAGER'}\' --define \"_topdir $ENV{'PBBUILDDIR'}\" -ba $f","Building package with $f under $ENV{'PBBUILDDIR'}"); last; } } $made="$made RPMS/*/$pbpkg-$pbver-$pbtag$pbsuf.*.rpm SRPMS/$pbpkg-$pbver-$pbtag$pbsuf.src.rpm"; if (-f "/usr/bin/rpmlint") { pb_system("rpmlint $made","Checking validity of rpms with rpmlint"); } } elsif ($dtype eq "deb") { chdir "$ENV{'PBBUILDDIR'}" || die "Unable to chdir to $ENV{'PBBUILDDIR'}"; pb_system("tar xfz $src","Extracting sources"); chdir "$pbpkg-$pbver" || die "Unable to chdir to $pbpkg-$pbver"; pb_rm_rf("debian"); symlink "pbconf/$ddir-$dver","debian" || die "Unable to symlink to pbconf/$ddir-$dver"; chmod 0755,"debian/rules"; pb_system("dpkg-buildpackage -us -uc -rfakeroot","Building package"); $made="$made $pbpkg"."_*.deb $pbpkg"."_*.dsc $pbpkg"."_*.tar.gz"; if (-f "/usr/bin/lintian") { pb_system("lintian $made","Checking validity of debs with lintian"); } } elsif ($dtype eq "ebuild") { my @ebuildfile; # For gentoo we need to take pb as subsystem name # We put every apps here under sys-apps. hope it's correct # We use pb's home dir in order o have a single OVERLAY line my $tmpd = "$ENV{'HOME'}/portage/pb/sys-apps/$pbpkg"; pb_mkdir_p($tmpd) if (! -d "$tmpd"); pb_mkdir_p("$ENV{'HOME'}/portage/distfiles") if (! -d "$ENV{'HOME'}/portage/distfiles"); # We need to first extract the ebuild file @ebuildfile = pb_extract_build_files($src,"$pbpkg-$pbver/pbconf/$ddir-$dver/","$tmpd"); # Prepare the build env for gentoo my $found = 0; my $pbbd = $ENV{'HOME'}; $pbbd =~ s|/|\\/|g; if (-r "/etc/make.conf") { open(MAKE,"/etc/make.conf"); while () { $found = 1 if (/$pbbd\/portage/); } close(MAKE); } if ($found == 0) { pb_system("sudo sh -c 'echo PORTDIR_OVERLAY=\"$ENV{'HOME'}/portage\" >> /etc/make.conf'"); } #$found = 0; #if (-r "/etc/portage/package.keywords") { #open(KEYW,"/etc/portage/package.keywords"); #while () { #$found = 1 if (/portage\/pb/); #} #close(KEYW); #} #if ($found == 0) { #pb_system("sudo sh -c \"echo portage/pb >> /etc/portage/package.keywords\""); #} # Build foreach my $f (@ebuildfile) { if ($f =~ /\.ebuild$/) { move($f,"$tmpd/$pbpkg-$pbver.ebuild"); pb_system("cd $tmpd ; ebuild $pbpkg-$pbver.ebuild clean ; ebuild $pbpkg-$pbver.ebuild digest ; ebuild $pbpkg-$pbver.ebuild package"); # Now move it where pb expects it pb_mkdir_p("$ENV{'PBBUILDDIR'}/portage/pb/sys-apps/$pbpkg"); move("$tmpd/$pbpkg-$pbver.ebuild","$ENV{'PBBUILDDIR'}/portage/pb/sys-apps/$pbpkg"); } } $made="$made portage/pb/sys-apps/$pbpkg/$pbpkg-$pbver.ebuild"; } elsif ($dtype eq "slackware") { $made="$made build-$pbpkg/$pbpkg-$pbver-*-$pbtag.tgz"; pb_mkdir_p("$ENV{'PBBUILDDIR'}/install") if (! -d "$ENV{'PBBUILDDIR'}/install"); } else { die "Unknown dtype format $dtype"; } } # Keep track of what is generated so that we can get them back from VMs open(KEEP,"> $ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}") || die "Unable to create $ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}"; print KEEP "$made\n"; close(KEEP); } sub pb_build2ssh { pb_send2target("Sources"); } sub pb_pkg2ssh { pb_send2target("Packages"); } # By default deliver to the the public site hosting the # ftp structure (or whatever) or a VM/VE sub pb_send2target { my $cmt = shift; my $v = shift || undef; my $vmexist = shift || 0; # 0 is FALSE my $vmpid = shift || 0; # 0 is FALSE my $host = "sshhost"; my $login = "sshlogin"; my $dir = "sshdir"; my $port = "sshport"; my $tmout = "sshtmout"; my $path = "sshpath"; my $conf = "sshconf"; my $rebuild = "sshrebuild"; if (($cmt eq "vm") || ($cmt eq "Script")) { $login = "vmlogin"; $dir = "pbdefdir"; $tmout = "vmtmout"; $rebuild = "vmrebuild"; # Specific VM $host = "vmhost"; $port = "vmport"; } elsif ($cmt eq "ve") { $login = "velogin"; $dir = "pbdefdir"; $tmout = "vetmout"; # Specific VE $path = "vepath"; $conf = "veconf"; $rebuild = "verebuild"; } my $cmd = ""; my $ptr = pb_get_pkg(); @pkgs = @$ptr; # Get the running distro to consider my ($odir,$over,$oarch) = (undef, undef, undef); if (defined $v) { ($odir,$over,$oarch) = split(/-/,$v); } my ($ddir, $dver, $dfam, $dtype, $pbsuf) = pb_distro_init($odir,$over); pb_log(2,"DEBUG: distro tuple: ".join(',',($ddir, $dver, $dfam, $dtype, $pbsuf))."\n"); # Get list of packages to build # Get content saved in cms2build my ($pkg) = pb_conf_read("$ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb","pbpkg"); $pkg = { } if (not defined $pkg); my $src = ""; chdir "$ENV{'PBBUILDDIR'}"; foreach my $pbpkg (@pkgs) { my $vertag = $pkg->{$pbpkg}; # get the version of the current package - maybe different ($pbver,$pbtag) = split(/-/,$vertag); if (($cmt eq "Sources") || ($cmt eq "vm") || ($cmt eq "ve")) { $src = "$src $ENV{'PBDESTDIR'}/$pbpkg-$pbver.tar.gz"; if ($cmd eq "") { $cmd = "ln -sf $pbpkg-$pbver.tar.gz $pbpkg-latest.tar.gz"; } else { $cmd = "$cmd ; ln -sf $pbpkg-$pbver.tar.gz $pbpkg-latest.tar.gz"; } } } if (($cmt eq "vm") || ($cmt eq "ve")) { $src="$src $ENV{'PBDESTDIR'}/pbscript $ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb $ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb $ENV{'PBETC'} $ENV{'PBDESTDIR'}/pbrc"; } elsif ($cmt eq "Script") { $src="$src $ENV{'PBDESTDIR'}/pbscript"; } elsif ($cmt eq "Packages") { # Get package list from file made during build2pkg open(KEEP,"$ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}") || die "Unable to read $ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}"; $src = ; chomp($src); close(KEEP); if ($dtype eq "rpm") { # Also make a pbscript to generate yum/urpmi bases # $src = "$src $ENV{'PBDESTDIR'}/pbscript" } elsif ($dtype eq "deb") { # Also make a pbscript to generate apt bases # $src = "$src $ENV{'PBDESTDIR'}/pbscript" } } # Remove potential leading spaces (cause problem with basename) $src =~ s/^ *//; my $basesrc = ""; foreach my $i (split(/ +/,$src)) { $basesrc .= " ".basename($i); } pb_log(0,"Sources handled ($cmt): $src\n"); pb_log(2,"values: ".Dumper(($host,$login,$dir,$port,$tmout,$rebuild,$path,$conf))."\n"); my ($sshhost,$sshlogin,$sshdir,$sshport,$vtmout,$vrebuild,$vepath,$veconf) = pb_conf_get($host,$login,$dir,$port,$tmout,$rebuild,$path,$conf); pb_log(2,"ssh: ".Dumper(($sshhost,$sshlogin,$sshdir,$sshport,$vtmout,$vrebuild,$vepath,$veconf))."\n"); # Not mandatory my ($testver) = pb_conf_get_if("testver"); my $mac; # Useless for VE if ($cmt ne "ve") { $mac = "$sshlogin->{$ENV{'PBPROJ'}}\@$sshhost->{$ENV{'PBPROJ'}}"; # Overwrite account value if passed as parameter $mac = "$pbaccount\@$sshhost->{$ENV{'PBPROJ'}}" if (defined $pbaccount); pb_log(2, "DEBUG: pbaccount: $pbaccount => mac: $mac\n") if (defined $pbaccount); } my $tdir; my $bdir; if (($cmt eq "Sources") || ($cmt eq "Script")) { $tdir = "$sshdir->{$ENV{'PBPROJ'}}/src"; } elsif (($cmt eq "vm") || ($cmt eq "ve")) { $tdir = $sshdir->{$ENV{'PBPROJ'}}."/$ENV{'PBPROJ'}/delivery"; $bdir = $sshdir->{$ENV{'PBPROJ'}}."/$ENV{'PBPROJ'}/build"; # Remove a potential $ENV{'HOME'} as bdir should be relative to pb's home $bdir =~ s|\$ENV.+\}/||; } elsif ($cmt eq "Packages") { $tdir = "$sshdir->{$ENV{'PBPROJ'}}/$ddir/$dver"; if ((defined $testver) && (defined $testver->{$ENV{'PBPROJ'}}) && ($testver->{$ENV{'PBPROJ'}} =~ /true/i)) { # This is a test pkg => target dir is under test $tdir .= "/test"; } } else { return; } # Useless for VE my $nport; if ($cmt ne "ve") { $nport = $sshport->{$ENV{'PBPROJ'}}; $nport = "$pbport" if (defined $pbport); } # Remove a potential $ENV{'HOME'} as tdir should be relative to pb's home $tdir =~ s|\$ENV.+\}/||; my $tm = $vtmout->{$ENV{'PBPROJ'}}; # ssh communication if not VE # should use a hash instead... my ($shcmd,$cpcmd,$cptarget,$cp2target); if ($cmt ne "ve") { my $keyfile = pb_ssh_get(0); $shcmd = "ssh -i $keyfile -q -p $nport $mac"; $cpcmd = "scp -i $keyfile -p -P $nport"; $cptarget = "$mac:$tdir"; if ($cmt eq "vm") { $cp2target = "$mac:$bdir"; } } else { my $tp = $vepath->{$ENV{'PBPROJ'}}; $shcmd = "sudo chroot $tp/$v /bin/su - $sshlogin->{$ENV{'PBPROJ'}} -c "; $cpcmd = "cp -a "; $cptarget = "$tp/$tdir"; $cp2target = "$tp/$bdir"; } pb_system("$shcmd \"mkdir -p $tdir ; cd $tdir ; echo \'for i in $basesrc; do if [ -f \$i ]; then rm -f \$i; fi; done\ ; $cmd' | bash\"","Preparing $tdir on $cptarget"); pb_system("cd $ENV{'PBBUILDDIR'} ; $cpcmd $src $cptarget 2> /dev/null","$cmt delivery in $cptarget"); # For VE we need to change the owner manually - To be tested if needed #if ($cmt eq "ve") { #pb_system("cd $cptarget ; sudo chown -R $sshlogin->{$ENV{'PBPROJ'}} .","$cmt chown in $cptarget to $sshlogin->{$ENV{'PBPROJ'}}"); #} pb_system("$shcmd \"echo \'cd $tdir ; if [ -f pbscript ]; then ./pbscript; fi\' | bash\"","Executing pbscript on $cptarget if needed"); if (($cmt eq "vm") || ($cmt eq "ve")) { # Get back info on pkg produced, compute their name and get them from the VM pb_system("$cpcmd $cp2target/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'} $ENV{'PBBUILDDIR'} 2> /dev/null","Get package names in $cp2target"); open(KEEP,"$ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}") || die "Unable to read $ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}"; my $src = ; chomp($src); close(KEEP); $src =~ s/^ *//; pb_mkdir_p("$ENV{'PBBUILDDIR'}/$odir/$over"); # Change pgben to make the next send2target happy my $made = ""; open(KEEP,"> $ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}") || die "Unable to write $ENV{'PBBUILDDIR'}/pbgen-$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}"; foreach my $p (split(/ +/,$src)) { my $j = basename($p); pb_system("$cpcmd $cp2target/\'$p\' $ENV{'PBBUILDDIR'}/$odir/$over 2> /dev/null","Package recovery of $j in $cp2target"); $made="$made $odir/$over/$j" if (($dtype ne "rpm") || ($j !~ /.src.rpm$/)); } print KEEP "$made\n"; close(KEEP); pb_system("$shcmd \"rm -rf $tdir $bdir\"","$cmt cleanup"); # We want to send them to the ssh account so overwrite what has been done before undef $pbaccount; pb_log(2,"Before sending pkgs, vmexist: $vmexist, vmpid: $vmpid\n"); pb_send2target("Packages",$odir."-".$over."-".$oarch,$vmexist,$vmpid); if ((! $vmexist) && ($cmt eq "vm")) { pb_system("$shcmd \"sudo /sbin/halt -p \"; sleep $tm ; echo \'if [ -d /proc/$vmpid ]; then kill -9 $vmpid; fi \' | bash ; sleep 10","VM $v halt (pid $vmpid)"); } pb_rm_rf("$ENV{'PBBUILDDIR'}/$odir"); } } sub pb_script2v { my $pbscript=shift; my $vtype=shift; # Prepare the script to be executed on the VM # in $ENV{'PBDESTDIR'}/pbscript if ((defined $pbscript ) && ($pbscript ne "$ENV{'PBDESTDIR'}/pbscript")) { copy($pbscript,"$ENV{'PBDESTDIR'}/pbscript") || die "Unable to create $ENV{'PBDESTDIR'}/pbscript"; chmod 0755,"$ENV{'PBDESTDIR'}/pbscript"; } my ($vm,$all) = pb_get_v($vtype); my ($vmexist,$vmpid) = (undef,undef); foreach my $v (@$vm) { # Launch the VM/VE if ($vtype eq "vm") { ($vmexist,$vmpid) = pb_launchv($vtype,$v,0); # Skip that VM if something went wrong next if (($vmpid == 0) && ($vmexist ==0)); } # Gather all required files to send them to the VM # and launch the build through pbscript pb_send2target("Script","$v",$vmexist,$vmpid); } } sub pb_launchv { my $vtype = shift; my $v = shift; my $create = shift || 0; # By default do not create a VM die "No VM/VE defined, unable to launch" if (not defined $v); # Keep only the first VM in case many were given $v =~ s/,.*//; # Which is our local arch ? (standardize on i386 for those platforms) my $arch = `uname -m`; chomp($arch); $arch =~ s/i.86/i386/; # Launch the VMs/VEs if ($vtype eq "vm") { die "-i iso parameter needed" if (((not defined $iso) || ($iso eq "")) && ($create != 0)); my ($ptr,$vmopt,$vmport,$vmpath,$vmtmout,$vmsize) = pb_conf_get("vmtype","vmopt","vmport","vmpath","vmtmout","vmsize"); my $vmtype = $ptr->{$ENV{'PBPROJ'}}; if (not defined $ENV{'PBVMOPT'}) { $ENV{'PBVMOPT'} = ""; } if (defined $vmopt->{$ENV{'PBPROJ'}}) { $ENV{'PBVMOPT'} .= " $vmopt->{$ENV{'PBPROJ'}}" if ($ENV{'PBVMOPT'} !~ / $vmopt->{$ENV{'PBPROJ'}}/); } my $nport = $vmport->{$ENV{'PBPROJ'}}; $nport = "$pbport" if (defined $pbport); my $cmd; my $vmcmd; # has to be used for pb_check_ps my $vmm; # has to be used for pb_check_ps if ($vmtype eq "qemu") { my $qemucmd32; my $qemucmd64; if ($arch eq "x86_64") { $qemucmd32 = "/usr/bin/qemu-system-i386"; $qemucmd64 = "/usr/bin/qemu"; } else { $qemucmd32 = "/usr/bin/qemu"; $qemucmd64 = "/usr/bin/qemu-system-x86_64"; } if ($v =~ /x86_64/) { $vmcmd = "$qemucmd64 -no-kqemu"; } else { $vmcmd = "$qemucmd32"; } $vmm = "$vmpath->{$ENV{'PBPROJ'}}/$v.qemu"; if ($create != 0) { $ENV{'PBVMOPT'} .= " -cdrom $iso -boot d"; } $cmd = "$vmcmd $ENV{'PBVMOPT'} -redir tcp:$nport:10.0.2.15:22 $vmm" } elsif ($vmtype eq "xen") { } elsif ($vmtype eq "vmware") { } else { die "VM of type $vmtype not supported. Report to the dev team"; } my ($tmpcmd,$void) = split(/ +/,$cmd); my $vmexist = pb_check_ps($tmpcmd,$vmm); my $vmpid = 0; if (! $vmexist) { if ($create != 0) { if (($vmtype eq "qemu") || ($vmtype eq "xen")) { pb_system("/usr/bin/qemu-img create -f qcow2 $vmm $vmsize->{$ENV{'PBPROJ'}}","Creating the QEMU VM"); } elsif ($vmtype eq "vmware") { } else { } } if (! -f "$vmm") { pb_log(0,"Unable to find VM $vmm\n"); } else { pb_system("$cmd &","Launching the VM $vmm"); pb_system("sleep $vmtmout->{$ENV{'PBPROJ'}}","Waiting for VM $v to come up"); $vmpid = pb_check_ps($tmpcmd,$vmm); pb_log(0,"VM $vmm launched (pid $vmpid)\n"); } } else { pb_log(0,"Found an existing VM $vmm (pid $vmexist)\n"); } return($vmexist,$vmpid); # VE here } else { # Get VE context my ($ptr,$vepath,$vetmout,$verebuild,$veconf) = pb_conf_get("vetype","vepath","vetmout","verebuild","veconf"); my $vetype = $ptr->{$ENV{'PBPROJ'}}; # Get distro context my ($name,$ver,$darch) = split(/-/,$v); chomp($darch); my ($ddir, $dver, $dfam, $dtype, $pbsuf) = pb_distro_init($name,$ver); if ($vetype eq "chroot") { # Architecture consistency if ($arch ne $darch) { die "Unable to launch a VE of architecture $darch on a $arch platform" if (not (($darch eq "x86_64") && ($arch =~ /i?86/))); } if (($create != 0) || ($verebuild->{$ENV{'PBPROJ'}} eq "true") || ($force == 1)) { # We have to rebuild the chroot if ($dtype eq "rpm") { pb_system("sudo /usr/sbin/mock --init --resultdir=\"/tmp\" --configdir=\"$veconf->{$ENV{'PBPROJ'}}\" -r $v","Creating the mock VE"); # Once setup we need to install some packages, the pb account, ... pb_system("sudo /usr/sbin/mock --install --configdir=\"$veconf->{$ENV{'PBPROJ'}}\" -r $v su","Configuring the mock VE"); #pb_system("sudo /usr/sbin/mock --init --resultdir=\"/tmp\" --configdir=\"$veconf->{$ENV{'PBPROJ'}}\" --basedir=\"$vepath->{$ENV{'PBPROJ'}}\" -r $v","Creating the mock VE"); } elsif ($dtype eq "deb") { pb_system("","Creating the pbuilder VE"); } elsif ($dtype eq "ebuild") { die "Please teach the dev team how to build gentoo chroot"; } else { die "Unknown distribution type $dtype. Report to dev team"; } } # Nothing more to do for VE. No real launch } else { die "VE of type $vetype not supported. Report to the dev team"; } } } sub pb_build2v { my $vtype = shift; # Prepare the script to be executed on the VM/VE # in $ENV{'PBDESTDIR'}/pbscript #my ($ntp) = pb_conf_get($vtype."ntp"); #my $vntp = $ntp->{$ENV{'PBPROJ'}}; open(SCRIPT,"> $ENV{'PBDESTDIR'}/pbscript") || die "Unable to create $ENV{'PBDESTDIR'}/pbscript"; print SCRIPT "#!/bin/bash\n"; print SCRIPT "echo ... Execution needed\n"; print SCRIPT "# This is in directory delivery\n"; print SCRIPT "# Setup the variables required for building\n"; print SCRIPT "export PBPROJ=$ENV{'PBPROJ'}\n"; print SCRIPT "# Preparation for pb\n"; print SCRIPT "mv .pbrc \$HOME\n"; print SCRIPT "cd ..\n"; # Force new date to be in the future compared to the date of the tar file by adding 1 minute my @date=pb_get_date(); $date[1]++; my $upddate = strftime("%m%d%H%M%Y", @date); #print SCRIPT "echo Setting up date on $vntp...\n"; # Or use ntpdate if available TBC print SCRIPT "sudo date $upddate\n"; # Get list of packages to build and get some ENV vars as well my $ptr = pb_get_pkg(); @pkgs = @$ptr; my $p = join(' ',@pkgs) if (@pkgs); print SCRIPT "export PBPROJVER=$ENV{'PBPROJVER'}\n"; print SCRIPT "export PBPROJTAG=$ENV{'PBPROJTAG'}\n"; print SCRIPT "export PBPACKAGER=\"$ENV{'PBPACKAGER'}\"\n"; print SCRIPT "# Build\n"; print SCRIPT "echo Building packages on $vtype...\n"; print SCRIPT "pb -p $ENV{'PBPROJ'} build2pkg $p\n"; close(SCRIPT); chmod 0755,"$ENV{'PBDESTDIR'}/pbscript"; my ($v,$all) = pb_get_v($vtype); # Send tar files when we do a global generation pb_build2ssh() if ($all == 1); my ($vmexist,$vmpid) = (undef,undef); foreach my $v (@$v) { if ($vtype eq "vm") { # Launch the VM ($vmexist,$vmpid) = pb_launchv($vtype,$v,0); # Skip that VM if it something went wrong next if (($vmpid == 0) && ($vmexist == 0)); } # Gather all required files to send them to the VM/VE # and launch the build through pbscript pb_log(2,"Calling send2target $vtype,$v,$vmexist,$vmpid\n"); pb_send2target($vtype,"$v",$vmexist,$vmpid); } } sub pb_newver { die "-V Version parameter needed" if ((not defined $newver) || ($newver eq "")); # Need this call for PBDIR my ($scheme2,$uri) = pb_cms_init($pbinit); my ($pbconf) = pb_conf_read("$ENV{'PBETC'}","pbconfurl"); $uri = $pbconf->{$ENV{'PBPROJ'}}; my ($scheme, $account, $host, $port, $path) = pb_get_uri($uri); # Checking CMS repositories status my ($pburl) = pb_conf_get("pburl"); ($scheme2, $account, $host, $port, $path) = pb_get_uri($pburl->{$ENV{'PBPROJ'}}); if ($scheme !~ /^svn/) { die "Only SVN is supported at the moment"; } my $res = pb_cms_isdiff($scheme,$ENV{'PBROOTDIR'}); die "ERROR: No differences accepted in CMS for $ENV{'PBROOTDIR'} before creating a new version" if ($res != 0); $res = pb_cms_isdiff($scheme2,$ENV{'PBDIR'}); die "ERROR: No differences accepted in CMS for $ENV{'PBDIR'} before creating a new version" if ($res != 0); # Tree identical between PBCONFDIR and PBROOTDIR. The delta is what # we want to get for the root of the new URL my $tmp = $ENV{'PBROOTDIR'}; $tmp =~ s|^$ENV{'PBCONFDIR'}||; my $newurl = "$uri/".dirname($tmp)."/$newver"; # Should probably use projver in the old file my $oldver= basename($tmp); # Checking pbcl files foreach my $f (<$ENV{'PBROOTDIR'}/*/pbcl>) { open(PBCL,$f) || die "Unable to open $f"; my $foundnew = 0; while () { $foundnew = 1 if (/^$newver \(/); } close(PBCL); die "ERROR: version $newver not found in $f" if ($foundnew == 0); } # Duplicate and extract project-builder part pb_log(2,"Copying $uri/$tmp to $newurl\n"); pb_cms_copy($scheme,"$uri/$tmp",$newurl); pb_log(2,"Checkout $newurl to $ENV{'PBROOTDIR'}/../$newver\n"); pb_cms_up($scheme,"$ENV{'PBCONFDIR'}/.."); # Duplicate and extract project my $newurl2 = "$pburl->{$ENV{'PBPROJ'}}/".dirname($tmp)."/$newver"; pb_log(2,"Copying $pburl->{$ENV{'PBPROJ'}}/$tmp to $newurl2\n"); pb_cms_copy($scheme,"$pburl->{$ENV{'PBPROJ'}}/$tmp",$newurl2); pb_log(2,"Checkout $newurl2 to $ENV{'PBDIR'}/../$newver\n"); pb_cms_up($scheme,"$ENV{'PBDIR'}/.."); # Update the .pb file open(FILE,"$ENV{'PBROOTDIR'}/../$newver/$ENV{'PBPROJ'}.pb") || die "Unable to open $ENV{'PBROOTDIR'}/../$newver/$ENV{'PBPROJ'}.pb"; open(OUT,"> $ENV{'PBROOTDIR'}/../$newver/$ENV{'PBPROJ'}.pb.new") || die "Unable to write to $ENV{'PBROOTDIR'}/../$newver/$ENV{'PBPROJ'}.pb.new"; while() { s/^projver\s+$ENV{'PBPROJ'}\s*=\s*$oldver/projver $ENV{'PBPROJ'} = $newver/; pb_log(0,"Changing projver from $oldver to $newver in $ENV{'PBROOTDIR'}/../$newver/$ENV{'PBPROJ'}.pb\n") if (/^projver\s+$ENV{'PBPROJ'}\s*=\s*$oldver/); s/^testver/#testver/; pb_log(0,"Commenting testver in $ENV{'PBROOTDIR'}/../$newver/$ENV{'PBPROJ'}.pb\n") if (/^testver/); print OUT $_; } close(FILE); close(OUT); rename("$ENV{'PBROOTDIR'}/../$newver/$ENV{'PBPROJ'}.pb.new","$ENV{'PBROOTDIR'}/../$newver/$ENV{'PBPROJ'}.pb"); pb_log(2,"Checkin $ENV{'PBROOTDIR'}/../$newver\n"); pb_cms_checkin($scheme,"$ENV{'PBROOTDIR'}/../$newver"); } # # Return the list of VMs/VEs we are working on # $all is a flag to know if we return all of them # or only some (if all we publish also tar files in addition to pkgs # sub pb_get_v { my $vtype = shift; my @v; my $all = 0; my $vlist; my $pbv = 'PBV'; if ($vtype eq "vm") { $vlist = "vmlist"; } elsif ($vtype eq "ve") { $vlist = "velist"; } # Get VM/VE list if ((not defined $ENV{$pbv}) || ($ENV{$pbv} =~ /^all$/)) { my ($ptr) = pb_conf_get($vlist); $ENV{$pbv} = $ptr->{$ENV{'PBPROJ'}}; $all = 1; } pb_log(2,"$vtype: $ENV{$pbv}\n"); @v = split(/,/,$ENV{$pbv}); return(\@v,$all); } # Function to create a potentialy missing pb account on the VM/VE, and adds it to sudo # Needs to use root account to connect to the VM/VE # pb will take your local public SSH key to access # the pb account in the VM later on if needed sub pb_setup_v { my $vtype = shift; my ($vm,$all) = pb_get_v($vtype); # Script generated my $pbscript = "$ENV{'PBDESTDIR'}/setupv"; foreach my $v (@$vm) { # Name of the account to deal with for VM/VE # Do not use the one passed potentially with -a my ($pbac) = pb_conf_get($vtype."login"); my ($key,$zero0,$zero1,$zero2); my ($vmexist,$vmpid); if ($vtype eq "vm") { # Prepare the key to be used and transfered remotely my $keyfile = pb_ssh_get(1); my ($vmhost,$vmport) = pb_conf_get("vmhost","vmport"); my $nport = $vmport->{$ENV{'PBPROJ'}}; $nport = "$pbport" if (defined $pbport); # Launch the VM ($vmexist,$vmpid) = pb_launchv($vtype,$v,0); # Skip that VM if something went wrong return if (($vmpid == 0) && ($vmexist == 0)); # Store the pub key part in a variable open(FILE,"$keyfile.pub") || die "Unable to open $keyfile.pub"; ($zero0,$zero1,$zero2) = split(/ /,); close(FILE); $key = "\Q$zero1"; pb_system("cat $keyfile.pub | ssh -q -p $nport -i $keyfile root\@$vmhost->{$ENV{'PBPROJ'}} \"mkdir -p .ssh ; chmod 700 .ssh ; cat >> .ssh/authorized_keys ; chmod 600 .ssh/authorized_keys\"","Copying local keys to $vtype. This will require the root password"); # once this is done, we can do what we want on the VM remotely } # Prepare the script to be executed on the VM/VE # in $ENV{'PBDESTDIR'}/setupv open(SCRIPT,"> $pbscript") || die "Unable to create $pbscript"; print SCRIPT << 'EOF'; #!/usr/bin/perl -w use strict; use File::Copy; EOF if ($vtype eq "vm") { print SCRIPT << 'EOF'; # Removes duplicate in .ssh/authorized_keys of our key if needed # my $file1="$ENV{'HOME'}/.ssh/authorized_keys"; open(PBFILE,$file1) || die "Unable to open $file1"; open(PBOUT,"> $file1.new") || die "Unable to open $file1.new"; my $count = 0; while () { EOF print SCRIPT << "EOF"; if (/ $key /) { \$count++; } print PBOUT \$_ if ((\$count <= 1) || (\$_ !~ / $key /)); } close(PBFILE); close(PBOUT); rename("\$file1.new",\$file1); chmod 0600,\$file1; EOF } print SCRIPT << 'EOF'; # Adds $pbac->{$ENV{'PBPROJ'}} as an account if needed # my $file="/etc/passwd"; open(PBFILE,$file) || die "Unable to open $file"; my $found = 0; while () { EOF print SCRIPT << "EOF"; \$found = 1 if (/^$pbac->{$ENV{'PBPROJ'}}:/); EOF print SCRIPT << 'EOF'; } close(PBFILE); if ( $found == 0 ) { if ( ! -d "/home" ) { mkdir "/home"; } EOF print SCRIPT << "EOF"; system "groupadd $pbac->{$ENV{'PBPROJ'}}"; system "useradd $pbac->{$ENV{'PBPROJ'}} -g $pbac->{$ENV{'PBPROJ'}} -m -d /home/$pbac->{$ENV{'PBPROJ'}}"; # allow ssh entry to build # chdir "/home/$pbac->{$ENV{'PBPROJ'}}"; mkdir ".ssh",0700; # Allow those accessing root to access the build account copy("\$ENV{'HOME'}/.ssh/authorized_keys",".ssh/authorized_keys"); chmod 0600,".ssh/authorized_keys"; system 'chown -R $pbac->{$ENV{'PBPROJ'}}:$pbac->{$ENV{'PBPROJ'}} .ssh'; EOF print SCRIPT << 'EOF'; } # No passwd for build account only keys $file="/etc/shadow"; open(PBFILE,$file) || die "Unable to open $file"; open(PBOUT,"> $file.new") || die "Unable to open $file.new"; while () { EOF print SCRIPT << "EOF"; s/^$pbac->{$ENV{'PBPROJ'}}:\!\!:/$pbac->{$ENV{'PBPROJ'}}:*:/; s/^$pbac->{$ENV{'PBPROJ'}}:\!:/$pbac->{$ENV{'PBPROJ'}}:*:/; #SLES 9 e.g. EOF print SCRIPT << 'EOF'; print PBOUT $_; } close(PBFILE); close(PBOUT); rename("$file.new",$file); chmod 0640,$file; # pb has to be added to portage group on gentoo # Adapt sudoers $file="/etc/sudoers"; open(PBFILE,$file) || die "Unable to open $file"; open(PBOUT,"> $file.new") || die "Unable to open $file.new"; while () { EOF print SCRIPT << "EOF"; next if (/^$pbac->{$ENV{'PBPROJ'}} /); EOF print SCRIPT << 'EOF'; s/Defaults[ \t]+requiretty//; print PBOUT $_; } close(PBFILE); EOF print SCRIPT << "EOF"; # This is needed in order to be able to halt the machine from the $pbac->{$ENV{'PBPROJ'}} account at least print PBOUT "$pbac->{$ENV{'PBPROJ'}} ALL=(ALL) NOPASSWD:ALL\n"; EOF print SCRIPT << 'EOF'; close(PBOUT); rename("$file.new",$file); chmod 0440,$file; EOF my $SCRIPT = \*SCRIPT; pb_install_deps($SCRIPT); print SCRIPT << 'EOF'; # Suse wants sudoers as 640 if (($ddir eq "sles") || (($ddir eq "suse")) && ($dver ne "10.3")) { chmod 0640,$file; } # Sync date #system "/usr/sbin/ntpdate ntp.pool.org"; system "rm -rf project-builder-* ; wget --passive-ftp ftp://ftp.mondorescue.org/src/project-builder-latest.tar.gz ; tar xvfz project-builder-latest.tar.gz ; cd project-builder-* ; perl Makefile.PL ; make ; make install ; cd .. ; rm -rf project-builder-*"; system "pb 2>&1 | head -5"; EOF if ((! $vmexist) && ($vtype eq "vm")) { print SCRIPT << 'EOF'; system "sudo /sbin/halt -p"; EOF } # Adds pb_distro_init from ProjectBuilder::Distribution foreach my $d (@INC) { my $f = "$d/ProjectBuilder/Distribution.pm"; if (-f "$f") { open(PBD,"$f") || die "Unable to open $f"; while () { next if (/^package/); next if (/^use Exporter/); next if (/^\@our /); print SCRIPT $_; } close(PBD); last; } } close(SCRIPT); chmod 0755,"$pbscript"; # That build script needs to be run as root $pbaccount = "root"; pb_script2v($pbscript,$vtype); } return; } sub pb_install_deps { my $SCRIPT = shift; print {$SCRIPT} << 'EOF'; # We need to have that pb_distro_init function # Get it from Project-Builder::Distribution my ($ddir, $dver, $dfam, $dtype, $pbsuf) = pb_distro_init(); print "distro tuple: ".join(',',($ddir, $dver, $dfam, $dtype, $pbsuf))."\n"; # Get and install pb my $insdm = "rm -rf Date-Manip* ; wget http://search.cpan.org/CPAN/authors/id/S/SB/SBECK/Date-Manip-5.48.tar.gz ; tar xvfz Date-Manip-5.48.tar.gz ; cd Date-Manip* ; perl Makefile.PL ; make ; make install ; cd .. ; rm -rf Date-Manip*"; my $insmb = "rm -rf Module-Build* ; wget http://search.cpan.org/CPAN/authors/id/K/KW/KWILLIAMS/Module-Build-0.2808.tar.gz ; tar xvfz Module-Build-0.2808.tar.gz ; cd Module-Build* ; perl Makefile.PL ; make ; make install ; cd .. ; rm -rf Module-Build*"; my $insfm = "rm -rf File-MimeInfo* ; wget http://search.cpan.org/CPAN/authors/id/P/PA/PARDUS/File-MimeInfo/File-MimeInfo-0.15.tar.gz ; tar xvfz File-MimeInfo-0.15.tar.gz ; cd File-MimeInfo* ; perl Makefile.PL ; make ; make install ; cd .. ; rm -rf File-MimeInfo*"; my $insfb = "rm -rf File-Basedir* ; wget http://search.cpan.org/CPAN/authors/id/P/PA/PARDUS/File-BaseDir-0.03.tar.gz ; tar xvfz File-BaseDir-0.03.tar.gz ; cd File-BaseDir* ; perl Makefile.PL ; make ; make install ; cd .. ; rm -rf File-BaseDir*"; if ( $ddir eq "fedora" ) { system "yum clean all"; #system "yum update -y"; my $arch=`uname -m`; my $opt = ""; chomp($arch); if ($arch eq "x86_64") { $opt="--exclude=*.i?86"; } system "yum -y $opt install rpm-build wget patch ntp sudo perl-DateManip perl-File-MimeInfo perl-ExtUtils-MakeMaker"; if ($dver eq 4) { system "$insmb"; system "$insfm"; system "$insfb"; } } elsif (( $dfam eq "rh" ) || ($ddir eq "sles") || (($ddir eq "suse") && (($dver eq "10.1") || ($dver eq "10.0"))) || ($ddir eq "slackware")) { # Suppose pkg are installed already as no online mirror available system "rpm -e lsb 2>&1 > /dev/null"; system "$insdm"; system "$insmb"; system "$insfm"; system "$insfb"; } elsif ($ddir eq "suse") { # New OpenSuSE system "$insmb"; system "$insfm"; system "$insfb"; system "export TERM=linux ; liste=\"\" ; for i in make wget patch sudo perl-DateManip perl-File-HomeDir xntp; do rpm -q \$i 1> /dev/null 2> /dev/null ; if [ \$\? != 0 ]; then liste=\"\$liste \$i\"; fi; done; echo \"Liste: \$liste\" ; if [ \"\$liste\" != \"\" ]; then yast2 -i \$liste ; fi"; } elsif ( $dfam eq "md" ) { system "urpmi.update -a ; urpmi --auto rpm-build wget sudo patch ntp-client perl-File-MimeInfo"; if (($ddir eq "mandrake") && ($dver eq "10.1")) { system "$insdm"; } else { system "urpmi --auto perl-DateManip"; } } elsif ( $dfam eq "du" ) { if (( $dver eq "3.1" ) && ($ddir eq "debian")) { #system "apt-get update"; system "$insfb"; system "$insfm"; system "apt-get -y install wget patch ssh sudo debian-builder dh-make fakeroot ntpdate libmodule-build-perl libdate-manip-perl"; } else { system "apt-get update; apt-get -y install wget patch openssh-server dpkg-dev sudo debian-builder dh-make fakeroot ntpdate libfile-mimeinfo-perl libmodule-build-perl libdate-manip-perl"; } } elsif ( $dfam eq "gen" ) { #system "emerge -u system ; emerge wget sudo ntp DateManip File-MimeInfo"; system "emerge wget sudo ntp DateManip File-MimeInfo"; } else { print "No pkg to install\n"; } EOF } # Return the SSH key file to use # Potentially create it if needed sub pb_ssh_get { my $create = shift || 0; # Do not create keys by default # Check the SSH environment my $keyfile = undef; # We have specific keys by default $keyfile = "$ENV{'HOME'}/.ssh/pb_dsa"; if (!(-e $keyfile) && ($create eq 1)) { pb_system("ssh-keygen -q -b 1024 -N '' -f $keyfile -t dsa","Generating SSH keys for pb"); } $keyfile = "$ENV{'HOME'}/.ssh/id_rsa" if (-s "$ENV{'HOME'}/.ssh/id_rsa"); $keyfile = "$ENV{'HOME'}/.ssh/id_dsa" if (-s "$ENV{'HOME'}/.ssh/id_dsa"); $keyfile = "$ENV{'HOME'}/.ssh/pb_dsa" if (-s "$ENV{'HOME'}/.ssh/pb_dsa"); die "Unable to find your public ssh key under $keyfile" if (not defined $keyfile); return($keyfile); } # Returns the pid of a running VM command using a specific VM file sub pb_check_ps { my $vmcmd = shift; my $vmm = shift; my $vmexist = 0; # FALSE by default open(PS, "ps auxhww|") || die "Unable to call ps"; while () { next if (! /$vmcmd/); next if (! /$vmm/); my ($void1, $void2); ($void1, $vmexist, $void2) = split(/ +/); last; } return($vmexist); } sub pb_extract_build_files { my $src=shift; my $dir=shift; my $ddir=shift; my @files; if ($src =~ /tar\.gz$/) { pb_system("tar xfpz $src $dir","Extracting build files"); } elsif ($src =~ /tar\.bz2$/) { pb_system("tar xfpj $src $dir","Extracting build files"); } else { die "Unknown compression algorithm for $src"; } opendir(DIR,"$dir") || die "Unable to open directory $dir"; foreach my $f (readdir(DIR)) { next if ($f =~ /^\./); move("$dir/$f","$ddir") || die "Unable to move $dir/$f to $ddir"; pb_log(2,"mv $dir/$f $ddir\n"); push @files,"$ddir/$f"; } closedir(DIR); # Not enough but still a first cleanup pb_rm_rf("$dir"); return(@files); } sub pb_list_bfiles { my $dir = shift; my $pbpkg = shift; my $bfiles = shift; my $pkgfiles = shift; my $supfiles = shift; opendir(BDIR,"$dir") || die "Unable to open dir $dir: $!"; foreach my $f (readdir(BDIR)) { next if ($f =~ /^\./); $bfiles->{$f} = "$dir/$f"; $bfiles->{$f} =~ s~$ENV{'PBROOTDIR'}~~; if (defined $supfiles->{$pbpkg}) { $pkgfiles->{$f} = "$dir/$f" if ($f =~ /$supfiles->{$pbpkg}/); } } closedir(BDIR); } sub pb_env_init { my $proj=shift || undef; my $pbinit=shift || undef; my $action=shift; my $ver; my $tag; $ENV{'PBETC'} = "$ENV{'HOME'}/.pbrc"; # # Check project name # Could be with env var PBPROJ # or option -p # if not define take the first in conf file # if ((defined $ENV{'PBPROJ'}) && (not (defined $proj))) { $proj = $ENV{'PBPROJ'}; } # # We get the pbconf file for that project # and use its content # my ($pbconf) = pb_conf_read("$ENV{'PBETC'}","pbconfurl"); pb_log(2,"DEBUG pbconfurl: ".Dumper($pbconf)."\n"); my %pbconf = %$pbconf; if (not defined $proj) { # Take the first as the default project $proj = (keys %pbconf)[0]; if (defined $proj) { pb_log(1,"WARNING: using $proj as default project as none has been specified\n"); pb_log(1," Please either create a pbconfurl reference for project $proj in $ENV{'PBETC'}\n"); pb_log(1," or call pb with the -p project option or use the env var PBPROJ\n"); pb_log(1," if you want to use another project\n"); } } die "No project defined - use env var PBPROJ or -p proj or a pbconfurl entry in $ENV{'PBETC'}" if (not (defined $proj)); # That's always the environment variable that will be used $ENV{'PBPROJ'} = $proj; pb_log(2,"PBPROJ: $ENV{'PBPROJ'}\n"); if (not defined ($pbconf{$ENV{'PBPROJ'}})) { die "Please create a pbconfurl reference for project $ENV{'PBPROJ'} in $ENV{'PBETC'}\n"; } # # Detect the root dir for hosting all the content generated with pb # # Tree will look like this: # # maint pbdefdir PBDEFDIR dev dir (optional) # | | # ------------------------ -------------------- # | | | | # pbproj1 pbproj2 PBPROJ pbproj1 pbproj2 PBPROJDIR # | | # --------------------------------------------- ---------- # * * * | | | * * # tag dev pbconf ... build delivery PBCONFDIR dev tag # | | | PBDESTDIR | # --- ------ pbrc PBBUILDDIR ------- # | | | | | # 1.1 dev tag 1.0 1.1 PBDIR # | # ------- # | | # 1.0 1.1 PBROOTDIR # | # ---------------------------------- # | | | | # pkg1 pbproj1.pb pbfilter pbcl # | # ----------------- # | | | # rpm deb pbfilter # # # (*) By default, if no relocation in .pbrc, dev dir is taken in the maint pbdefdir (when appropriate) # Names under a pbproj and the corresponding pbconf should be similar # my ($pbdefdir) = pb_conf_get_if("pbdefdir"); if (not defined $ENV{'PBDEFDIR'}) { if ((not defined $pbdefdir) || (not defined $pbdefdir->{$ENV{'PBPROJ'}})) { pb_log(1,"WARNING: no pbdefdir defined, using /var/cache\n"); pb_log(1," Please create a pbdefdir reference for project $ENV{'PBPROJ'} in $ENV{'PBETC'}\n"); pb_log(1," if you want to use another directory\n"); $ENV{'PBDEFDIR'} = "/var/cache"; } else { # That's always the environment variable that will be used $ENV{'PBDEFDIR'} = $pbdefdir->{$ENV{'PBPROJ'}}; } } # Expand potential env variable in it eval { $ENV{'PBDEFDIR'} =~ s/(\$ENV.+\})/$1/eeg }; pb_log(2,"PBDEFDIR: $ENV{'PBDEFDIR'}\n"); # # Set delivery directory # $ENV{'PBDESTDIR'}="$ENV{'PBDEFDIR'}/$ENV{'PBPROJ'}/delivery"; pb_log(2,"PBDESTDIR: $ENV{'PBDESTDIR'}\n"); # # Removes all directory existing below the delivery dir # as they are temp dir only # Files stay and have to be cleaned up manually if needed # those files serves as communication channels between pb phases # Removing them prevents a following phase to detect what has been done before # if (-d $ENV{'PBDESTDIR'}) { opendir(DIR,$ENV{'PBDESTDIR'}) || die "Unable to open directory $ENV{'PBDESTDIR'}: $!"; foreach my $d (readdir(DIR)) { next if ($d =~ /^\./); next if (-f "$ENV{'PBDESTDIR'}/$d"); pb_rm_rf("$ENV{'PBDESTDIR'}/$d") if (-d "$ENV{'PBDESTDIR'}/$d"); } closedir(DIR); } if (! -d "$ENV{'PBDESTDIR'}") { pb_mkdir_p($ENV{'PBDESTDIR'}) || die "Unable to recursively create $ENV{'PBDESTDIR'}"; } # # Set build directory # $ENV{'PBBUILDDIR'}="$ENV{'PBDEFDIR'}/$ENV{'PBPROJ'}/build"; if (! -d "$ENV{'PBBUILDDIR'}") { pb_mkdir_p($ENV{'PBBUILDDIR'}) || die "Unable to recursively create $ENV{'PBBUILDDIR'}"; } pb_log(2,"PBBUILDDIR: $ENV{'PBBUILDDIR'}\n"); pb_temp_init(); pb_log(2,"PBTMP: $ENV{'PBTMP'}\n"); # # The following part is only useful when in cms2something of newver # In VMs/VEs we want to skip that by providing good env vars. # return values in that case are useless # if (($action =~ /^cms2/) || ($action =~ /^newver$/)) { # # Check pbconf cms compliance # pb_cms_compliant("pbconfdir",'PBCONFDIR',"$ENV{'PBDEFDIR'}/$ENV{'PBPROJ'}/pbconf",$pbconf{$ENV{'PBPROJ'}},$pbinit); # Check where is our PBROOTDIR (release tag name can't be guessed the first time) # if (not defined $ENV{'PBROOTDIR'}) { if (! -f ("$ENV{'PBDESTDIR'}/pbrc")) { opendir(DIR,$ENV{'PBCONFDIR'}) || die "Unable to open directory $ENV{'PBCONFDIR'}: $!"; my $maxmtime = 0; foreach my $d (readdir(DIR)) { pb_log(3,"Looking at \'$d\'..."); next if ($d =~ /^\./); next if (! -d "$ENV{'PBCONFDIR'}/$d"); my $s = stat("$ENV{'PBCONFDIR'}/$d"); next if (not defined $s); pb_log(3,"KEEP\n"); # Keep the most recent pb_log(2," $s->mtime\n"); if ($s->mtime > $maxmtime) { $ENV{'PBROOTDIR'} = "$ENV{'PBCONFDIR'}/$d"; $maxmtime = $s->mtime; } } closedir(DIR); die "No directory found under $ENV{'PBCONFDIR'}" if (not defined $ENV{'PBROOTDIR'}); pb_log(1,"WARNING: no pbroot defined, using $ENV{'PBROOTDIR'}\n"); pb_log(1," Please use -r release if you want to use another release\n"); } else { my ($pbroot) = pb_conf_read_if("$ENV{'PBDESTDIR'}/pbrc","pbroot"); # That's always the environment variable that will be used die "Please remove inconsistent $ENV{'PBDESTDIR'}/pbrc" if ((not defined $pbroot) || (not defined $pbroot->{$ENV{'PBPROJ'}})); $ENV{'PBROOTDIR'} = $pbroot->{$ENV{'PBPROJ'}}; } } else { # transform in full path if relative $ENV{'PBROOTDIR'} = "$ENV{'PBCONFDIR'}/$ENV{'PBROOTDIR'}" if ($ENV{'PBROOTDIR'} !~ /^\//); pb_mkdir_p($ENV{'PBROOTDIR'}) if (defined $pbinit); die "$ENV{'PBROOTDIR'} is not a directory" if (not -d $ENV{'PBROOTDIR'}); } return if ($action =~ /^newver$/); my %version = (); my %defpkgdir = (); my %extpkgdir = (); my %filteredfiles = (); my %supfiles = (); if ((-f "$ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb") and (not defined $pbinit)) { # List of pkg to build by default (mandatory) my ($defpkgdir,$pbpackager, $pkgv, $pkgt) = pb_conf_get("defpkgdir","pbpackager","projver","projtag"); # List of additional pkg to build when all is called (optional) # Valid version names (optional) # List of files to filter (optional) # Project version and tag (optional) my ($extpkgdir, $version, $filteredfiles, $supfiles) = pb_conf_get_if("extpkgdir","version","filteredfiles","supfiles"); pb_log(2,"DEBUG: defpkgdir: ".Dumper($defpkgdir)."\n"); pb_log(2,"DEBUG: extpkgdir: ".Dumper($extpkgdir)."\n"); pb_log(2,"DEBUG: version: ".Dumper($version)."\n"); pb_log(2,"DEBUG: filteredfiles: ".Dumper($filteredfiles)."\n"); pb_log(2,"DEBUG: supfiles: ".Dumper($supfiles)."\n"); # Global %defpkgdir = %$defpkgdir; %extpkgdir = %$extpkgdir if (defined $extpkgdir); %version = %$version if (defined $version); %filteredfiles = %$filteredfiles if (defined $filteredfiles); %supfiles = %$supfiles if (defined $supfiles); # # Get global Version/Tag # if (not defined $ENV{'PBPROJVER'}) { if ((defined $pkgv) && (defined $pkgv->{$ENV{'PBPROJ'}})) { $ENV{'PBPROJVER'}=$pkgv->{$ENV{'PBPROJ'}}; } else { die "No projver found in $ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb"; } } die "Invalid version name $ENV{'PBPROJVER'} in $ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb" if (($ENV{'PBPROJVER'} !~ /[0-9.]+/) && (not defined $version) && ($ENV{'PBPROJVER'} =~ /$version{$ENV{'PBPROJ'}}/)); if (not defined $ENV{'PBPROJTAG'}) { if ((defined $pkgt) && (defined $pkgt->{$ENV{'PBPROJ'}})) { $ENV{'PBPROJTAG'}=$pkgt->{$ENV{'PBPROJ'}}; } else { die "No projtag found in $ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb"; } } die "Invalid tag name $ENV{'PBPROJTAG'} in $ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb" if ($ENV{'PBPROJTAG'} !~ /[0-9.]+/); if (not defined $ENV{'PBPACKAGER'}) { if ((defined $pbpackager) && (defined $pbpackager->{$ENV{'PBPROJ'}})) { $ENV{'PBPACKAGER'}=$pbpackager->{$ENV{'PBPROJ'}}; } else { die "No pbpackager found in $ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb"; } } } else { if (defined $pbinit) { my $ptr = pb_get_pkg(); my @pkgs = @$ptr; @pkgs = ("pkg1") if (not @pkgs); open(CONF,"> $ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb") || die "Unable to create $ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb"; print CONF << "EOF"; # # Project Builder configuration file # For project $ENV{'PBPROJ'} # # \$Id\$ # # # What is the project URL # #pburl $ENV{'PBPROJ'} = svn://svn.$ENV{'PBPROJ'}.org/$ENV{'PBPROJ'}/devel #pburl $ENV{'PBPROJ'} = svn://svn+ssh.$ENV{'PBPROJ'}.org/$ENV{'PBPROJ'}/devel #pburl $ENV{'PBPROJ'} = cvs://cvs.$ENV{'PBPROJ'}.org/$ENV{'PBPROJ'}/devel #pburl $ENV{'PBPROJ'} = http://www.$ENV{'PBPROJ'}.org/src/$ENV{'PBPROJ'}-devel.tar.gz #pburl $ENV{'PBPROJ'} = ftp://ftp.$ENV{'PBPROJ'}.org/src/$ENV{'PBPROJ'}-devel.tar.gz #pburl $ENV{'PBPROJ'} = file:///src/$ENV{'PBPROJ'}-devel.tar.gz #pburl $ENV{'PBPROJ'} = dir:///src/$ENV{'PBPROJ'}-devel # Check whether project is well formed # (containing already a directory with the project-version name) #pbwf $ENV{'PBPROJ'} = 1 # # Packager label # #pbpackager $ENV{'PBPROJ'} = William Porte # # For delivery to a machine by SSH (potentially the FTP server) # Needs hostname, account and directory # #sshhost $ENV{'PBPROJ'} = www.$ENV{'PBPROJ'}.org #sshlogin $ENV{'PBPROJ'} = bill #sshdir $ENV{'PBPROJ'} = /$ENV{'PBPROJ'}/ftp #sshport $ENV{'PBPROJ'} = 22 # # For Virtual machines management # Naming convention to follow: distribution name (as per ProjectBuilder::Distribution) # followed by '-' and by release number # followed by '-' and by architecture # a .vmtype extension will be added to the resulting string # a QEMU rhel-3-i286 here means that the VM will be named rhel-3-i386.qemu # #vmlist $ENV{'PBPROJ'} = mandrake-10.1-i386,mandrake-10.2-i386,mandriva-2006.0-i386,mandriva-2007.0-i386,mandriva-2007.1-i386,mandriva-2008.0-i386,redhat-7.3-i386,redhat-9-i386,fedora-4-i386,fedora-5-i386,fedora-6-i386,fedora-7-i386,fedora-8-i386,rhel-3-i386,rhel-4-i386,rhel-5-i386,suse-10.0-i386,suse-10.1-i386,suse-10.2-i386,suse-10.3-i386,sles-9-i386,sles-10-i386,gentoo-nover-i386,debian-3.1-i386,debian-4.0-i386,ubuntu-6.06-i386,ubuntu-7.04-i386,ubuntu-7.10-i386,mandriva-2007.0-x86_64,mandriva-2007.1-x86_64,mandriva-2008.0-x86_64,fedora-6-x86_64,fedora-7-x86_64,fedora-8-x86_64,rhel-4-x86_64,rhel-5-x86_64,suse-10.2-x86_64,suse-10.3-x86_64,sles-10-x86_64,gentoo-nover-x86_64,debian-4.0-x86_64,ubuntu-7.04-x86_64,ubuntu-7.10-x86_64 # # Valid values for vmtype are # qemu, (vmware, xen, ... TBD) #vmtype $ENV{'PBPROJ'} = qemu # Hash for VM stuff on vmtype #vmntp default = pool.ntp.org # We suppose we can commmunicate with the VM through SSH #vmhost $ENV{'PBPROJ'} = localhost #vmlogin $ENV{'PBPROJ'} = pb #vmport $ENV{'PBPROJ'} = 2222 # Timeout to wait when VM is launched/stopped #vmtmout default = 120 # per VMs needed paramaters #vmopt $ENV{'PBPROJ'} = -m 384 -daemonize #vmpath $ENV{'PBPROJ'} = /home/qemu #vmsize $ENV{'PBPROJ'} = 5G # # For Virtual environment management # Naming convention to follow: distribution name (as per ProjectBuilder::Distribution) # followed by '-' and by release number # followed by '-' and by architecture # a .vetype extension will be added to the resulting string # a chroot rhel-3-i286 here means that the VE will be named rhel-3-i386.chroot # #velist $ENV{'PBPROJ'} = fedora-7-i386 # VE params #vetype $ENV{'PBPROJ'} = chroot #ventp default = pool.ntp.org #velogin $ENV{'PBPROJ'} = pb #vepath $ENV{'PBPROJ'} = /var/lib/mock #veconf $ENV{'PBPROJ'} = /etc/mock #verebuild $ENV{'PBPROJ'} = false # # Global version/tag for the project # #projver $ENV{'PBPROJ'} = devel #projtag $ENV{'PBPROJ'} = 1 # Hash of valid version names #version $ENV{'PBPROJ'} = devel,stable # Adapt to your needs: # Optional if you need to overwrite the global values above # EOF foreach my $pp (@pkgs) { print CONF << "EOF"; #pkgver $pp = stable #pkgtag $pp = 3 EOF } foreach my $pp (@pkgs) { print CONF << "EOF"; # Hash of default package/package directory #defpkgdir $pp = dir-$pp EOF } print CONF << "EOF"; # Hash of additional package/package directory #extpkgdir minor-pkg = dir-minor-pkg # List of files per pkg on which to apply filters # Files are mentioned relatively to pbroot/defpkgdir EOF foreach my $pp (@pkgs) { print CONF << "EOF"; #filteredfiles $pp = Makefile.PL,configure.in,install.sh,$pp.8 #supfiles $pp = $pp.init EOF } close(CONF); pb_mkdir_p("$ENV{'PBROOTDIR'}/pbfilter") || die "Unable to create $ENV{'PBROOTDIR'}/pbfilter"; open(CONF,"> $ENV{'PBROOTDIR'}/pbfilter/all.pbf") || die "Unable to create $ENV{'PBROOTDIR'}/pbfilter/all.pbf"; print CONF << "EOF"; # # \$Id\$ # # Filter for all files # # PBSRC is replaced by the source package format #filter PBSRC = ftp://ftp.$ENV{'PBPROJ'}.org/src/%{name}-%{version}.tar.gz # PBVER is replaced by the version (\$pbver in code) filter PBVER = \$pbver # PBDATE is replaced by the date (\$pbdate in code) filter PBDATE = \$pbdate # PBLOG is replaced by the changelog if value is yes #filter PBLOG = yes # PBTAG is replaced by the tag (\$pbtag in code) filter PBTAG = \$pbtag # PBREV is replaced by the revision (\$pbrev in code) filter PBREV = \$pbrev # PBPKG is replaced by the package name (\$pbpkg in code) filter PBPKG = \$pbpkg # PBPACKAGER is replaced by the packager name (\$pbpackager in code) filter PBPACKAGER = \$pbpackager # PBDESC contains the description of the package #filter PBDESC = "Bla-Bla" # PBURL contains the URL of the Web site of the project #filter PBURL = http://www.$ENV{'PBPROJ'}.org EOF close(CONF); open(CONF,"> $ENV{'PBROOTDIR'}/pbfilter/rpm.pbf") || die "Unable to create $ENV{'PBROOTDIR'}/pbfilter/rpm.pbf"; print CONF << "EOF"; # # \$Id\$ # # Filter for rpm build # # PBGRP is replaced by the RPM group of apps # Cf: http://fedoraproject.org/wiki/RPMGroups #filter PBGRP = Applications/Archiving # PBLIC is replaced by the license of the application # Cf: http://fedoraproject.org/wiki/Licensing #filter PBLIC = GPL # PBDEP is replaced by the list of dependencies #filter PBDEP = # PBSUF is replaced by the package suffix (\$pbsuf in code) filter PBSUF = \$pbsuf # PBOBS is replaced by the Obsolete line #filter PBOBS = EOF close(CONF); open(CONF,"> $ENV{'PBROOTDIR'}/pbfilter/deb.pbf") || die "Unable to create $ENV{'PBROOTDIR'}/pbfilter/deb.pbf"; print CONF << "EOF"; # # \$Id\$ # # Filter for debian build # # PBGRP is replaced by the group of apps filter PBGRP = utils # PBLIC is replaced by the license of the application # Cf: #filter PBLIC = GPL # PBDEP is replaced by the list of dependencies #filter PBDEP = # PBSUG is replaced by the list of suggestions #filter PBSUG = # PBREC is replaced by the list of recommandations #filter PBREC = EOF close(CONF); open(CONF,"> $ENV{'PBROOTDIR'}/pbfilter/md.pbf") || die "Unable to create $ENV{'PBROOTDIR'}/pbfilter/md.pbf"; print CONF << "EOF"; # Specific group for Mandriva for $ENV{'PBPROJ'} # Cf: http://wiki.mandriva.com/en/Development/Packaging/Groups #filter PBGRP = Archiving/Backup # PBLIC is replaced by the license of the application # Cf: http://wiki.mandriva.com/en/Development/Packaging/Licenses #filter PBLIC = GPL EOF close(CONF); open(CONF,"> $ENV{'PBROOTDIR'}/pbfilter/novell.pbf") || die "Unable to create $ENV{'PBROOTDIR'}/pbfilter/novell.pbf"; print CONF << "EOF"; # Specific group for SuSE for $ENV{'PBPROJ'} # Cf: http://en.opensuse.org/SUSE_Package_Conventions/RPM_Groups #filter PBGRP = Productivity/Archiving/Backup # PBLIC is replaced by the license of the application # Cf: http://en.opensuse.org/Packaging/SUSE_Package_Conventions/RPM_Style#1.6._License_Tag #filter PBLIC = GPL EOF close(CONF); foreach my $pp (@pkgs) { pb_mkdir_p("$ENV{'PBROOTDIR'}/$pp/deb") || die "Unable to create $ENV{'PBROOTDIR'}/$pp/deb"; open(CONF,"> $ENV{'PBROOTDIR'}/$pp/deb/control") || die "Unable to create $ENV{'PBROOTDIR'}/$pp/deb/control"; print CONF << "EOF"; Source: PBPKG Section: PBGRP Priority: optional Maintainer: PBPACKAGER Build-Depends: debhelper (>= 4.2.20), PBDEP Standards-Version: 3.6.1 Package: PBPKG Architecture: amd64 i386 ia64 Section: PBGRP Priority: optional Depends: \${shlibs:Depends}, \${misc:Depends}, PBDEP Recommends: PBREC Suggests: PBSUG Description: PBDESC . Homepage: PBURL EOF close(CONF); open(CONF,"> $ENV{'PBROOTDIR'}/$pp/deb/copyright") || die "Unable to create $ENV{'PBROOTDIR'}/$pp/deb/copyright"; print CONF << "EOF"; This package is debianized by PBPACKAGER `date` The current upstream source was downloaded from ftp://ftp.$ENV{'PBPROJ'}.org/src/. Upstream Authors: Put their name here Copyright: This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 dated June, 1991. This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this package; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL. EOF close(CONF); open(CONF,"> $ENV{'PBROOTDIR'}/$pp/deb/changelog") || die "Unable to create $ENV{'PBROOTDIR'}/$pp/deb/changelog"; print CONF << "EOF"; PBLOG EOF close(CONF); open(CONF,"> $ENV{'PBROOTDIR'}/$pp/deb/compat") || die "Unable to create $ENV{'PBROOTDIR'}/$pp/deb/compat"; print CONF << "EOF"; 4 EOF close(CONF); open(CONF,"> $ENV{'PBROOTDIR'}/$pp/deb/$pp.dirs") || die "Unable to create $ENV{'PBROOTDIR'}/$pp/deb/$pp.dirs"; print CONF << "EOF"; EOF close(CONF); open(CONF,"> $ENV{'PBROOTDIR'}/$pp/deb/$pp.docs") || die "Unable to create $ENV{'PBROOTDIR'}/$pp/deb/$pp.docs"; print CONF << "EOF"; INSTALL COPYING AUTHORS NEWS README EOF close(CONF); open(CONF,"> $ENV{'PBROOTDIR'}/$pp/deb/rules") || die "Unable to create $ENV{'PBROOTDIR'}/$pp/deb/rules"; print CONF << 'EOF'; #!/usr/bin/make -f # -*- makefile -*- # Sample debian/rules that uses debhelper. # GNU copyright 1997 to 1999 by Joey Hess. # # $Id$ # # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 # Define package name variable for a one-stop change. PACKAGE_NAME = PBPKG # These are used for cross-compiling and for saving the configure script # from having to guess our platform (since we know it already) DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) CFLAGS = -Wall -g ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) CFLAGS += -O0 else CFLAGS += -O2 endif ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) INSTALL_PROGRAM += -s endif config.status: configure dh_testdir # Configure the package. CFLAGS="$(CFLAGS)" ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr --mandir=\$${prefix}/share/man # Build both architecture dependent and independent build: build-arch build-indep # Build architecture dependent build-arch: build-arch-stamp build-arch-stamp: config.status dh_testdir # Compile the package. $(MAKE) touch build-stamp # Build architecture independent build-indep: build-indep-stamp build-indep-stamp: config.status # Nothing to do, the only indep item is the manual which is available as html in original source touch build-indep-stamp # Clean up clean: dh_testdir dh_testroot rm -f build-arch-stamp build-indep-stamp #CONFIGURE-STAMP# # Clean temporary document directory rm -rf debian/doc-temp # Clean up. -$(MAKE) distclean rm -f config.log ifneq "$(wildcard /usr/share/misc/config.sub)" "" cp -f /usr/share/misc/config.sub config.sub endif ifneq "$(wildcard /usr/share/misc/config.guess)" "" cp -f /usr/share/misc/config.guess config.guess endif dh_clean # Install architecture dependent and independent install: install-arch install-indep # Install architecture dependent install-arch: build-arch dh_testdir dh_testroot dh_clean -k -s dh_installdirs -s # Install the package files into build directory: # - start with upstream make install $(MAKE) install prefix=$(CURDIR)/debian/$(PACKAGE_NAME)/usr mandir=$(CURDIR)/debian/$(PACKAGE_NAME)/us r/share/man # - copy html manual to temporary location for renaming mkdir -p debian/doc-temp dh_install -s # Install architecture independent install-indep: build-indep dh_testdir dh_testroot dh_clean -k -i dh_installdirs -i dh_install -i # Must not depend on anything. This is to be called by # binary-arch/binary-indep # in another 'make' thread. binary-common: dh_testdir dh_testroot dh_installchangelogs ChangeLog dh_installdocs dh_installman dh_link dh_strip dh_compress dh_fixperms dh_installdeb dh_shlibdeps dh_gencontrol dh_md5sums dh_builddeb # Build architecture independant packages using the common target. binary-indep: build-indep install-indep $(MAKE) -f debian/rules DH_OPTIONS=-i binary-common # Build architecture dependant packages using the common target. binary-arch: build-arch install-arch $(MAKE) -f debian/rules DH_OPTIONS=-a binary-common # Build architecture depdendent and independent packages binary: binary-arch binary-indep .PHONY: clean binary EOF close(CONF); pb_mkdir_p("$ENV{'PBROOTDIR'}/$pp/rpm") || die "Unable to create $ENV{'PBROOTDIR'}/$pp/rpm"; open(CONF,"> $ENV{'PBROOTDIR'}/$pp/rpm/$pp.spec") || die "Unable to create $ENV{'PBROOTDIR'}/$pp/rpm/$pp.spec"; print CONF << 'EOF'; # # $Id$ # Summary: bla-bla Summary(fr): french bla-bla Name: PBPKG Version: PBVER Release: PBTAGPBSUF License: PBLIC Group: PBGRP Url: PBURL Source: PBSRC BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(id -u -n) #Requires: PBDEP %description PBDESC %description -l fr french desc %prep %setup -q %build %configure make %{?_smp_mflags} %install %{__rm} -rf $RPM_BUILD_ROOT make DESTDIR=$RPM_BUILD_ROOT install %clean %{__rm} -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %doc ChangeLog %doc INSTALL COPYING README AUTHORS NEWS %changelog PBLOG EOF close(CONF); pb_mkdir_p("$ENV{'PBROOTDIR'}/$pp/pbfilter") || die "Unable to create $ENV{'PBROOTDIR'}/$pp/pbfilter"; pb_log(0,"\nDo not to forget to commit the pbconf directory in your CMS if needed\n"); } } else { die "Unable to open $ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb"; } } umask 0022; return(\%filteredfiles, \%supfiles, \%defpkgdir, \%extpkgdir); } else { # Setup the variables from what has been stored at the end of cms2build my ($var) = pb_conf_read("$ENV{'PBDESTDIR'}/pbrc","pbroot"); $ENV{'PBROOTDIR'} = $var->{$ENV{'PBPROJ'}}; ($var) = pb_conf_read("$ENV{'PBDESTDIR'}/pbrc","projver"); $ENV{'PBPROJVER'} = $var->{$ENV{'PBPROJ'}}; ($var) = pb_conf_read("$ENV{'PBDESTDIR'}/pbrc","projtag"); $ENV{'PBPROJTAG'} = $var->{$ENV{'PBPROJ'}}; ($var) = pb_conf_read("$ENV{'PBDESTDIR'}/pbrc","pbpackager"); $ENV{'PBPACKAGER'} = $var->{$ENV{'PBPROJ'}}; return; } } # Function which returns a pointer on a table # corresponding to a set of values queried in the conf file # and test the returned vaue as they need to exist in that case sub pb_conf_get { my @param = @_; my @return = pb_conf_get_if(@param); die "No params found for $ENV{'PBPROJ'}" if (not @return); foreach my $i (0..$#param) { die "No $param[$i] defined for $ENV{'PBPROJ'}" if (not defined $return[$i]); } return(@return); } # Function which returns a pointer on a table # corresponding to a set of values queried in the conf file # Those value may be undef if they do not exist sub pb_conf_get_if { my @param = @_; # Everything is returned via ptr1 my @ptr1 = (); my @ptr2 = (); @ptr1 = pb_conf_read_if("$ENV{'PBETC'}", @param) if (defined $ENV{'PBETC'}); @ptr2 = pb_conf_read_if("$ENV{'PBROOTDIR'}/$ENV{'PBPROJ'}.pb", @param) if ((defined $ENV{'PBROOTDIR'}) and (defined $ENV{'PBPROJ'})); my $p1; my $p2; pb_log(2,"DEBUG: pb_conf_get param1: ".Dumper(@ptr1)."\n"); pb_log(2,"DEBUG: pb_conf_get param2: ".Dumper(@ptr2)."\n"); foreach my $i (0..$#param) { $p1 = $ptr1[$i]; $p2 = $ptr2[$i]; # Always try to take the param from the home dir conf file in priority # in order to mask what could be defined under the CMS to allow for overloading if (not defined $p2) { # No ref in CMS project conf file so use the home dir one. $p1->{$ENV{'PBPROJ'}} = $p1->{'default'} if ((not defined $p1->{$ENV{'PBPROJ'}}) && (defined $p1->{'default'})); } else { # Ref found in CMS project conf file if (not defined $p1) { # No ref in home dir project conf file so use the CMS one. $p2->{$ENV{'PBPROJ'}} = $p2->{'default'} if ((not defined $p2->{$ENV{'PBPROJ'}}) && (defined $p2->{'default'})); $p1 = $p2; } else { # Both are defined - handling the overloading if (not defined $p1->{'default'}) { if (defined $p2->{'default'}) { $p1->{'default'} = $p2->{'default'}; } } if (not defined $p1->{$ENV{'PBPROJ'}}) { if (defined $p2->{$ENV{'PBPROJ'}}) { $p1->{$ENV{'PBPROJ'}} = $p2->{$ENV{'PBPROJ'}} if (defined $p2->{$ENV{'PBPROJ'}}); } else { $p1->{$ENV{'PBPROJ'}} = $p1->{'default'} if (defined $p1->{'default'}); } } # Now copy back into p1 all p2 content which doesn't exist in p1 # p1 content (local) always has priority over p2 (project) foreach my $k (keys %$p2) { $p1->{$k} = $p2->{$k} if (not defined $p1->{$k}); } } } $ptr1[$i] = $p1; } pb_log(2,"DEBUG: pb_conf_get param ptr1: ".Dumper(@ptr1)."\n"); return(@ptr1); } # Setup environment for CMS system for URL passed sub pb_cms_init { my $pbinit = shift || undef; my ($pburl) = pb_conf_get("pburl"); pb_log(2,"DEBUG: Project URL of $ENV{'PBPROJ'}: $pburl->{$ENV{'PBPROJ'}}\n"); my ($scheme, $account, $host, $port, $path) = pb_get_uri($pburl->{$ENV{'PBPROJ'}}); my ($pbprojdir) = pb_conf_get_if("pbprojdir"); if ((defined $pbprojdir) && (defined $pbprojdir->{$ENV{'PBPROJ'}})) { $ENV{'PBPROJDIR'} = $pbprojdir->{$ENV{'PBPROJ'}}; } else { $ENV{'PBPROJDIR'} = "$ENV{'PBDEFDIR'}/$ENV{'PBPROJ'}"; } # Computing the default dir for PBDIR. # what we have is PBPROJDIR so work from that. # Tree identical between PBCONFDIR and PBROOTDIR on one side and # PBPROJDIR and PBDIR on the other side. my $tmp = $ENV{'PBROOTDIR'}; $tmp =~ s|^$ENV{'PBCONFDIR'}||; # # Check project cms compliance # pb_cms_compliant(undef,'PBDIR',"$ENV{'PBPROJDIR'}/$tmp",$pburl->{$ENV{'PBPROJ'}},$pbinit); if ($scheme =~ /^svn/) { # svnversion more precise than svn info $tmp = `(cd "$ENV{'PBDIR'}" ; svnversion .)`; chomp($tmp); $ENV{'PBREVISION'}=$tmp; $ENV{'PBCMSLOGFILE'}="svn.log"; } elsif (($scheme eq "file") || ($scheme eq "ftp") || ($scheme eq "http")) { $ENV{'PBREVISION'}="flat"; $ENV{'PBCMSLOGFILE'}="flat.log"; } elsif ($scheme =~ /^cvs/) { # Way too slow #$ENV{'PBREVISION'}=`(cd "$ENV{'PBROOTDIR'}" ; cvs rannotate -f . 2>&1 | awk '{print \$1}' | grep -E '^[0-9]' | cut -d. -f2 |sort -nu | tail -1)`; #chomp($ENV{'PBREVISION'}); $ENV{'PBREVISION'}="cvs"; $ENV{'PBCMSLOGFILE'}="cvs.log"; $ENV{'CVS_RSH'} = "ssh" if ($scheme =~ /ssh/); } else { die "cms $scheme unknown"; } return($scheme,$pburl->{$ENV{'PBPROJ'}}); } sub pb_cms_export { my $uri = shift; my $source = shift; my $destdir = shift; my $tmp; my $tmp1; my @date = pb_get_date(); # If it's not flat, then we have a real uri as source my ($scheme, $account, $host, $port, $path) = pb_get_uri($uri); if ($scheme =~ /^svn/) { if (-d $source) { $tmp = $destdir; } else { $tmp = "$destdir/".basename($source); } pb_system("svn export $source $tmp","Exporting $source from SVN to $tmp"); } elsif ($scheme eq "dir") { pb_system("cp -a $path $destdir","Copying $uri from DIR to $destdir"); } elsif (($scheme eq "http") || ($scheme eq "ftp")) { my $f = basename($path); unlink "$ENV{'PBTMP'}/$f"; if (-x "/usr/bin/wget") { pb_system("/usr/bin/wget -nv -O $ENV{'PBTMP'}/$f $uri"," "); } elsif (-x "/usr/bin/curl") { pb_system("/usr/bin/curl $uri -o $ENV{'PBTMP'}/$f","Downloading $uri with curl to $ENV{'PBTMP'}/$f\n"); } else { die "Unable to download $uri.\nNo wget/curl available, please install one of those"; } pb_cms_export("file://$ENV{'PBTMP'}/$f",$source,$destdir); } elsif ($scheme eq "file") { use File::MimeInfo; my $mm = mimetype($path); pb_log(2,"mimetype: $mm\n"); pb_mkdir_p($destdir); # Check whether the file is well formed # (containing already a directory with the project-version name) my ($pbwf) = pb_conf_get_if("pbwf"); if ((defined $pbwf) && (defined $pbwf->{$ENV{'PBPROJ'}})) { $destdir = dirname($destdir); } if ($mm =~ /\/x-bzip-compressed-tar$/) { # tar+bzip2 pb_system("cd $destdir ; tar xfj $path","Extracting $path in $destdir"); } elsif ($mm =~ /\/x-lzma-compressed-tar$/) { # tar+lzma pb_system("cd $destdir ; tar xfY $path","Extracting $path in $destdir"); } elsif ($mm =~ /\/x-compressed-tar$/) { # tar+gzip pb_system("cd $destdir ; tar xfz $path","Extracting $path in $destdir"); } elsif ($mm =~ /\/x-tar$/) { # tar pb_system("cd $destdir ; tar xf $path","Extracting $path in $destdir"); } elsif ($mm =~ /\/zip$/) { # zip pb_system("cd $destdir ; unzip $path","Extracting $path in $destdir"); } } elsif ($scheme =~ /^cvs/) { # CVS needs a relative path ! my $dir=dirname($destdir); my $base=basename($destdir); # CVS also needs a modules name not a dir #if (-d $source) { $tmp1 = basename($source); #} else { #$tmp1 = dirname($source); #$tmp1 = basename($tmp1); #} my $optcvs = ""; # If we're working on the CVS itself my $cvstag = basename($ENV{'PBROOTDIR'}); my $cvsopt = ""; if ($cvstag eq "cvs") { my $pbdate = strftime("%Y-%m-%d %H:%M:%S", @date); $cvsopt = "-D \"$pbdate\""; } else { # we're working on a tag which should be the last part of PBROOTDIR $cvsopt = "-r $cvstag"; } pb_system("cd $dir ; cvs -d $account\@$host:$path export $cvsopt -d $base $tmp1","Exporting $tmp1 from $source under CVS to $destdir"); } else { die "cms $scheme unknown"; } } sub pb_create_authors { my $authors=shift; my $dest=shift; my $scheme=shift; return if ($authors eq "/dev/null"); open(SAUTH,$authors) || die "Unable to open $authors"; # Save a potentially existing AUTHORS file and write instead toi AUTHORS.pb my $ext = ""; if (-f "$dest/AUTHORS") { $ext = ".pb"; } open(DAUTH,"> $dest/AUTHORS$ext") || die "Unable to create $dest/AUTHORS$ext"; print DAUTH "Authors of the project are:\n"; print DAUTH "===========================\n"; while () { my ($nick,$gcos) = split(/:/); chomp($gcos); print DAUTH "$gcos"; if (defined $scheme) { # Do not give a scheme for flat types my $endstr=""; if ("$ENV{'PBREVISION'}" ne "flat") { $endstr = " under $scheme"; } print DAUTH " ($nick$endstr)\n"; } else { print DAUTH "\n"; } } close(DAUTH); close(SAUTH); } sub pb_cms_log { my $scheme = shift; my $pkgdir = shift; my $dest = shift; my $chglog = shift; my $authors = shift; pb_create_authors($authors,$dest,$scheme); if ($scheme =~ /^svn/) { if (! -f "$dest/ChangeLog") { if (-x "/usr/bin/svn2cl") { # In case we have no network, just create an empty one before to allow correct build open(CL,"> $dest/ChangeLog") || die "Unable to create $dest/ChangeLog"; close(CL); pb_system("/usr/bin/svn2cl --group-by-day --authors=$authors -i -o $dest/ChangeLog $pkgdir","Generating ChangeLog from SVN with svn2cl"); } else { # To be written from pbcl pb_system("svn log -v $pkgdir > $dest/$ENV{'PBCMSLOGFILE'}","Extracting log info from SVN"); } } } elsif (($scheme eq "file") || ($scheme eq "dir") || ($scheme eq "http") || ($scheme eq "ftp")) { if (! -f "$dest/ChangeLog") { pb_system("echo ChangeLog for $pkgdir > $dest/ChangeLog","Empty ChangeLog file created"); } } elsif ($scheme =~ /^cvs/) { my $tmp=basename($pkgdir); # CVS needs a relative path ! if (! -f "$dest/ChangeLog") { if (-x "/usr/bin/cvs2cl") { # In case we have no network, just create an empty one before to allow correct build open(CL,"> $dest/ChangeLog") || die "Unable to create $dest/ChangeLog"; close(CL); pb_system("/usr/bin/cvs2cl --group-by-day -U $authors -f $dest/ChangeLog $pkgdir","Generating ChangeLog from CVS with cvs2cl"); } else { # To be written from pbcl pb_system("cvs log $tmp > $dest/$ENV{'PBCMSLOGFILE'}","Extracting log info from CVS"); } } } else { die "cms $scheme unknown"; } } # This function is only called with a real CMS system sub pb_cms_get_uri { my $scheme = shift; my $dir = shift; my $res = ""; my $void = ""; if ($scheme =~ /^svn/) { open(PIPE,"LANGUAGE=C svn info $dir |") || return(""); while () { ($void,$res) = split(/^URL:/) if (/^URL:/); } $res =~ s/^\s*//; close(PIPE); chomp($res); } elsif ($scheme =~ /^cvs/) { # This path is always the root path of CVS, but we may be below open(FILE,"$dir/CVS/Root") || die "$dir isn't CVS controlled"; $res = ; chomp($res); close(FILE); # Find where we are in the tree my $rdir = $dir; while ((! -d "$rdir/CVSROOT") && ($rdir ne "/")) { $rdir = dirname($rdir); } die "Unable to find a CVSROOT dir in the parents of $dir" if (! -d "$rdir/CVSROOT"); #compute our place under that root dir - should be a relative path $dir =~ s|^$rdir||; my $suffix = ""; $suffix = "$dir" if ($dir ne ""); my $prefix = ""; if ($scheme =~ /ssh/) { $prefix = "cvs+ssh://"; } else { $prefix = "cvs://"; } $res = $prefix.$res.$suffix; } else { die "cms $scheme unknown"; } pb_log(2,"Found CMS info: $res\n"); return($res); } sub pb_cms_copy { my $scheme = shift; my $oldurl = shift; my $newurl = shift; if ($scheme =~ /^svn/) { pb_system("svn copy -m \"Creation of $newurl from $oldurl\" $oldurl $newurl","Copying $oldurl to $newurl "); } elsif ($scheme eq "flat") { } elsif ($scheme =~ /^cvs/) { } else { die "cms $scheme unknown"; } } sub pb_cms_checkout { my $scheme = shift; my $url = shift; my $destination = shift; if ($scheme =~ /^svn/) { pb_system("svn co $url $destination","Checking out $url to $destination "); } elsif (($scheme eq "ftp") || ($scheme eq "http")) { return; } elsif ($scheme =~ /^cvs/) { pb_system("cvs co $url $destination","Checking out $url to $destination "); } else { die "cms $scheme unknown"; } } sub pb_cms_up { my $scheme = shift; my $dir = shift; if ($scheme =~ /^svn/) { pb_system("svn up $dir","Updating $dir"); } elsif ($scheme eq "flat") { } elsif ($scheme =~ /^cvs/) { } else { die "cms $scheme unknown"; } } sub pb_cms_checkin { my $scheme = shift; my $dir = shift; my $ver = basename($dir); if ($scheme =~ /^svn/) { pb_system("svn ci -m \"updated to $ver\" $dir","Checking in $dir"); } elsif ($scheme eq "flat") { } elsif ($scheme =~ /^cvs/) { } else { die "cms $scheme unknown"; } pb_cms_up($scheme,$dir); } sub pb_cms_isdiff { my $scheme = shift; my $dir =shift; if ($scheme =~ /^svn/) { open(PIPE,"svn diff $dir |") || die "Unable to get svn diff from $dir"; my $l = 0; while () { $l++; } return($l); } elsif ($scheme eq "flat") { } elsif ($scheme =~ /^cvs/) { open(PIPE,"cvs diff $dir |") || die "Unable to get svn diff from $dir"; my $l = 0; while () { # Skipping normal messages next if (/^cvs diff:/); $l++; } return($l); } else { die "cms $scheme unknown"; } } # Get all filters to apply # They're cumulative from less specific to most specific # suffix is .pbf sub pb_get_filters { my @ffiles; my ($ffile00, $ffile0, $ffile1, $ffile2, $ffile3); my ($mfile00, $mfile0, $mfile1, $mfile2, $mfile3); my $pbpkg = shift || die "No package specified"; my $dtype = shift || ""; my $dfam = shift || ""; my $ddir = shift || ""; my $dver = shift || ""; my $ptr = undef; # returned value pointer on the hash of filters my %h; # Global filter files first, then package specificities if (-d "$ENV{'PBROOTDIR'}/pbfilter") { $mfile00 = "$ENV{'PBROOTDIR'}/pbfilter/all.pbf" if (-f "$ENV{'PBROOTDIR'}/pbfilter/all.pbf"); $mfile0 = "$ENV{'PBROOTDIR'}/pbfilter/$dtype.pbf" if (-f "$ENV{'PBROOTDIR'}/pbfilter/$dtype.pbf"); $mfile1 = "$ENV{'PBROOTDIR'}/pbfilter/$dfam.pbf" if (-f "$ENV{'PBROOTDIR'}/pbfilter/$dfam.pbf"); $mfile2 = "$ENV{'PBROOTDIR'}/pbfilter/$ddir.pbf" if (-f "$ENV{'PBROOTDIR'}/pbfilter/$ddir.pbf"); $mfile3 = "$ENV{'PBROOTDIR'}/pbfilter/$ddir-$dver.pbf" if (-f "$ENV{'PBROOTDIR'}/pbfilter/$ddir-$dver.pbf"); push @ffiles,$mfile00 if (defined $mfile00); push @ffiles,$mfile0 if (defined $mfile0); push @ffiles,$mfile1 if (defined $mfile1); push @ffiles,$mfile2 if (defined $mfile2); push @ffiles,$mfile3 if (defined $mfile3); } if (-d "$ENV{'PBROOTDIR'}/$pbpkg/pbfilter") { $ffile00 = "$ENV{'PBROOTDIR'}/$pbpkg/pbfilter/all.pbf" if (-f "$ENV{'PBROOTDIR'}/$pbpkg/pbfilter/all.pbf"); $ffile0 = "$ENV{'PBROOTDIR'}/$pbpkg/pbfilter/$dtype.pbf" if (-f "$ENV{'PBROOTDIR'}/$pbpkg/pbfilter/$dtype.pbf"); $ffile1 = "$ENV{'PBROOTDIR'}/$pbpkg/pbfilter/$dfam.pbf" if (-f "$ENV{'PBROOTDIR'}/$pbpkg/pbfilter/$dfam.pbf"); $ffile2 = "$ENV{'PBROOTDIR'}/$pbpkg/pbfilter/$ddir.pbf" if (-f "$ENV{'PBROOTDIR'}/$pbpkg/pbfilter/$ddir.pbf"); $ffile3 = "$ENV{'PBROOTDIR'}/$pbpkg/pbfilter/$ddir-$dver.pbf" if (-f "$ENV{'PBROOTDIR'}/$pbpkg/pbfilter/$ddir-$dver.pbf"); push @ffiles,$ffile00 if (defined $ffile00); push @ffiles,$ffile0 if (defined $ffile0); push @ffiles,$ffile1 if (defined $ffile1); push @ffiles,$ffile2 if (defined $ffile2); push @ffiles,$ffile3 if (defined $ffile3); } if (@ffiles) { pb_log(2,"DEBUG ffiles: ".Dumper(\@ffiles)."\n"); foreach my $f (@ffiles) { open(CONF,$f) || next; while() { if (/^\s*([A-z0-9-_]+)\s+([[A-z0-9-_]+)\s*=\s*(.+)$/) { $h{$1}{$2}=$3; } } close(CONF); $ptr = $h{"filter"}; pb_log(2,"DEBUG f:".Dumper($ptr)."\n"); } } return($ptr); } # Function which applies filter on pb build files sub pb_filter_file_pb { my $f=shift; my $ptr=shift; my %filter=%$ptr; my $destfile=shift; my $dtype=shift; my $pbsuf=shift; my $pbproj=shift; my $pbpkg=shift; my $pbver=shift; my $pbtag=shift; my $pbrev=shift; my $pbdate=shift; my $defpkgdir = shift; my $extpkgdir = shift; my $pbpackager = shift; my $chglog = shift || undef; pb_log(2,"DEBUG: From $f to $destfile\n"); pb_mkdir_p(dirname($destfile)) if (! -d dirname($destfile)); open(DEST,"> $destfile") || die "Unable to create $destfile"; open(FILE,"$f") || die "Unable to open $f: $!"; while () { my $line = $_; foreach my $s (keys %filter) { # Process single variables pb_log(2,"DEBUG filter{$s}: $filter{$s}\n"); my $tmp = $filter{$s}; next if (not defined $tmp); # Expand variables if any single one found pb_log(2,"DEBUG tmp: $tmp\n"); if ($tmp =~ /\$/) { eval { $tmp =~ s/(\$\w+)/$1/eeg }; # special case for ChangeLog only for pb } elsif (($s =~ /^PBLOG$/) && ($line =~ /^PBLOG$/)) { my $p = $defpkgdir->{$pbpkg}; $p = $extpkgdir->{$pbpkg} if (not defined $p); pb_changelog($dtype, $pbpkg, $pbver, $pbtag, $pbsuf, $p, \*DEST, $tmp, $chglog); $tmp = ""; } $line =~ s|$s|$tmp|; } print DEST $line; } close(FILE); close(DEST); } # Function which applies filter on files (external call) sub pb_filter_file_inplace { my $ptr=shift; my %filter=%$ptr; my $destfile=shift; my $pbproj=shift; my $pbpkg=shift; my $pbver=shift; my $pbtag=shift; my $pbrev=shift; my $pbdate=shift; my $pbpackager=shift; my $cp = "$ENV{'PBTMP'}/".basename($destfile); copy($destfile,$cp) || die "Unable to create $cp"; pb_filter_file($cp,$ptr,$destfile,$pbproj,$pbpkg,$pbver,$pbtag,$pbrev,$pbdate,$pbpackager); unlink $cp; } # Function which applies filter on files (external call) sub pb_filter_file { my $f=shift; my $ptr=shift; my %filter=%$ptr; my $destfile=shift; my $pbproj=shift; my $pbpkg=shift; my $pbver=shift; my $pbtag=shift; my $pbrev=shift; my $pbdate=shift; my $pbpackager=shift; pb_log(2,"DEBUG: From $f to $destfile\n"); pb_mkdir_p(dirname($destfile)) if (! -d dirname($destfile)); open(DEST,"> $destfile") || die "Unable to create $destfile"; open(FILE,"$f") || die "Unable to open $f: $!"; while () { my $line = $_; foreach my $s (keys %filter) { # Process single variables pb_log(2,"DEBUG filter{$s}: $filter{$s}\n"); my $tmp = $filter{$s}; next if (not defined $tmp); # Expand variables if any single one found if ($tmp =~ /\$/) { eval { $tmp =~ s/(\$\w+)/$1/eeg }; } $line =~ s|$s|$tmp|; } print DEST $line; } close(FILE); close(DEST); } # # Return the list of packages we are working on in a CMS action # sub pb_cms_get_pkg { my @pkgs = (); my $defpkgdir = shift || undef; my $extpkgdir = shift || undef; # Get packages list if (not defined $ARGV[0]) { @pkgs = keys %$defpkgdir if (defined $defpkgdir); } elsif ($ARGV[0] =~ /^all$/) { @pkgs = keys %$defpkgdir if (defined $defpkgdir); push(@pkgs, keys %$extpkgdir) if (defined $extpkgdir); } else { @pkgs = @ARGV; } pb_log(0,"Packages: ".join(',',@pkgs)."\n"); return(\@pkgs); } # # Return the list of packages we are working on in a non CMS action # sub pb_get_pkg { my @pkgs = (); my ($var) = pb_conf_read("$ENV{'PBDESTDIR'}/$ENV{'PBPROJVER'}-$ENV{'PBPROJTAG'}.pb","pbpkg"); @pkgs = keys %$var; pb_log(0,"Packages: ".join(',',@pkgs)."\n"); return(\@pkgs); } # # Check pbconf/project cms compliance # sub pb_cms_compliant { my $param = shift; my $envar = shift; my $defdir = shift; my $uri = shift; my $pbinit = shift; my %pdir; my ($pdir) = pb_conf_get_if($param) if (defined $param); if (defined $pdir) { %pdir = %$pdir; } if ((defined $pdir) && (%pdir) && (defined $pdir{$ENV{'PBPROJ'}})) { # That's always the environment variable that will be used $ENV{$envar} = $pdir{$ENV{'PBPROJ'}}; } else { if (defined $param) { pb_log(1,"WARNING: no $param defined, using $defdir\n"); pb_log(1," Please create a $param reference for project $ENV{'PBPROJ'} in $ENV{'PBETC'}\n"); pb_log(1," if you want to use another directory\n"); } $ENV{$envar} = "$defdir"; } # Expand potential env variable in it eval { $ENV{$envar} =~ s/(\$ENV.+\})/$1/eeg }; pb_log(2,"$envar: $ENV{$envar}\n"); my ($scheme, $account, $host, $port, $path) = pb_get_uri($uri); if ((! -d "$ENV{$envar}") || (defined $pbinit)) { if (defined $pbinit) { pb_mkdir_p("$ENV{$envar}"); } else { pb_log(1,"Checking out $uri\n"); pb_cms_checkout($scheme,$uri,$ENV{$envar}); } } elsif (($scheme !~ /^cvs/) || ($scheme !~ /^svn/)) { # Do not compare if it's not a real cms return; } else { pb_log(1,"$uri found locally, checking content\n"); my $cmsurl = pb_cms_get_uri($scheme,$ENV{$envar}); my ($scheme2, $account2, $host2, $port2, $path2) = pb_get_uri($cmsurl); if ($cmsurl ne $uri) { # The local content doesn't correpond to the repository pb_log(0,"ERROR: Inconsistency detected:\n"); pb_log(0," * $ENV{$envar} refers to $cmsurl but\n"); pb_log(0," * $ENV{'PBETC'} refers to $uri\n"); die "Project $ENV{'PBPROJ'} is not Project-Builder compliant."; } else { pb_log(1,"Content correct - doing nothing - you may want to update your repository however\n"); # they match - do nothing - there may be local changes } } } sub pb_changelog { my $dtype = shift; my $pkg = shift; my $pbver = shift; my $pbtag = shift; my $dsuf = shift; my $path = shift; my $OUTPUT = shift; my $doit = shift; my $chglog = shift || undef; my $log = ""; # For date handling $ENV{LANG}="C"; if ((not (defined $dtype)) || ($dtype eq "") || (not (defined $pkg)) || ($pkg eq "") || (not (defined $pbver)) || ($pbver eq "") || (not (defined $pbtag)) || ($pbtag eq "") || (not (defined $dsuf)) || ($dsuf eq "") || (not (defined $path)) || ($path eq "") || (not (defined $OUTPUT)) || ($OUTPUT eq "") || (not (defined $doit)) || ($doit eq "")) { print $OUTPUT "\n"; return; } if (((not defined $chglog) || (! -f $chglog)) && ($doit eq "yes")) { #pb_log(2,"No ChangeLog file ($chglog) for $pkg\n"; print $OUTPUT "\n"; return; } my $date; my $ndate; my $n2date; my $ver; my $ver2; my ($pbpackager) = pb_conf_get("pbpackager"); if (not defined $pbpackager->{$ENV{'PBPROJ'}}) { $pbpackager->{$ENV{'PBPROJ'}} = "undefined\@noproject.noorg"; } # If we don't need to do it, or don't have it fake something if (((not defined $chglog) || (! -f $chglog)) && ($doit ne "yes")) { my @date = pb_get_date(); $date = strftime("%Y-%m-%d", @date); $ndate = UnixDate($date,"%a", "%b", "%d", "%Y"); $n2date = &UnixDate($date,"%a, %d %b %Y %H:%M:%S %z"); if (($dtype eq "rpm") || ($dtype eq "fc")) { $ver2 = "$pbver-$pbtag$dsuf"; print $OUTPUT "* $ndate $pbpackager->{$ENV{'PBPROJ'}} $ver2\n"; print $OUTPUT "- Updated to $pbver\n"; } if ($dtype eq "deb") { print $OUTPUT "$pkg ($pbver) unstable; urgency=low\n"; print $OUTPUT "\n"; print $OUTPUT " -- $pbpackager->{$ENV{'PBPROJ'}} $n2date\n\n\n"; } return; } open(INPUT,"$chglog") || die "Unable to open $chglog (read)"; # Skip first 4 lines my $tmp = ; $tmp = ; $tmp = ; if ($dtype eq "announce") { print $OUTPUT $tmp; } $tmp = ; if ($dtype eq "announce") { print $OUTPUT $tmp; } my $first=1; # Handle each block separated by newline while () { ($ver, $date) = split(/ /); $ver =~ s/^v//; chomp($date); $date =~ s/\(([0-9-]+)\)/$1/; #pb_log(2,"**$date**\n"; $ndate = UnixDate($date,"%a", "%b", "%d", "%Y"); $n2date = &UnixDate($date,"%a, %d %b %Y %H:%M:%S %z"); #pb_log(2,"**$ndate**\n"; if (($dtype eq "rpm") || ($dtype eq "fc")) { if ($ver !~ /-/) { if ($first eq 1) { $ver2 = "$ver-$pbtag$dsuf"; $first=0; } else { $ver2 = "$ver-1$dsuf"; } } else { $ver2 = "$ver$dsuf"; } print $OUTPUT "* $ndate $pbpackager->{$ENV{'PBPROJ'}} $ver2\n"; print $OUTPUT "- Updated to $ver\n"; } if ($dtype eq "deb") { print $OUTPUT "$pkg ($ver) unstable; urgency=low\n"; print $OUTPUT "\n"; } $tmp = ; while ($tmp !~ /^$/) { if ($dtype eq "deb") { $tmp =~ s/^- //; print $OUTPUT " * $tmp"; } elsif ($dtype eq "rpm") { print $OUTPUT "$tmp"; } else { print $OUTPUT "$tmp"; } last if (eof(INPUT)); $tmp = ; } print $OUTPUT "\n"; if ($dtype eq "deb") { # Cf: http://www.debian.org/doc/debian-policy/ch-source.html#s-dpkgchangelog print $OUTPUT " -- $pbpackager->{$ENV{'PBPROJ'}} $n2date\n\n\n"; } last if (eof(INPUT)); last if ($dtype eq "announce"); } close(INPUT); } 1;