File debbuild-lua.patch of Package debbuild
diff --git a/debbuild b/debbuild
index 0e7286e..8c113af 100755
--- a/debbuild
+++ b/debbuild
@@ -8,6 +8,7 @@
# Copyright (C) 2015-2019 Andreas Scherer <https://ascherer.github.io/>
# Copyright (C) 2015-2019 Neal Gompa <ngompa13@gmail.com>
# Copyright (C) 2017-2019 Datto, Inc. <https://datto.com>
+# Copyright (C) 2020-2021 Victor Zhestkov <vzhestkov@suse.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -25,7 +26,6 @@
use strict;
use warnings;
-use threads;
use Cwd qw(abs_path); # for finding where files really are
use Fcntl; # for sysopen flags
@@ -73,6 +73,7 @@ my $finalmessages = ''; # A place to stuff messages that I want printed at the *
# For %define's in specfile, among many other things.
my %specglobals = (vendor => 'debbuild'); # this can be changed by the Vendor: header in the spec file
my %macroopts; # For macro options
+my @macropsstk = ();
# Ah, the joys of multiple architectures. :( Feh.
# Compiler options will be loaded from 'debrc' file(s).
my %optflags = (all => '');
@@ -86,7 +87,6 @@ my %optflags = (all => '');
my %pkgdata = (main => {source => ''});
my @pkglist = ('main'); #sigh
# Files listing. Embedding this in %pkgdata would be, um, messy.
-my %filelist;
my %doclist;
my @buildrequires;
my @buildconflicts;
@@ -106,6 +106,21 @@ my $fh;
# Store filelist files from "%files -f <filename>"
my %files_files=();
+my $debug_level = 0;
+
+my $lua_present;
+my $lua_ver;
+
+$lua_present = eval {
+ require Lua::API;
+ $lua_ver = lua_get('Lua::API::RELEASE');
+ 1;
+};
+$lua_present //= 0;
+
+my $gL;
+my @lstk = ();
+
#### main ####
# Program flow:
@@ -118,7 +133,13 @@ config_debrc();
lsb_detection();
parse_cmd();
+my $build_shell = expandmacros('%{___build_shell}');
+
print version() if defined $specglobals{verbose};
+$specglobals{_debbuild} = $static_config{version};
+$specglobals{_debbuild_lua} = $lua_ver if defined($lua_ver);
+print "Lua: ".($lua_present ? $lua_ver : 'No Lua module loaded')."\n"
+ if $specglobals{verbose};
if ($cmdopts{type} eq 's') {
install_sdeb($specglobals{srcpkg});
@@ -129,7 +150,7 @@ if ($cmdopts{type} eq 's') {
if ($cmdopts{type} eq 'd') {
parse_spec($specglobals{specfile});
foreach my $pkg (@pkglist) {
- $finalmessages .= format_debfile($pkg)."\n" if $filelist{$pkg};
+ $finalmessages .= format_debfile($pkg)."\n" if $pkgdata{$pkg}{files};
}
# Source package
$finalmessages .= format_sdebfile()."\n";
@@ -150,7 +171,7 @@ if ($cmdopts{type} eq 'r') {
} else {
die _('Can\'t --rebuild with ').$specglobals{srcpkg}."\n";
}
- chomp( $specglobals{specfile} = expandmacros("%{_specdir}/$specfile") );
+ chomp( $specglobals{_specfile} = $specglobals{specfile} = expandmacros("%{_specdir}/$specfile") );
$cmdopts{type} = 'b'; # fall through
}
@@ -162,7 +183,7 @@ if ($cmdopts{type} eq 't') {
unless defined $specglobals{tarball};
my $tarball = $specglobals{tarball};
my $cmdline = expandmacros(lookup_specfile($tarball));
- chomp( $specglobals{specfile} = expandmacros("%{_specdir}/").
+ chomp( $specglobals{_specfile} = $specglobals{specfile} = expandmacros("%{_specdir}/").
basename( qx { $cmdline } ) );
$tarball = abs_path($tarball);
@@ -172,6 +193,10 @@ if ($cmdopts{type} eq 't') {
}
if ($cmdopts{type} eq 'b') {
+ # Make a copy of spec lowercased and `_` replaced with `-` to do some magic
+ (my $spec_lc = lc(basename($specglobals{specfile}))) =~ tr/_/-/;
+ $spec_lc = dirname($specglobals{specfile})."/".$spec_lc;
+ qx ( $specglobals{__cp} -a $specglobals{specfile} $spec_lc ) if ( $specglobals{specfile} ne $spec_lc );
# Need to read the spec file to find the tarball. Note that
# this also generates most of the shell script required.
parse_spec($specglobals{specfile});
@@ -211,6 +236,12 @@ exit 0;
#### end main ####
+sub vdebug {
+ my ($msg, $dl, $tag) = @_;
+ print(STDERR "DEBUG".(defined($tag) ? "[".$tag."]" : "").": ".$msg."\n")
+ if $debug_level && ((not defined($dl)) || $debug_level >= $dl);
+}
+
## load_static_config()
# Load build-time configuration for debbuild itself.
# The Makefile stores this configuration as a debrc-format
@@ -238,6 +269,34 @@ sub load_static_config {
}
+sub read_multiline {
+ my ($value, $fh) = @_;
+ my $is_sub = ref($fh) eq 'CODE';
+ if ($value =~ /\\\n\z/) { # multi-line macro
+ while (my $l = $is_sub ? &$fh() : <$fh>) {
+ $value .= $l;
+ last unless $l =~ /\\\n\z/s;
+ }
+ # multiline macros workaround.
+ $value =~ s/\s?\\\n/\n/g;
+ $value =~ s/\\\\\n/\\\n/g;
+ $value =~ s/\\"/"/g;
+ $value =~ s/\n\z//;
+ }
+ if ($value =~ s/%\{lua:\s*$/\{lua:\n/) { # multi-line LUA macro
+ while (my $l = $is_sub ? &$fh() : <$fh>) {
+ $value .= $l;
+ my $t = $value;
+ last if extract_bracketed($t, '{}');
+ }
+ $value =~ s/\n\z//;
+ $value = '%'.$value;
+ }
+ $value =~ s/\\\\/\\/g if $value =~ /\A%\{lua:/;
+ return $value;
+}
+
+
## load_config()
# Load system macros similar to RPM which digests
# /usr/lib/rpm/macros /usr/lib/rpm/redhat/macros /etc/rpm/macros
@@ -245,23 +304,37 @@ sub load_static_config {
sub load_config {
# Load user configuration, permitting local override
my $homedir = $ENV{HOME} // $ENV{LOGDIR} // (getpwuid($<))[7];
- foreach my $macros ( ("$static_config{debconfigdir}/macros",
- glob("$static_config{debconfigdir}/macros.d/macros.*"),
- "$static_config{sysconfdir}/debbuild/macros",
- glob("$static_config{sysconfdir}/debbuild/macros.*"),
- "$homedir/.debmacros") ) {
- open MACROS,$macros or next; # should we warn about missing macro files?
- while (<MACROS>) {
- next unless my ($macro,$eq,$value) = /^%(\w+(?:\([\w:]*\))?)(=|\s*)(.+)$/;
- if ($value =~ s/\\$/\\\n/) { # multi-line macro
- while (<MACROS>) {
- $value .= $_;
- last unless /\\$/;
- }
- }
+ vdebug("Loading ...", 3, "load_config");
+ my @cfgs = ("$static_config{debconfigdir}/macros",
+ glob("$static_config{debconfigdir}/macros.d/macros.*"),
+ "$static_config{sysconfdir}/rpm/macros",
+ glob("$static_config{sysconfdir}/rpm/macros.*"),
+ "$static_config{sysconfdir}/debbuild/macros",
+ glob("$static_config{sysconfdir}/debbuild/macros.*"),
+ "$homedir/.rpmmacros",
+ "$homedir/.debmacros");
+ my %cfl = ();
+ my %ercd = ();
+ while ( my $macros = shift @cfgs ) {
+ next if $cfl{$macros} and not ( $macros eq "$homedir/.debmacros" or $macros eq "$homedir/.rpmmacros" );
+ open my $MACROS,$macros or next; # should we warn about missing macro files?
+ vdebug("Loading $macros ...", 3, "load_config");
+ while (<$MACROS>) {
+ next unless my ($macro,$eq,$value) = /^%(\w+(?:\([^)]*\))?)(=|\s*)(.+)$/s;
+ $value = read_multiline($value, $MACROS);
+ chomp($value);
+ vdebug("($macros): $macro = $value", 5, "load_config");
store_value('define', $macro, $eq eq '=' ? $specglobals{$value} : $value);
+ if ( $macro eq '_rpmconfigdir' and not $ercd{$macros} ) {
+ $ercd{$macros} = 1;
+ unshift @cfgs, expandmacros($value)."/macros",
+ glob(expandmacros($value)."/macros.d/macros.*");
+ push @cfgs, "$homedir/.rpmmacros", "$homedir/.debmacros"
+ if $macros eq "$homedir/.debmacros" or $macros eq "$homedir/.rpmmacros";
+ }
}
- close MACROS;
+ $cfl{$macros} = 1;
+ close $MACROS;
}
} # end load_config()
@@ -414,7 +487,7 @@ sub parse_cmd {
my $opt_arg = shift;
if ($cmdopts{type} eq 'b' or $cmdopts{type} eq 'd') {
# Spec file
- $specglobals{specfile} = $opt_arg;
+ $specglobals{_specfile} = $specglobals{specfile} = $opt_arg;
} elsif ($cmdopts{type} eq 't') {
# Tarball build. Need to extract tarball to find spec file. Whee.
$specglobals{tarball} = $opt_arg;
@@ -530,12 +603,21 @@ sub parse_spec {
# Otherwise, parse the line according to which section we're supposedly
# parsing right now
-LINE: while (<$fh>) {
- next if /^\s*#/ and $stage !~ /changelog|copyrightdata/; # Ignore comments...
- next if /^\s*$/ and $stage !~ /changelog|copyrightdata|description/; # ... and blank lines.
+ our @rbuf = ();
+ sub spec_readline {
+ if ( @rbuf ) {
+ $_ = shift @rbuf;
+ $_ .= "\n";
+ } else {
+ $_ = <$fh>;
+ }
+ }
+LINE: while ( spec_readline() ) {
+ next if /^\s*#/ and $stage =~ /\A(preamble|files)\z/; # Ignore comments...
+ next if /^\s*$/ and $stage =~ /\A(preamble|files)\z/; # ... and blank lines.
# need to deal with these someday
- next if /^%(?:verify|ghost)/;
+ next if /^%verify/;
# Escape '%' -- rpmbuild seems to do this
s/%%/%/g;
@@ -549,7 +631,7 @@ LINE: while (<$fh>) {
# First a set of %-tags that are required to be used flush-left:
if ((/^%([a-z_]\w*)/ and not (grep { $1 eq $_ } qw(build changelog check
clean config copyrightdata description files ghost install package
- post postun pre prep preun setup verify) or /patch\d*/))
+ post posttrans postun pre prep pretrans preun setup verify) or /patch\d*/))
and # then a set of %-tags that are permitted in more liberal layouts:
(/^\s*%([a-z_]\w*)/ and not grep { $1 eq $_ } qw(attr autopatch
autosetup bcond_with bcond_without configure defattr define dir
@@ -559,7 +641,17 @@ LINE: while (<$fh>) {
if (defined $specglobals{$1}) {
# This looks like a user-defined macro, possibly with arguments.
# Wrap the whole thing in curly braces for easier processing.
- s/^\s*%(.+)\s*$/%{$1}/ if defined $macroopts{$1};
+ # And avoid removing trailing new line symbol.
+ s/^\s*%(.+)\s*?(\n?)$/%{$1}$2/ if defined $macroopts{$1};
+ my $e = expandmacros($_);
+ $e =~ s/\s+\z//;
+ my @a = split(/\n/, $e);
+ if ( scalar(@a) > 1 ) {
+ unshift(@rbuf, @a) if scalar(@a);
+ next LINE;
+ }
+ $_ = shift(@a) or next LINE;
+ $_ .= "\n";
} else {
die _('Unknown tag \'%').$1._('\' at line ').$..
_(' of ').$specfile."\n";
@@ -567,30 +659,20 @@ LINE: while (<$fh>) {
}
# RPM conditionals - transform to generic form
- if (s/^\s*%if(arch|os)\s+//) {
+ if (s/^\s*%if(n|)(arch|os)\s+//) {
my $expanded_conditional = lc(expandmacros($_));
- my @args = map { " '%{_$1}' == '$_'" } split(/[\s,]+/, $expanded_conditional);
- $_ = '%if ' . join ' || ', @args;
- }
- if (s/^\s*%ifn(arch|os)\s+//) {
- my $expanded_conditional = lc(expandmacros($_));
- my @args = map { "'%{_$1}' != '$_'" } split(/[\s,]+/, $expanded_conditional);
- $_ = '%if ' . join ' && ', @args;
+ my @args = map { "'%{_$2}' ".($1 eq 'n' ? '!=' : '==')." '$_'" } split(/[\s,]+/, $expanded_conditional);
+ $_ = '%if ' . join(($1 eq 'n' ? ' && ' : ' || '), @args);
}
# Generic %if..%else..%endif construct
if (s/^\s*%if//) {
- chomp( my $expr = lc expandmacros($_) );
+ chomp( my $expr = expandmacros($_) );
if ($expr =~ /^[\d\s<=>&|\(\)+-]+$/) {
# "plain" numeric expressions are evaluated as-is, except
$expr =~ s/(\D)0(\d+)/$1$2/g; # shortcut 0%{?ubuntu} == 1204
} else {
- # got a logic statement we want to turn into a 1 or a 0.
- # correctly "quote" the Boolean variables for Perl's eval below
- $expr =~ s/"//g;
- $expr =~ s/([\w\/]+)/"$1"/g;
-
# Done in this order so we don't cascade incorrectly.
# Yes, those spaces ARE correct in the replacements!
$expr =~ s/==/ eq /g;
@@ -607,7 +689,7 @@ LINE: while (<$fh>) {
next LINE if $ifexpr[-1]; # This appears to be the only case we call false.
my $iflevel = @ifexpr;
- while (<$fh>) { # Skip %if-block, inluding nested %if..%else..%endif
+ while ( spec_readline() ) { # Skip %if-block, inluding nested %if..%else..%endif
if (/^\s*%if/) {
$iflevel++;
} elsif (/^\s*%else/) {
@@ -620,11 +702,12 @@ LINE: while (<$fh>) {
die _("Unmatched %if at end of file. Missing %else/%endif.\n");
}
ELSE: if (/^\s*%else/) {
- die _('Unmatched %else in line ').$..
+ chomp;
+ die _('Unmatched %else in line ').$_.
_(". Missing %if.\n") unless @ifexpr;
next LINE unless $ifexpr[-1];
my $iflevel = @ifexpr;
- while (<$fh>) { # Skip %else-block, inluding nested %if..%else..%endif
+ while ( spec_readline() ) { # Skip %else-block, inluding nested %if..%else..%endif
if (/^\s*%if/) {
$iflevel++;
} elsif (/^\s*%else/) {
@@ -637,7 +720,8 @@ ELSE: if (/^\s*%else/) {
die _("Unmatched %else at end of file. Missing %endif.\n");
}
ENDIF: if (/^\s*%endif/) {
- die _('Unmatched %endif in line ').$..
+ chomp;
+ die _('Unmatched %endif in line ').$_.
_(". Missing %if/%else.\n") unless @ifexpr;
pop @ifexpr;
} # %if..%else..%endif
@@ -672,6 +756,7 @@ ENDIF: if (/^\s*%endif/) {
# Preprocess %define's and Conditional Build Stuff
elsif (/^\s*%(?:(?:un)?define|dump|global|bcond_with(?:out)?)\s/) {
+ $_ = read_multiline($_, \&spec_readline);
expandmacros($_);
}
@@ -682,16 +767,31 @@ ENDIF: if (/^\s*%endif/) {
($stage,$subname) = ($1,'main');
my $f;
my $n = $2;
+ if ( $stage eq 'files' ) {
+ vdebug($_, 5, 'parse_spec/files/'.$subname);
+ }
if ($n and $n =~ s/\s*-f\s+(.*)\s*//) {
$f = expandmacros("%{_builddir}/%{buildsubdir}/$1");
}
if ($n) { # Magic to add entries to the right package
my $tmp = expandmacros($n);
- $subname = /\s-n\s/ ? $tmp : "$pkgdata{main}{name}-$tmp";
+ if ( $stage eq 'files' ) {
+ vdebug($subname." / ".$tmp, 5, 'parse_spec/files/tmp');
+ }
+ if ( $tmp =~ /\A\s*-n\s+/ ) {
+ $subname = $';
+ } else {
+ $subname = /\s-n\s/ ? $tmp : "$pkgdata{main}{name}-$tmp";
+ $subname = 'main' if $pkgdata{main}{name} eq $subname;
+ }
+ if ( $stage eq 'files' ) {
+ vdebug($subname, 5, 'parse_spec/files/new');
+ }
}
if ($f) {
$files_files{$subname} = $f;
}
+ $pkgdata{$subname}{files} //= [] if $stage eq 'files';
} # %description, %copyrightdata, %files
elsif (/^%(package)\s+(?:-n\s+)?(.+)/) {
@@ -702,7 +802,8 @@ ENDIF: if (/^\s*%endif/) {
push @pkglist, $subname;
# Hack the filename for the package into a Debian-tool-compatible format. GRRRRRR!!!!!
# Have I mentioned I hate Debian Policy?
- ($pkgdata{$subname}{name} = $subname) =~ tr/_/-/;
+ # Package names are lower case only!
+ ($pkgdata{$subname}{name} = lc($subname)) =~ tr/_/-/;
$pkgdata{$subname}{version} = $pkgdata{main}{version};
# Build "same arch as previous package found" by default. Where rpm just picks the
# *very* last one, we want to allow arch<native>+arch-all
@@ -719,12 +820,12 @@ ENDIF: if (/^\s*%endif/) {
$script{$stage} .= "cd '%{buildsubdir}'\n" if $pkgdata{main}{hassetup};
} # %build,install,check,clean
- elsif (s/^%((?:pre|post)(?:un)?)//i) {
+ elsif (s/^%((?:pre|post)(?:un|trans)?)//i) {
$scriptlet = lc $1;
($stage,$subname) = ('prepost','main');
Getopt::Long::GetOptionsFromString($_,
# Rudimentary support for '-p <command>'
- 'p=s' => sub { $pkgdata{$subname}{$scriptlet} .= $_[1] },
+ 'p=s' => sub { $pkgdata{$subname}{$scriptlet} .= $_[1]."\n" },
# Magic to add entries to the right package
'n=s' => sub { $subname = expandmacros($_[1]) },
'<>' => sub { $subname =
@@ -822,10 +923,24 @@ ENDIF: if (/^\s*%endif/) {
\s*\)/x) {
($defattr{filemode}, $defattr{owner}, $defattr{group}) = ($1, $2, $4);
$defattr{dirmode} = ($6 or $defattr{filemode}); # default directory setting is optional
- } elsif (/^\s*%exclude/) {
- warn _("'%exclude' keyword found, ignoring input line\n");
+ } elsif (/^\s*%exclude\s+(.*)/) {
+ my $efl = $1;
+ $efl =~ s/\s+$//;
+ vdebug($efl, 5, "parse_spec/exclude/$subname");
+ $pkgdata{$subname}{files} //= [];
+ push @{$pkgdata{$subname}{files}}, { f => $efl, ex => 1 };
} else {
- process_filesline($subname);
+ my $p = $_;
+ my $e = expandmacros($p);
+ $e =~ s/\\(\n|\z)/$1/g;
+ $e =~ s/\s+\z//;
+ my @a = split(/\n/, $e);
+ if ( scalar @a > 1 ) {
+ unshift @rbuf, @a;
+ next LINE;
+ } else {
+ process_filesline($subname, $p);
+ }
}
} # files
@@ -836,9 +951,13 @@ ENDIF: if (/^\s*%endif/) {
elsif ($stage eq 'preamble') {
if (/^(summary|name|epoch|version|release|
- group|copyright|url|packager):\s*(.+)/ix) {
- $pkgdata{main}{lc $1} //= expandmacros($2);
- $pkgdata{main}{lc $1} =~ tr/_/-/ if 'name' eq $1;
+ group|copyright|url|packager|license):\s*(.+)/ix) {
+ my $_v = lc($1);
+ $pkgdata{main}{$_v} //= expandmacros($2);
+ if ( $_v eq 'name' ) {
+ $pkgdata{main}{$_v} = lc($pkgdata{main}{$_v});
+ $pkgdata{main}{$_v} =~ tr/_/-/;
+ }
} elsif (/^(vendor|buildroot):\s*(.+)\s*/i) {
$specglobals{lc $1} = $2;
} elsif (my ($srcnum, $src) = /^source(\d*):\s*(.+)\s*$/i) {
@@ -883,7 +1002,12 @@ ENDIF: if (/^\s*%endif/) {
# we don't handle auto-provides (yet)
$NoAutoReq = 1 if $1 =~ /(?:no|0)/i;
} else { # Other lines may contain '%{?!conditional:macros}' as well
- expandmacros($_);
+ my $pp = $_;
+ $_ = expandmacros($_);
+ next LINE if $pp eq $_;
+ s/\s+\z//;
+ my @a = split /\n/;
+ unshift(@rbuf, @a) if scalar(@a);
}
} # preamble
@@ -1148,7 +1272,7 @@ sub process_patch {
$patchscript .= q(%{__echo} "Patch ).($pnum eq '' ? '' : "#$pnum ");
$pnum = expandmacros("%{patch$pnum}");
$patchscript .= q|(|.basename($pnum).qq|):"\n|.
- "%{uncompress:$pnum} | %{__patch} $patchopts".$check_status;
+ "test -f $pnum && %{uncompress:$pnum} | %{__patch} $patchopts".$check_status;
}
return $patchscript;
} # end process_patch()
@@ -1171,23 +1295,26 @@ sub uncompress {
## process_filesline()
sub process_filesline {
- my $subname = shift;
+ my ($subname, $l) = @_;
# create and initialize flags
my ($perms, $owner, $group, $conf) =
($defattr{filemode}, $defattr{owner}, $defattr{group}, '-');
- # Debian dpkg doesn't speak "%docdir". Meh.
- my $dir_only = s/^\s*%(?:dir|docdir)\s*//;
+ vdebug("$subname: $l", 3, "process_filesline/in");
+ return if $l =~ /%ghost\s+/;
+
+ my $dir_only = $l =~ s/^\s*%dir\s*//;
+ $l =~ s/^\s*%docdir\s*//;
# strip and flag %attr constructs ... and wipe it when we're done.
- if (s/^\s*%attr # lot of formatting whitespace permitted
- \s*\(\s* # opening and closing parentheses; required
- (-|\d+) # (1) file mode, numeric (octal) or '-'
- [\s,]+ # field separator, comma or space
- (-|(['"]?)\w+\3) # (2) default owner, (3) quotes permitted, or '-'
- [\s,]+ # field separator, comma or space
- (-|(['"]?)\w+\5) # (4) default group, (5) quotes permitted, or '-'
+ if ($l =~ s/\s*%attr # lot of formatting whitespace permitted
+ \s*\(\s* # opening and closing parentheses; required
+ (-|\d+) # (1) file mode, numeric (octal) or '-'
+ [\s,]+ # field separator, comma or space
+ (-|(['"]?)\w+\3) # (2) default owner, (3) quotes permitted, or '-'
+ [\s,]+ # field separator, comma or space
+ (-|(['"]?)\w+\5) # (4) default group, (5) quotes permitted, or '-'
\s*\)\s*//x) {
($perms,$owner,$group) = ($1,$2,$4);
}
@@ -1199,7 +1326,7 @@ sub process_filesline {
##fixme
# also need to handle missingok (file that doesn't exist, but should be removed on uninstall)
# hmm. not sure if such is **POSSIBLE** with Debian... maybe an addition to %post?
- if (s/%config\b(?:\s*\(\s*noreplace\s*\)\s*)?//) {
+ if ($l =~ s/%config\b(?:\s*\(\s*noreplace\s*\)\s*)?//) {
$pkgdata{$subname}{conffiles} = 1; # Flag it for later
$conf = 'y';
}
@@ -1214,38 +1341,33 @@ sub process_filesline {
# /usr/share/licenses/<packagename>. Debian has no concept of this, so we just
# reuse the %doc handling and put it there. That's where these things used to go
# anyway...
- if (s/(%doc|%license)\s+//) {
+ if ($l =~ s/(%doc|%license)\s+//) {
# have to extract the partial pathnames that %doc installs automagically
- foreach my $pp (split) {
+ foreach my $pp (split(/\s+/, $l)) {
if (not $pp =~ m|^[%/]|) {
$doclist{$subname} .= " $pp";
my ($element) = $pp =~ m|([^/\s]+/?)$|;
- s|$pp|%{_docdir}/$pkgdata{$subname}{name}/$element|;
+ $pp =~ s/\*/\\*/g;
+ $pp =~ s/\./\\./g;
+ $l =~ s|$pp|%{_docdir}/$pkgdata{$subname}{name}/$element|;
}
}
} # $filesline =~ /%doc\b/
- s/^\s*//; chomp; # Just In Case. For, uh, neatness.
-
-# due to Debian's total lack of real permissions-processing in its actual package
-# handling component (dpkg-deb), this can't really be done "properly". We'll have
-# to add chown/chmod commands to the postinst instead. Feh.
- $pkgdata{$subname}{post} .= "%{__chown} -Rh $owner $_\n" if $owner ne '-';
- $pkgdata{$subname}{post} .= "%{__chgrp} -Rh $group $_\n" if $group ne '-';
- if (/\*/) { # will be 'globbed' later; will assume type 'file'
- $pkgdata{$subname}{post} .= "%{__chmod} $perms $_\n" if $perms ne '-';
- } else { # single entry; either 'directory' or 'file'
- $pkgdata{$subname}{post} .= "if [ -d $_ ]; then %{__chmod} $defattr{dirmode} $_; fi\n" if $defattr{dirmode} ne '-';
- $pkgdata{$subname}{post} .= "if [ -f $_ ]; then %{__chmod} $perms $_; fi\n" if $perms ne '-';
- }
+ $l =~ s/^\s*//; chomp $l; # Just In Case. For, uh, neatness.
##fixme
# need hackery to assure only one filespec per %config. NB: "*" is one filespec. <g>
- push @{$pkgdata{$subname}{conflist}}, $_ if $conf ne '-';
+ push @{$pkgdata{$subname}{conflist}}, $l if $conf ne '-';
# now that we've got the specials out of the way, we can add things to the appropriate list of files.
# ... and finally everything else
- $filelist{$subname} .= " $_" unless $dir_only;
+
+ # Save file and permissions to process in binpackage
+ $pkgdata{$subname}{files} //= [];
+ push @{$pkgdata{$subname}{files}}, { f => $l, u => $owner, g => $group,
+ fm => $perms, dm => $defattr{dirmode},
+ od => $dir_only };
} # end process_filesline()
@@ -1263,6 +1385,7 @@ sub execute_script {
or die _('Can\'t open/create ').($what or $stage).
_(' script file ')."$scriptfile: $!\n";
$specglobals{___build_body} = $script{$stage}; # Inject stage script from specfile
+ vdebug($specglobals{___build_body}, 5, "execute_script/$stage");
print SCRIPT expandmacros('%{___build_template}');
close SCRIPT;
@@ -1335,68 +1458,113 @@ sub binpackage {
my $debdir = expandmacros('%{_debdir}');
mkdir "$debdir/$pkgdata{$pkg}{arch}" unless -e "$debdir/$pkgdata{$pkg}{arch}";
+ vdebug("$pkg(".$pkgdata{$pkg}{name}.") - [".(defined($pkgdata{$pkg}{files}) ? 1 : 0)."]", 3, "binpackage");
# Skip building a package that doesn't have any files or dependencies. True
# metapackages don't have any files, but they depend on a bunch of things.
# Packages with neither have, essentially, no content.
next if
+ (not defined($pkgdata{$pkg}{files})) or (
(
- (not $filelist{$pkg} or $filelist{$pkg} =~ /^\s*$/)
+ not scalar @{$pkgdata{$pkg}{files}}
and not $files_files{$pkg}
- ) and (not $pkgdata{$pkg}{requires});
+ ) and (not $pkgdata{$pkg}{requires}));
- $filelist{$pkg} //= '';
+ $pkgdata{$pkg}{files} //= [];
+ vdebug("$pkg(".$pkgdata{$pkg}{name}.") - building...", 3, "binpackage/build");
# Gotta do this first, otherwise we don't have a place to move files from %files
mkdir "$specglobals{buildroot}/$pkg";
if ($files_files{$pkg}) {
- if (-e $files_files{$pkg}) {
- open(FILES, "<", $files_files{$pkg}) || die _('Could not open: ').$files_files{$pkg}."\n";
- while(<FILES>) {
- chomp($_);
- process_filesline($pkg, $_);
- }
- close FILES;
- } else {
- die _('File not found: ').$files_files{$pkg}."\n";
- }
+ if (-e $files_files{$pkg}) {
+ open(FILES, "<", $files_files{$pkg}) || die _('Could not open: ').$files_files{$pkg}."\n";
+ while(<FILES>) {
+ chomp($_);
+ process_filesline($pkg, $_);
+ }
+ close FILES;
+ } else {
+ die _('File not found: ').$files_files{$pkg}."\n";
+ }
}
- foreach my $pkgfile (split ' ', expandmacros($filelist{$pkg})) {
- # Feh. Manpages don't **NEED** to be gzipped, but rpmbuild does, and so shall we.
- # ... and your little info page too!
- if ($pkgfile =~ m{/usr/share/(?:man/man|info)}) {
- # need to check to see if manpage is gzipped
- if (-e "$specglobals{buildroot}$pkgfile") {
- # if we've just been pointed to a manpage section with "many" pages,
- # we need to gzip them all.
- # fortunately, we do NOT need to explicitly track each file for the
- # purpose of stuffing them in the package... the original %files
- # entry will do just fine.
- if ( -d "$specglobals{buildroot}$pkgfile") {
- foreach my $globfile (glob("$specglobals{buildroot}$pkgfile/*")) {
- qx ( $specglobals{__gzip} $globfile ) if $globfile !~ m|\.gz$|;
- }
- } else {
- if ($pkgfile !~ m|\.gz$|) {
- qx ( $specglobals{__gzip} $specglobals{buildroot}$pkgfile );
- $pkgfile .= '.gz';
- }
- }
- } else {
- if ($pkgfile !~ m|\.gz$|) {
- $pkgfile .= '.gz' unless $pkgfile =~ /\*$/;
- } else {
- $pkgfile =~ s/\.gz$//;
- qx ( $specglobals{__gzip} $specglobals{buildroot}$pkgfile );
- $pkgfile .= '.gz';
- }
- }
+ my $fmo = '';
+ foreach my $i ( @{$pkgdata{$pkg}{files}} ) {
+ vdebug($i->{f}, 5, "binpackage/files/pre/$pkg");
+ my $fr = expandmacros($i->{f});
+ $fr =~ s/\\(\n|\z)/\n/g;
+ # Not sure what should we do with %ghost
+ $fr =~ s/(?:\A|\s+)%ghost\s+.*(\n|\z)//mg;
+ #$fr =~ s/(?:\A|\s+)%ghost\s+(.*)(\n|\z)/$1$2/mg;
+ $fr =~ s/\n+/\n/g;
+ $fr =~ s/\A\s+//;
+ $fr =~ s/\s+\z//;
+ vdebug($fr, 5, "binpackage/files/post/$pkg");
+ foreach my $j ( split /\s+/, $fr ) {
+ if ( $i->{ex} ) {
+ # Perform %exclude from binpackage
+ vdebug($j, 5, "binpackage/exclude/$pkg");
+ qx ( $specglobals{__rm} -rf $specglobals{buildroot}/$pkg$j );
+ next;
+ }
+ vdebug($j, 5, "binpackage/include/$pkg");
+ my $brl = length($specglobals{buildroot});
+ foreach my $pkgfile ( glob $specglobals{buildroot}.$j ) {
+ $pkgfile = substr($pkgfile, $brl);
+ # Feh. Manpages don't **NEED** to be gzipped, but rpmbuild does, and so shall we.
+ # ... and your little info page too!
+ if ($pkgfile =~ m{/usr/share/(?:man/man|info)}) {
+ # need to check to see if manpage is gzipped
+ if (-e "$specglobals{buildroot}$pkgfile") {
+ # if we've just been pointed to a manpage section with "many" pages,
+ # we need to gzip them all.
+ # fortunately, we do NOT need to explicitly track each file for the
+ # purpose of stuffing them in the package... the original %files
+ # entry will do just fine.
+ if ( -d "$specglobals{buildroot}$pkgfile") {
+ foreach my $globfile (glob("$specglobals{buildroot}$pkgfile/*")) {
+ qx ( $specglobals{__gzip} $globfile ) if $globfile !~ m|\.gz$|;
+ }
+ } else {
+ if ($pkgfile !~ m|\.gz$|) {
+ qx ( $specglobals{__gzip} $specglobals{buildroot}$pkgfile );
+ $pkgfile .= '.gz';
+ }
+ }
+ } else {
+ if ($pkgfile !~ m|\.gz$|) {
+ $pkgfile .= '.gz' unless $pkgfile =~ /\*$/;
+ } else {
+ $pkgfile =~ s/\.gz$//;
+ qx ( $specglobals{__gzip} $specglobals{buildroot}$pkgfile );
+ $pkgfile .= '.gz';
+ }
+ }
+ }
+
+ my ($fpath,$fname) = $pkgfile =~ m|(.+?/?)?([^/]+/?)$|; # We don't need $fname now, but we might.
+ if ( -d "$specglobals{buildroot}$pkgfile" ) {
+ vdebug($pkgfile, 5, "binpackage/add/dir/$pkg");
+ qx ( $specglobals{__mkdir_p} $specglobals{buildroot}/$pkg$pkgfile );
+ qx ( $specglobals{__cp} -ar $specglobals{buildroot}$pkgfile $specglobals{buildroot}/$pkg$fpath ) unless $i->{od};
+ } else {
+ vdebug($pkgfile, 5, "binpackage/add/file/$pkg");
+ qx ( $specglobals{__mkdir_p} $specglobals{buildroot}/$pkg$fpath ) if $fpath;
+ qx ( $specglobals{__cp} -a $specglobals{buildroot}$pkgfile $specglobals{buildroot}/$pkg$fpath );
+ }
+
+ # due to Debian's total lack of real permissions-processing in its actual package
+ # handling component (dpkg-deb), this can't really be done "properly". We'll have
+ # to add chown/chmod commands to the postinst instead. Feh.
+ $fmo .= $specglobals{__chown}." -Rh ".$i->{u}." $pkgfile\n" if $i->{u} ne '-';
+ $fmo .= $specglobals{__chgrp}." -Rh ".$i->{g}." $pkgfile\n" if $i->{g} ne '-';
+ if ( -d "$specglobals{buildroot}$pkgfile" ) {
+ $fmo .= $specglobals{__chmod}." ".$i->{dm}." $pkgfile\n" if $i->{dm} ne '-';
+ } else {
+ $fmo .= $specglobals{__chmod}." ".$i->{fm}." $pkgfile\n" if $i->{fm} ne '-';
+ }
+ }
}
-
- my ($fpath,$fname) = $pkgfile =~ m|(.+?/?)?([^/]+/?)$|; # We don't need $fname now, but we might.
- qx ( $specglobals{__mkdir_p} $specglobals{buildroot}/$pkg$fpath ) if $fpath;
- qx ( $specglobals{__cp} -ar $specglobals{buildroot}$pkgfile $specglobals{buildroot}/$pkg$fpath );
}
# Add 'changelog' and 'copyrightdata' sections as 'doc' files.
@@ -1428,25 +1596,26 @@ sub binpackage {
# Munge things so that Debian tools don't choke on errant blank lines
$pkgdata{$pkg}{description} =~ s/\s+$//g; # Trim trailing blanks
- $pkgdata{$pkg}{description} =~ s/^ $/ ./mg; # Replace lines consisting of " \n" with " .\n"
+ $pkgdata{$pkg}{description} =~ s/^\s+$/ ./mg; # Replace lines consisting of " \n" with " .\n"
# Give an estimate of the installation size
my ($installedsize) =
qx($specglobals{__du} -s --apparent-size $specglobals{buildroot}/$pkg) =~
/(\d+)/;
+ my $maintainer = defined $pkgdata{main}{packager} ? $pkgdata{main}{packager} : expandmacros('%{_deb_maintainer}');
my $control = "Package: $pkgdata{$pkg}{name}\n".
- 'Version: '.format_version($pkg)."\n".
- ( defined $pkgdata{$pkg}{group} ?
- "Section: $pkgdata{$pkg}{group}\n" : '' ).
- "Priority: optional\n".
- "Architecture: $pkgdata{$pkg}{arch}\n".
- "Installed-Size: $installedsize\n".
- ( defined $pkgdata{main}{packager} ?
- "Maintainer: $pkgdata{main}{packager}\n" : '' ).
- "Description: $pkgdata{$pkg}{summary}\n$pkgdata{$pkg}{description}\n".
- ( defined $pkgdata{main}{url} ?
- "Homepage: $pkgdata{main}{url}\n" : '' );
+ 'Version: '.format_version($pkg)."\n".
+ ( defined $pkgdata{$pkg}{group} ?
+ "Section: $pkgdata{$pkg}{group}\n" : '' ).
+ "Priority: optional\n".
+ "Architecture: $pkgdata{$pkg}{arch}\n".
+ "Installed-Size: $installedsize\n".
+ ( $maintainer ?
+ "Maintainer: $maintainer\n" : '' ).
+ "Description: $pkgdata{$pkg}{summary}\n$pkgdata{$pkg}{description}\n".
+ ( defined $pkgdata{main}{url} ?
+ "Homepage: $pkgdata{main}{url}\n" : '' );
foreach my $deplist (qw(recommends suggests enhances breaks replaces
requires conflicts provides pre-depends)) {
if (defined $pkgdata{$pkg}{$deplist} and @{$pkgdata{$pkg}{$deplist}}) {
@@ -1455,6 +1624,8 @@ sub binpackage {
$control .= "\u$tag: ".join(',', do {
my %seen; grep { !$seen{$_}++ } # uniq
map { my ($name,$rel,$ver) = splitver($_);
+ $name = lc($name);
+ $name =~ tr/_/-/;
# magic needed to properly version dependencies...
$ver eq '0' ? $name : "$name ($rel $ver)" }
@{$pkgdata{$pkg}{$deplist}} })."\n";
@@ -1470,13 +1641,13 @@ sub binpackage {
if ($pkgdata{$pkg}{conffiles}) {
open CONFLIST, ">$specglobals{buildroot}/$pkg/DEBIAN/conffiles" or die;
foreach my $conffile (@{$pkgdata{$pkg}{conflist}}) {
- $conffile = expandmacros($conffile);
- foreach (glob "$specglobals{buildroot}/$pkg/$conffile") {
- (my $buildroot = $specglobals{buildroot}) =~ s/([+])/\\$1/g;
- s|$buildroot/$pkg/||g; # nrgl. gotta be a better way to do this...
- s/\s+/\n/g; # Not gonna support spaces in filenames. Ewww.
- print CONFLIST "$_\n";
- }
+ $conffile = expandmacros($conffile);
+ foreach (glob "$specglobals{buildroot}/$pkg/$conffile") {
+ (my $buildroot = $specglobals{buildroot}) =~ s/([+])/\\$1/g;
+ s|$buildroot/$pkg/||g; # nrgl. gotta be a better way to do this...
+ s/\s+/\n/g; # Not gonna support spaces in filenames. Ewww.
+ print CONFLIST "$_\n";
+ }
}
close CONFLIST;
}
@@ -1485,8 +1656,23 @@ sub binpackage {
foreach my $scr (qw(pre post preun postun)) {
my $scrfile = $scr;
$scrfile .= 'inst' unless $scrfile =~ s/un/rm/;
- if ($pkgdata{$pkg}{$scr}) {
- (my $content = expandmacros($pkgdata{$pkg}{$scr})) =~ s/^[\s]*$//mg;
+ if ($pkgdata{$pkg}{$scr} || (($scr eq 'pre') && defined($pkgdata{$pkg}{pretrans})) ||
+ (($scr eq 'post') && defined($pkgdata{$pkg}{posttrans}))) {
+ my $content = defined($pkgdata{$pkg}{$scr}) ? expandmacros($pkgdata{$pkg}{$scr}) : '';
+ if ($scr eq 'pre' and defined($pkgdata{$pkg}{pretrans})) {
+ $content = expandmacros($pkgdata{$pkg}{pretrans})."\n".$content;
+ warn _('Warning: \'').'pretrans'.
+ _("' is not natively supported by .deb packages.\n").
+ _("Merging with 'pre' script.\n");
+ }
+ if ($scr eq 'post' and defined($pkgdata{$pkg}{posttrans})) {
+ $content .= "\n".expandmacros($pkgdata{$pkg}{posttrans});
+ warn _('Warning: \'').'posttrans'.
+ _("' is not natively supported by .deb packages.\n").
+ _("Merging with 'post' script.\n");
+ }
+ $content =~ s/^[\s]*$//mg;
+ $content = $fmo.($content ? $content : '') if $scr eq 'post' and $fmo ne '';
next unless $content;
# glob all %files lines if necessary
@@ -1517,7 +1703,7 @@ sub binpackage {
execute_script('pkg', 'package-creation', _(' for ').$pkgdata{$pkg}{name});
$finalmessages .= _('Wrote binary package ').format_debfile($pkg).
- _(' in ')."%{_debdir}/$pkgdata{$pkg}{arch}\n";
+ _(' in ')."%{_debdir}/$pkgdata{$pkg}{arch}\n";
if ($cmdopts{sign}) {
$script{pkg} = "%{__fakeroot} -- %{__dpkg_sig} ".
@@ -1527,7 +1713,7 @@ sub binpackage {
execute_script('pkg', 'package-signature', _(' for ').$pkgdata{$pkg}{name});
$finalmessages .= _('Signed binary package ').format_debfile($pkg).
- _(' in ')."%{_debdir}/$pkgdata{$pkg}{arch}\n";
+ _(' in ')."%{_debdir}/$pkgdata{$pkg}{arch}\n";
}
} # subpackage loop
@@ -1574,8 +1760,24 @@ sub splitver {
$req .= $ver if $ver;
}
# Pick up the details of versioned build requirements
- my ($pkg,$rel,$ver) = $req =~ /([\w.+-]+)\s*([><=]+)\s*([\w:.~+-]+)/;
+ my ($pkg,$rel,$ver) = $req =~ /([\w.+\-()]+)\s*([><=]+)\s*([\w:.~+-]+)/;
+ $pkg =~ s/\(([^\)]+)\)/-$1/g;
$rel =~ s/^([><])$/$1$1/;
+
+ # We need this workaround as _ is forbidden in the package name
+ # and probably was changed to - on building such packages.
+ $pkg =~ tr/_/-/;
+
+ # Fix strict version checking by including release and epoch in case of specifying the packages currently building
+ if ( $rel eq '=' ) {
+ foreach my $p ( keys(%pkgdata) ) {
+ if ( $ver eq $pkgdata{main}{version} ) {
+ $ver = (defined $pkgdata{main}{epoch} ? "$pkgdata{main}{epoch}:" : '').$ver."-".$pkgdata{main}{release};
+ last;
+ }
+ }
+ }
+
return ($pkg,$rel,$ver);
} # end splitver()
@@ -1716,17 +1918,10 @@ sub getreqs {
my @reqlist;
my $pid = open2(\*IN,\*OUT,"LANG=C $specglobals{__xargs} $specglobals{__ldd}");
- my $thread = async {
- close IN;
- print OUT join ' ', @binlist;
- close OUT;
- };
- {
- close OUT;
- @reqlist = grep { not m|^/| } <IN>;
- close IN;
- }
- $thread->join();
+ print OUT join ' ', @binlist;
+ close OUT;
+ @reqlist = grep { not m|^/| } <IN>;
+ close IN;
waitpid($pid,0);
# Get the list of libs provided by this package. Still doesn't
@@ -1736,6 +1931,7 @@ sub getreqs {
my $reqliblist;
foreach (@reqlist) {
next if /not a dynamic executable/;
+ next if /statically linked/;
next if m|/lib(?:64)?/ld-linux|; # Hack! Hack! PTHBTT! (libc suxx0rz)
next if /linux-(gate|vdso).so/; # Kernel hackery for teh W1n!!1!1eleventy-one!1 (Don't ask. Feh.)
@@ -1747,8 +1943,8 @@ sub getreqs {
}
my ($req) = m|=\>\s+([\w./+-]+)|; # dig out the actual library (so)name.
- # And feh, we need the *path*, since I've discovered a new edge case where
- # the same libnnn.1.2.3 *file*name is found across *several* lib dirs. >:(
+ # And feh, we need the *path*, since I've discovered a new edge case where
+ # the same libnnn.1.2.3 *file*name is found across *several* lib dirs. >:(
# Ignore libs provided by this package. Note that we don't match
# on word-boundary at the *end* of the lib we're looking for, as the
@@ -1784,13 +1980,10 @@ sub install_sdeb {
# Helper function for writing to the %macro storage(s)
sub store_value {
my ($caller, $key, $value) = @_;
- # Handle multiline macro definitions
- if ($value =~ s/\\$/\\\n/) {
- while (<$fh>) {
- $value .= $_;
- last unless /\\$/;
- }
- }
+
+ $debug_level = $value if $key eq "_debbuild_debug_level";
+ vdebug("$caller: $key = $value", 5, "store_value");
+
# Strip and store '%macro(options)'
$macroopts{$key} = $1 if $key =~ s/\((.*)\)//;
my $recipient = ( grep { lc $key eq $_ } qw(summary name version
@@ -1812,181 +2005,521 @@ sub store_value {
## expandmacros()
# Expands all %{blah} macros in the passed string
sub expandmacros {
- local $_ = shift;
- return $_ unless /%/; # nothing to substitute
-
- # support for **some** %if constructs: handle '%{?conditional:macros}'
- # with nested curly braces, all in one go!
- while (my ($qex,$macro,$value) = map { /{([?!]+)(\w+)(?::(.+))?}/ }
- bracelet() ) {
- (my $initvalue = "%{$qex$macro".(defined $value ? ":$value" : '').'}')
- =~ s/([?!{*}(+)])/\\$1/g; # neutralize quantifiers
- $value //= ($specglobals{$macro} or '');
- $value = '' unless $specglobals{$macro} xor $qex =~ /!/; # equivalence
- $value = '' if $macro eq 'verbose' and defined $specglobals{$macro}; # shut up!
- s/$initvalue/expandmacros($value)/eg;
- }
- pos = 0; # reset to start of $_
-
- # Process %define's and Conditional Build Stuff
- s/%(bcond_with(?:out)?)\s+(\S+)/%{$1 $2}/g;
- # Store %globals (from '%bcond_with[out]()' in 'macros[.in]')
- s/%(define|global)\s+(\S+)\s+(.+)/store_value($1,$2,$3)/eg;
- die _('Missing value for \'%')."$1 $2".
- _('\'. Aborting!') if m/%(define|global)\s+(.+)/;
- # Permit unsetting/deleting of stored values
- { no warnings; s/%(undefine)\s+(\S+)/store_value($1,$2)/eg; }
- # Print the active macro table
- s/^\s*%dump/dump_macros()/e;
- # Is debbuild in verbose mode?
- s/%verbose/defined $specglobals{verbose} ? $specglobals{verbose} : ''/eg;
-
- # Replace global macros
- while (m/%(\w+)/g) {
- my $macro = $1;
- s/%$macro(\W|$)/%{$macro}$1/g if grep { $macro eq $_ }
- qw(optflags getconfdir sources patches)
- or defined $specglobals{$macro}
- or defined $pkgdata{main}{$macro};
- }
- s/%\{optflags}/$optflags{$pkgdata{main}{arch}}/g if $pkgdata{main}{arch};
- s|%\{getconfdir}|$specglobals{_prefix}/lib/debbuild|g;
- s|%\{sources}|expandmacros( join ' ', sources() )|eg;
- s|%\{patches}|expandmacros( join ' ', patches() )|eg;
-
- # Package data
- s|%\{source}|%{_sourcedir}/$pkgdata{main}{source}|gi;
- foreach my $source (keys %{$pkgdata{sources}}) {
- s/%\{S:$source}/%{source$source}/g;
- s|%\{source$source}|%{_sourcedir}/$pkgdata{sources}{$source}|gi;
- }
- s/%\{P:(\d+)}/%{patch$1}/g;
- s|%\{(patch\d*)}|%{_sourcedir}/$pkgdata{main}{$1}|gi;
-
- # Globals, and not-so-globals
- # special %define's. Handle the general case where we eval anything.
- # Even more general: %(...) is a spec-parse-time shell code wrapper.
- # Prime example from 'macros.perl':
- # %define perl_vendorlib %(eval "`perl -V:installvendorlib`"; echo $installvendorlib)
- # Oy vey this gets silly for the perl bits. Executing a shell to
- # call Perl to get the vendorlib/sitelib/whatever "core" globals.
- # This can do more, but... eww.
- s/%\((.+)\)/my $in = expandmacros($1); chomp(my $res = qx($in)); $res/eg;
- # Yay! ' characters apparently get properly exscapededed.
-
- # handle '%{parametrized macros}' with nested curly braces, all in one go!
- while (my ($prefix,$spc,$arg) = map { /{(\w+)(\s+)(.+)}/ } bracelet() ) {
- (my $initvalue = "%{$prefix$spc$arg}") =~ s/([{+}])/\\$1/g; # neutralize curlies
- s/$initvalue/handle_macro_options("%$prefix $arg")/eg;
- }
- pos = 0; # reset to start of $_
-
- # handle '%{prefixed:macros}' with nested curly braces, all in one go!
- s/url2path/u2p/g;
- while (my ($prefix,$arg) = map { /{(\w+):(.+)}/ } bracelet() ) {
- (my $initvalue = "%{$prefix:$arg}") =~ s/([?!{+}])/\\$1/g; # neutralize specials
- $arg = expandmacros($arg);
- if ($prefix eq 'u2p') {
- # curious form of 'basename'? - strip domain host (and port)
- $arg =~ s|\w+://[\w.:-]+||;
- s/$initvalue/$arg/g;
- } elsif (grep {$prefix eq $_} qw(basename dirname uncompress)) {
- no strict qw(refs); # we use strings as function refs
- s/$initvalue/&$prefix($arg)/eg;
- } elsif ($prefix eq 'suffix') {
- my (undef,undef,$suffix) = fileparse($arg,qr/\.[^.]*/);
- s/$initvalue/$suffix/g;
- } elsif ($prefix eq 'getenv') {
- # support '%{getenv:HOME}' alongside '%(echo $HOME)'.
- s/$initvalue/$ENV{$arg}/g;
- } elsif (grep { $prefix eq $_ } qw(expand quote)) {
- # helper for parametrized macros and quoted macro arguments
- s/$initvalue/$arg/g;
- } elsif ($prefix eq 'shrink') {
- # trim leading, trailing, and intermediate whitespace
- $arg =~ s/^\s+|\s+//g; $arg =~ s/\s+/ /g;
- s/$initvalue/$arg/g;
- } elsif ($prefix eq 'verbose') {
- # 'positive verbosity'
- defined $specglobals{$prefix} ? s/$initvalue/$arg/g : s/$initvalue//g;
+ my $s = shift;
+ my $r = '';
+ my $orig = $s;
+ vdebug($s, 1, "expandmacros/input");
+ return '' unless defined($s);
+ sub expd_tocomplex {
+ my ($macro, $params) = @_;
+ return "%$macro $params" if $macro =~ /\A(description|dir|doc|exclude|ghost|package|if(?:n?arch|)|else|endif|post(?:un)?|pre(?:un)?)\z/
+ or not defined($macroopts{$macro});
+ return "%{$macro $params}";
+ }
+ $s =~ s/(?:\A|\R)\s*?%(define|undefine|global)\s+(\S+)\s+(.*)/store_value($1,$2,$3);''/eg;
+ $s =~ s/(\A|\R[ \t]*)%([a-zA-Z_]\w+)[ \t]+(.*)/$1.expd_tocomplex($2, $3)/eg;
+ my $l = length $s;
+ sub expd_simple {
+ my $m = shift;
+ my $o = $m;
+ my $macroparms = {'#' => 0};
+ foreach my $ms ( @macropsstk ) {
+ $macroparms = $ms;
+ last if $macroparms->{'#'};
}
+ if ( $m =~ /\A(\d+|#|\*{1,2})\z/ ) {
+ $m = defined($macroparms->{$1}) ? $macroparms->{$1} : '';
+ } elsif ( $m eq 'dump' ) {
+ $m = dump_macros();
+ } elsif ( $m eq 'optflags' ) {
+ $m = ($pkgdata{main}{arch} and $optflags{$pkgdata{main}{arch}}) ?
+ $optflags{$pkgdata{main}{arch}} : '';
+ } elsif ( $m eq 'getconfdir' ) {
+ $m = $specglobals{_prefix}."/lib/debbuild";
+ } elsif ( $m eq 'sources' ) {
+ $m = join ' ', sources();
+ } elsif ( $m eq 'patches' ) {
+ $m = join ' ', sources();
+ } elsif ( $m eq 'source' ) {
+ $m = "%{_sourcedir}/".$pkgdata{main}{source};
+ } elsif ( $m =~ /^source(\d+)/i ) {
+ $m = defined($pkgdata{sources}{$1}) ? "%{_sourcedir}/".$pkgdata{sources}{$1} : '';
+ } elsif ( $m =~ /^(patch\d+)/i ) {
+ $m = defined($pkgdata{main}{$1}) ? "%{_sourcedir}/".$pkgdata{main}{$1} : '';
+ } elsif ( defined($specglobals{$m}) ) {
+ my $macro = $m;
+ $m = $specglobals{$m};
+ if ( $m =~ /\A%\{lua:/ ) {
+ my $tst = $m;
+ $tst =~ s/\A%//;
+ if ( defined(extract_bracketed($tst, '{}')) ) {
+ $m =~ s/\A%\{lua:\s+//;
+ $m =~ s/\}\s*\z//;
+ my %macroparms = ();
+ $macroparms{0} = $macro;
+ $macroparms{'#'} = 0;
+ $macroparms{'**'} = $macroparms{'*'} = '';
+ unshift @macropsstk, \%macroparms;
+ $m = lua_macro($m);
+ shift @macropsstk;
+ }
+ }
+ } elsif ( defined($pkgdata{main}{$m}) ) {
+ $m = $pkgdata{main}{$m};
+ } else {
+ $m = '';
+ }
+ vdebug($o, 5, "expandmacros/simple/in");
+ my $i = scalar @macropsstk;
+ vdebug("Parameterized macro stack: [".($i)."]", 7, "expandmacros/simple/stack");
+ foreach my $ms ( @macropsstk ) {
+ vdebug("[$i] ".$ms->{'0'}." / ".$ms->{'#'}.": ".$ms->{'**'}, 7, "expandmacros/simple/stack");
+ $i--;
+ }
+ vdebug($m, 5, "expandmacros/simple/out");
+ return $m eq $o ? $m : expandmacros($m);
}
- pos = 0; # reset to start of $_
-
- # Expand 'simple' '%{macros}': %define's and %{all_the_rest}
- while (/%\{([a-z_]\w*)}/ig) {
- my $key = $1;
- if (defined $specglobals{$key}) {
- s/%\{$key}/expandmacros($specglobals{$key})/eg;
- } elsif (defined $pkgdata{main}{$key}) {
- s/%\{$key}/expandmacros($pkgdata{main}{$key})/eg;
+ sub expd_complex {
+ my $m = shift;
+ my $o = $m;
+ my ($qex, $macro, $value);
+ my $macroparms = {'#' => 0};
+ foreach my $ms ( @macropsstk ) {
+ $macroparms = $ms;
+ last if $macroparms->{'#'};
+ }
+ if ( ($macro,$qex) = $m =~ /\A\{\??(\d+|#|\*{1,2}|\-\w)(\*?)\}\z/ ) {
+ $m = defined($macroparms->{$macro}) ? (($macro =~ /\A\-/ and $qex ne '*') ? $macro : $macroparms->{$macro}) : '';
+ } elsif ( ($qex,$macro,$value) = $m =~ /\A\{([?!]*)(\d+|#|\*{1,2}|\-\w\*?)(?::(.+))\}\z/ ) {
+ $value //= (defined($macroparms->{$macro}) ? $macroparms->{$macro} : '');
+ $value = '' unless defined($macroparms->{$macro}) xor $qex =~ /!/; # equivalence
+ $m = $value;
+ } elsif ( ($qex,$macro,$value) = $m =~ /\A\{([?!]+)(\w+)(?::(.+))?\}\z/m ) {
+ $value //= ($specglobals{$macro} or '');
+ $value = '' unless $specglobals{$macro} xor $qex =~ /!/; # equivalence
+ $value = '' if $macro eq 'verbose' and defined $specglobals{$macro}; # shut up!
+ $m = expandmacros($value);
+ } elsif ( my ($prefix,$arg) = $m =~ /\A\{(\w+):(.*)\}\z/s ) {
+ if ( $prefix eq 'lua' ) {
+ my %macroparms = ();
+ $macroparms{0} = '_ANONYMOUS_MACRO_';
+ $macroparms{'#'} = 0;
+ $macroparms{'**'} = $macroparms{'*'} = '';
+ unshift @macropsstk, \%macroparms;
+ $m = lua_macro($arg);
+ shift @macropsstk;
+ } elsif ( $prefix eq 'url2path' or $prefix eq 'u2p' ) {
+ $arg = expandmacros($arg);
+ $arg =~ s|\w+://[\w.:-]+||;
+ $m = $arg;
+ } elsif (grep {$prefix eq $_} qw(basename dirname uncompress)) {
+ no strict qw(refs); # we use strings as function refs
+ $m = &$prefix($arg);
+ } elsif ($prefix eq 'suffix') {
+ my (undef,undef,$suffix) = fileparse($arg,qr/\.[^.]*/);
+ $m = $suffix;
+ } elsif ($prefix eq 'getenv') {
+ # support '%{getenv:HOME}' alongside '%(echo $HOME)'.
+ $m = defined($ENV{$arg}) ? $ENV{$arg} : '';
+ } elsif (grep { $prefix eq $_ } qw(expand quote)) {
+ # helper for parametrized macros and quoted macro arguments
+ $m = expandmacros($arg);
+ } elsif ($prefix eq 'shrink') {
+ # trim leading, trailing, and intermediate whitespace
+ $arg =~ s/^\s+|\s+//g; $arg =~ s/\s+/ /g;
+ $m = $arg;
+ } elsif ($prefix eq 'verbose') {
+ # 'positive verbosity'
+ $m = defined $specglobals{$prefix} ? $arg : '';
+ } elsif ($prefix eq 'S') {
+ $m = expd_simple('source'.$arg);
+ } elsif ($prefix eq 'P') {
+ $m = expd_simple('patch'.$arg);
+ }
+ } elsif ( my ($macra,$spc,$args) = $m =~ /\A\{(\w+)(\s+)(.+)\}\z/s ) {
+ $m = expandmacros(handle_macro_options("%$macra $args"));
+ } elsif ( my ($smpl) = $m =~ /\A\{\$?([a-z_]\w*)\s*\}\z/i ) {
+ $m = expd_simple($smpl);
}
+ vdebug($o, 5, "expandmacros/complex/in");
+ my $i = scalar @macropsstk;
+ vdebug("Parameterized macro stack: [".($i)."]", 7, "expandmacros/complex/stack");
+ foreach my $ms ( @macropsstk ) {
+ vdebug("[$i] ".$ms->{'0'}." / ".$ms->{'#'}.": ".$ms->{'**'}, 7, "expandmacros/complex/stack");
+ $i--;
+ }
+ vdebug($m, 5, "expandmacros/complex/out");
+ return $m eq $o ? $m : expandmacros($m);
}
- pos = 0; # reset to start of $_
-
- # unescape multi-line macros
- s/\\"/"/g;
- s/\\\\(\w)/\\$1/g;
- s/(\S)\\+\n/$1\n/g;
- # revert changes of dir macro because of spcial use in %files
- s/%\{dir\}/%dir/g;
- return $_;
+ sub expd_exec {
+ my ($c) = @_;
+ my $r = '';
+ $c =~ s/\\\$/\$/g;
+ $c =~ s/\\\\n/\\n/g;
+ open(my $ch, '-|', $build_shell, '-c', $c) or return $r;
+ while ( <$ch> ) {
+ $r .= $_;
+ }
+ close($ch);
+ chomp($r);
+ return $r;
+ }
+ while ( $l ) {
+ if ( $s =~ /%+/ ) {
+ $r .= $`;
+ $s = $';
+ my $qs = $&;
+ my $ql = length $qs;
+ $l -= length($`) + $ql;
+ $r .= '%' x ($ql-1);
+ next if $ql > 1;
+ if ( $s =~ /\A[\w\*\#]+/ ) {
+ my $m = $&;
+ $s = $';
+ $l -= length $m;
+ if ( $m =~ /\A(description|dir|doc|exclude|ghost|package|if(?:n?arch|)|else|endif|post(?:un)?|pre(?:un)?)\z/ ) {
+ $r .= "%".$m;
+ } else {
+ $r .= expd_simple($m);
+ }
+ } elsif ( $s =~ /\A\{/ ) {
+ my $m = '{';
+ $s = $';
+ my $tr;
+ do {
+ if ( $s =~ /\}/ ) {
+ $m .= $`.$&;
+ $s = $';
+ my $tst = $m;
+ $tr = defined(extract_bracketed($tst, '{}'));
+ if ( $tr ) {
+ $r .= expd_complex($m);
+ $l -= length $m;
+ }
+ } else {
+ $r .= '%'.$m;
+ $l -= length $m;
+ $tr = 1;
+ }
+ } until $tr;
+ } elsif ( $s =~ /\A\(/ ) {
+ my $m = '(';
+ $s = $';
+ my $tr;
+ do {
+ if ( $s =~ /\)/ ) {
+ $m .= $`.$&;
+ $s = $';
+ my $tst = $m;
+ $tr = defined(extract_bracketed($tst, '()'));
+ if ( $tr ) {
+ $m =~ s/\A\(//;
+ $m =~ s/\)\z//;
+ $r .= expd_exec(expandmacros($m));
+ $l -= length $m;
+ }
+ } else {
+ $r .= '%'.$m;
+ $l -= length $m;
+ $tr = 1;
+ }
+ } until $tr;
+ } else {
+ $r .= '%';
+ }
+ } else {
+ $r .= $s;
+ $l = 0;
+ $s = '';
+ }
+ }
+ vdebug($orig, 5, "expandmacros/in");
+ vdebug($r, 5, "expandmacros/out");
+ return $r;
} # end expandmacros()
-## bracelet()
-# Shortcut for extracting paired curly braces
-sub bracelet {
- return extract_multiple($_, [ sub { extract_bracketed($_[0],'{}') } ]);
-} # end bracelet()
-
-
## handle_macro_options()
# Option handling for '%macro(ino:pts)'.
# Note that 'getopts()' normally works on '@ARGV', so we have to pull some
# tricks to make it work with 'string input'.
sub handle_macro_options {
my $inline = shift;
- my ($macro,$argv) = $inline =~ /%(\w+)(?:\s+(.+))?/;
+ my ($macro,$argv) = $inline =~ /%(\w+)(?:\s+(.+))?/s;
+ if ( not defined($macroopts{$macro}) ) {
+ return expandmacros("%{$macro} $argv");
+ }
+ $argv = expandmacros($argv);
+ vdebug("$macro | $argv / $inline", 5, "handle_macro_options/in");
+ if ( $macro eq 'if' ) {
+ chomp( my $expr = expandmacros($argv) );
+ if ($expr =~ /^[\d\s<=>&|\(\)+-]+$/) {
+ # "plain" numeric expressions are evaluated as-is, except
+ $expr =~ s/(\D)0(\d+)/$1$2/g; # shortcut 0%{?ubuntu} == 1204
+ } else {
+ # Done in this order so we don't cascade incorrectly.
+ # Yes, those spaces ARE correct in the replacements!
+ $expr =~ s/==/ eq /g;
+ $expr =~ s/!=/ ne /g;
+ $expr =~ s/<=>/ cmp /g;
+ $expr =~ s/<=/ le /g;
+ $expr =~ s/>=/ ge /g;
+ $expr =~ s/</ lt /g;
+ $expr =~ s/>/ gt /g;
+ }
+ return (eval $expr or 0);
+ }
local @ARGV = split ' ',$argv if $argv;
- my %options; # store result of 'getopts()'
- my @nonoptions; # store all 'other' arguments
+ my $argc = scalar @ARGV;
+ my %options = (); # store result of 'getopts()'
+ my @nonoptions = (); # store all 'other' arguments
while (@ARGV) { # separate options and non-options
push @nonoptions, shift @ARGV while @ARGV and $ARGV[0] !~ m/^-/;
+ my $ac = scalar @ARGV;
getopts($macroopts{$macro},\%options) if $macroopts{$macro};
+ push @nonoptions, shift @ARGV if $ac and $ac == scalar @ARGV;
}
- local $_ = $specglobals{$macro};
- while (my ($qex,$arg,$value) = map { /{([?!]+)(\d+)(?::(.+))?}/ }
- bracelet() ) { # handle '%{?2:%{2}}' et al.
- (my $initvalue = "%{$qex$arg".(defined $value ? ":$value" : '').'}')
- =~ s/([?!{+}])/\\$1/g; # neutralisation
- $value //= "%{$arg}";
- $value = '' unless defined $nonoptions[$arg-1] xor $qex =~ /!/; # equivalence
- s/$initvalue/$value/g;
- }
- pos = 0; # reset to start of $_
- while (my ($option,$repl) = map { /{-(\w):\s*(\S+)}/ } bracelet() ) {
- (my $result = $options{$option} ? $repl : '') =~ s/%\{-(\w)\*}/$options{$1}/g;
- $repl =~ s/([*{}])/\\$1/g; # mask Perlish special characters
- s/%\{-$option:\s*$repl}/$result/g;
- }
- pos = 0; # reset to start of $_
- while (my ($option) = map { /{-(\w)(?:\*)?}/ } bracelet() ) {
- my $result = $options{$option} ? "-$option" : '';
- s/%\{-$option}/$result/g;
- s/%\{-($option)\*}/$options{$1}/g;
- }
- s/%%/%/g; # reduce level of macronization
- s/\s+\\+\n/\n/g; # prepare for multi-line shipment
- s/%\{?0\}?/$macro/g; # the name of the macro invoked
- s/%\{\?\*\}/join(' ',@nonoptions)/eg; # replace 'all arguments'
+ my %macroparms = ();
+ $macroparms{0} = $macro;
for my $i (1..@nonoptions) { # fill '%{i}' parameters
- s/%\{?$i\}?/$nonoptions[$i-1]/g;
+ $macroparms{$i} = $nonoptions[$i-1];
}
- return $_;
+ $macroparms{'**'} = $argv;
+ $macroparms{'*'} = join(' ', @nonoptions);
+ $macroparms{'#'} = $argc;
+ foreach my $f ( keys %options ) {
+ vdebug("$f = ".$options{$f}, 5, "handle_macro_options/flag");
+ $macroparms{'-'.$f} = $options{$f};
+ }
+ unshift @macropsstk, \%macroparms;
+ vdebug($macro.": ".$argv, 5, "handle_macro_options/expanding/".(scalar @macropsstk));
+ my $m = $specglobals{$macro};
+ if ( $m =~ /\A%\{lua:/ ) {
+ my $tst = $m;
+ $tst =~ s/\A%//;
+ if ( defined(extract_bracketed($tst, '{}')) ) {
+ $m =~ s/\A%\{lua:\s+//;
+ $m =~ s/\}\s*\z//;
+ $m = lua_macro($m);
+ } else {
+ $m = expandmacros($m);
+ }
+ } else {
+ $m = expandmacros($m);
+ }
+ shift @macropsstk;
+ vdebug($m, 5, "handle_macro_options/ret");
+ return $m;
} # end handle_macro_options()
+sub lua_get {
+ my ($v, $d) = @_;
+ my $r;
+ eval('$r = '.$v);
+ return defined($r) ? $r : $d;
+}
+
+
+sub lua_traceback {
+ my ($L) = @_;
+ return 1
+ if (! $L->isstring(1)); # 'message' not a string? keep it intact
+ $L->getfield(lua_get('Lua::API::GLOBALSINDEX'), "debug");
+ if (! $L->istable(-1)) {
+ $L->pop(1);
+ return 1;
+ }
+ $L->getfield(-1, "traceback");
+ if (! $L->isfunction(-1)) {
+ $L->pop(2);
+ return 1;
+ }
+ $L->pushvalue(1); # pass error message
+ $L->pushinteger(2); # skip this function and traceback
+ $L->call(2, 1); # call debug.traceback
+ return 1;
+}
+
+
+sub lua_print {
+ my ($L) = @_;
+ my $n = $L->gettop();
+ my $dbg = 'UNDEF';
+ if ( @macropsstk and $debug_level >= 7 ) {
+ $dbg = $macropsstk[0]->{0};
+ }
+ for ( my $i = 1; $i <= $n; $i++ ) {
+ my $p = $L->tostring($i);
+ vdebug($p, 7, "lua_print/$n/$i/$dbg/$lstk[0]");
+ $lstk[0]->{stdout} .= ($i >1 ? "\t" : "").$p;
+ }
+}
+
+
+sub lua_vdebug {
+ my ($L) = @_;
+ my $n = $L->gettop();
+ if ( $n >= 3 ) {
+ my $msg = $L->tostring(1);
+ my $vbl = $L->tointeger(2);
+ my $tag = $L->tostring(3);
+ vdebug($msg, $vbl, "lua/".$tag);
+ } else {
+ vdebug("Not enough parameters", 3, "lua/vdebug");
+ }
+}
+
+
+sub lua_rpm_expand {
+ my ($L) = @_;
+ my $p = $L->checkstring(1);
+ my $r = expandmacros($p);
+ $r =~ s/\\n/\n/g;
+ $r =~ s/\n /\n/g;
+ $L->pushstring($r);
+ vdebug($p, 4, "lua_rpm_expand/in");
+ vdebug($r, 4, "lua_rpm_expand/out");
+ return 1;
+}
+
+
+sub lua_rpm_define {
+ my ($L) = @_;
+ my $p = $L->tostring(1);
+ vdebug($p, 4, "lua_rpm_define");
+ if ( my ($macro,$eq,$value) = $p =~ /^(\w+(?:\([^)]*\))?)(=|\s*)(.+)$/ ) {
+ store_value('define', $macro, $value);
+ }
+ return 0;
+}
+
+
+sub lua_posix_getcwd {
+ my ($L) = @_;
+ my $r = getcwd();
+ $L->pushstring($r);
+ vdebug($r, 4, "lua_posix_getcwd");
+ return 1;
+}
+
+
+sub lua_posix_stat {
+ my ($L) = @_;
+ my $n = $L->gettop();
+ if ( $n < 2 ) {
+ $L->pushnil();
+ return 1;
+ }
+ my $f = $L->tostring(1);
+ my $p = $L->tostring(2);
+ my %c = (
+ 'dev' => 0, 'ino' => 1, 'mode' => 2,
+ 'nlink' => 3, 'uid' => 4, 'gid' => 5,
+ 'rdev' => 6, 'size' => 7, 'atime' => 8,
+ 'mtime' => 9, 'ctime' => 10, 'blksize' => 11,
+ 'blocks' => 12
+ );
+ my @r = stat($f);
+ if ( not @r ) {
+ vdebug("$f / $p => FILE NOT FOUND", 4, "lua_posix_stat");
+ $L->pushnil();
+ return 1;
+ }
+ my $r = defined($c{$p}) ? $r[$c{$p}] : undef;
+ vdebug("$f / $p => @r ($p: ".(defined($r) ? $r : "UNKNOWN").")", 4, "lua_posix_stat");
+ if ( not defined($r) ) {
+ $L->pushnil();
+ return 1;
+ }
+ $L->pushinteger($r);
+ return 1;
+}
+
+
+sub lua_pmain {
+ my ($L) = @_;
+ my $m = $lstk[0]->{m};
+ my $st = $L->loadstring($m);
+ if ( $st == 0 ) {
+ my $base = $L->gettop(); # function index
+ $L->pushcfunction(\&lua_traceback); # push traceback function
+ $L->insert($base); # put it under chunk and args
+ $st = $L->pcall(0, 0, $base);
+ $L->remove($base); # remove traceback function
+ }
+ if ($st && !$L->isnil(-1)) {
+ my $msg = $L->tostring(-1);
+ $msg = "(error object is not a string)" if ! defined $msg;
+ print(STDERR "Lua Error: ".$msg."\n");
+ $lstk[0]->{error} = 1;
+ $L->pop(1);
+ }
+ return 0;
+}
+
+
+sub lua_init {
+ my $lsh = lua_get('Lua::API::State->new()');
+ if ( $lsh ) {
+ my $L = $lsh->open(); # create state
+ if (! defined $L ) {
+ vdebug("Lua Error: Cannot create state: not enough memory!", 3, "lua_init");
+ print(STDERR "Lua Error: Cannot create state: not enough memory!\n");
+ return;
+ }
+ $L->openlibs;
+ $L->register("print", \&lua_print);
+ $L->register("vdebug", \&lua_vdebug);
+ my %rpm_lib = ('expand' => \&lua_rpm_expand,
+ 'define' => \&lua_rpm_define);
+ $L->register("rpm", \%rpm_lib);
+ my %posix_lib = ('getcwd' => \&lua_posix_getcwd,
+ 'stat' => \&lua_posix_stat);
+ $L->register("posix", \%posix_lib);
+ return $L;
+ } else {
+ vdebug("Lua Error: Unable to open Lua::API::State!", 3, "lua_init");
+ print(STDERR "Lua Error: Unable to open Lua::API::State!\n");
+ }
+ return;
+}
+
+
+sub lua_macro {
+ my ($m) = @_;
+ unless ( $lua_present ) {
+ print(STDERR "WARNING: Lua module not loaded! The following macro is omitted:\n".
+ $m."\n# end of the ommited macro\n");
+ return '';
+ }
+ unless ( defined($gL) ) {
+ $gL = lua_init();
+ }
+ return '' unless defined($gL);
+ my $r = {m => $m, stdout => ''};
+ unshift @lstk, $r;
+ my $st = $gL->cpcall(\&lua_pmain, undef);
+ shift @lstk;
+ $r->{stdout} =~ s/\s+\z//s;
+ if ( $debug_level >= 7 ) {
+ vdebug($r->{stdout}, 7, "lua_print/out/$r");
+ vdebug("Lua macro (in):\n".$m."\n# end of the macro", 7, "lua_macro/in");
+ if ( @macropsstk ) {
+ my $i = scalar @macropsstk;
+ vdebug("Parameterized macro stack: [".($i)."]", 7, "lua_macro/stack");
+ foreach my $ms ( @macropsstk ) {
+ vdebug("[$i] ".$ms->{'0'}." / ".$ms->{'#'}.": ".$ms->{'**'}, 7, "lua_macro/stack");
+ $i--;
+ }
+ }
+ vdebug("Lua macro (out):\n".$r->{stdout}."\n# end of the macro out", 7, "lua_macro/out");
+ }
+ exit(16) if $r->{error};
+ return $r->{stdout};
+}
+
+
=pod
=encoding utf8
@@ -2007,6 +2540,8 @@ debbuild — Build Debian-compatible .deb packages from RPM .spec files
=item 2017-2019 © Datto, Inc. L<https://datto.com>
+=item 2020-2021 © Victor Zhestkov L<vzhestkov@suse.com>
+
=back
=head1 SHORT DESCRIPTION