From ce3125196d98baf054e841ea3fb368d81df645e1 Mon Sep 17 00:00:00 2001 From: Florian Pritz Date: Wed, 1 May 2013 00:18:17 +0200 Subject: Add makepkg-template This allows for somewhat easy templating for PKGBUILDs. Signed-off-by: Florian Pritz Signed-off-by: Allan McRae --- scripts/makepkg-template.pl.in | 168 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100755 scripts/makepkg-template.pl.in (limited to 'scripts/makepkg-template.pl.in') diff --git a/scripts/makepkg-template.pl.in b/scripts/makepkg-template.pl.in new file mode 100755 index 00000000..1ba007bb --- /dev/null +++ b/scripts/makepkg-template.pl.in @@ -0,0 +1,168 @@ +#!/usr/bin/perl +use warnings; +use strict; +use v5.10.1; +use Cwd qw(abs_path); +use File::Spec; +use Getopt::Long; +use Pod::Usage; + +my %opts = ( + input => '@BUILDSCRIPT@', + template_dir => '@TEMPLATE_DIR@', +); + +my $template_name_charset = qr/[[:alnum:]+_.@-]/; +my $template_marker = qr/# template/; + +sub burp { + my ($file_name, @lines) = @_; + open (my $fh, ">", $file_name) || die "can't create $file_name $!" ; + 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]+)=(.*)$/); + die "invalid key/value pair $filename:$linenumber: $line" + unless $key and $val; + $values{$key} = $val; + } + + # end doesn't take arguments + if ($values{command} ne "end") { + if (!$values{name}) { + die "invalid template line: can't find template name\n", + "$filename:$linenumber: $line"; + } + + unless ($values{name} =~ /^$template_name_charset+$/) { + die "invalid chars used in name '$values{name}'. allowed: [:alnum:]+_.@-\n", + "$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) { + die "Couldn't detect version for template '$values->{name}'"; + } + + 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; + + open (my $fh, "<", $filename) or die "failed to open '$filename': $!"; + my @lines = <$fh>; + close $fh; + + foreach my $line (@lines) { + $linenumber++; + + if ($line =~ $template_marker) { + my $values = parse_template_line($line, $filename, $linenumber); + + given ($values->{command}) { + when (['start', 'input']) { + if ($nesting_level == 0) { + $ret .= load_template($values); + } + } + + when ('end') { + # nothing to do here, just for completeness + } + + default { + die "Unknown template marker '$values->{command}'\n", + "$filename:$linenumber: $line"; + } + } + + $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; +} + +Getopt::Long::Configure ("bundling"); +GetOptions( + "help" => sub {pod2usage(-exitval => 0, -verbose => 1); }, + "h" => sub {pod2usage(-exitval => 0, -verbose => 0); }, + "input|p=s" => \$opts{input}, + "output|o=s" => \$opts{output}, + "newest|n" => \$opts{newest}, + "template-dir=s" => \$opts{template_dir}, +) or pod2usage(1); + +$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})); + +__END__ +=head1 SYNOPSIS + +makepkg-template [options] + + Options: + --input, -p Build script to read (default: @BUILDSCRIPT@) + --output, -o file to output to (default: input file) + --newest, -n update templates to newest version + (default: use specified version in the template markers) + --template-dir directory to search for templates + (default: @TEMPLATE_DIR@) + +=cut +# vim: set noet: -- cgit v1.2.3-24-g4f1b