This allows for somewhat easy templating for PKGBUILDs.
Signed-off-by: Florian Pritz <bluewind(a)xinu.at>
---
Andrew reviewed most of the perl script already, I just got rid of a dependency
on File::Slurp afterwards.
doc/.gitignore | 1 +
doc/Makefile.am | 4 ++
doc/makepkg-template.1.txt | 89 +++++++++++++++++++++++
scripts/.gitignore | 1 +
scripts/Makefile.am | 7 ++
scripts/makepkg-template.pl.in | 160 +++++++++++++++++++++++++++++++++++++++++
6 files changed, 262 insertions(+)
create mode 100644 doc/makepkg-template.1.txt
create mode 100755 scripts/makepkg-template.pl.in
diff --git a/doc/.gitignore b/doc/.gitignore
index a96ddb3..ad496ce 100644
--- a/doc/.gitignore
+++ b/doc/.gitignore
@@ -1,6 +1,7 @@
PKGBUILD.5
libalpm.3
makepkg.8
+makepkg-template.1
makepkg.conf.5
pacman.8
pacman-key.8
diff --git a/doc/Makefile.am b/doc/Makefile.am
index bcb05b7..cb01255 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -6,6 +6,7 @@
ASCIIDOC_MANS = \
pacman.8 \
makepkg.8 \
+ makepkg-template.1 \
repo-add.8 \
vercmp.8 \
pkgdelta.8 \
@@ -21,6 +22,7 @@ DOXYGEN_MANS = $(wildcard man3/*.3)
HTML_MANPAGES = \
pacman.8.html \
makepkg.8.html \
+ makepkg-template.1.html \
repo-add.8.html \
vercmp.8.html \
pkgdelta.8.html \
@@ -46,6 +48,7 @@ EXTRA_DIST = \
asciidoc-override.css \
pacman.8.txt \
makepkg.8.txt \
+ makepkg-template.1.txt \
repo-add.8.txt \
vercmp.8.txt \
pkgdelta.8.txt \
@@ -147,6 +150,7 @@ $(HTML_OTHER): asciidoc.conf Makefile.am
# Dependency rules
pacman.8 pacman.8.html: pacman.8.txt
makepkg.8 makepkg.8.html: makepkg.8.txt
+makepkg-template.1 makepkg-template.1.html: makepkg-template.1.txt
repo-add.8 repo-add.8.html: repo-add.8.txt
vercmp.8 vercmp.8.html: vercmp.8.txt
pkgdelta.8 pkgdelta.8.html: pkgdelta.8.txt
diff --git a/doc/makepkg-template.1.txt b/doc/makepkg-template.1.txt
new file mode 100644
index 0000000..cea470a
--- /dev/null
+++ b/doc/makepkg-template.1.txt
@@ -0,0 +1,89 @@
+/////
+vim:set ts=4 sw=4 syntax=asciidoc noet spell spelllang=en_us:
+/////
+makepkg-template(1)
+===================
+
+Name
+----
+makepkg-template - package build templating utility
+
+
+Synopsis
+--------
+'makepkg-template' [options]
+
+
+Description
+-----------
+'makepkg-template' is a script to ease the work of maintaining multiple similar PKGBUILDs.
+It allows you to move most of the code from the PKGBUILD into a template file and uses
+markers to allow in-place updating of existing PKGBUILDs if the template has been changed.
+
+Markers are bash comments in the form of:
+
+ # template (start|end); key=value; key2=value2
+
+and
+
+ # template end;
+
+Currently used keys are: name (mandatory), version
+
+For initial creation there is a shortcut:
+
+ %% template input; key=value;
+
+If the version is not set, 'makepkg-template' will automatically use the most
+recent version of the template, otherwise the specified version will be used
+allowing for easier verification of untrused PKGBUILDs if the template is trusted.
+
+Template files may also contain markers leading to nested templates in the
+resulting PKGBUILD.
+
+Template files should be stored in one directory and filenames should be
+"$template_name.$version.template" with a symlink "$template_name.template"
+pointing to the most recent template.
+
+Options
+-------
+
+*-p, \--input* <buildscript>::
+ Read the package script `buildscript` instead of the `PKGBUILD` default.
+
+*-o, \--output* <buildscript>::
+ Write the updated file to `buildscript` instead of overwriting the input file.
+
+*-n, \--newest*::
+ Always use the newest available template file.
+
+*\--template-dir* <dir>::
+ Change the dir where we are looking for template files.
+
+Example PKGBUILD
+----------------
+
+ pkgname=foo-bar
+ # template start; name=foo-module; version=1.2.3
+ _srcdir="$pkgname-$pkgver"
+
+ build() {
+ cd "$_srcdir"
+ ./configure
+ make
+ }
+ # template start; name=package-simple; version=1.0
+ package()
+ cd "$_srcdir"
+ make DESTDIR="$pkgdir" install
+ }
+ # template end;
+ # template end;
+
+
+
+See Also
+--------
+linkman:makepkg[8], linkman:PKGBUILD[5]
+
+include::footer.txt[]
diff --git a/scripts/.gitignore b/scripts/.gitignore
index 9e403bf..26e088b 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -1,4 +1,5 @@
makepkg
+makepkg-template
pacman-db-upgrade
pacman-key
pacman-optimize
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
index 784b180..bc5d588 100644
--- a/scripts/Makefile.am
+++ b/scripts/Makefile.am
@@ -5,6 +5,7 @@ SUBDIRS = po
bin_SCRIPTS = \
$(OURSCRIPTS) \
+ makepkg-template \
repo-remove \
repo-elephant
@@ -18,6 +19,7 @@ OURSCRIPTS = \
EXTRA_DIST = \
makepkg.sh.in \
+ makepkg-template.pl.in \
pacman-db-upgrade.sh.in \
pacman-key.sh.in \
pacman-optimize.sh.in \
@@ -76,6 +78,11 @@ makepkg: \
$(srcdir)/makepkg.sh.in \
$(srcdir)/library/parseopts.sh
+makepkg-template: \
+ $(srcdir)/makepkg-template.pl.in
+ $(AM_V_at)$(RM) -f makepkg-template
+ $(AM_V_at)cp $< $@
+
pacman-db-upgrade: \
$(srcdir)/pacman-db-upgrade.sh.in \
$(srcdir)/library/output_format.sh
diff --git a/scripts/makepkg-template.pl.in b/scripts/makepkg-template.pl.in
new file mode 100755
index 0000000..d03fd33
--- /dev/null
+++ b/scripts/makepkg-template.pl.in
@@ -0,0 +1,160 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+use v5.14;
+use Cwd qw(abs_path);
+use File::Spec;
+use Getopt::Long;
+use Pod::Usage;
+
+my %opts = (
+ input => 'PKGBUILD',
+ template_dir => '/usr/share/makepkg-template',
+);
+
+sub burp {
+ my ($file_name) = shift;
+ open (my $fh, ">", $file_name) || die "can't create $file_name $!" ;
+ print $fh @_;
+}
+
+# read a template marker line and parse values into a hash
+# format is "(#|%%) template (start|input|end); key=value; key2=value2; ..."
+sub parse_template_line {
+ my ($line, $filename, $linenumber) = @_;
+ my %values;
+
+ my @elements = split(/;\s?/, $line);
+
+ foreach my $element (@elements) {
+ given($element) {
+ when (/^(?:#|%%) template (.*)$/) {
+ $values{template} = $1;
+ }
+ when (/^([a-z0-9_]+)=(.*);?$/) {
+ $values{$1} = $2;
+ }
+ }
+ }
+
+ if (!$values{name}) {
+ die "invalid template line: can't find template name",
+ "$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 basename for version detection
+ my $basename = (File::Spec->splitpath(abs_path($path)))[2];
+ my ($version) = ($basename =~ /^[^\.]+\.([0-9\.]+)\.template$/);
+
+ 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 $in_block = 0;
+ my $linenumber = 0;
+
+ open FH, "<", $filename or die "failed to open '$filename': $!";
+ my @lines = <FH>;
+ close FH;
+
+ foreach my $line (@lines) {
+ my $add_line = 1;
+ $linenumber++;
+
+ # special marker to insert a template for the first time
+ # start with %% in order to create an invalid bash script until replaced
+ if ($line =~ /^%% template input/) {
+ my $values = parse_template_line($line, $filename, $linenumber);
+ $ret .= load_template($values);
+ $add_line = 0;
+ }
+
+ if ($line =~ /^# template ([^;]+);?/) {
+ given ($1) {
+ # marker followed by code from the template and an end
+ when ('start') {
+ my $values = parse_template_line($line, $filename, $linenumber);
+
+ # only process the first template level here
+ # load_template calls us again if templates are nested
+ if ($in_block == 0) {
+ $ret .= load_template($values);
+ }
+ $in_block++;
+ }
+
+ when ('end') {
+ $in_block--;
+ $add_line = 0;
+ }
+
+ default {
+ die "Unknown template marker '$1'",
+ "$filename:$linenumber: $line";
+ }
+ }
+ }
+
+ if ($in_block > 0) {
+ $add_line = 0;
+ }
+
+ $ret .= "$line" if $add_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};
+
+my $output = process_file($opts{input});
+
+burp($opts{output}, $output);
+
+__END__
+=head1 SYNOPSIS
+
+makepkg-template [options]
+
+ Options:
+ --input, -p <file> PKGBUILD to read (default: ./PKGBUILD)
+ --output, -o <file> file to output to (default: input file)
+ --newest, -n update templates to newest possible version
+ (default: use specified version in the template markers)
+ --template-dir <dir> dir to search for templates (default: /usr/share/makepkg-template)
+
+=cut
--
1.8.2.2