tokuhirom's Blog

use Daiku for very customizable Makefile.PL

Module::Install::TestTargets is cool *hack*. But it's code is too complex and the code using it is not maintainable.

So here is yet another approach for this issue using Daiku.

↓Makefile using Daiku and other ExUtils::* modules.

use Daiku;
use autodie ':all';
use ExtUtils::InstallPaths;
use CPAN::Meta ();
use File::Find::Rule ();
use File::Spec::Functions qw/catfile catdir rel2abs/;
use ExtUtils::Helpers 0.007 qw/make_executable split_like_shell build_script manify man1_pagename man3_pagename/;
use ExtUtils::Install qw/pm_to_blib install/;

sub load_meta {
	my ($metafile) = grep { -e $_ } qw/META.json META.yml/ or die "No META information provided\n";
	return CPAN::Meta->load_file($metafile);
}

my @MODULES = File::Find::Rule::find(file => name => [qw/*.pm *.pod/], in => 'lib');
my @SCRIPTS = File::Find::Rule::find(file => name => '*', in => 'script');

task 'all' => ['build'];

task 'init' => ['Makefile'] => sub {
	0
};

task 'build' => [@MODULES, @SCRIPTS] => sub {
	my %opt;

	pm_to_blib({ map { $_ => catfile('blib', $_) } @MODULES, @SCRIPTS }, catdir(qw/blib lib auto/));
	make_executable($_) for File::Find::Rule::find(file => in => catdir(qw/blib script/));
	manify($_, catdir('blib', 'bindoc', man1_pagename($_)), 1, \%opt) for @SCRIPTS;
	manify($_, catdir('blib', 'libdoc', man3_pagename($_)), 3, \%opt) for @MODULES;
	chmod +(stat $_)[2] & ~0222, $_ for map { catfile('blib', $_) } @SCRIPTS, @MODULES;
};

task 'install' => ['build'] => sub {
	my %opt;

	my $meta = load_meta();
	my $paths = ExtUtils::InstallPaths->new(%opt, dist_name => $meta->name);
	install($paths->install_map, @opt{'verbose', 'dry_run', 'uninst'});
};

# silly hack
file 'Makefile' => ['Makefile.PL'] => sub {
	open my $fh, '>', 'Makefile';
	for (qw/all test clean install/) {
		print {$fh}   "$_:\n"
					. "\t$^X $0 $_\n\n";
	}
	close $fh;
};

task 'clean' => sub {
	for (qw/Makefile/) {
		unlink $_ if -f $_
	}
};

task 'test' => ['build'] => sub {
	system 'prove -Ilib t/';
};

build(shift @ARGV || 'init');

↓META.json describes dependencies.

{
   "resources" : {
      "license" : "http://dev.perl.org/licenses/"
   },
   "no_index" : {
      "directory" : [
         "inc",
         "t",
         "xt"
      ]
   },
   "meta-spec" : {
      "version" : "1.4",
      "url" : "http://module-build.sourceforge.net/META-spec-v1.4.html"
   },
   "distribution_type" : "module",
   "version" : "0.01",
   "name" : "example",
   "author" : [
      "Tokuhiro Matsuno <tokuhirom AAJKLFJEF GMAIL COM>"
   ],
   "license" : "perl",
   "build_requires" : {
      "Test::More" : "0.96",
      "ExtUtils::MakeMaker" : "6.42"
   },
   "requires" : {
      "perl" : "5.8.1",
      "Mouse" : "0.92"
   },
   "abstract" : "Make for Perl",
   "configure_requires" : {
      "ExtUtils::MakeMaker" : "6.42",
      "Daiku" : "0.03",
      "CPAN::Meta" : 0,
      "ExtUtils::Helpers" : "0.007",
      "ExtUtils::Install" : 0,
      "ExtUtils::InstallPaths" : "0.002",
      "File::Find::Rule" : 0,
      "File::Slurp" : 0,
      "File::Spec::Functions" : 0,
      "Getopt::Long" : 0,
      "JSON" : "2"
   }
}

I think this approach is very useful to development your own application, is not deploying to CPAN.