summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Pritz <bluewind@xinu.at>2013-05-01 00:18:17 +0200
committerAllan McRae <allan@archlinux.org>2013-05-29 06:17:21 +0200
commitce3125196d98baf054e841ea3fb368d81df645e1 (patch)
tree46744c5027ca3a62d8da57f22416a620ad80b4ce
parent7ea58d09f69a9a13b637e7128e7b882ac2bebc64 (diff)
downloadpacman-ce3125196d98baf054e841ea3fb368d81df645e1.tar.gz
pacman-ce3125196d98baf054e841ea3fb368d81df645e1.tar.xz
Add makepkg-template
This allows for somewhat easy templating for PKGBUILDs. Signed-off-by: Florian Pritz <bluewind@xinu.at> Signed-off-by: Allan McRae <allan@archlinux.org>
-rw-r--r--configure.ac19
-rw-r--r--doc/.gitignore1
-rw-r--r--doc/Makefile.am4
-rw-r--r--doc/makepkg-template.1.txt120
-rw-r--r--scripts/.gitignore1
-rw-r--r--scripts/Makefile.am11
-rwxr-xr-xscripts/makepkg-template.pl.in168
7 files changed, 324 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index 0d08e862..1ea0fce8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -97,6 +97,11 @@ AC_ARG_WITH(buildscript,
AS_HELP_STRING([--with-buildscript=name], [set the build script name used by makepkg]),
[BUILDSCRIPT=$withval], [BUILDSCRIPT=PKGBUILD])
+# Help line for buildscript filename
+AC_ARG_WITH(makepkg-template-dir,
+ AS_HELP_STRING([--with-makepkg-template-dir=name], [set the template dir used by makepkg-template]),
+ [TEMPLATE_DIR=$withval], [TEMPLATE_DIR=/usr/share/makepkg-template])
+
# Help line for debug package suffix
AC_ARG_WITH(debug-suffix,
AS_HELP_STRING([--with-debug-suffix=name], [set the suffix for split debugging symbol packages used by makepkg]),
@@ -166,6 +171,16 @@ AC_PROG_INSTALL
AC_CHECK_PROGS([PYTHON], [python2.7 python2.6 python2.5 python2 python], [false])
AC_PATH_PROGS([BASH_SHELL], [bash bash4], [false])
+# check for perl 5.10.1 (needed by makepkg-template)
+AC_PATH_PROG([PERL],[perl])
+AC_DEFUN([AX_PROG_PERL_VERSION],
+ [AC_CACHE_CHECK([for Perl version $1 or later], [ax_cv_prog_perl_version],
+ [AS_IF(["$PERL" -e 'require v$1;' >/dev/null 2>&1],
+ [ax_cv_prog_perl_version=yes],
+ [ax_cv_prog_perl_version=no])])
+ AS_IF([test x"$ax_cv_prog_perl_version" = xyes], [$2], [$3])])
+AX_PROG_PERL_VERSION([5.10.1], [], [AC_MSG_ERROR([perl is too old])])
+
AS_IF([test "x$BASH_SHELL" = "xfalse"],
AC_MSG_WARN([*** bash >= 4.1.0 is required for pacman scripts]),
[bash_version_major=`$BASH_SHELL -c 'echo "${BASH_VERSINFO[[0]]}"'`
@@ -457,6 +472,9 @@ AC_DEFINE_UNQUOTED([SRCEXT], "$SRCEXT", [The file extension used by pacman sourc
# Set makepkg build script name
AC_SUBST(BUILDSCRIPT)
AC_DEFINE_UNQUOTED([BUILDSCRIPT], "$BUILDSCRIPT", [The build script name used by makepkg])
+# Set makepkg-template template directory
+AC_SUBST(TEMPLATE_DIR)
+AC_DEFINE_UNQUOTED([TEMPLATE_DIR], "$TEMPLATE_DIR", [The template directory used by makepkg-teplate])
# Set makepkg split debugging symbol package suffix
AC_SUBST(DEBUGSUFFIX)
AC_DEFINE_UNQUOTED([DEBUGSUFFIX], "$DEBUGSUFFIX", [The suffix for debugging symbol packages used by makepkg])
@@ -524,6 +542,7 @@ ${PACKAGE_NAME}:
package extension : ${PKGEXT}
source pkg extension : ${SRCEXT}
build script name : ${BUILDSCRIPT}
+ template directory : ${TEMPLATE_DIR}
Compilation options:
Use libcurl : ${have_libcurl}
diff --git a/doc/.gitignore b/doc/.gitignore
index a96ddb30..ad496ce0 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 bcb05b74..cb012551 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 00000000..8fa5c2e1
--- /dev/null
+++ b/doc/makepkg-template.1.txt
@@ -0,0 +1,120 @@
+/////
+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.
+
+Template files can contain any code allowed in a PKGBUILD. You can think of
+them like external files included with "." or "source", but they will be
+inlined into the PKGBUILD by 'makepkg-template' so you do not depend on the
+template file when building the package.
+
+Markers are bash comments in the form of:
+
+ # template start; key=value; key2=value2; ...
+
+and
+
+ # template end;
+
+Currently used keys are: name (mandatory) and version. Template names are limited to
+alphanumerics, "@", "+", ".", "-" and "_". Versions are limited to numbers and ".".
+
+For initial creation there is a one line short cut which does not need an end marker:
+
+ # template input; key=value;
+
+Using this short-cut will result in 'makepkg-template' replacing it with start
+and end markers and the template code on the first run.
+
+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. If the version is not set in the marker,
+'makepkg-template' will automatically use the most recent version of the
+template, otherwise the specified version will be used. This allows for easier
+verification of untrusted PKGBUILDs if the template is trusted. You verify the
+non-template code and then use a command similar to this:
+
+ diff -u <(makepkg-template -o -) PKGBUILD
+
+Template files may also contain markers leading to nested templates in the
+resulting PKGBUILD. If you use markers in a template, please set the version
+you used/tested with in the start/input marker so other people can properly
+recreate from templates.
+
+Options
+-------
+
+*-p, \--input* <build script>::
+ Read the package script `build script` instead of the default.
+
+*-o, \--output* <build script>::
+ Write the updated file to `build script` 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=perl-config-simple
+ pkgver=4.58
+ pkgrel=1
+ pkgdesc="simple configuration file class"
+ arch=('any')
+ license=('PerlArtistic' 'GPL')
+ depends=('perl')
+ source=("http://search.cpan.org/CPAN/authors/id/S/SH/SHERZODR/Config-Simple-${pkgver}.tar.gz")
+ md5sums=('f014aec54f0a1e2e880d317180fce502')
+ _distname="Config-Simple"
+
+ # template start; name=perl-module; version=1.0;
+ _distdir="${_distname}-${pkgver}"
+ url="https://metacpan.org/release/${_distname}"
+ options+=('!emptydirs')
+
+ build() {
+ cd "$srcdir/$_distdir"
+ perl Makefile.PL INSTALLDIRS=vendor
+ make
+ }
+
+ check() {
+ cd "$srcdir/$_distdir"
+ make test
+ }
+
+ package() {
+ cd "$srcdir/$_distdir"
+ make DESTDIR="$pkgdir" install
+ }
+ # template end;
+
+
+
+See Also
+--------
+linkman:makepkg[8], linkman:PKGBUILD[5]
+
+include::footer.txt[]
diff --git a/scripts/.gitignore b/scripts/.gitignore
index 9e403bfb..26e088b9 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 784b1802..1f3bae24 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 \
@@ -54,6 +56,7 @@ edit = sed \
-e 's|@PACKAGE_BUGREPORT[@]|$(PACKAGE_BUGREPORT)|g' \
-e 's|@PACKAGE_NAME[@]|$(PACKAGE_NAME)|g' \
-e 's|@BUILDSCRIPT[@]|$(BUILDSCRIPT)|g' \
+ -e 's|@TEMPLATE_DIR[@]|$(TEMPLATE_DIR)|g' \
-e 's|@DEBUGSUFFIX[@]|$(DEBUGSUFFIX)|g' \
-e "s|@INODECMD[@]|$(INODECMD)|g" \
-e 's|@SIZECMD[@]|$(SIZECMD)|g' \
@@ -76,6 +79,14 @@ makepkg: \
$(srcdir)/makepkg.sh.in \
$(srcdir)/library/parseopts.sh
+makepkg-template: \
+ $(srcdir)/makepkg-template.pl.in \
+ Makefile
+
+ $(AM_V_at)$(RM) -f makepkg-template
+ $(AM_V_GEN)$(edit) $< > $@
+ $(AM_V_at)chmod +x,a-w $@
+
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 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 <file> Build script to read (default: @BUILDSCRIPT@)
+ --output, -o <file> file to output to (default: input file)
+ --newest, -n update templates to newest version
+ (default: use specified version in the template markers)
+ --template-dir <dir> directory to search for templates
+ (default: @TEMPLATE_DIR@)
+
+=cut
+# vim: set noet: