On 07/05/13 04:48, Florian Pritz wrote:
> This allows for somewhat easy templating for PKGBUILDs.
> 
> Signed-off-by: Florian Pritz <[email protected]>
> ---
> 
> v5:
>  - configure checks for perl
>  - minor manpages changes
>  - change dep from perl 5.14 to 5.10.1 (given/when)
>  - remove some env variables from the example PKGBUILD
> 
>  configure.ac                   |  19 +++++
>  doc/.gitignore                 |   1 +
>  doc/Makefile.am                |   4 +
>  doc/makepkg-template.1.txt     | 120 +++++++++++++++++++++++++++++
>  scripts/.gitignore             |   1 +
>  scripts/Makefile.am            |  11 +++
>  scripts/makepkg-template.pl.in | 167 
> +++++++++++++++++++++++++++++++++++++++++
>  7 files changed, 323 insertions(+)
>  create mode 100644 doc/makepkg-template.1.txt
>  create mode 100755 scripts/makepkg-template.pl.in
> 
> diff --git a/configure.ac b/configure.ac
> index 81bc1b3..ac629f9 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])])

Indented with reckless abandon...

I'd just use the ax_prog_perl_version.m4 from autoconf-archive (which
looks more robust) and put it in our m4 directory.

> +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 dir
> +AC_SUBST(TEMPLATE_DIR)
> +AC_DEFINE_UNQUOTED([TEMPLATE_DIR], "$TEMPLATE_DIR", [The template dir used 
> by makepkg-teplate])

directory

>  # 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 dir           : ${TEMPLATE_DIR}

directory

>  
>    Compilation options:
>      Use libcurl            : ${have_libcurl}
> 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..74fd8d4
> --- /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 untrused 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* <buildscript>::
> +     Read the package script `buildscript` instead of the `PKGBUILD` default.

build script

and just "instead of the default" because PKGBUILD may not be the
default depending on configuration.

> +
> +*-o, \--output* <buildscript>::
> +     Write the updated file to `buildscript` instead of overwriting the 
> input file.

build script

> +
> +*-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)

Quotes (single) around 'any'

> +     license=(PerlArtistic GPL)

Quotes...

> +     depends=('perl')
> +     
> source=("http://search.cpan.org/CPAN/authors/id/S/SH/SHERZODR/Config-Simple-${pkgver}.tar.gz";)
> +     md5sums=(f014aec54f0a1e2e880d317180fce502)

Quotes...

> +     _distname="Config-Simple"
> +
> +     # template start; name=perl-module; version=1.0;
> +     options+=(!emptydirs)

Quotes.

> +     _distdir="${_distname}-${pkgver}"
> +     url="https://metacpan.org/release/${_distname}";

put this above "options+=".

> +
> +     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 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..1f3bae2 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 0000000..0951e16
> --- /dev/null
> +++ b/scripts/makepkg-template.pl.in
> @@ -0,0 +1,167 @@
> +#!/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>     PKGBUILD to read (default: @BUILDSCRIPT@)

Build script to read

> +   --output, -o <file>    file to output to (default: input file)
> +   --newest, -n           update templates to newest possible version

s/possible//

> +                          (default: use specified version in the template 
> markers)
> +   --template-dir <dir>   dir to search for templates (default: 
> @TEMPLATE_DIR@)

s/dir/directory/  - unless the line goes over 80 characters.

> +
> +=cut
> +# vim: set noet:
> 


Reply via email to