michael@428: ##
michael@428: ## openpkg dev -- OpenPKG Package Development Tool
michael@428: ## Copyright (c) 2008-2012 OpenPKG GmbH
michael@428: ##
michael@428: ## This software is property of the OpenPKG GmbH, DE MUC HRB 160208.
michael@428: ## All rights reserved. Licenses which grant limited permission to use,
michael@428: ## copy, modify and distribute this software are available from the
michael@428: ## OpenPKG GmbH.
michael@428: ##
michael@428: ## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
michael@428: ## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
michael@428: ## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
michael@428: ## IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
michael@428: ## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@428: ## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@428: ## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
michael@428: ## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
michael@428: ## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
michael@428: ## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
michael@428: ## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
michael@428: ## SUCH DAMAGE.
michael@428: ##
michael@428:
michael@428: require 5;
michael@428:
michael@428: # OpenPKG instance prefix and RPM
michael@428: my $openpkg_prefix = $ENV{'OPENPKG_PREFIX'};
michael@428: delete $ENV{'OPENPKG_PREFIX'};
michael@428:
michael@428: # program identification
michael@428: my $prog_name = "dev";
michael@428: my $prog_vers = "20100111";
michael@428:
michael@428: # home-brewn getopt(3) style option parser
michael@428: sub getopts ($$@) {
michael@428: my ($opt_spec, $opts, @argv_orig) = @_;
michael@428: my (%optf) = map { m/(\w)/; $1 => $_ } $opt_spec =~ m/(\w:|\w)/g;
michael@428: my (@argv, $optarg);
michael@428:
michael@428: foreach (@argv_orig) {
michael@428: if (@argv) {
michael@428: push @argv, $_;
michael@428: } elsif (defined $optarg) {
michael@428: if (exists $opts->{$optarg}) {
michael@428: $opts->{$optarg} .= " $_";
michael@428: } else {
michael@428: $opts->{$optarg} = $_;
michael@428: }
michael@428: $optarg = undef;
michael@428: } elsif (!/^[-]/) {
michael@428: push @argv, $_;
michael@428: } else {
michael@428: while (/^\-(\w)(.*)/) {
michael@428: if (exists $optf{$1}) {
michael@428: if (length($optf{$1}) > 1) {
michael@428: if ($2 ne '') {
michael@428: if (exists $opts->{$1}) {
michael@428: $opts->{$1} .= " $2";
michael@428: } else {
michael@428: $opts->{$1} = $2;
michael@428: }
michael@428: } else {
michael@428: $optarg = $1;
michael@428: }
michael@428: last;
michael@428: } else {
michael@428: $opts->{$1} = 1;
michael@428: }
michael@428: } else {
michael@428: warn "openpkg:$prog_name:WARNING: unknown option $_\n";
michael@428: }
michael@428: $_ = "-$2";
michael@428: }
michael@428: }
michael@428: }
michael@428: if (defined $optarg) {
michael@428: warn "openpkg:$prog_name:WARNING: option $optarg requires an argument\n";
michael@428: }
michael@428: foreach my $opt (keys %optf) {
michael@428: if (not exists $opts->{$opt}) {
michael@428: $opts->{$opt} = (length($optf{$opt}) > 1 ? "" : 0);
michael@428: }
michael@428: }
michael@428: return @argv;
michael@428: }
michael@428:
michael@428: # determine reasonable temporary directory
michael@428: my $tmpdir = ($ENV{"TMPDIR"} || "/tmp");
michael@428: $tmpdir .= "/openpkg-$prog_name-$$";
michael@428: my $rc = system("umask 022; $openpkg_prefix/lib/openpkg/shtool mkdir -f -p -m 755 $tmpdir || exit $?");
michael@428: if ($rc != 0) {
michael@428: die "failed to create temporary directory: $tmpdir";
michael@428: }
michael@428:
michael@428: # parse command line options
michael@428: my $opts = {};
michael@428: @ARGV = getopts("h", $opts, @ARGV);
michael@428:
michael@428: # usage sanity check and usage help
michael@428: sub usage {
michael@428: my ($rc) = @_;
michael@428: my $usage =
michael@428: "openpkg:$prog_name:USAGE: openpkg dev []\n";
michael@428: if ($rc == 0) {
michael@428: print STDOUT $usage;
michael@428: }
michael@428: else {
michael@428: print STDERR $usage;
michael@428: }
michael@428: exit($rc);
michael@428: }
michael@428: if ($opts->{"h"}) {
michael@428: usage(0);
michael@428: }
michael@428: if (@ARGV == 0) {
michael@428: usage(1);
michael@428: }
michael@428:
michael@428: # command map
michael@428: my $map = {
michael@428: "unpack " => { -alias => qr/^(up|ex)$/, -key => "x" },
michael@428: "edit\n" => { -alias => qr/^(ed|vi)$/, -key => "v" },
michael@428: "build -s track\n" => { -alias => qr/^(bt|tr)$/, -key => "t" },
michael@428: "build -s fetch\n" => { -alias => qr/^(bf|fe)$/, -key => "f" },
michael@428: "build\n" => { -alias => qr/^(ba|bu)$/, -key => "b" },
michael@428: "build -s prep\n" => { -alias => qr/^bp$/, -key => "1" },
michael@428: "build -s compile\n" => { -alias => qr/^bc$/, -key => "2" },
michael@428: "build -s install\n" => { -alias => qr/^bi$/, -key => "3" },
michael@428: "build -s binary\n" => { -alias => qr/^bb$/, -key => "4" },
michael@428: "build -s source\n" => { -alias => qr/^bs$/, -key => "s" },
michael@428: "peek\n" => { -alias => qr/^pe$/, -key => "p" },
michael@428: "diff\n" => { -alias => qr/^di$/, -key => "d" },
michael@428: "install\n" => { -alias => qr/^in(?:st)?$/, -key => "i" },
michael@428: "erase\n" => { -alias => qr/^er$/, -key => "e" },
michael@428: "lint\n" => { -alias => qr/^li$/, -key => "l" },
michael@428: "release " => { -alias => qr/^rel?$/, -key => "r" },
michael@428: };
michael@428:
michael@428: # dispatch command
michael@428: my $cmd = shift(@ARGV);
michael@428: foreach my $c (keys %{$map}) {
michael@428: my $a = $map->{$c}->{-alias};
michael@428: if ($cmd =~ $a) {
michael@428: $c =~ s/\n$//;
michael@428: my @args = split(/\s+/, $c);
michael@428: $cmd = shift(@args);
michael@428: unshift(@ARGV, @args);
michael@428: print STDOUT "\033[34m\$ opd $cmd " . join(" ", map {
michael@428: my $x = $_;
michael@428: $x =~ s/"/\\"/g;
michael@428: $x =~ s/^(.*[ \t].*)$/"$1"/;
michael@428: $x
michael@428: } @ARGV) . "\033[0m\n";
michael@428: }
michael@428: }
michael@428: my $func = "cmd_$cmd";
michael@428: if (not defined(&$func)) {
michael@428: print STDERR "openpkg:$prog_name:ERROR: invalid command \"$cmd\"\n";
michael@428: usage(1);
michael@428: }
michael@428: my $rc = &$func($opts, @ARGV);
michael@428: exit($rc);
michael@428:
michael@428: # execute a shell command
michael@428: sub run {
michael@428: my ($cmd) = @_;
michael@428: print STDOUT "\033[34m\$ $cmd\033[0m\n";
michael@428: my $rc = system($cmd);
michael@428: return $rc;
michael@428: }
michael@428:
michael@428: # determine path to package specification
michael@428: sub specfile {
michael@428: my $specfile = (glob("*.spec"))[0];
michael@428: if (not defined $specfile) {
michael@428: $specfile = (glob("src/*.spec"))[0];
michael@428: if (not defined $specfile) {
michael@428: $specfile = (glob("*/*.spec"))[0];
michael@428: if (not defined $specfile) {
michael@428: print STDERR "openpkg:$prog_name:ERROR: unable to determine package specification file\n";
michael@428: exit(1);
michael@428: }
michael@428: }
michael@428: }
michael@428: return $specfile;
michael@428: }
michael@428:
michael@428: # command: interactive shell
michael@428: sub cmd_shell ($@) {
michael@428: my ($gopts, @argv) = @_;
michael@428: my $rc = 0;
michael@428:
michael@428: # command line argument processing
michael@428: my $lopts = {};
michael@428: @argv = getopts("s", $lopts, @argv);
michael@428:
michael@428: # determine release
michael@428: my $release = `$openpkg_prefix/bin/openpkg release -F '%t'`;
michael@428: $release =~ s/\n$//s;
michael@428:
michael@428: # create dot files
michael@428: my $screenrc = "$tmpdir/dot.screenrc";
michael@428: my $bashsh = "$tmpdir/bash.sh";
michael@428: my $bashrc = "$tmpdir/dot.bashrc";
michael@428: my $inputrc = "$tmpdir/dot.inputrc";
michael@428: unlink("$screenrc");
michael@428: unlink("$bashsh");
michael@428: unlink("$bashrc");
michael@428: unlink("$inputrc");
michael@428: my $title = "openpkg dev";
michael@428: $title .= '%? %{= rW} %n %{-}%?';
michael@428: $title .= ' %=%-w%{= rW}%50>%n %t%{-}%+w';
michael@428: my $screenrc_data = "";
michael@428: $screenrc_data .= "source \"$ENV{HOME}/.screenrc\"\n" if (-f "$ENV{HOME}/.screenrc");
michael@428: $screenrc_data .=
michael@428: "escape ^Aa\n" .
michael@428: "startup_message off\n" .
michael@428: "vbell off\n" .
michael@428: "defscrollback 10000\n" .
michael@428: "defmonitor off\n" .
michael@428: "msgminwait 1\n" .
michael@428: "msgwait 1\n" .
michael@428: "hardstatus alwayslastline \" $title \"\n" .
michael@428: "shell $bashsh\n";
michael@428: my $bashsh_data =
michael@428: "##\n" .
michael@428: "##\ bash.sh -- \"openpkg dev shell\" GNU bash wrapper script\n" .
michael@428: "##\n" .
michael@428: "\n" .
michael@428: "OPENPKG_PREFIX=\"$openpkg_prefix\"\n" .
michael@428: "export OPENPKG_PREFIX\n" .
michael@428: "INPUTRC=\"$inputrc\"\n" .
michael@428: "export INPUTRC\n" .
michael@428: "SHELL=\"$openpkg_prefix/lib/openpkg/bash\"\n" .
michael@428: "export SHELL\n" .
michael@428: "eval `$openpkg_prefix/bin/openpkg rpm --eval 'T=\"\%{_tmppath}\"; S=\"\%{_specdir}\"; D=\"\%{_sourcedir}\"'`\n" .
michael@428: "export T S D\n" .
michael@428: "\$SHELL --rcfile $bashrc";
michael@428: my $bashrc_data =
michael@428: "##\n" .
michael@428: "## dot.bashrc -- \"openpkg dev shell\" GNU bash configuration\n" .
michael@428: "##\n" .
michael@428: "\n" .
michael@428: "# load user's standard bash run-command script\n" .
michael@428: "if [ -f ~/.bashrc ]; then\n" .
michael@428: " . ~/.bashrc\n" .
michael@428: "fi\n" .
michael@428: "\n" .
michael@428: "# configure a special command-line prompt\n" .
michael@428: "if [ \".\$TERM\" = .screen ]; then\n" .
michael@428: " PS1=\"\\\\u@\\\\h:\\\\w [P=\\\\e[1m\\\${OPENPKG_PREFIX}\\\\e[0m]\\n\\\\\\\$ \\\\ek\\\\W\\\\e\\\\\\\\\"\n" .
michael@428: "else\n" .
michael@428: " PS1=\"\\\\u@\\\\h:\\\\w [P=\\\\e[1m\\\${OPENPKG_PREFIX}\\\\e[0m]\\n\\\\\\\$ \"\n" .
michael@428: "fi\n" .
michael@428: "alias openpkg=\"\\\${OPENPKG_PREFIX}/bin/openpkg\"\n" .
michael@428: "alias opd=\"\\\${OPENPKG_PREFIX}/bin/openpkg dev\"\n" .
michael@428: "\n";
michael@428: my $inputrc_data =
michael@428: "##\n" .
michael@428: "## dot.inputrc -- \"openpkg dev shell\" GNU readline configuration\n" .
michael@428: "##\n" .
michael@428: "\n";
michael@428: foreach my $c (keys %{$map}) {
michael@428: my $k = $map->{$c}->{-key};
michael@428: $c =~ s/\n/\\n/sg;
michael@428: $inputrc_data .= "\"\\e$k\": \"opd $c\"\n";
michael@428: }
michael@428: $inputrc_data .= "\n";
michael@428: open(SCREENRC, ">$screenrc");
michael@428: print(SCREENRC $screenrc_data);
michael@428: close(SCREENRC);
michael@428: open(BASHSH, ">$bashsh");
michael@428: print(BASHSH $bashsh_data);
michael@428: close(BASHSH);
michael@428: system("chmod a+x $bashsh");
michael@428: open(BASHRC, ">$bashrc");
michael@428: print(BASHRC $bashrc_data);
michael@428: close(BASHRC);
michael@428: open(INPUTRC, ">$inputrc");
michael@428: print(INPUTRC $inputrc_data);
michael@428: close(INPUTRC);
michael@428:
michael@428: # run interactive shell
michael@428: print STDOUT "\033[34m++ entering OpenPKG $release development shell\033[0m\n";
michael@428: my $rc;
michael@428: if ($lopts->{"s"}) {
michael@428: $rc = system("screen -c $screenrc -S 'openpkg-dev-shell' -d -R");
michael@428: }
michael@428: else {
michael@428: $rc = system("$bashsh");
michael@428: }
michael@428:
michael@428: # cleanup
michael@428: unlink("$tmpdir/dot.screenrc");
michael@428: unlink("$tmpdir/bash.sh");
michael@428: unlink("$tmpdir/dot.bashrc");
michael@428: unlink("$tmpdir/dot.inputrc");
michael@428: unlink("$tmpdir");
michael@428:
michael@428: return $rc;
michael@428: }
michael@428:
michael@428: # command: unpack source RPM
michael@428: sub cmd_unpack ($@) {
michael@428: my ($gopts, @argv) = @_;
michael@428: my $rc = 0;
michael@428:
michael@428: # command line argument processing
michael@428: my $lopts = {};
michael@428: @argv = getopts("l:b:sd", $lopts, @argv);
michael@428: if ($lopts->{"l"} eq "") {
michael@428: $lopts->{"l"} = "structured";
michael@428: }
michael@428: if ($lopts->{"l"} !~ m/^(global|local|simple|structured|distributed)$/) {
michael@428: die sprintf("invalid layout type \"%s\"", $lopts->{"l"});
michael@428: }
michael@428: if (@argv != 1) {
michael@428: die sprintf("exactly one SRPM has to be given");
michael@428: }
michael@428: my $srpm = $argv[0];
michael@428: if (not -f $srpm) {
michael@428: die sprintf("SRPM \"%s\" has to be a regular file", $srpm);
michael@428: }
michael@428: my $name = `$openpkg_prefix/bin/openpkg rpm -qp --qf '\%{NAME}' $srpm 2>/dev/null || true`;
michael@428: $name =~ s/\r?\n$//s;
michael@428: if ($name eq '') {
michael@428: die sprintf("unable to determine package name from SRPM \"%s\"", $srpm);
michael@428: }
michael@428: if ($lopts->{"b"} eq "") {
michael@428: $lopts->{"b"} = $srpm;
michael@428: if ($lopts->{"b"} =~ m/\.src\.rpm$/) {
michael@428: $lopts->{"b"} =~ s/\.src\.rpm$//;
michael@428: }
michael@428: else {
michael@428: my $subdir = `$openpkg_prefix/bin/openpkg rpm -qp --qf '\%{NAME}-\%{VERSION}-\%{RELEASE}' $srpm 2>/dev/null || true`;
michael@428: $lopts->{"b"} = $subdir;
michael@428: }
michael@428: }
michael@428:
michael@428: # determine result directory
michael@428: my $basedir = $lopts->{"b"};
michael@428: my ($macrosfile, $specdir, $sourcedir);
michael@428: if ($lopts->{"l"} eq "global") {
michael@428: $macrosdir = "$openpkg_prefix/etc/openpkg";
michael@428: $macrosfile = "$openpkg_prefix/etc/openpkg/rpmmacros";
michael@428: $specdir = "$openpkg_prefix/RPM/SRC/$name";
michael@428: $sourcedir = "$openpkg_prefix/RPM/SRC/$name";
michael@428: $builddir = "$openpkg_prefix/RPM/TMP";
michael@428: $tmpdir = "$openpkg_prefix/RPM/TMP";
michael@428: $binrpmdir = "$openpkg_prefix/RPM/PKG";
michael@428: $srcrpmdir = "$openpkg_prefix/RPM/PKG";
michael@428: }
michael@428: elsif ($lopts->{"l"} eq "local") {
michael@428: $macrosdir = "$basedir/.openpkg";
michael@428: $macrosfile = "$basedir/.openpkg/rpmmacros";
michael@428: $specdir = "$basedir";
michael@428: $sourcedir = "$basedir";
michael@428: $builddir = "$basedir";
michael@428: $tmpdir = "$basedir";
michael@428: $binrpmdir = "$basedir";
michael@428: $srcrpmdir = "$basedir";
michael@428: }
michael@428: elsif ($lopts->{"l"} eq "simple") {
michael@428: $macrosdir = "$basedir/.openpkg";
michael@428: $macrosfile = "$basedir/.openpkg/rpmmacros";
michael@428: $specdir = "$basedir";
michael@428: $sourcedir = "$basedir";
michael@428: $builddir = "$tmpdir";
michael@428: $tmpdir = "$tmpdir";
michael@428: $binrpmdir = "$basedir/..";
michael@428: $srcrpmdir = "$basedir/..";
michael@428: }
michael@428: elsif ($lopts->{"l"} eq "structured") {
michael@428: $macrosdir = "$basedir/.openpkg";
michael@428: $macrosfile = "$basedir/.openpkg/rpmmacros";
michael@428: $specdir = "$basedir/src";
michael@428: $sourcedir = "$basedir/dst";
michael@428: $builddir = "$basedir/tmp";
michael@428: $tmpdir = "$basedir/tmp";
michael@428: $binrpmdir = "$basedir/pkg/bin";
michael@428: $srcrpmdir = "$basedir/pkg/src";
michael@428: }
michael@428: elsif ($lopts->{"l"} eq "distributed") {
michael@428: $macrosdir = "$basedir/.openpkg";
michael@428: $macrosfile = "$basedir/.openpkg/rpmmacros";
michael@428: $specdir = "$basedir/src/$name";
michael@428: $sourcedir = "$basedir/dst/$name";
michael@428: $builddir = "$basedir/tmp";
michael@428: $tmpdir = "$basedir/tmp";
michael@428: $binrpmdir = "$basedir/pkg/bin";
michael@428: $srcrpmdir = "$basedir/pkg/src";
michael@428: }
michael@428:
michael@428: # create still missing directories
michael@428: foreach my $dir ($macrosdir, $specdir, $sourcedir, $builddir, $tmpdir, $binrpmdir, $srcrpmdir) {
michael@428: if (not -d $dir) {
michael@428: print STDOUT "openpkg:$prog_name: creating directory \"$dir\"\n";
michael@428: system("$openpkg_prefix/lib/openpkg/shtool mkdir -f -p -m 755 $dir");
michael@428: }
michael@428: }
michael@428:
michael@428: # unpack SRPM
michael@428: print STDOUT "openpkg:$prog_name: unpacking source: \"$srpm\"\n";
michael@428: print STDOUT "openpkg:$prog_name: unpacking target: \"$specdir\"\n";
michael@428: print STDOUT "openpkg:$prog_name: unpacking target: \"$sourcedir\"\n";
michael@428: my $abs_specdir = $specdir;
michael@428: my $abs_sourcedir = $sourcedir;
michael@428: my $pwd = `pwd`; $pwd =~ s/\r?\n$//s;
michael@428: $abs_specdir = "$pwd/$abs_specdir" if ($abs_specdir !~ m/^\//);
michael@428: $abs_sourcedir = "$pwd/$abs_sourcedir" if ($abs_sourcedir !~ m/^\//);
michael@428: my $rc = system(
michael@428: "$openpkg_prefix/bin/openpkg" .
michael@428: " --keep-privileges" .
michael@428: " rpm" .
michael@428: " -i" .
michael@428: " --define '_specdir $abs_specdir'" .
michael@428: " --define '_sourcedir $abs_sourcedir'" .
michael@428: " $srpm"
michael@428: );
michael@428:
michael@428: # fix location of files
michael@428: if (not -f "$specdir/$name.spec") {
michael@428: die sprintf("failed to install package \"%s\": file \"%s\" not found\n", $srpm, "$specdir/$name.spec");
michael@428: }
michael@428: open(SPEC, "<$specdir/$name.spec");
michael@428: my $spec = ""; { local $/; $spec = ; }
michael@428: close(SPEC);
michael@428: my $src = {};
michael@428: $spec =~ s/^(?:Source|Patch)\d+:\s+(\S+)/$src->{$1} = 1, ''/mgei;
michael@428: foreach my $file (keys %{$src}) {
michael@428: if ($file !~ m/^(https?|ftp):\/\//) {
michael@428: if (not -f "$specdir/$file" and -f "$sourcedir/$file") {
michael@428: system("mv $sourcedir/$file $specdir/$file");
michael@428: }
michael@428: }
michael@428: }
michael@428:
michael@428: # create .openpkg/rpmmacros file
michael@428: if (not -f $macrosfile) {
michael@428: print STDOUT "openpkg:$prog_name: creating file: \"$macrosfile\"\n";
michael@428: my $rpmmacros =
michael@428: "##\n" .
michael@428: "## .openpkg/rpmmacros -- local OpenPKG RPM macro definitions\n" .
michael@428: "##\n" .
michael@428: "\n" .
michael@428: "\%openpkg_layout" .
michael@428: " macrosfile=\%{macrosfile}" .
michael@428: " layout=" . $lopts->{"l"} .
michael@428: " shared=" . ($lopts->{"s"} ? "yes" : "no") .
michael@428: " debug=" . ($lopts->{"d"} ? "yes" : "no") .
michael@428: "\n" .
michael@428: "\n";
michael@428: open(MACROS, ">$macrosfile");
michael@428: print(MACROS $rpmmacros);
michael@428: close(MACROS);
michael@428: }
michael@428:
michael@428: return $rc;
michael@428: }
michael@428:
michael@428: # command: edit package specification
michael@428: sub cmd_edit ($@) {
michael@428: my ($gopts, @argv) = @_;
michael@428: my $rc = 0;
michael@428:
michael@428: # run editor
michael@428: my $editor = ($ENV{"EDITOR"} || "vi");
michael@428: my $specfile = ($argv[0] || specfile());
michael@428: run("$editor $specfile");
michael@428:
michael@428: return $rc;
michael@428: }
michael@428:
michael@428: # command: build package
michael@428: sub cmd_build ($@) {
michael@428: my ($gopts, @argv) = @_;
michael@428: my $rc = 0;
michael@428:
michael@428: # command line argument processing
michael@428: my $lopts = {};
michael@428: @argv = getopts("s:D:w:", $lopts, @argv);
michael@428: if ($lopts->{"s"} eq '') {
michael@428: $lopts->{"s"} = "all";
michael@428: }
michael@428: if ($lopts->{"s"} !~ m/^(track|fetch|prep|compile|install|binary|source|all)$/) {
michael@428: die "invalid step";
michael@428: }
michael@428:
michael@428: # assembly defines
michael@428: my $defs = "";
michael@428: if ($lopts->{"D"}) {
michael@428: foreach my $def (split(/\s+/, $lopts->{"D"})) {
michael@428: if ($def =~ m/^([^=]+)=(.+)$/) {
michael@428: $defs .= "--define '$1 $2' ";
michael@428: }
michael@428: else {
michael@428: $defs .= "--define '$def yes' ";
michael@428: }
michael@428: }
michael@428: }
michael@428: if ($lopts->{"w"}) {
michael@428: foreach my $def (split(/\s+/, $lopts->{"w"})) {
michael@428: $defs .= "--with $def ";
michael@428: }
michael@428: }
michael@428:
michael@428: # run build command
michael@428: my $specfile = ($argv[0] || specfile());
michael@428: if ($lopts->{"s"} eq 'track') {
michael@428: run("$openpkg_prefix/bin/openpkg rpm -bt $defs$specfile");
michael@428: }
michael@428: elsif ($lopts->{"s"} eq 'fetch') {
michael@428: run("$openpkg_prefix/bin/openpkg rpm -bf $defs$specfile");
michael@428: }
michael@428: elsif ($lopts->{"s"} eq 'prep') {
michael@428: run("$openpkg_prefix/bin/openpkg rpm -bp $defs$specfile");
michael@428: }
michael@428: elsif ($lopts->{"s"} eq 'compile') {
michael@428: run("$openpkg_prefix/bin/openpkg rpm -bc --short-circuit $defs$specfile");
michael@428: }
michael@428: elsif ($lopts->{"s"} eq 'install') {
michael@428: run("$openpkg_prefix/bin/openpkg rpm -bi --short-circuit $defs$specfile");
michael@428: }
michael@428: elsif ($lopts->{"s"} eq 'binary') {
michael@428: run("$openpkg_prefix/bin/openpkg rpm -bb --short-circuit $defs$specfile");
michael@428: }
michael@428: elsif ($lopts->{"s"} eq 'source') {
michael@428: run("$openpkg_prefix/bin/openpkg rpm -bs $defs$specfile");
michael@428: }
michael@428: elsif ($lopts->{"s"} eq 'all') {
michael@428: run("$openpkg_prefix/bin/openpkg rpm -ba $defs$specfile");
michael@428: }
michael@428:
michael@428: return $rc;
michael@428: }
michael@428:
michael@428: # command: peek into package
michael@428: sub cmd_peek ($@) {
michael@428: my ($gopts, @argv) = @_;
michael@428: my $rc = 0;
michael@428:
michael@428: # run query command
michael@428: my $template = `$openpkg_prefix/bin/openpkg rpm --eval '%{_rpmdir}/%{_rpmfilename}'`;
michael@428: $template =~ s/\n$//s;
michael@428: my $specfile = specfile();
michael@428: my $rpm = `$openpkg_prefix/bin/openpkg rpm -q --specfile '$specfile' --qf 'XXX$template'`;
michael@428: $rpm =~ s/^XXX//s;
michael@428: $rpm =~ s/\n$//s;
michael@428:
michael@428: # determine files
michael@428: print STDOUT "\033[34m++ determining configuration files\033[0m\n";
michael@428: my @cfgfiles = split(/\n/, `$openpkg_prefix/bin/openpkg rpm -qplc $rpm`);
michael@428: print STDOUT "\033[34m++ determining documentation files\033[0m\n";
michael@428: my @docfiles = split(/\n/, `$openpkg_prefix/bin/openpkg rpm -qpld $rpm`);
michael@428: print STDOUT "\033[34m++ determining all file information\033[0m\n";
michael@428: my @allfiles = split(/\n/, `$openpkg_prefix/bin/openpkg rpm -qplv $rpm`);
michael@428:
michael@428: # create package file listing
michael@428: foreach my $line (@allfiles) {
michael@428: $prefix = "";
michael@428: foreach my $docfile (@docfiles) {
michael@428: if ($line =~ m/\s+$docfile\b/s) {
michael@428: $prefix .= "D";
michael@428: last;
michael@428: }
michael@428: }
michael@428: foreach my $cfgfile (@cfgfiles) {
michael@428: if ($line =~ m/\s+$cfgfile\b/s) {
michael@428: $prefix .= "C";
michael@428: last;
michael@428: }
michael@428: }
michael@428: $prefix .= "--";
michael@428: $prefix = substr($prefix, 0, 2);
michael@428: if ($line =~ m/^d/) {
michael@428: $line =~ s/(\s+\/\S+)/\033[34m$1\033[0m/s;
michael@428: }
michael@428: print "$prefix $line\n";
michael@428: }
michael@428:
michael@428: return $rc;
michael@428: }
michael@428:
michael@428: # command: show modifications via VCS
michael@428: sub cmd_diff ($@) {
michael@428: my ($gopts, @argv) = @_;
michael@428: my $rc = 0;
michael@428:
michael@428: my $vcs = "";
michael@428: my $cmd = "";
michael@428: if (-d "CVS") {
michael@428: $vcs = "CVS";
michael@428: $cmd = "cvs diff -u3";
michael@428: }
michael@428: elsif (-d ".svn") {
michael@428: $vcs = "Subversion";
michael@428: $cmd = "svn diff";
michael@428: }
michael@428: elsif (-d "_MTN" or -d ".mtn" or
michael@428: -d "../_MTN" or -d "../.mtn" or
michael@428: -d "../../_MTN" or -d "../../.mtn" or
michael@428: -d "../../../_MTN" or -d "../../../.mtn") {
michael@428: $vcs = "Monotone";
michael@428: $cmd = "mtn diff .";
michael@428: }
michael@428: elsif (-d ".git" or
michael@428: -d "../.git" or
michael@428: -d "../../.git" or
michael@428: -d "../../../.git") {
michael@428: $vcs = "Git";
michael@428: $cmd = "git diff . ";
michael@428: }
michael@428: elsif (-d ".hg" or
michael@428: -d "../.hg" or
michael@428: -d "../../.hg" or
michael@428: -d "../../../.hg") {
michael@428: $vcs = "Mercurial";
michael@428: $cmd = "hg diff ."
michael@428: }
michael@428: else {
michael@428: $vcs = "OSSP svs";
michael@428: $cmd = "svs diff";
michael@428: }
michael@428: print STDOUT "\033[34m++ modifications as known to underlying $vcs VCS\033[0m\n";
michael@428: run($cmd);
michael@428: }
michael@428:
michael@428: # command: install package
michael@428: sub cmd_install ($@) {
michael@428: my ($gopts, @argv) = @_;
michael@428: my $rc = 0;
michael@428:
michael@428: # command line argument processing
michael@428: my $lopts = {};
michael@428: @argv = getopts("fnos", $lopts, @argv);
michael@428:
michael@428: # run install command
michael@428: my $template = `$openpkg_prefix/bin/openpkg rpm --eval '%{_rpmdir}/%{_rpmfilename}'`;
michael@428: $template =~ s/\n$//s;
michael@428: my $specfile = specfile();
michael@428: my $rpm = `$openpkg_prefix/bin/openpkg rpm -q --specfile '$specfile' --qf 'XXX$template'`;
michael@428: $rpm =~ s/^XXX//s;
michael@428: $rpm =~ s/\n$//s;
michael@428: chdir("/");
michael@428: run(($lopts->{"s"} ? "sudo " : "") .
michael@428: "$openpkg_prefix/bin/openpkg rpm -Uvh"
michael@428: . ($lopts->{"f"} ? " --force" : "")
michael@428: . ($lopts->{"n"} ? " --nodeps" : "")
michael@428: . ($lopts->{"o"} ? " --oldpackage" : "")
michael@428: . " $rpm");
michael@428:
michael@428: return $rc;
michael@428: }
michael@428:
michael@428: # command: erase package
michael@428: sub cmd_erase ($@) {
michael@428: my ($gopts, @argv) = @_;
michael@428: my $rc = 0;
michael@428:
michael@428: # command line argument processing
michael@428: my $lopts = {};
michael@428: @argv = getopts("fnas", $lopts, @argv);
michael@428:
michael@428: # run erase command
michael@428: my $specfile = specfile();
michael@428: my $name = `$openpkg_prefix/bin/openpkg rpm -q --specfile $specfile --qf '%{NAME}'`;
michael@428: $name =~ s/\n$//s;
michael@428: chdir("/");
michael@428: run(($lopts->{"s"} ? "sudo " : "") .
michael@428: "$openpkg_prefix/bin/openpkg rpm -e"
michael@428: . ($lopts->{"f"} ? " --force" : "")
michael@428: . ($lopts->{"n"} ? " --nodeps" : "")
michael@428: . ($lopts->{"a"} ? " --allmatches" : "")
michael@428: . " $name");
michael@428:
michael@428: return $rc;
michael@428: }
michael@428:
michael@428: # command: lint package
michael@428: sub cmd_lint ($@) {
michael@428: my ($gopts, @argv) = @_;
michael@428: my $rc = 0;
michael@428:
michael@428: # command line argument processing
michael@428: my $lopts = {};
michael@428: @argv = getopts("vb", $lopts, @argv);
michael@428:
michael@428: # run source linting commands
michael@428: my $specfile = specfile();
michael@428: my $fslfile = $specfile;
michael@428: $fslfile =~ s/([^\/]+)\.spec$/fsl.$1/s;
michael@428: my $rcfile = $specfile;
michael@428: $rcfile =~ s/([^\/]+)\.spec$/rc.$1/s;
michael@428: my $name = `$openpkg_prefix/bin/openpkg rpm -q --specfile $specfile --qf '%{NAME}'`;
michael@428: $name =~ s/\n$//s;
michael@428: my $template = `$openpkg_prefix/bin/openpkg rpm --eval '%{_rpmdir}/%{_rpmfilename}'`;
michael@428: $template =~ s/\n$//s;
michael@428: my $rpm = `$openpkg_prefix/bin/openpkg rpm -q --specfile '$specfile' --qf 'XXX$template'`;
michael@428: $rpm =~ s/^XXX//s;
michael@428: $rpm =~ s/\n$//s;
michael@428: my $rc = 0;
michael@428: $rc += run("$openpkg_prefix/bin/openpkg lint-spec" . ($lopts->{"v"} ? " --verbose" : "") . " $specfile");
michael@428: $rc += run("$openpkg_prefix/bin/openpkg lint-fsl" . ($lopts->{"v"} ? " --verbose" : "") . " $fslfile") if (-f $fslfile);
michael@428: $rc += run("$openpkg_prefix/bin/openpkg lint-rc" . ($lopts->{"v"} ? " --verbose" : "") . " $rcfile") if (-f $rcfile);
michael@428:
michael@428: # optionally run binary linting command
michael@428: run("$openpkg_prefix/bin/openpkg lint-rpm" . ($lopts->{"v"} ? " --verbose" : "") . " $rpm") if (-f $rpm and not $lopts->{"b"});
michael@428:
michael@428: return $rc;
michael@428: }
michael@428:
michael@428: # command: release package
michael@428: sub cmd_release ($@) {
michael@428: my ($gopts, @argv) = @_;
michael@428: my $rc = 0;
michael@428:
michael@428: # command line argument processing
michael@428: my $lopts = {};
michael@428: @argv = getopts("nm:f", $lopts, @argv);
michael@428:
michael@428: # implicit linting
michael@428: if (not $lopts->{"f"}) {
michael@428: my $rc = cmd_lint($gopts);
michael@428: if ($rc != 0 and !$lopts->{"f"}) {
michael@428: return $rc;
michael@428: }
michael@428: }
michael@428:
michael@428: # sanity check environment
michael@428: my $cmd = $ENV{"OPENPKG_DEV_RELEASE"}
michael@428: || `$openpkg_prefix/bin/openpkg rpm --eval '%{openpkg_dev_release}' 2>/dev/null || true` || "";
michael@428: $cmd =~ s/\n$//s;
michael@428: if ($cmd eq "") {
michael@428: print STDERR "openpkg:$prog_name:ERROR: no \$OPENPKG_DEV_RELEASE command defined\n";
michael@428: exit(1);
michael@428: }
michael@428:
michael@428: #
michael@428: # determine package information
michael@428: #
michael@428:
michael@428: print STDOUT "\033[34m++ determining package information\033[0m\n";
michael@428: my $info = {};
michael@428: $info->{"openpkg-prefix"} = $openpkg_prefix;
michael@428: $info->{"option-force"} = $lopts->{"f"} ? "yes" : "no";
michael@428:
michael@428: print STDOUT "-- determining package name/version/release\n";
michael@428: my $specfile = specfile();
michael@428: my $result = `$openpkg_prefix/bin/openpkg rpm -q --specfile $specfile --qf '::%{NAME}::%{VERSION}::%{RELEASE}'`;
michael@428: $result =~ s/\n$//s;
michael@428: $result =~ s/^:://s;
michael@428: my @result = split(/::/, $result);
michael@428: $info->{"package-name"} = $result[0];
michael@428: $info->{"package-version"} = $result[1];
michael@428: $info->{"package-release"} = $result[2];
michael@428:
michael@428: print STDOUT "-- determining package source and distribution location\n";
michael@428: my $defines = "--define '\%name " . $info->{"package-name"} . "'";
michael@428: $defines .= " --define '\%version " . $info->{"package-version"} . "'";
michael@428: $defines .= " --define '\%release " . $info->{"package-release"} . "'";
michael@428: my $result = `$openpkg_prefix/bin/openpkg rpm $defines --eval '%{_specdir}::%{_sourcedir}'`;
michael@428: $result =~ s/\n$//s;
michael@428: @result = split(/::/, $result);
michael@428: $info->{"spec-dir"} = $result[0];
michael@428: $info->{"source-dir"} = $result[1];
michael@428:
michael@428: print STDOUT "-- determining package source and binary RPM files\n";
michael@428: my $template = `$openpkg_prefix/bin/openpkg rpm --eval '%{_rpmdir}/%{l_binrpmfilename}::%{_srcrpmdir}/%{l_srcrpmfilename}'`;
michael@428: $template =~ s/\n$//s;
michael@428: $result = `$openpkg_prefix/bin/openpkg rpm -q --specfile $specfile --qf '::$template'`;
michael@428: $result =~ s/\n$//s;
michael@428: $result =~ s/^:://s;
michael@428: @result = split(/::/, $result);
michael@428: $info->{"binary-rpm-file"} = $result[0];
michael@428: $info->{"source-rpm-file"} = $result[1];
michael@428: $info->{"package-version-old"} = "";
michael@428: $info->{"package-release-old"} = "";
michael@428: $info->{"vcs"} = "none";
michael@428:
michael@428: print STDOUT "-- determining previous package version/release\n";
michael@428: my $vcs = "";
michael@428: my $diff = "";
michael@428: my $content_old = "";
michael@428: my $specdir = $info->{"spec-dir"};
michael@428: my $specfile = $info->{"package-name"} . ".spec";
michael@428: if (-f "$specdir/$specfile") {
michael@428: open(FP, "<$specdir/$specfile");
michael@428: $content_new .= $_ while ();
michael@428: close(FP);
michael@428: if ($content_new =~ m/\n\%No(?:Source|Patch)\s+/s) {
michael@428: $info->{"source-rpm-file"} =~ s/\.src\.rpm$/.nosrc.rpm/s;
michael@428: }
michael@428: if (-d "$specdir/CVS") {
michael@428: # package is version controlled via CVS
michael@428: $vcs = "cvs";
michael@428: $diff = `(cd $specdir && cvs diff -u3 $specfile) 2>/dev/null || true`;
michael@428: }
michael@428: elsif (-d "$specdir/.svn") {
michael@428: # package is version controlled via Subverson (SVN)
michael@428: $vcs = "svn";
michael@428: $diff = `(cd $specdir && svn diff $specfile) 2>/dev/null || true`;
michael@428: }
michael@428: elsif (-d "$specdir/_MTN" or -d "$specdir/.mtn" or
michael@428: -d "$specdir/../_MTN" or -d "$specdir/../.mtn" or
michael@428: -d "$specdir/../../_MTN" or -d "$specdir/../../.mtn" or
michael@428: -d "$specdir/../../../_MTN" or -d "$specdir/../../../.mtn") {
michael@428: # package is version controlled via Monotone (MTN)
michael@428: $vcs = "mtn";
michael@428: $diff = `(cd $specdir && mtn diff $specfile) 2>/dev/null || true`;
michael@428: $content_old = `(cd $specdir && mtn automate get_file_of -r h: $specfile) 2>/dev/null || true`;
michael@428: }
michael@428: elsif (-d "$specdir/.git" or
michael@428: -d "$specdir/../.git" or
michael@428: -d "$specdir/../../.git" or
michael@428: -d "$specdir/../../../.git") {
michael@428: # package is version controlled via Git
michael@428: $vcs = "git";
michael@428: $diff = `(cd $specdir && git diff $specfile) 2>/dev/null || true`;
michael@428: }
michael@428: elsif (-d "$specdir/.hg" or
michael@428: -d "$specdir/../.hg" or
michael@428: -d "$specdir/../../.hg" or
michael@428: -d "$specdir/../../../.hg") {
michael@428: # package is version controlled via Mercurial (Hg)
michael@428: $vcs = "hg";
michael@428: $diff = `(cd $specdir && hg diff $specfile) 2>/dev/null || true`;
michael@428: }
michael@428: elsif (-f "$specdir/$specfile.orig") {
michael@428: # package is patched via OSSP svs
michael@428: $vcs = "svs";
michael@428: $diff = `(cd $specdir && svs diff $specfile) 2>/dev/null || true`;
michael@428: }
michael@428: if ($vcs ne '') {
michael@428: $info->{"vcs"} = $vcs;
michael@428: }
michael@428: if ($content_old ne '') {
michael@428: my $define = {};
michael@428: $content_old =~ s/\n\%define[ \t]+([^ \t\n]+)[ \t]+([^ \t\n]+)/$define->{$1} = $2, ''/sge;
michael@428: $content_old =~ s/\n([^ \t\n]+):[ \t]+([^ \t\n]+)/$define->{lc($1)} = $2, ''/sge;
michael@428: sub resolve {
michael@428: my ($define, $name) = @_;
michael@428: my $value = $define->{$name};
michael@428: $value = "" if (not defined $value);
michael@428: $value =~ s/\%\{(.+?)\}/resolve($define, $1)/sge;
michael@428: return $value;
michael@428: }
michael@428: $info->{"package-version-old"} = resolve($define, "version");
michael@428: $info->{"package-release-old"} = resolve($define, "release");
michael@428: }
michael@428: if (( $info->{"package-version-old"} eq ''
michael@428: or $info->{"package-release-old"} eq '')
michael@428: and $diff ne '' ) {
michael@428: if ($info->{"package-version-old"} eq '' and $diff =~ m/\n-Version:\s+(\S+)/s) {
michael@428: $info->{"package-version-old"} = $1;
michael@428: }
michael@428: if ($info->{"package-release-old"} eq '' and $diff =~ m/\n-Release:\s+(\S+)/s) {
michael@428: $info->{"package-release-old"} = $1;
michael@428: }
michael@428: }
michael@428: }
michael@428:
michael@428: print STDOUT "-- determining commit message\n";
michael@428: $info->{"commit-message"} = ($lopts->{"m"} || "");
michael@428: if ($info->{"commit-message"} eq "") {
michael@428: if ($info->{"package-version-old"} ne $info->{"package-version"}) {
michael@428: # new version
michael@428: $info->{"commit-message"} = "upgrading package: " .
michael@428: $info->{"package-name"} . " " .
michael@428: $info->{"package-version-old"} . " -> " .
michael@428: $info->{"package-version"};
michael@428: }
michael@428: elsif (!$lopts->{"f"}) {
michael@428: print STDERR "openpkg:$prog_name:ERROR: package version not changed -- you have to manually provide a commit message\n";
michael@428: exit(1);
michael@428: }
michael@428: }
michael@428:
michael@428: # run external command
michael@428: print STDOUT "\033[34m++ executing openpkg development release program\033[0m\n";
michael@428: $cmd .= " %{openpkg-prefix}";
michael@428: $cmd .= " %{spec-dir} %{source-dir} %{binary-rpm-file} %{source-rpm-file}";
michael@428: $cmd .= " %{package-name} %{package-version} %{package-release} %{package-version-old} %{package-release-old}";
michael@428: $cmd .= " %{commit-message} %{vcs}";
michael@428: $cmd .= " %{option-force}";
michael@428: $cmd =~ s/(\%\{([a-z][a-z-]+)\})/&subst($info, $1, $2)/sge;
michael@428: sub subst {
michael@428: my ($info, $text, $name) = @_;
michael@428: if (exists($info->{$name})) {
michael@428: $text = $info->{$name};
michael@428: $text =~ s/'/\\'/sg;
michael@428: $text = "'$text'";
michael@428: }
michael@428: }
michael@428: if ($lopts->{"n"}) {
michael@428: print STDOUT "-- DRY RUN:\n";
michael@428: print STDOUT "-- $cmd\n";
michael@428: $rc = 0;
michael@428: }
michael@428: else {
michael@428: $rc = system($cmd);
michael@428: }
michael@428:
michael@428: return $rc;
michael@428: }
michael@428: