[pacman-dev] [RFC] [PATCHv2] Add makepkg-template

Allan McRae allan at archlinux.org
Thu May 2 00:19:07 EDT 2013


On 02/05/13 08:12, Florian Pritz wrote:
> This allows for somewhat easy templating for PKGBUILDs.
> 
> Signed-off-by: Florian Pritz <bluewind at xinu.at>
> ---
> 
> Andrew reviewed most of the perl script already, I just got rid of a dependency
> on File::Slurp afterwards.
> 
> v2: Got rid of %% for "template input" markers, they now also use #.
> 
> Comments on the man page are very welcome.
> 
>  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 | 159 +++++++++++++++++++++++++++++++++++++++++
>  6 files changed, 261 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..40ac3e1
> --- /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

Just "template start" here, or it is end too?

> +and
> +
> +	# template end;
> +
> +Currently used keys are: name (mandatory), version
> +

No checksum?

> +For initial creation there is a shortcut:
> +
> +	# template input; key=value;

I do not understand this from the (lack of) description.

> +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.

This versioning of templates is not described anywhere....

> +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.

... oh here it is.  Describe the versioning before you refer to the
version.   Also, what exactly is inside the template file?  Just the bash?

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

I'd go for a real life example (e.g. a perl module), rather than a plain
./configure.

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

Why the RM?  Anyway, this will need to change with the comments below.

> +	$(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..6c11c24
> --- /dev/null
> +++ b/scripts/makepkg-template.pl.in
> @@ -0,0 +1,159 @@
> +#!/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',

Needs to use whatever the build script name is configured to build time.

> +	template_dir => '/usr/share/makepkg-template',

Also needs to be configurable at build time.

> +);
> +
> +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; ..."

"input" ?

> +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$/);

Document the restrictions on template names.  Does that say no "." is
allowed?

> +	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++;
> +
> +		if ($line =~ /^# template ([^;]+);?/) {
> +			given ($1) {
> +				# special marker to insert a template for the first time
> +				when ('input') {
> +					my $values = parse_template_line($line, $filename, $linenumber);
> +					$ret .= load_template($values);
> +					$add_line = 0;
> +				}
> +
> +				# 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)

Configured.

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

Configured.

> +
> +=cut
> 


I know too little perl to comment beyond that.

Allan




More information about the pacman-dev mailing list