#!/usr/bin/perl -w # # rpmbootstrap application, a debootstrap like for RPM distros # # $Id$ # # Copyright B. Cornec 2010 # 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 LWP::UserAgent; #use File::Basename; #use File::Copy; use ProjectBuilder::Version; use ProjectBuilder::Base; use ProjectBuilder::Env; use ProjectBuilder::Conf; use ProjectBuilder::Distribution; # Global variables my %opts; # CLI Options =pod =head1 NAME rpmbootstrap - creates a chrooted RPM based distribution a la debootstrap, aka Virtual Environment (VE) =head1 DESCRIPTION rpmbootstrap creates a chroot environment (Virtual Environment or VE) with a minimal distribution in it, suited for building packages for example. It's very much like debootstrap but for RPM based distribution. It aims at supporting all distributions supported by project-builder;org (RHEL, RH, Fedora, OpeSUSE, SLES, Mandriva, ...) It is inspired by work done by Steve Kemp for rinse (http://www.steve.org.uk/), and similar to mock, but fully integrated with project-builder.org (which also supports rinse and mock). =head1 SYNOPSIS rpmbootstrap [-vhmqpdk][-s script][-i iso] distribution-version-arch [target-dir] [mirror [script]] pb [--verbose][--help][--man][--quiet][--print-rpms][--download-only][--keep][--include pkg1, pkg2, ...][--script script][--iso iso] distribution-version-arch [target-dir] [mirror [script]] =head1 OPTIONS =over 4 =item B<-v|--verbose> Print a brief help message and exits. =item B<-h|--help> Print a brief help message and exits. =item B<--man> Prints the manual page and exits. =item B<-q|--quiet> Do not print any output. =item B<-p|--print-rpms> Print the packages to be installed, and exit. Note that a target directory must be specified so rpmbootstrap can determine which packages should be installed, and to resolve dependencies. The target directory will be deleted. =item B<-d|--download-only> Download packages, but don't perform installation. =item B<-k|--keep> Keep packages in the cache dir for later reuse. By default remove them. =item B<-s|--script script> Name of the script you want to execute on the related VEs after the installation. =item B<-i|--iso iso_image> Name of the ISO image of the distribution you want to install on the related VE. =back =head1 ARGUMENTS =item B Full name of the distribution that needs to be installed in the VE. E.g. fedora-11-x86_64. =item B This is the target directory under which the VE will be created. Created on the fly if needed. If none is given use the default directory hosting VE for project-builder.org (Cf: vepath parameter in $HOME/.pbrc) =head1 EXAMPLE To setup a Fedora 12 distribution with an i386 architecture issue: rpmbootstrap fedora-12-i386 /tmp/fedora/12/i386 =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 Cf: L for announces and L for the development of the pb project. =head1 CONFIGURATION FILE Uses Project-Builder.org configuration file (/etc/pb/pb.conf or /usr/local/etc/pb/pb.conf) =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 # --------------------------------------------------------------------------- my ($projectbuilderver,$projectbuilderrev) = pb_version_init(); my $appname = "rpmbootstrap"; # Initialize the syntax string pb_syntax_init("$appname Version $projectbuilderver-$projectbuilderrev\n"); GetOptions("help|?|h" => \$opts{'h'}, "man|m" => \$opts{'man'}, "verbose|v+" => \$opts{'v'}, "quiet|q" => \$opts{'q'}, "log-files|l=s" => \$opts{'l'}, "script|s=s" => \$opts{'s'}, "print-rpms|p" => \$opts{'p'}, "download-only|d" => \$opts{'d'}, "keep|k" => \$opts{'k'}, "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'}) { $pbdebug = $opts{'v'}; } if (defined $opts{'q'}) { $pbdebug=-1; } if (defined $opts{'l'}) { open(pbLOG,"> $opts{'l'}") || die "Unable to log to $opts{'l'}: $!"; $pbLOG = \*pbLOG; $pbdebug = 0 if ($pbdebug == -1); } pb_log_init($pbdebug, $pbLOG); #pb_display_init("text",""); #if (defined $opts{'s'}) { #$pbscript = $opts{'s'}; #} #if (defined $opts{'i'}) { #$iso = $opts{'i'}; #} # Get VE name $ENV{'PBV'} = shift @ARGV; die pb_syntax(-1,1) if (not defined $ENV{'PBV'}); die "Needs to be run as root" if ($EFFECTIVE_USER_ID != 0); # # Initialize distribution info from pb conf file # my ($name,$ver,$darch) = split(/-/,$ENV{'PBV'}); chomp($darch); my ($ddir, $dver, $dfam, $dtype, $pbsuf, $dsuf, $dupd) = pb_distro_init($name,$ver,$darch); # # Check target dir # Create if not existent and use default if none given # pb_env_init_pbrc(); # to get content of HOME/.pbrc my $vepath = shift @ARGV; # # Check for command requirements # my ($req,$opt) = pb_conf_get_if("oscmd","oscmdopt"); my ($req2,$opt2) = (undef,undef); $req2 = $req->{$appname} if (defined $req); $opt2 = $opt->{$appname} if (defined $opt); pb_check_requirements($req2,$opt2); if (not defined $vepath) { my ($vestdpath) = pb_conf_get_if("vepath"); $vepath = "$vestdpath->{'default'}/$ddir/$dver/$darch"; } die pb_log(0,"No target-dir specified and no default vepath found in $ENV{'PBETC'}\n") if (not defined $vepath); pb_mkdir_p($vepath) if (! -d $vepath); # # Get the package list to download, store them in a cache directory # my ($rbsmindep,$rbsmirrorsrv) = pb_conf_get("rbsmindep","rbsmirrorsrv"); my ($rbscachedir) = pb_conf_get_if("rbscachedir"); my $pkgs = pb_distro_get_param($ddir,$dver,$darch,$rbsmindep); my $mirror = pb_distro_get_param($ddir,$dver,$darch,$rbsmirrorsrv); my $cachedir = "/var/cache/rpmbootstrap"; $cachedir = $rbscachedir->{'default'} if (defined $rbscachedir->{'default'}); # Point to the right subdir and create it if needed $cachedir .= "/$ddir-$dver-$darch"; pb_mkdir_p($cachedir) if (! -d $cachedir); # Get the complete package name from the mirror # my $ua = LWP::UserAgent->new; $ua->timeout(10); $ua->env_proxy; my $response = $ua->get($mirror); if (! $response->is_success) { die "Unable to download packages from $mirror for $ddir-$dver-$darch"; } pb_log(3,"Mirror $mirror gave answer: $response->dump(maxlength => 0)\n"); # Just print packages names if asked so. if ($opts{'p'}) { pb_log(0,"Should process package list: $pkgs\n"); exit(0); } # For each package to process, get it, put it in the cache dir # and extract it in the target dir. If not asked to keep, remove it # Just download if asked so. foreach my $p (split(/,/,$pkgs)) { pb_log(1,"Processing package $p ...\n") }