summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustin Davis <jrcd83@gmail.com>2011-08-14 21:15:27 +0200
committerJustin Davis <jrcd83@gmail.com>2011-08-14 21:15:27 +0200
commit01da7f81b3d6924d5a9a25d804a3905c6fd616ed (patch)
tree5483bc3d6dca6a45addae0710ce82d1410a343c4
downloadgenpkg-01da7f81b3d6924d5a9a25d804a3905c6fd616ed.tar.gz
genpkg-01da7f81b3d6924d5a9a25d804a3905c6fd616ed.tar.xz
Initial commit.
-rw-r--r--.gitignore1
-rwxr-xr-xbin/macros/perl-cpan42
-rwxr-xr-xbin/macros/perl-dist552
-rwxr-xr-xbin/pbj58
-rwxr-xr-xbin/pbjparse.awk119
-rwxr-xr-xbin/templ/perl-pkg145
-rw-r--r--pbj/perl-moose.pbj4
7 files changed, 921 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b25c15b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*~
diff --git a/bin/macros/perl-cpan b/bin/macros/perl-cpan
new file mode 100755
index 0000000..810ad8d
--- /dev/null
+++ b/bin/macros/perl-cpan
@@ -0,0 +1,42 @@
+#!/Users/juster/perl5/perlbrew/perls/perl-5.14.1/bin/perl
+
+use warnings 'FATAL' => 'all';
+use strict;
+
+use LWP::UserAgent;
+use IO::Handle; # for autoflush
+
+my $dist = shift or die "Usage: $0 [CPAN dist name]\n";
+my $url = "http://search.cpan.org/dist/$dist";
+my $ua = LWP::UserAgent->new();
+my $resp = $ua->get($url);
+
+die "$0: GET $url failed: ", $resp->status_line, "\n"
+ unless $resp->is_success;
+
+$resp = $resp->content;
+my ($href) = $resp =~ m{\[<a href="([^"]+)">Download</a>\]}
+ or die "$0: no download link found at $url\n";
+
+unless (-d 'src') {
+ mkdir 'src' or die "$0: mkdir src: $!"
+}
+
+my $file = $href;
+$file =~ s{\A.*/}{};
+$href = "http://search.cpan.org" . $href;
+
+STDERR->autoflush(1);
+print STDERR "Downloading $file... ";
+$resp = $ua->get($href, ':content_file' => "src/$file");
+die "$0: download of $file failed: ", $resp->status_line
+ unless $resp->is_success;
+print STDERR "OK\n";
+
+print "+ url $url\n";
+print "+ source $href\n";
+system "perl-dist src/$file";
+if ($? != 0) {
+ printf STDERR "$0: failed to run perl-dist%s\n", ($! ? " ($!)" : q{});
+ exit 1;
+}
diff --git a/bin/macros/perl-dist b/bin/macros/perl-dist
new file mode 100755
index 0000000..dc62ec8
--- /dev/null
+++ b/bin/macros/perl-dist
@@ -0,0 +1,552 @@
+#!/Users/juster/perl5/perlbrew/perls/perl-5.14.1/bin/perl
+
+use warnings 'FATAL' => 'all';
+use strict;
+
+package Convert;
+
+use Module::CoreList;
+use LWP::UserAgent qw();
+use YAML::XS qw();
+use version qw();
+
+sub dist2pkg
+{
+ my ($name, $ver) = @_;
+ return dist_pkgname($name), dist_pkgver($ver);
+}
+
+# Copied from CPANPLUS::Dist::Arch
+sub dist_pkgname
+{
+ my ($distname) = @_;
+
+ # Package names should be lowercase and consist of alphanumeric
+ # characters only (and hyphens!)...
+ $distname = lc $distname;
+ $distname =~ tr/_+/--/;
+ $distname =~ tr/-a-z0-9//cd; # Delete all other chars
+ $distname =~ tr/-/-/s;
+
+ # Delete leading or trailing hyphens...
+ $distname =~ s/\A-//;
+ $distname =~ s/-\z//;
+
+ die qq{Dist name '$distname' completely violates packaging standards}
+ if length $distname == 0;
+
+ # Don't prefix the package with perl- if it IS perl...
+ $distname = "perl-$distname" unless $distname eq 'perl';
+
+ return $distname;
+}
+
+sub dist_pkgver
+{
+ my ($version) = @_;
+
+ # Package versions should be numbers and decimal points only...
+ $version =~ tr/-/./;
+ $version =~ tr/_0-9.//cd;
+
+ # Remove developer versions because pacman has no special logic
+ # to handle comparing them to regular versions like perl does.
+ $version =~ s/_\d+\z//;
+
+ $version =~ tr/././s;
+ $version =~ s/^[.]|[.]$//g;
+
+ return $version;
+}
+
+#---HELPER FUNCTION---
+# Decide if the dist. is named after the module.
+sub _ismainmod
+{
+ my ($mod_name, $dist_name) = @_;
+
+ $mod_name =~ tr/:/-/s;
+ return (lc $mod_name) eq (lc $dist_name);
+}
+
+#---HELPER FUNCTION---
+# Merges the right-hand deps into the left-hand deps.
+sub _merge
+{
+ my ($left_deps, $right_deps) = @_;
+
+ MERGE_LOOP:
+ while ( my ($pkg, $ver) = each %$right_deps ) {
+ if ( $left_deps->{$pkg} ) {
+ my $leftver = version->parse($left_deps->{$pkg});
+ my $rightver = version->parse($ver);
+ next MERGE_LOOP if $leftver > $rightver;
+ }
+ $left_deps->{$pkg} = $ver;
+ }
+
+ return;
+}
+
+#---HELPER FUNCTION---
+# Merge duplicate deps into $left always storing the greatest version there.
+sub _mergedups
+{
+ my ($left, $right) = @_;
+
+ for my $name (keys %$left) {
+ my $rver = $right->{$name} or next;
+ my $lver = $left->{$name};
+ my $lvo = ($lver ? version->parse($lver) : 0);
+ my $rvo = ($rver ? version->parse($rver) : 0);
+ $left->{$name} = ($lvo > $rvo ? $lvo : $rvo);
+ }
+
+ return;
+}
+
+#---HELPER FUNCTION---
+sub _yankcheckers
+{
+ my ($deps_ref) = @_;
+ my %checkdeps;
+
+ for my $testdep (grep { /perl-test-/ } keys %$deps_ref) {
+ my $val = delete $deps_ref->{$testdep};
+ $checkdeps{$testdep} = $val if $val;
+ }
+
+ # Also extract Pod::Coverage module into checkdepends
+ for my $dep ( qw/ perl-pod-coverage / ) {
+ my $val = delete $deps_ref->{$dep};
+ $checkdeps{$dep} = $val if $val;
+ }
+
+ return \%checkdeps;
+}
+
+#---HELPER FUNCTION---
+# Converts a decimal perl version (like $]) into the dotted decimal
+# form that the official ArchLinux perl package uses.
+sub _perldepver
+{
+ my ($perlver) = @_;
+
+ # Fix perl-style vstrings which have a leading "v".
+ return $perlver if $perlver =~ s/\Av//;
+ return $perlver unless $perlver =~ /\A(\d+)[.](\d{3})(\d{1,3})\z/;
+
+ # Re-apply the missing trailing zeroes.
+ my $patch = $3;
+ $patch .= q{0} x (3 - length($patch));
+ return sprintf '%d.%d.%d', $1, $2, $patch;
+}
+
+#---PUBLIC FUNCNTION---
+# Translates CPAN module dependencies into ArchLinux package dependencies.
+sub _reqs2deps
+{
+ my ($prereqs) = @_;
+
+ my %pkgdeps;
+
+ CPAN_DEP_LOOP:
+ while (my ($name, $ver) = each %$prereqs) {
+ # Sometimes a perl version is given as a prerequisite
+ if ($name eq 'perl') {
+ $pkgdeps{'perl'} = _perldepver($ver);
+ next CPAN_DEP_LOOP;
+ }
+
+# Ideally we could take advantage of the perl package's provides list
+# and add dependencies for core modules.
+
+# This is more robust and handles the problem of packages built
+# with a different version of perl than the perl that is present
+# when the package is installed.
+
+# The problem is that the perl package provides list still needs work.
+# While I was trying to generate a provides list I noticed the
+# Module::CoreList module had some incorrect version numbers
+# as well. So until I get around to reporting these bugs I will
+# just go back to not depending on packages provided by perl.
+
+ # 0+$] is needed to force the perl version into number-dom
+ # otherwise trailing zeros cause problems
+ my $bundled_version = $Module::CoreList::version{ 0 + $] }->{$name};
+ if ($bundled_version) {
+ # Avoid parsing an empty string (causes an error) or 0.
+ next CPAN_DEP_LOOP unless $ver;
+
+ # Avoid parsing a bundled version of 0. Is this possible?
+ my $bundle_vobj = version->parse($bundled_version);
+ my $dep_vobj = version->parse($ver);
+ next CPAN_DEP_LOOP if $bundle_vobj >= $dep_vobj;
+ }
+
+ my $dist = _distofmod($name);
+ my $pkgname = dist_pkgname($dist);
+
+ # If the module is not named after the distribution, ignore its
+ # version which might not match the distribution.
+ undef $ver unless _ismainmod($name, $dist);
+
+ # If two module prereqs are in the same CPAN distribution then
+ # the version required for the main module will override.
+ # (because versions specified for other modules in the dist
+ # are 0)
+ $pkgdeps{$pkgname} ||= ($ver ? dist_pkgver($ver) : 0);
+ }
+
+ return \%pkgdeps;
+}
+
+sub prereqs
+{
+ my ($pkgname, $prereqs) = @_;
+
+ # maps perl names for different dependencies to ArchLinux's names
+ my %namemap = ('configure' => 'makedepends',
+ 'build' => 'makedepends',
+ 'testing' => 'checkdepends',
+ 'runtime' => 'depends');
+
+ my %pkgdeps;
+ while (my ($perl, $arch) = each %namemap) {
+ $pkgdeps{$arch} ||= {};
+ my $reqs = $prereqs->{$perl}{'requires'};
+ my $deps = _reqs2deps($reqs) if $reqs;
+ _merge($pkgdeps{$arch}, $deps) if $deps;
+ }
+
+ # ArchLinux now has a separate array for dependencies that we only
+ # need for checking (aka "testing"). Older perl METAs do not
+ # have this separated. Force any test modules to be checkdepends.
+ if (!$pkgdeps{'checkdepends'} && $pkgname !~ /\Aperl-test-/) {
+ my $checkdeps;
+ my $makedeps = $pkgdeps{'makedepends'};
+ _merge($checkdeps, _yankcheckers($makedeps));
+ $pkgdeps{'checkdepends'} = $checkdeps;
+ }
+
+ # We at least require perl, if nothing else.
+ unless (grep { scalar keys %$_ > 0 } values %pkgdeps) {
+ $pkgdeps{'depends'}{'perl'} = 0;
+ }
+
+ _mergedups(@pkgdeps{qw/makedepends checkdepends/});
+ _mergedups(@pkgdeps{qw/depends makedepends/});
+
+ # Convert all deps into arrays of strings.
+ for my $deptype (keys %pkgdeps) {
+ $pkgdeps{$deptype} = _stringify($pkgdeps{$deptype});
+ }
+
+ return \%pkgdeps;
+}
+
+#---HELPER FUNCTION---
+sub _stringify
+{
+ my ($deps) = @_;
+
+ my @depstrs;
+ for my $pkg (sort keys %$deps) {
+ my $ver = $deps->{$pkg};
+ my $str = ($ver eq '0' ? $pkg : "$pkg>=$ver");
+ push @depstrs, $str;
+ }
+
+ return \@depstrs;
+}
+
+my $UA;
+sub _distofmod
+{
+ my ($mod) = @_;
+
+ my $UA ||= LWP::UserAgent->new();
+ my $url = "http://cpanmetadb.appspot.com/v1.0/package/$mod";
+ my $resp = $UA->get($url);
+ die "failed to lookup dist for $mod: " . $resp->status_line
+ unless $resp->is_success;
+
+ $resp = YAML::XS::Load($resp->content);
+ my $file = $resp->{'distfile'};
+ $file =~ s{.*/}{};
+ $file =~ s{-[^-]+\z}{};
+
+ return $file;
+}
+
+#-----------------------------------------------------------------------------
+
+package main;
+
+use File::Basename qw(basename dirname);
+use File::Spec::Functions qw(catfile);
+use File::Find qw(find);
+
+use JSON::XS qw(decode_json); # parse META.{json,yml} files
+use YAML::XS qw();
+use Pod::Select qw(); # search POD for description
+
+use Digest::MD5 qw(); # for md5sums & sha512sums
+use Digest::SHA qw();
+
+# Override a package's name to conform to packaging guidelines.
+# Copied entries from CPANPLUS::Dist::Pacman and alot more
+# from searching for packages with perl in their name in
+# [extra] and [community]
+my $NAME_OVERRIDES =
+{ map { split /[\s=]+/ } split /\s*\n+\s*/, <<'END_OVERRIDES' };
+
+libwww-perl = perl-libwww
+aceperl = perl-ace
+mod_perl = mod_perl
+
+glade-perl-two = perl-glade-two
+Gnome2-GConf = gconf-perl
+Gtk2-GladeXML = glade-perl
+Glib = glib-perl
+Gnome2 = gnome-perl
+Gnome2-VFS = gnome-vfs-perl
+Gnome2-Canvas = gnomecanvas-perl
+Gnome2-GConf = gconf-perl
+Gtk2 = gtk2-perl
+Cairo = cairo-perl
+Pango = pango-perl
+
+SDL_Perl = sdl_perl
+Perl-Critic = perl-critic
+Perl-Tidy = perl-tidy
+App-Ack = ack
+TermReadKey = perl-term-readkey
+
+END_OVERRIDES
+
+sub main
+{
+ my $distpath = shift or die "Usage: $0 [path to cpan dist file]\n";
+ my $dir = dirname($distpath);
+ my $file = basename($distpath);
+ my $info = distinfo($file);
+
+ chdir $dir or die "chdir $dir: $!";
+ $dir = extractdist($file);
+
+ my $meta = loadmeta($dir);
+ my $desc = $meta->{'abstract'};
+ if (!$desc || $desc eq '~') {
+ $meta->{'abstract'} = distdesc($dir, $info->{'mod'});
+ }
+
+ my ($name, $ver) = Convert::dist2pkg(@{$info}{'name', 'ver'});
+ my $deps = Convert::prereqs($name, $meta->{'prereqs'});
+
+ my %pbvars =
+ ('pkgname' => $name,
+ 'pkgver' => $ver,
+ 'pkgdesc' => $meta->{'abstract'},
+
+ 'arch' => (xsdist($dir) ? ['i686', 'x86_64'] : 'any'),
+ 'md5sums' => md5sums($file),
+ 'sha512sums' => sha512sums($file),
+ 'distdir' => $dir,
+ %$deps,
+ );
+
+ # Since this is a perl distribution, use the perl-pkg template.
+ printf "| perl-pkg %s\n", (-f "$dir/Build.PL" ? "MB" : "MM");
+
+ printjam(\%pbvars);
+}
+
+sub envvar
+{
+ my ($name) = @_;
+ my $val = $ENV{uc $name};
+ ($name => [ split /\s+/, $name ]);
+}
+
+sub distinfo
+{
+ my ($distfile) = @_;
+
+ my @c = split /-/, $distfile;
+ my $ver = pop @c;
+ my $name = join q{-}, @c;
+ my $mod = $name;
+ $mod =~ s/-/::/g;
+ return { 'name' => $name, 'ver' => $ver, 'mod' => $mod };
+}
+
+sub extractdist
+{
+ my ($file) = @_;
+
+ system "bsdtar -xf $file";
+ die "$0: bsdtar failed to extract $file\n" unless $? == 0;
+
+ opendir my $srcdir, '.' or die "opendir: $!";
+ my @dirs = grep { -d $_ && !/\A[.]/ } readdir $srcdir;
+ closedir $srcdir;
+
+ die "$0: many dirs (@dirs) inside the tarball $file\n"
+ if @dirs > 1;
+ die "$0: no dirs found in tarball $file\n" if @dirs == 0;
+ return $dirs[0];
+}
+
+sub printjam
+{
+ my ($pbvars) = @_;
+ while (my ($name, $val) = each %$pbvars) {
+ if (! defined $val || $val eq q{}) {
+ warn "$0: warning: $name is undefined\n";
+ $val = q{};
+ }
+ print "+ $name $_\n" for (ref $val ? @$val : $val);
+ }
+}
+
+sub loadmeta
+{
+ my ($distdir) = @_;
+
+ for my $metaext (qw/json yml/) {
+ my $path = "$distdir/META.$metaext";
+ next unless -f $path;
+
+ open my $metafh, '<', $path or die "open: $!";
+ my $meta = do { local $/; <$metafh> };
+ close $metafh;
+
+ $meta = ($metaext eq 'json' ? decode_json($meta) :
+ $metaext eq 'yml' ? YAML::XS::Load($meta) :
+ die "internal error: unknown \$metaext: $metaext");
+
+ upgrademeta($meta);
+ return $meta;
+ }
+
+ return undef;
+}
+
+sub upgrademeta
+{
+ my ($meta) = @_;
+
+ return if exists $meta->{'prereqs'};
+
+ my $prereqs;
+ $prereqs->{'configure'}{'requires'} = delete $meta->{'configure_requires'};
+ $prereqs->{'build' }{'requires'} = delete $meta->{'build_requires'};
+ $prereqs->{'runtime' }{'requires'} = delete $meta->{'requires'};
+
+ $meta->{'prereqs'} = $prereqs;
+ return;
+}
+
+sub xsdist
+{
+ my ($dir) = @_;
+ my $isxs;
+ find({ 'wanted' => sub { $isxs = 1 if /[.]xs$/ }, 'no_chdir' => 1 }, $dir);
+ return $isxs;
+}
+
+#-----------------------------------------------------------------------------
+
+sub distdesc
+{
+ my ($dir, $modname) = @_;
+ return _poddesc($dir, $modname) || _readmedesc($dir, $modname);
+}
+
+sub _poddesc
+{
+ my ($dir, $modname) = @_;
+
+ my $podselect = Pod::Select->new;
+ $podselect->select('NAME');
+
+ my $modpath = $modname; $modpath =~ s{::}{/}g;
+ my $moddir = dirname($modpath);
+ my $modfile = basename($modpath);
+
+ # First check under lib/ for a "properly" pathed module, with
+ # nested directories. Then search desperately for a .pm file that
+ # matches the module's last name component.
+
+ my @possible = glob "$dir/{lib/,}{moddir/,}$modfile.{pod,pm}";
+
+ PODSEARCH:
+ for my $podpath ( @possible ) {
+ next PODSEARCH unless -f $podpath;
+
+ # Read the NAME section of the POD into a scalar.
+ my $namesect = q{};
+ open my $podfile, '<', $podpath or next PODSEARCH;
+ open my $podout, '>', \$namesect or die "open: $!";
+
+ $podselect->parse_from_filehandle($podfile, $podout);
+
+ close $podfile;
+ close $podout or die "close: $!";
+
+ next PODSEARCH unless $namesect;
+
+ # Remove formatting codes.
+ $namesect =~ s{ [IBCLEFSXZ] <(.*?)> }{$1}gxms;
+ $namesect =~ s{ [IBCLEFSXZ] <<(.*?)>> }{$1}gxms;
+
+ # The short desc is on a line beginning with 'Module::Name - '
+ if ( $namesect =~ / ^ \s* $modname [ -]+ ([^\n]+) /xms ) {
+ print STDERR qq{Found description "$1" in POD};
+ return $1;
+ }
+ }
+
+ return undef;
+}
+
+#---HELPER FUNCTION---
+sub _readmedesc
+{
+ my ($dir, $modname) = @_;
+
+ my $path = catfile($dir, 'README');
+ return undef unless -f $path;
+ open my $fh, '<', $path or die "open: $!";
+
+ while (<$fh>) {
+ chomp;
+ next unless /\ANAME/ ... /\A[A-Z]+/
+ and / \A \s* ${modname} [\s\-]+ (.+) \z /x;
+ print STDERR qq{Found description "$1" in README};
+ return $1;
+ }
+
+ close $fh;
+ return undef;
+}
+
+#-----------------------------------------------------------------------------
+
+sub md5sums
+{
+ return [ map {
+ open my $fh, '<', $_ or die "open: $!";
+ my $md5 = Digest::MD5->new()->addfile($fh)->hexdigest;
+ } @_ ]
+}
+
+sub sha512sums
+{
+ return [ map {
+ my $sha = Digest::SHA->new()->addfile($_)->hexdigest;
+ } @_ ]
+}
+
+main(@ARGV);
diff --git a/bin/pbj b/bin/pbj
new file mode 100755
index 0000000..ac926b6
--- /dev/null
+++ b/bin/pbj
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+VERSION=0.01
+
+die() {
+ echo "error: $1"
+ exit 1
+}
+
+if [ -z "$1" ] ; then
+ die "Usage: $0 [package name]"
+fi
+
+if [ "$PBJROOT" ] ; then
+ cd "$PBJROOT"
+fi
+
+bindir="$(pwd)/bin"
+if [ ! -d "$bindir" ] ; then
+ die "$bindir does not exist"
+fi
+PATH="$PATH:$bindir"
+
+pkgroot="$(pwd)/pkg"
+if [ ! -d "$pkgroot" ] ; then
+ die "$pkgroot does not exist"
+fi
+
+jamdir="$(pwd)/pbj"
+if [ ! -d "$jamdir" ] ; then
+ die "$jamdir does not exist"
+fi
+
+jamfile="$jamdir/$1.pbj"
+if [ ! -f "$jamfile" ] ; then
+ die "$jamfile is missing"
+fi
+
+pkg=$1
+rm -rf "$pkgroot/$pkg"
+mkdir "$pkgroot/$pkg"
+cd "$pkgroot/$pkg"
+
+export PATH="$PATH:$bindir/macros:$bindir/templ"
+
+# Provide values for things macros won't be able to.
+printf "+ pbjver $VERSION\n+ pkgrel ${PKGREL:-1}\n" \
+ | cat - "$jamfile" \
+ | awk -v packager="$PACKAGER" -f "$bindir/pbjparse.awk" \
+ > PKGBUILD
+
+if [ $? -ne 0 ] ; then
+ echo "Failed to write $pkgroot/$pkg/PKGBUILD"
+ exit $?
+fi
+
+echo "Wrote $pkgroot/$pkg/PKGBUILD."
+exit 0
diff --git a/bin/pbjparse.awk b/bin/pbjparse.awk
new file mode 100755
index 0000000..d5e89ff
--- /dev/null
+++ b/bin/pbjparse.awk
@@ -0,0 +1,119 @@
+# pbjparse.awk
+##
+# Parse a PBJ data file and print a PBDATA datafile to STDOUT.
+# Justin Davis <jrcd83@gmail.com>
+
+BEGIN {
+ templcount = 0 # number of templates that will be in the templates array
+ PROG = "pbjparse"
+}
+
+{ parsepbj() }
+
+END {
+ tcmd = ""
+ if (templcount > 0) {
+ tcmd = templates[1]
+ for (i=2; i<=templcount; i++) tcmd = "|" templates[i]
+ }
+ else tcmd = "cat"
+
+ for (key in pbvars) {
+ split(key, keys, SUBSEP)
+
+ if (keys[2] != "len") continue
+ name = keys[1]
+ len = pbvars[key]
+
+ print name | tcmd
+ for (i=1; i<=len; i++) print pbvars[name,i] | tcmd
+ print "" | tcmd
+ }
+
+ if (optdepcount > 0) {
+ print "optdepends" | tcmd
+ for (name in optdeps) print optdeps[name]
+ print "" | tcmd
+ }
+
+ if (!seenpkgr) print "packager\n" packager "\n\n" | tcmd
+}
+
+function parsepbj ( cmd)
+{
+ # Ignore comments.
+ sub(/#.*/, "")
+
+ # Optdeps are special. In an annoying way.
+ if ($1 == "+") {
+ if ($2 == "optdepends") {
+ msg = $3
+ for (i=4; i<=NF; i++) msg = msg " " $i
+
+ ++optdepcount
+ name = optdepname($3)
+ optdeps[name] = msg
+
+ remdep("depends", name)
+ remdep("makedeps", name)
+ }
+ else {
+ # We print the default packager if none was seen.
+ if ($2 == "packager") seenpkgr = 1
+
+ val = $3
+ for (i=4; i<=NF; i++) val = val " " $i
+ pbvars[$2, ++pbvars[$2,"len"]] = val
+ }
+ }
+ else if ($1 == "-") {
+ if ($2 == "optdepends")
+ die("cannot delete an optdep once it is created.")
+ remdep($2, $3)
+ }
+ else if ($1 == "!") {
+ cmd = $2
+ for (i=3; i<=NF; i++) cmd = cmd " " $i
+
+ while ((ret = cmd | getline) > 0) parsepbj()
+ if (ret == -1) die("failed to run $cmd")
+ close(cmd)
+ }
+ else if ($1 == "|") {
+ tcmd = $2
+ for (i=3; i<=NF; i++) tcmd = tcmd " " $i
+ templates[++templcount] = tcmd
+ }
+ else if ($1 == "") ; # ignore blank lines
+ else {
+ print "ignoring line " FNR ": " $0 | "cat 1>&2"
+ }
+}
+
+function die (msg)
+{
+ printf "%s:%s.%d:%s\n", PROG, FILENAME, FNR, msg | "cat 1>&2"
+ exit 1
+}
+
+function remdep (name, prefix)
+{
+ len = pbvars[name, "len"]
+ if (len == 0) return
+
+ for (i=1; i<=len; i++)
+ if (pbvars[name, i] ~ "^" prefix) break
+
+ if (i > len) die("could not find " prefix " in " name)
+
+ while (i < len) { pbvars[name, i] = pbvars[name, i+1]; i++ }
+ delete pbvars[name, i]
+ pbvars[name, "len"]--
+}
+
+function optdepname (msgbeg)
+{
+ if (! match(msgbeg, "^[a-z_-]+:"))
+ die("failed to extract name from optdept")
+ return substr(msgbeg, 1, RLENGTH-1)
+}
diff --git a/bin/templ/perl-pkg b/bin/templ/perl-pkg
new file mode 100755
index 0000000..92dd43a
--- /dev/null
+++ b/bin/templ/perl-pkg
@@ -0,0 +1,145 @@
+#!/Users/juster/perl5/perlbrew/perls/perl-5.14.1/bin/perl
+
+use warnings 'FATAL' => 'all';
+use strict;
+
+use Text::Wrap qw(wrap);
+
+my %ACTIONS_OF = ('MM',
+ { 'build' => [ q{/usr/bin/perl Makefile.PL}, q{make} ],
+ 'check' => [ q{make test} ],
+ 'package' => [ q{make DESTDIR="$pkgdir" install} ]
+ },
+ 'MB',
+ { 'build' => [ q{/usr/bin/perl Build.PL}, q{./Build} ],
+ 'check' => [ q{./Build test} ],
+ 'package' => [ q{./Build install} ]
+ } );
+
+my $PBBEG = <<'END_BEG';
+# Maintainer : {: packager :}
+# Generator : pbjam {: pbjver :}
+
+pkgname={: pkgname :}
+pkgver={: pkgver :}
+pkgrel={: pkgrel :}
+pkgdesc={: pkgdesc :}
+arch=({: arch :})
+license=(PerlArtistic GPL)
+options=('!emptydirs')
+depends=({: depends :})
+makedepends=({: makedepends :})
+url={: url :}
+source=({: source :})
+md5sums=({: md5sums :})
+sha512sums=({: sha512sums :})
+_distdir="${srcdir}/{: distdir :}"
+END_BEG
+
+my %FUNCFMTS;
+$FUNCFMTS{'build'} = <<'END_FMT';
+build() {
+ ( export PERL_MM_USE_DEFAULT=1 PERL5LIB="" \
+ PERL_AUTOINSTALL=--skipdeps \
+ PERL_MM_OPT="INSTALLDIRS=vendor DESTDIR='$pkgdir'" \
+ PERL_MB_OPT="--installdirs vendor --destdir '$pkgdir'" \
+ MODULEBUILDRC=/dev/null
+
+ cd "$_distdir"
+%s
+ )
+}
+END_FMT
+
+$FUNCFMTS{'check'} = <<'END_FMT';
+check() {
+ ( export PERL_MM_USE_DEFAULT=1 PERL5LIB=""
+ cd "$_distdir"
+%s
+ )
+}
+END_FMT
+
+$FUNCFMTS{'package'} = <<'END_FMT';
+package() {
+ cd "$_distdir"
+%s
+ find "$pkgdir" -name .packlist -o -name perllocal.pod -delete
+}
+END_FMT
+
+my $PBEND = <<'END_END';
+# Local Variables:
+# mode: shell-script
+# sh-basic-offset: 2
+# End:
+# vim:set ts=2 sw=2 et:
+END_END
+
+# Expands one variable into its bash string representation.
+sub expandvar
+{
+ my ($pbvars, $name) = @_;
+
+ my $val = $pbvars->{$1};
+ if ($name eq 'pkgdesc') {
+ $val->[0] =~ s/([\$\"\`])/\\$1/g;
+ return qq{"$val->[0]"};
+ }
+ elsif ($name =~ /depends$/) {
+ my @deps = map { qq{'$_'} } @$val;
+ return wrap(q{}, q{ } x (length($name) + 2), @deps);
+ }
+ return ($val ? join q{ }, @$val : q{});
+}
+
+# Expand variables used in the template text.
+sub expandvars
+{
+ my ($tmpl, $pbvars) = @_;
+
+ my $txt = $tmpl;
+ $txt =~ s/ {: \s* (\w+) \s* :} /expandvar($pbvars, $1)/gex;
+ return $txt;
+}
+
+# Convert actions array into lines of bash to insert into template.
+sub bashify
+{
+ my (@lines) = @_;
+# use Data::Dump qw(dump);
+# print STDERR dump($lines), "\n";
+ my $txt = join qq{\n}, map { s/^/ /gm; $_ } @lines;
+ return $txt
+}
+
+sub printpb
+{
+ my ($btype, $pbvars) = @_;
+ my $acts = $ACTIONS_OF{$btype}
+ or die "$0: unknown build type ($btype)\n";
+
+ print expandvars($PBBEG, $pbvars), "\n";
+ for my $func (qw/build check package/) {
+ printf $FUNCFMTS{$func}, bashify(@{$acts->{$func}});
+ print "\n";
+ }
+ print $PBEND;
+}
+
+sub readvars
+{
+ my %pbvars;
+ my $name;
+ local $/ = ""; # split records on empty lines
+ while (<STDIN>) {
+ my ($name, @vals) = split /\n/;
+ $pbvars{$name} = \@vals;
+ }
+
+ return \%pbvars;
+}
+
+my $type = shift or die qq{$0: please provide "MM" or "MB" as argument\n};
+my $vars = readvars();
+printpb($type, $vars);
diff --git a/pbj/perl-moose.pbj b/pbj/perl-moose.pbj
new file mode 100644
index 0000000..cb2509e
--- /dev/null
+++ b/pbj/perl-moose.pbj
@@ -0,0 +1,4 @@
+# A prototype, by Justin "juster" Davis
+! perl-cpan Moose
++ replaces perl-class-mop
++ conflicts perl-class-mop