1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/openpkg/dev.pl Tue Jul 31 12:23:42 2012 +0200 1.3 @@ -0,0 +1,905 @@ 1.4 +## 1.5 +## openpkg dev -- OpenPKG Package Development Tool 1.6 +## Copyright (c) 2008-2012 OpenPKG GmbH <http://openpkg.com/> 1.7 +## 1.8 +## This software is property of the OpenPKG GmbH, DE MUC HRB 160208. 1.9 +## All rights reserved. Licenses which grant limited permission to use, 1.10 +## copy, modify and distribute this software are available from the 1.11 +## OpenPKG GmbH. 1.12 +## 1.13 +## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 1.14 +## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 1.15 +## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1.16 +## IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR 1.17 +## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.18 +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.19 +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 1.20 +## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 1.21 +## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 1.22 +## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 1.23 +## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 1.24 +## SUCH DAMAGE. 1.25 +## 1.26 + 1.27 +require 5; 1.28 + 1.29 +# OpenPKG instance prefix and RPM 1.30 +my $openpkg_prefix = $ENV{'OPENPKG_PREFIX'}; 1.31 +delete $ENV{'OPENPKG_PREFIX'}; 1.32 + 1.33 +# program identification 1.34 +my $prog_name = "dev"; 1.35 +my $prog_vers = "20100111"; 1.36 + 1.37 +# home-brewn getopt(3) style option parser 1.38 +sub getopts ($$@) { 1.39 + my ($opt_spec, $opts, @argv_orig) = @_; 1.40 + my (%optf) = map { m/(\w)/; $1 => $_ } $opt_spec =~ m/(\w:|\w)/g; 1.41 + my (@argv, $optarg); 1.42 + 1.43 + foreach (@argv_orig) { 1.44 + if (@argv) { 1.45 + push @argv, $_; 1.46 + } elsif (defined $optarg) { 1.47 + if (exists $opts->{$optarg}) { 1.48 + $opts->{$optarg} .= " $_"; 1.49 + } else { 1.50 + $opts->{$optarg} = $_; 1.51 + } 1.52 + $optarg = undef; 1.53 + } elsif (!/^[-]/) { 1.54 + push @argv, $_; 1.55 + } else { 1.56 + while (/^\-(\w)(.*)/) { 1.57 + if (exists $optf{$1}) { 1.58 + if (length($optf{$1}) > 1) { 1.59 + if ($2 ne '') { 1.60 + if (exists $opts->{$1}) { 1.61 + $opts->{$1} .= " $2"; 1.62 + } else { 1.63 + $opts->{$1} = $2; 1.64 + } 1.65 + } else { 1.66 + $optarg = $1; 1.67 + } 1.68 + last; 1.69 + } else { 1.70 + $opts->{$1} = 1; 1.71 + } 1.72 + } else { 1.73 + warn "openpkg:$prog_name:WARNING: unknown option $_\n"; 1.74 + } 1.75 + $_ = "-$2"; 1.76 + } 1.77 + } 1.78 + } 1.79 + if (defined $optarg) { 1.80 + warn "openpkg:$prog_name:WARNING: option $optarg requires an argument\n"; 1.81 + } 1.82 + foreach my $opt (keys %optf) { 1.83 + if (not exists $opts->{$opt}) { 1.84 + $opts->{$opt} = (length($optf{$opt}) > 1 ? "" : 0); 1.85 + } 1.86 + } 1.87 + return @argv; 1.88 +} 1.89 + 1.90 +# determine reasonable temporary directory 1.91 +my $tmpdir = ($ENV{"TMPDIR"} || "/tmp"); 1.92 +$tmpdir .= "/openpkg-$prog_name-$$"; 1.93 +my $rc = system("umask 022; $openpkg_prefix/lib/openpkg/shtool mkdir -f -p -m 755 $tmpdir || exit $?"); 1.94 +if ($rc != 0) { 1.95 + die "failed to create temporary directory: $tmpdir"; 1.96 +} 1.97 + 1.98 +# parse command line options 1.99 +my $opts = {}; 1.100 +@ARGV = getopts("h", $opts, @ARGV); 1.101 + 1.102 +# usage sanity check and usage help 1.103 +sub usage { 1.104 + my ($rc) = @_; 1.105 + my $usage = 1.106 + "openpkg:$prog_name:USAGE: openpkg dev <command> [<options>]\n"; 1.107 + if ($rc == 0) { 1.108 + print STDOUT $usage; 1.109 + } 1.110 + else { 1.111 + print STDERR $usage; 1.112 + } 1.113 + exit($rc); 1.114 +} 1.115 +if ($opts->{"h"}) { 1.116 + usage(0); 1.117 +} 1.118 +if (@ARGV == 0) { 1.119 + usage(1); 1.120 +} 1.121 + 1.122 +# command map 1.123 +my $map = { 1.124 + "unpack " => { -alias => qr/^(up|ex)$/, -key => "x" }, 1.125 + "edit\n" => { -alias => qr/^(ed|vi)$/, -key => "v" }, 1.126 + "build -s track\n" => { -alias => qr/^(bt|tr)$/, -key => "t" }, 1.127 + "build -s fetch\n" => { -alias => qr/^(bf|fe)$/, -key => "f" }, 1.128 + "build\n" => { -alias => qr/^(ba|bu)$/, -key => "b" }, 1.129 + "build -s prep\n" => { -alias => qr/^bp$/, -key => "1" }, 1.130 + "build -s compile\n" => { -alias => qr/^bc$/, -key => "2" }, 1.131 + "build -s install\n" => { -alias => qr/^bi$/, -key => "3" }, 1.132 + "build -s binary\n" => { -alias => qr/^bb$/, -key => "4" }, 1.133 + "build -s source\n" => { -alias => qr/^bs$/, -key => "s" }, 1.134 + "peek\n" => { -alias => qr/^pe$/, -key => "p" }, 1.135 + "diff\n" => { -alias => qr/^di$/, -key => "d" }, 1.136 + "install\n" => { -alias => qr/^in(?:st)?$/, -key => "i" }, 1.137 + "erase\n" => { -alias => qr/^er$/, -key => "e" }, 1.138 + "lint\n" => { -alias => qr/^li$/, -key => "l" }, 1.139 + "release " => { -alias => qr/^rel?$/, -key => "r" }, 1.140 +}; 1.141 + 1.142 +# dispatch command 1.143 +my $cmd = shift(@ARGV); 1.144 +foreach my $c (keys %{$map}) { 1.145 + my $a = $map->{$c}->{-alias}; 1.146 + if ($cmd =~ $a) { 1.147 + $c =~ s/\n$//; 1.148 + my @args = split(/\s+/, $c); 1.149 + $cmd = shift(@args); 1.150 + unshift(@ARGV, @args); 1.151 + print STDOUT "\033[34m\$ opd $cmd " . join(" ", map { 1.152 + my $x = $_; 1.153 + $x =~ s/"/\\"/g; 1.154 + $x =~ s/^(.*[ \t].*)$/"$1"/; 1.155 + $x 1.156 + } @ARGV) . "\033[0m\n"; 1.157 + } 1.158 +} 1.159 +my $func = "cmd_$cmd"; 1.160 +if (not defined(&$func)) { 1.161 + print STDERR "openpkg:$prog_name:ERROR: invalid command \"$cmd\"\n"; 1.162 + usage(1); 1.163 +} 1.164 +my $rc = &$func($opts, @ARGV); 1.165 +exit($rc); 1.166 + 1.167 +# execute a shell command 1.168 +sub run { 1.169 + my ($cmd) = @_; 1.170 + print STDOUT "\033[34m\$ $cmd\033[0m\n"; 1.171 + my $rc = system($cmd); 1.172 + return $rc; 1.173 +} 1.174 + 1.175 +# determine path to package specification 1.176 +sub specfile { 1.177 + my $specfile = (glob("*.spec"))[0]; 1.178 + if (not defined $specfile) { 1.179 + $specfile = (glob("src/*.spec"))[0]; 1.180 + if (not defined $specfile) { 1.181 + $specfile = (glob("*/*.spec"))[0]; 1.182 + if (not defined $specfile) { 1.183 + print STDERR "openpkg:$prog_name:ERROR: unable to determine package specification file\n"; 1.184 + exit(1); 1.185 + } 1.186 + } 1.187 + } 1.188 + return $specfile; 1.189 +} 1.190 + 1.191 +# command: interactive shell 1.192 +sub cmd_shell ($@) { 1.193 + my ($gopts, @argv) = @_; 1.194 + my $rc = 0; 1.195 + 1.196 + # command line argument processing 1.197 + my $lopts = {}; 1.198 + @argv = getopts("s", $lopts, @argv); 1.199 + 1.200 + # determine release 1.201 + my $release = `$openpkg_prefix/bin/openpkg release -F '%t'`; 1.202 + $release =~ s/\n$//s; 1.203 + 1.204 + # create dot files 1.205 + my $screenrc = "$tmpdir/dot.screenrc"; 1.206 + my $bashsh = "$tmpdir/bash.sh"; 1.207 + my $bashrc = "$tmpdir/dot.bashrc"; 1.208 + my $inputrc = "$tmpdir/dot.inputrc"; 1.209 + unlink("$screenrc"); 1.210 + unlink("$bashsh"); 1.211 + unlink("$bashrc"); 1.212 + unlink("$inputrc"); 1.213 + my $title = "openpkg dev"; 1.214 + $title .= '%? %{= rW} %n %{-}%?'; 1.215 + $title .= ' %=%-w%{= rW}%50>%n %t%{-}%+w'; 1.216 + my $screenrc_data = ""; 1.217 + $screenrc_data .= "source \"$ENV{HOME}/.screenrc\"\n" if (-f "$ENV{HOME}/.screenrc"); 1.218 + $screenrc_data .= 1.219 + "escape ^Aa\n" . 1.220 + "startup_message off\n" . 1.221 + "vbell off\n" . 1.222 + "defscrollback 10000\n" . 1.223 + "defmonitor off\n" . 1.224 + "msgminwait 1\n" . 1.225 + "msgwait 1\n" . 1.226 + "hardstatus alwayslastline \" $title \"\n" . 1.227 + "shell $bashsh\n"; 1.228 + my $bashsh_data = 1.229 + "##\n" . 1.230 + "##\ bash.sh -- \"openpkg dev shell\" GNU bash wrapper script\n" . 1.231 + "##\n" . 1.232 + "\n" . 1.233 + "OPENPKG_PREFIX=\"$openpkg_prefix\"\n" . 1.234 + "export OPENPKG_PREFIX\n" . 1.235 + "INPUTRC=\"$inputrc\"\n" . 1.236 + "export INPUTRC\n" . 1.237 + "SHELL=\"$openpkg_prefix/lib/openpkg/bash\"\n" . 1.238 + "export SHELL\n" . 1.239 + "eval `$openpkg_prefix/bin/openpkg rpm --eval 'T=\"\%{_tmppath}\"; S=\"\%{_specdir}\"; D=\"\%{_sourcedir}\"'`\n" . 1.240 + "export T S D\n" . 1.241 + "\$SHELL --rcfile $bashrc"; 1.242 + my $bashrc_data = 1.243 + "##\n" . 1.244 + "## dot.bashrc -- \"openpkg dev shell\" GNU bash configuration\n" . 1.245 + "##\n" . 1.246 + "\n" . 1.247 + "# load user's standard bash run-command script\n" . 1.248 + "if [ -f ~/.bashrc ]; then\n" . 1.249 + " . ~/.bashrc\n" . 1.250 + "fi\n" . 1.251 + "\n" . 1.252 + "# configure a special command-line prompt\n" . 1.253 + "if [ \".\$TERM\" = .screen ]; then\n" . 1.254 + " PS1=\"\\\\u@\\\\h:\\\\w [P=\\\\e[1m\\\${OPENPKG_PREFIX}\\\\e[0m]\\n\\\\\\\$ \\\\ek\\\\W\\\\e\\\\\\\\\"\n" . 1.255 + "else\n" . 1.256 + " PS1=\"\\\\u@\\\\h:\\\\w [P=\\\\e[1m\\\${OPENPKG_PREFIX}\\\\e[0m]\\n\\\\\\\$ \"\n" . 1.257 + "fi\n" . 1.258 + "alias openpkg=\"\\\${OPENPKG_PREFIX}/bin/openpkg\"\n" . 1.259 + "alias opd=\"\\\${OPENPKG_PREFIX}/bin/openpkg dev\"\n" . 1.260 + "\n"; 1.261 + my $inputrc_data = 1.262 + "##\n" . 1.263 + "## dot.inputrc -- \"openpkg dev shell\" GNU readline configuration\n" . 1.264 + "##\n" . 1.265 + "\n"; 1.266 + foreach my $c (keys %{$map}) { 1.267 + my $k = $map->{$c}->{-key}; 1.268 + $c =~ s/\n/\\n/sg; 1.269 + $inputrc_data .= "\"\\e$k\": \"opd $c\"\n"; 1.270 + } 1.271 + $inputrc_data .= "\n"; 1.272 + open(SCREENRC, ">$screenrc"); 1.273 + print(SCREENRC $screenrc_data); 1.274 + close(SCREENRC); 1.275 + open(BASHSH, ">$bashsh"); 1.276 + print(BASHSH $bashsh_data); 1.277 + close(BASHSH); 1.278 + system("chmod a+x $bashsh"); 1.279 + open(BASHRC, ">$bashrc"); 1.280 + print(BASHRC $bashrc_data); 1.281 + close(BASHRC); 1.282 + open(INPUTRC, ">$inputrc"); 1.283 + print(INPUTRC $inputrc_data); 1.284 + close(INPUTRC); 1.285 + 1.286 + # run interactive shell 1.287 + print STDOUT "\033[34m++ entering OpenPKG $release development shell\033[0m\n"; 1.288 + my $rc; 1.289 + if ($lopts->{"s"}) { 1.290 + $rc = system("screen -c $screenrc -S 'openpkg-dev-shell' -d -R"); 1.291 + } 1.292 + else { 1.293 + $rc = system("$bashsh"); 1.294 + } 1.295 + 1.296 + # cleanup 1.297 + unlink("$tmpdir/dot.screenrc"); 1.298 + unlink("$tmpdir/bash.sh"); 1.299 + unlink("$tmpdir/dot.bashrc"); 1.300 + unlink("$tmpdir/dot.inputrc"); 1.301 + unlink("$tmpdir"); 1.302 + 1.303 + return $rc; 1.304 +} 1.305 + 1.306 +# command: unpack source RPM 1.307 +sub cmd_unpack ($@) { 1.308 + my ($gopts, @argv) = @_; 1.309 + my $rc = 0; 1.310 + 1.311 + # command line argument processing 1.312 + my $lopts = {}; 1.313 + @argv = getopts("l:b:sd", $lopts, @argv); 1.314 + if ($lopts->{"l"} eq "") { 1.315 + $lopts->{"l"} = "structured"; 1.316 + } 1.317 + if ($lopts->{"l"} !~ m/^(global|local|simple|structured|distributed)$/) { 1.318 + die sprintf("invalid layout type \"%s\"", $lopts->{"l"}); 1.319 + } 1.320 + if (@argv != 1) { 1.321 + die sprintf("exactly one SRPM has to be given"); 1.322 + } 1.323 + my $srpm = $argv[0]; 1.324 + if (not -f $srpm) { 1.325 + die sprintf("SRPM \"%s\" has to be a regular file", $srpm); 1.326 + } 1.327 + my $name = `$openpkg_prefix/bin/openpkg rpm -qp --qf '\%{NAME}' $srpm 2>/dev/null || true`; 1.328 + $name =~ s/\r?\n$//s; 1.329 + if ($name eq '') { 1.330 + die sprintf("unable to determine package name from SRPM \"%s\"", $srpm); 1.331 + } 1.332 + if ($lopts->{"b"} eq "") { 1.333 + $lopts->{"b"} = $srpm; 1.334 + if ($lopts->{"b"} =~ m/\.src\.rpm$/) { 1.335 + $lopts->{"b"} =~ s/\.src\.rpm$//; 1.336 + } 1.337 + else { 1.338 + my $subdir = `$openpkg_prefix/bin/openpkg rpm -qp --qf '\%{NAME}-\%{VERSION}-\%{RELEASE}' $srpm 2>/dev/null || true`; 1.339 + $lopts->{"b"} = $subdir; 1.340 + } 1.341 + } 1.342 + 1.343 + # determine result directory 1.344 + my $basedir = $lopts->{"b"}; 1.345 + my ($macrosfile, $specdir, $sourcedir); 1.346 + if ($lopts->{"l"} eq "global") { 1.347 + $macrosdir = "$openpkg_prefix/etc/openpkg"; 1.348 + $macrosfile = "$openpkg_prefix/etc/openpkg/rpmmacros"; 1.349 + $specdir = "$openpkg_prefix/RPM/SRC/$name"; 1.350 + $sourcedir = "$openpkg_prefix/RPM/SRC/$name"; 1.351 + $builddir = "$openpkg_prefix/RPM/TMP"; 1.352 + $tmpdir = "$openpkg_prefix/RPM/TMP"; 1.353 + $binrpmdir = "$openpkg_prefix/RPM/PKG"; 1.354 + $srcrpmdir = "$openpkg_prefix/RPM/PKG"; 1.355 + } 1.356 + elsif ($lopts->{"l"} eq "local") { 1.357 + $macrosdir = "$basedir/.openpkg"; 1.358 + $macrosfile = "$basedir/.openpkg/rpmmacros"; 1.359 + $specdir = "$basedir"; 1.360 + $sourcedir = "$basedir"; 1.361 + $builddir = "$basedir"; 1.362 + $tmpdir = "$basedir"; 1.363 + $binrpmdir = "$basedir"; 1.364 + $srcrpmdir = "$basedir"; 1.365 + } 1.366 + elsif ($lopts->{"l"} eq "simple") { 1.367 + $macrosdir = "$basedir/.openpkg"; 1.368 + $macrosfile = "$basedir/.openpkg/rpmmacros"; 1.369 + $specdir = "$basedir"; 1.370 + $sourcedir = "$basedir"; 1.371 + $builddir = "$tmpdir"; 1.372 + $tmpdir = "$tmpdir"; 1.373 + $binrpmdir = "$basedir/.."; 1.374 + $srcrpmdir = "$basedir/.."; 1.375 + } 1.376 + elsif ($lopts->{"l"} eq "structured") { 1.377 + $macrosdir = "$basedir/.openpkg"; 1.378 + $macrosfile = "$basedir/.openpkg/rpmmacros"; 1.379 + $specdir = "$basedir/src"; 1.380 + $sourcedir = "$basedir/dst"; 1.381 + $builddir = "$basedir/tmp"; 1.382 + $tmpdir = "$basedir/tmp"; 1.383 + $binrpmdir = "$basedir/pkg/bin"; 1.384 + $srcrpmdir = "$basedir/pkg/src"; 1.385 + } 1.386 + elsif ($lopts->{"l"} eq "distributed") { 1.387 + $macrosdir = "$basedir/.openpkg"; 1.388 + $macrosfile = "$basedir/.openpkg/rpmmacros"; 1.389 + $specdir = "$basedir/src/$name"; 1.390 + $sourcedir = "$basedir/dst/$name"; 1.391 + $builddir = "$basedir/tmp"; 1.392 + $tmpdir = "$basedir/tmp"; 1.393 + $binrpmdir = "$basedir/pkg/bin"; 1.394 + $srcrpmdir = "$basedir/pkg/src"; 1.395 + } 1.396 + 1.397 + # create still missing directories 1.398 + foreach my $dir ($macrosdir, $specdir, $sourcedir, $builddir, $tmpdir, $binrpmdir, $srcrpmdir) { 1.399 + if (not -d $dir) { 1.400 + print STDOUT "openpkg:$prog_name: creating directory \"$dir\"\n"; 1.401 + system("$openpkg_prefix/lib/openpkg/shtool mkdir -f -p -m 755 $dir"); 1.402 + } 1.403 + } 1.404 + 1.405 + # unpack SRPM 1.406 + print STDOUT "openpkg:$prog_name: unpacking source: \"$srpm\"\n"; 1.407 + print STDOUT "openpkg:$prog_name: unpacking target: \"$specdir\"\n"; 1.408 + print STDOUT "openpkg:$prog_name: unpacking target: \"$sourcedir\"\n"; 1.409 + my $abs_specdir = $specdir; 1.410 + my $abs_sourcedir = $sourcedir; 1.411 + my $pwd = `pwd`; $pwd =~ s/\r?\n$//s; 1.412 + $abs_specdir = "$pwd/$abs_specdir" if ($abs_specdir !~ m/^\//); 1.413 + $abs_sourcedir = "$pwd/$abs_sourcedir" if ($abs_sourcedir !~ m/^\//); 1.414 + my $rc = system( 1.415 + "$openpkg_prefix/bin/openpkg" . 1.416 + " --keep-privileges" . 1.417 + " rpm" . 1.418 + " -i" . 1.419 + " --define '_specdir $abs_specdir'" . 1.420 + " --define '_sourcedir $abs_sourcedir'" . 1.421 + " $srpm" 1.422 + ); 1.423 + 1.424 + # fix location of files 1.425 + if (not -f "$specdir/$name.spec") { 1.426 + die sprintf("failed to install package \"%s\": file \"%s\" not found\n", $srpm, "$specdir/$name.spec"); 1.427 + } 1.428 + open(SPEC, "<$specdir/$name.spec"); 1.429 + my $spec = ""; { local $/; $spec = <SPEC>; } 1.430 + close(SPEC); 1.431 + my $src = {}; 1.432 + $spec =~ s/^(?:Source|Patch)\d+:\s+(\S+)/$src->{$1} = 1, ''/mgei; 1.433 + foreach my $file (keys %{$src}) { 1.434 + if ($file !~ m/^(https?|ftp):\/\//) { 1.435 + if (not -f "$specdir/$file" and -f "$sourcedir/$file") { 1.436 + system("mv $sourcedir/$file $specdir/$file"); 1.437 + } 1.438 + } 1.439 + } 1.440 + 1.441 + # create .openpkg/rpmmacros file 1.442 + if (not -f $macrosfile) { 1.443 + print STDOUT "openpkg:$prog_name: creating file: \"$macrosfile\"\n"; 1.444 + my $rpmmacros = 1.445 + "##\n" . 1.446 + "## .openpkg/rpmmacros -- local OpenPKG RPM macro definitions\n" . 1.447 + "##\n" . 1.448 + "\n" . 1.449 + "\%openpkg_layout" . 1.450 + " macrosfile=\%{macrosfile}" . 1.451 + " layout=" . $lopts->{"l"} . 1.452 + " shared=" . ($lopts->{"s"} ? "yes" : "no") . 1.453 + " debug=" . ($lopts->{"d"} ? "yes" : "no") . 1.454 + "\n" . 1.455 + "\n"; 1.456 + open(MACROS, ">$macrosfile"); 1.457 + print(MACROS $rpmmacros); 1.458 + close(MACROS); 1.459 + } 1.460 + 1.461 + return $rc; 1.462 +} 1.463 + 1.464 +# command: edit package specification 1.465 +sub cmd_edit ($@) { 1.466 + my ($gopts, @argv) = @_; 1.467 + my $rc = 0; 1.468 + 1.469 + # run editor 1.470 + my $editor = ($ENV{"EDITOR"} || "vi"); 1.471 + my $specfile = ($argv[0] || specfile()); 1.472 + run("$editor $specfile"); 1.473 + 1.474 + return $rc; 1.475 +} 1.476 + 1.477 +# command: build package 1.478 +sub cmd_build ($@) { 1.479 + my ($gopts, @argv) = @_; 1.480 + my $rc = 0; 1.481 + 1.482 + # command line argument processing 1.483 + my $lopts = {}; 1.484 + @argv = getopts("s:D:w:", $lopts, @argv); 1.485 + if ($lopts->{"s"} eq '') { 1.486 + $lopts->{"s"} = "all"; 1.487 + } 1.488 + if ($lopts->{"s"} !~ m/^(track|fetch|prep|compile|install|binary|source|all)$/) { 1.489 + die "invalid step"; 1.490 + } 1.491 + 1.492 + # assembly defines 1.493 + my $defs = ""; 1.494 + if ($lopts->{"D"}) { 1.495 + foreach my $def (split(/\s+/, $lopts->{"D"})) { 1.496 + if ($def =~ m/^([^=]+)=(.+)$/) { 1.497 + $defs .= "--define '$1 $2' "; 1.498 + } 1.499 + else { 1.500 + $defs .= "--define '$def yes' "; 1.501 + } 1.502 + } 1.503 + } 1.504 + if ($lopts->{"w"}) { 1.505 + foreach my $def (split(/\s+/, $lopts->{"w"})) { 1.506 + $defs .= "--with $def "; 1.507 + } 1.508 + } 1.509 + 1.510 + # run build command 1.511 + my $specfile = ($argv[0] || specfile()); 1.512 + if ($lopts->{"s"} eq 'track') { 1.513 + run("$openpkg_prefix/bin/openpkg rpm -bt $defs$specfile"); 1.514 + } 1.515 + elsif ($lopts->{"s"} eq 'fetch') { 1.516 + run("$openpkg_prefix/bin/openpkg rpm -bf $defs$specfile"); 1.517 + } 1.518 + elsif ($lopts->{"s"} eq 'prep') { 1.519 + run("$openpkg_prefix/bin/openpkg rpm -bp $defs$specfile"); 1.520 + } 1.521 + elsif ($lopts->{"s"} eq 'compile') { 1.522 + run("$openpkg_prefix/bin/openpkg rpm -bc --short-circuit $defs$specfile"); 1.523 + } 1.524 + elsif ($lopts->{"s"} eq 'install') { 1.525 + run("$openpkg_prefix/bin/openpkg rpm -bi --short-circuit $defs$specfile"); 1.526 + } 1.527 + elsif ($lopts->{"s"} eq 'binary') { 1.528 + run("$openpkg_prefix/bin/openpkg rpm -bb --short-circuit $defs$specfile"); 1.529 + } 1.530 + elsif ($lopts->{"s"} eq 'source') { 1.531 + run("$openpkg_prefix/bin/openpkg rpm -bs $defs$specfile"); 1.532 + } 1.533 + elsif ($lopts->{"s"} eq 'all') { 1.534 + run("$openpkg_prefix/bin/openpkg rpm -ba $defs$specfile"); 1.535 + } 1.536 + 1.537 + return $rc; 1.538 +} 1.539 + 1.540 +# command: peek into package 1.541 +sub cmd_peek ($@) { 1.542 + my ($gopts, @argv) = @_; 1.543 + my $rc = 0; 1.544 + 1.545 + # run query command 1.546 + my $template = `$openpkg_prefix/bin/openpkg rpm --eval '%{_rpmdir}/%{_rpmfilename}'`; 1.547 + $template =~ s/\n$//s; 1.548 + my $specfile = specfile(); 1.549 + my $rpm = `$openpkg_prefix/bin/openpkg rpm -q --specfile '$specfile' --qf 'XXX$template'`; 1.550 + $rpm =~ s/^XXX//s; 1.551 + $rpm =~ s/\n$//s; 1.552 + 1.553 + # determine files 1.554 + print STDOUT "\033[34m++ determining configuration files\033[0m\n"; 1.555 + my @cfgfiles = split(/\n/, `$openpkg_prefix/bin/openpkg rpm -qplc $rpm`); 1.556 + print STDOUT "\033[34m++ determining documentation files\033[0m\n"; 1.557 + my @docfiles = split(/\n/, `$openpkg_prefix/bin/openpkg rpm -qpld $rpm`); 1.558 + print STDOUT "\033[34m++ determining all file information\033[0m\n"; 1.559 + my @allfiles = split(/\n/, `$openpkg_prefix/bin/openpkg rpm -qplv $rpm`); 1.560 + 1.561 + # create package file listing 1.562 + foreach my $line (@allfiles) { 1.563 + $prefix = ""; 1.564 + foreach my $docfile (@docfiles) { 1.565 + if ($line =~ m/\s+$docfile\b/s) { 1.566 + $prefix .= "D"; 1.567 + last; 1.568 + } 1.569 + } 1.570 + foreach my $cfgfile (@cfgfiles) { 1.571 + if ($line =~ m/\s+$cfgfile\b/s) { 1.572 + $prefix .= "C"; 1.573 + last; 1.574 + } 1.575 + } 1.576 + $prefix .= "--"; 1.577 + $prefix = substr($prefix, 0, 2); 1.578 + if ($line =~ m/^d/) { 1.579 + $line =~ s/(\s+\/\S+)/\033[34m$1\033[0m/s; 1.580 + } 1.581 + print "$prefix $line\n"; 1.582 + } 1.583 + 1.584 + return $rc; 1.585 +} 1.586 + 1.587 +# command: show modifications via VCS 1.588 +sub cmd_diff ($@) { 1.589 + my ($gopts, @argv) = @_; 1.590 + my $rc = 0; 1.591 + 1.592 + my $vcs = ""; 1.593 + my $cmd = ""; 1.594 + if (-d "CVS") { 1.595 + $vcs = "CVS"; 1.596 + $cmd = "cvs diff -u3"; 1.597 + } 1.598 + elsif (-d ".svn") { 1.599 + $vcs = "Subversion"; 1.600 + $cmd = "svn diff"; 1.601 + } 1.602 + elsif (-d "_MTN" or -d ".mtn" or 1.603 + -d "../_MTN" or -d "../.mtn" or 1.604 + -d "../../_MTN" or -d "../../.mtn" or 1.605 + -d "../../../_MTN" or -d "../../../.mtn") { 1.606 + $vcs = "Monotone"; 1.607 + $cmd = "mtn diff ."; 1.608 + } 1.609 + elsif (-d ".git" or 1.610 + -d "../.git" or 1.611 + -d "../../.git" or 1.612 + -d "../../../.git") { 1.613 + $vcs = "Git"; 1.614 + $cmd = "git diff . "; 1.615 + } 1.616 + elsif (-d ".hg" or 1.617 + -d "../.hg" or 1.618 + -d "../../.hg" or 1.619 + -d "../../../.hg") { 1.620 + $vcs = "Mercurial"; 1.621 + $cmd = "hg diff ." 1.622 + } 1.623 + else { 1.624 + $vcs = "OSSP svs"; 1.625 + $cmd = "svs diff"; 1.626 + } 1.627 + print STDOUT "\033[34m++ modifications as known to underlying $vcs VCS\033[0m\n"; 1.628 + run($cmd); 1.629 +} 1.630 + 1.631 +# command: install package 1.632 +sub cmd_install ($@) { 1.633 + my ($gopts, @argv) = @_; 1.634 + my $rc = 0; 1.635 + 1.636 + # command line argument processing 1.637 + my $lopts = {}; 1.638 + @argv = getopts("fnos", $lopts, @argv); 1.639 + 1.640 + # run install command 1.641 + my $template = `$openpkg_prefix/bin/openpkg rpm --eval '%{_rpmdir}/%{_rpmfilename}'`; 1.642 + $template =~ s/\n$//s; 1.643 + my $specfile = specfile(); 1.644 + my $rpm = `$openpkg_prefix/bin/openpkg rpm -q --specfile '$specfile' --qf 'XXX$template'`; 1.645 + $rpm =~ s/^XXX//s; 1.646 + $rpm =~ s/\n$//s; 1.647 + chdir("/"); 1.648 + run(($lopts->{"s"} ? "sudo " : "") . 1.649 + "$openpkg_prefix/bin/openpkg rpm -Uvh" 1.650 + . ($lopts->{"f"} ? " --force" : "") 1.651 + . ($lopts->{"n"} ? " --nodeps" : "") 1.652 + . ($lopts->{"o"} ? " --oldpackage" : "") 1.653 + . " $rpm"); 1.654 + 1.655 + return $rc; 1.656 +} 1.657 + 1.658 +# command: erase package 1.659 +sub cmd_erase ($@) { 1.660 + my ($gopts, @argv) = @_; 1.661 + my $rc = 0; 1.662 + 1.663 + # command line argument processing 1.664 + my $lopts = {}; 1.665 + @argv = getopts("fnas", $lopts, @argv); 1.666 + 1.667 + # run erase command 1.668 + my $specfile = specfile(); 1.669 + my $name = `$openpkg_prefix/bin/openpkg rpm -q --specfile $specfile --qf '%{NAME}'`; 1.670 + $name =~ s/\n$//s; 1.671 + chdir("/"); 1.672 + run(($lopts->{"s"} ? "sudo " : "") . 1.673 + "$openpkg_prefix/bin/openpkg rpm -e" 1.674 + . ($lopts->{"f"} ? " --force" : "") 1.675 + . ($lopts->{"n"} ? " --nodeps" : "") 1.676 + . ($lopts->{"a"} ? " --allmatches" : "") 1.677 + . " $name"); 1.678 + 1.679 + return $rc; 1.680 +} 1.681 + 1.682 +# command: lint package 1.683 +sub cmd_lint ($@) { 1.684 + my ($gopts, @argv) = @_; 1.685 + my $rc = 0; 1.686 + 1.687 + # command line argument processing 1.688 + my $lopts = {}; 1.689 + @argv = getopts("vb", $lopts, @argv); 1.690 + 1.691 + # run source linting commands 1.692 + my $specfile = specfile(); 1.693 + my $fslfile = $specfile; 1.694 + $fslfile =~ s/([^\/]+)\.spec$/fsl.$1/s; 1.695 + my $rcfile = $specfile; 1.696 + $rcfile =~ s/([^\/]+)\.spec$/rc.$1/s; 1.697 + my $name = `$openpkg_prefix/bin/openpkg rpm -q --specfile $specfile --qf '%{NAME}'`; 1.698 + $name =~ s/\n$//s; 1.699 + my $template = `$openpkg_prefix/bin/openpkg rpm --eval '%{_rpmdir}/%{_rpmfilename}'`; 1.700 + $template =~ s/\n$//s; 1.701 + my $rpm = `$openpkg_prefix/bin/openpkg rpm -q --specfile '$specfile' --qf 'XXX$template'`; 1.702 + $rpm =~ s/^XXX//s; 1.703 + $rpm =~ s/\n$//s; 1.704 + my $rc = 0; 1.705 + $rc += run("$openpkg_prefix/bin/openpkg lint-spec" . ($lopts->{"v"} ? " --verbose" : "") . " $specfile"); 1.706 + $rc += run("$openpkg_prefix/bin/openpkg lint-fsl" . ($lopts->{"v"} ? " --verbose" : "") . " $fslfile") if (-f $fslfile); 1.707 + $rc += run("$openpkg_prefix/bin/openpkg lint-rc" . ($lopts->{"v"} ? " --verbose" : "") . " $rcfile") if (-f $rcfile); 1.708 + 1.709 + # optionally run binary linting command 1.710 + run("$openpkg_prefix/bin/openpkg lint-rpm" . ($lopts->{"v"} ? " --verbose" : "") . " $rpm") if (-f $rpm and not $lopts->{"b"}); 1.711 + 1.712 + return $rc; 1.713 +} 1.714 + 1.715 +# command: release package 1.716 +sub cmd_release ($@) { 1.717 + my ($gopts, @argv) = @_; 1.718 + my $rc = 0; 1.719 + 1.720 + # command line argument processing 1.721 + my $lopts = {}; 1.722 + @argv = getopts("nm:f", $lopts, @argv); 1.723 + 1.724 + # implicit linting 1.725 + if (not $lopts->{"f"}) { 1.726 + my $rc = cmd_lint($gopts); 1.727 + if ($rc != 0 and !$lopts->{"f"}) { 1.728 + return $rc; 1.729 + } 1.730 + } 1.731 + 1.732 + # sanity check environment 1.733 + my $cmd = $ENV{"OPENPKG_DEV_RELEASE"} 1.734 + || `$openpkg_prefix/bin/openpkg rpm --eval '%{openpkg_dev_release}' 2>/dev/null || true` || ""; 1.735 + $cmd =~ s/\n$//s; 1.736 + if ($cmd eq "") { 1.737 + print STDERR "openpkg:$prog_name:ERROR: no \$OPENPKG_DEV_RELEASE command defined\n"; 1.738 + exit(1); 1.739 + } 1.740 + 1.741 + # 1.742 + # determine package information 1.743 + # 1.744 + 1.745 + print STDOUT "\033[34m++ determining package information\033[0m\n"; 1.746 + my $info = {}; 1.747 + $info->{"openpkg-prefix"} = $openpkg_prefix; 1.748 + $info->{"option-force"} = $lopts->{"f"} ? "yes" : "no"; 1.749 + 1.750 + print STDOUT "-- determining package name/version/release\n"; 1.751 + my $specfile = specfile(); 1.752 + my $result = `$openpkg_prefix/bin/openpkg rpm -q --specfile $specfile --qf '::%{NAME}::%{VERSION}::%{RELEASE}'`; 1.753 + $result =~ s/\n$//s; 1.754 + $result =~ s/^:://s; 1.755 + my @result = split(/::/, $result); 1.756 + $info->{"package-name"} = $result[0]; 1.757 + $info->{"package-version"} = $result[1]; 1.758 + $info->{"package-release"} = $result[2]; 1.759 + 1.760 + print STDOUT "-- determining package source and distribution location\n"; 1.761 + my $defines = "--define '\%name " . $info->{"package-name"} . "'"; 1.762 + $defines .= " --define '\%version " . $info->{"package-version"} . "'"; 1.763 + $defines .= " --define '\%release " . $info->{"package-release"} . "'"; 1.764 + my $result = `$openpkg_prefix/bin/openpkg rpm $defines --eval '%{_specdir}::%{_sourcedir}'`; 1.765 + $result =~ s/\n$//s; 1.766 + @result = split(/::/, $result); 1.767 + $info->{"spec-dir"} = $result[0]; 1.768 + $info->{"source-dir"} = $result[1]; 1.769 + 1.770 + print STDOUT "-- determining package source and binary RPM files\n"; 1.771 + my $template = `$openpkg_prefix/bin/openpkg rpm --eval '%{_rpmdir}/%{l_binrpmfilename}::%{_srcrpmdir}/%{l_srcrpmfilename}'`; 1.772 + $template =~ s/\n$//s; 1.773 + $result = `$openpkg_prefix/bin/openpkg rpm -q --specfile $specfile --qf '::$template'`; 1.774 + $result =~ s/\n$//s; 1.775 + $result =~ s/^:://s; 1.776 + @result = split(/::/, $result); 1.777 + $info->{"binary-rpm-file"} = $result[0]; 1.778 + $info->{"source-rpm-file"} = $result[1]; 1.779 + $info->{"package-version-old"} = ""; 1.780 + $info->{"package-release-old"} = ""; 1.781 + $info->{"vcs"} = "none"; 1.782 + 1.783 + print STDOUT "-- determining previous package version/release\n"; 1.784 + my $vcs = ""; 1.785 + my $diff = ""; 1.786 + my $content_old = ""; 1.787 + my $specdir = $info->{"spec-dir"}; 1.788 + my $specfile = $info->{"package-name"} . ".spec"; 1.789 + if (-f "$specdir/$specfile") { 1.790 + open(FP, "<$specdir/$specfile"); 1.791 + $content_new .= $_ while (<FP>); 1.792 + close(FP); 1.793 + if ($content_new =~ m/\n\%No(?:Source|Patch)\s+/s) { 1.794 + $info->{"source-rpm-file"} =~ s/\.src\.rpm$/.nosrc.rpm/s; 1.795 + } 1.796 + if (-d "$specdir/CVS") { 1.797 + # package is version controlled via CVS 1.798 + $vcs = "cvs"; 1.799 + $diff = `(cd $specdir && cvs diff -u3 $specfile) 2>/dev/null || true`; 1.800 + } 1.801 + elsif (-d "$specdir/.svn") { 1.802 + # package is version controlled via Subverson (SVN) 1.803 + $vcs = "svn"; 1.804 + $diff = `(cd $specdir && svn diff $specfile) 2>/dev/null || true`; 1.805 + } 1.806 + elsif (-d "$specdir/_MTN" or -d "$specdir/.mtn" or 1.807 + -d "$specdir/../_MTN" or -d "$specdir/../.mtn" or 1.808 + -d "$specdir/../../_MTN" or -d "$specdir/../../.mtn" or 1.809 + -d "$specdir/../../../_MTN" or -d "$specdir/../../../.mtn") { 1.810 + # package is version controlled via Monotone (MTN) 1.811 + $vcs = "mtn"; 1.812 + $diff = `(cd $specdir && mtn diff $specfile) 2>/dev/null || true`; 1.813 + $content_old = `(cd $specdir && mtn automate get_file_of -r h: $specfile) 2>/dev/null || true`; 1.814 + } 1.815 + elsif (-d "$specdir/.git" or 1.816 + -d "$specdir/../.git" or 1.817 + -d "$specdir/../../.git" or 1.818 + -d "$specdir/../../../.git") { 1.819 + # package is version controlled via Git 1.820 + $vcs = "git"; 1.821 + $diff = `(cd $specdir && git diff $specfile) 2>/dev/null || true`; 1.822 + } 1.823 + elsif (-d "$specdir/.hg" or 1.824 + -d "$specdir/../.hg" or 1.825 + -d "$specdir/../../.hg" or 1.826 + -d "$specdir/../../../.hg") { 1.827 + # package is version controlled via Mercurial (Hg) 1.828 + $vcs = "hg"; 1.829 + $diff = `(cd $specdir && hg diff $specfile) 2>/dev/null || true`; 1.830 + } 1.831 + elsif (-f "$specdir/$specfile.orig") { 1.832 + # package is patched via OSSP svs 1.833 + $vcs = "svs"; 1.834 + $diff = `(cd $specdir && svs diff $specfile) 2>/dev/null || true`; 1.835 + } 1.836 + if ($vcs ne '') { 1.837 + $info->{"vcs"} = $vcs; 1.838 + } 1.839 + if ($content_old ne '') { 1.840 + my $define = {}; 1.841 + $content_old =~ s/\n\%define[ \t]+([^ \t\n]+)[ \t]+([^ \t\n]+)/$define->{$1} = $2, ''/sge; 1.842 + $content_old =~ s/\n([^ \t\n]+):[ \t]+([^ \t\n]+)/$define->{lc($1)} = $2, ''/sge; 1.843 + sub resolve { 1.844 + my ($define, $name) = @_; 1.845 + my $value = $define->{$name}; 1.846 + $value = "" if (not defined $value); 1.847 + $value =~ s/\%\{(.+?)\}/resolve($define, $1)/sge; 1.848 + return $value; 1.849 + } 1.850 + $info->{"package-version-old"} = resolve($define, "version"); 1.851 + $info->{"package-release-old"} = resolve($define, "release"); 1.852 + } 1.853 + if (( $info->{"package-version-old"} eq '' 1.854 + or $info->{"package-release-old"} eq '') 1.855 + and $diff ne '' ) { 1.856 + if ($info->{"package-version-old"} eq '' and $diff =~ m/\n-Version:\s+(\S+)/s) { 1.857 + $info->{"package-version-old"} = $1; 1.858 + } 1.859 + if ($info->{"package-release-old"} eq '' and $diff =~ m/\n-Release:\s+(\S+)/s) { 1.860 + $info->{"package-release-old"} = $1; 1.861 + } 1.862 + } 1.863 + } 1.864 + 1.865 + print STDOUT "-- determining commit message\n"; 1.866 + $info->{"commit-message"} = ($lopts->{"m"} || ""); 1.867 + if ($info->{"commit-message"} eq "") { 1.868 + if ($info->{"package-version-old"} ne $info->{"package-version"}) { 1.869 + # new version 1.870 + $info->{"commit-message"} = "upgrading package: " . 1.871 + $info->{"package-name"} . " " . 1.872 + $info->{"package-version-old"} . " -> " . 1.873 + $info->{"package-version"}; 1.874 + } 1.875 + elsif (!$lopts->{"f"}) { 1.876 + print STDERR "openpkg:$prog_name:ERROR: package version not changed -- you have to manually provide a commit message\n"; 1.877 + exit(1); 1.878 + } 1.879 + } 1.880 + 1.881 + # run external command 1.882 + print STDOUT "\033[34m++ executing openpkg development release program\033[0m\n"; 1.883 + $cmd .= " %{openpkg-prefix}"; 1.884 + $cmd .= " %{spec-dir} %{source-dir} %{binary-rpm-file} %{source-rpm-file}"; 1.885 + $cmd .= " %{package-name} %{package-version} %{package-release} %{package-version-old} %{package-release-old}"; 1.886 + $cmd .= " %{commit-message} %{vcs}"; 1.887 + $cmd .= " %{option-force}"; 1.888 + $cmd =~ s/(\%\{([a-z][a-z-]+)\})/&subst($info, $1, $2)/sge; 1.889 + sub subst { 1.890 + my ($info, $text, $name) = @_; 1.891 + if (exists($info->{$name})) { 1.892 + $text = $info->{$name}; 1.893 + $text =~ s/'/\\'/sg; 1.894 + $text = "'$text'"; 1.895 + } 1.896 + } 1.897 + if ($lopts->{"n"}) { 1.898 + print STDOUT "-- DRY RUN:\n"; 1.899 + print STDOUT "-- $cmd\n"; 1.900 + $rc = 0; 1.901 + } 1.902 + else { 1.903 + $rc = system($cmd); 1.904 + } 1.905 + 1.906 + return $rc; 1.907 +} 1.908 +