diff -r 71503088f51b -r f880f219c566 openpkg/dev.pl
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/openpkg/dev.pl Tue Jul 31 12:23:42 2012 +0200
@@ -0,0 +1,905 @@
+##
+## openpkg dev -- OpenPKG Package Development Tool
+## Copyright (c) 2008-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;
+
+# OpenPKG instance prefix and RPM
+my $openpkg_prefix = $ENV{'OPENPKG_PREFIX'};
+delete $ENV{'OPENPKG_PREFIX'};
+
+# program identification
+my $prog_name = "dev";
+my $prog_vers = "20100111";
+
+# home-brewn getopt(3) style option parser
+sub getopts ($$@) {
+ my ($opt_spec, $opts, @argv_orig) = @_;
+ my (%optf) = map { m/(\w)/; $1 => $_ } $opt_spec =~ m/(\w:|\w)/g;
+ my (@argv, $optarg);
+
+ foreach (@argv_orig) {
+ 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:$prog_name:WARNING: unknown option $_\n";
+ }
+ $_ = "-$2";
+ }
+ }
+ }
+ if (defined $optarg) {
+ warn "openpkg:$prog_name:WARNING: option $optarg requires an argument\n";
+ }
+ foreach my $opt (keys %optf) {
+ if (not exists $opts->{$opt}) {
+ $opts->{$opt} = (length($optf{$opt}) > 1 ? "" : 0);
+ }
+ }
+ return @argv;
+}
+
+# determine reasonable temporary directory
+my $tmpdir = ($ENV{"TMPDIR"} || "/tmp");
+$tmpdir .= "/openpkg-$prog_name-$$";
+my $rc = system("umask 022; $openpkg_prefix/lib/openpkg/shtool mkdir -f -p -m 755 $tmpdir || exit $?");
+if ($rc != 0) {
+ die "failed to create temporary directory: $tmpdir";
+}
+
+# parse command line options
+my $opts = {};
+@ARGV = getopts("h", $opts, @ARGV);
+
+# usage sanity check and usage help
+sub usage {
+ my ($rc) = @_;
+ my $usage =
+ "openpkg:$prog_name:USAGE: openpkg dev []\n";
+ if ($rc == 0) {
+ print STDOUT $usage;
+ }
+ else {
+ print STDERR $usage;
+ }
+ exit($rc);
+}
+if ($opts->{"h"}) {
+ usage(0);
+}
+if (@ARGV == 0) {
+ usage(1);
+}
+
+# command map
+my $map = {
+ "unpack " => { -alias => qr/^(up|ex)$/, -key => "x" },
+ "edit\n" => { -alias => qr/^(ed|vi)$/, -key => "v" },
+ "build -s track\n" => { -alias => qr/^(bt|tr)$/, -key => "t" },
+ "build -s fetch\n" => { -alias => qr/^(bf|fe)$/, -key => "f" },
+ "build\n" => { -alias => qr/^(ba|bu)$/, -key => "b" },
+ "build -s prep\n" => { -alias => qr/^bp$/, -key => "1" },
+ "build -s compile\n" => { -alias => qr/^bc$/, -key => "2" },
+ "build -s install\n" => { -alias => qr/^bi$/, -key => "3" },
+ "build -s binary\n" => { -alias => qr/^bb$/, -key => "4" },
+ "build -s source\n" => { -alias => qr/^bs$/, -key => "s" },
+ "peek\n" => { -alias => qr/^pe$/, -key => "p" },
+ "diff\n" => { -alias => qr/^di$/, -key => "d" },
+ "install\n" => { -alias => qr/^in(?:st)?$/, -key => "i" },
+ "erase\n" => { -alias => qr/^er$/, -key => "e" },
+ "lint\n" => { -alias => qr/^li$/, -key => "l" },
+ "release " => { -alias => qr/^rel?$/, -key => "r" },
+};
+
+# dispatch command
+my $cmd = shift(@ARGV);
+foreach my $c (keys %{$map}) {
+ my $a = $map->{$c}->{-alias};
+ if ($cmd =~ $a) {
+ $c =~ s/\n$//;
+ my @args = split(/\s+/, $c);
+ $cmd = shift(@args);
+ unshift(@ARGV, @args);
+ print STDOUT "\033[34m\$ opd $cmd " . join(" ", map {
+ my $x = $_;
+ $x =~ s/"/\\"/g;
+ $x =~ s/^(.*[ \t].*)$/"$1"/;
+ $x
+ } @ARGV) . "\033[0m\n";
+ }
+}
+my $func = "cmd_$cmd";
+if (not defined(&$func)) {
+ print STDERR "openpkg:$prog_name:ERROR: invalid command \"$cmd\"\n";
+ usage(1);
+}
+my $rc = &$func($opts, @ARGV);
+exit($rc);
+
+# execute a shell command
+sub run {
+ my ($cmd) = @_;
+ print STDOUT "\033[34m\$ $cmd\033[0m\n";
+ my $rc = system($cmd);
+ return $rc;
+}
+
+# determine path to package specification
+sub specfile {
+ my $specfile = (glob("*.spec"))[0];
+ if (not defined $specfile) {
+ $specfile = (glob("src/*.spec"))[0];
+ if (not defined $specfile) {
+ $specfile = (glob("*/*.spec"))[0];
+ if (not defined $specfile) {
+ print STDERR "openpkg:$prog_name:ERROR: unable to determine package specification file\n";
+ exit(1);
+ }
+ }
+ }
+ return $specfile;
+}
+
+# command: interactive shell
+sub cmd_shell ($@) {
+ my ($gopts, @argv) = @_;
+ my $rc = 0;
+
+ # command line argument processing
+ my $lopts = {};
+ @argv = getopts("s", $lopts, @argv);
+
+ # determine release
+ my $release = `$openpkg_prefix/bin/openpkg release -F '%t'`;
+ $release =~ s/\n$//s;
+
+ # create dot files
+ my $screenrc = "$tmpdir/dot.screenrc";
+ my $bashsh = "$tmpdir/bash.sh";
+ my $bashrc = "$tmpdir/dot.bashrc";
+ my $inputrc = "$tmpdir/dot.inputrc";
+ unlink("$screenrc");
+ unlink("$bashsh");
+ unlink("$bashrc");
+ unlink("$inputrc");
+ my $title = "openpkg dev";
+ $title .= '%? %{= rW} %n %{-}%?';
+ $title .= ' %=%-w%{= rW}%50>%n %t%{-}%+w';
+ my $screenrc_data = "";
+ $screenrc_data .= "source \"$ENV{HOME}/.screenrc\"\n" if (-f "$ENV{HOME}/.screenrc");
+ $screenrc_data .=
+ "escape ^Aa\n" .
+ "startup_message off\n" .
+ "vbell off\n" .
+ "defscrollback 10000\n" .
+ "defmonitor off\n" .
+ "msgminwait 1\n" .
+ "msgwait 1\n" .
+ "hardstatus alwayslastline \" $title \"\n" .
+ "shell $bashsh\n";
+ my $bashsh_data =
+ "##\n" .
+ "##\ bash.sh -- \"openpkg dev shell\" GNU bash wrapper script\n" .
+ "##\n" .
+ "\n" .
+ "OPENPKG_PREFIX=\"$openpkg_prefix\"\n" .
+ "export OPENPKG_PREFIX\n" .
+ "INPUTRC=\"$inputrc\"\n" .
+ "export INPUTRC\n" .
+ "SHELL=\"$openpkg_prefix/lib/openpkg/bash\"\n" .
+ "export SHELL\n" .
+ "eval `$openpkg_prefix/bin/openpkg rpm --eval 'T=\"\%{_tmppath}\"; S=\"\%{_specdir}\"; D=\"\%{_sourcedir}\"'`\n" .
+ "export T S D\n" .
+ "\$SHELL --rcfile $bashrc";
+ my $bashrc_data =
+ "##\n" .
+ "## dot.bashrc -- \"openpkg dev shell\" GNU bash configuration\n" .
+ "##\n" .
+ "\n" .
+ "# load user's standard bash run-command script\n" .
+ "if [ -f ~/.bashrc ]; then\n" .
+ " . ~/.bashrc\n" .
+ "fi\n" .
+ "\n" .
+ "# configure a special command-line prompt\n" .
+ "if [ \".\$TERM\" = .screen ]; then\n" .
+ " PS1=\"\\\\u@\\\\h:\\\\w [P=\\\\e[1m\\\${OPENPKG_PREFIX}\\\\e[0m]\\n\\\\\\\$ \\\\ek\\\\W\\\\e\\\\\\\\\"\n" .
+ "else\n" .
+ " PS1=\"\\\\u@\\\\h:\\\\w [P=\\\\e[1m\\\${OPENPKG_PREFIX}\\\\e[0m]\\n\\\\\\\$ \"\n" .
+ "fi\n" .
+ "alias openpkg=\"\\\${OPENPKG_PREFIX}/bin/openpkg\"\n" .
+ "alias opd=\"\\\${OPENPKG_PREFIX}/bin/openpkg dev\"\n" .
+ "\n";
+ my $inputrc_data =
+ "##\n" .
+ "## dot.inputrc -- \"openpkg dev shell\" GNU readline configuration\n" .
+ "##\n" .
+ "\n";
+ foreach my $c (keys %{$map}) {
+ my $k = $map->{$c}->{-key};
+ $c =~ s/\n/\\n/sg;
+ $inputrc_data .= "\"\\e$k\": \"opd $c\"\n";
+ }
+ $inputrc_data .= "\n";
+ open(SCREENRC, ">$screenrc");
+ print(SCREENRC $screenrc_data);
+ close(SCREENRC);
+ open(BASHSH, ">$bashsh");
+ print(BASHSH $bashsh_data);
+ close(BASHSH);
+ system("chmod a+x $bashsh");
+ open(BASHRC, ">$bashrc");
+ print(BASHRC $bashrc_data);
+ close(BASHRC);
+ open(INPUTRC, ">$inputrc");
+ print(INPUTRC $inputrc_data);
+ close(INPUTRC);
+
+ # run interactive shell
+ print STDOUT "\033[34m++ entering OpenPKG $release development shell\033[0m\n";
+ my $rc;
+ if ($lopts->{"s"}) {
+ $rc = system("screen -c $screenrc -S 'openpkg-dev-shell' -d -R");
+ }
+ else {
+ $rc = system("$bashsh");
+ }
+
+ # cleanup
+ unlink("$tmpdir/dot.screenrc");
+ unlink("$tmpdir/bash.sh");
+ unlink("$tmpdir/dot.bashrc");
+ unlink("$tmpdir/dot.inputrc");
+ unlink("$tmpdir");
+
+ return $rc;
+}
+
+# command: unpack source RPM
+sub cmd_unpack ($@) {
+ my ($gopts, @argv) = @_;
+ my $rc = 0;
+
+ # command line argument processing
+ my $lopts = {};
+ @argv = getopts("l:b:sd", $lopts, @argv);
+ if ($lopts->{"l"} eq "") {
+ $lopts->{"l"} = "structured";
+ }
+ if ($lopts->{"l"} !~ m/^(global|local|simple|structured|distributed)$/) {
+ die sprintf("invalid layout type \"%s\"", $lopts->{"l"});
+ }
+ if (@argv != 1) {
+ die sprintf("exactly one SRPM has to be given");
+ }
+ my $srpm = $argv[0];
+ if (not -f $srpm) {
+ die sprintf("SRPM \"%s\" has to be a regular file", $srpm);
+ }
+ my $name = `$openpkg_prefix/bin/openpkg rpm -qp --qf '\%{NAME}' $srpm 2>/dev/null || true`;
+ $name =~ s/\r?\n$//s;
+ if ($name eq '') {
+ die sprintf("unable to determine package name from SRPM \"%s\"", $srpm);
+ }
+ if ($lopts->{"b"} eq "") {
+ $lopts->{"b"} = $srpm;
+ if ($lopts->{"b"} =~ m/\.src\.rpm$/) {
+ $lopts->{"b"} =~ s/\.src\.rpm$//;
+ }
+ else {
+ my $subdir = `$openpkg_prefix/bin/openpkg rpm -qp --qf '\%{NAME}-\%{VERSION}-\%{RELEASE}' $srpm 2>/dev/null || true`;
+ $lopts->{"b"} = $subdir;
+ }
+ }
+
+ # determine result directory
+ my $basedir = $lopts->{"b"};
+ my ($macrosfile, $specdir, $sourcedir);
+ if ($lopts->{"l"} eq "global") {
+ $macrosdir = "$openpkg_prefix/etc/openpkg";
+ $macrosfile = "$openpkg_prefix/etc/openpkg/rpmmacros";
+ $specdir = "$openpkg_prefix/RPM/SRC/$name";
+ $sourcedir = "$openpkg_prefix/RPM/SRC/$name";
+ $builddir = "$openpkg_prefix/RPM/TMP";
+ $tmpdir = "$openpkg_prefix/RPM/TMP";
+ $binrpmdir = "$openpkg_prefix/RPM/PKG";
+ $srcrpmdir = "$openpkg_prefix/RPM/PKG";
+ }
+ elsif ($lopts->{"l"} eq "local") {
+ $macrosdir = "$basedir/.openpkg";
+ $macrosfile = "$basedir/.openpkg/rpmmacros";
+ $specdir = "$basedir";
+ $sourcedir = "$basedir";
+ $builddir = "$basedir";
+ $tmpdir = "$basedir";
+ $binrpmdir = "$basedir";
+ $srcrpmdir = "$basedir";
+ }
+ elsif ($lopts->{"l"} eq "simple") {
+ $macrosdir = "$basedir/.openpkg";
+ $macrosfile = "$basedir/.openpkg/rpmmacros";
+ $specdir = "$basedir";
+ $sourcedir = "$basedir";
+ $builddir = "$tmpdir";
+ $tmpdir = "$tmpdir";
+ $binrpmdir = "$basedir/..";
+ $srcrpmdir = "$basedir/..";
+ }
+ elsif ($lopts->{"l"} eq "structured") {
+ $macrosdir = "$basedir/.openpkg";
+ $macrosfile = "$basedir/.openpkg/rpmmacros";
+ $specdir = "$basedir/src";
+ $sourcedir = "$basedir/dst";
+ $builddir = "$basedir/tmp";
+ $tmpdir = "$basedir/tmp";
+ $binrpmdir = "$basedir/pkg/bin";
+ $srcrpmdir = "$basedir/pkg/src";
+ }
+ elsif ($lopts->{"l"} eq "distributed") {
+ $macrosdir = "$basedir/.openpkg";
+ $macrosfile = "$basedir/.openpkg/rpmmacros";
+ $specdir = "$basedir/src/$name";
+ $sourcedir = "$basedir/dst/$name";
+ $builddir = "$basedir/tmp";
+ $tmpdir = "$basedir/tmp";
+ $binrpmdir = "$basedir/pkg/bin";
+ $srcrpmdir = "$basedir/pkg/src";
+ }
+
+ # create still missing directories
+ foreach my $dir ($macrosdir, $specdir, $sourcedir, $builddir, $tmpdir, $binrpmdir, $srcrpmdir) {
+ if (not -d $dir) {
+ print STDOUT "openpkg:$prog_name: creating directory \"$dir\"\n";
+ system("$openpkg_prefix/lib/openpkg/shtool mkdir -f -p -m 755 $dir");
+ }
+ }
+
+ # unpack SRPM
+ print STDOUT "openpkg:$prog_name: unpacking source: \"$srpm\"\n";
+ print STDOUT "openpkg:$prog_name: unpacking target: \"$specdir\"\n";
+ print STDOUT "openpkg:$prog_name: unpacking target: \"$sourcedir\"\n";
+ my $abs_specdir = $specdir;
+ my $abs_sourcedir = $sourcedir;
+ my $pwd = `pwd`; $pwd =~ s/\r?\n$//s;
+ $abs_specdir = "$pwd/$abs_specdir" if ($abs_specdir !~ m/^\//);
+ $abs_sourcedir = "$pwd/$abs_sourcedir" if ($abs_sourcedir !~ m/^\//);
+ my $rc = system(
+ "$openpkg_prefix/bin/openpkg" .
+ " --keep-privileges" .
+ " rpm" .
+ " -i" .
+ " --define '_specdir $abs_specdir'" .
+ " --define '_sourcedir $abs_sourcedir'" .
+ " $srpm"
+ );
+
+ # fix location of files
+ if (not -f "$specdir/$name.spec") {
+ die sprintf("failed to install package \"%s\": file \"%s\" not found\n", $srpm, "$specdir/$name.spec");
+ }
+ open(SPEC, "<$specdir/$name.spec");
+ my $spec = ""; { local $/; $spec = ; }
+ close(SPEC);
+ my $src = {};
+ $spec =~ s/^(?:Source|Patch)\d+:\s+(\S+)/$src->{$1} = 1, ''/mgei;
+ foreach my $file (keys %{$src}) {
+ if ($file !~ m/^(https?|ftp):\/\//) {
+ if (not -f "$specdir/$file" and -f "$sourcedir/$file") {
+ system("mv $sourcedir/$file $specdir/$file");
+ }
+ }
+ }
+
+ # create .openpkg/rpmmacros file
+ if (not -f $macrosfile) {
+ print STDOUT "openpkg:$prog_name: creating file: \"$macrosfile\"\n";
+ my $rpmmacros =
+ "##\n" .
+ "## .openpkg/rpmmacros -- local OpenPKG RPM macro definitions\n" .
+ "##\n" .
+ "\n" .
+ "\%openpkg_layout" .
+ " macrosfile=\%{macrosfile}" .
+ " layout=" . $lopts->{"l"} .
+ " shared=" . ($lopts->{"s"} ? "yes" : "no") .
+ " debug=" . ($lopts->{"d"} ? "yes" : "no") .
+ "\n" .
+ "\n";
+ open(MACROS, ">$macrosfile");
+ print(MACROS $rpmmacros);
+ close(MACROS);
+ }
+
+ return $rc;
+}
+
+# command: edit package specification
+sub cmd_edit ($@) {
+ my ($gopts, @argv) = @_;
+ my $rc = 0;
+
+ # run editor
+ my $editor = ($ENV{"EDITOR"} || "vi");
+ my $specfile = ($argv[0] || specfile());
+ run("$editor $specfile");
+
+ return $rc;
+}
+
+# command: build package
+sub cmd_build ($@) {
+ my ($gopts, @argv) = @_;
+ my $rc = 0;
+
+ # command line argument processing
+ my $lopts = {};
+ @argv = getopts("s:D:w:", $lopts, @argv);
+ if ($lopts->{"s"} eq '') {
+ $lopts->{"s"} = "all";
+ }
+ if ($lopts->{"s"} !~ m/^(track|fetch|prep|compile|install|binary|source|all)$/) {
+ die "invalid step";
+ }
+
+ # assembly defines
+ my $defs = "";
+ if ($lopts->{"D"}) {
+ foreach my $def (split(/\s+/, $lopts->{"D"})) {
+ if ($def =~ m/^([^=]+)=(.+)$/) {
+ $defs .= "--define '$1 $2' ";
+ }
+ else {
+ $defs .= "--define '$def yes' ";
+ }
+ }
+ }
+ if ($lopts->{"w"}) {
+ foreach my $def (split(/\s+/, $lopts->{"w"})) {
+ $defs .= "--with $def ";
+ }
+ }
+
+ # run build command
+ my $specfile = ($argv[0] || specfile());
+ if ($lopts->{"s"} eq 'track') {
+ run("$openpkg_prefix/bin/openpkg rpm -bt $defs$specfile");
+ }
+ elsif ($lopts->{"s"} eq 'fetch') {
+ run("$openpkg_prefix/bin/openpkg rpm -bf $defs$specfile");
+ }
+ elsif ($lopts->{"s"} eq 'prep') {
+ run("$openpkg_prefix/bin/openpkg rpm -bp $defs$specfile");
+ }
+ elsif ($lopts->{"s"} eq 'compile') {
+ run("$openpkg_prefix/bin/openpkg rpm -bc --short-circuit $defs$specfile");
+ }
+ elsif ($lopts->{"s"} eq 'install') {
+ run("$openpkg_prefix/bin/openpkg rpm -bi --short-circuit $defs$specfile");
+ }
+ elsif ($lopts->{"s"} eq 'binary') {
+ run("$openpkg_prefix/bin/openpkg rpm -bb --short-circuit $defs$specfile");
+ }
+ elsif ($lopts->{"s"} eq 'source') {
+ run("$openpkg_prefix/bin/openpkg rpm -bs $defs$specfile");
+ }
+ elsif ($lopts->{"s"} eq 'all') {
+ run("$openpkg_prefix/bin/openpkg rpm -ba $defs$specfile");
+ }
+
+ return $rc;
+}
+
+# command: peek into package
+sub cmd_peek ($@) {
+ my ($gopts, @argv) = @_;
+ my $rc = 0;
+
+ # run query command
+ my $template = `$openpkg_prefix/bin/openpkg rpm --eval '%{_rpmdir}/%{_rpmfilename}'`;
+ $template =~ s/\n$//s;
+ my $specfile = specfile();
+ my $rpm = `$openpkg_prefix/bin/openpkg rpm -q --specfile '$specfile' --qf 'XXX$template'`;
+ $rpm =~ s/^XXX//s;
+ $rpm =~ s/\n$//s;
+
+ # determine files
+ print STDOUT "\033[34m++ determining configuration files\033[0m\n";
+ my @cfgfiles = split(/\n/, `$openpkg_prefix/bin/openpkg rpm -qplc $rpm`);
+ print STDOUT "\033[34m++ determining documentation files\033[0m\n";
+ my @docfiles = split(/\n/, `$openpkg_prefix/bin/openpkg rpm -qpld $rpm`);
+ print STDOUT "\033[34m++ determining all file information\033[0m\n";
+ my @allfiles = split(/\n/, `$openpkg_prefix/bin/openpkg rpm -qplv $rpm`);
+
+ # create package file listing
+ foreach my $line (@allfiles) {
+ $prefix = "";
+ foreach my $docfile (@docfiles) {
+ if ($line =~ m/\s+$docfile\b/s) {
+ $prefix .= "D";
+ last;
+ }
+ }
+ foreach my $cfgfile (@cfgfiles) {
+ if ($line =~ m/\s+$cfgfile\b/s) {
+ $prefix .= "C";
+ last;
+ }
+ }
+ $prefix .= "--";
+ $prefix = substr($prefix, 0, 2);
+ if ($line =~ m/^d/) {
+ $line =~ s/(\s+\/\S+)/\033[34m$1\033[0m/s;
+ }
+ print "$prefix $line\n";
+ }
+
+ return $rc;
+}
+
+# command: show modifications via VCS
+sub cmd_diff ($@) {
+ my ($gopts, @argv) = @_;
+ my $rc = 0;
+
+ my $vcs = "";
+ my $cmd = "";
+ if (-d "CVS") {
+ $vcs = "CVS";
+ $cmd = "cvs diff -u3";
+ }
+ elsif (-d ".svn") {
+ $vcs = "Subversion";
+ $cmd = "svn diff";
+ }
+ elsif (-d "_MTN" or -d ".mtn" or
+ -d "../_MTN" or -d "../.mtn" or
+ -d "../../_MTN" or -d "../../.mtn" or
+ -d "../../../_MTN" or -d "../../../.mtn") {
+ $vcs = "Monotone";
+ $cmd = "mtn diff .";
+ }
+ elsif (-d ".git" or
+ -d "../.git" or
+ -d "../../.git" or
+ -d "../../../.git") {
+ $vcs = "Git";
+ $cmd = "git diff . ";
+ }
+ elsif (-d ".hg" or
+ -d "../.hg" or
+ -d "../../.hg" or
+ -d "../../../.hg") {
+ $vcs = "Mercurial";
+ $cmd = "hg diff ."
+ }
+ else {
+ $vcs = "OSSP svs";
+ $cmd = "svs diff";
+ }
+ print STDOUT "\033[34m++ modifications as known to underlying $vcs VCS\033[0m\n";
+ run($cmd);
+}
+
+# command: install package
+sub cmd_install ($@) {
+ my ($gopts, @argv) = @_;
+ my $rc = 0;
+
+ # command line argument processing
+ my $lopts = {};
+ @argv = getopts("fnos", $lopts, @argv);
+
+ # run install command
+ my $template = `$openpkg_prefix/bin/openpkg rpm --eval '%{_rpmdir}/%{_rpmfilename}'`;
+ $template =~ s/\n$//s;
+ my $specfile = specfile();
+ my $rpm = `$openpkg_prefix/bin/openpkg rpm -q --specfile '$specfile' --qf 'XXX$template'`;
+ $rpm =~ s/^XXX//s;
+ $rpm =~ s/\n$//s;
+ chdir("/");
+ run(($lopts->{"s"} ? "sudo " : "") .
+ "$openpkg_prefix/bin/openpkg rpm -Uvh"
+ . ($lopts->{"f"} ? " --force" : "")
+ . ($lopts->{"n"} ? " --nodeps" : "")
+ . ($lopts->{"o"} ? " --oldpackage" : "")
+ . " $rpm");
+
+ return $rc;
+}
+
+# command: erase package
+sub cmd_erase ($@) {
+ my ($gopts, @argv) = @_;
+ my $rc = 0;
+
+ # command line argument processing
+ my $lopts = {};
+ @argv = getopts("fnas", $lopts, @argv);
+
+ # run erase command
+ my $specfile = specfile();
+ my $name = `$openpkg_prefix/bin/openpkg rpm -q --specfile $specfile --qf '%{NAME}'`;
+ $name =~ s/\n$//s;
+ chdir("/");
+ run(($lopts->{"s"} ? "sudo " : "") .
+ "$openpkg_prefix/bin/openpkg rpm -e"
+ . ($lopts->{"f"} ? " --force" : "")
+ . ($lopts->{"n"} ? " --nodeps" : "")
+ . ($lopts->{"a"} ? " --allmatches" : "")
+ . " $name");
+
+ return $rc;
+}
+
+# command: lint package
+sub cmd_lint ($@) {
+ my ($gopts, @argv) = @_;
+ my $rc = 0;
+
+ # command line argument processing
+ my $lopts = {};
+ @argv = getopts("vb", $lopts, @argv);
+
+ # run source linting commands
+ my $specfile = specfile();
+ my $fslfile = $specfile;
+ $fslfile =~ s/([^\/]+)\.spec$/fsl.$1/s;
+ my $rcfile = $specfile;
+ $rcfile =~ s/([^\/]+)\.spec$/rc.$1/s;
+ my $name = `$openpkg_prefix/bin/openpkg rpm -q --specfile $specfile --qf '%{NAME}'`;
+ $name =~ s/\n$//s;
+ my $template = `$openpkg_prefix/bin/openpkg rpm --eval '%{_rpmdir}/%{_rpmfilename}'`;
+ $template =~ s/\n$//s;
+ my $rpm = `$openpkg_prefix/bin/openpkg rpm -q --specfile '$specfile' --qf 'XXX$template'`;
+ $rpm =~ s/^XXX//s;
+ $rpm =~ s/\n$//s;
+ my $rc = 0;
+ $rc += run("$openpkg_prefix/bin/openpkg lint-spec" . ($lopts->{"v"} ? " --verbose" : "") . " $specfile");
+ $rc += run("$openpkg_prefix/bin/openpkg lint-fsl" . ($lopts->{"v"} ? " --verbose" : "") . " $fslfile") if (-f $fslfile);
+ $rc += run("$openpkg_prefix/bin/openpkg lint-rc" . ($lopts->{"v"} ? " --verbose" : "") . " $rcfile") if (-f $rcfile);
+
+ # optionally run binary linting command
+ run("$openpkg_prefix/bin/openpkg lint-rpm" . ($lopts->{"v"} ? " --verbose" : "") . " $rpm") if (-f $rpm and not $lopts->{"b"});
+
+ return $rc;
+}
+
+# command: release package
+sub cmd_release ($@) {
+ my ($gopts, @argv) = @_;
+ my $rc = 0;
+
+ # command line argument processing
+ my $lopts = {};
+ @argv = getopts("nm:f", $lopts, @argv);
+
+ # implicit linting
+ if (not $lopts->{"f"}) {
+ my $rc = cmd_lint($gopts);
+ if ($rc != 0 and !$lopts->{"f"}) {
+ return $rc;
+ }
+ }
+
+ # sanity check environment
+ my $cmd = $ENV{"OPENPKG_DEV_RELEASE"}
+ || `$openpkg_prefix/bin/openpkg rpm --eval '%{openpkg_dev_release}' 2>/dev/null || true` || "";
+ $cmd =~ s/\n$//s;
+ if ($cmd eq "") {
+ print STDERR "openpkg:$prog_name:ERROR: no \$OPENPKG_DEV_RELEASE command defined\n";
+ exit(1);
+ }
+
+ #
+ # determine package information
+ #
+
+ print STDOUT "\033[34m++ determining package information\033[0m\n";
+ my $info = {};
+ $info->{"openpkg-prefix"} = $openpkg_prefix;
+ $info->{"option-force"} = $lopts->{"f"} ? "yes" : "no";
+
+ print STDOUT "-- determining package name/version/release\n";
+ my $specfile = specfile();
+ my $result = `$openpkg_prefix/bin/openpkg rpm -q --specfile $specfile --qf '::%{NAME}::%{VERSION}::%{RELEASE}'`;
+ $result =~ s/\n$//s;
+ $result =~ s/^:://s;
+ my @result = split(/::/, $result);
+ $info->{"package-name"} = $result[0];
+ $info->{"package-version"} = $result[1];
+ $info->{"package-release"} = $result[2];
+
+ print STDOUT "-- determining package source and distribution location\n";
+ my $defines = "--define '\%name " . $info->{"package-name"} . "'";
+ $defines .= " --define '\%version " . $info->{"package-version"} . "'";
+ $defines .= " --define '\%release " . $info->{"package-release"} . "'";
+ my $result = `$openpkg_prefix/bin/openpkg rpm $defines --eval '%{_specdir}::%{_sourcedir}'`;
+ $result =~ s/\n$//s;
+ @result = split(/::/, $result);
+ $info->{"spec-dir"} = $result[0];
+ $info->{"source-dir"} = $result[1];
+
+ print STDOUT "-- determining package source and binary RPM files\n";
+ my $template = `$openpkg_prefix/bin/openpkg rpm --eval '%{_rpmdir}/%{l_binrpmfilename}::%{_srcrpmdir}/%{l_srcrpmfilename}'`;
+ $template =~ s/\n$//s;
+ $result = `$openpkg_prefix/bin/openpkg rpm -q --specfile $specfile --qf '::$template'`;
+ $result =~ s/\n$//s;
+ $result =~ s/^:://s;
+ @result = split(/::/, $result);
+ $info->{"binary-rpm-file"} = $result[0];
+ $info->{"source-rpm-file"} = $result[1];
+ $info->{"package-version-old"} = "";
+ $info->{"package-release-old"} = "";
+ $info->{"vcs"} = "none";
+
+ print STDOUT "-- determining previous package version/release\n";
+ my $vcs = "";
+ my $diff = "";
+ my $content_old = "";
+ my $specdir = $info->{"spec-dir"};
+ my $specfile = $info->{"package-name"} . ".spec";
+ if (-f "$specdir/$specfile") {
+ open(FP, "<$specdir/$specfile");
+ $content_new .= $_ while ();
+ close(FP);
+ if ($content_new =~ m/\n\%No(?:Source|Patch)\s+/s) {
+ $info->{"source-rpm-file"} =~ s/\.src\.rpm$/.nosrc.rpm/s;
+ }
+ if (-d "$specdir/CVS") {
+ # package is version controlled via CVS
+ $vcs = "cvs";
+ $diff = `(cd $specdir && cvs diff -u3 $specfile) 2>/dev/null || true`;
+ }
+ elsif (-d "$specdir/.svn") {
+ # package is version controlled via Subverson (SVN)
+ $vcs = "svn";
+ $diff = `(cd $specdir && svn diff $specfile) 2>/dev/null || true`;
+ }
+ elsif (-d "$specdir/_MTN" or -d "$specdir/.mtn" or
+ -d "$specdir/../_MTN" or -d "$specdir/../.mtn" or
+ -d "$specdir/../../_MTN" or -d "$specdir/../../.mtn" or
+ -d "$specdir/../../../_MTN" or -d "$specdir/../../../.mtn") {
+ # package is version controlled via Monotone (MTN)
+ $vcs = "mtn";
+ $diff = `(cd $specdir && mtn diff $specfile) 2>/dev/null || true`;
+ $content_old = `(cd $specdir && mtn automate get_file_of -r h: $specfile) 2>/dev/null || true`;
+ }
+ elsif (-d "$specdir/.git" or
+ -d "$specdir/../.git" or
+ -d "$specdir/../../.git" or
+ -d "$specdir/../../../.git") {
+ # package is version controlled via Git
+ $vcs = "git";
+ $diff = `(cd $specdir && git diff $specfile) 2>/dev/null || true`;
+ }
+ elsif (-d "$specdir/.hg" or
+ -d "$specdir/../.hg" or
+ -d "$specdir/../../.hg" or
+ -d "$specdir/../../../.hg") {
+ # package is version controlled via Mercurial (Hg)
+ $vcs = "hg";
+ $diff = `(cd $specdir && hg diff $specfile) 2>/dev/null || true`;
+ }
+ elsif (-f "$specdir/$specfile.orig") {
+ # package is patched via OSSP svs
+ $vcs = "svs";
+ $diff = `(cd $specdir && svs diff $specfile) 2>/dev/null || true`;
+ }
+ if ($vcs ne '') {
+ $info->{"vcs"} = $vcs;
+ }
+ if ($content_old ne '') {
+ my $define = {};
+ $content_old =~ s/\n\%define[ \t]+([^ \t\n]+)[ \t]+([^ \t\n]+)/$define->{$1} = $2, ''/sge;
+ $content_old =~ s/\n([^ \t\n]+):[ \t]+([^ \t\n]+)/$define->{lc($1)} = $2, ''/sge;
+ sub resolve {
+ my ($define, $name) = @_;
+ my $value = $define->{$name};
+ $value = "" if (not defined $value);
+ $value =~ s/\%\{(.+?)\}/resolve($define, $1)/sge;
+ return $value;
+ }
+ $info->{"package-version-old"} = resolve($define, "version");
+ $info->{"package-release-old"} = resolve($define, "release");
+ }
+ if (( $info->{"package-version-old"} eq ''
+ or $info->{"package-release-old"} eq '')
+ and $diff ne '' ) {
+ if ($info->{"package-version-old"} eq '' and $diff =~ m/\n-Version:\s+(\S+)/s) {
+ $info->{"package-version-old"} = $1;
+ }
+ if ($info->{"package-release-old"} eq '' and $diff =~ m/\n-Release:\s+(\S+)/s) {
+ $info->{"package-release-old"} = $1;
+ }
+ }
+ }
+
+ print STDOUT "-- determining commit message\n";
+ $info->{"commit-message"} = ($lopts->{"m"} || "");
+ if ($info->{"commit-message"} eq "") {
+ if ($info->{"package-version-old"} ne $info->{"package-version"}) {
+ # new version
+ $info->{"commit-message"} = "upgrading package: " .
+ $info->{"package-name"} . " " .
+ $info->{"package-version-old"} . " -> " .
+ $info->{"package-version"};
+ }
+ elsif (!$lopts->{"f"}) {
+ print STDERR "openpkg:$prog_name:ERROR: package version not changed -- you have to manually provide a commit message\n";
+ exit(1);
+ }
+ }
+
+ # run external command
+ print STDOUT "\033[34m++ executing openpkg development release program\033[0m\n";
+ $cmd .= " %{openpkg-prefix}";
+ $cmd .= " %{spec-dir} %{source-dir} %{binary-rpm-file} %{source-rpm-file}";
+ $cmd .= " %{package-name} %{package-version} %{package-release} %{package-version-old} %{package-release-old}";
+ $cmd .= " %{commit-message} %{vcs}";
+ $cmd .= " %{option-force}";
+ $cmd =~ s/(\%\{([a-z][a-z-]+)\})/&subst($info, $1, $2)/sge;
+ sub subst {
+ my ($info, $text, $name) = @_;
+ if (exists($info->{$name})) {
+ $text = $info->{$name};
+ $text =~ s/'/\\'/sg;
+ $text = "'$text'";
+ }
+ }
+ if ($lopts->{"n"}) {
+ print STDOUT "-- DRY RUN:\n";
+ print STDOUT "-- $cmd\n";
+ $rc = 0;
+ }
+ else {
+ $rc = system($cmd);
+ }
+
+ return $rc;
+}
+