PAR-Dist-0.51/0000755000175000017500000000000013761166661013157 5ustar roderichroderichPAR-Dist-0.51/META.yml0000644000175000017500000000143613761166661014434 0ustar roderichroderich--- abstract: 'Create and manipulate PAR distributions' author: - 'Audrey Tang ' build_requires: ExtUtils::MakeMaker: '0' Test::More: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.44, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: PAR-Dist no_index: directory: - t - inc requires: File::Find: '0' File::Path: '0' File::Spec: '0' File::Temp: '0' resources: MailingList: mailto:par@perl.org bugtracker: https://rt.cpan.org/Dist/Display.html?Queue=PAR-Dist repository: git://github.com/rschupp/PAR-Dist.git version: '0.51' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' PAR-Dist-0.51/Makefile.PL0000644000175000017500000000450013753241741015122 0ustar roderichroderichuse 5.008; use ExtUtils::MakeMaker; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. WriteMakefile1( NAME => 'PAR::Dist', VERSION_FROM => 'lib/PAR/Dist.pm', ABSTRACT_FROM => 'lib/PAR/Dist.pm', LICENSE => 'perl_5', AUTHOR => [ 'Audrey Tang ' ], PREREQ_PM => { 'File::Find' => '0', 'File::Path' => '0', 'File::Spec' => '0', 'File::Temp' => '0', }, TEST_REQUIRES => { 'Test::More' => 0, }, META_MERGE => { 'meta-spec' => { version => 2 }, resources => { repository => { type => 'git', url => 'git://github.com/rschupp/PAR-Dist.git', web => 'https://github.com/rschupp/PAR-Dist', }, MailingList => 'mailto:par@perl.org', bugtracker => { web => 'https://rt.cpan.org/Dist/Display.html?Queue=PAR-Dist' }, }, }, ); sub WriteMakefile1 { #Compatibility code for old versions of EU::MM. Written by Alexandr Ciornii, version 2. Added by eumm-upgrade. my %params=@_; my $eumm_version=$ExtUtils::MakeMaker::VERSION; $eumm_version=eval $eumm_version; die "EXTRA_META is deprecated" if exists $params{EXTRA_META}; die "License not specified" if not exists $params{LICENSE}; if ($params{AUTHOR} and ref($params{AUTHOR}) eq 'ARRAY' and $eumm_version < 6.5705) { $params{META_ADD}->{author}=$params{AUTHOR}; $params{AUTHOR}=join(', ',@{$params{AUTHOR}}); } if ($params{TEST_REQUIRES} and $eumm_version < 6.64) { $params{BUILD_REQUIRES}={ %{$params{BUILD_REQUIRES} || {}} , %{$params{TEST_REQUIRES}} }; delete $params{TEST_REQUIRES}; } if ($params{BUILD_REQUIRES} and $eumm_version < 6.5503) { #EUMM 6.5502 has problems with BUILD_REQUIRES $params{PREREQ_PM}={ %{$params{PREREQ_PM} || {}} , %{$params{BUILD_REQUIRES}} }; delete $params{BUILD_REQUIRES}; } delete $params{CONFIGURE_REQUIRES} if $eumm_version < 6.52; delete $params{MIN_PERL_VERSION} if $eumm_version < 6.48; delete $params{META_MERGE} if $eumm_version < 6.46; delete $params{META_ADD} if $eumm_version < 6.46; delete $params{LICENSE} if $eumm_version < 6.31; WriteMakefile(%params); } PAR-Dist-0.51/META.json0000644000175000017500000000267413761166661014611 0ustar roderichroderich{ "abstract" : "Create and manipulate PAR distributions", "author" : [ "Audrey Tang " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.44, CPAN::Meta::Converter version 2.150010", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "PAR-Dist", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "File::Find" : "0", "File::Path" : "0", "File::Spec" : "0", "File::Temp" : "0" } }, "test" : { "requires" : { "Test::More" : "0" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://rt.cpan.org/Dist/Display.html?Queue=PAR-Dist" }, "repository" : { "type" : "git", "url" : "git://github.com/rschupp/PAR-Dist.git", "web" : "https://github.com/rschupp/PAR-Dist" }, "x_MailingList" : "mailto:par@perl.org" }, "version" : "0.51", "x_serialization_backend" : "JSON::PP version 4.05" } PAR-Dist-0.51/README0000644000175000017500000000153013753241013014020 0ustar roderichroderichThis is the README file for PAR::Dist, a toolkit to create and manipulate PAR distributions. Please type "perldoc PAR::Dist" after installation to see the module usage information. * Installation PAR::Dist uses the standard perl module install process: perl Makefile.PL make make test make install * Source Repository You can check out the most recent revision from PAR's GitHub repository: https://github.com/rschupp/PAR-Dist * Contact You can write to the mailing list at , or send an empty mail to to participate in the discussion. Please submit bug reports to . * Copyright Copyright 2003-2011 by Audrey Tang . All rights reserved. You can redistribute and/or modify this bundle under the same terms as Perl itself. See LICENSE. PAR-Dist-0.51/LICENSE0000644000175000017500000004415013753235110014153 0ustar roderichroderichCopyright 2002-2010 by Audrey Tang . Copyright 2006-2010 by Steffen Mueller . This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Terms of the Perl programming language system itself a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" --- The GNU General Public License, Version 1, February 1989 --- Copyright 2002-2010 by Audrey Tang . Copyright 2006-2010 by Steffen Mueller . This is free software, licensed under: The GNU General Public License, Version 1, February 1989 GNU GENERAL PUBLIC LICENSE Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The license agreements of most software companies try to keep users at the mercy of those companies. By contrast, our General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. The General Public License applies to the Free Software Foundation's software and to any other program whose authors commit to using it. You can use it for your programs, too. When we speak of free software, we are referring to freedom, not price. Specifically, the General Public License is designed to make sure that you have the freedom to give away or sell copies of free software, that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of a such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must tell them their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any work containing the Program or a portion of it, either verbatim or with modifications. Each licensee is addressed as "you". 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains the Program or any part thereof, either with or without modifications, to be licensed at no charge to all third parties under the terms of this General Public License (except that you may choose to grant warranty protection to some or all third parties, at your option). c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the simplest and most usual way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this General Public License. d) You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. Mere aggregation of another independent work with the Program (or its derivative) on a volume of a storage or distribution medium does not bring the other work under the scope of these terms. 3. You may copy and distribute the Program (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 1 and 2 above provided that you also do one of the following: a) accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal charge for the cost of distribution) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) Source code for a work means the preferred form of the work for making modifications to it. For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs, or for standard header files or definitions files that accompany that operating system. 4. You may not copy, modify, sublicense, distribute or transfer the Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. 5. By copying, distributing or modifying the Program (or any work based on the Program) you indicate your acceptance of this license to do so, and all its terms and conditions. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. 7. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of the license which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the license, you may choose any version ever published by the Free Software Foundation. 8. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to humanity, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19xx name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (a program to direct compilers to make passes at assemblers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice That's all there is to it! --- The Artistic License 1.0 --- Copyright 2002-2010 by Audrey Tang . Copyright 2006-2010 by Steffen Mueller . This is free software, licensed under: The Artistic License 1.0 The Artistic License Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: - "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. - "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. - "Copyright Holder" is whoever is named in the copyright or copyrights for the package. - "You" is you, if you're thinking about copying or distributing this Package. - "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) - "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. 7. C or perl subroutines supplied by you and linked into this Package shall not be considered part of this Package. 8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End PAR-Dist-0.51/Changes0000644000175000017500000001060513761166615014453 0ustar roderichroderich0.51 2020-11-30 - Fix problem with Cwd::realpath() Some versions of Cwd::realpath() must be called on an *existing* path, otherwise they will return undef. 0.50 2020-11-17 - Fix RT#132067: fix for Archive::Zip related test failures due to symlinks Thanks, Shawn Laffan! - create repo on GitHub, update metadata 0.49 2012-10-15 - Fix RT #78194: PAR::Dist::parse_dist_name mis-parses par file name 0.48 2011-11-05 - Prefer MYMETA.yml over META.yml if possible. - Try YAML implementations in different order (XS first). 0.47 2009-11-29 - POD fixes (Frank Wiegand) 0.46 2009-07-31 - Do not use Archive::Zip if its version is 1.28. 0.45 2009-02-20 - Fix test skipping if certain optional dependencies couldn't be found. 0.44 2009-02-02 - Abandon support for perl 5.005. - Merging of the various requires-like META.yml sections in merge_par. 0.43 2009-01-23 - Don't rely on the return value of ExtUtils::Install::(un)?install 0.42 2009-01-03 - Apply *correct* patch for blib_to_par across file system boundaries 0.41 2008-12-17 - Apply patch for blib_to_par across file system boundaries from Radek. 0.40 2008-10-27 - Rewrite parts of the install_par docs. - Add the esoteric auto_inst_lib_conversion parameter to install_par. 0.39 2008-10-21 - Add the "verbose" option to install_par and uninstall_par. - Add the "uninstall_shadows" option to install_par. 0.38 2008-10-16 - Fix _check_tools() to use *Foo{THING} syntax instead of \&{}. 0.37 2008-10-08 - Fix the "Skip 03merge_meta tests if no A::Zip nor zip/unzip found." logic. - Add more debug output to debug mode (system calls). - Add internal _check_tools() sub which checks the availability of various required tools (yaml, zip). 0.36 2008-09-30 - Skip 03merge_meta tests if no YAML *DUMPER* could be found. - Better debug output for the YAML-search. 0.35 2008-09-30 - Skip 03merge_meta tests if no A::Zip nor zip/unzip found. - Better error messages from _zip/_unzip 0.34 2008-09-24 - Do not fail if _zip() doesn't return true, doh! 0.33 2008-09-17 - Better diagnostics for the CPAN testers test failures. - Extra -f check in _merge_meta. 0.32 2008-09-12 - Version bump, fix tests. 0.31 2008-05-28 - Fix small bug in _unzip that could cause double extraction. 0.29 2008-02-06 - Make file://foo.par URLs installable. 0.28 2008-02-05 - Setting installation targets to undef with install_par should remove them altogether now. This way, you can make sure, some parts aren't installed. (Such as manpages on win32) 0.27 2008-02-04 - No more signature. I keep breaking things with it. 0.26 2008-02-03 - If the return code from LWP::Simple is 304/not modified, then that's a success. So we shouldn't throw an error. 0.25 2007-06-29 - Use Archive::Unzip::Burst for unzipping if available. 0.24 2007-07-20 - Remove shebang from Makefile.PL. No assumptions about the user's perl. - Port Makefile.PL to use ExtUtils::MakeMaker 0.23 2007-06-20 - Add contains_binaries. 0.21 2006-10-12 - _install_or_uninstall tries to remove the temporary directory while cwd() is in that directory. That fails on win32 leaving temporary directories on disk. This is now fixed. 0.20 2006-10-11 - Added a more flexible way of using PAR::Dist::install_par's custom target logic. 0.19 2006-09-03 - It's not possible to specify your own installation paths. - Installation paths now documented. 0.15 2006-07-28 - PAR::Dist would previously generate bad file names and META.yml if the newlines contained Windows' \r. That's history. 0.14 2006-07-19 - The "version" field of META.yml files written by Module::Build was not parsed correctly by the ad-hoc YAML parser. 0.13 2006-07-22 - Module::Install didn't regenerate META.yml because author bit wasn't set. 0.12 2006-07-21 - Found a couple of path-related bugs in the new functions of 0.11. 0.11 2006-07-21 - Fixed potential bugs where slashes were used as path separators. - Added merge_par() which merges two or more .par archives. - Added remove_man() which removes all man pages and html docs from a .par archive. 0.10 2006-07-05 - .par distributions fetched from URLs will now be installed as distributions named "Module-Name" instead of "http://foo.bar/path/Module-Name-0.01-architecture-version.par". - Updated Module::Install to 0.63 0.09 2006-05-20 - Updated Module::Install to 0.62 0.08 2006-02-13 - Updated Module::Install - Slight documentation fixes. PAR-Dist-0.51/t/0000755000175000017500000000000013761166661013422 5ustar roderichroderichPAR-Dist-0.51/t/03merge_meta.t0000644000175000017500000000614213755216272016057 0ustar roderichroderich#!/usr/bin/perl -w use strict; use Test::More; use vars '$loaded'; BEGIN { $loaded = eval { require PAR::Dist; 1 } }; BEGIN { my $tests = 29; if ($loaded) { # skip these tests without YAML loader or without (A::Zip or zipo/unzip) $PAR::Dist::DEBUG = 1; my $tools = PAR::Dist::_check_tools(); $PAR::Dist::DEBUG = 0; if (not defined $tools->{DumpFile}) { plan skip_all => "Skip because no YAML loader/dumper could be found"; exit(); } elsif (not defined $tools->{zip}) { plan skip_all => "Skip because neither Archive::Zip nor zip/unzip could be found"; exit(); } else { plan tests => $tests; ok(1); } } else { plan tests => $tests; ok(0, "Could not load PAR::Dist: $@"); exit(); } } ok (eval { require PAR::Dist; 1 }); chdir('t') if -d 't'; my @dist = ( 'data/dist1.par', 'data/dist2.par', ); my @tmp = map {my $f = $_; $f =~ s/^data\///; $f} @dist; require File::Copy; for (0..$#dist) { ok(-f $dist[$_]); ok(File::Copy::copy($dist[$_], $tmp[$_])); } sub cleanup { unlink($_) for @tmp; } $SIG{INT} = \&cleanup; $SIG{TERM} = \&cleanup; END { cleanup(); } my %provides_expect = ( "Math::Symbolic::Custom::Transformation" => { file => "lib/Math/Symbolic/Custom/Transformation.pm", version => "2.01", }, "Math::Symbolic::Custom::Transformation::Group" => { file => "lib/Math/Symbolic/Custom/Transformation/Group.pm", version => "1.25", }, "Test::Kit" => { file => "lib/Test/Kit.pm", version => "0.02", }, "Test::Kit::Features" => { file => "lib/Test/Kit/Features.pm", version => "0.02", }, "Test::Kit::Result" => { file => "lib/Test/Kit/Features.pm", }, ); my %requires_expect = ( "Math::Symbolic" => '0.507', "Math::Symbolic::Custom::Pattern" => '1.20', "base" => '2.11', "namespace::clean" => '0.08', "Test::More" => '0', ); my %build_requires_expect = ( "Test::More" => '0.1', "Test::Differences" => undef, ); my %recommends_expect = ( "Test::Pod" => '1.0', "Test::Pod::Coverage" => '1.0', ); PAR::Dist::merge_par(@tmp); ok(1); # got to this point my ($y_func) = PAR::Dist::_get_yaml_functions(); my $meta = PAR::Dist::get_meta($tmp[0]); ok(defined($meta)); my $result = $y_func->{Load}->( $meta ); ok(defined $result); $result = $result->[0] if ref($result) eq 'ARRAY'; my $provides = $result->{provides}; ok(ref($provides) eq 'HASH'); foreach my $module (keys %provides_expect) { ok(ref($provides->{$module}) eq 'HASH'); my $modhash = $provides->{$module}; my $exphash = $provides_expect{$module}; ok($exphash->{file} eq $modhash->{file}); if (exists $exphash->{version}) { ok($exphash->{version} eq $modhash->{version}); } else { ok(!exists($modhash->{version})); } } is_deeply($result->{requires}, \%requires_expect, "requires merged as expected"); is_deeply($result->{build_requires}, \%build_requires_expect, "build_requires merged as expected"); is_deeply($result->{configure_requires}, undef, "configure_requires merged as expected"); is_deeply($result->{recommends}, \%recommends_expect, "recommends merged as expected"); __END__ PAR-Dist-0.51/t/data/0000755000175000017500000000000013761166661014333 5ustar roderichroderichPAR-Dist-0.51/t/data/dist1.par0000644000175000017500000002453513753232350016062 0ustar roderichroderichPK!9%kMETA.ymlRJ0+r., xZXpɂuSBy/ozѼ~:1O%sfGDszuBr^ZD6q^o ULm =PK!9CµTFMANIFESTN0Ei+*1 VyI*t,ZQiC!K$V;%њUXSFBj-1:*e MOGd-Es6b@6 ZFr+,t-džJ(zPk:iKSG bBEb*:4:QiNqR'Vhh7/`U6.z)fKF4v>xc414g2s,ticSvPK!9lib/PK!9 lib/Math/PK!9lib/Math/Symbolic/PK!9lib/Math/Symbolic/Custom/PK!9`hD*lib/Math/Symbolic/Custom/Transformation.pm\rG~E ڵc"aQ,1, VC4>/>ФaxA8_$;o*Ny"O1]foOm8 w" [3x3E~';Gr4>:j/GJg*J=Xa"/K>䔎3ztLҽY>"(O@CU0~bg 'g:!eo@LSܮ+-12J3N ӣj,!rpykZ%q*V1HH*2I`6Oa֌ .1#OE\$uŠ>/*[ij3#Kt"fOVO^5cnX4O+ -zKY /ިa.IpD{'k.M1t3xXY6`cS:$'&ޚJq_{CR b(G`G/&woīNwoĎ{.ϻ3]>0\BD͞{h۫COf &h:vV]Asg$:p`n ]ǓK-9rdA]Zp(kP_M"gJ 4$#HYk87 O*I e 2{d^xJ}@:p)a pYB$pmJ=5C[]bbL,໒$k=Ƥ0nu:Cէt4v US VS.+t[4R8PZ-B#=j<)n2ߡIBL!k鑦y3q0!2 6hDRAo^qztNx~=\^\]{9++ cXL qjX֐d1$fN*O2|![PI|+ӑ(-h ` iKX< )>¹>_eFy>lFc @EHKJnU=(b}wux+["$㍷i XQ l0#j*ӫpߘVGށ,n%;ȎC )әqi ^R;5 *(@/ \s*MTd RPARqSgq:m9)ޑ5dqy` a;ŽG`9P3P O=u:!Wd,ET{P-( M" G[ ^ryJ/Uc1ĺ}qU/ LRtY, "nHMT2z+d] 9қs%;G=ːZLvSE;Fo׶kZ2oxJZ7W;D{Im%zD A%kOf.a4_)x:;7iY~QA5EI!kUVR|Çai9K@BMB|U?40/$Phӛ#SZtfVgLޥJBQ57k<[i `Blb0|qpU.lֶ`~g*4>nDAX[D <{e*tju歧Le͢L%&`kI-±EV"k^3";c"չTu;U,+CJ!odYf *pE~^gO3}Ρ&'pцru7 Z?zrCw^W.%sϼ;[Z݈M}qt70SϱCe֯}w ,&P)^&\.U17Lldȹ>Hn!aˬ[h0ϼ"ޭN?{yX:Ps?k9Y7}&e?YpH]IN{ J+j9e_8pDnp9:y=,b뾿:޴֝vzkO"z:j!tl o{On f/뫓1t4y}qsی{,CkeIpVgum\[}nPON\O 5h#$dm f6|V O0vb]n_Jb~tZD>}WW_[--<ڽ'~Ig%;#H{*LuI%rŽx5u L\ML Էfj- 'vO4E2}(.258~OrSKwwT .{;~}rl,i O{?&&]LjAK7eb$݉gaY}S2c ^)]ȦrǗE.'Y&MX}-`ĈtZ CBA}QNg_rUU\j(a؋.rSBZY\KtH<&?_ȋ4CZub˧K\(f7mC )qW:i'سVƕ#yo%EKcwsꚏ:֙jGwx>5==qG$N {gd6qRU@TI֛֙Ăn<_{Gu*oe36*r)IǕ#+, x $zaK7􆣝 Vs}3ۿv-Ī3NJe kl ش~?_(<4kq <8{Fo[1!pT2KG7Mݎj5n_w/MzvL[楓PdH*S،&| ۍϙ}UA.jEkBlMղ 3MA~IezH1} /ha"W@]1+RA#\KiJ-tЀ=A{ʡ,|qd BK + v_S U6N-ųZ 7>G_҅4/:ZuBbɦD;kƹR58/XTh'o,X3d͍8 {Kп]`gfQzR<-|L@S_җ굻jL/L?{BmG4t$rA}d,] I1;jjvShd7ا O580w*a9dtv]$巉?b/,ZRgbSQ6s.[G|goiRzj*{_ܓU|jLiWuQfؔ=d׮\ bAlh:lԽdR 9Hm˞^ ԽL't6.,+\Bу#Rupj;Q3N>RC鬝so0;c5x&E71 oHJV_Nˣ̺Xߙ+P&/boX#脵K4Y"Ƥ['h\\m@eu~"n{ K’9 fT) ~tE[>N\i6^>~Vy0ݶ  U]`t0,,(d7z!H}K ujƺ>ӷ̄p0fEv%1;<]f xtB1ae݋wg磇G `^Y/SJL7Q]~w!]R`~ٯc}ұ4RȦ<~ 7͐*le~\E{\J\z2g…5-Gr͗Rw }ܰp&;{]ß~}qyc}0ZRgdH6:ɆnӋ_^'/śxyjr;]=뿨5 iB]Q<#yzZktSss->])3߾s/Ķ_k~~f?CysDLǹ ⸱;'.RmPK!9(lib/Math/Symbolic/Custom/Transformation/PK!9 N0lib/Math/Symbolic/Custom/Transformation/Group.pmXmoFS׍Vc,[OQmX኶VbLriEp|nfvI&pBH2;/>3啂,,B`g&YL Ki$>8x< g yO>7J82j(u WN]R?fd=8QBtl$i}֭.FDjv9g4~Prg'oGB|C$;b|:13+yhMRgjd90W[a:XF HZVmhM.G'x{-A1Z<<"jx~6Le" ~ruZVTbE>{YLiI^'~ߪX-H:p+$T, N dFV~FcY }"sr%U]+SwV565o6o'2nh#;6 l{1/O/&k!N`xM @2| !W*Esi)OL(-#0u샌M'L#EBJBiu ^᡽~<ϣdEe 3fxpT (ġA"˄dXuÈ[-1-]<˗t_͂,CA3Úg)4OBAjDW#@(}1RAyZ1y/ 4CKx6tbB²"r4Rfau"xTf& f @OU8ZW㆑ś0ї1Rs.^bhMo}۬3`:U N6Y7<āb4xR: }rBDgk" p /_5$!$Ǭ: ` P f2VԱ 2Mi1; ѩ4QJZ*H1AZRBhԒfs6ߪ(5}Y%KFءC:U#}.SH2A+lPL(YaƩa3h8_ΔtP.QaJNZ*H~ИNN^Ȝ0$[alrGOTu_$HE|" 0򘥿#*hϟ헾E^r? ŕNb#uwVmRۧ1V%἖8֭ΖJRcQfzY~9a_Nm{0kB6?nk<[vt)o*B2AJ87@\սp ź偵NQK$ !90jao b [wíCI{[<I.Fgbƃ)7peQOU\=+(W=dO_u.dWIifwc9˻\0(Յ,)% ` '$l^QFJ c2 #TGcGs1go۝sRXAQbG;HWas,prKuYdrFL?YAzC" ѿa}=cI2efh"P^~ zHq{5,r{L}QŐ:4J9% )V>~TTBnQ%N)y!xk _BۅއjT S5 Q*\Vb=3>D1Q, à]) [D.=F3xGk7p8LFt&@ˢspN.Kr끭5r3X@RH"^k꓋!Ee xChR1=&P-<*Bd3vPt$a)IZb3'6R 8L{RK4jqAZ{_/"f(TJ{l{f[0Q9s7Iͤ]w<79==nzZcU^B={׵2cIΑRZ%upYIG7{#ya]B+)%W"!ذrvetӋ'FSzRNGg/zt`<ɛgH\YVTx+ƤQA2Ki/V +e(L}VR!s/%Arάbo|YOM^_ 1v? ;0:̠Pl7 F23:2RW'prޜGgVIƊua=ӧ{So:EL"qe, ϐh5!CXƽ3:K~¼P:ro]P!դvyϽ=eWH~zҐܴCF$QR{oT wO Jn"?PK!9arch/PK!9%kMETA.ymlPK!9CµTFMANIFESTPK!9Alib/PK!9 Alib/Math/PK!9AFlib/Math/Symbolic/PK!9Avlib/Math/Symbolic/Custom/PK!9`hD*$lib/Math/Symbolic/Custom/Transformation.pmPK!9(Alib/Math/Symbolic/Custom/Transformation/PK!9 N0$Llib/Math/Symbolic/Custom/Transformation/Group.pmPK!9A&arch/PK &PAR-Dist-0.51/t/data/dist2.par0000644000175000017500000001373013753232350016056 0ustar roderichroderichPKB:+43MANIFESTuO0&5踸D4鶎t-@~hY2cx!PT5,F-g;e+YG.VݗXmc#I)Q;AVwmUp?\ޢڲ܎Q0^ & ӞMp)4o2SRtQ}t="?PKB:?A[META.ymlQMo0 WXpj P4MLhKI8 .s!؄[\pG Tk x`,Su>(P!2^צ7py[IV7#HAפ>@"a^a[EM)'hGRXSj`c>cq:Aekƒ9Ʉ=%ftOdE>3T{D/<ŀ.r"#9ph&k2%ˡ!癟!KO?1&{̙ M,oMxtQHY8{01`) T1NgAd,RxΎ<Dci.,5| cdeW:ۤ-m+T# {9I%Z-SĜ&Ṕf>c3SIX6V@ Q i!Mꖆ@\!uBQ¸#YKĜ,%֐$Vp3ey(!*IAC޸k MP{NvB7)Z"EChC-]9GG$1Rƣ8 @z;=5^k&qIcܦmiHL%a36%|Y4]@VmN~9YLOPA 1VBt*t@mE9,Neﰌ2NY#>aEbwO{tL)wgc- NVKKl9Z[7ZL A?(JyK aL%;?we:j[K\~`װȍX*C@m&DNKtIp+2Dl4 E:Pacd+ )<).fr XNܘ>ވs葡p PP% GcbԾp1^KRTa۴T: 3mn< #&NJrYZN"`ZWV -j`KIu$,!BW,Z͔J4"ZXd4`j[Z#|3x((liPoh͆@cn[CJsyB1z)!@?}Y(s xTeZ B0V=PlYUfWG$ѐ4 -mE͔Tmhkm8[7}pP#[R83Nb')$78E_y|M|@u.M-iWg'IŮ#ӄ?`Q8n3CDВ4C#aẊzM2`[:(]$JlxI*z5$=<9mˤq8GL t١ [,@@ct+ч7LfRwƿqVla-.G<>KBELPimudct^ͺ vaVQy,:sQ!Q4%5Xbl$)a dA*Ane*A2Ķ"Q;Q=_5wXZI~f,ZG{eЛXlQ?T>O\CJQ0@oE7Jd٠g-[̘iϬ.++5׷g'MCxjj21=w&TX>ĵMڐͽ虶U}j㽜ckqPR8qkS!+nnH.ʉRv+:RW+]W vN+ ѕcݕ Y[8x%x)v4ywfV=fHզ4~wy\TGO1^e~Y)mܥ RhP케^}>|8F`'Pg$_ZիUS<ǴZenl@9*E-A#nڬӾ©~dLy ʹG~i%{C<'˶}^cۆU"ڈLJ}H"q9ՔRښoM몊,dEn!Tmwb < ƒ I㗘(nXL]ִ,)j`Qe)Bl1jPaz{qqqeV*?.oEXA=+Җ^fo:w5yjOe٪=ԥ.k4iy'bS9L\UU]EqػUќzd{N|Lw2ؽ|z~`[ xk@(WNШLM݄;wg}J]6-4FgMVhfȡQV\N2]M'cf^t76N |YZ\no]^ArqԀ+@s[ Rcq}.aTܫ%{{Xu;i@v]QM|>8\^O i>K~G ~Lݣ7zS{/Ob#$`E.f,ǪcHjLP)7CwgXhݽz g۫ hZEDb\m~k]M]us%H.QQs5hGȒ;KPV1S?BXޮyiCwJ&3dlV'>V.9T;E=)tDp^¤ezṭy1paoT_=]7ryxgӋ)F/~ë/5FW؊ yZUP魄s&96MнeQɑ*M|O8id'L^p^dB7/u;MKPK!9 lib/Test/Kit/PK!9q Q glib/Test/Kit/Features.pmWms7ίغ fL?5u4Naı+ljHw8;qϮvVa:!}\HRzjA'* 񍶿΅@KtKx3>?\Z9# ",BXH%a?itum}BCq%ijTAQ)x|e$}0Z {ᮘ| 5o2*&Ìi$7 w1k``xp4Ͱך 8…JH7IW3$dLik9g%G[F` cH .Paqr\F$ߤ !Pw,UpKx %c./1@D18Lā#a""[ ^fiƙ礰Ϧaa-a!JtM:zlOFBFeט,\ !7ڄ 9ɞ ^C/3|fyGn}Ayz!IZrRRќ2:CxW0zâWHX-ȅŊ$+ 998]'.ruFsT}x /id\3)וSH' Cr8՘;PٜsW"^uD=hg=8<%gAFfO9LtlVd*`iȜN/Ŏ^v}Ʋ2/kө3h:]݃q0"ث~XuW!>K/޽Np~Аl?ab}9m"[d/O gR56DjϞ>/8YnaI%]3l?i%i]~'Sk?\v`6S>N%kEJ_@{8rrc$kv~H<. q<^خ)>+Od*}Ի=g~@~䮤 %"]W4+i\j*CL' 5uxLVSY&rz1?GE5WQ]z?24ѻl*v84(\I*)5{j"9gi|f|V!)PJ U(Y*4tY& k&GLU% -SXZ\*+tY|Jsmr_/,W.+CdWIR$5zpK# sA& O=b*]WN ۳&RBA,^npKJ/=U(PK!9arch/PKB:+43MANIFESTPKB:?A[YMETA.ymlPK!9Alib/PK!9 Alib/Test/PK!9_m 6 $#lib/Test/Kit.pmPK!9 Aklib/Test/Kit/PK!9q Q g$lib/Test/Kit/Features.pmPK!9Aarch/PKPAR-Dist-0.51/t/01basic.t0000644000175000017500000000016313753232350015017 0ustar roderichroderich#!/usr/bin/perl -w use strict; use Test; BEGIN { plan tests => 1 } ok (eval { require PAR::Dist; 1 }); __END__ PAR-Dist-0.51/t/02parsedistname.t0000644000175000017500000000162213753232350016577 0ustar roderichroderichuse strict; use warnings; our @tests; BEGIN { @tests = ( 'Math-Symbolic-0.502-x86_64-linux-gnu-thread-multi-5.8.7.par' => ['Math-Symbolic', '0.502', 'x86_64-linux-gnu-thread-multi', '5.8.7'], 'Math-Symbolic-0.502.tar.gz' => ['Math-Symbolic', '0.502', undef, undef], 'Foo-0.5.3_1-x86-win32-thread-multi-any_version' => ['Foo', '0.5.3_1', 'x86-win32-thread-multi', 'any_version'], 'Foo-v0.5.3_1-MSWin32-x86-thread-multi-5.005_03' => ['Foo', 'v0.5.3_1', 'MSWin32-x86-thread-multi', '5.005_03'], 'Foo-Bar-5-0.5.3_1-MSWin32-x86-thread-multi-5.005_03' => ['Foo-Bar-5', '0.5.3_1', 'MSWin32-x86-thread-multi', '5.005_03'], ); } use Test::More tests => int(scalar(@tests)/2) + 1; use_ok('PAR::Dist'); while (@tests) { my $str = shift @tests; my $res = shift @tests; my @res = PAR::Dist::parse_dist_name($str); is_deeply($res, \@res, "Parsing '$str'"); } PAR-Dist-0.51/t/00pod.t0000644000175000017500000000040413753232350014515 0ustar roderichroderichuse strict; use warnings; use Test::More; plan skip_all => "Set environment variable PERL_TEST_POD=1 to test POD" if not $ENV{PERL_TEST_POD}; eval "use Test::Pod 1.00"; plan skip_all => "Test::Pod 1.00 required for testing POD" if $@; all_pod_files_ok(); PAR-Dist-0.51/t/00podcover.t0000644000175000017500000000046413753232350015562 0ustar roderichroderich#!/usr/bin/perl use strict; use warnings; use Test::More; plan skip_all => "Set environment variable PERL_TEST_POD=1 to test POD" if not $ENV{PERL_TEST_POD}; eval "use Test::Pod::Coverage 1.00"; plan skip_all => "Test::Pod::Coverage 1.00 required for testing POD coverage" if $@; all_pod_coverage_ok(); PAR-Dist-0.51/MANIFEST0000644000175000017500000000054513761166661014314 0ustar roderichroderichChanges lib/PAR/Dist.pm LICENSE Makefile.PL MANIFEST This list of files README t/00pod.t t/00podcover.t t/01basic.t t/02parsedistname.t t/03merge_meta.t t/data/dist1.par t/data/dist2.par META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) PAR-Dist-0.51/lib/0000755000175000017500000000000013761166661013725 5ustar roderichroderichPAR-Dist-0.51/lib/PAR/0000755000175000017500000000000013761166661014347 5ustar roderichroderichPAR-Dist-0.51/lib/PAR/Dist.pm0000644000175000017500000012353713761166345015622 0ustar roderichroderichpackage PAR::Dist; use 5.006; use strict; require Exporter; use vars qw/$VERSION @ISA @EXPORT @EXPORT_OK $DEBUG/; $VERSION = '0.51'; @ISA = 'Exporter'; @EXPORT = qw/ blib_to_par install_par uninstall_par sign_par verify_par merge_par remove_man get_meta generate_blib_stub /; @EXPORT_OK = qw/ parse_dist_name contains_binaries /; $DEBUG = 0; use Carp qw/carp croak/; use File::Spec; =head1 NAME PAR::Dist - Create and manipulate PAR distributions =head1 SYNOPSIS As a shell command: % perl -MPAR::Dist -eblib_to_par In programs: use PAR::Dist; my $dist = blib_to_par(); # make a PAR file using ./blib/ install_par($dist); # install it into the system uninstall_par($dist); # uninstall it from the system sign_par($dist); # sign it using Module::Signature verify_par($dist); # verify it using Module::Signature install_par("http://foo.com/DBI-1.37-MSWin32-5.8.0.par"); # works too install_par("http://foo.com/DBI-1.37"); # auto-appends archname + perlver install_par("cpan://SMUELLER/PAR-Packer-0.975"); # uses CPAN author directory =head1 DESCRIPTION This module creates and manipulates I. They are architecture-specific B files, containing everything under F of CPAN distributions after their C or C stage, a F describing metadata of the original CPAN distribution, and a F detailing all files within it. Digitally signed PAR distributions will also contain a F file. The naming convention for such distributions is: $NAME-$VERSION-$ARCH-$PERL_VERSION.par For example, C corresponds to the 0.01 release of C on CPAN, built for perl 5.8.0 running on C. =head1 FUNCTIONS Several functions are exported by default. Unless otherwise noted, they can take either a hash of named arguments, a single argument (taken as C<$path> by C and C<$dist> by other functions), or no arguments (in which case the first PAR file in the current directory is used). Therefore, under a directory containing only a single F, all invocations below are equivalent: % perl -MPAR::Dist -e"install_par( dist => 'test.par' )" % perl -MPAR::Dist -e"install_par( 'test.par' )" % perl -MPAR::Dist -einstall_par; If C<$dist> resembles a URL, C is called to mirror it locally under C<$ENV{PAR_TEMP}> (or C<$TEMP/par/> if unspecified), and the function will act on the fetched local file instead. If the URL begins with C, it will be expanded automatically to the author's CPAN directory (e.g. C). If C<$dist> does not have a file extension beginning with a letter or underscore, a dash and C<$suffix> ($ARCH-$PERL_VERSION.par by default) will be appended to it. =head2 blib_to_par Takes key/value pairs as parameters or a single parameter indicating the path that contains the F subdirectory. Builds a PAR distribution from the F subdirectory under C, or under the current directory if unspecified. If F does not exist, it automatically runs F, F, F or F to create it. Returns the filename of the generated PAR distribution. Valid parameters are: =over 2 =item path Sets the path which contains the F subdirectory from which the PAR distribution will be generated. =item name, version, suffix These attributes set the name, version and platform specific suffix of the distribution. Name and version can be automatically determined from the distributions F or F files. The suffix is generated from your architecture name and your version of perl by default. =item dist The output filename for the PAR distribution. =item quiet Set to true to suppress as much output as possible. =back =cut sub blib_to_par { @_ = (path => @_) if @_ == 1; my %args = @_; require Config; # don't use 'my $foo ... if ...' it creates a static variable! my $quiet = $args{quiet} || 0; my $dist; my $path = $args{path}; $dist = File::Spec->rel2abs($args{dist}) if $args{dist}; my $name = $args{name}; my $version = $args{version}; my $suffix = $args{suffix} || "$Config::Config{archname}-$Config::Config{version}.par"; my $cwd; if (defined $path) { require Cwd; $cwd = Cwd::cwd(); chdir $path; } _build_blib() unless -d "blib"; my @files; open MANIFEST, ">", File::Spec->catfile("blib", "MANIFEST") or die $!; open META, ">", File::Spec->catfile("blib", "META.yml") or die $!; require File::Find; File::Find::find( sub { next unless $File::Find::name; (-r && !-d) and push ( @files, substr($File::Find::name, 5) ); } , 'blib' ); print MANIFEST join( "\n", ' ', (sort @files), q( # ) ); close MANIFEST; # if MYMETA.yml exists, that takes precedence over META.yml my $meta_file_name = "META.yml"; my $mymeta_file_name = "MYMETA.yml"; $meta_file_name = -s $mymeta_file_name ? $mymeta_file_name : $meta_file_name; if (open(OLD_META, $meta_file_name)) { while () { if (/^distribution_type:/) { print META "distribution_type: par\n"; } else { print META $_; } if (/^name:\s+(.*)/) { $name ||= $1; $name =~ s/::/-/g; } elsif (/^version:\s+.*Module::Build::Version/) { while () { /^\s+original:\s+(.*)/ or next; $version ||= $1; last; } } elsif (/^version:\s+(.*)/) { $version ||= $1; } } close OLD_META; close META; } if ((!$name or !$version) and open(MAKEFILE, "Makefile")) { while () { if (/^DISTNAME\s+=\s+(.*)$/) { $name ||= $1; } elsif (/^VERSION\s+=\s+(.*)$/) { $version ||= $1; } } } if (not defined($name) or not defined($version)) { # could not determine name or version. Error. my $what; if (not defined $name) { $what = 'name'; $what .= ' and version' if not defined $version; } elsif (not defined $version) { $what = 'version'; } 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."); return(); } $name =~ s/\s+$//; $version =~ s/\s+$//; my $file = "$name-$version-$suffix"; unlink $file if -f $file; print META << "YAML" if fileno(META); name: $name version: $version build_requires: {} conflicts: {} dist_name: $file distribution_type: par dynamic_config: 0 generated_by: 'PAR::Dist version $PAR::Dist::VERSION' license: unknown YAML close META; mkdir('blib', 0777); chdir('blib'); require Cwd; my $zipoutfile = File::Spec->catfile(File::Spec->updir, $file); _zip(dist => $zipoutfile); chdir(File::Spec->updir); unlink File::Spec->catfile("blib", "MANIFEST"); unlink File::Spec->catfile("blib", "META.yml"); $dist ||= File::Spec->catfile($cwd, $file) if $cwd; if ($dist and $file ne $dist) { if ( File::Copy::copy($file, $dist) ) { unlink $file; } else { die "Cannot copy $file: $!"; } $file = $dist; } my $pathname = File::Spec->rel2abs($file); if ($^O eq 'MSWin32') { $pathname =~ s!\\!/!g; $pathname =~ s!:!|!g; }; print << "." if !$quiet; Successfully created binary distribution '$file'. Its contents are accessible in compliant browsers as: jar:file://$pathname!/MANIFEST . chdir $cwd if $cwd; return $file; } sub _build_blib { if (-e 'Build') { _system_wrapper($^X, "Build"); } elsif (-e 'Makefile') { _system_wrapper($Config::Config{make}); } elsif (-e 'Build.PL') { _system_wrapper($^X, "Build.PL"); _system_wrapper($^X, "Build"); } elsif (-e 'Makefile.PL') { _system_wrapper($^X, "Makefile.PL"); _system_wrapper($Config::Config{make}); } } =head2 install_par Installs a PAR distribution into the system, using C. If only a single parameter is given, it is treated as the value for the C parameter. Valid named parameters are: =over 2 =item dist The .par file to install. The heuristics outlined in the B section above apply. =item prefix This string will be prepended to all installation paths. If it isn't specified, the environment variable C is used as a prefix. =item uninstall_shadows This corresponds to the C option of L. Quoting its manual: If C is set to true, any differing versions throughout C<@INC> will be uninstalled. This is C. =item verbose This corresponds to the C option of L. According to its manual: If C is true, will print out each file removed. This is C. C values going up to 5 show increasingly more diagnostics output. Default verbosity for PAR::Dist is 1. =back If you're just going to install into the running perl like everything else, you can stop reading the rest of this section now. Additionally, you can use several parameters to change the default installation destinations. You don't usually have to worry about this unless you are installing into a user-local directory. The following section outlines the parameter names and default settings: Parameter From To inst_lib blib/lib $Config{installsitelib} (*) inst_archlib blib/arch $Config{installsitearch} inst_script blib/script $Config{installscript} inst_bin blib/bin $Config{installbin} inst_man1dir blib/man1 $Config{installman1dir} inst_man3dir blib/man3 $Config{installman3dir} packlist_read $Config{sitearchexp}/auto/$name/.packlist packlist_write $Config{installsitearch}/auto/$name/.packlist The C parameter is used to control where the F<.packlist> file is written to. (Necessary for uninstallation.) The C parameter specifies a .packlist file to merge in if it exists. By setting any of the above installation targets to C, you can remove that target altogether. For example, passing C<< inst_man1dir => undef, inst_man3dir => undef >> means that the contained manual pages won't be installed. This is not available for the packlists. Again, the defaults will be the normal I paths from C<%Config>. (*) If the C<.par>'s I section (normally C) isn't empty, the code in I (normally C) is also installed into the I path. This makes sense for XS modules. If, however, you override C, this automatic conversion is also overridden! You can use the named parameter C 1> to re-enable the conversion for custom I's. Finally, you may specify a C parameter. Its value should be a reference to a hash of custom installation targets such as custom_targets => { 'blib/my_data' => '/some/path/my_data' } You can use this to install the F<.par> archives contents to arbitrary locations. =cut sub install_par { my %args = &_args; _install_or_uninstall(%args, action => 'install'); } =head2 uninstall_par Uninstalls all previously installed contents of a PAR distribution, using C. Takes almost the same parameters as C, but naturally, the installation target parameters do not apply. The only exception to this is the C parameter which specifies the F<.packlist> file to read the list of installed files from. It defaults to C<$Config::Config{installsitearch}/auto/$name/.packlist>. Additionally, the C parameter of C isn't available. =cut sub uninstall_par { my %args = &_args; _install_or_uninstall(%args, action => 'uninstall'); } sub _install_or_uninstall { my %args = &_args; my $name = $args{name}; my $action = $args{action}; my %ENV_copy = %ENV; $ENV{PERL_INSTALL_ROOT} = $args{prefix} if defined $args{prefix}; require Cwd; my $old_dir = Cwd::cwd(); my ($dist, $tmpdir) = _unzip_to_tmpdir( dist => $args{dist}, subdir => 'blib' ); if ( open (META, File::Spec->catfile('blib', 'META.yml')) ) { while () { next unless /^name:\s+(.*)/; $name = $1; $name =~ s/\s+$//; last; } close META; } return if not defined $name or $name eq ''; if (-d 'script') { require ExtUtils::MY; foreach my $file (glob("script/*")) { next unless -T $file; ExtUtils::MY->fixin($file); chmod(0555, $file); } } $name =~ s{::|-}{/}g; require ExtUtils::Install; if ($action eq 'install') { my $target = _installation_target( File::Spec->curdir, $name, \%args ); my $custom_targets = $args{custom_targets} || {}; $target->{$_} = $custom_targets->{$_} foreach keys %{$custom_targets}; my $uninstall_shadows = $args{uninstall_shadows}; my $verbose = $args{verbose}; ExtUtils::Install::install($target, $verbose, 0, $uninstall_shadows); } elsif ($action eq 'uninstall') { require Config; my $verbose = $args{verbose}; ExtUtils::Install::uninstall( $args{packlist_read}||"$Config::Config{installsitearch}/auto/$name/.packlist", $verbose ); } %ENV = %ENV_copy; chdir($old_dir); File::Path::rmtree([$tmpdir]); return 1; } # Returns the default installation target as used by # ExtUtils::Install::install(). First parameter should be the base # directory containing the blib/ we're installing from. # Second parameter should be the name of the distribution for the packlist # paths. Third parameter may be a hash reference with user defined keys for # the target hash. In fact, any contents that do not start with 'inst_' are # skipped. sub _installation_target { require Config; my $dir = shift; my $name = shift; my $user = shift || {}; # accepted sources (and user overrides) my %sources = ( inst_lib => File::Spec->catdir($dir,"blib","lib"), inst_archlib => File::Spec->catdir($dir,"blib","arch"), inst_bin => File::Spec->catdir($dir,'blib','bin'), inst_script => File::Spec->catdir($dir,'blib','script'), inst_man1dir => File::Spec->catdir($dir,'blib','man1'), inst_man3dir => File::Spec->catdir($dir,'blib','man3'), packlist_read => 'read', packlist_write => 'write', ); my $par_has_archlib = _directory_not_empty( $sources{inst_archlib} ); # default targets my $target = { read => $Config::Config{sitearchexp}."/auto/$name/.packlist", write => $Config::Config{installsitearch}."/auto/$name/.packlist", $sources{inst_lib} => ($par_has_archlib ? $Config::Config{installsitearch} : $Config::Config{installsitelib}), $sources{inst_archlib} => $Config::Config{installsitearch}, $sources{inst_bin} => $Config::Config{installbin} , $sources{inst_script} => $Config::Config{installscript}, $sources{inst_man1dir} => $Config::Config{installman1dir}, $sources{inst_man3dir} => $Config::Config{installman3dir}, }; # Included for future support for ${flavour}perl external lib installation # if ($Config::Config{flavour_perl}) { # my $ext = File::Spec->catdir($dir, 'blib', 'ext'); # # from => to # $sources{inst_external_lib} = File::Spec->catdir($ext, 'lib'); # $sources{inst_external_bin} = File::Spec->catdir($ext, 'bin'); # $sources{inst_external_include} = File::Spec->catdir($ext, 'include'); # $sources{inst_external_src} = File::Spec->catdir($ext, 'src'); # $target->{ $sources{inst_external_lib} } = $Config::Config{flavour_install_lib}; # $target->{ $sources{inst_external_bin} } = $Config::Config{flavour_install_bin}; # $target->{ $sources{inst_external_include} } = $Config::Config{flavour_install_include}; # $target->{ $sources{inst_external_src} } = $Config::Config{flavour_install_src}; # } # insert user overrides foreach my $key (keys %$user) { my $value = $user->{$key}; if (not defined $value and $key ne 'packlist_read' and $key ne 'packlist_write') { # undef means "remove" delete $target->{ $sources{$key} }; } elsif (exists $sources{$key}) { # overwrite stuff, don't let the user create new entries $target->{ $sources{$key} } = $value; } } # apply the automatic inst_lib => inst_archlib conversion again # if the user asks for it and there is an archlib in the .par if ($user->{auto_inst_lib_conversion} and $par_has_archlib) { $target->{inst_lib} = $target->{inst_archlib}; } return $target; } sub _directory_not_empty { require File::Find; my($dir) = @_; my $files = 0; File::Find::find(sub { return if $_ eq ".exists"; if (-f) { $File::Find::prune++; $files = 1; } }, $dir); return $files; } =head2 sign_par Digitally sign a PAR distribution using C or B, via B. =cut sub sign_par { my %args = &_args; _verify_or_sign(%args, action => 'sign'); } =head2 verify_par Verify the digital signature of a PAR distribution using C or B, via B. Returns a boolean value indicating whether verification passed; C<$!> is set to the return code of C. =cut sub verify_par { my %args = &_args; $! = _verify_or_sign(%args, action => 'verify'); return ( $! == Module::Signature::SIGNATURE_OK() ); } =head2 merge_par I Since version 0.32 of PAR::Dist, this function requires a YAML reader. The order of precedence is: YAML:XS YAML YAML::Syck YAML::Tiny Merges two or more PAR distributions into one. First argument must be the name of the distribution you want to merge all others into. Any following arguments will be interpreted as the file names of further PAR distributions to merge into the first one. merge_par('foo.par', 'bar.par', 'baz.par') This will merge the distributions C, C and C into the distribution C. C will be overwritten! The original META.yml of C is retained, but augmented with any C, C, C, C, and C sections from the other C<.par> files. =cut sub merge_par { my $base_par = shift; my @additional_pars = @_; require Cwd; require File::Copy; require File::Path; require File::Find; # parameter checking if (not defined $base_par) { croak "First argument to merge_par() must be the .par archive to modify."; } if (not -f $base_par or not -r _ or not -w _) { croak "'$base_par' is not a file or you do not have enough permissions to read and modify it."; } foreach (@additional_pars) { if (not -f $_ or not -r _) { croak "'$_' is not a file or you do not have enough permissions to read it."; } } # The unzipping will change directories. Remember old dir. my $old_cwd = Cwd::cwd(); # Unzip the base par to a temp. dir. (undef, my $base_dir) = _unzip_to_tmpdir( dist => $base_par, subdir => 'blib' ); my $blibdir = File::Spec->catdir($base_dir, 'blib'); # move the META.yml to the (main) temp. dir. my $main_meta_file = File::Spec->catfile($base_dir, 'META.yml'); File::Copy::move( File::Spec->catfile($blibdir, 'META.yml'), $main_meta_file ); # delete (incorrect) MANIFEST unlink File::Spec->catfile($blibdir, 'MANIFEST'); # extract additional pars and merge foreach my $par (@additional_pars) { # restore original directory because the par path # might have been relative! chdir($old_cwd); (undef, my $add_dir) = _unzip_to_tmpdir( dist => $par ); # merge the meta (at least the provides info) into the main meta.yml my $meta_file = File::Spec->catfile($add_dir, 'META.yml'); if (-f $meta_file) { _merge_meta($main_meta_file, $meta_file); } my @files; my @dirs; # I hate File::Find # And I hate writing portable code, too. File::Find::find( {wanted =>sub { my $file = $File::Find::name; push @files, $file if -f $file; push @dirs, $file if -d _; }}, $add_dir ); my ($vol, $subdir, undef) = File::Spec->splitpath( $add_dir, 1); my @dir = File::Spec->splitdir( $subdir ); # merge directory structure foreach my $dir (@dirs) { my ($v, $d, undef) = File::Spec->splitpath( $dir, 1 ); my @d = File::Spec->splitdir( $d ); shift @d foreach @dir; # remove tmp dir from path my $target = File::Spec->catdir( $blibdir, @d ); mkdir($target); } # merge files foreach my $file (@files) { my ($v, $d, $f) = File::Spec->splitpath( $file ); my @d = File::Spec->splitdir( $d ); shift @d foreach @dir; # remove tmp dir from path my $target = File::Spec->catfile( File::Spec->catdir( $blibdir, @d ), $f ); File::Copy::copy($file, $target) or die "Could not copy '$file' to '$target': $!"; } chdir($old_cwd); File::Path::rmtree([$add_dir]); } # delete (copied) MANIFEST and META.yml unlink File::Spec->catfile($blibdir, 'MANIFEST'); unlink File::Spec->catfile($blibdir, 'META.yml'); chdir($base_dir); my $resulting_par_file = Cwd::abs_path(blib_to_par(quiet => 1)); chdir($old_cwd); File::Copy::move($resulting_par_file, $base_par); File::Path::rmtree([$base_dir]); } sub _merge_meta { my $meta_orig_file = shift; my $meta_extra_file = shift; return() if not defined $meta_orig_file or not -f $meta_orig_file; return 1 if not defined $meta_extra_file or not -f $meta_extra_file; my $yaml_functions = _get_yaml_functions(); die "Cannot merge META.yml files without a YAML reader/writer" if !exists $yaml_functions->{LoadFile} or !exists $yaml_functions->{DumpFile}; my $orig_meta = $yaml_functions->{LoadFile}->($meta_orig_file); my $extra_meta = $yaml_functions->{LoadFile}->($meta_extra_file); # I seem to remember there was this incompatibility between the different # YAML implementations with regards to "document" handling: my $orig_tree = (ref($orig_meta) eq 'ARRAY' ? $orig_meta->[0] : $orig_meta); my $extra_tree = (ref($extra_meta) eq 'ARRAY' ? $extra_meta->[0] : $extra_meta); _merge_provides($orig_tree, $extra_tree); _merge_requires($orig_tree, $extra_tree); $yaml_functions->{DumpFile}->($meta_orig_file, $orig_meta); return 1; } # merge the two-level provides sections of META.yml sub _merge_provides { my $orig_hash = shift; my $extra_hash = shift; return() if not exists $extra_hash->{provides}; $orig_hash->{provides} ||= {}; my $orig_provides = $orig_hash->{provides}; my $extra_provides = $extra_hash->{provides}; # two level clone is enough wrt META spec 1.4 # overwrite the original provides since we're also overwriting the files. foreach my $module (keys %$extra_provides) { my $extra_mod_hash = $extra_provides->{$module}; my %mod_hash; $mod_hash{$_} = $extra_mod_hash->{$_} for keys %$extra_mod_hash; $orig_provides->{$module} = \%mod_hash; } } # merge the single-level requires-like sections of META.yml sub _merge_requires { my $orig_hash = shift; my $extra_hash = shift; foreach my $type (qw(requires build_requires configure_requires recommends)) { next if not exists $extra_hash->{$type}; $orig_hash->{$type} ||= {}; # one level clone is enough wrt META spec 1.4 foreach my $module (keys %{ $extra_hash->{$type} }) { # FIXME there should be a version comparison here, BUT how are we going to do that without a guaranteed version.pm? $orig_hash->{$type}{$module} = $extra_hash->{$type}{$module}; # assign version and module name } } } =head2 remove_man Remove the man pages from a PAR distribution. Takes one named parameter: I which should be the name (and path) of the PAR distribution file. The calling conventions outlined in the C section above apply. The PAR archive will be extracted, stripped of all C and C subdirectories and then repackaged into the original file. =cut sub remove_man { my %args = &_args; my $par = $args{dist}; require Cwd; require File::Copy; require File::Path; require File::Find; # parameter checking if (not defined $par) { croak "First argument to remove_man() must be the .par archive to modify."; } if (not -f $par or not -r _ or not -w _) { croak "'$par' is not a file or you do not have enough permissions to read and modify it."; } # The unzipping will change directories. Remember old dir. my $old_cwd = Cwd::cwd(); # Unzip the base par to a temp. dir. (undef, my $base_dir) = _unzip_to_tmpdir( dist => $par, subdir => 'blib' ); my $blibdir = File::Spec->catdir($base_dir, 'blib'); # move the META.yml to the (main) temp. dir. File::Copy::move( File::Spec->catfile($blibdir, 'META.yml'), File::Spec->catfile($base_dir, 'META.yml') ); # delete (incorrect) MANIFEST unlink File::Spec->catfile($blibdir, 'MANIFEST'); opendir DIRECTORY, 'blib' or die $!; my @dirs = grep { /^blib\/(?:man\d*|html)$/ } grep { -d $_ } map { File::Spec->catfile('blib', $_) } readdir DIRECTORY; close DIRECTORY; File::Path::rmtree(\@dirs); chdir($base_dir); my $resulting_par_file = Cwd::abs_path(blib_to_par()); chdir($old_cwd); File::Copy::move($resulting_par_file, $par); File::Path::rmtree([$base_dir]); } =head2 get_meta Opens a PAR archive and extracts the contained META.yml file. Returns the META.yml file as a string. Takes one named parameter: I. If only one parameter is passed, it is treated as the I parameter. (Have a look at the description in the C section above.) Returns undef if no PAR archive or no META.yml within the archive were found. =cut sub get_meta { my %args = &_args; my $dist = $args{dist}; return undef if not defined $dist or not -r $dist; require Cwd; require File::Path; # The unzipping will change directories. Remember old dir. my $old_cwd = Cwd::cwd(); # Unzip the base par to a temp. dir. (undef, my $base_dir) = _unzip_to_tmpdir( dist => $dist, subdir => 'blib' ); my $blibdir = File::Spec->catdir($base_dir, 'blib'); my $meta = File::Spec->catfile($blibdir, 'META.yml'); if (not -r $meta) { return undef; } open FH, '<', $meta or die "Could not open file '$meta' for reading: $!"; local $/ = undef; my $meta_text = ; close FH; chdir($old_cwd); File::Path::rmtree([$base_dir]); return $meta_text; } sub _unzip { my %args = &_args; my $dist = $args{dist}; my $path = $args{path} || File::Spec->curdir; return unless -f $dist; # Try fast unzipping first if (eval { require Archive::Unzip::Burst; 1 }) { my $return = !Archive::Unzip::Burst::unzip($dist, $path); return if $return; # true return value == error (a la system call) } # Then slow unzipping if (eval { require Archive::Zip; 1 }) { my $zip = Archive::Zip->new; local %SIG; $SIG{__WARN__} = sub { print STDERR $_[0] unless $_[0] =~ /\bstat\b/ }; return unless $zip->read($dist) == Archive::Zip::AZ_OK() and $zip->extractTree('', "$path/") == Archive::Zip::AZ_OK(); } # Then fall back to the system else { undef $!; if (_system_wrapper(unzip => $dist, '-d', $path)) { die "Failed to unzip '$dist' to path '$path': Could neither load " . "Archive::Zip nor (successfully) run the system 'unzip' (unzip said: $!)"; } } return 1; } sub _zip { my %args = &_args; my $dist = $args{dist}; if (eval { require Archive::Zip; 1 }) { my $zip = Archive::Zip->new; $zip->addTree( File::Spec->curdir, '' ); $zip->writeToFileNamed( $dist ) == Archive::Zip::AZ_OK() or die $!; } else { undef $!; if (_system_wrapper(qw(zip -r), $dist, File::Spec->curdir)) { die "Failed to zip '" .File::Spec->curdir(). "' to '$dist': Could neither load " . "Archive::Zip nor (successfully) run the system 'zip' (zip said: $!)"; } } return 1; } # This sub munges the arguments to most of the PAR::Dist functions # into a hash. On the way, it downloads PAR archives as necessary, etc. sub _args { # default to the first .par in the CWD if (not @_) { @_ = (glob('*.par'))[0]; } # single argument => it's a distribution file name or URL @_ = (dist => @_) if @_ == 1; my %args = @_; $args{name} ||= $args{dist}; # If we are installing from an URL, we want to munge the # distribution name so that it is in form "Module-Name" if (defined $args{name}) { $args{name} =~ s/^\w+:\/\///; my @elems = parse_dist_name($args{name}); # @elems is name, version, arch, perlversion if (defined $elems[0]) { $args{name} = $elems[0]; } else { $args{name} =~ s/^.*\/([^\/]+)$/$1/; $args{name} =~ s/^([0-9A-Za-z_-]+)-\d+\..+$/$1/; } } # append suffix if there is none if ($args{dist} and not $args{dist} =~ /\.[a-zA-Z_][^.]*$/) { require Config; my $suffix = $args{suffix}; $suffix ||= "$Config::Config{archname}-$Config::Config{version}.par"; $args{dist} .= "-$suffix"; } # download if it's an URL if ($args{dist} and $args{dist} =~ m!^\w+://!) { $args{dist} = _fetch(dist => $args{dist}) } return %args; } # Download PAR archive, but only if necessary (mirror!) my %escapes; sub _fetch { my %args = @_; if ($args{dist} =~ s/^file:\/\///) { return $args{dist} if -e $args{dist}; return; } require LWP::Simple; $ENV{PAR_TEMP} ||= File::Spec->catdir(File::Spec->tmpdir, 'par'); mkdir $ENV{PAR_TEMP}, 0777; %escapes = map { chr($_) => sprintf("%%%02X", $_) } 0..255 unless %escapes; $args{dist} =~ s{^cpan://((([a-zA-Z])[a-zA-Z])[-_a-zA-Z]+)/} {http://www.cpan.org/modules/by-authors/id/\U$3/$2/$1\E/}; my $file = $args{dist}; $file =~ s/([^\w\.])/$escapes{$1}/g; $file = File::Spec->catfile( $ENV{PAR_TEMP}, $file); my $rc = LWP::Simple::mirror( $args{dist}, $file ); if (!LWP::Simple::is_success($rc) and $rc != 304) { die "Error $rc: ", LWP::Simple::status_message($rc), " ($args{dist})\n"; } return $file if -e $file; return; } sub _verify_or_sign { my %args = &_args; require File::Path; require Module::Signature; die "Module::Signature version 0.25 required" unless Module::Signature->VERSION >= 0.25; require Cwd; my $cwd = Cwd::cwd(); my $action = $args{action}; my ($dist, $tmpdir) = _unzip_to_tmpdir($args{dist}); $action ||= (-e 'SIGNATURE' ? 'verify' : 'sign'); if ($action eq 'sign') { open FH, '>SIGNATURE' unless -e 'SIGNATURE'; open FH, 'MANIFEST' or die $!; local $/; my $out = ; if ($out !~ /^SIGNATURE(?:\s|$)/m) { $out =~ s/^(?!\s)/SIGNATURE\n/m; open FH, '>MANIFEST' or die $!; print FH $out; } close FH; $args{overwrite} = 1 unless exists $args{overwrite}; $args{skip} = 0 unless exists $args{skip}; } my $rv = Module::Signature->can($action)->(%args); _zip(dist => $dist) if $action eq 'sign'; File::Path::rmtree([$tmpdir]); chdir($cwd); return $rv; } sub _unzip_to_tmpdir { my %args = &_args; require File::Temp; require Cwd; my $dist = File::Spec->rel2abs($args{dist}); my $tmpdir = File::Temp::tempdir("parXXXXX", TMPDIR => 1, CLEANUP => 1) or die "Could not create temporary directory: $!"; $tmpdir = Cwd::abs_path($tmpdir); # symlinks cause Archive::Zip issues on some systems my $path = $tmpdir; $path = File::Spec->catdir($tmpdir, $args{subdir}) if defined $args{subdir}; _unzip(dist => $dist, path => $path); chdir $tmpdir; return ($dist, $tmpdir); } =head2 parse_dist_name First argument must be a distribution file name. The file name is parsed into I, I, I, and I. Returns the results as a list in the above order. If any or all of the above cannot be determined, returns undef instead of the undetermined elements. Supported formats are: Math-Symbolic-0.502-x86_64-linux-gnu-thread-multi-5.8.7 Math-Symbolic-0.502 The ".tar.gz" or ".par" extensions as well as any preceding paths are stripped before parsing. Starting with C 0.22, versions containing a preceding C are parsed correctly. This function is not exported by default. =cut sub parse_dist_name { my $file = shift; return(undef, undef, undef, undef) if not defined $file; (undef, undef, $file) = File::Spec->splitpath($file); my $version = qr/v?(?:\d+(?:_\d+)?|\d*(?:\.\d+(?:_\d+)?)+)/; $file =~ s/\.(?:par|tar\.gz|tar)$//i; my @elem = split /-/, $file; my (@dn, $dv, @arch, $pv); while (@elem) { my $e = shift @elem; if ( $e =~ /^$version$/o and not(# if not next token also a version # (assumes an arch string doesnt start with a version...) @elem and $elem[0] =~ /^$version$/o ) ) { $dv = $e; last; } push @dn, $e; } my $dn; $dn = join('-', @dn) if @dn; if (not @elem) { return( $dn, $dv, undef, undef); } while (@elem) { my $e = shift @elem; if ($e =~ /^(?:$version|any_version)$/) { $pv = $e; last; } push @arch, $e; } my $arch; $arch = join('-', @arch) if @arch; return($dn, $dv, $arch, $pv); } =head2 generate_blib_stub Creates a F subdirectory in the current directory and prepares a F with meta information for a new PAR distribution. First argument should be the name of the PAR distribution in a format understood by C. Alternatively, named arguments resembling those of C are accepted. After running C and injecting files into the F directory, you can create a PAR distribution using C. This function is useful for creating custom PAR distributions from scratch. (I.e. not from an unpacked CPAN distribution) Example: use PAR::Dist; use File::Copy 'copy'; generate_blib_stub( name => 'MyApp', version => '1.00' ); copy('MyApp.pm', 'blib/lib/MyApp.pm'); blib_to_par(); # generates the .par file! C will not overwrite existing files. =cut sub generate_blib_stub { my %args = &_args; my $dist = $args{dist}; require Config; my $name = $args{name}; my $version = $args{version}; my $suffix = $args{suffix}; my ($parse_name, $parse_version, $archname, $perlversion) = parse_dist_name($dist); $name ||= $parse_name; $version ||= $parse_version; $suffix = "$archname-$perlversion" if (not defined $suffix or $suffix eq '') and $archname and $perlversion; $suffix ||= "$Config::Config{archname}-$Config::Config{version}"; if ( grep { not defined $_ } ($name, $version, $suffix) ) { warn "Could not determine distribution meta information from distribution name '$dist'"; return(); } $suffix =~ s/\.par$//; if (not -f 'META.yml') { open META, '>', 'META.yml' or die "Could not open META.yml file for writing: $!"; print META << "YAML" if fileno(META); name: $name version: $version build_requires: {} conflicts: {} dist_name: $name-$version-$suffix.par distribution_type: par dynamic_config: 0 generated_by: 'PAR::Dist version $PAR::Dist::VERSION' license: unknown YAML close META; } mkdir('blib'); mkdir(File::Spec->catdir('blib', 'lib')); mkdir(File::Spec->catdir('blib', 'script')); return 1; } =head2 contains_binaries This function is not exported by default. Opens a PAR archive tries to determine whether that archive contains platform-specific binary code. Takes one named parameter: I. If only one parameter is passed, it is treated as the I parameter. (Have a look at the description in the C section above.) Throws a fatal error if the PAR archive could not be found. Returns one if the PAR was found to contain binary code and zero otherwise. =cut sub contains_binaries { require File::Find; my %args = &_args; my $dist = $args{dist}; return undef if not defined $dist or not -r $dist; require Cwd; require File::Path; # The unzipping will change directories. Remember old dir. my $old_cwd = Cwd::cwd(); # Unzip the base par to a temp. dir. (undef, my $base_dir) = _unzip_to_tmpdir( dist => $dist, subdir => 'blib' ); my $blibdir = File::Spec->catdir($base_dir, 'blib'); my $archdir = File::Spec->catdir($blibdir, 'arch'); my $found = 0; File::Find::find( sub { $found++ if -f $_ and not /^\.exists$/; }, $archdir ); chdir($old_cwd); File::Path::rmtree([$base_dir]); return $found ? 1 : 0; } sub _system_wrapper { if ($DEBUG) { Carp::cluck("Running system call '@_' from:"); } return system(@_); } # stolen from Module::Install::Can # very much internal and subject to change or removal sub _MI_can_run { require ExtUtils::MakeMaker; my ($cmd) = @_; my $_cmd = $cmd; return $_cmd if (-x $_cmd or $_cmd = MM->maybe_command($_cmd)); for my $dir ((split /$Config::Config{path_sep}/, $ENV{PATH}), '.') { my $abs = File::Spec->catfile($dir, $cmd); return $abs if (-x $abs or $abs = MM->maybe_command($abs)); } return; } # Tries to load any YAML reader writer I know of # returns nothing on failure or hash reference containing # a subset of Load, Dump, LoadFile, DumpFile # entries with sub references on success. sub _get_yaml_functions { # reasoning for the ranking here: # - XS is the de-facto standard nowadays. # - YAML.pm is slow and aging # - syck is fast and reasonably complete # - Tiny is only a very small subset # - Parse... is only a reader and only deals with the same subset as ::Tiny my @modules = qw(YAML::XS YAML YAML::Tiny YAML::Syck Parse::CPAN::Meta); my %yaml_functions; foreach my $module (@modules) { eval "require $module;"; if (!$@) { warn "PAR::Dist testers/debug info: Using '$module' as YAML implementation" if $DEBUG; foreach my $sub (qw(Load Dump LoadFile DumpFile)) { no strict 'refs'; my $subref = *{"${module}::$sub"}{CODE}; if (defined $subref and ref($subref) eq 'CODE') { $yaml_functions{$sub} = $subref; } } $yaml_functions{yaml_provider} = $module; last; } } # end foreach module candidates if (not keys %yaml_functions) { warn "Cannot find a working YAML reader/writer implementation. Tried to load all of '@modules'"; } return(\%yaml_functions); } sub _check_tools { my $tools = _get_yaml_functions(); if ($DEBUG) { foreach (qw/Load Dump LoadFile DumpFile/) { warn "No YAML support for $_ found.\n" if not defined $tools->{$_}; } } $tools->{zip} = undef; # A::Zip 1.28 was a broken release... if (eval {require Archive::Zip; 1;} and $Archive::Zip::VERSION ne '1.28') { warn "Using Archive::Zip as ZIP tool.\n" if $DEBUG; $tools->{zip} = 'Archive::Zip'; } elsif (_MI_can_run("zip") and _MI_can_run("unzip")) { warn "Using zip/unzip as ZIP tool.\n" if $DEBUG; $tools->{zip} = 'zip'; } else { warn "Found neither Archive::Zip (version != 1.28) nor ZIP/UNZIP as valid ZIP tools.\n" if $DEBUG; $tools->{zip} = undef; } return $tools; } 1; =head1 SEE ALSO L, L, L, L =head1 AUTHORS Audrey Tang Ecpan@audreyt.orgE 2003-2007 Steffen Mueller Esmueller@cpan.orgE 2005-2011 PAR has a mailing list, Epar@perl.orgE, that you can write to; send an empty mail to Epar-subscribe@perl.orgE to join the list and participate in the discussion. Please send bug reports to Ebug-par@rt.cpan.orgE. =head1 COPYRIGHT Copyright 2003-2011 by Audrey Tang Eautrijus@autrijus.orgE. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See L =cut