2013-04-30 18:18:17 -04:00
|
|
|
#!/usr/bin/perl
|
2013-05-29 08:51:24 -04:00
|
|
|
# makepkg-template - template system for makepkg
|
|
|
|
# @configure_input@
|
|
|
|
#
|
2015-01-21 01:31:20 -05:00
|
|
|
# Copyright (c) 2013-2015 Pacman Development Team <pacman-dev@archlinux.org>
|
2013-05-29 08:51:24 -04:00
|
|
|
#
|
|
|
|
# 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
|
|
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#
|
2013-04-30 18:18:17 -04:00
|
|
|
use warnings;
|
|
|
|
use strict;
|
|
|
|
use v5.10.1;
|
|
|
|
use Cwd qw(abs_path);
|
|
|
|
use Getopt::Long;
|
2013-05-19 06:17:57 -04:00
|
|
|
use Module::Load;
|
|
|
|
use Module::Load::Conditional qw(can_load);
|
2013-04-30 18:18:17 -04:00
|
|
|
|
|
|
|
my %opts = (
|
|
|
|
input => '@BUILDSCRIPT@',
|
|
|
|
template_dir => '@TEMPLATE_DIR@',
|
|
|
|
);
|
|
|
|
|
|
|
|
my $template_name_charset = qr/[[:alnum:]+_.@-]/;
|
|
|
|
my $template_marker = qr/# template/;
|
|
|
|
|
2013-05-19 06:17:57 -04:00
|
|
|
# runtime loading to avoid dependency on cpan since this is the only non-core module
|
|
|
|
my $loaded_gettext = can_load(modules => {'Locale::gettext' => undef});
|
|
|
|
if ($loaded_gettext) {
|
|
|
|
Locale::gettext::bindtextdomain("pacman-scripts", '@localedir@');
|
|
|
|
Locale::gettext::textdomain("pacman-scripts");
|
|
|
|
}
|
|
|
|
|
|
|
|
sub gettext {
|
|
|
|
my ($string) = @_;
|
|
|
|
|
|
|
|
if ($loaded_gettext) {
|
|
|
|
return Locale::gettext::gettext($string);
|
|
|
|
} else {
|
|
|
|
return $string;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-30 18:18:17 -04:00
|
|
|
sub burp {
|
|
|
|
my ($file_name, @lines) = @_;
|
2013-05-19 06:17:57 -04:00
|
|
|
open (my $fh, ">", $file_name) || die sprintf(gettext("can't create '%s': %s"), $file_name, $!);
|
2013-04-30 18:18:17 -04:00
|
|
|
print $fh @lines;
|
|
|
|
close $fh;
|
|
|
|
}
|
|
|
|
|
|
|
|
# read a template marker line and parse values into a hash
|
|
|
|
# format is "# template (start|input); key=value; key2=value2; ..."
|
|
|
|
sub parse_template_line {
|
|
|
|
my ($line, $filename, $linenumber) = @_;
|
|
|
|
my %values;
|
|
|
|
|
|
|
|
my ($marker, @elements) = split(/;\s?/, $line);
|
|
|
|
|
|
|
|
($values{command}) = ($marker =~ /$template_marker (.*)/);
|
|
|
|
|
|
|
|
foreach my $element (@elements) {
|
|
|
|
my ($key, $val) = ($element =~ /^([a-z0-9]+)=(.*)$/);
|
2013-05-19 06:17:57 -04:00
|
|
|
unless ($key and $val) {
|
2014-12-21 10:04:59 -05:00
|
|
|
die gettext("invalid key/value pair\n"),
|
2013-05-19 06:17:57 -04:00
|
|
|
"$filename:$linenumber: $line";
|
|
|
|
}
|
2013-04-30 18:18:17 -04:00
|
|
|
$values{$key} = $val;
|
|
|
|
}
|
|
|
|
|
|
|
|
# end doesn't take arguments
|
|
|
|
if ($values{command} ne "end") {
|
|
|
|
if (!$values{name}) {
|
2013-05-19 06:17:57 -04:00
|
|
|
die gettext("invalid template line: can't find template name\n"),
|
2013-04-30 18:18:17 -04:00
|
|
|
"$filename:$linenumber: $line";
|
|
|
|
}
|
|
|
|
|
|
|
|
unless ($values{name} =~ /^$template_name_charset+$/) {
|
2013-05-19 06:17:57 -04:00
|
|
|
die sprintf(gettext("invalid chars used in name '%s'. allowed: [:alnum:]+_.\@-\n"), $values{name}),
|
2013-04-30 18:18:17 -04:00
|
|
|
"$filename:$linenumber: $line";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return \%values;
|
|
|
|
}
|
|
|
|
|
|
|
|
# load a template, process possibly existing markers (nested templates)
|
|
|
|
sub load_template {
|
|
|
|
my ($values) = @_;
|
|
|
|
|
|
|
|
my $ret = "";
|
|
|
|
|
|
|
|
my $path;
|
|
|
|
if (!$opts{newest} and $values->{version}) {
|
|
|
|
$path = "$opts{template_dir}/$values->{name}-$values->{version}.template";
|
|
|
|
} else {
|
|
|
|
$path = "$opts{template_dir}/$values->{name}.template";
|
|
|
|
}
|
|
|
|
|
|
|
|
# resolve symlink(s) and use the real file's name for version detection
|
|
|
|
my ($version) = (abs_path($path) =~ /-([0-9.]+)[.]template$/);
|
|
|
|
|
|
|
|
if (!$version) {
|
2014-12-28 09:56:53 -05:00
|
|
|
die sprintf(gettext("Couldn't detect version for template '%s'\n"), $values->{name});
|
2013-04-30 18:18:17 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
my $parsed = process_file($path);
|
|
|
|
|
|
|
|
$ret .= "# template start; name=$values->{name}; version=$version;\n";
|
|
|
|
$ret .= $parsed;
|
|
|
|
$ret .= "# template end;\n";
|
|
|
|
return $ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
# process input file and load templates for all markers found
|
|
|
|
sub process_file {
|
|
|
|
my ($filename) = @_;
|
|
|
|
|
|
|
|
my $ret = "";
|
|
|
|
my $nesting_level = 0;
|
|
|
|
my $linenumber = 0;
|
|
|
|
|
2014-12-28 09:56:53 -05:00
|
|
|
open (my $fh, "<", $filename) or die sprintf(gettext("failed to open '%s': %s\n"), $filename, $!);
|
2013-04-30 18:18:17 -04:00
|
|
|
my @lines = <$fh>;
|
|
|
|
close $fh;
|
|
|
|
|
|
|
|
foreach my $line (@lines) {
|
|
|
|
$linenumber++;
|
|
|
|
|
|
|
|
if ($line =~ $template_marker) {
|
|
|
|
my $values = parse_template_line($line, $filename, $linenumber);
|
|
|
|
|
2013-05-22 10:35:23 -04:00
|
|
|
if ($values->{command} eq "start" or $values->{command} eq "input") {
|
|
|
|
if ($nesting_level == 0) {
|
|
|
|
$ret .= load_template($values);
|
2013-04-30 18:18:17 -04:00
|
|
|
}
|
2013-05-22 10:35:23 -04:00
|
|
|
} elsif ($values->{command} eq "end") {
|
|
|
|
# nothing to do here, just for completeness
|
|
|
|
} else {
|
|
|
|
die sprintf(gettext("Unknown template marker '%s'\n"), $values->{command}),
|
|
|
|
"$filename:$linenumber: $line";
|
2013-04-30 18:18:17 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
$nesting_level++ if $values->{command} eq "start";
|
|
|
|
$nesting_level-- if $values->{command} eq "end";
|
|
|
|
|
|
|
|
# marker lines should never be added
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
|
|
|
|
# we replace code inside blocks with the template
|
|
|
|
# so we ignore the content of the block
|
|
|
|
next if $nesting_level > 0;
|
|
|
|
|
|
|
|
$ret .= $line;
|
|
|
|
}
|
|
|
|
return $ret;
|
|
|
|
}
|
|
|
|
|
2013-05-19 06:17:57 -04:00
|
|
|
sub usage {
|
|
|
|
my ($exitstatus) = @_;
|
|
|
|
print gettext("makepkg-template [options]\n");
|
|
|
|
print "\n";
|
|
|
|
print gettext("Options:\n");
|
|
|
|
printf(gettext(" --input, -p <file> Build script to read (default: %s)\n"), '@BUILDSCRIPT@');
|
|
|
|
print gettext(" --output, -o <file> file to output to (default: input file)\n");
|
|
|
|
print gettext(" --newest, -n update templates to newest version\n");
|
|
|
|
print gettext(" (default: use version specified in the template markers)\n");
|
|
|
|
print gettext(" --template-dir <dir> directory to search for templates\n");
|
|
|
|
printf(gettext(" (default: %s)\n"), '@TEMPLATE_DIR@');
|
2013-05-29 08:51:24 -04:00
|
|
|
print gettext(" --help, -h This help message\n");
|
|
|
|
print gettext(" --version Version information\n");
|
2013-05-19 06:17:57 -04:00
|
|
|
print "\n";
|
|
|
|
exit($exitstatus);
|
|
|
|
}
|
|
|
|
|
2013-05-29 08:51:24 -04:00
|
|
|
sub version {
|
|
|
|
my ($exitstatus) = @_;
|
|
|
|
printf "makepkg-template (pacman) %s\n", '@PACKAGE_VERSION@';
|
2013-07-21 21:09:58 -04:00
|
|
|
print gettext(
|
2015-01-21 01:31:20 -05:00
|
|
|
'Copyright (c) 2013-2015 Pacman Development Team <pacman-dev@archlinux.org>.'."\n".
|
2013-05-29 08:51:24 -04:00
|
|
|
'This is free software; see the source for copying conditions.'."\n".
|
|
|
|
'There is NO WARRANTY, to the extent permitted by law.'."\n");
|
|
|
|
exit($exitstatus);
|
|
|
|
}
|
|
|
|
|
2013-04-30 18:18:17 -04:00
|
|
|
Getopt::Long::Configure ("bundling");
|
|
|
|
GetOptions(
|
2013-05-29 08:51:24 -04:00
|
|
|
"help|h" => sub {usage(0); },
|
|
|
|
"version" => sub {version(0); },
|
2013-04-30 18:18:17 -04:00
|
|
|
"input|p=s" => \$opts{input},
|
|
|
|
"output|o=s" => \$opts{output},
|
|
|
|
"newest|n" => \$opts{newest},
|
|
|
|
"template-dir=s" => \$opts{template_dir},
|
2013-05-19 06:17:57 -04:00
|
|
|
) or usage(1);
|
2013-04-30 18:18:17 -04:00
|
|
|
|
|
|
|
$opts{output} = $opts{input} unless $opts{output};
|
|
|
|
|
|
|
|
$opts{input} = "/dev/stdin" if $opts{input} eq "-";
|
|
|
|
$opts{output} = "/dev/stdout" if $opts{output} eq "-";
|
|
|
|
|
|
|
|
burp($opts{output}, process_file($opts{input}));
|
|
|
|
|
|
|
|
# vim: set noet:
|