diff options
| -rw-r--r-- | configure.ac | 19 | ||||
| -rw-r--r-- | doc/.gitignore | 1 | ||||
| -rw-r--r-- | doc/Makefile.am | 4 | ||||
| -rw-r--r-- | doc/makepkg-template.1.txt | 120 | ||||
| -rw-r--r-- | scripts/.gitignore | 1 | ||||
| -rw-r--r-- | scripts/Makefile.am | 11 | ||||
| -rwxr-xr-x | scripts/makepkg-template.pl.in | 168 | 
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: | 
