3 use vars qw/$VERSION @ISA @EXPORT @EXPORT_OK/;
25 use Carp qw/carp croak/;
30 PAR::Dist - Create and manipulate PAR distributions
34 This document describes version 0.29 of PAR::Dist, released Feb 6, 2008.
40 % perl -MPAR::Dist -eblib_to_par
46 my $dist = blib_to_par(); # make a PAR file using ./blib/
47 install_par($dist); # install it into the system
48 uninstall_par($dist); # uninstall it from the system
49 sign_par($dist); # sign it using Module::Signature
50 verify_par($dist); # verify it using Module::Signature
52 install_par("http://foo.com/DBI-1.37-MSWin32-5.8.0.par"); # works too
53 install_par("http://foo.com/DBI-1.37"); # auto-appends archname + perlver
54 install_par("cpan://SMUELLER/PAR-Packer-0.975"); # uses CPAN author directory
58 This module creates and manipulates I<PAR distributions>. They are
59 architecture-specific B<PAR> files, containing everything under F<blib/>
60 of CPAN distributions after their C<make> or C<Build> stage, a
61 F<META.yml> describing metadata of the original CPAN distribution,
62 and a F<MANIFEST> detailing all files within it. Digitally signed PAR
63 distributions will also contain a F<SIGNATURE> file.
65 The naming convention for such distributions is:
67 $NAME-$VERSION-$ARCH-$PERL_VERSION.par
69 For example, C<PAR-Dist-0.01-i386-freebsd-5.8.0.par> corresponds to the
70 0.01 release of C<PAR-Dist> on CPAN, built for perl 5.8.0 running on
75 Several functions are exported by default. Unless otherwise noted,
76 they can take either a hash of
77 named arguments, a single argument (taken as C<$path> by C<blib_to_par>
78 and C<$dist> by other functions), or no arguments (in which case
79 the first PAR file in the current directory is used).
81 Therefore, under a directory containing only a single F<test.par>, all
82 invocations below are equivalent:
84 % perl -MPAR::Dist -e"install_par( dist => 'test.par' )"
85 % perl -MPAR::Dist -e"install_par( 'test.par' )"
86 % perl -MPAR::Dist -einstall_par;
88 If C<$dist> resembles a URL, C<LWP::Simple::mirror> is called to mirror it
89 locally under C<$ENV{PAR_TEMP}> (or C<$TEMP/par/> if unspecified), and the
90 function will act on the fetched local file instead. If the URL begins
91 with C<cpan://AUTHOR/>, it will be expanded automatically to the author's CPAN
92 directory (e.g. C<http://www.cpan.org/modules/by-authors/id/A/AU/AUTHOR/>).
94 If C<$dist> does not have a file extension beginning with a letter or
95 underscore, a dash and C<$suffix> ($ARCH-$PERL_VERSION.par by default)
96 will be appended to it.
100 Takes key/value pairs as parameters or a single parameter indicating the
101 path that contains the F<blib/> subdirectory.
103 Builds a PAR distribution from the F<blib/> subdirectory under C<path>, or
104 under the current directory if unspecified. If F<blib/> does not exist,
105 it automatically runs F<Build>, F<make>, F<Build.PL> or F<Makefile.PL> to
108 Returns the filename or the generated PAR distribution.
110 Valid parameters are:
116 Sets the path which contains the F<blib/> subdirectory from which the PAR
117 distribution will be generated.
119 =item name, version, suffix
121 These attributes set the name, version and platform specific suffix
122 of the distribution. Name and version can be automatically
123 determined from the distributions F<META.yml> or F<Makefile.PL> files.
125 The suffix is generated from your architecture name and your version of
130 The output filename for the PAR distribution.
137 @_ = (path => @_) if @_ == 1;
143 # don't use 'my $foo ... if ...' it creates a static variable!
145 my $path = $args{path};
146 $dist = File::Spec->rel2abs($args{dist}) if $args{dist};
147 my $name = $args{name};
148 my $version = $args{version};
149 my $suffix = $args{suffix} || "$Config::Config{archname}-$Config::Config{version}.par";
158 _build_blib() unless -d "blib";
161 open MANIFEST, ">", File::Spec->catfile("blib", "MANIFEST") or die $!;
162 open META, ">", File::Spec->catfile("blib", "META.yml") or die $!;
165 File::Find::find( sub {
166 next unless $File::Find::name;
167 (-r && !-d) and push ( @files, substr($File::Find::name, 5) );
172 ' <!-- accessible as jar:file:///NAME.par!/MANIFEST in compliant browsers -->',
174 q( # <html><body onload="var X=document.body.innerHTML.split(/\n/);var Y='<iframe src="META.yml" style="float:right;height:40%;width:40%"></iframe><ul>';for(var x in X){if(!X[x].match(/^\s*#/)&&X[x].length)Y+='<li><a href="'+X[x]+'">'+X[x]+'</a>'}document.body.innerHTML=Y">)
178 if (open(OLD_META, "META.yml")) {
180 if (/^distribution_type:/) {
181 print META "distribution_type: par\n";
187 if (/^name:\s+(.*)/) {
191 elsif (/^version:\s+.*Module::Build::Version/) {
193 /^\s+original:\s+(.*)/ or next;
198 elsif (/^version:\s+(.*)/) {
206 if ((!$name or !$version) and open(MAKEFILE, "Makefile")) {
208 if (/^DISTNAME\s+=\s+(.*)$/) {
211 elsif (/^VERSION\s+=\s+(.*)$/) {
217 if (not defined($name) or not defined($version)) {
218 # could not determine name or version. Error.
220 if (not defined $name) {
222 $what .= ' and version' if not defined $version;
224 elsif (not defined $version) {
228 carp("I was unable to determine the $what of the PAR distribution. Please create a Makefile or META.yml file from which we can infer the information or just specify the missing information as an option to blib_to_par.");
233 $version =~ s/\s+$//;
235 my $file = "$name-$version-$suffix";
236 unlink $file if -f $file;
238 print META << "YAML" if fileno(META);
244 distribution_type: par
246 generated_by: 'PAR::Dist version $PAR::Dist::VERSION'
253 _zip(dist => File::Spec->catfile(File::Spec->updir, $file)) or die $!;
254 chdir(File::Spec->updir);
256 unlink File::Spec->catfile("blib", "MANIFEST");
257 unlink File::Spec->catfile("blib", "META.yml");
259 $dist ||= File::Spec->catfile($cwd, $file) if $cwd;
261 if ($dist and $file ne $dist) {
262 rename( $file => $dist );
266 my $pathname = File::Spec->rel2abs($file);
267 if ($^O eq 'MSWin32') {
268 $pathname =~ s!\\!/!g;
269 $pathname =~ s!:!|!g;
272 Successfully created binary distribution '$file'.
273 Its contents are accessible in compliant browsers as:
274 jar:file://$pathname!/MANIFEST
283 system($^X, "Build");
285 elsif (-e 'Makefile') {
286 system($Config::Config{make});
288 elsif (-e 'Build.PL') {
289 system($^X, "Build.PL");
290 system($^X, "Build");
292 elsif (-e 'Makefile.PL') {
293 system($^X, "Makefile.PL");
294 system($Config::Config{make});
300 Installs a PAR distribution into the system, using
301 C<ExtUtils::Install::install_default>.
303 Valid parameters are:
309 The .par file to install. The heuristics outlined in the B<FUNCTIONS>
314 This string will be prepended to all installation paths.
315 If it isn't specified, the environment variable
316 C<PERL_INSTALL_ROOT> is used as a prefix.
320 Additionally, you can use several parameters to change the default
321 installation destinations. You don't usually have to worry about this
322 unless you are installing into a user-local directory.
323 The following section outlines the parameter names and default settings:
326 inst_lib blib/lib $Config{installsitelib} (*)
327 inst_archlib blib/arch $Config{installsitearch}
328 inst_script blib/script $Config{installscript}
329 inst_bin blib/bin $Config{installbin}
330 inst_man1dir blib/man1 $Config{installman1dir}
331 inst_man3dir blib/man3 $Config{installman3dir}
332 packlist_read $Config{sitearchexp}/auto/$name/.packlist
333 packlist_write $Config{installsitearch}/auto/$name/.packlist
335 The C<packlist_write> parameter is used to control where the F<.packlist>
336 file is written to. (Necessary for uninstallation.)
337 The C<packlist_read> parameter specifies a .packlist file to merge in if
338 it exists. By setting any of the above installation targets to C<undef>,
339 you can remove that target altogether. For example, passing
340 C<inst_man1dir => undef, inst_man3dir => undef> means that the contained
341 manual pages won't be installed. This is not available for the packlists.
343 Finally, you may specify a C<custom_targets> parameter. Its value should be
344 a reference to a hash of custom installation targets such as
346 custom_targets => { 'blib/my_data' => '/some/path/my_data' }
348 You can use this to install the F<.par> archives contents to arbitrary
351 If only a single parameter is given, it is treated as the C<dist>
358 _install_or_uninstall(%args, action => 'install');
363 Uninstalls all previously installed contents of a PAR distribution,
364 using C<ExtUtils::Install::uninstall>.
366 Takes almost the same parameters as C<install_par>, but naturally,
367 the installation target parameters do not apply. The only exception
368 to this is the C<packlist_read> parameter which specifies the
369 F<.packlist> file to read the list of installed files from.
370 It defaults to C<$Config::Config{installsitearch}/auto/$name/.packlist>.
376 _install_or_uninstall(%args, action => 'uninstall');
379 sub _install_or_uninstall {
381 my $name = $args{name};
382 my $action = $args{action};
385 $ENV{PERL_INSTALL_ROOT} = $args{prefix} if defined $args{prefix};
388 my $old_dir = Cwd::cwd();
390 my ($dist, $tmpdir) = _unzip_to_tmpdir( dist => $args{dist}, subdir => 'blib' );
392 if ( open (META, File::Spec->catfile('blib', 'META.yml')) ) {
394 next unless /^name:\s+(.*)/;
401 return if not defined $name or $name eq '';
404 require ExtUtils::MY;
405 foreach my $file (glob("script/*")) {
406 next unless -T $file;
407 ExtUtils::MY->fixin($file);
412 $name =~ s{::|-}{/}g;
413 require ExtUtils::Install;
416 if ($action eq 'install') {
417 my $target = _installation_target( File::Spec->curdir, $name, \%args );
418 my $custom_targets = $args{custom_targets} || {};
419 $target->{$_} = $custom_targets->{$_} foreach keys %{$custom_targets};
421 $rv = ExtUtils::Install::install($target, 1, 0, 0);
423 elsif ($action eq 'uninstall') {
425 $rv = ExtUtils::Install::uninstall(
426 $args{packlist_read}||"$Config::Config{installsitearch}/auto/$name/.packlist"
433 File::Path::rmtree([$tmpdir]);
437 # Returns the default installation target as used by
438 # ExtUtils::Install::install(). First parameter should be the base
439 # directory containing the blib/ we're installing from.
440 # Second parameter should be the name of the distribution for the packlist
441 # paths. Third parameter may be a hash reference with user defined keys for
442 # the target hash. In fact, any contents that do not start with 'inst_' are
444 sub _installation_target {
448 my $user = shift || {};
450 # accepted sources (and user overrides)
452 inst_lib => File::Spec->catdir($dir,"blib","lib"),
453 inst_archlib => File::Spec->catdir($dir,"blib","arch"),
454 inst_bin => File::Spec->catdir($dir,'blib','bin'),
455 inst_script => File::Spec->catdir($dir,'blib','script'),
456 inst_man1dir => File::Spec->catdir($dir,'blib','man1'),
457 inst_man3dir => File::Spec->catdir($dir,'blib','man3'),
458 packlist_read => 'read',
459 packlist_write => 'write',
465 read => $Config::Config{sitearchexp}."/auto/$name/.packlist",
466 write => $Config::Config{installsitearch}."/auto/$name/.packlist",
468 => (_directory_not_empty($sources{inst_archlib}))
469 ? $Config::Config{installsitearch}
470 : $Config::Config{installsitelib},
471 $sources{inst_archlib} => $Config::Config{installsitearch},
472 $sources{inst_bin} => $Config::Config{installbin} ,
473 $sources{inst_script} => $Config::Config{installscript},
474 $sources{inst_man1dir} => $Config::Config{installman1dir},
475 $sources{inst_man3dir} => $Config::Config{installman3dir},
478 # Included for future support for ${flavour}perl external lib installation
479 # if ($Config::Config{flavour_perl}) {
480 # my $ext = File::Spec->catdir($dir, 'blib', 'ext');
482 # $sources{inst_external_lib} = File::Spec->catdir($ext, 'lib');
483 # $sources{inst_external_bin} = File::Spec->catdir($ext, 'bin');
484 # $sources{inst_external_include} = File::Spec->catdir($ext, 'include');
485 # $sources{inst_external_src} = File::Spec->catdir($ext, 'src');
486 # $target->{ $sources{inst_external_lib} } = $Config::Config{flavour_install_lib};
487 # $target->{ $sources{inst_external_bin} } = $Config::Config{flavour_install_bin};
488 # $target->{ $sources{inst_external_include} } = $Config::Config{flavour_install_include};
489 # $target->{ $sources{inst_external_src} } = $Config::Config{flavour_install_src};
492 # insert user overrides
493 foreach my $key (keys %$user) {
494 my $value = $user->{$key};
495 if (not defined $value and $key ne 'packlist_read' and $key ne 'packlist_write') {
496 # undef means "remove"
497 delete $target->{ $sources{$key} };
499 elsif (exists $sources{$key}) {
500 # overwrite stuff, don't let the user create new entries
501 $target->{ $sources{$key} } = $value;
508 sub _directory_not_empty {
512 File::Find::find(sub {
513 return if $_ eq ".exists";
515 $File::Find::prune++;
524 Digitally sign a PAR distribution using C<gpg> or B<Crypt::OpenPGP>,
525 via B<Module::Signature>.
531 _verify_or_sign(%args, action => 'sign');
536 Verify the digital signature of a PAR distribution using C<gpg> or
537 B<Crypt::OpenPGP>, via B<Module::Signature>.
539 Returns a boolean value indicating whether verification passed; C<$!>
540 is set to the return code of C<Module::Signature::verify>.
546 $! = _verify_or_sign(%args, action => 'verify');
547 return ( $! == Module::Signature::SIGNATURE_OK() );
552 Merge two or more PAR distributions into one. First argument must
553 be the name of the distribution you want to merge all others into.
554 Any following arguments will be interpreted as the file names of
555 further PAR distributions to merge into the first one.
557 merge_par('foo.par', 'bar.par', 'baz.par')
559 This will merge the distributions C<foo.par>, C<bar.par> and C<baz.par>
560 into the distribution C<foo.par>. C<foo.par> will be overwritten!
561 The original META.yml of C<foo.par> is retained.
566 my $base_par = shift;
567 my @additional_pars = @_;
574 if (not defined $base_par) {
575 croak "First argument to merge_par() must be the .par archive to modify.";
578 if (not -f $base_par or not -r _ or not -w _) {
579 croak "'$base_par' is not a file or you do not have enough permissions to read and modify it.";
582 foreach (@additional_pars) {
583 if (not -f $_ or not -r _) {
584 croak "'$_' is not a file or you do not have enough permissions to read it.";
588 # The unzipping will change directories. Remember old dir.
589 my $old_cwd = Cwd::cwd();
591 # Unzip the base par to a temp. dir.
592 (undef, my $base_dir) = _unzip_to_tmpdir(
593 dist => $base_par, subdir => 'blib'
595 my $blibdir = File::Spec->catdir($base_dir, 'blib');
597 # move the META.yml to the (main) temp. dir.
599 File::Spec->catfile($blibdir, 'META.yml'),
600 File::Spec->catfile($base_dir, 'META.yml')
602 # delete (incorrect) MANIFEST
603 unlink File::Spec->catfile($blibdir, 'MANIFEST');
605 # extract additional pars and merge
606 foreach my $par (@additional_pars) {
607 # restore original directory because the par path
608 # might have been relative!
610 (undef, my $add_dir) = _unzip_to_tmpdir(
616 # And I hate writing portable code, too.
619 my $file = $File::Find::name;
620 push @files, $file if -f $file;
621 push @dirs, $file if -d _;
625 my ($vol, $subdir, undef) = File::Spec->splitpath( $add_dir, 1);
626 my @dir = File::Spec->splitdir( $subdir );
628 # merge directory structure
629 foreach my $dir (@dirs) {
630 my ($v, $d, undef) = File::Spec->splitpath( $dir, 1 );
631 my @d = File::Spec->splitdir( $d );
632 shift @d foreach @dir; # remove tmp dir from path
633 my $target = File::Spec->catdir( $blibdir, @d );
638 foreach my $file (@files) {
639 my ($v, $d, $f) = File::Spec->splitpath( $file );
640 my @d = File::Spec->splitdir( $d );
641 shift @d foreach @dir; # remove tmp dir from path
642 my $target = File::Spec->catfile(
643 File::Spec->catdir( $blibdir, @d ),
646 File::Copy::copy($file, $target)
647 or die "Could not copy '$file' to '$target': $!";
651 File::Path::rmtree([$add_dir]);
654 # delete (copied) MANIFEST and META.yml
655 unlink File::Spec->catfile($blibdir, 'MANIFEST');
656 unlink File::Spec->catfile($blibdir, 'META.yml');
659 my $resulting_par_file = Cwd::abs_path(blib_to_par());
661 File::Copy::move($resulting_par_file, $base_par);
663 File::Path::rmtree([$base_dir]);
669 Remove the man pages from a PAR distribution. Takes one named
670 parameter: I<dist> which should be the name (and path) of the
671 PAR distribution file. The calling conventions outlined in
672 the C<FUNCTIONS> section above apply.
674 The PAR archive will be
675 extracted, stripped of all C<man\d?> and C<html> subdirectories
676 and then repackaged into the original file.
682 my $par = $args{dist};
689 if (not defined $par) {
690 croak "First argument to remove_man() must be the .par archive to modify.";
693 if (not -f $par or not -r _ or not -w _) {
694 croak "'$par' is not a file or you do not have enough permissions to read and modify it.";
697 # The unzipping will change directories. Remember old dir.
698 my $old_cwd = Cwd::cwd();
700 # Unzip the base par to a temp. dir.
701 (undef, my $base_dir) = _unzip_to_tmpdir(
702 dist => $par, subdir => 'blib'
704 my $blibdir = File::Spec->catdir($base_dir, 'blib');
706 # move the META.yml to the (main) temp. dir.
708 File::Spec->catfile($blibdir, 'META.yml'),
709 File::Spec->catfile($base_dir, 'META.yml')
711 # delete (incorrect) MANIFEST
712 unlink File::Spec->catfile($blibdir, 'MANIFEST');
714 opendir DIRECTORY, 'blib' or die $!;
715 my @dirs = grep { /^blib\/(?:man\d*|html)$/ }
717 map { File::Spec->catfile('blib', $_) }
721 File::Path::rmtree(\@dirs);
724 my $resulting_par_file = Cwd::abs_path(blib_to_par());
726 File::Copy::move($resulting_par_file, $par);
728 File::Path::rmtree([$base_dir]);
734 Opens a PAR archive and extracts the contained META.yml file.
735 Returns the META.yml file as a string.
737 Takes one named parameter: I<dist>. If only one parameter is
738 passed, it is treated as the I<dist> parameter. (Have a look
739 at the description in the C<FUNCTIONS> section above.)
741 Returns undef if no PAR archive or no META.yml within the
748 my $dist = $args{dist};
749 return undef if not defined $dist or not -r $dist;
753 # The unzipping will change directories. Remember old dir.
754 my $old_cwd = Cwd::cwd();
756 # Unzip the base par to a temp. dir.
757 (undef, my $base_dir) = _unzip_to_tmpdir(
758 dist => $dist, subdir => 'blib'
760 my $blibdir = File::Spec->catdir($base_dir, 'blib');
762 my $meta = File::Spec->catfile($blibdir, 'META.yml');
769 or die "Could not open file '$meta' for reading: $!";
772 my $meta_text = <FH>;
777 File::Path::rmtree([$base_dir]);
786 my $dist = $args{dist};
787 my $path = $args{path} || File::Spec->curdir;
788 return unless -f $dist;
790 # Try fast unzipping first
791 if (eval { require Archive::Unzip::Burst; 1 }) {
792 my $return = Archive::Unzip::Burst::unzip($dist, $path);
793 return if $return; # true return value == error (a la system call)
795 # Then slow unzipping
796 if (eval { require Archive::Zip; 1 }) {
797 my $zip = Archive::Zip->new;
799 $SIG{__WARN__} = sub { print STDERR $_[0] unless $_[0] =~ /\bstat\b/ };
800 return unless $zip->read($dist) == Archive::Zip::AZ_OK()
801 and $zip->extractTree('', "$path/") == Archive::Zip::AZ_OK();
803 # Then fall back to the system
805 return if system(unzip => $dist, '-d', $path);
813 my $dist = $args{dist};
815 if (eval { require Archive::Zip; 1 }) {
816 my $zip = Archive::Zip->new;
817 $zip->addTree( File::Spec->curdir, '' );
818 $zip->writeToFileNamed( $dist ) == Archive::Zip::AZ_OK() or die $!;
821 system(qw(zip -r), $dist, File::Spec->curdir) and die $!;
826 # This sub munges the arguments to most of the PAR::Dist functions
827 # into a hash. On the way, it downloads PAR archives as necessary, etc.
829 # default to the first .par in the CWD
831 @_ = (glob('*.par'))[0];
834 # single argument => it's a distribution file name or URL
835 @_ = (dist => @_) if @_ == 1;
838 $args{name} ||= $args{dist};
840 # If we are installing from an URL, we want to munge the
841 # distribution name so that it is in form "Module-Name"
842 if (defined $args{name}) {
843 $args{name} =~ s/^\w+:\/\///;
844 my @elems = parse_dist_name($args{name});
845 # @elems is name, version, arch, perlversion
846 if (defined $elems[0]) {
847 $args{name} = $elems[0];
850 $args{name} =~ s/^.*\/([^\/]+)$/$1/;
851 $args{name} =~ s/^([0-9A-Za-z_-]+)-\d+\..+$/$1/;
855 # append suffix if there is none
856 if ($args{dist} and not $args{dist} =~ /\.[a-zA-Z_][^.]*$/) {
858 my $suffix = $args{suffix};
859 $suffix ||= "$Config::Config{archname}-$Config::Config{version}.par";
860 $args{dist} .= "-$suffix";
863 # download if it's an URL
864 if ($args{dist} and $args{dist} =~ m!^\w+://!) {
865 $args{dist} = _fetch(dist => $args{dist})
872 # Download PAR archive, but only if necessary (mirror!)
877 if ($args{dist} =~ s/^file:\/\///) {
878 return $args{dist} if -e $args{dist};
883 $ENV{PAR_TEMP} ||= File::Spec->catdir(File::Spec->tmpdir, 'par');
884 mkdir $ENV{PAR_TEMP}, 0777;
885 %escapes = map { chr($_) => sprintf("%%%02X", $_) } 0..255 unless %escapes;
887 $args{dist} =~ s{^cpan://((([a-zA-Z])[a-zA-Z])[-_a-zA-Z]+)/}
888 {http://www.cpan.org/modules/by-authors/id/\U$3/$2/$1\E/};
890 my $file = $args{dist};
891 $file =~ s/([^\w\.])/$escapes{$1}/g;
892 $file = File::Spec->catfile( $ENV{PAR_TEMP}, $file);
893 my $rc = LWP::Simple::mirror( $args{dist}, $file );
895 if (!LWP::Simple::is_success($rc) and $rc != 304) {
896 die "Error $rc: ", LWP::Simple::status_message($rc), " ($args{dist})\n";
899 return $file if -e $file;
903 sub _verify_or_sign {
907 require Module::Signature;
908 die "Module::Signature version 0.25 required"
909 unless Module::Signature->VERSION >= 0.25;
912 my $cwd = Cwd::cwd();
913 my $action = $args{action};
914 my ($dist, $tmpdir) = _unzip_to_tmpdir($args{dist});
915 $action ||= (-e 'SIGNATURE' ? 'verify' : 'sign');
917 if ($action eq 'sign') {
918 open FH, '>SIGNATURE' unless -e 'SIGNATURE';
919 open FH, 'MANIFEST' or die $!;
923 if ($out !~ /^SIGNATURE(?:\s|$)/m) {
924 $out =~ s/^(?!\s)/SIGNATURE\n/m;
925 open FH, '>MANIFEST' or die $!;
930 $args{overwrite} = 1 unless exists $args{overwrite};
931 $args{skip} = 0 unless exists $args{skip};
934 my $rv = Module::Signature->can($action)->(%args);
935 _zip(dist => $dist) if $action eq 'sign';
936 File::Path::rmtree([$tmpdir]);
942 sub _unzip_to_tmpdir {
947 my $dist = File::Spec->rel2abs($args{dist});
948 my $tmpdirname = File::Spec->catdir(File::Spec->tmpdir, "parXXXXX");
949 my $tmpdir = File::Temp::mkdtemp($tmpdirname)
950 or die "Could not create temporary directory from template '$tmpdirname': $!";
952 $path = File::Spec->catdir($tmpdir, $args{subdir}) if defined $args{subdir};
953 _unzip(dist => $dist, path => $path);
956 return ($dist, $tmpdir);
961 =head2 parse_dist_name
963 First argument must be a distribution file name. The file name
964 is parsed into I<distribution name>, I<distribution version>,
965 I<architecture name>, and I<perl version>.
967 Returns the results as a list in the above order.
968 If any or all of the above cannot be determined, returns undef instead
969 of the undetermined elements.
971 Supported formats are:
973 Math-Symbolic-0.502-x86_64-linux-gnu-thread-multi-5.8.7
977 The ".tar.gz" or ".par" extensions as well as any
978 preceding paths are stripped before parsing. Starting with C<PAR::Dist>
979 0.22, versions containing a preceding C<v> are parsed correctly.
981 This function is not exported by default.
985 sub parse_dist_name {
987 return(undef, undef, undef, undef) if not defined $file;
989 (undef, undef, $file) = File::Spec->splitpath($file);
991 my $version = qr/v?(?:\d+(?:_\d+)?|\d*(?:\.\d+(?:_\d+)?)+)/;
992 $file =~ s/\.(?:par|tar\.gz|tar)$//i;
993 my @elem = split /-/, $file;
994 my (@dn, $dv, @arch, $pv);
999 and not(# if not next token also a version
1000 # (assumes an arch string doesnt start with a version...)
1001 @elem and $elem[0] =~ /^$version$/o
1012 $dn = join('-', @dn) if @dn;
1015 return( $dn, $dv, undef, undef);
1019 my $e = shift @elem;
1020 if ($e =~ /^$version|any_version$/) {
1028 $arch = join('-', @arch) if @arch;
1030 return($dn, $dv, $arch, $pv);
1033 =head2 generate_blib_stub
1035 Creates a F<blib/lib> subdirectory in the current directory
1036 and prepares a F<META.yml> with meta information for a
1037 new PAR distribution. First argument should be the name of the
1038 PAR distribution in a format understood by C<parse_dist_name()>.
1039 Alternatively, named arguments resembling those of
1040 C<blib_to_par> are accepted.
1042 After running C<generate_blib_stub> and injecting files into
1043 the F<blib> directory, you can create a PAR distribution
1044 using C<blib_to_par>.
1045 This function is useful for creating custom PAR distributions
1046 from scratch. (I.e. not from an unpacked CPAN distribution)
1050 use File::Copy 'copy';
1053 name => 'MyApp', version => '1.00'
1055 copy('MyApp.pm', 'blib/lib/MyApp.pm');
1056 blib_to_par(); # generates the .par file!
1058 C<generate_blib_stub> will not overwrite existing files.
1062 sub generate_blib_stub {
1064 my $dist = $args{dist};
1067 my $name = $args{name};
1068 my $version = $args{version};
1069 my $suffix = $args{suffix};
1071 my ($parse_name, $parse_version, $archname, $perlversion)
1072 = parse_dist_name($dist);
1074 $name ||= $parse_name;
1075 $version ||= $parse_version;
1076 $suffix = "$archname-$perlversion"
1077 if (not defined $suffix or $suffix eq '')
1078 and $archname and $perlversion;
1080 $suffix ||= "$Config::Config{archname}-$Config::Config{version}";
1081 if ( grep { not defined $_ } ($name, $version, $suffix) ) {
1082 warn "Could not determine distribution meta information from distribution name '$dist'";
1085 $suffix =~ s/\.par$//;
1087 if (not -f 'META.yml') {
1088 open META, '>', 'META.yml'
1089 or die "Could not open META.yml file for writing: $!";
1090 print META << "YAML" if fileno(META);
1095 dist_name: $name-$version-$suffix.par
1096 distribution_type: par
1098 generated_by: 'PAR::Dist version $PAR::Dist::VERSION'
1105 mkdir(File::Spec->catdir('blib', 'lib'));
1106 mkdir(File::Spec->catdir('blib', 'script'));
1112 =head2 contains_binaries
1114 This function is not exported by default.
1116 Opens a PAR archive tries to determine whether that archive
1117 contains platform-specific binary code.
1119 Takes one named parameter: I<dist>. If only one parameter is
1120 passed, it is treated as the I<dist> parameter. (Have a look
1121 at the description in the C<FUNCTIONS> section above.)
1123 Throws a fatal error if the PAR archive could not be found.
1125 Returns one if the PAR was found to contain binary code
1130 sub contains_binaries {
1133 my $dist = $args{dist};
1134 return undef if not defined $dist or not -r $dist;
1138 # The unzipping will change directories. Remember old dir.
1139 my $old_cwd = Cwd::cwd();
1141 # Unzip the base par to a temp. dir.
1142 (undef, my $base_dir) = _unzip_to_tmpdir(
1143 dist => $dist, subdir => 'blib'
1145 my $blibdir = File::Spec->catdir($base_dir, 'blib');
1146 my $archdir = File::Spec->catdir($blibdir, 'arch');
1152 $found++ if -f $_ and not /^\.exists$/;
1159 File::Path::rmtree([$base_dir]);
1161 return $found ? 1 : 0;
1168 L<PAR>, L<ExtUtils::Install>, L<Module::Signature>, L<LWP::Simple>
1172 Audrey Tang E<lt>cpan@audreyt.orgE<gt> 2003-2007
1174 Steffen Mueller E<lt>smueller@cpan.orgE<gt> 2005-2007
1176 PAR has a mailing list, E<lt>par@perl.orgE<gt>, that you can write to;
1177 send an empty mail to E<lt>par-subscribe@perl.orgE<gt> to join the list
1178 and participate in the discussion.
1180 Please send bug reports to E<lt>bug-par@rt.cpan.orgE<gt>.
1184 Copyright 2003-2007 by Audrey Tang E<lt>autrijus@autrijus.orgE<gt>.
1186 This program is free software; you can redistribute it and/or modify it
1187 under the same terms as Perl itself.
1189 See L<http://www.perl.com/perl/misc/Artistic.html>