2006-10-23 Damien Carbery <
[email protected]>
* docs/ssa/*: Remove these, as they're now up on the
JDS project pages under 'Tasks/Single Sys Admin'.
use strict;
use warnings;
package rpm_spec;
sub get_name_and_version ($);
use overload ('""' => \&get_name_and_version);
# Create a new rpm_spec object.
# Return undef if the spec_file is not found
sub new ($;$) {
my $class = shift;
my $spec_file = shift;
my $arch = shift;
my $self = {};
if (! -r $spec_file) {
return (undef);
}
$self->{file_name} = $spec_file;
if (defined ($arch)) {
$self->{default_build_architecture} = $arch;
} else {
$self->{default_build_architecture} = 'i386';
}
$self->{defines} = {};
# some defaults:
$self->{defines}->{_tmppath} = "/tmp";
$self->{defines}->{_prefix} = "/usr";
$self->{defines}->{_exec_prefix} = "/usr";
$self->{defines}->{_defaultdocdir} = "%_prefix/doc";
$self->{defines}->{_sysconfdir} = "/etc";
$self->{defines}->{_datadir} = "%_prefix/share";
$self->{defines}->{_bindir} = "%_exec_prefix/bin";
$self->{defines}->{_libdir} = "%_exec_prefix/lib";
$self->{defines}->{_docdir} = "%_datadir/doc";
$self->{defines}->{_includedir} = "%_prefix/include";
$self->{defines}->{_mandir} = "%_prefix/man";
$self->{defines}->{_sbindir} = "%_exec_prefix/sbin";
$self->{defines}->{__libtoolize} = "libtoolize";
$self->{defines}->{optflags} = "-O3";
return (bless $self, $class);
}
sub _partial_deref ($$) {
my $self = shift;
my $str = shift;
my $def;
my $val;
while ($str =~ /\%{\?([^:]*):(.*)}/) {
$def = $2;
if (defined ($self->{defines}->{$1})) {
$str =~ s/\%{?([^:]*):(.*)}/$def/;
} else {
$str =~ s/\%{?([^:]*):(.*)}//;
}
}
while ($str =~ /\%\(([^)]*)\)/) {
$def = $1;
$val = `$def`;
$str =~ s/\%\(([^)]*)\)/$val/;
}
return $str;
}
sub _deref ($$) {
my $self = shift;
my $str = shift;
my $def;
my $val;
while ($str =~ /\%(?:{([a-zA-Z_][a-zA-Z0-9_]*)}|([a-zA-Z_][a-zA-Z0-9_]*))/) {
$def = $1;
if (not defined $def) {
$def = $2;
}
$val = get_def_or_param ($self, $def);
if (not defined ($val)) {
# print "WARNING: undefined symbol $def\n";
$val = "";
}
$str =~ s/\%{$def}/$val/g;
$str =~ s/\%$def/$val/g;
}
return ($str);
}
sub _split_opts ($) {
my $line = shift;
my @tokens = ();
$line =~ s/^\s*//;
$line =~ s/\s*$//;
while ($line ne "") {
my $tok = "";
while ($line =~ /^\S/) {
if ($line =~ /^"((\\"|[^"])*)"/) {
$tok = "$tok$1";
$line =~ s/^"((\\"|[^"])*)"//;
} elsif ($line =~ /^((\\"|[^\s"])+)/) {
$tok = "$tok$1";
$line =~ s/^((\\"|[^\s"])+)//;
} else {
print "ERROR: assertion failed: _split_opts ($line)\n"
}
}
$tok =~ s/\\"/"/g;
@tokens = (@tokens, $tok);
$line =~ s/^\s*//;
}
return @tokens;
}
sub _read_spec ($) {
my $self = shift;
open SPEC_FILE, "<$self->{file_name}" or
$self->{error} = "Could not open file $self->{file_name} for reading",
return (0);
my $line;
# initialisation
my @packages = ();
my @patches = ();
my @sources = ();
my @orig_sources = ();
my @rpms = ();
my @rpm_paths = ();
my @files = ();
$self->{rpm_loaded} = 0;
$self->{orig_sources} = \@orig_sources;
$self->{sources} = \@sources;
$self->{patches} = \@patches;
$self->{packages} = \@packages;
$self->{rpms} = \@rpms;
$self->{rpm_paths} = \@rpm_paths;
$self->{files} = \@files;
$self->{buildarchitecture} = $self->{default_build_architecture};
my $add_ref;
my $pkg_name = 'unknown';
my $next_add_ref;
while (1) {
$line = <SPEC_FILE>;
if (not defined ($line)) {
last;
}
$next_add_ref = undef;
if ($line =~ /^\%{/) {
$line = $self->_partial_deref ($line);
}
if ($line =~ /^#/) {
# comment, nothing to do.
} elsif ($line =~ /^[nN][aA][mM][eE]\s*:\s*(\S+)\s*$/) {
$pkg_name = $1;
my $ref = $self->{packages};
push (@$ref, $pkg_name);
$self->{$pkg_name} = {};
$self->{name} = $pkg_name;
my @provides = ($pkg_name);
$self->{$pkg_name}->{provides} = \@provides;
my @dummy = ();
$self->{$pkg_name}->{requires} = \@dummy;
} elsif ($line =~ /^[vV][eE][rR][sS][iI][oO][nN]\s*:\s*(.*\S)\s*$/) {
if (not defined ($self->{version})) {
$self->{version} = _deref($self, $1);
}
$self->{$pkg_name}->{version} = _deref($self, $1);
$self->{defines}->{version} = _deref($self, $1);
} elsif ($line =~ /^[sS][uU][mM][mM][aA][rR][yY]\s*:\s*(.*\S)\s*$/) {
$self->{$pkg_name}->{summary} = $1;
} elsif ($line =~ /^[gG][rR][oO][uU][pP]\s*:\s*(.*\S)\s*$/) {
$self->{$pkg_name}->{group} = $1;
} elsif ($line =~ /^[pP][rR][oO][vV][iI][dD][eE][sS]\s*:\s*(.*\S)\s*$/) { my $ref = $self->{$pkg_name}->{provides};
push (@$ref, _deref($self, $1));
} elsif ($line =~ /^[rR][eE][qQ][uU][iI][rR][eE][sS]\s*:\s*(.*\S)\s*$/) {
my $ref = $self->{$pkg_name}->{requires};
my @deps = split /,\s*/, _deref($self, $1);
push (@$ref, @deps);
} elsif ($line =~ /^[pP][rR][eE][rR][eE][qQ]\s*:\s*(.*\S)\s*$/) {
my $ref = $self->{$pkg_name}->{requires};
my @deps = split /,\s*/, _deref($self, $1);
push (@$ref, @deps);
} elsif ($line =~ /^[bB][uU][iI][lL][dD][rR][eE][qQ][uU][iI][rR][eE][sS]\s*:\s*(.*\S)\s*$/) {
my $ref = $self->{$pkg_name}->{requires};
my @deps = split /,\s*/, _deref($self, $1);
push (@$ref, @deps);
} elsif ($line =~ /^[bB][uU][iI][lL][dD][aA][rR][cC][hH][iI][tT][eE][cC][tT][uU][rR][eE][sS]\s*:\s*(.*\S)\s*$/) {
$self->{buildarchitecture} = $1;
} elsif ($line =~ /^[bB][uU][iI][lL][dD][aA][rR][cC][hH]\s*:\s*(.*\S)\s*$/) {
$self->{buildarchitecture} = $1;
} elsif ($line =~ /^[eE][xX][cC][lL][uU][sS][iI][vV][eE][aA][rR][cC][hH]\s*:\s*(.*\S)\s*$/) {
$self->{buildarchitecture} = $1;
} elsif ($line =~ /^\%package\s+-n\s+(\S+)$/) {
$pkg_name = $1;
my $ref = $self->{packages};
push (@$ref, $pkg_name);
$self->{$pkg_name} = {};
$self->{$pkg_name}->{version} = $self->{version};
my @provides = ($pkg_name);
$self->{$pkg_name}->{provides} = \@provides;
my @dummy = ();
$self->{$pkg_name}->{requires} = \@dummy;
} elsif ($line =~ /^\%package\s+(\S+)$/) {
$pkg_name = $self->{name}."-$1";
my $ref = $self->{packages};
push (@$ref, $pkg_name);
$self->{$pkg_name} = {};
$self->{$pkg_name}->{version} = $self->{version};
my @provides = ($pkg_name);
$self->{$pkg_name}->{provides} = \@provides;
my @dummy = ();
$self->{$pkg_name}->{requires} = \@dummy;
} elsif ($line =~ /^\%define\s+(\S+)\s+(.*\S)\s*$/) {
$self->{defines}->{$1} = _deref ($self, $2);
} elsif ($line =~ /^\%description/) {
$self->{$pkg_name}->{description} = '';
$next_add_ref = \$self->{$pkg_name}->{description};
} elsif ($line =~ /^\%files\s*(.*)\s*$/) {
my $files_opts = $1;
$files_opts =~ s/\s*$//;
my $pname = $self->{name};
if ($files_opts ne "") {
if ($files_opts =~ /^([^-]\S*)/) {
$pname = "${pname}-$1";
} elsif ($files_opts =~ /-n\s*(\S+)/) {
$pname = $1;
}
}
my $ref = $self->{files};
push (@$ref, $pname);
} elsif ($line =~ /^\%prep/) {
} elsif ($line =~ /^Source([0-9]*)\s*:\s*(\S*)\s*$/) {
my $num = $1;
my $orig_src = $2;
my $src = $orig_src;
$src =~ s/^.*\/([^\/]*)$/$1/;
if ($num eq '') {
$num = 0;
}
$self->{orig_sources}[$num] = _deref ($self, $orig_src);
$self->{sources}[$num] = _deref ($self, $src);
} elsif ($line =~ /^Patch([0-9]*)\s*:\s*(\S*)\s*$/) {
if ($1 eq '') {
$self->{patches}[0] = _deref ($self, $2);
} else {
$self->{patches}[$1] = _deref ($self, $2);
}
} elsif ($line =~ /^(\S+)\s*:\s*(.*\S)\s*$/) {
$self->{lc ($1)} = _deref ($self, $2);
} elsif ($line =~ /^%setup.*$/) {
my @setups = _split_opts ($line);
while (@setups) {
my $setup = shift (@setups);
if ($setup eq '-n') {
$setup = _deref ($self, shift (@setups));
if ($setup ne '') {
$self->add_define('_build_src_dir_name', $setup);
}
}
}
} else {
if (defined ($add_ref)) {
$$add_ref = $$add_ref . $line;
$next_add_ref = $add_ref;
} else {
if (not defined ($self->{unknown})) {
$self->{unknown} = "$line";
} else {
$self->{unknown} = $self->{unknown} . "$line";
}
}
}
$add_ref = $next_add_ref;
}
close SPEC_FILE;
@rpms = map "$_-$self->{$_}->{version}-$self->{release}.$self->{buildarchitecture}.rpm", @files;
@rpm_paths = map "RPMS/$self->{buildarchitecture}/$_", @rpms;
$self->{rpm_loaded} = 1;
return 1;
}
sub get_param ($$) {
my $self = shift;
my $param = shift;
if (not defined ($self->{rpm_loaded})) {
if (not $self->_read_spec) {
return (undef);
}
}
if (not defined ($self->{$param})) {
$self->{error} = "Parameter \"$param\" not found in the spec file";
return (undef);
}
return ($self->{$param});
}
sub get_param_array ($$) {
my $self = shift;
my $param = shift;
if (not defined ($self->{rpm_loaded})) {
if (not $self->_read_spec) {
return (undef);
}
}
if (not defined ($self->{$param})) {
$self->{error} = "Parameter \"$param\" not found in the spec file";
return (undef);
}
my $ref = $self->{$param};
return (@$ref);
}
sub get_pkg_param ($$$) {
my $self = shift;
my $pkg = shift;
my $param = shift;
if (not defined ($self->{rpm_loaded})) {
if (not $self->_read_spec) {
return (undef);
}
}
if (not defined ($self->{$pkg}->{$param})) {
$self->{error} = "Parameter \"$param\" not defined for $pkg";
return (undef);
}
return ($self->{$pkg}->{$param});
}
sub get_pkg_param_array ($$$) {
my $self = shift;
my $pkg = shift;
my $param = shift;
if (not defined ($self->{rpm_loaded})) {
if (not $self->_read_spec) {
return (undef);
}
}
if (not defined ($self->{$pkg}->{$param})) {
$self->{error} = "Parameter \"$param\" not defined for $pkg";
return (undef);
}
my $ref = $self->{$pkg}->{$param};
return (@$ref);
}
sub get_def ($$) {
my $self = shift;
my $def = shift;
if (not defined ($self->{rpm_loaded})) {
if (not $self->_read_spec) {
return (undef);
}
}
if (not defined ($self->{defines})) {
return (undef);
}
if (not defined ($self->{defines}->{$def})) {
return (undef);
}
return ($self->{defines}->{$def});
}
sub get_def_or_param ($$) {
my $self = shift;
my $def = shift;
my $val = $self->get_def ($def);
if (not defined ($val)) {
$val = $self->get_param ($def);
}
if (not defined ($val)) {
return (undef);
}
return ($val);
}
sub get_name ($) {
my $self = shift;
return ($self->get_param ("name"));
}
sub get_version ($) {
my $self = shift;
return ($self->get_param ("version"));
}
sub get_release ($) {
my $self = shift;
return ($self->get_param ("release"));
}
sub add_define ($$$) {
my $self = shift;
my $name = shift;
my $value = shift;
$self->{defines}->{$name} = $value;
}
sub get_name_and_version ($) {
my $self = shift;
my $name = $self->get_name;
if (not defined ($name)) {
return (undef);
}
my $version = $self->get_version;
if (not defined ($version)) {
return (undef);
}
my $release = $self->get_release;
if (not defined ($release)) {
return (undef);
}
return "$name-$version-$release";
}
1;