openpkg/dev.pl

Thu, 04 Oct 2012 20:30:05 +0200

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 04 Oct 2012 20:30:05 +0200
changeset 715
c10fb90893b9
permissions
-rw-r--r--

Correct out of date build configuration, porting to Solaris 11 network
link infrastructure and new libpcap logic. This additionally allows for
device drivers in subdirectories of /dev. Correct packaged nmap
personalities and signatures to work out of the box. Finally, hack
arpd logic to properly close sockets and quit on TERM by repeating
signaling in the run command script. Sadly, all this fails to correct
the run time behaviour of honeyd which fails to bind to the IP layer.

     1 ##
     2 ##  openpkg dev -- OpenPKG Package Development Tool
     3 ##  Copyright (c) 2008-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;
    26 #   OpenPKG instance prefix and RPM
    27 my $openpkg_prefix = $ENV{'OPENPKG_PREFIX'};
    28 delete $ENV{'OPENPKG_PREFIX'};
    30 #   program identification
    31 my $prog_name  = "dev";
    32 my $prog_vers  = "20100111";
    34 #   home-brewn getopt(3) style option parser
    35 sub getopts ($$@) {
    36     my ($opt_spec, $opts, @argv_orig) = @_;
    37     my (%optf) = map { m/(\w)/; $1 => $_ } $opt_spec =~ m/(\w:|\w)/g;
    38     my (@argv, $optarg);
    40     foreach (@argv_orig) {
    41         if (@argv) {
    42             push @argv, $_;
    43         } elsif (defined $optarg) {
    44             if (exists $opts->{$optarg}) {
    45                 $opts->{$optarg} .= " $_";
    46             } else {
    47                 $opts->{$optarg} = $_;
    48             }
    49             $optarg = undef;
    50         } elsif (!/^[-]/) {
    51             push @argv, $_;
    52         } else {
    53             while (/^\-(\w)(.*)/) {
    54                 if (exists $optf{$1}) {
    55                     if (length($optf{$1}) > 1) {
    56                         if ($2 ne '') {
    57                             if (exists $opts->{$1}) {
    58                                 $opts->{$1} .= " $2";
    59                             } else {
    60                                 $opts->{$1} = $2;
    61                             }
    62                         } else {
    63                             $optarg = $1;
    64                         }
    65                         last;
    66                     } else {
    67                         $opts->{$1} = 1;
    68                     }
    69                 } else {
    70                     warn "openpkg:$prog_name:WARNING: unknown option $_\n";
    71                 }
    72                 $_ = "-$2";
    73             }
    74         }
    75     }
    76     if (defined $optarg) {
    77         warn "openpkg:$prog_name:WARNING: option $optarg requires an argument\n";
    78     }
    79     foreach my $opt (keys %optf) {
    80         if (not exists $opts->{$opt}) {
    81             $opts->{$opt} = (length($optf{$opt}) > 1 ? "" : 0);
    82         }
    83     }
    84     return @argv;
    85 }
    87 #   determine reasonable temporary directory
    88 my $tmpdir = ($ENV{"TMPDIR"} || "/tmp");
    89 $tmpdir .= "/openpkg-$prog_name-$$";
    90 my $rc = system("umask 022; $openpkg_prefix/lib/openpkg/shtool mkdir -f -p -m 755 $tmpdir || exit $?");
    91 if ($rc != 0) {
    92     die "failed to create temporary directory: $tmpdir";
    93 }
    95 #   parse command line options
    96 my $opts = {};
    97 @ARGV = getopts("h", $opts, @ARGV);
    99 #   usage sanity check and usage help
   100 sub usage {
   101     my ($rc) = @_;
   102     my $usage =
   103         "openpkg:$prog_name:USAGE: openpkg dev <command> [<options>]\n";
   104     if ($rc == 0) {
   105         print STDOUT $usage;
   106     }
   107     else {
   108         print STDERR $usage;
   109     }
   110     exit($rc);
   111 }
   112 if ($opts->{"h"}) {
   113     usage(0);
   114 }
   115 if (@ARGV == 0) {
   116     usage(1);
   117 }
   119 #   command map
   120 my $map = {
   121     "unpack "            => { -alias => qr/^(up|ex)$/,   -key => "x" },
   122     "edit\n"             => { -alias => qr/^(ed|vi)$/,   -key => "v" },
   123     "build -s track\n"   => { -alias => qr/^(bt|tr)$/,   -key => "t" },
   124     "build -s fetch\n"   => { -alias => qr/^(bf|fe)$/,   -key => "f" },
   125     "build\n"            => { -alias => qr/^(ba|bu)$/,   -key => "b" },
   126     "build -s prep\n"    => { -alias => qr/^bp$/,        -key => "1" },
   127     "build -s compile\n" => { -alias => qr/^bc$/,        -key => "2" },
   128     "build -s install\n" => { -alias => qr/^bi$/,        -key => "3" },
   129     "build -s binary\n"  => { -alias => qr/^bb$/,        -key => "4" },
   130     "build -s source\n"  => { -alias => qr/^bs$/,        -key => "s" },
   131     "peek\n"             => { -alias => qr/^pe$/,        -key => "p" },
   132     "diff\n"             => { -alias => qr/^di$/,        -key => "d" },
   133     "install\n"          => { -alias => qr/^in(?:st)?$/, -key => "i" },
   134     "erase\n"            => { -alias => qr/^er$/,        -key => "e" },
   135     "lint\n"             => { -alias => qr/^li$/,        -key => "l" },
   136     "release "           => { -alias => qr/^rel?$/,      -key => "r" },
   137 };
   139 #   dispatch command
   140 my $cmd = shift(@ARGV);
   141 foreach my $c (keys %{$map}) {
   142     my $a = $map->{$c}->{-alias};
   143     if ($cmd =~ $a) {
   144         $c =~ s/\n$//;
   145         my @args = split(/\s+/, $c);
   146         $cmd = shift(@args);
   147         unshift(@ARGV, @args);
   148         print STDOUT "\033[34m\$ opd $cmd " . join(" ", map {
   149             my $x = $_;
   150             $x =~ s/"/\\"/g;
   151             $x =~ s/^(.*[ \t].*)$/"$1"/;
   152             $x
   153         } @ARGV) . "\033[0m\n";
   154     }
   155 }
   156 my $func = "cmd_$cmd";
   157 if (not defined(&$func)) {
   158     print STDERR "openpkg:$prog_name:ERROR: invalid command \"$cmd\"\n";
   159     usage(1);
   160 }
   161 my $rc = &$func($opts, @ARGV);
   162 exit($rc);
   164 #   execute a shell command
   165 sub run {
   166     my ($cmd) = @_;
   167     print STDOUT "\033[34m\$ $cmd\033[0m\n";
   168     my $rc = system($cmd);
   169     return $rc;
   170 }
   172 #   determine path to package specification
   173 sub specfile {
   174     my $specfile = (glob("*.spec"))[0];
   175     if (not defined $specfile) {
   176         $specfile = (glob("src/*.spec"))[0];
   177         if (not defined $specfile) {
   178             $specfile = (glob("*/*.spec"))[0];
   179             if (not defined $specfile) {
   180                 print STDERR "openpkg:$prog_name:ERROR: unable to determine package specification file\n";
   181                 exit(1);
   182             }
   183         }
   184     }
   185     return $specfile;
   186 }
   188 #   command: interactive shell
   189 sub cmd_shell ($@) {
   190     my ($gopts, @argv) = @_;
   191     my $rc = 0;
   193     #   command line argument processing
   194     my $lopts = {};
   195     @argv = getopts("s", $lopts, @argv);
   197     #   determine release
   198     my $release = `$openpkg_prefix/bin/openpkg release -F '%t'`;
   199     $release =~ s/\n$//s;
   201     #   create dot files
   202     my $screenrc = "$tmpdir/dot.screenrc";
   203     my $bashsh   = "$tmpdir/bash.sh";
   204     my $bashrc   = "$tmpdir/dot.bashrc";
   205     my $inputrc  = "$tmpdir/dot.inputrc";
   206     unlink("$screenrc");
   207     unlink("$bashsh");
   208     unlink("$bashrc");
   209     unlink("$inputrc");
   210     my $title = "openpkg dev";
   211     $title .= '%? %{= rW} %n %{-}%?';
   212     $title .= ' %=%-w%{= rW}%50>%n %t%{-}%+w';
   213     my $screenrc_data = "";
   214     $screenrc_data .= "source \"$ENV{HOME}/.screenrc\"\n" if (-f "$ENV{HOME}/.screenrc");
   215     $screenrc_data .=
   216         "escape          ^Aa\n" .
   217         "startup_message off\n" .
   218         "vbell           off\n" .
   219         "defscrollback   10000\n" .
   220         "defmonitor      off\n" .
   221         "msgminwait      1\n" .
   222         "msgwait         1\n" .
   223         "hardstatus      alwayslastline \" $title \"\n" .
   224         "shell           $bashsh\n";
   225     my $bashsh_data =
   226         "##\n" .
   227         "##\  bash.sh -- \"openpkg dev shell\" GNU bash wrapper script\n" .
   228         "##\n" .
   229         "\n" .
   230         "OPENPKG_PREFIX=\"$openpkg_prefix\"\n" .
   231         "export OPENPKG_PREFIX\n" .
   232         "INPUTRC=\"$inputrc\"\n" .
   233         "export INPUTRC\n" .
   234         "SHELL=\"$openpkg_prefix/lib/openpkg/bash\"\n" .
   235         "export SHELL\n" .
   236         "eval `$openpkg_prefix/bin/openpkg rpm --eval 'T=\"\%{_tmppath}\"; S=\"\%{_specdir}\"; D=\"\%{_sourcedir}\"'`\n" .
   237         "export T S D\n" .
   238         "\$SHELL --rcfile $bashrc";
   239     my $bashrc_data =
   240         "##\n" .
   241         "##  dot.bashrc -- \"openpkg dev shell\" GNU bash configuration\n" .
   242         "##\n" .
   243         "\n" .
   244         "#   load user's standard bash run-command script\n" .
   245         "if [ -f ~/.bashrc ]; then\n" .
   246         "    . ~/.bashrc\n" .
   247         "fi\n" .
   248         "\n" .
   249         "#   configure a special command-line prompt\n" .
   250         "if [ \".\$TERM\" = .screen ]; then\n" .
   251         "    PS1=\"\\\\u@\\\\h:\\\\w [P=\\\\e[1m\\\${OPENPKG_PREFIX}\\\\e[0m]\\n\\\\\\\$ \\\\ek\\\\W\\\\e\\\\\\\\\"\n" .
   252         "else\n" .
   253         "    PS1=\"\\\\u@\\\\h:\\\\w [P=\\\\e[1m\\\${OPENPKG_PREFIX}\\\\e[0m]\\n\\\\\\\$ \"\n" .
   254         "fi\n" .
   255         "alias openpkg=\"\\\${OPENPKG_PREFIX}/bin/openpkg\"\n" .
   256         "alias opd=\"\\\${OPENPKG_PREFIX}/bin/openpkg dev\"\n" .
   257         "\n";
   258     my $inputrc_data =
   259         "##\n" .
   260         "##  dot.inputrc -- \"openpkg dev shell\" GNU readline configuration\n" .
   261         "##\n" .
   262         "\n";
   263     foreach my $c (keys %{$map}) {
   264         my $k = $map->{$c}->{-key};
   265         $c =~ s/\n/\\n/sg;
   266         $inputrc_data .= "\"\\e$k\": \"opd $c\"\n";
   267     }
   268     $inputrc_data .= "\n";
   269     open(SCREENRC, ">$screenrc");
   270     print(SCREENRC $screenrc_data);
   271     close(SCREENRC);
   272     open(BASHSH, ">$bashsh");
   273     print(BASHSH $bashsh_data);
   274     close(BASHSH);
   275     system("chmod a+x $bashsh");
   276     open(BASHRC, ">$bashrc");
   277     print(BASHRC $bashrc_data);
   278     close(BASHRC);
   279     open(INPUTRC, ">$inputrc");
   280     print(INPUTRC $inputrc_data);
   281     close(INPUTRC);
   283     #   run interactive shell
   284     print STDOUT "\033[34m++ entering OpenPKG $release development shell\033[0m\n";
   285     my $rc;
   286     if ($lopts->{"s"}) {
   287         $rc = system("screen -c $screenrc -S 'openpkg-dev-shell' -d -R");
   288     }
   289     else {
   290         $rc = system("$bashsh");
   291     }
   293     #   cleanup
   294     unlink("$tmpdir/dot.screenrc");
   295     unlink("$tmpdir/bash.sh");
   296     unlink("$tmpdir/dot.bashrc");
   297     unlink("$tmpdir/dot.inputrc");
   298     unlink("$tmpdir");
   300     return $rc;
   301 }
   303 #   command: unpack source RPM
   304 sub cmd_unpack ($@) {
   305     my ($gopts, @argv) = @_;
   306     my $rc = 0;
   308     #   command line argument processing
   309     my $lopts = {};
   310     @argv = getopts("l:b:sd", $lopts, @argv);
   311     if ($lopts->{"l"} eq "") {
   312         $lopts->{"l"} = "structured";
   313     }
   314     if ($lopts->{"l"} !~ m/^(global|local|simple|structured|distributed)$/) {
   315         die sprintf("invalid layout type \"%s\"", $lopts->{"l"});
   316     }
   317     if (@argv != 1) {
   318         die sprintf("exactly one SRPM has to be given");
   319     }
   320     my $srpm = $argv[0];
   321     if (not -f $srpm) {
   322         die sprintf("SRPM \"%s\" has to be a regular file", $srpm);
   323     }
   324     my $name = `$openpkg_prefix/bin/openpkg rpm -qp --qf '\%{NAME}' $srpm 2>/dev/null || true`;
   325     $name =~ s/\r?\n$//s;
   326     if ($name eq '') {
   327         die sprintf("unable to determine package name from SRPM \"%s\"", $srpm);
   328     }
   329     if ($lopts->{"b"} eq "") {
   330         $lopts->{"b"} = $srpm;
   331         if ($lopts->{"b"} =~ m/\.src\.rpm$/) {
   332             $lopts->{"b"} =~ s/\.src\.rpm$//;
   333         }
   334         else {
   335             my $subdir = `$openpkg_prefix/bin/openpkg rpm -qp --qf '\%{NAME}-\%{VERSION}-\%{RELEASE}' $srpm 2>/dev/null || true`;
   336             $lopts->{"b"} = $subdir;
   337         }
   338     }
   340     #   determine result directory
   341     my $basedir = $lopts->{"b"};
   342     my ($macrosfile, $specdir, $sourcedir);
   343     if ($lopts->{"l"} eq "global") {
   344         $macrosdir  = "$openpkg_prefix/etc/openpkg";
   345         $macrosfile = "$openpkg_prefix/etc/openpkg/rpmmacros";
   346         $specdir    = "$openpkg_prefix/RPM/SRC/$name";
   347         $sourcedir  = "$openpkg_prefix/RPM/SRC/$name";
   348         $builddir   = "$openpkg_prefix/RPM/TMP";
   349         $tmpdir     = "$openpkg_prefix/RPM/TMP";
   350         $binrpmdir  = "$openpkg_prefix/RPM/PKG";
   351         $srcrpmdir  = "$openpkg_prefix/RPM/PKG";
   352     }
   353     elsif ($lopts->{"l"} eq "local") {
   354         $macrosdir  = "$basedir/.openpkg";
   355         $macrosfile = "$basedir/.openpkg/rpmmacros";
   356         $specdir    = "$basedir";
   357         $sourcedir  = "$basedir";
   358         $builddir   = "$basedir";
   359         $tmpdir     = "$basedir";
   360         $binrpmdir  = "$basedir";
   361         $srcrpmdir  = "$basedir";
   362     }
   363     elsif ($lopts->{"l"} eq "simple") {
   364         $macrosdir  = "$basedir/.openpkg";
   365         $macrosfile = "$basedir/.openpkg/rpmmacros";
   366         $specdir    = "$basedir";
   367         $sourcedir  = "$basedir";
   368         $builddir   = "$tmpdir";
   369         $tmpdir     = "$tmpdir";
   370         $binrpmdir  = "$basedir/..";
   371         $srcrpmdir  = "$basedir/..";
   372     }
   373     elsif ($lopts->{"l"} eq "structured") {
   374         $macrosdir  = "$basedir/.openpkg";
   375         $macrosfile = "$basedir/.openpkg/rpmmacros";
   376         $specdir    = "$basedir/src";
   377         $sourcedir  = "$basedir/dst";
   378         $builddir   = "$basedir/tmp";
   379         $tmpdir     = "$basedir/tmp";
   380         $binrpmdir  = "$basedir/pkg/bin";
   381         $srcrpmdir  = "$basedir/pkg/src";
   382     }
   383     elsif ($lopts->{"l"} eq "distributed") {
   384         $macrosdir  = "$basedir/.openpkg";
   385         $macrosfile = "$basedir/.openpkg/rpmmacros";
   386         $specdir    = "$basedir/src/$name";
   387         $sourcedir  = "$basedir/dst/$name";
   388         $builddir   = "$basedir/tmp";
   389         $tmpdir     = "$basedir/tmp";
   390         $binrpmdir  = "$basedir/pkg/bin";
   391         $srcrpmdir  = "$basedir/pkg/src";
   392     }
   394     #   create still missing directories
   395     foreach my $dir ($macrosdir, $specdir, $sourcedir, $builddir, $tmpdir, $binrpmdir, $srcrpmdir) {
   396         if (not -d $dir) {
   397             print STDOUT "openpkg:$prog_name: creating directory \"$dir\"\n";
   398             system("$openpkg_prefix/lib/openpkg/shtool mkdir -f -p -m 755 $dir");
   399         }
   400     }
   402     #   unpack SRPM
   403     print STDOUT "openpkg:$prog_name: unpacking source: \"$srpm\"\n";
   404     print STDOUT "openpkg:$prog_name: unpacking target: \"$specdir\"\n";
   405     print STDOUT "openpkg:$prog_name: unpacking target: \"$sourcedir\"\n";
   406     my $abs_specdir = $specdir;
   407     my $abs_sourcedir = $sourcedir;
   408     my $pwd = `pwd`; $pwd =~ s/\r?\n$//s;
   409     $abs_specdir   = "$pwd/$abs_specdir"   if ($abs_specdir   !~ m/^\//);
   410     $abs_sourcedir = "$pwd/$abs_sourcedir" if ($abs_sourcedir !~ m/^\//);
   411     my $rc = system(
   412         "$openpkg_prefix/bin/openpkg" .
   413         " --keep-privileges" .
   414         " rpm" .
   415         " -i" .
   416         " --define '_specdir $abs_specdir'" .
   417         " --define '_sourcedir $abs_sourcedir'" .
   418         " $srpm"
   419     );
   421     #   fix location of files
   422     if (not -f "$specdir/$name.spec") {
   423         die sprintf("failed to install package \"%s\": file \"%s\" not found\n", $srpm, "$specdir/$name.spec");
   424     }
   425     open(SPEC, "<$specdir/$name.spec");
   426     my $spec = ""; { local $/; $spec = <SPEC>; }
   427     close(SPEC);
   428     my $src = {};
   429     $spec =~ s/^(?:Source|Patch)\d+:\s+(\S+)/$src->{$1} = 1, ''/mgei;
   430     foreach my $file (keys %{$src}) {
   431         if ($file !~ m/^(https?|ftp):\/\//) {
   432             if (not -f "$specdir/$file" and -f "$sourcedir/$file") {
   433                 system("mv $sourcedir/$file $specdir/$file");
   434             }
   435         }
   436     }
   438     #   create .openpkg/rpmmacros file
   439     if (not -f $macrosfile) {
   440         print STDOUT "openpkg:$prog_name: creating file: \"$macrosfile\"\n";
   441         my $rpmmacros =
   442             "##\n" .
   443             "##  .openpkg/rpmmacros -- local OpenPKG RPM macro definitions\n" .
   444             "##\n" .
   445             "\n" .
   446             "\%openpkg_layout" .
   447             " macrosfile=\%{macrosfile}" .
   448             " layout=" . $lopts->{"l"} .
   449             " shared=" . ($lopts->{"s"} ? "yes" : "no") .
   450             " debug=" . ($lopts->{"d"} ? "yes" : "no") .
   451             "\n" .
   452             "\n";
   453         open(MACROS, ">$macrosfile");
   454         print(MACROS $rpmmacros);
   455         close(MACROS);
   456     }
   458     return $rc;
   459 }
   461 #   command: edit package specification
   462 sub cmd_edit ($@) {
   463     my ($gopts, @argv) = @_;
   464     my $rc = 0;
   466     #   run editor
   467     my $editor = ($ENV{"EDITOR"} || "vi");
   468     my $specfile = ($argv[0] || specfile());
   469     run("$editor $specfile");
   471     return $rc;
   472 }
   474 #   command: build package
   475 sub cmd_build ($@) {
   476     my ($gopts, @argv) = @_;
   477     my $rc = 0;
   479     #   command line argument processing
   480     my $lopts = {};
   481     @argv = getopts("s:D:w:", $lopts, @argv);
   482     if ($lopts->{"s"} eq '') {
   483         $lopts->{"s"} = "all";
   484     }
   485     if ($lopts->{"s"} !~ m/^(track|fetch|prep|compile|install|binary|source|all)$/) {
   486         die "invalid step";
   487     }
   489     #   assembly defines
   490     my $defs = "";
   491     if ($lopts->{"D"}) {
   492         foreach my $def (split(/\s+/, $lopts->{"D"})) {
   493             if ($def =~ m/^([^=]+)=(.+)$/) {
   494                 $defs .= "--define '$1 $2' ";
   495             }
   496             else {
   497                 $defs .= "--define '$def yes' ";
   498             }
   499         }
   500     }
   501     if ($lopts->{"w"}) {
   502         foreach my $def (split(/\s+/, $lopts->{"w"})) {
   503             $defs .= "--with $def ";
   504         }
   505     }
   507     #   run build command
   508     my $specfile = ($argv[0] || specfile());
   509     if ($lopts->{"s"} eq 'track') {
   510         run("$openpkg_prefix/bin/openpkg rpm -bt $defs$specfile");
   511     }
   512     elsif ($lopts->{"s"} eq 'fetch') {
   513         run("$openpkg_prefix/bin/openpkg rpm -bf $defs$specfile");
   514     }
   515     elsif ($lopts->{"s"} eq 'prep') {
   516         run("$openpkg_prefix/bin/openpkg rpm -bp $defs$specfile");
   517     }
   518     elsif ($lopts->{"s"} eq 'compile') {
   519         run("$openpkg_prefix/bin/openpkg rpm -bc --short-circuit $defs$specfile");
   520     }
   521     elsif ($lopts->{"s"} eq 'install') {
   522         run("$openpkg_prefix/bin/openpkg rpm -bi --short-circuit $defs$specfile");
   523     }
   524     elsif ($lopts->{"s"} eq 'binary') {
   525         run("$openpkg_prefix/bin/openpkg rpm -bb --short-circuit $defs$specfile");
   526     }
   527     elsif ($lopts->{"s"} eq 'source') {
   528         run("$openpkg_prefix/bin/openpkg rpm -bs $defs$specfile");
   529     }
   530     elsif ($lopts->{"s"} eq 'all') {
   531         run("$openpkg_prefix/bin/openpkg rpm -ba $defs$specfile");
   532     }
   534     return $rc;
   535 }
   537 #   command: peek into package
   538 sub cmd_peek ($@) {
   539     my ($gopts, @argv) = @_;
   540     my $rc = 0;
   542     #   run query command
   543     my $template = `$openpkg_prefix/bin/openpkg rpm --eval '%{_rpmdir}/%{_rpmfilename}'`;
   544     $template =~ s/\n$//s;
   545     my $specfile = specfile();
   546     my $rpm = `$openpkg_prefix/bin/openpkg rpm -q --specfile '$specfile' --qf 'XXX$template'`;
   547     $rpm =~ s/^XXX//s;
   548     $rpm =~ s/\n$//s;
   550     #   determine files
   551     print STDOUT "\033[34m++ determining configuration files\033[0m\n";
   552     my @cfgfiles = split(/\n/, `$openpkg_prefix/bin/openpkg rpm -qplc $rpm`);
   553     print STDOUT "\033[34m++ determining documentation files\033[0m\n";
   554     my @docfiles = split(/\n/, `$openpkg_prefix/bin/openpkg rpm -qpld $rpm`);
   555     print STDOUT "\033[34m++ determining all file information\033[0m\n";
   556     my @allfiles = split(/\n/, `$openpkg_prefix/bin/openpkg rpm -qplv $rpm`);
   558     #   create package file listing
   559     foreach my $line (@allfiles) {
   560         $prefix = "";
   561         foreach my $docfile (@docfiles) {
   562             if ($line =~ m/\s+$docfile\b/s) {
   563                 $prefix .= "D";
   564                 last;
   565             }
   566         }
   567         foreach my $cfgfile (@cfgfiles) {
   568             if ($line =~ m/\s+$cfgfile\b/s) {
   569                 $prefix .= "C";
   570                 last;
   571             }
   572         }
   573         $prefix .= "--";
   574         $prefix = substr($prefix, 0, 2);
   575         if ($line =~ m/^d/) {
   576             $line =~ s/(\s+\/\S+)/\033[34m$1\033[0m/s;
   577         }
   578         print "$prefix $line\n";
   579     }
   581     return $rc;
   582 }
   584 #   command: show modifications via VCS
   585 sub cmd_diff ($@) {
   586     my ($gopts, @argv) = @_;
   587     my $rc = 0;
   589     my $vcs = "";
   590     my $cmd = "";
   591     if (-d "CVS") {
   592         $vcs = "CVS";
   593         $cmd = "cvs diff -u3";
   594     }
   595     elsif (-d ".svn") {
   596         $vcs = "Subversion";
   597         $cmd = "svn diff";
   598     }
   599     elsif (-d "_MTN"          or -d ".mtn" or
   600            -d "../_MTN"       or -d "../.mtn" or
   601            -d "../../_MTN"    or -d "../../.mtn" or
   602            -d "../../../_MTN" or -d "../../../.mtn") {
   603         $vcs = "Monotone";
   604         $cmd = "mtn diff .";
   605     }
   606     elsif (-d ".git" or
   607            -d "../.git" or
   608            -d "../../.git" or
   609            -d "../../../.git") {
   610         $vcs = "Git";
   611         $cmd = "git diff . ";
   612     }
   613     elsif (-d ".hg" or
   614            -d "../.hg" or
   615            -d "../../.hg" or
   616            -d "../../../.hg") {
   617         $vcs = "Mercurial";
   618         $cmd = "hg diff ."
   619     }
   620     else {
   621         $vcs = "OSSP svs";
   622         $cmd = "svs diff";
   623     }
   624     print STDOUT "\033[34m++ modifications as known to underlying $vcs VCS\033[0m\n";
   625     run($cmd);
   626 }
   628 #   command: install package
   629 sub cmd_install ($@) {
   630     my ($gopts, @argv) = @_;
   631     my $rc = 0;
   633     #   command line argument processing
   634     my $lopts = {};
   635     @argv = getopts("fnos", $lopts, @argv);
   637     #   run install command
   638     my $template = `$openpkg_prefix/bin/openpkg rpm --eval '%{_rpmdir}/%{_rpmfilename}'`;
   639     $template =~ s/\n$//s;
   640     my $specfile = specfile();
   641     my $rpm = `$openpkg_prefix/bin/openpkg rpm -q --specfile '$specfile' --qf 'XXX$template'`;
   642     $rpm =~ s/^XXX//s;
   643     $rpm =~ s/\n$//s;
   644     chdir("/");
   645     run(($lopts->{"s"} ? "sudo " : "") .
   646         "$openpkg_prefix/bin/openpkg rpm -Uvh"
   647         . ($lopts->{"f"} ? " --force" : "")
   648         . ($lopts->{"n"} ? " --nodeps" : "")
   649         . ($lopts->{"o"} ? " --oldpackage" : "")
   650         . " $rpm");
   652     return $rc;
   653 }
   655 #   command: erase package
   656 sub cmd_erase ($@) {
   657     my ($gopts, @argv) = @_;
   658     my $rc = 0;
   660     #   command line argument processing
   661     my $lopts = {};
   662     @argv = getopts("fnas", $lopts, @argv);
   664     #   run erase command
   665     my $specfile = specfile();
   666     my $name = `$openpkg_prefix/bin/openpkg rpm -q --specfile $specfile --qf '%{NAME}'`;
   667     $name =~ s/\n$//s;
   668     chdir("/");
   669     run(($lopts->{"s"} ? "sudo " : "") .
   670         "$openpkg_prefix/bin/openpkg rpm -e"
   671         . ($lopts->{"f"} ? " --force" : "")
   672         . ($lopts->{"n"} ? " --nodeps" : "")
   673         . ($lopts->{"a"} ? " --allmatches" : "")
   674         . " $name");
   676     return $rc;
   677 }
   679 #   command: lint package
   680 sub cmd_lint ($@) {
   681     my ($gopts, @argv) = @_;
   682     my $rc = 0;
   684     #   command line argument processing
   685     my $lopts = {};
   686     @argv = getopts("vb", $lopts, @argv);
   688     #   run source linting commands
   689     my $specfile = specfile();
   690     my $fslfile = $specfile;
   691     $fslfile =~ s/([^\/]+)\.spec$/fsl.$1/s;
   692     my $rcfile = $specfile;
   693     $rcfile =~ s/([^\/]+)\.spec$/rc.$1/s;
   694     my $name = `$openpkg_prefix/bin/openpkg rpm -q --specfile $specfile --qf '%{NAME}'`;
   695     $name =~ s/\n$//s;
   696     my $template = `$openpkg_prefix/bin/openpkg rpm --eval '%{_rpmdir}/%{_rpmfilename}'`;
   697     $template =~ s/\n$//s;
   698     my $rpm = `$openpkg_prefix/bin/openpkg rpm -q --specfile '$specfile' --qf 'XXX$template'`;
   699     $rpm =~ s/^XXX//s;
   700     $rpm =~ s/\n$//s;
   701     my $rc = 0;
   702     $rc += run("$openpkg_prefix/bin/openpkg lint-spec" . ($lopts->{"v"} ? " --verbose" : "") . " $specfile");
   703     $rc += run("$openpkg_prefix/bin/openpkg lint-fsl"  . ($lopts->{"v"} ? " --verbose" : "") . " $fslfile") if (-f $fslfile);
   704     $rc += run("$openpkg_prefix/bin/openpkg lint-rc"   . ($lopts->{"v"} ? " --verbose" : "") . " $rcfile")  if (-f $rcfile);
   706     #   optionally run binary linting command
   707     run("$openpkg_prefix/bin/openpkg lint-rpm" . ($lopts->{"v"} ? " --verbose" : "") . " $rpm") if (-f $rpm and not $lopts->{"b"});
   709     return $rc;
   710 }
   712 #   command: release package
   713 sub cmd_release ($@) {
   714     my ($gopts, @argv) = @_;
   715     my $rc = 0;
   717     #   command line argument processing
   718     my $lopts = {};
   719     @argv = getopts("nm:f", $lopts, @argv);
   721     #   implicit linting
   722     if (not $lopts->{"f"}) {
   723         my $rc = cmd_lint($gopts);
   724         if ($rc != 0 and !$lopts->{"f"}) {
   725             return $rc;
   726         }
   727     }
   729     #   sanity check environment
   730     my $cmd = $ENV{"OPENPKG_DEV_RELEASE"}
   731         || `$openpkg_prefix/bin/openpkg rpm --eval '%{openpkg_dev_release}' 2>/dev/null || true` || "";
   732     $cmd =~ s/\n$//s;
   733     if ($cmd eq "") {
   734         print STDERR "openpkg:$prog_name:ERROR: no \$OPENPKG_DEV_RELEASE command defined\n";
   735         exit(1);
   736     }
   738     #
   739     #   determine package information
   740     #
   742     print STDOUT "\033[34m++ determining package information\033[0m\n";
   743     my $info = {};
   744     $info->{"openpkg-prefix"} = $openpkg_prefix;
   745     $info->{"option-force"} = $lopts->{"f"} ? "yes" : "no";
   747     print STDOUT "-- determining package name/version/release\n";
   748     my $specfile = specfile();
   749     my $result = `$openpkg_prefix/bin/openpkg rpm -q --specfile $specfile --qf '::%{NAME}::%{VERSION}::%{RELEASE}'`;
   750     $result =~ s/\n$//s;
   751     $result =~ s/^:://s;
   752     my @result = split(/::/, $result);
   753     $info->{"package-name"}    = $result[0];
   754     $info->{"package-version"} = $result[1];
   755     $info->{"package-release"} = $result[2];
   757     print STDOUT "-- determining package source and distribution location\n";
   758     my $defines = "--define '\%name " . $info->{"package-name"} . "'";
   759     $defines .= " --define '\%version " . $info->{"package-version"} . "'";
   760     $defines .= " --define '\%release " . $info->{"package-release"} . "'";
   761     my $result = `$openpkg_prefix/bin/openpkg rpm $defines --eval '%{_specdir}::%{_sourcedir}'`;
   762     $result =~ s/\n$//s;
   763     @result = split(/::/, $result);
   764     $info->{"spec-dir"}   = $result[0];
   765     $info->{"source-dir"} = $result[1];
   767     print STDOUT "-- determining package source and binary RPM files\n";
   768     my $template = `$openpkg_prefix/bin/openpkg rpm --eval '%{_rpmdir}/%{l_binrpmfilename}::%{_srcrpmdir}/%{l_srcrpmfilename}'`;
   769     $template =~ s/\n$//s;
   770     $result = `$openpkg_prefix/bin/openpkg rpm -q --specfile $specfile --qf '::$template'`;
   771     $result =~ s/\n$//s;
   772     $result =~ s/^:://s;
   773     @result = split(/::/, $result);
   774     $info->{"binary-rpm-file"} = $result[0];
   775     $info->{"source-rpm-file"} = $result[1];
   776     $info->{"package-version-old"} = "";
   777     $info->{"package-release-old"} = "";
   778     $info->{"vcs"} = "none";
   780     print STDOUT "-- determining previous package version/release\n";
   781     my $vcs = "";
   782     my $diff = "";
   783     my $content_old = "";
   784     my $specdir  = $info->{"spec-dir"};
   785     my $specfile = $info->{"package-name"} . ".spec";
   786     if (-f "$specdir/$specfile") {
   787         open(FP, "<$specdir/$specfile");
   788         $content_new .= $_ while (<FP>);
   789         close(FP);
   790         if ($content_new =~ m/\n\%No(?:Source|Patch)\s+/s) {
   791             $info->{"source-rpm-file"} =~ s/\.src\.rpm$/.nosrc.rpm/s;
   792         }
   793         if (-d "$specdir/CVS") {
   794             #   package is version controlled via CVS
   795             $vcs = "cvs";
   796             $diff = `(cd $specdir && cvs diff -u3 $specfile) 2>/dev/null || true`;
   797         }
   798         elsif (-d "$specdir/.svn") {
   799             #   package is version controlled via Subverson (SVN)
   800             $vcs = "svn";
   801             $diff = `(cd $specdir && svn diff $specfile) 2>/dev/null || true`;
   802         }
   803         elsif (-d "$specdir/_MTN"          or -d "$specdir/.mtn" or
   804                -d "$specdir/../_MTN"       or -d "$specdir/../.mtn" or
   805                -d "$specdir/../../_MTN"    or -d "$specdir/../../.mtn" or
   806                -d "$specdir/../../../_MTN" or -d "$specdir/../../../.mtn") {
   807             #   package is version controlled via Monotone (MTN)
   808             $vcs = "mtn";
   809             $diff = `(cd $specdir && mtn diff $specfile) 2>/dev/null || true`;
   810             $content_old = `(cd $specdir && mtn automate get_file_of -r h: $specfile) 2>/dev/null || true`;
   811         }
   812         elsif (-d "$specdir/.git" or
   813                -d "$specdir/../.git" or
   814                -d "$specdir/../../.git" or
   815                -d "$specdir/../../../.git") {
   816             #   package is version controlled via Git
   817             $vcs = "git";
   818             $diff = `(cd $specdir && git diff $specfile) 2>/dev/null || true`;
   819         }
   820         elsif (-d "$specdir/.hg" or
   821                -d "$specdir/../.hg" or
   822                -d "$specdir/../../.hg" or
   823                -d "$specdir/../../../.hg") {
   824             #   package is version controlled via Mercurial (Hg)
   825             $vcs = "hg";
   826             $diff = `(cd $specdir && hg diff $specfile) 2>/dev/null || true`;
   827         }
   828         elsif (-f "$specdir/$specfile.orig") {
   829             #   package is patched via OSSP svs
   830             $vcs = "svs";
   831             $diff = `(cd $specdir && svs diff $specfile) 2>/dev/null || true`;
   832         }
   833         if ($vcs ne '') {
   834             $info->{"vcs"} = $vcs;
   835         }
   836         if ($content_old ne '') {
   837             my $define = {};
   838             $content_old =~ s/\n\%define[ \t]+([^ \t\n]+)[ \t]+([^ \t\n]+)/$define->{$1} = $2, ''/sge;
   839             $content_old =~ s/\n([^ \t\n]+):[ \t]+([^ \t\n]+)/$define->{lc($1)} = $2, ''/sge;
   840             sub resolve {
   841                 my ($define, $name) = @_;
   842                 my $value = $define->{$name};
   843                 $value = "" if (not defined $value);
   844                 $value =~ s/\%\{(.+?)\}/resolve($define, $1)/sge;
   845                 return $value;
   846             }
   847             $info->{"package-version-old"} = resolve($define, "version");
   848             $info->{"package-release-old"} = resolve($define, "release");
   849         }
   850         if ((   $info->{"package-version-old"} eq ''
   851              or $info->{"package-release-old"} eq '')
   852             and $diff ne ''                          ) {
   853             if ($info->{"package-version-old"} eq '' and $diff =~ m/\n-Version:\s+(\S+)/s) {
   854                 $info->{"package-version-old"} = $1;
   855             }
   856             if ($info->{"package-release-old"} eq '' and $diff =~ m/\n-Release:\s+(\S+)/s) {
   857                 $info->{"package-release-old"} = $1;
   858             }
   859         }
   860     }
   862     print STDOUT "-- determining commit message\n";
   863     $info->{"commit-message"} = ($lopts->{"m"} || "");
   864     if ($info->{"commit-message"} eq "") {
   865         if ($info->{"package-version-old"} ne $info->{"package-version"}) {
   866             #   new version
   867             $info->{"commit-message"} = "upgrading package: " .
   868                 $info->{"package-name"} . " " .
   869                 $info->{"package-version-old"} . " -> " .
   870                 $info->{"package-version"};
   871         }
   872         elsif (!$lopts->{"f"}) {
   873             print STDERR "openpkg:$prog_name:ERROR: package version not changed -- you have to manually provide a commit message\n";
   874             exit(1);
   875         }
   876     }
   878     #   run external command
   879     print STDOUT "\033[34m++ executing openpkg development release program\033[0m\n";
   880     $cmd .= " %{openpkg-prefix}";
   881     $cmd .= " %{spec-dir} %{source-dir} %{binary-rpm-file} %{source-rpm-file}";
   882     $cmd .= " %{package-name} %{package-version} %{package-release} %{package-version-old} %{package-release-old}";
   883     $cmd .= " %{commit-message} %{vcs}";
   884     $cmd .= " %{option-force}";
   885     $cmd =~ s/(\%\{([a-z][a-z-]+)\})/&subst($info, $1, $2)/sge;
   886     sub subst {
   887         my ($info, $text, $name) = @_;
   888         if (exists($info->{$name})) {
   889             $text = $info->{$name};
   890             $text =~ s/'/\\'/sg;
   891             $text = "'$text'";
   892         }
   893     }
   894     if ($lopts->{"n"}) {
   895         print STDOUT "-- DRY RUN:\n";
   896         print STDOUT "-- $cmd\n";
   897         $rc = 0;
   898     }
   899     else {
   900         $rc = system($cmd);
   901     }
   903     return $rc;
   904 }

mercurial