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

Florian Pritz bluewind at xinu.at
Thu May 2 03:41:46 EDT 2013


On 02.05.2013 06:19, Allan McRae wrote:
>> +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?

Typo

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

I'd have to recalculate the checksum for the content (can't trust the
content, remember?) and then build the chain of templates (since
checksums depend on nested templates) and then compare that. Way easier
to just rebuild the whole thing and run diff. Something along the lines
of "diff PKGBUILD <(makepkg-template -o /dev/stdout)".

>> +For initial creation there is a shortcut:
>> +
>> +	# template input; key=value;
> 
> I do not understand this from the (lack of) description.

See next patch for a (hopefully) better version.

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

Alright, maybe my fear of autotools was a little bit irrational. I've
copied some code for @BUILDSCRIPT@ and it seems to work, please check
the next patch.

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

I think you ment "end", start and input both take arguments/options, end
doesn't. Fixed.

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

Allowed [[:alnum:]+_\. at -] and documented. The separator between name and
version is now also - to match makepkg/pacman.

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

Thanks :)


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: OpenPGP digital signature
URL: <http://mailman.archlinux.org/pipermail/pacman-dev/attachments/20130502/1225822d/attachment.asc>


More information about the pacman-dev mailing list