diff -r 71503088f51b -r f880f219c566 openpkg/makeproxy.pl
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/openpkg/makeproxy.pl Tue Jul 31 12:23:42 2012 +0200
@@ -0,0 +1,411 @@
+##
+## makeproxy.pl -- OpenPKG Tool Chain
+## Copyright (c) 2000-2012 OpenPKG GmbH
+##
+## This software is property of the OpenPKG GmbH, DE MUC HRB 160208.
+## All rights reserved. Licenses which grant limited permission to use,
+## copy, modify and distribute this software are available from the
+## OpenPKG GmbH.
+##
+## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
+## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+## IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
+## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+## SUCH DAMAGE.
+##
+
+require 5.003;
+
+# OpenPKG instance prefix and RPM
+my $my_prefix = $ENV{'OPENPKG_PREFIX'};
+my $my_rpm = "$my_prefix/bin/openpkg rpm";
+delete $ENV{'OPENPKG_PREFIX'};
+
+# program identification
+my $progname = "makeproxy";
+my $progvers = "2.1.0";
+
+# parameters (defaults)
+my $help = 0;
+my $version = 0;
+my $verbose = 0;
+my $debug = 0;
+my $slave_prefix = $my_prefix;
+my $master_prefix = '';
+my $tmpdir = ($ENV{TMPDIR} || "/tmp");
+my $output = '.';
+my $input = '-';
+
+# cleanup support
+my @cleanup = ();
+sub cleanup_remember {
+ my ($cmd) = @_;
+ push(@cleanup, $cmd);
+}
+sub cleanup_perform {
+ foreach my $cmd (reverse @cleanup) {
+ runcmd($cmd);
+ }
+}
+
+# exception handling support
+$SIG{__DIE__} = sub {
+ my ($err) = @_;
+ $err =~ s|\s+at\s+.*||s if (not $verbose);
+ $err =~ s/\n+$//s;
+ print STDERR "openpkg:$progname:ERROR: $err\n";
+ cleanup_perform() if (not $verbose);
+ exit(1);
+};
+
+# verbose message printing
+sub verbose {
+ my ($msg) = @_;
+ print STDERR "$msg\n" if ($verbose);
+}
+
+# execution of external commands
+sub runcmd {
+ my ($cmd) = @_;
+ if ($cmd =~ m/^(.+)\|$/s) {
+ print STDERR "\$ $1\n" if ($debug);
+ return `$1`;
+ }
+ else {
+ print STDERR "\$ $cmd\n" if ($debug);
+ $cmd = "($cmd) >/dev/null 2>&1" if (not $debug);
+ return (system($cmd) == 0);
+ }
+}
+
+# expand into a full filesystem path
+sub fullpath {
+ my ($prog) = @_;
+ my $fullprog = '';
+ foreach my $path (split(/:/, $ENV{PATH})) {
+ if (-x "$path/$prog") {
+ $fullprog = "$path/$prog";
+ last;
+ }
+ }
+ return $fullprog;
+}
+
+# convert a subdirectory (a/b/c/)
+# into a corresponding reverse path (../../../)
+sub sub2rev {
+ my ($sub) = @_;
+ my $rev = '';
+ $sub =~ s|^/+||s;
+ $sub =~ s|/+$||s;
+ while ($sub =~ s|/[^/]+||) {
+ $rev .= "../";
+ }
+ if ($sub ne '') {
+ $rev .= "../";
+ }
+ $rev =~ s|/$||s;
+ return $rev;
+}
+
+# create a directory (plus its missing parent dirs)
+sub mkdirp {
+ my ($dir) = @_;
+ my $pdir = $dir;
+ $pdir =~ s|/[^/]*$||s;
+ if (not -d $pdir) {
+ mkdirp($pdir);
+ }
+ if (not -d $dir) {
+ runcmd("mkdir $dir");
+ }
+}
+
+# home-brewn getopt(3) style option parser
+sub getopts ($) {
+ my ($opts) = @_;
+ my (%optf) = map { m/(\w)/; $1 => $_ } $opts =~ m/(\w:|\w)/g;
+ my (%opts, @argv, $optarg);
+
+ foreach (@ARGV) {
+ if (@argv) {
+ push @argv, $_;
+ } elsif (defined $optarg) {
+ if (exists $opts{$optarg}) {
+ $opts{$optarg} .= " $_";
+ } else {
+ $opts{$optarg} = $_;
+ }
+ $optarg = undef;
+ } elsif (!/^[-]/) {
+ push @argv, $_;
+ } else {
+ while (/^\-(\w)(.*)/) {
+ if (exists $optf{$1}) {
+ if (length($optf{$1}) > 1) {
+ if ($2 ne '') {
+ if (exists $opts{$1}) {
+ $opts{$1} .= " $2";
+ } else {
+ $opts{$1} = $2;
+ }
+ } else {
+ $optarg = $1;
+ }
+ last;
+ } else {
+ $opts{$1} = 1;
+ }
+ } else {
+ warn "openpkg:makeproxy:WARNING: unknown option $_\n";
+ }
+ $_ = "-$2";
+ }
+ }
+ }
+ if (defined $optarg) {
+ warn "openpkg:makeproxy:WARNING: option $optarg requires an argument\n";
+ }
+ foreach (keys %opts) {
+ eval '$opt_'.$_.' = "'.quotemeta($opts{$_}).'";';
+ }
+ @ARGV = @argv;
+}
+
+# command line parsing
+getopts("Vhdvm:s:t:o:");
+$version = $opt_V if (defined $opt_V);
+$help = $opt_h if (defined $opt_h);
+$debug = $opt_d if (defined $opt_d);
+$verbose = $opt_v if (defined $opt_v);
+$master_prefix = $opt_m if (defined $opt_m);
+$slave_prefix = $opt_s if (defined $opt_s);
+$tmpdir = $opt_t if (defined $opt_t);
+$output = $opt_o if (defined $opt_o);
+if ($help) {
+ print "Usage: openpkg $progname [options] master-package\n" .
+ " -h,--help print this usage page\n" .
+ " -V,--version print version\n" .
+ " -v,--verbose print verbose run-time information\n" .
+ " -d,--debug print debug information\n" .
+ " -m,--master=DIR filesystem path to master OpenPKG instance\n" .
+ " -s,--slave=DIR filesystem path to slave OpenPKG instance\n" .
+ " -t,--tmpdir=DIR filesystem path to temporary directory\n" .
+ " -o,--output=FILE filesystem path to output proxy OpenPKG RPM package\n";
+ exit(0);
+}
+if ($version) {
+ print "OpenPKG $progname $progvers\n";
+ exit(0);
+}
+if ($#ARGV == 0) {
+ $input = shift(@ARGV);
+}
+if ($#ARGV != -1) {
+ die "invalid number of command line arguments";
+}
+
+# prepare temporary location
+verbose("++ prepare temporary directory");
+$tmpdir = "$tmpdir/$progname.$$";
+if (not -d $tmpdir) {
+ runcmd("umask 077 && mkdir $tmpdir")
+ or die "cannot create temporary directory \"$tmpdir\"";
+ cleanup_remember("rm -rf $tmpdir");
+}
+verbose("-- temporary directory: $tmpdir");
+
+# determine input and output RPM
+verbose("++ determining OpenPKG RPM package files");
+verbose("-- input/master/regular RPM package: $input");
+verbose("-- output/slave/proxy RPM package: $output");
+
+# ensure input RPM package is available on the filesystem
+if ($input eq '-') {
+ $input = "$tmpdir/input.rpm";
+ runcmd("cat >$input");
+}
+
+# determine master and slave OpenPKG instance and RPM commands
+if ($master_prefix eq '') {
+ if (not -f $input) {
+ die "input/master/regular RPM package does not exist: \"$input\"";
+ }
+ $master_prefix = runcmd("($my_rpm -qp --qf '%{PREFIXES}' $input 2>/dev/null || true) |");
+ $master_prefix =~ s/\r?\n$//s;
+ if ($master_prefix eq '') {
+ die "unable to determine master OpenPKG instance";
+ }
+}
+if ($master_prefix eq $slave_prefix) {
+ die "master and slave OpenPKG instances have to be different";
+}
+my $slave_rpm = (-f "$slave_prefix/bin/openpkg" ? "$slave_prefix/bin/openpkg rpm" : $my_rpm);
+my $master_rpm = (-f "$master_prefix/bin/openpkg" ? "$master_prefix/bin/openpkg rpm" : $my_rpm);
+verbose("-- tool OpenPKG instance: $my_prefix");
+verbose("-- tool OpenPKG RPM command: $my_rpm");
+verbose("-- master OpenPKG instance: $master_prefix");
+verbose("-- master OpenPKG RPM command: $master_rpm");
+verbose("-- slave OpenPKG instance: $slave_prefix");
+verbose("-- slave OpenPKG RPM command: $slave_rpm");
+
+# helper function for parsing RPM query outputs
+sub parseresponse {
+ my ($r, $o) = @_;
+ sub parseline {
+ my ($r, $t, $k, $v) = @_;
+ $v =~ s|^\s+||s;
+ $v =~ s|\s+$||s;
+ if ($t eq 'S') { # single-value results
+ $r->{$k} = $v;
+ }
+ elsif ($t eq 'M') { # multi-value results
+ $r->{$k} = [] if (not defined($r->{$k}));
+ push(@{$r->{$k}}, $v);
+ }
+ }
+ $o =~ s|([SM])-([^:]+):<(.*?)>\n|parseline($r, $1, $2, $3, '')|egs;
+ return $r;
+}
+
+# query master OpenPKG RPM package
+verbose("++ query information from master OpenPKG RPM package");
+my $q = '';
+foreach my $t (qw(
+ NAME SUMMARY URL VENDOR PACKAGER DISTRIBUTION CLASS GROUP LICENSE VERSION RELEASE
+ DESCRIPTION
+)) {
+ $q .= "S-$t:<%{$t}>\\n";
+}
+$q .= '[M-PREREQ:<%{REQUIRENAME} %|REQUIREFLAGS?{%{REQUIREFLAGS:depflags} %{REQUIREVERSION}}:{}|>\n]';
+$q .= '[M-PROVIDES:<%{PROVIDENAME} %|PROVIDEFLAGS?{%{PROVIDEFLAGS:depflags} %{PROVIDEVERSION}}:{}|>\n]';
+$q .= '[M-PREFIXES:<%{PREFIXES}>\n]';
+my $cmd = sprintf("%s -q %s --qf '$q' %s", $master_rpm, (-f $input ? "-p" : ""), $input);
+my $o = runcmd("$cmd|");
+if ($o =~ m/package .* is not installed/s) {
+ die "master package \"$input\" not installed in master OpenPKG instance \"$master_prefix\"";
+}
+$o =~ s|M-PREREQ:\n||gs;
+my $r = {};
+$r = parseresponse($r, $o);
+my $BD = '';
+my $ID = '';
+my $PR = '';
+foreach my $d (@{$r->{PREREQ}}) {
+ if ($d =~ m|^OpenPKG|i) {
+ $BD .= ", " if ($BD ne '');
+ $BD .= $d;
+ }
+ $ID .= ", " if ($ID ne '');
+ $ID .= $d;
+}
+foreach my $d (@{$r->{PROVIDES}}) {
+ $PR .= ", " if ($PR ne '');
+ $PR .= $d;
+}
+
+# prepare build environment
+verbose("++ establishing temporary OpenPKG RPM environment");
+verbose("-- directory: $tmpdir");
+runcmd("rm -rf $tmpdir/src; mkdir $tmpdir/src");
+runcmd("rm -rf $tmpdir/bld; mkdir $tmpdir/bld");
+cleanup_remember("rm -rf $tmpdir/src");
+cleanup_remember("rm -rf $tmpdir/tmp");
+cleanup_remember("rm -rf $tmpdir/bld");
+cleanup_remember("rm -rf $tmpdir/pkg");
+runcmd("mkdir $tmpdir/src/.openpkg");
+open(MACRO, ">$tmpdir/src/.openpkg/rpmmacros")
+ or die "unable to write file \"$tmpdir/src/.openpkg/rpmmacros\": $!";
+print MACRO "\%openpkg_layout macrosfile=\%{macrosfile} layout=local shared=no\n";
+close(MACRO);
+$ENV{HOME} = $tmpdir;
+
+# generate OpenPKG RPM .spec file for proxy OpenPKG RPM package
+verbose("++ generating OpenPKG RPM package specification for proxy package");
+verbose("-- file: $tmpdir/src/".$r->{NAME}.".spec");
+my $S = '';
+$S .= "Name: ".$r->{NAME}."\n";
+$S .= "Summary: ".$r->{SUMMARY}."\n";
+$S .= "URL: ".$r->{URL}."\n";
+$S .= "Vendor: ".$r->{VENDOR}."\n";
+$S .= "Packager: ".$r->{PACKAGER}."\n";
+$S .= "Distribution: ".$r->{DISTRIBUTION}."\n";
+$S .= "Class: ".$r->{CLASS}."\n";
+$S .= "Group: ".$r->{GROUP}."\n";
+$S .= "License: ".$r->{LICENSE}."\n";
+$S .= "Version: ".$r->{VERSION}."\n";
+$S .= "Release: ".$r->{RELEASE}."+PROXY\n";
+$S .= "\n";
+$S .= "BuildPreReq: $BD\n" if ($BD ne '');
+$S .= "PreReq: $ID\n" if ($ID ne '');
+$S .= "Provides: $PR\n" if ($PR ne '');
+$S .= "\n";
+$S .= "\%description\n";
+$S .= " ".$r->{DESCRIPTION}."\n";
+$S .= "\n";
+$S .= "\%install\n";
+$S .= " \%{l_rpmtool} files -v -ofiles -r\$RPM_BUILD_ROOT \%{l_files_std}\n";
+$S .= "\n";
+$S .= "\%files -f files\n";
+$S .= "\n";
+open(SPEC, ">$tmpdir/src/".$r->{NAME}.".spec")
+ or die "unable to write file \"$tmpdir/src/".$r->{NAME}."\": $!";
+print SPEC $S;
+close(SPEC);
+
+# creating shadow tree of original contents
+verbose("++ creating shadow tree from original package contents");
+$q = '[%{FILEMODES:perms} %{FILENAMES}\n]';
+$cmd = sprintf("%s -q %s --qf '$q' '%s'", $master_rpm, (-f $input ? "-p" : ""), $input);
+my @FL = runcmd("$cmd|");
+my $FD = [];
+my $FR = [];
+foreach my $fl (@FL) {
+ $fl =~ s|\n$||s;
+ if ($fl =~ m|^(d\S+)\s+$master_prefix(.*)$|) {
+ mkdirp("$tmpdir/bld$slave_prefix$2");
+ verbose("-- | PHYS $1 $slave_prefix$2");
+ }
+ elsif ($fl =~ m|^(\S+)\s+$master_prefix(.*?)([^/\s]+)$|) {
+ my ($subdir, $file) = ($2, $3);
+ my $target = sub2rev($subdir)."/.prefix-".$r->{NAME}.$subdir.$file;
+ mkdirp("$tmpdir/bld$slave_prefix$subdir");
+ runcmd("ln -s $target $tmpdir/bld$slave_prefix$subdir$file");
+ verbose("-- | VIRT $1 $slave_prefix$subdir$file");
+ }
+}
+
+# create master-reference symbolic link
+runcmd("ln -s $master_prefix $tmpdir/bld$slave_prefix/.prefix-".$r->{NAME});
+
+# rolling output proxy RPM package
+verbose("++ rolling output proxy RPM package");
+runcmd(
+ "cd $tmpdir/src && " .
+ "$slave_rpm -bb " .
+ "--define 'buildroot $tmpdir/bld' " .
+ "--define '__spec_install_pre \%{___build_pre}' " .
+ "--nodeps ".$r->{NAME}.".spec"
+);
+
+# providing output
+verbose("++ providing output: $output");
+if ($output eq '-') {
+ runcmd("cat $tmpdir/src/*.rpm");
+}
+else {
+ runcmd("cp $tmpdir/src/*.rpm $output");
+}
+
+# die gracefully...
+verbose("++ cleaning up environment");
+cleanup_perform();
+exit(0);
+