openpkg/makeproxy.pl

Mon, 28 Jan 2013 17:37:18 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Mon, 28 Jan 2013 17:37:18 +0100
changeset 758
a2c6460cfb16
permissions
-rw-r--r--

Correct socket error reporting improvement with IPv6 portable code,
after helpful recommendation by Saúl Ibarra Corretgé on OSips devlist.

     1 ##
     2 ##  makeproxy.pl -- OpenPKG Tool Chain
     3 ##  Copyright (c) 2000-2012 OpenPKG GmbH <http://openpkg.com/>
     4 ##
     5 ##  This software is property of the OpenPKG GmbH, DE MUC HRB 160208.
     6 ##  All rights reserved. Licenses which grant limited permission to use,
     7 ##  copy, modify and distribute this software are available from the
     8 ##  OpenPKG GmbH.
     9 ##
    10 ##  THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
    11 ##  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    12 ##  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    13 ##  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
    14 ##  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    15 ##  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    16 ##  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
    17 ##  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    18 ##  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    19 ##  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    20 ##  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    21 ##  SUCH DAMAGE.
    22 ##
    24 require 5.003;
    26 #   OpenPKG instance prefix and RPM
    27 my $my_prefix = $ENV{'OPENPKG_PREFIX'};
    28 my $my_rpm    = "$my_prefix/bin/openpkg rpm";
    29 delete $ENV{'OPENPKG_PREFIX'};
    31 #   program identification
    32 my $progname  = "makeproxy";
    33 my $progvers  = "2.1.0";
    35 #   parameters (defaults)
    36 my $help          = 0;
    37 my $version       = 0;
    38 my $verbose       = 0;
    39 my $debug         = 0;
    40 my $slave_prefix  = $my_prefix;
    41 my $master_prefix = '';
    42 my $tmpdir        = ($ENV{TMPDIR} || "/tmp");
    43 my $output        = '.';
    44 my $input         = '-';
    46 #   cleanup support
    47 my @cleanup = ();
    48 sub cleanup_remember {
    49     my ($cmd) = @_;
    50     push(@cleanup, $cmd);
    51 }
    52 sub cleanup_perform {
    53     foreach my $cmd (reverse @cleanup) {
    54         runcmd($cmd);
    55     }
    56 }
    58 #   exception handling support
    59 $SIG{__DIE__} = sub {
    60     my ($err) = @_;
    61     $err =~ s|\s+at\s+.*||s if (not $verbose);
    62     $err =~ s/\n+$//s;
    63     print STDERR "openpkg:$progname:ERROR: $err\n";
    64     cleanup_perform() if (not $verbose);
    65     exit(1);
    66 };
    68 #   verbose message printing
    69 sub verbose {
    70     my ($msg) = @_;
    71     print STDERR "$msg\n" if ($verbose);
    72 }
    74 #   execution of external commands
    75 sub runcmd {
    76     my ($cmd) = @_;
    77     if ($cmd =~ m/^(.+)\|$/s) {
    78         print STDERR "\$ $1\n" if ($debug);
    79         return `$1`;
    80     }
    81     else {
    82         print STDERR "\$ $cmd\n" if ($debug);
    83         $cmd = "($cmd) >/dev/null 2>&1" if (not $debug);
    84         return (system($cmd) == 0);
    85     }
    86 }
    88 #   expand into a full filesystem path
    89 sub fullpath {
    90     my ($prog) = @_;
    91     my $fullprog = '';
    92     foreach my $path (split(/:/, $ENV{PATH})) {
    93         if (-x "$path/$prog") {
    94             $fullprog = "$path/$prog";
    95             last;
    96         }
    97     }
    98     return $fullprog;
    99 }
   101 #   convert a subdirectory (a/b/c/)
   102 #   into a corresponding reverse path (../../../)
   103 sub sub2rev {
   104     my ($sub) = @_;
   105     my $rev = '';
   106     $sub =~ s|^/+||s;
   107     $sub =~ s|/+$||s;
   108     while ($sub =~ s|/[^/]+||) {
   109         $rev .= "../";
   110     }
   111     if ($sub ne '') {
   112         $rev .= "../";
   113     }
   114     $rev =~ s|/$||s;
   115     return $rev;
   116 }
   118 #   create a directory (plus its missing parent dirs)
   119 sub mkdirp {
   120     my ($dir) = @_;
   121     my $pdir = $dir;
   122     $pdir =~ s|/[^/]*$||s;
   123     if (not -d $pdir) {
   124         mkdirp($pdir);
   125     }
   126     if (not -d $dir) {
   127         runcmd("mkdir $dir");
   128     }
   129 }
   131 #   home-brewn getopt(3) style option parser
   132 sub getopts ($) {
   133     my ($opts) = @_;
   134     my (%optf) = map { m/(\w)/; $1 => $_ } $opts =~ m/(\w:|\w)/g;
   135     my (%opts, @argv, $optarg);
   137     foreach (@ARGV) {
   138         if (@argv) {
   139             push @argv, $_;
   140         } elsif (defined $optarg) {
   141             if (exists $opts{$optarg}) {
   142                 $opts{$optarg} .= " $_";
   143             } else {
   144                 $opts{$optarg} = $_;
   145             }
   146             $optarg = undef;
   147         } elsif (!/^[-]/) {
   148             push @argv, $_;
   149         } else {
   150             while (/^\-(\w)(.*)/) {
   151                 if (exists $optf{$1}) {
   152                     if (length($optf{$1}) > 1) {
   153                         if ($2 ne '') {
   154                             if (exists $opts{$1}) {
   155                                 $opts{$1} .= " $2";
   156                             } else {
   157                                 $opts{$1} = $2;
   158                             }
   159                         } else {
   160                             $optarg = $1;
   161                         }
   162                         last;
   163                     } else {
   164                         $opts{$1} = 1;
   165                     }
   166                 } else {
   167                     warn "openpkg:makeproxy:WARNING: unknown option $_\n";
   168                 }
   169                 $_ = "-$2";
   170             }
   171         }
   172     }
   173     if (defined $optarg) {
   174         warn "openpkg:makeproxy:WARNING: option $optarg requires an argument\n";
   175     }
   176     foreach (keys %opts) {
   177         eval '$opt_'.$_.' = "'.quotemeta($opts{$_}).'";';
   178     }
   179     @ARGV = @argv;
   180 }
   182 #   command line parsing
   183 getopts("Vhdvm:s:t:o:");
   184 $version       = $opt_V if (defined $opt_V);
   185 $help          = $opt_h if (defined $opt_h);
   186 $debug         = $opt_d if (defined $opt_d);
   187 $verbose       = $opt_v if (defined $opt_v);
   188 $master_prefix = $opt_m if (defined $opt_m);
   189 $slave_prefix  = $opt_s if (defined $opt_s);
   190 $tmpdir        = $opt_t if (defined $opt_t);
   191 $output        = $opt_o if (defined $opt_o);
   192 if ($help) {
   193     print "Usage: openpkg $progname [options] master-package\n" .
   194           " -h,--help          print this usage page\n" .
   195           " -V,--version       print version\n" .
   196           " -v,--verbose       print verbose run-time information\n" .
   197           " -d,--debug         print debug information\n" .
   198           " -m,--master=DIR    filesystem path to master OpenPKG instance\n" .
   199           " -s,--slave=DIR     filesystem path to slave OpenPKG instance\n" .
   200           " -t,--tmpdir=DIR    filesystem path to temporary directory\n" .
   201           " -o,--output=FILE   filesystem path to output proxy OpenPKG RPM package\n";
   202     exit(0);
   203 }
   204 if ($version) {
   205     print "OpenPKG $progname $progvers\n";
   206     exit(0);
   207 }
   208 if ($#ARGV == 0) {
   209     $input = shift(@ARGV);
   210 }
   211 if ($#ARGV != -1) {
   212     die "invalid number of command line arguments";
   213 }
   215 #   prepare temporary location
   216 verbose("++ prepare temporary directory");
   217 $tmpdir = "$tmpdir/$progname.$$";
   218 if (not -d $tmpdir) {
   219     runcmd("umask 077 && mkdir $tmpdir")
   220         or die "cannot create temporary directory \"$tmpdir\"";
   221     cleanup_remember("rm -rf $tmpdir");
   222 }
   223 verbose("-- temporary directory: $tmpdir");
   225 #   determine input and output RPM
   226 verbose("++ determining OpenPKG RPM package files");
   227 verbose("-- input/master/regular RPM package: $input");
   228 verbose("-- output/slave/proxy   RPM package: $output");
   230 #   ensure input RPM package is available on the filesystem
   231 if ($input eq '-') {
   232     $input = "$tmpdir/input.rpm";
   233     runcmd("cat >$input");
   234 }
   236 #   determine master and slave OpenPKG instance and RPM commands
   237 if ($master_prefix eq '') {
   238     if (not -f $input) {
   239         die "input/master/regular RPM package does not exist: \"$input\"";
   240     }
   241     $master_prefix = runcmd("($my_rpm -qp --qf '%{PREFIXES}' $input 2>/dev/null || true) |");
   242     $master_prefix =~ s/\r?\n$//s;
   243     if ($master_prefix eq '') {
   244         die "unable to determine master OpenPKG instance";
   245     }
   246 }
   247 if ($master_prefix eq $slave_prefix) {
   248     die "master and slave OpenPKG instances have to be different";
   249 }
   250 my $slave_rpm  = (-f "$slave_prefix/bin/openpkg"  ? "$slave_prefix/bin/openpkg rpm"  : $my_rpm);
   251 my $master_rpm = (-f "$master_prefix/bin/openpkg" ? "$master_prefix/bin/openpkg rpm" : $my_rpm);
   252 verbose("-- tool   OpenPKG instance:    $my_prefix");
   253 verbose("-- tool   OpenPKG RPM command: $my_rpm");
   254 verbose("-- master OpenPKG instance:    $master_prefix");
   255 verbose("-- master OpenPKG RPM command: $master_rpm");
   256 verbose("-- slave  OpenPKG instance:    $slave_prefix");
   257 verbose("-- slave  OpenPKG RPM command: $slave_rpm");
   259 #   helper function for parsing RPM query outputs
   260 sub parseresponse {
   261     my ($r, $o) = @_;
   262     sub parseline {
   263         my ($r, $t, $k, $v) = @_;
   264         $v =~ s|^\s+||s;
   265         $v =~ s|\s+$||s;
   266         if ($t eq 'S') {     # single-value results
   267             $r->{$k} = $v;
   268         }
   269         elsif ($t eq 'M') {  # multi-value results
   270             $r->{$k} = [] if (not defined($r->{$k}));
   271             push(@{$r->{$k}}, $v);
   272         }
   273     }
   274     $o =~ s|([SM])-([^:]+):<(.*?)>\n|parseline($r, $1, $2, $3, '')|egs;
   275     return $r;
   276 }
   278 #   query master OpenPKG RPM package
   279 verbose("++ query information from master OpenPKG RPM package");
   280 my $q = '';
   281 foreach my $t (qw(
   282     NAME SUMMARY URL VENDOR PACKAGER DISTRIBUTION CLASS GROUP LICENSE VERSION RELEASE
   283     DESCRIPTION
   284 )) {
   285     $q .= "S-$t:<%{$t}>\\n";
   286 }
   287 $q .= '[M-PREREQ:<%{REQUIRENAME} %|REQUIREFLAGS?{%{REQUIREFLAGS:depflags} %{REQUIREVERSION}}:{}|>\n]';
   288 $q .= '[M-PROVIDES:<%{PROVIDENAME} %|PROVIDEFLAGS?{%{PROVIDEFLAGS:depflags} %{PROVIDEVERSION}}:{}|>\n]';
   289 $q .= '[M-PREFIXES:<%{PREFIXES}>\n]';
   290 my $cmd = sprintf("%s -q %s --qf '$q' %s", $master_rpm, (-f $input ? "-p" : ""), $input);
   291 my $o = runcmd("$cmd|");
   292 if ($o =~ m/package .* is not installed/s) {
   293     die "master package \"$input\" not installed in master OpenPKG instance \"$master_prefix\"";
   294 }
   295 $o =~ s|M-PREREQ:<rpmlib\(.*?\).*?>\n||gs;
   296 my $r = {};
   297 $r = parseresponse($r, $o);
   298 my $BD = '';
   299 my $ID = '';
   300 my $PR = '';
   301 foreach my $d (@{$r->{PREREQ}}) {
   302     if ($d =~ m|^OpenPKG|i) {
   303         $BD .= ", " if ($BD ne '');
   304         $BD .= $d;
   305     }
   306     $ID .= ", " if ($ID ne '');
   307     $ID .= $d;
   308 }
   309 foreach my $d (@{$r->{PROVIDES}}) {
   310     $PR .= ", " if ($PR ne '');
   311     $PR .= $d;
   312 }
   314 #   prepare build environment
   315 verbose("++ establishing temporary OpenPKG RPM environment");
   316 verbose("-- directory: $tmpdir");
   317 runcmd("rm -rf $tmpdir/src; mkdir $tmpdir/src");
   318 runcmd("rm -rf $tmpdir/bld; mkdir $tmpdir/bld");
   319 cleanup_remember("rm -rf $tmpdir/src");
   320 cleanup_remember("rm -rf $tmpdir/tmp");
   321 cleanup_remember("rm -rf $tmpdir/bld");
   322 cleanup_remember("rm -rf $tmpdir/pkg");
   323 runcmd("mkdir $tmpdir/src/.openpkg");
   324 open(MACRO, ">$tmpdir/src/.openpkg/rpmmacros")
   325     or die "unable to write file \"$tmpdir/src/.openpkg/rpmmacros\": $!";
   326 print MACRO "\%openpkg_layout macrosfile=\%{macrosfile} layout=local shared=no\n";
   327 close(MACRO);
   328 $ENV{HOME} = $tmpdir;
   330 #   generate OpenPKG RPM .spec file for proxy OpenPKG RPM package
   331 verbose("++ generating OpenPKG RPM package specification for proxy package");
   332 verbose("-- file: $tmpdir/src/".$r->{NAME}.".spec");
   333 my $S = '';
   334 $S .= "Name:         ".$r->{NAME}."\n";
   335 $S .= "Summary:      ".$r->{SUMMARY}."\n";
   336 $S .= "URL:          ".$r->{URL}."\n";
   337 $S .= "Vendor:       ".$r->{VENDOR}."\n";
   338 $S .= "Packager:     ".$r->{PACKAGER}."\n";
   339 $S .= "Distribution: ".$r->{DISTRIBUTION}."\n";
   340 $S .= "Class:        ".$r->{CLASS}."\n";
   341 $S .= "Group:        ".$r->{GROUP}."\n";
   342 $S .= "License:      ".$r->{LICENSE}."\n";
   343 $S .= "Version:      ".$r->{VERSION}."\n";
   344 $S .= "Release:      ".$r->{RELEASE}."+PROXY\n";
   345 $S .= "\n";
   346 $S .= "BuildPreReq:  $BD\n" if ($BD ne '');
   347 $S .= "PreReq:       $ID\n" if ($ID ne '');
   348 $S .= "Provides:     $PR\n" if ($PR ne '');
   349 $S .= "\n";
   350 $S .= "\%description\n";
   351 $S .= "    ".$r->{DESCRIPTION}."\n";
   352 $S .= "\n";
   353 $S .= "\%install\n";
   354 $S .= "    \%{l_rpmtool} files -v -ofiles -r\$RPM_BUILD_ROOT \%{l_files_std}\n";
   355 $S .= "\n";
   356 $S .= "\%files -f files\n";
   357 $S .= "\n";
   358 open(SPEC, ">$tmpdir/src/".$r->{NAME}.".spec")
   359    or die "unable to write file \"$tmpdir/src/".$r->{NAME}."\": $!";
   360 print SPEC $S;
   361 close(SPEC);
   363 #   creating shadow tree of original contents
   364 verbose("++ creating shadow tree from original package contents");
   365 $q = '[%{FILEMODES:perms} %{FILENAMES}\n]';
   366 $cmd = sprintf("%s -q %s --qf '$q' '%s'", $master_rpm, (-f $input ? "-p" : ""), $input);
   367 my @FL = runcmd("$cmd|");
   368 my $FD = [];
   369 my $FR = [];
   370 foreach my $fl (@FL) {
   371     $fl =~ s|\n$||s;
   372     if ($fl =~ m|^(d\S+)\s+$master_prefix(.*)$|) {
   373         mkdirp("$tmpdir/bld$slave_prefix$2");
   374         verbose("-- | PHYS $1 $slave_prefix$2");
   375     }
   376     elsif ($fl =~ m|^(\S+)\s+$master_prefix(.*?)([^/\s]+)$|) {
   377         my ($subdir, $file) = ($2, $3);
   378         my $target = sub2rev($subdir)."/.prefix-".$r->{NAME}.$subdir.$file;
   379         mkdirp("$tmpdir/bld$slave_prefix$subdir");
   380         runcmd("ln -s $target $tmpdir/bld$slave_prefix$subdir$file");
   381         verbose("-- | VIRT $1 $slave_prefix$subdir$file");
   382     }
   383 }
   385 #   create master-reference symbolic link
   386 runcmd("ln -s $master_prefix $tmpdir/bld$slave_prefix/.prefix-".$r->{NAME});
   388 #   rolling output proxy RPM package
   389 verbose("++ rolling output proxy RPM package");
   390 runcmd(
   391     "cd $tmpdir/src && " .
   392     "$slave_rpm -bb " .
   393     "--define 'buildroot $tmpdir/bld' " .
   394     "--define '__spec_install_pre \%{___build_pre}' " .
   395     "--nodeps ".$r->{NAME}.".spec"
   396 );
   398 #   providing output
   399 verbose("++ providing output: $output");
   400 if ($output eq '-') {
   401     runcmd("cat $tmpdir/src/*.rpm");
   402 }
   403 else {
   404     runcmd("cp $tmpdir/src/*.rpm $output");
   405 }
   407 #   die gracefully...
   408 verbose("++ cleaning up environment");
   409 cleanup_perform();
   410 exit(0);

mercurial