From 2a051e40a3fc09bba24c335060e8df327d313e55 Mon Sep 17 00:00:00 2001 From: Lorry Tar Creator Date: Fri, 8 Aug 2014 22:52:09 +0000 Subject: CPAN-Mini-1.111016 --- Changes | 232 +++++++ LICENSE | 379 +++++++++++ MANIFEST | 21 + MANIFEST.SKIP | 2 + META.json | 512 +++++++++++++++ META.yml | 376 +++++++++++ Makefile.PL | 83 +++ README | 15 + bin/minicpan | 185 ++++++ dist.ini | 13 + lib/CPAN/Mini.pm | 1311 ++++++++++++++++++++++++++++++++++++++ lib/CPAN/Mini/App.pm | 209 ++++++ t/00-load.t | 7 + t/000-report-versions-tiny.t | 86 +++ t/app.t | 132 ++++ t/config-file.t | 108 ++++ t/filter.t | 157 +++++ xt/fake.t | 52 ++ xt/release/changes_has_content.t | 41 ++ xt/release/pod-syntax.t | 6 + 20 files changed, 3927 insertions(+) create mode 100644 Changes create mode 100644 LICENSE create mode 100644 MANIFEST create mode 100644 MANIFEST.SKIP create mode 100644 META.json create mode 100644 META.yml create mode 100644 Makefile.PL create mode 100644 README create mode 100644 bin/minicpan create mode 100644 dist.ini create mode 100644 lib/CPAN/Mini.pm create mode 100644 lib/CPAN/Mini/App.pm create mode 100644 t/00-load.t create mode 100644 t/000-report-versions-tiny.t create mode 100644 t/app.t create mode 100644 t/config-file.t create mode 100644 t/filter.t create mode 100644 xt/fake.t create mode 100644 xt/release/changes_has_content.t create mode 100644 xt/release/pod-syntax.t diff --git a/Changes b/Changes new file mode 100644 index 0000000..e91ca8f --- /dev/null +++ b/Changes @@ -0,0 +1,232 @@ +Revision history for CPAN-Mini + +1.111016 2014-08-08 18:52:05-04:00 America/New_York + - cope with a difference in the 02packages headers made by Pinto + (thanks, Fabrice Gabolde) + +1.111015 2013-12-13 08:17:02 America/New_York + update repo and bugtracker + +1.111014 2013-11-15 19:17:39 America/New_York + prune overly-aggressively-set prereqs; we do not require CPANPLUS! + +1.111013 2013-04-13 14:02:58 Europe/London + make www.cpan.org the default remote! + + link to the list of mirrors, too (thanks, SYSMON!) + + pass all options from command line, not just known ones (thanks, + Jeffrey Thalhammer, who waited a very very long time for me to apply + this!) + + add --remote-from option to get remote from CPAN or CPANPLUS config + (thanks, Jeff Bisbee, who also waited a long time) + + expand leading "~" in config file name (suggested by justincase) + + die if local target isn't writable (suggested by SARGIE) + +1.111012 2013-03-28 16:32:58 America/New_York + when testing, mock my_home harder (thanks, David Golden!) + +1.111011 2013-02-07 16:40:23 America/New_York + check that the received 02packages seems at least remotely plausible + +1.111010 2012-10-24 10:46:35 America/New_York + fix the old ->trace method, broken in 1.111004 + +1.111009 2012-08-27 21:32:39 America/New_York + config options that once had to be specified as multiple entries + on one line may now be given as repeated entries; these are + also_mirror, module_filters, and path_filters + +1.111008 2011-12-23 13:36:41 America/New_York + don't fail tests when the outside env has set CPAN_MINI_CONFIG + (thanks, Stephen Thirwall!) + +1.111007 2011-05-12 08:21:55 America/New_York + run the test minicpan in offline mode to avoid tester errors + +1.111006 2011-04-30 14:21:22 America/New_York + set the default log_level much earlier, to avoid an undef warning + +1.111005 2011-04-29 11:14:10 America/New_York + no code changes, this release is just intended to be indexed + +1.111004 2011-04-26 08:57:00 America/New_York + overhaul logging: there is now a log_level + + delay creation of scratch dir until needed + + a bunch of tests added for switch and config processing + +1.111003 2011-04-18 14:17:36 Europe/Amsterdam + add tools for building a fake cpan and an xt test for testing online + +1.111002 2011-04-16 18:20:43 Europe/Amsterdam + + test for online-ness by HEAD-ing 02packages, not the remote root + +1.111001 2011-02-10 19:34:38 America/New_York + restore six-digit-mantissa versioning to help downstream packagers + +1.111 2011-02-05 15:13:17 America/New_York + add --timeout (thanks, Gabor Szabo!) + +1.110 2011-01-27 21:48:34 America/New_York + if the config file does not exist, do not die or spew warnings; this + fixes RT #57388 + +1.100630 2010-03-04 07:57:34 America/New_York + suppress "using config..." during setup with -qq + +1.100593 2010-02-28 16:58:34 America/New_York + fix a previously unreached bit of code re: basename + +1.100592 2010-02-28 15:15:36 America/New_York + fix insanely stupid typo; need more tests! + +1.100591 2010-02-28 15:11:03 America/New_York + add an option to skip source code control files (thanks, brian d foy) + +1.100590 2009-02-28 + add -C switch to allow alternate config file (thanks, brian d foy) + getopt switches are now correctly case-sensitive (thanks, brian) + improve subclassability for config file and output (thanks, brian) + switch to Dist::Zilla for release management + +0.576 2009-01-16 + add repo to metadata + +0.575 2009-01-12 + add no_conn_cache argument + +0.574 2008-11-26 + fix broken prereq declaration in Makefile.PL + +0.573 2008-11-25 + switch to new File::Path API, do not suffer undef dirmodes + write a RECENT file of the files mirrored in the latest run + +0.572 2008-11-04 + add 'use File::HomeDir' to CPAN/Mini.pm (thanks DAGOLDEN) + improve handling of trailing whitespace in config (thanks ANK) + +0.571 2008-05-23 + set LWP::UserAgent's env_proxy option to use proxy (RT #36124 from + IFOMICHEV) + + allow skip_cleanup in config + +0.570 2008-05-01 + offline mode now (correctly) means that the remote is not checked for + availability (RT #35563) + +0.569 2008-04-30 + massive speed improvements by caching connection to remote mirror + add offline mode (by request of ADAMK) + add default config file location (by request of ADAMK) + +0.568 2008-03-05 + [ no code changes ] + fix distribution to remove resource forks (ugh!) + +0.567 2008-02-05 + BUGFIX: actually respect -c option + internal refactoring to make subclassing easier (DAGOLDEN) + bring code formatting inline with other (code (simply)) code + +0.566 2008-01-21 + do not mirror "also_mirror" files twice (thanks DAGOLDEN) + +0.565 2007-11-08 + move guts of minicpan command to ::App + CPANTS tweaks + switch to Module::Install + +0.564 2007-10-31 + tweak packaging for CPANTS + +0.563 2007-10-16 + MAJOR BUG FIX: mirror files in ./modules + introduced in 0.561, this bug only affected new mirrors, so anyone + who had been using it before that would not have noticed + BUG FIX: don't be so pedantic about requiring that remote end in / + +0.562 2007-07-04 + fix skip_perl to continue to skip a perl-like dist + +0.561 2007-07-03 + initially mirror indices to a scratch space, so that the indices in + the minicpan are not replaced until all referenced files are in place + + when skipping perls, also skip: kurila, perl_mlb + +0.552 2006-12-01 + documentation fixes + +0.551 2006-11-13 + packaging improvements + +0.550 2006-08-08 + add tilde expansion for homedir in local mirror specification + move configuration reading into CPAN::Mini + document a few previously-undocumented things + documentation cleanup + added unused-by-script option to use current mtime for indices + (this helps CPANPLUS do the right thing) + +0.500 2006-07-11 + we no longer need File::HomeDir::Win32 on Windows + provide the also_mirror option to get other static files + +0.40 2005-11-04 + remove force option to trace + create local mirror if needed + notice if local mirror -e && ! -d + cleared out stupid /\A\s+\z/ lines + +0.38 2005-10-13 00:05 + more intelligently divide cleanup tasks (isn't ADAMK great?) + move arg validity check constructor (to silence ADAMK) + add some more checks for validity (stolen from ADAMK) + add errors option and -qq commandline option for it + +0.36 2005-01-06 18:40 + code refs can be passed to _filters, which were slightly refactored + +0.32 2004-12-31 15:45 + added an old alpha binary for perl to the perls to skip + +0.30 2004-12-28 10:00 + added a "new" method for construction + update_mirror can act as class or instance method + added clean_file method + +0.26 2004-12-02 15:05 + require version 5.6 of perl in Makefile.PL + +0.24 2004-11-29 14:30 + dirmode is correctly octalized (thanks SSORICHE) + sungo's *_filters patch + +0.20 2004-09-28 10:20 + added config file + added file_allowed (to override cleanup) + the -d option, long documented, now works + +0.18 2004-09-21 20:15 + canonpath File::Find::name to avoid horrible Win32 bug + added -v to print version of CPAN::Mini + +0.16 2004-09-07 21:50 + added -d to set mode for created dirs + +0.14 2004-08-28 17:05 + uses Pod::Usage + now skips ponie and parrot (not just perl) + -p option to override the above skipping + "seen_changes" attribute and return value added + +0.10 2004-08-26 10:50 + initial release diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c08394d --- /dev/null +++ b/LICENSE @@ -0,0 +1,379 @@ +This software is copyright (c) 2004 by Ricardo SIGNES. + +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 --- + +This software is Copyright (c) 2004 by Ricardo SIGNES. + +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 --- + +This software is Copyright (c) 2004 by Ricardo SIGNES. + +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 + diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..0d05514 --- /dev/null +++ b/MANIFEST @@ -0,0 +1,21 @@ +# This file was automatically generated by Dist::Zilla::Plugin::Manifest v5.020. +Changes +LICENSE +MANIFEST +MANIFEST.SKIP +META.json +META.yml +Makefile.PL +README +bin/minicpan +dist.ini +lib/CPAN/Mini.pm +lib/CPAN/Mini/App.pm +t/00-load.t +t/000-report-versions-tiny.t +t/app.t +t/config-file.t +t/filter.t +xt/fake.t +xt/release/changes_has_content.t +xt/release/pod-syntax.t diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP new file mode 100644 index 0000000..d04795b --- /dev/null +++ b/MANIFEST.SKIP @@ -0,0 +1,2 @@ +misc +fakecpan diff --git a/META.json b/META.json new file mode 100644 index 0000000..b1c4854 --- /dev/null +++ b/META.json @@ -0,0 +1,512 @@ +{ + "abstract" : "create a minimal mirror of CPAN", + "author" : [ + "Ricardo SIGNES ", + "Randal Schwartz " + ], + "dynamic_config" : 0, + "generated_by" : "Dist::Zilla version 5.020, CPAN::Meta::Converter version 2.141520", + "license" : [ + "perl_5" + ], + "meta-spec" : { + "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", + "version" : "2" + }, + "name" : "CPAN-Mini", + "prereqs" : { + "configure" : { + "requires" : { + "ExtUtils::MakeMaker" : "0" + } + }, + "develop" : { + "requires" : { + "Test::Pod" : "1.41", + "version" : "0.9901" + } + }, + "runtime" : { + "requires" : { + "Carp" : "0", + "Compress::Zlib" : "1.20", + "File::Basename" : "0", + "File::Copy" : "0", + "File::Find" : "0", + "File::HomeDir" : "0.57", + "File::Path" : "2.04", + "File::Spec" : "0", + "File::Temp" : "0", + "Getopt::Long" : "0", + "LWP::UserAgent" : "5", + "Pod::Usage" : "1.00", + "URI" : "1", + "perl" : "5.006", + "strict" : "0", + "warnings" : "0" + } + }, + "test" : { + "requires" : { + "Test::More" : "0.96" + } + } + }, + "release_status" : "stable", + "resources" : { + "bugtracker" : { + "web" : "https://github.com/rjbs/CPAN-Mini/issues" + }, + "homepage" : "https://github.com/rjbs/CPAN-Mini", + "repository" : { + "type" : "git", + "url" : "https://github.com/rjbs/CPAN-Mini.git", + "web" : "https://github.com/rjbs/CPAN-Mini" + } + }, + "version" : "1.111016", + "x_Dist_Zilla" : { + "perl" : { + "version" : "5.021002" + }, + "plugins" : [ + { + "class" : "Dist::Zilla::Plugin::Git::GatherDir", + "config" : { + "Dist::Zilla::Plugin::Git::GatherDir" : { + "include_untracked" : "0" + }, + "Dist::Zilla::Role::Git::Repo" : { + "repo_root" : "." + } + }, + "name" : "@RJBS/Git::GatherDir", + "version" : "2.023" + }, + { + "class" : "Dist::Zilla::Plugin::CheckPrereqsIndexed", + "name" : "@RJBS/CheckPrereqsIndexed", + "version" : "0.012" + }, + { + "class" : "Dist::Zilla::Plugin::CheckExtraTests", + "name" : "@RJBS/CheckExtraTests", + "version" : "0.022" + }, + { + "class" : "Dist::Zilla::Plugin::PromptIfStale", + "config" : { + "Dist::Zilla::Plugin::PromptIfStale" : { + "check_all_plugins" : 0, + "check_all_prereqs" : 0, + "modules" : [ + "Dist::Zilla::PluginBundle::RJBS" + ], + "phase" : "build", + "skip" : [] + } + }, + "name" : "@RJBS/RJBS-Outdated", + "version" : "0.024" + }, + { + "class" : "Dist::Zilla::Plugin::PromptIfStale", + "config" : { + "Dist::Zilla::Plugin::PromptIfStale" : { + "check_all_plugins" : "1", + "check_all_prereqs" : 0, + "modules" : [], + "phase" : "release", + "skip" : [] + } + }, + "name" : "@RJBS/CPAN-Outdated", + "version" : "0.024" + }, + { + "class" : "Dist::Zilla::Plugin::PruneCruft", + "name" : "@RJBS/@Filter/PruneCruft", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::ManifestSkip", + "name" : "@RJBS/@Filter/ManifestSkip", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::MetaYAML", + "name" : "@RJBS/@Filter/MetaYAML", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::License", + "name" : "@RJBS/@Filter/License", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::Readme", + "name" : "@RJBS/@Filter/Readme", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::ExecDir", + "name" : "@RJBS/@Filter/ExecDir", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::ShareDir", + "name" : "@RJBS/@Filter/ShareDir", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::Manifest", + "name" : "@RJBS/@Filter/Manifest", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::TestRelease", + "name" : "@RJBS/@Filter/TestRelease", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::ConfirmRelease", + "name" : "@RJBS/@Filter/ConfirmRelease", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::UploadToCPAN", + "name" : "@RJBS/@Filter/UploadToCPAN", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::MakeMaker", + "config" : { + "Dist::Zilla::Role::TestRunner" : { + "default_jobs" : 9 + } + }, + "name" : "@RJBS/MakeMaker", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::AutoPrereqs", + "name" : "@RJBS/AutoPrereqs", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::Git::NextVersion", + "config" : { + "Dist::Zilla::Plugin::Git::NextVersion" : { + "first_version" : "0.001", + "version_by_branch" : "0", + "version_regexp" : "(?^:^([0-9]+\\.[0-9]+)$)" + }, + "Dist::Zilla::Role::Git::Repo" : { + "repo_root" : "." + } + }, + "name" : "@RJBS/Git::NextVersion", + "version" : "2.023" + }, + { + "class" : "Dist::Zilla::Plugin::PkgVersion", + "name" : "@RJBS/PkgVersion", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::MetaConfig", + "name" : "@RJBS/MetaConfig", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::MetaJSON", + "name" : "@RJBS/MetaJSON", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::NextRelease", + "name" : "@RJBS/NextRelease", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::Test::ChangesHasContent", + "name" : "@RJBS/Test::ChangesHasContent", + "version" : "0.006" + }, + { + "class" : "Dist::Zilla::Plugin::PodSyntaxTests", + "name" : "@RJBS/PodSyntaxTests", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::ReportVersions::Tiny", + "name" : "@RJBS/ReportVersions::Tiny", + "version" : "1.10" + }, + { + "class" : "Dist::Zilla::Plugin::Prereqs", + "config" : { + "Dist::Zilla::Plugin::Prereqs" : { + "phase" : "test", + "type" : "requires" + } + }, + "name" : "@RJBS/TestMoreWithSubtests", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::PodWeaver", + "config" : { + "Dist::Zilla::Plugin::PodWeaver" : { + "config_plugins" : [ + "@RJBS" + ], + "finder" : [ + ":InstallModules", + ":ExecFiles" + ], + "plugins" : [ + { + "class" : "Pod::Weaver::Plugin::EnsurePod5", + "name" : "@CorePrep/EnsurePod5", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Plugin::H1Nester", + "name" : "@CorePrep/H1Nester", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Plugin::SingleEncoding", + "name" : "@RJBS/SingleEncoding", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Name", + "name" : "@RJBS/Name", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Version", + "name" : "@RJBS/Version", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Region", + "name" : "@RJBS/Prelude", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Generic", + "name" : "@RJBS/Synopsis", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Generic", + "name" : "@RJBS/Description", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Generic", + "name" : "@RJBS/Overview", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Generic", + "name" : "@RJBS/Stability", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Collect", + "name" : "Attributes", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Collect", + "name" : "Methods", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Collect", + "name" : "Functions", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Leftovers", + "name" : "@RJBS/Leftovers", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Region", + "name" : "@RJBS/postlude", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Authors", + "name" : "@RJBS/Authors", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Section::Legal", + "name" : "@RJBS/Legal", + "version" : "4.006" + }, + { + "class" : "Pod::Weaver::Plugin::Transformer", + "name" : "@RJBS/List", + "version" : "4.006" + } + ] + } + }, + "name" : "@RJBS/PodWeaver", + "version" : "4.005" + }, + { + "class" : "Dist::Zilla::Plugin::GithubMeta", + "name" : "@RJBS/GithubMeta", + "version" : "0.46" + }, + { + "class" : "Dist::Zilla::Plugin::Git::Check", + "config" : { + "Dist::Zilla::Plugin::Git::Check" : { + "untracked_files" : "die" + }, + "Dist::Zilla::Role::Git::DirtyFiles" : { + "allow_dirty" : [ + "dist.ini", + "Changes" + ], + "allow_dirty_match" : [], + "changelog" : "Changes" + }, + "Dist::Zilla::Role::Git::Repo" : { + "repo_root" : "." + } + }, + "name" : "@RJBS/@Git/Check", + "version" : "2.023" + }, + { + "class" : "Dist::Zilla::Plugin::Git::Commit", + "config" : { + "Dist::Zilla::Plugin::Git::Commit" : { + "add_files_in" : [], + "commit_msg" : "v%v%n%n%c", + "time_zone" : "local" + }, + "Dist::Zilla::Role::Git::DirtyFiles" : { + "allow_dirty" : [ + "dist.ini", + "Changes" + ], + "allow_dirty_match" : [], + "changelog" : "Changes" + }, + "Dist::Zilla::Role::Git::Repo" : { + "repo_root" : "." + } + }, + "name" : "@RJBS/@Git/Commit", + "version" : "2.023" + }, + { + "class" : "Dist::Zilla::Plugin::Git::Tag", + "config" : { + "Dist::Zilla::Plugin::Git::Tag" : { + "branch" : null, + "signed" : 0, + "tag" : "1.111016", + "tag_format" : "%v", + "tag_message" : "v%v", + "time_zone" : "local" + }, + "Dist::Zilla::Role::Git::Repo" : { + "repo_root" : "." + } + }, + "name" : "@RJBS/@Git/Tag", + "version" : "2.023" + }, + { + "class" : "Dist::Zilla::Plugin::Git::Push", + "config" : { + "Dist::Zilla::Plugin::Git::Push" : { + "push_to" : [ + "origin :", + "github :" + ], + "remotes_must_exist" : 0 + }, + "Dist::Zilla::Role::Git::Repo" : { + "repo_root" : "." + } + }, + "name" : "@RJBS/@Git/Push", + "version" : "2.023" + }, + { + "class" : "Dist::Zilla::Plugin::RemovePrereqs", + "config" : { + "Dist::Zilla::Plugin::RemovePrereqs" : { + "modules_to_remove" : [ + "CPAN", + "CPANPLUS::Backend" + ] + } + }, + "name" : "RemovePrereqs", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":InstallModules", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":IncModules", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":TestFiles", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":ExecFiles", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":ShareFiles", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":MainModule", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":AllFiles", + "version" : "5.020" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":NoFiles", + "version" : "5.020" + } + ], + "zilla" : { + "class" : "Dist::Zilla::Dist::Builder", + "config" : { + "is_trial" : "0" + }, + "version" : "5.020" + } + } +} + diff --git a/META.yml b/META.yml new file mode 100644 index 0000000..2e672f9 --- /dev/null +++ b/META.yml @@ -0,0 +1,376 @@ +--- +abstract: 'create a minimal mirror of CPAN' +author: + - 'Ricardo SIGNES ' + - 'Randal Schwartz ' +build_requires: + Test::More: '0.96' +configure_requires: + ExtUtils::MakeMaker: '0' +dynamic_config: 0 +generated_by: 'Dist::Zilla version 5.020, CPAN::Meta::Converter version 2.141520' +license: perl +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.4.html + version: '1.4' +name: CPAN-Mini +requires: + Carp: '0' + Compress::Zlib: '1.20' + File::Basename: '0' + File::Copy: '0' + File::Find: '0' + File::HomeDir: '0.57' + File::Path: '2.04' + File::Spec: '0' + File::Temp: '0' + Getopt::Long: '0' + LWP::UserAgent: '5' + Pod::Usage: '1.00' + URI: '1' + perl: '5.006' + strict: '0' + warnings: '0' +resources: + bugtracker: https://github.com/rjbs/CPAN-Mini/issues + homepage: https://github.com/rjbs/CPAN-Mini + repository: https://github.com/rjbs/CPAN-Mini.git +version: '1.111016' +x_Dist_Zilla: + perl: + version: '5.021002' + plugins: + - + class: Dist::Zilla::Plugin::Git::GatherDir + config: + Dist::Zilla::Plugin::Git::GatherDir: + include_untracked: '0' + Dist::Zilla::Role::Git::Repo: + repo_root: . + name: '@RJBS/Git::GatherDir' + version: '2.023' + - + class: Dist::Zilla::Plugin::CheckPrereqsIndexed + name: '@RJBS/CheckPrereqsIndexed' + version: '0.012' + - + class: Dist::Zilla::Plugin::CheckExtraTests + name: '@RJBS/CheckExtraTests' + version: '0.022' + - + class: Dist::Zilla::Plugin::PromptIfStale + config: + Dist::Zilla::Plugin::PromptIfStale: + check_all_plugins: 0 + check_all_prereqs: 0 + modules: + - Dist::Zilla::PluginBundle::RJBS + phase: build + skip: [] + name: '@RJBS/RJBS-Outdated' + version: '0.024' + - + class: Dist::Zilla::Plugin::PromptIfStale + config: + Dist::Zilla::Plugin::PromptIfStale: + check_all_plugins: '1' + check_all_prereqs: 0 + modules: [] + phase: release + skip: [] + name: '@RJBS/CPAN-Outdated' + version: '0.024' + - + class: Dist::Zilla::Plugin::PruneCruft + name: '@RJBS/@Filter/PruneCruft' + version: '5.020' + - + class: Dist::Zilla::Plugin::ManifestSkip + name: '@RJBS/@Filter/ManifestSkip' + version: '5.020' + - + class: Dist::Zilla::Plugin::MetaYAML + name: '@RJBS/@Filter/MetaYAML' + version: '5.020' + - + class: Dist::Zilla::Plugin::License + name: '@RJBS/@Filter/License' + version: '5.020' + - + class: Dist::Zilla::Plugin::Readme + name: '@RJBS/@Filter/Readme' + version: '5.020' + - + class: Dist::Zilla::Plugin::ExecDir + name: '@RJBS/@Filter/ExecDir' + version: '5.020' + - + class: Dist::Zilla::Plugin::ShareDir + name: '@RJBS/@Filter/ShareDir' + version: '5.020' + - + class: Dist::Zilla::Plugin::Manifest + name: '@RJBS/@Filter/Manifest' + version: '5.020' + - + class: Dist::Zilla::Plugin::TestRelease + name: '@RJBS/@Filter/TestRelease' + version: '5.020' + - + class: Dist::Zilla::Plugin::ConfirmRelease + name: '@RJBS/@Filter/ConfirmRelease' + version: '5.020' + - + class: Dist::Zilla::Plugin::UploadToCPAN + name: '@RJBS/@Filter/UploadToCPAN' + version: '5.020' + - + class: Dist::Zilla::Plugin::MakeMaker + config: + Dist::Zilla::Role::TestRunner: + default_jobs: 9 + name: '@RJBS/MakeMaker' + version: '5.020' + - + class: Dist::Zilla::Plugin::AutoPrereqs + name: '@RJBS/AutoPrereqs' + version: '5.020' + - + class: Dist::Zilla::Plugin::Git::NextVersion + config: + Dist::Zilla::Plugin::Git::NextVersion: + first_version: '0.001' + version_by_branch: '0' + version_regexp: (?^:^([0-9]+\.[0-9]+)$) + Dist::Zilla::Role::Git::Repo: + repo_root: . + name: '@RJBS/Git::NextVersion' + version: '2.023' + - + class: Dist::Zilla::Plugin::PkgVersion + name: '@RJBS/PkgVersion' + version: '5.020' + - + class: Dist::Zilla::Plugin::MetaConfig + name: '@RJBS/MetaConfig' + version: '5.020' + - + class: Dist::Zilla::Plugin::MetaJSON + name: '@RJBS/MetaJSON' + version: '5.020' + - + class: Dist::Zilla::Plugin::NextRelease + name: '@RJBS/NextRelease' + version: '5.020' + - + class: Dist::Zilla::Plugin::Test::ChangesHasContent + name: '@RJBS/Test::ChangesHasContent' + version: '0.006' + - + class: Dist::Zilla::Plugin::PodSyntaxTests + name: '@RJBS/PodSyntaxTests' + version: '5.020' + - + class: Dist::Zilla::Plugin::ReportVersions::Tiny + name: '@RJBS/ReportVersions::Tiny' + version: '1.10' + - + class: Dist::Zilla::Plugin::Prereqs + config: + Dist::Zilla::Plugin::Prereqs: + phase: test + type: requires + name: '@RJBS/TestMoreWithSubtests' + version: '5.020' + - + class: Dist::Zilla::Plugin::PodWeaver + config: + Dist::Zilla::Plugin::PodWeaver: + config_plugins: + - '@RJBS' + finder: + - ':InstallModules' + - ':ExecFiles' + plugins: + - + class: Pod::Weaver::Plugin::EnsurePod5 + name: '@CorePrep/EnsurePod5' + version: '4.006' + - + class: Pod::Weaver::Plugin::H1Nester + name: '@CorePrep/H1Nester' + version: '4.006' + - + class: Pod::Weaver::Plugin::SingleEncoding + name: '@RJBS/SingleEncoding' + version: '4.006' + - + class: Pod::Weaver::Section::Name + name: '@RJBS/Name' + version: '4.006' + - + class: Pod::Weaver::Section::Version + name: '@RJBS/Version' + version: '4.006' + - + class: Pod::Weaver::Section::Region + name: '@RJBS/Prelude' + version: '4.006' + - + class: Pod::Weaver::Section::Generic + name: '@RJBS/Synopsis' + version: '4.006' + - + class: Pod::Weaver::Section::Generic + name: '@RJBS/Description' + version: '4.006' + - + class: Pod::Weaver::Section::Generic + name: '@RJBS/Overview' + version: '4.006' + - + class: Pod::Weaver::Section::Generic + name: '@RJBS/Stability' + version: '4.006' + - + class: Pod::Weaver::Section::Collect + name: Attributes + version: '4.006' + - + class: Pod::Weaver::Section::Collect + name: Methods + version: '4.006' + - + class: Pod::Weaver::Section::Collect + name: Functions + version: '4.006' + - + class: Pod::Weaver::Section::Leftovers + name: '@RJBS/Leftovers' + version: '4.006' + - + class: Pod::Weaver::Section::Region + name: '@RJBS/postlude' + version: '4.006' + - + class: Pod::Weaver::Section::Authors + name: '@RJBS/Authors' + version: '4.006' + - + class: Pod::Weaver::Section::Legal + name: '@RJBS/Legal' + version: '4.006' + - + class: Pod::Weaver::Plugin::Transformer + name: '@RJBS/List' + version: '4.006' + name: '@RJBS/PodWeaver' + version: '4.005' + - + class: Dist::Zilla::Plugin::GithubMeta + name: '@RJBS/GithubMeta' + version: '0.46' + - + class: Dist::Zilla::Plugin::Git::Check + config: + Dist::Zilla::Plugin::Git::Check: + untracked_files: die + Dist::Zilla::Role::Git::DirtyFiles: + allow_dirty: + - dist.ini + - Changes + allow_dirty_match: [] + changelog: Changes + Dist::Zilla::Role::Git::Repo: + repo_root: . + name: '@RJBS/@Git/Check' + version: '2.023' + - + class: Dist::Zilla::Plugin::Git::Commit + config: + Dist::Zilla::Plugin::Git::Commit: + add_files_in: [] + commit_msg: v%v%n%n%c + time_zone: local + Dist::Zilla::Role::Git::DirtyFiles: + allow_dirty: + - dist.ini + - Changes + allow_dirty_match: [] + changelog: Changes + Dist::Zilla::Role::Git::Repo: + repo_root: . + name: '@RJBS/@Git/Commit' + version: '2.023' + - + class: Dist::Zilla::Plugin::Git::Tag + config: + Dist::Zilla::Plugin::Git::Tag: + branch: ~ + signed: 0 + tag: '1.111016' + tag_format: '%v' + tag_message: v%v + time_zone: local + Dist::Zilla::Role::Git::Repo: + repo_root: . + name: '@RJBS/@Git/Tag' + version: '2.023' + - + class: Dist::Zilla::Plugin::Git::Push + config: + Dist::Zilla::Plugin::Git::Push: + push_to: + - 'origin :' + - 'github :' + remotes_must_exist: 0 + Dist::Zilla::Role::Git::Repo: + repo_root: . + name: '@RJBS/@Git/Push' + version: '2.023' + - + class: Dist::Zilla::Plugin::RemovePrereqs + config: + Dist::Zilla::Plugin::RemovePrereqs: + modules_to_remove: + - CPAN + - CPANPLUS::Backend + name: RemovePrereqs + version: '5.020' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':InstallModules' + version: '5.020' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':IncModules' + version: '5.020' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':TestFiles' + version: '5.020' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':ExecFiles' + version: '5.020' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':ShareFiles' + version: '5.020' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':MainModule' + version: '5.020' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':AllFiles' + version: '5.020' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':NoFiles' + version: '5.020' + zilla: + class: Dist::Zilla::Dist::Builder + config: + is_trial: '0' + version: '5.020' diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..ca5bb37 --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,83 @@ + +# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v5.020. +use strict; +use warnings; + +use 5.006; + +use ExtUtils::MakeMaker ; + + + +my %WriteMakefileArgs = ( + "ABSTRACT" => "create a minimal mirror of CPAN", + "AUTHOR" => "Ricardo SIGNES , Randal Schwartz ", + "CONFIGURE_REQUIRES" => { + "ExtUtils::MakeMaker" => 0 + }, + "DISTNAME" => "CPAN-Mini", + "EXE_FILES" => [ + "bin/minicpan" + ], + "LICENSE" => "perl", + "NAME" => "CPAN::Mini", + "PREREQ_PM" => { + "Carp" => 0, + "Compress::Zlib" => "1.20", + "File::Basename" => 0, + "File::Copy" => 0, + "File::Find" => 0, + "File::HomeDir" => "0.57", + "File::Path" => "2.04", + "File::Spec" => 0, + "File::Temp" => 0, + "Getopt::Long" => 0, + "LWP::UserAgent" => 5, + "Pod::Usage" => "1.00", + "URI" => 1, + "strict" => 0, + "warnings" => 0 + }, + "TEST_REQUIRES" => { + "Test::More" => "0.96" + }, + "VERSION" => "1.111016", + "test" => { + "TESTS" => "t/*.t" + } +); + + +my %FallbackPrereqs = ( + "Carp" => 0, + "Compress::Zlib" => "1.20", + "File::Basename" => 0, + "File::Copy" => 0, + "File::Find" => 0, + "File::HomeDir" => "0.57", + "File::Path" => "2.04", + "File::Spec" => 0, + "File::Temp" => 0, + "Getopt::Long" => 0, + "LWP::UserAgent" => 5, + "Pod::Usage" => "1.00", + "Test::More" => "0.96", + "URI" => 1, + "strict" => 0, + "warnings" => 0 +); + + +unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) { + delete $WriteMakefileArgs{TEST_REQUIRES}; + delete $WriteMakefileArgs{BUILD_REQUIRES}; + $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs; +} + +delete $WriteMakefileArgs{CONFIGURE_REQUIRES} + unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; + +WriteMakefile(%WriteMakefileArgs); + + + diff --git a/README b/README new file mode 100644 index 0000000..d6b538c --- /dev/null +++ b/README @@ -0,0 +1,15 @@ + + +This archive contains the distribution CPAN-Mini, +version 1.111016: + + create a minimal mirror of CPAN + +This software is copyright (c) 2004 by Ricardo SIGNES. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + + +This README file was generated by Dist::Zilla::Plugin::Readme v5.020. + diff --git a/bin/minicpan b/bin/minicpan new file mode 100644 index 0000000..66f4e65 --- /dev/null +++ b/bin/minicpan @@ -0,0 +1,185 @@ +#!/usr/bin/perl -w +use strict; +use warnings; +use CPAN::Mini::App; +CPAN::Mini::App->run; + +# PODNAME: minicpan +# ABSTRACT: uses CPAN::Mini to create or update a local mirror + +=pod + +=encoding UTF-8 + +=head1 NAME + +minicpan - uses CPAN::Mini to create or update a local mirror + +=head1 VERSION + +version 1.111016 + +=head1 SYNOPSIS + + minicpan [options] + + Options + -l LOCAL - where is the local minicpan? (required) + -r REMOTE - where is the remote cpan mirror? (required) + -d 0### - permissions (numeric) to use when creating directories + -f - check all directories, even if indices are unchanged + -p - mirror perl, ponie, and parrot distributions + --debug - run in debug mode (print even banal messages) + -q - run in quiet mode (don't print status) + -qq - run in silent mode (don't even print warnings) + -c CLASS - what class to use to mirror (default: CPAN::Mini) + -C FILE - what config file to use (default: ~/.minicpanrc) + -h - print help and exit + -v - print version and exit + -x - build an exact mirror, getting even normally disallowed files + -t SEC - timeout in sec. Defaults to 180 sec + --offline - operate in offline mode (generally: do nothing) + --log-level - provide a log level; instead of --debug, -q, or -qq + --remote-from TYPE - cpan remote from 'cpan' or 'cpanplus' configs + +=head1 DESCRIPTION + +This simple shell script just updates (or creates) a miniature CPAN mirror as +described in CPAN::Mini. + +=head1 CONFIGURATION FILE + +By default, C will read a configuration file to get configuration +information. The file is a simple set of names and values, as in the following +example: + + local: /home/rjbs/mirrors/minicpan/ + remote: http://your.favorite.cpan/cpan/ + exact_mirror: 1 + +C tries to find a configuration file through the following process. +It takes the first defined it finds: + +=over 4 + +=item * Use the value specified by C<-C> on the command line + +=item * Use the value in the C environment variable + +=item * Use F<~/.minicpanrc> + +=item * Use F + +=back + +If the selected file does not exist, C does not keep looking. + +You can override this process with a C method in your subclass. + +See C for a full listing of available options. + +=head1 TO DO + +Improve command-line options. + +=head1 SEE ALSO + +Randal Schwartz's original article, which can be found here: + + http://www.stonehenge.com/merlyn/LinuxMag/col42.html + +=head1 AUTHORS + +=over 4 + +=item * + +Ricardo SIGNES + +=item * + +Randal Schwartz + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2004 by Ricardo SIGNES. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut + +__END__ + +#pod =head1 SYNOPSIS +#pod +#pod minicpan [options] +#pod +#pod Options +#pod -l LOCAL - where is the local minicpan? (required) +#pod -r REMOTE - where is the remote cpan mirror? (required) +#pod -d 0### - permissions (numeric) to use when creating directories +#pod -f - check all directories, even if indices are unchanged +#pod -p - mirror perl, ponie, and parrot distributions +#pod --debug - run in debug mode (print even banal messages) +#pod -q - run in quiet mode (don't print status) +#pod -qq - run in silent mode (don't even print warnings) +#pod -c CLASS - what class to use to mirror (default: CPAN::Mini) +#pod -C FILE - what config file to use (default: ~/.minicpanrc) +#pod -h - print help and exit +#pod -v - print version and exit +#pod -x - build an exact mirror, getting even normally disallowed files +#pod -t SEC - timeout in sec. Defaults to 180 sec +#pod --offline - operate in offline mode (generally: do nothing) +#pod --log-level - provide a log level; instead of --debug, -q, or -qq +#pod --remote-from TYPE - cpan remote from 'cpan' or 'cpanplus' configs +#pod +#pod =head1 DESCRIPTION +#pod +#pod This simple shell script just updates (or creates) a miniature CPAN mirror as +#pod described in CPAN::Mini. +#pod +#pod =head1 CONFIGURATION FILE +#pod +#pod By default, C will read a configuration file to get configuration +#pod information. The file is a simple set of names and values, as in the following +#pod example: +#pod +#pod local: /home/rjbs/mirrors/minicpan/ +#pod remote: http://your.favorite.cpan/cpan/ +#pod exact_mirror: 1 +#pod +#pod C tries to find a configuration file through the following process. +#pod It takes the first defined it finds: +#pod +#pod =over 4 +#pod +#pod =item * Use the value specified by C<-C> on the command line +#pod +#pod =item * Use the value in the C environment variable +#pod +#pod =item * Use F<~/.minicpanrc> +#pod +#pod =item * Use F +#pod +#pod =back +#pod +#pod If the selected file does not exist, C does not keep looking. +#pod +#pod You can override this process with a C method in your subclass. +#pod +#pod See C for a full listing of available options. +#pod +#pod =head1 TO DO +#pod +#pod Improve command-line options. +#pod +#pod =head1 SEE ALSO +#pod +#pod Randal Schwartz's original article, which can be found here: +#pod +#pod http://www.stonehenge.com/merlyn/LinuxMag/col42.html +#pod +#pod =cut diff --git a/dist.ini b/dist.ini new file mode 100644 index 0000000..829bb89 --- /dev/null +++ b/dist.ini @@ -0,0 +1,13 @@ +name = CPAN-Mini +author = Ricardo SIGNES +author = Randal Schwartz +license = Perl_5 +copyright_year = 2004 +copyright_holder = Ricardo SIGNES + +[@RJBS] +version = 1 + +[RemovePrereqs] +remove = CPAN +remove = CPANPLUS::Backend diff --git a/lib/CPAN/Mini.pm b/lib/CPAN/Mini.pm new file mode 100644 index 0000000..9569082 --- /dev/null +++ b/lib/CPAN/Mini.pm @@ -0,0 +1,1311 @@ +use 5.006; +use strict; +use warnings; + +package CPAN::Mini; +$CPAN::Mini::VERSION = '1.111016'; +# ABSTRACT: create a minimal mirror of CPAN + +## no critic RequireCarping + +#pod =head1 SYNOPSIS +#pod +#pod (If you're not going to do something weird, you probably want to look at the +#pod L command, instead.) +#pod +#pod use CPAN::Mini; +#pod +#pod CPAN::Mini->update_mirror( +#pod remote => "http://cpan.mirrors.comintern.su", +#pod local => "/usr/share/mirrors/cpan", +#pod log_level => 'debug', +#pod ); +#pod +#pod =head1 DESCRIPTION +#pod +#pod CPAN::Mini provides a simple mechanism to build and update a minimal mirror of +#pod the CPAN on your local disk. It contains only those files needed to install +#pod the newest version of every distribution. Those files are: +#pod +#pod =for :list +#pod * 01mailrc.txt.gz +#pod * 02packages.details.txt.gz +#pod * 03modlist.data.gz +#pod * the last non-developer release of every dist for every author +#pod +#pod =cut + +use Carp (); + +use File::Basename (); +use File::Copy (); +use File::HomeDir 0.57 (); # Win32 support +use File::Find (); +use File::Path 2.04 (); # new API, bugfixes +use File::Spec (); +use File::Temp (); + +use URI 1 (); +use LWP::UserAgent 5 (); + +use Compress::Zlib 1.20 (); + +#pod =method update_mirror +#pod +#pod CPAN::Mini->update_mirror( +#pod remote => "http://cpan.mirrors.comintern.su", +#pod local => "/usr/share/mirrors/cpan", +#pod force => 0, +#pod log_level => 'debug', +#pod ); +#pod +#pod This is the only method that need be called from outside this module. It will +#pod update the local mirror with the files from the remote mirror. +#pod +#pod If called as a class method, C creates an ephemeral CPAN::Mini +#pod object on which other methods are called. That object is used to store mirror +#pod location and state. +#pod +#pod This method returns the number of files updated. +#pod +#pod The following options are recognized: +#pod +#pod =begin :list +#pod +#pod * C +#pod +#pod This is the local file path where the mirror will be written or updated. +#pod +#pod * C +#pod +#pod This is the URL of the CPAN mirror from which to work. A reasonable default +#pod will be picked by default. A list of CPAN mirrors can be found at +#pod L +#pod +#pod * C +#pod +#pod Generally an octal number, this option sets the permissions of created +#pod directories. It defaults to 0711. +#pod +#pod * C +#pod +#pod If true, the C method will allow all extra files to be mirrored. +#pod +#pod * C +#pod +#pod If true, CPAN::Mini will not try to remove source control files during +#pod cleanup. See C for details. +#pod +#pod * C +#pod +#pod If true, this option will cause CPAN::Mini to read the entire module list and +#pod update anything out of date, even if the module list itself wasn't out of date +#pod on this run. +#pod +#pod * C +#pod +#pod If true, CPAN::Mini will skip the major language distributions: perl, parrot, +#pod and ponie. It will also skip embperl, sybperl, bioperl, and kurila. +#pod +#pod * C +#pod +#pod This defines the minimum level of message to log: debug, info, warn, or fatal +#pod +#pod * C +#pod +#pod If true, CPAN::Mini will warn with status messages on errors. (default: true) +#pod +#pod * C +#pod +#pod This options provides a set of rules for filtering paths. If a distribution +#pod matches one of the rules in C, it will not be mirrored. A regex +#pod rule is matched if the path matches the regex; a code rule is matched if the +#pod code returns 1 when the path is passed to it. For example, the following +#pod setting would skip all distributions from RJBS and SUNGO: +#pod +#pod path_filters => [ +#pod qr/RJBS/, +#pod sub { $_[0] =~ /SUNGO/ } +#pod ] +#pod +#pod * C +#pod +#pod This option provides a set of rules for filtering modules. It behaves like +#pod path_filters, but acts only on module names. (Since most modules are in +#pod distributions with more than one module, this setting will probably be less +#pod useful than C.) For example, this setting will skip any +#pod distribution containing only modules with the word "Acme" in them: +#pod +#pod module_filters => [ qr/Acme/i ] +#pod +#pod * C +#pod +#pod This option should be an arrayref of extra files in the remote CPAN to mirror +#pod locally. +#pod +#pod * C +#pod +#pod If this option is true, CPAN::Mini will not try delete unmirrored files when it +#pod has finished mirroring +#pod +#pod * C +#pod +#pod If offline, CPAN::Mini will not attempt to contact remote resources. +#pod +#pod * C +#pod +#pod If true, no connection cache will be established. This is mostly useful as a +#pod workaround for connection cache failures. +#pod +#pod =end :list +#pod +#pod =cut + +sub update_mirror { + my $self = shift; + $self = $self->new(@_) unless ref $self; + + unless ($self->{offline}) { + my $local = $self->{local}; + + $self->log("Updating $local"); + $self->log("Mirroring from $self->{remote}"); + $self->log("=" x 63); + + die "local mirror target $local is not writable" unless -w $local; + + # mirrored tracks the already done, keyed by filename + # 1 = local-checked, 2 = remote-mirrored + $self->mirror_indices; + + return unless $self->{force} or $self->{changes_made}; + + # mirror all the files + $self->_mirror_extras; + $self->mirror_file($_, 1) for @{ $self->_get_mirror_list }; + + # install indices after files are mirrored in case we're interrupted + # so indices will seem new again when continuing + $self->_install_indices; + + $self->_write_out_recent; + + # eliminate files we don't need + $self->clean_unmirrored unless $self->{skip_cleanup}; + } + + return $self->{changes_made}; +} + +sub _recent { $_[0]->{recent}{ $_[1] } = 1 } + +sub _write_out_recent { + my ($self) = @_; + return unless my @keys = keys %{ $self->{recent} }; + + my $recent = File::Spec->catfile($self->{local}, 'RECENT'); + open my $recent_fh, '>', $recent or die "can't open $recent for writing: $!"; + + for my $file (sort keys %{ $self->{recent} }) { + print {$recent_fh} "$file\n" or die "can't write to $recent: $!"; + } + + die "error closing $recent: $!" unless close $recent_fh; + return; +} + +sub _get_mirror_list { + my $self = shift; + + my %mirror_list; + + # now walk the packages list + my $details = File::Spec->catfile( + $self->_scratch_dir, + qw(modules 02packages.details.txt.gz) + ); + + my $gz = Compress::Zlib::gzopen($details, "rb") + or die "Cannot open details: $Compress::Zlib::gzerrno"; + + my $inheader = 1; + my $file_ok = 0; + while ($gz->gzreadline($_) > 0) { + if ($inheader) { + if (/\S/) { + my ($header, $value) = split /:\s*/, $_, 2; + chomp $value; + if ($header eq 'File' + and ($value eq '02packages.details.txt' + or $value eq '02packages.details.txt.gz')) { + $file_ok = 1; + } + } else { + $inheader = 0; + } + + next; + } + + die "02packages.details.txt file is not a valid index\n" + unless $file_ok; + + my ($module, $version, $path) = split; + next if $self->_filter_module({ + module => $module, + version => $version, + path => $path, + }); + + $mirror_list{"authors/id/$path"}++; + } + + return [ sort keys %mirror_list ]; +} + +#pod =method new +#pod +#pod my $minicpan = CPAN::Mini->new; +#pod +#pod This method constructs a new CPAN::Mini object. Its parameters are described +#pod above, under C. +#pod +#pod =cut + +sub new { + my $class = shift; + my %defaults = ( + changes_made => 0, + dirmode => 0711, ## no critic Zero + errors => 1, + mirrored => {}, + log_level => 'info', + ); + + my $self = bless { %defaults, @_ } => $class; + + $self->{dirmode} = $defaults{dirmode} unless defined $self->{dirmode}; + + $self->{recent} = {}; + + Carp::croak "no local mirror supplied" unless $self->{local}; + + substr($self->{local}, 0, 1, $class->__homedir) + if substr($self->{local}, 0, 1) eq q{~}; + + Carp::croak "local mirror path exists but is not a directory" + if (-e $self->{local}) + and not(-d $self->{local}); + + unless (-e $self->{local}) { + File::Path::mkpath( + $self->{local}, + { + verbose => $self->{log_level} eq 'debug', + mode => $self->{dirmode}, + }, + ); + } + + Carp::croak "no write permission to local mirror" unless -w $self->{local}; + + Carp::croak "no remote mirror supplied" unless $self->{remote}; + + $self->{remote} = "$self->{remote}/" if substr($self->{remote}, -1) ne '/'; + + my $version = $class->VERSION; + $version = 'v?' unless defined $version; + + $self->{__lwp} = LWP::UserAgent->new( + agent => "$class/$version", + env_proxy => 1, + ($self->{no_conn_cache} ? () : (keep_alive => 5)), + ($self->{timeout} ? (timeout => $self->{timeout}) : ()), + ); + + unless ($self->{offline}) { + my $test_uri = URI->new_abs( + 'modules/02packages.details.txt.gz', + $self->{remote}, + )->as_string; + + Carp::croak "unable to contact the remote mirror" + unless eval { $self->__lwp->head($test_uri)->is_success }; + } + + return $self; +} + +sub __lwp { $_[0]->{__lwp} } + +#pod =method mirror_indices +#pod +#pod $minicpan->mirror_indices; +#pod +#pod This method updates the index files from the CPAN. +#pod +#pod =cut + +sub _fixed_mirrors { + qw( + authors/01mailrc.txt.gz + modules/02packages.details.txt.gz + modules/03modlist.data.gz + ); +} + +sub _scratch_dir { + my ($self) = @_; + + $self->{scratch} ||= File::Temp::tempdir(CLEANUP => 1); + return $self->{scratch}; +} + +sub mirror_indices { + my $self = shift; + + $self->_make_index_dirs($self->_scratch_dir); + + for my $path ($self->_fixed_mirrors) { + my $local_file = File::Spec->catfile($self->{local}, split m{/}, $path); + my $scratch_file = File::Spec->catfile( + $self->_scratch_dir, + split(m{/}, $path), + ); + + File::Copy::copy($local_file, $scratch_file); + + utime((stat $local_file)[ 8, 9 ], $scratch_file); + + $self->mirror_file($path, undef, { to_scratch => 1 }); + } +} + +sub _mirror_extras { + my $self = shift; + + for my $path (@{ $self->{also_mirror} }) { + $self->mirror_file($path, undef); + } +} + +sub _make_index_dirs { + my ($self, $base_dir, $dir_mode, $trace) = @_; + $base_dir ||= $self->_scratch_dir; + $dir_mode = 0711 if !defined $dir_mode; ## no critic Zero + $trace = 0 if !defined $trace; + + for my $index ($self->_fixed_mirrors) { + my $dir = File::Basename::dirname($index); + my $needed = File::Spec->catdir($base_dir, $dir); + File::Path::mkpath($needed, { verbose => $trace, mode => $dir_mode }); + die "couldn't create $needed: $!" unless -d $needed; + } +} + +sub _install_indices { + my $self = shift; + + $self->_make_index_dirs( + $self->{local}, + $self->{dirmode}, + $self->{log_level} eq 'debug', + ); + + for my $file ($self->_fixed_mirrors) { + my $local_file = File::Spec->catfile($self->{local}, split m{/}, $file); + + unlink $local_file; + + File::Copy::copy( + File::Spec->catfile($self->_scratch_dir, split m{/}, $file), + $local_file, + ); + + $self->{mirrored}{$local_file} = 1; + } +} + +#pod =method mirror_file +#pod +#pod $minicpan->mirror_file($path, $skip_if_present) +#pod +#pod This method will mirror the given file from the remote to the local mirror, +#pod overwriting any existing file unless C<$skip_if_present> is true. +#pod +#pod =cut + +sub mirror_file { + my ($self, $path, $skip_if_present, $arg) = @_; + + $arg ||= {}; + + # full URL + my $remote_uri = eval { $path->isa('URI') } + ? $path + : URI->new_abs($path, $self->{remote})->as_string; + + # native absolute file + my $local_file = File::Spec->catfile( + $arg->{to_scratch} ? $self->_scratch_dir : $self->{local}, + split m{/}, $path + ); + + my $checksum_might_be_up_to_date = 1; + + if ($skip_if_present and -f $local_file) { + ## upgrade to checked if not already + $self->{mirrored}{$local_file} ||= 1; + } elsif (($self->{mirrored}{$local_file} || 0) < 2) { + ## upgrade to full mirror + $self->{mirrored}{$local_file} = 2; + + File::Path::mkpath( + File::Basename::dirname($local_file), + { + verbose => $self->{log_level} eq 'debug', + mode => $self->{dirmode}, + }, + ); + + $self->log($path, { no_nl => 1 }); + my $res = $self->{__lwp}->mirror($remote_uri, $local_file); + + if ($res->is_success) { + utime undef, undef, $local_file if $arg->{update_times}; + $checksum_might_be_up_to_date = 0; + $self->_recent($path); + $self->log(" ... updated"); + $self->{changes_made}++; + } elsif ($res->code != 304) { # not modified + $self->log(" ... resulted in an HTTP error with status " . $res->code); + $self->log_warn("$remote_uri: " . $res->status_line); + return; + } else { + $self->log(" ... up to date"); + } + } + + if ($path =~ m{^authors/id}) { # maybe fetch CHECKSUMS + my $checksum_path + = URI->new_abs("CHECKSUMS", $remote_uri)->rel($self->{remote})->as_string; + + if ($path ne $checksum_path) { + $self->mirror_file($checksum_path, $checksum_might_be_up_to_date); + } + } +} + +#pod =begin devel +#pod +#pod =method _filter_module +#pod +#pod next +#pod if $self->_filter_module({ module => $foo, version => $foo, path => $foo }); +#pod +#pod This method holds the filter chain logic. C takes an optional +#pod set of filter parameters. As C encounters a distribution, it +#pod calls this method to figure out whether or not it should be downloaded. The +#pod user provided filters are taken into account. Returns 1 if the distribution is +#pod filtered (to be skipped). Returns 0 if the distribution is to not filtered +#pod (not to be skipped). +#pod +#pod =end devel +#pod +#pod =cut + +sub __do_filter { + my ($self, $filter, $file) = @_; + return unless $filter; + + if (ref($filter) eq 'ARRAY') { + for (@$filter) { + return 1 if $self->__do_filter($_, $file); + } + return; + } + + if (ref($filter) eq 'CODE') { + return $filter->($file); + } else { + return $file =~ $filter; + } +} + +sub _filter_module { + my $self = shift; + my $args = shift; + + if ($self->{skip_perl}) { + return 1 if $args->{path} =~ m{/(?:emb|syb|bio)?perl-\d}i; + return 1 if $args->{path} =~ m{/(?:parrot|ponie)-\d}i; + return 1 if $args->{path} =~ m{/(?:kurila)-\d}i; + return 1 if $args->{path} =~ m{/\bperl-?5\.004}i; + return 1 if $args->{path} =~ m{/\bperl_mlb\.zip}i; + } + + return 1 if $self->__do_filter($self->{path_filters}, $args->{path}); + return 1 if $self->__do_filter($self->{module_filters}, $args->{module}); + return 0; +} + +#pod =method file_allowed +#pod +#pod next unless $minicpan->file_allowed($filename); +#pod +#pod This method returns true if the given file is allowed to exist in the local +#pod mirror, even if it isn't one of the required mirror files. +#pod +#pod By default, only dot-files are allowed. If the C option is true, +#pod all files are allowed. +#pod +#pod =cut + +sub file_allowed { + my ($self, $file) = @_; + return 1 if $self->{exact_mirror}; + + # It's a cheap hack, but it gets the job done. + return 1 if $file eq File::Spec->catfile($self->{local}, 'RECENT'); + + return (substr(File::Basename::basename($file), 0, 1) eq q{.}) ? 1 : 0; +} + +#pod =method clean_unmirrored +#pod +#pod $minicpan->clean_unmirrored; +#pod +#pod This method looks through the local mirror's files. If it finds a file that +#pod neither belongs in the mirror nor is allowed (see the C method), +#pod C is called on the file. +#pod +#pod If you set C to a true value, then this doesn't clean +#pod up files that belong to source control systems. Currently this ignores: +#pod +#pod .cvs .cvsignore +#pod .svn .svnignore +#pod .git .gitignore +#pod +#pod Send patches for other source control files that you would like to have added. +#pod +#pod =cut + +my %Source_control_files; +BEGIN { + %Source_control_files = map { $_ => 1 } + qw(.cvs .svn .git .cvsignore .svnignore .gitignore); +} + +sub clean_unmirrored { + my $self = shift; + + File::Find::find sub { + my $file = File::Spec->canonpath($File::Find::name); ## no critic Package + my $basename = File::Basename::basename( $file ); + + if ( + $self->{ignore_source_control} + and exists $Source_control_files{$basename} + ) { + $File::Find::prune = 1; + return; + } + + return unless (-f $file and not $self->{mirrored}{$file}); + return if $self->file_allowed($file); + + $self->clean_file($file); + + }, $self->{local}; +} + +#pod =method clean_file +#pod +#pod $minicpan->clean_file($filename); +#pod +#pod This method, called by C, deletes the named file. It returns +#pod true if the file is successfully unlinked. Otherwise, it returns false. +#pod +#pod =cut + +sub clean_file { + my ($self, $file) = @_; + + unless (unlink $file) { + $self->log_warn("$file cannot be removed: $!"); + return; + } + + $self->log("$file removed"); + + return 1; +} + +#pod =method log_warn +#pod +#pod =method log +#pod +#pod =method log_debug +#pod +#pod $minicpan->log($message); +#pod +#pod This will log (print) the given message unless the log level is too low. +#pod +#pod C, which logs at the I level, may also be called as C for +#pod backward compatibility reasons. +#pod +#pod =cut + +sub log_level { + return $_[0]->{log_level} if ref $_[0]; + return 'info'; +} + +sub log_unconditionally { + my ($self, $message, $arg) = @_; + $arg ||= {}; + + print($message, $arg->{no_nl} ? () : "\n"); +} + +sub log_warn { + return if $_[0]->log_level eq 'fatal'; + $_[0]->log_unconditionally($_[1], $_[2]); +} + +sub log { + return unless $_[0]->log_level =~ /\A(?:info|debug)\z/; + $_[0]->log_unconditionally($_[1], $_[2]); +} + +sub trace { + my $self = shift; + $self->log(@_); +} + +sub log_debug { + my ($self, @rest) = @_; + return unless $_[0]->log_level eq 'debug'; + $_[0]->log_unconditionally($_[1], $_[2]); +} + +#pod =method read_config +#pod +#pod my %config = CPAN::Mini->read_config(\%options); +#pod +#pod This routine returns a set of arguments that can be passed to CPAN::Mini's +#pod C or C methods. It will look for a file called +#pod F<.minicpanrc> in the user's home directory as determined by +#pod L. +#pod +#pod =cut + +sub __homedir { + my ($class) = @_; + + my $homedir = File::HomeDir->my_home || $ENV{HOME}; + + Carp::croak "couldn't determine your home directory! set HOME env variable" + unless defined $homedir; + + return $homedir; +} + +sub __homedir_configfile { + my ($class) = @_; + my $default = File::Spec->catfile($class->__homedir, '.minicpanrc'); +} + +sub __default_configfile { + my ($self) = @_; + + (my $pm_loc = $INC{'CPAN/Mini.pm'}) =~ s/Mini\.pm\z//; + File::Spec->catfile($pm_loc, 'minicpan.conf'); +} + +sub read_config { + my ($class, $options) = @_; + + my $config_file = $class->config_file($options); + + return unless defined $config_file; + + # This is ugly, but lets us respect -qq for now even before we have an + # object. I think a better fix is warranted. -- rjbs, 2010-03-04 + $class->log("Using config from $config_file") + if ($options->{log_level}||'info') =~ /\A(?:warn|fatal)\z/; + + substr($config_file, 0, 1, $class->__homedir) + if substr($config_file, 0, 1) eq q{~}; + + return unless -e $config_file; + + open my $config_fh, '<', $config_file + or die "couldn't open config file $config_file: $!"; + + my %config; + my %is_multivalue = map {; $_ => 1 } + qw(also_mirror module_filters path_filters); + + $config{$_} = [] for keys %is_multivalue; + + while (<$config_fh>) { + chomp; + next if /\A\s*\Z/sm; + + if (/\A(\w+):\s*(\S.*?)\s*\Z/sm) { + my ($key, $value) = ($1, $2); + + if ($is_multivalue{ $key }) { + push @{ $config{$key} }, split /\s+/, $value; + } else { + $config{ $key } = $value; + } + } + } + + for (qw(also_mirror)) { + $config{$_} = [ grep { length } @{ $config{$_} } ]; + } + + for (qw(module_filters path_filters)) { + $config{$_} = [ map { qr/$_/ } @{ $config{$_} } ]; + } + + for (keys %is_multivalue) { + delete $config{$_} unless @{ $config{$_} }; + } + + return %config; +} + +#pod =method config_file +#pod +#pod my $config_file = CPAN::Mini->config_file( { options } ); +#pod +#pod This routine returns the config file name. It first looks at for the +#pod C setting, then the C environment +#pod variable, then the default F<~/.minicpanrc>, and finally the +#pod F. It uses the first defined value it finds. +#pod If the filename it selects does not exist, it returns false. +#pod +#pod OPTIONS is an optional hash reference of the C config hash. +#pod +#pod =cut + +sub config_file { + my ($class, $options) = @_; + + my $config_file = do { + if (defined eval { $options->{config_file} }) { + $options->{config_file}; + } elsif (defined $ENV{CPAN_MINI_CONFIG}) { + $ENV{CPAN_MINI_CONFIG}; + } elsif (defined $class->__homedir_configfile) { + $class->__homedir_configfile; + } elsif (defined $class->__default_configfile) { + $class->__default_configfile; + } else { + (); + } + }; + + return ( + (defined $config_file && -e $config_file) + ? $config_file + : () + ); +} + +#pod =head2 remote_from +#pod +#pod my $remote = CPAN::Mini->remote_from( $remote_from, $orig_remote, $quiet ); +#pod +#pod This routine take an string argument and turn it into a method +#pod call to handle to retrieve the a cpan mirror url from a source. +#pod Currently supported methods: +#pod +#pod cpan - fetch the first mirror from your CPAN.pm config +#pod cpanplus - fetch the first mirror from your CPANPLUS.pm config +#pod +#pod =cut + +sub remote_from { + my ( $class, $remote_from, $orig_remote, $quiet ) = @_; + + my $method = lc "remote_from_" . $remote_from; + + Carp::croak "unknown remote_from value: $remote_from" + unless $class->can($method); + + my $new_remote = $class->$method; + + warn "overriding '$orig_remote' with '$new_remote' via $method\n" + if !$quiet && $orig_remote; + + return $new_remote; +} + +#pod =head2 remote_from_cpan +#pod +#pod my $remote = CPAN::Mini->remote_from_cpan; +#pod +#pod This routine loads your CPAN.pm config and returns the first mirror in mirror +#pod list. You can set this as your default by setting remote_from:cpan in your +#pod F<.minicpanrc> file. +#pod +#pod =cut + +sub remote_from_cpan { + my ($self) = @_; + + Carp::croak "unable find a CPAN, maybe you need to install it" + unless eval { require CPAN; 1 }; + + CPAN::HandleConfig::require_myconfig_or_config(); + + Carp::croak "unable to find mirror list in your CPAN config" + unless exists $CPAN::Config->{urllist}; + + Carp::croak "unable to find first mirror url in your CPAN config" + unless ref( $CPAN::Config->{urllist} ) eq 'ARRAY' && $CPAN::Config->{urllist}[0]; + + return $CPAN::Config->{urllist}[0]; +} + +#pod =head2 remote_from_cpanplus +#pod +#pod my $remote = CPAN::Mini->remote_from_cpanplus; +#pod +#pod This routine loads your CPANPLUS.pm config and returns the first mirror in +#pod mirror list. You can set this as your default by setting remote_from:cpanplus +#pod in your F<.minicpanrc> file. +#pod +#pod =cut + +sub remote_from_cpanplus { + my ($self) = @_; + + Carp::croak "unable find a CPANPLUS, maybe you need to install it" + unless eval { require CPANPLUS::Backend }; + + my $cb = CPANPLUS::Backend->new; + my $hosts = $cb->configure_object->get_conf('hosts'); + + Carp::croak "unable to find mirror list in your CPANPLUS config" + unless $hosts; + + Carp::croak "unable to find first mirror in your CPANPLUS config" + unless ref($hosts) eq 'ARRAY' && $hosts->[0]; + + my $url_parts = $hosts->[0]; + return $url_parts->{scheme} . "://" . $url_parts->{host} . ( $url_parts->{path} || '' ); +} + +#pod =head1 SEE ALSO +#pod +#pod Randal Schwartz's original article on minicpan, here: +#pod +#pod http://www.stonehenge.com/merlyn/LinuxMag/col42.html +#pod +#pod L, which provides the C method, which performs +#pod the same task as this module. +#pod +#pod =head1 THANKS +#pod +#pod Thanks to David Dyck for letting me know about my stupid documentation errors. +#pod +#pod Thanks to Roy Fulbright for finding an obnoxious bug on Win32. +#pod +#pod Thanks to Shawn Sorichetti for fixing a stupid octal-number-as-string bug. +#pod +#pod Thanks to sungo for implementing the filters, so I can finally stop mirroring +#pod bioperl, and Robert Rothenberg for suggesting adding coderef rules. +#pod +#pod Thanks to Adam Kennedy for noticing and complaining about a lot of stupid +#pod little design decisions. +#pod +#pod Thanks to Michael Schwern and Jason Kohles, for pointing out missing +#pod documentation. +#pod +#pod Thanks to David Golden for some important bugfixes and refactoring. +#pod +#pod =cut + +1; + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +CPAN::Mini - create a minimal mirror of CPAN + +=head1 VERSION + +version 1.111016 + +=head1 SYNOPSIS + +(If you're not going to do something weird, you probably want to look at the +L command, instead.) + + use CPAN::Mini; + + CPAN::Mini->update_mirror( + remote => "http://cpan.mirrors.comintern.su", + local => "/usr/share/mirrors/cpan", + log_level => 'debug', + ); + +=head1 DESCRIPTION + +CPAN::Mini provides a simple mechanism to build and update a minimal mirror of +the CPAN on your local disk. It contains only those files needed to install +the newest version of every distribution. Those files are: + +=over 4 + +=item * + +01mailrc.txt.gz + +=item * + +02packages.details.txt.gz + +=item * + +03modlist.data.gz + +=item * + +the last non-developer release of every dist for every author + +=back + +=head1 METHODS + +=head2 update_mirror + + CPAN::Mini->update_mirror( + remote => "http://cpan.mirrors.comintern.su", + local => "/usr/share/mirrors/cpan", + force => 0, + log_level => 'debug', + ); + +This is the only method that need be called from outside this module. It will +update the local mirror with the files from the remote mirror. + +If called as a class method, C creates an ephemeral CPAN::Mini +object on which other methods are called. That object is used to store mirror +location and state. + +This method returns the number of files updated. + +The following options are recognized: + +=over 4 + +=item * + +C + +This is the local file path where the mirror will be written or updated. + +=item * + +C + +This is the URL of the CPAN mirror from which to work. A reasonable default +will be picked by default. A list of CPAN mirrors can be found at +L + +=item * + +C + +Generally an octal number, this option sets the permissions of created +directories. It defaults to 0711. + +=item * + +C + +If true, the C method will allow all extra files to be mirrored. + +=item * + +C + +If true, CPAN::Mini will not try to remove source control files during +cleanup. See C for details. + +=item * + +C + +If true, this option will cause CPAN::Mini to read the entire module list and +update anything out of date, even if the module list itself wasn't out of date +on this run. + +=item * + +C + +If true, CPAN::Mini will skip the major language distributions: perl, parrot, +and ponie. It will also skip embperl, sybperl, bioperl, and kurila. + +=item * + +C + +This defines the minimum level of message to log: debug, info, warn, or fatal + +=item * + +C + +If true, CPAN::Mini will warn with status messages on errors. (default: true) + +=item * + +C + +This options provides a set of rules for filtering paths. If a distribution +matches one of the rules in C, it will not be mirrored. A regex +rule is matched if the path matches the regex; a code rule is matched if the +code returns 1 when the path is passed to it. For example, the following +setting would skip all distributions from RJBS and SUNGO: + + path_filters => [ + qr/RJBS/, + sub { $_[0] =~ /SUNGO/ } + ] + +=item * + +C + +This option provides a set of rules for filtering modules. It behaves like +path_filters, but acts only on module names. (Since most modules are in +distributions with more than one module, this setting will probably be less +useful than C.) For example, this setting will skip any +distribution containing only modules with the word "Acme" in them: + + module_filters => [ qr/Acme/i ] + +=item * + +C + +This option should be an arrayref of extra files in the remote CPAN to mirror +locally. + +=item * + +C + +If this option is true, CPAN::Mini will not try delete unmirrored files when it +has finished mirroring + +=item * + +C + +If offline, CPAN::Mini will not attempt to contact remote resources. + +=item * + +C + +If true, no connection cache will be established. This is mostly useful as a +workaround for connection cache failures. + +=back + +=head2 new + + my $minicpan = CPAN::Mini->new; + +This method constructs a new CPAN::Mini object. Its parameters are described +above, under C. + +=head2 mirror_indices + + $minicpan->mirror_indices; + +This method updates the index files from the CPAN. + +=head2 mirror_file + + $minicpan->mirror_file($path, $skip_if_present) + +This method will mirror the given file from the remote to the local mirror, +overwriting any existing file unless C<$skip_if_present> is true. + +=head2 file_allowed + + next unless $minicpan->file_allowed($filename); + +This method returns true if the given file is allowed to exist in the local +mirror, even if it isn't one of the required mirror files. + +By default, only dot-files are allowed. If the C option is true, +all files are allowed. + +=head2 clean_unmirrored + + $minicpan->clean_unmirrored; + +This method looks through the local mirror's files. If it finds a file that +neither belongs in the mirror nor is allowed (see the C method), +C is called on the file. + +If you set C to a true value, then this doesn't clean +up files that belong to source control systems. Currently this ignores: + + .cvs .cvsignore + .svn .svnignore + .git .gitignore + +Send patches for other source control files that you would like to have added. + +=head2 clean_file + + $minicpan->clean_file($filename); + +This method, called by C, deletes the named file. It returns +true if the file is successfully unlinked. Otherwise, it returns false. + +=head2 log_warn + +=head2 log + +=head2 log_debug + + $minicpan->log($message); + +This will log (print) the given message unless the log level is too low. + +C, which logs at the I level, may also be called as C for +backward compatibility reasons. + +=head2 read_config + + my %config = CPAN::Mini->read_config(\%options); + +This routine returns a set of arguments that can be passed to CPAN::Mini's +C or C methods. It will look for a file called +F<.minicpanrc> in the user's home directory as determined by +L. + +=head2 config_file + + my $config_file = CPAN::Mini->config_file( { options } ); + +This routine returns the config file name. It first looks at for the +C setting, then the C environment +variable, then the default F<~/.minicpanrc>, and finally the +F. It uses the first defined value it finds. +If the filename it selects does not exist, it returns false. + +OPTIONS is an optional hash reference of the C config hash. + +=begin devel + +=method _filter_module + + next + if $self->_filter_module({ module => $foo, version => $foo, path => $foo }); + +This method holds the filter chain logic. C takes an optional +set of filter parameters. As C encounters a distribution, it +calls this method to figure out whether or not it should be downloaded. The +user provided filters are taken into account. Returns 1 if the distribution is +filtered (to be skipped). Returns 0 if the distribution is to not filtered +(not to be skipped). + +=end devel + +=head2 remote_from + + my $remote = CPAN::Mini->remote_from( $remote_from, $orig_remote, $quiet ); + +This routine take an string argument and turn it into a method +call to handle to retrieve the a cpan mirror url from a source. +Currently supported methods: + + cpan - fetch the first mirror from your CPAN.pm config + cpanplus - fetch the first mirror from your CPANPLUS.pm config + +=head2 remote_from_cpan + + my $remote = CPAN::Mini->remote_from_cpan; + +This routine loads your CPAN.pm config and returns the first mirror in mirror +list. You can set this as your default by setting remote_from:cpan in your +F<.minicpanrc> file. + +=head2 remote_from_cpanplus + + my $remote = CPAN::Mini->remote_from_cpanplus; + +This routine loads your CPANPLUS.pm config and returns the first mirror in +mirror list. You can set this as your default by setting remote_from:cpanplus +in your F<.minicpanrc> file. + +=head1 SEE ALSO + +Randal Schwartz's original article on minicpan, here: + + http://www.stonehenge.com/merlyn/LinuxMag/col42.html + +L, which provides the C method, which performs +the same task as this module. + +=head1 THANKS + +Thanks to David Dyck for letting me know about my stupid documentation errors. + +Thanks to Roy Fulbright for finding an obnoxious bug on Win32. + +Thanks to Shawn Sorichetti for fixing a stupid octal-number-as-string bug. + +Thanks to sungo for implementing the filters, so I can finally stop mirroring +bioperl, and Robert Rothenberg for suggesting adding coderef rules. + +Thanks to Adam Kennedy for noticing and complaining about a lot of stupid +little design decisions. + +Thanks to Michael Schwern and Jason Kohles, for pointing out missing +documentation. + +Thanks to David Golden for some important bugfixes and refactoring. + +=head1 AUTHORS + +=over 4 + +=item * + +Ricardo SIGNES + +=item * + +Randal Schwartz + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2004 by Ricardo SIGNES. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/lib/CPAN/Mini/App.pm b/lib/CPAN/Mini/App.pm new file mode 100644 index 0000000..29b4c69 --- /dev/null +++ b/lib/CPAN/Mini/App.pm @@ -0,0 +1,209 @@ +use strict; +use warnings; + +package CPAN::Mini::App; +$CPAN::Mini::App::VERSION = '1.111016'; +# ABSTRACT: the guts of the minicpan command + +#pod =head1 SYNOPSIS +#pod +#pod #!/usr/bin/perl +#pod use CPAN::Mini::App; +#pod CPAN::Mini::App->run; +#pod +#pod =cut + +use CPAN::Mini; +use File::HomeDir; +use File::Spec; +use Getopt::Long qw(:config no_ignore_case); +use Pod::Usage 1.00; + +sub _display_version { + my $class = shift; + no strict 'refs'; + print "minicpan", + ($class ne 'CPAN::Mini' ? ' (from CPAN::Mini)' : q{}), + ", powered by $class ", $class->VERSION, "\n\n"; + exit; +} + +#pod =method run +#pod +#pod This method is called by F to do all the work. Don't rely on what it +#pod does just yet. +#pod +#pod =cut + +sub _validate_log_level { + my ($class, $level) = @_; + return $level if $level =~ /\A(?:fatal|warn|debug|info)\z/; + die "unknown logging level: $level\n"; +} + +sub run { + my ($class) = @_; + + my $minicpan = $class->initialize_minicpan; + + $minicpan->update_mirror; +} + +sub initialize_minicpan { + my ($class) = @_; + + my $version; + + my %commandline; + + my @option_spec = $class->_option_spec(); + GetOptions(\%commandline, @option_spec) or pod2usage(2); + + # These two options will cause the program to exit before finishing ->run + pod2usage(1) if $commandline{help}; + $version = 1 if $commandline{version}; + + # How noisy should we be? + my $debug = $commandline{debug}; + my $log_level = $commandline{log_level}; + my $quiet = $commandline{qq} ? 2 : $commandline{quiet}; + + die "can't mix --debug, --log-level, and --debug\n" + if defined($quiet) + defined($debug) + defined($log_level) > 1; + + # Set log_level accordingly + $quiet ||= 0; + $log_level = $debug ? 'debug' + : $quiet == 1 ? 'warn' + : $quiet >= 2 ? 'fatal' + : $log_level ? $log_level + : undef; + + my %config = CPAN::Mini->read_config({ + log_level => 'info', + %commandline + }); + + $config{class} ||= 'CPAN::Mini'; + + # Override config with commandline options + %config = (%config, %commandline); + + $config{log_level} = $log_level || $config{log_level} || 'info'; + $class->_validate_log_level($config{log_level}); + + eval "require $config{class}"; + die $@ if $@; + + _display_version($config{class}) if $version; + + if ($config{remote_from} && ! $config{remote}) { + $config{remote} = $config{class}->remote_from( + $config{remote_from}, + $config{remote}, + $config{quiet}, + ); + } + + $config{remote} ||= 'http://www.cpan.org/'; + + pod2usage(2) unless $config{local} and $config{remote}; + + $|++; + + # Convert dirmode string to a real octal value, if given + $config{dirmode} = oct $config{dirmode} if $config{dirmode}; + + # Turn the 'perl' option into 'skip_perl', for backward compatibility + $config{skip_perl} = not delete $config{perl}; + + return $config{class}->new(%config); +} + +sub _option_spec { + return qw< + class|c=s + help|h + version|v + quiet|q+ + qq + debug + log_level|log-level=s + local|l=s + remote|r=s + dirmode|d=s + offline + force|f + perl + exact_mirror|x + timeout|t=i + config_file|config|C=s + remote-from=s + >; +} + +#pod =head1 SEE ALSO +#pod +#pod Randal Schwartz's original article, which can be found here: +#pod +#pod http://www.stonehenge.com/merlyn/LinuxMag/col42.html +#pod +#pod =cut + +1; + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +CPAN::Mini::App - the guts of the minicpan command + +=head1 VERSION + +version 1.111016 + +=head1 SYNOPSIS + + #!/usr/bin/perl + use CPAN::Mini::App; + CPAN::Mini::App->run; + +=head1 METHODS + +=head2 run + +This method is called by F to do all the work. Don't rely on what it +does just yet. + +=head1 SEE ALSO + +Randal Schwartz's original article, which can be found here: + + http://www.stonehenge.com/merlyn/LinuxMag/col42.html + +=head1 AUTHORS + +=over 4 + +=item * + +Ricardo SIGNES + +=item * + +Randal Schwartz + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2004 by Ricardo SIGNES. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/t/00-load.t b/t/00-load.t new file mode 100644 index 0000000..8a560de --- /dev/null +++ b/t/00-load.t @@ -0,0 +1,7 @@ +#!perl + +use Test::More tests => 1; + +use_ok( 'CPAN::Mini' ); + +diag( "Testing CPAN::Mini $CPAN::Mini::VERSION" ); diff --git a/t/000-report-versions-tiny.t b/t/000-report-versions-tiny.t new file mode 100644 index 0000000..e25334d --- /dev/null +++ b/t/000-report-versions-tiny.t @@ -0,0 +1,86 @@ +use strict; +use warnings; +use Test::More 0.88; +# This is a relatively nice way to avoid Test::NoWarnings breaking our +# expectations by adding extra tests, without using no_plan. It also helps +# avoid any other test module that feels introducing random tests, or even +# test plans, is a nice idea. +our $success = 0; +END { $success && done_testing; } + +# List our own version used to generate this +my $v = "\nGenerated by Dist::Zilla::Plugin::ReportVersions::Tiny v1.10\n"; + +eval { # no excuses! + # report our Perl details + my $want = '5.006'; + $v .= "perl: $] (wanted $want) on $^O from $^X\n\n"; +}; +defined($@) and diag("$@"); + +# Now, our module version dependencies: +sub pmver { + my ($module, $wanted) = @_; + $wanted = " (want $wanted)"; + my $pmver; + eval "require $module;"; + if ($@) { + if ($@ =~ m/Can't locate .* in \@INC/) { + $pmver = 'module not found.'; + } else { + diag("${module}: $@"); + $pmver = 'died during require.'; + } + } else { + my $version; + eval { $version = $module->VERSION; }; + if ($@) { + diag("${module}: $@"); + $pmver = 'died during VERSION check.'; + } elsif (defined $version) { + $pmver = "$version"; + } else { + $pmver = ''; + } + } + + # So, we should be good, right? + return sprintf('%-45s => %-10s%-15s%s', $module, $pmver, $wanted, "\n"); +} + +eval { $v .= pmver('Carp','any version') }; +eval { $v .= pmver('Compress::Zlib','1.20') }; +eval { $v .= pmver('ExtUtils::MakeMaker','any version') }; +eval { $v .= pmver('File::Basename','any version') }; +eval { $v .= pmver('File::Copy','any version') }; +eval { $v .= pmver('File::Find','any version') }; +eval { $v .= pmver('File::HomeDir','0.57') }; +eval { $v .= pmver('File::Path','2.04') }; +eval { $v .= pmver('File::Spec','any version') }; +eval { $v .= pmver('File::Temp','any version') }; +eval { $v .= pmver('Getopt::Long','any version') }; +eval { $v .= pmver('LWP::UserAgent','5') }; +eval { $v .= pmver('Pod::Usage','1.00') }; +eval { $v .= pmver('Test::More','0.96') }; +eval { $v .= pmver('URI','1') }; +eval { $v .= pmver('strict','any version') }; +eval { $v .= pmver('warnings','any version') }; + + +# All done. +$v .= <<'EOT'; + +Thanks for using my code. I hope it works for you. +If not, please try and include this output in the bug report. +That will help me reproduce the issue and solve your problem. + +EOT + +diag($v); +ok(1, "we really didn't test anything, just reporting data"); +$success = 1; + +# Work around another nasty module on CPAN. :/ +no warnings 'once'; +$Template::Test::NO_FLUSH = 1; +exit 0; diff --git a/t/app.t b/t/app.t new file mode 100644 index 0000000..8b278ac --- /dev/null +++ b/t/app.t @@ -0,0 +1,132 @@ +use strict; +use warnings; +use Test::More; + +use CPAN::Mini::App; +use File::Spec; +use File::Temp qw(tempdir); + +my $TARGET = tempdir(CLEANUP => 1); +my @LR_ARGS = (qw(--offline -r http://example.tld/cpan -l), $TARGET); + +delete $ENV{CPAN_MINI_CONFIG}; + +{ + no warnings 'redefine'; + *File::HomeDir::my_home = sub { $ENV{HOME} }; +} + +sub config_dir { + my ($config) = @_; + + my $tempdir = tempdir(CLEANUP => 1); + + return $tempdir unless defined $config; + + my $filename = File::Spec->catfile($tempdir, '.minicpanrc'); + open my $config_fh, '>', $filename or die "can't write to $filename: $!"; + + for my $key (keys %$config) { + print {$config_fh} "$key: $config->{$key}\n"; + } + + close $config_fh or die "error closing $filename: $!"; + + return $tempdir; +} + +subtest "defaults" => sub { + local $ENV{HOME} = config_dir; + local @ARGV = @LR_ARGS; + + my $minicpan = CPAN::Mini::App->initialize_minicpan; + isa_ok($minicpan, 'CPAN::Mini'); + + is($minicpan->log_level, 'info', "default log level is info"); +}; + +subtest "--debug" => sub { + local $ENV{HOME} = config_dir; + local @ARGV = (qw(--debug), @LR_ARGS); + + my $minicpan = CPAN::Mini::App->initialize_minicpan; + isa_ok($minicpan, 'CPAN::Mini'); + + is($minicpan->log_level, 'debug', "--debug to get log level debug"); +}; + +subtest "config: log_level" => sub { + local $ENV{HOME} = config_dir({ log_level => 'debug' }); + local @ARGV = @LR_ARGS; + + my $minicpan = CPAN::Mini::App->initialize_minicpan; + isa_ok($minicpan, 'CPAN::Mini'); + + is($minicpan->log_level, 'debug', "debug from config file"); +}; + +subtest "--debug overrides config" => sub { + local $ENV{HOME} = config_dir({ log_level => 'fatal' }); + local @ARGV = (qw(--debug), @LR_ARGS); + + my $minicpan = CPAN::Mini::App->initialize_minicpan; + isa_ok($minicpan, 'CPAN::Mini'); + + is($minicpan->log_level, 'debug', "--debug overrides config file"); +}; + +subtest "--log-level" => sub { + local $ENV{HOME} = config_dir; + local @ARGV = (qw(--log-level debug), @LR_ARGS); + + my $minicpan = CPAN::Mini::App->initialize_minicpan; + isa_ok($minicpan, 'CPAN::Mini'); + + is($minicpan->log_level, 'debug', "--debug to get log level debug"); +}; + +subtest "only one log-level-like switch allowed" => sub { + for my $combo ( + [ qw(--debug -q) ], + [ qw(--debug --log-level debug) ], + ) { + local $ENV{HOME} = config_dir; + local @ARGV = (@$combo, @LR_ARGS); + + my $minicpan = eval { CPAN::Mini::App->initialize_minicpan }; + like($@, qr/can't mix/, "can't use @$combo together"); + }; +}; + +for my $switch (qw(-qq --qq)) { + subtest "extra quiet with $switch" => sub { + local $ENV{HOME} = config_dir; + local @ARGV = ($switch, @LR_ARGS); + + my $minicpan = CPAN::Mini::App->initialize_minicpan; + isa_ok($minicpan, 'CPAN::Mini'); + + is($minicpan->log_level, 'fatal', "$switch gets us log level 'fatal'"); + }; +} + + +subtest "-perl switch" => sub { + + local $ENV{HOME} = config_dir; + local @ARGV = @LR_ARGS; + + my $minicpan = CPAN::Mini::App->initialize_minicpan; + isa_ok($minicpan, 'CPAN::Mini'); + is($minicpan->{skip_perl}, 1, "'skip_perl' is true without -perl switch"); + + + local @ARGV = ('-perl', @LR_ARGS); + $minicpan = CPAN::Mini::App->initialize_minicpan; + isa_ok($minicpan, 'CPAN::Mini'); + is($minicpan->{skip_perl}, q{}, "'skip_perl' is false with -perl switch"); +}; + +done_testing; + +1; diff --git a/t/config-file.t b/t/config-file.t new file mode 100644 index 0000000..4d476a6 --- /dev/null +++ b/t/config-file.t @@ -0,0 +1,108 @@ +#!perl + +use warnings; +use strict; + +use Test::More tests => 18; + +use File::Basename; + +my $class = 'CPAN::Mini'; + +use_ok($class); +can_ok($class, 'config_file'); + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# command line option case +{ + my $filename = 'Changes'; + ok(-e $filename, "file name [$filename] exists"); + + local $ENV{CPAN_MINI_CONFIG} = 'Buster'; + my $options = { config_file => $filename, }; + + is($class->config_file($options), + $filename, 'selects config file name from command line'); +} + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# environment variable case +{ + my $filename = $0; + ok(-e $filename, "file name [$filename] exists"); + + local $ENV{CPAN_MINI_CONFIG} = $filename; + + is($class->config_file, $filename, + 'selects config file name from environment with no args'); + is($class->config_file({}), + $filename, 'selects config file name from environment with empty hash ref'); + is($class->config_file('trash'), + $filename, 'selects config file name from environment with non-ref arg'); +} + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# default case +# this is the case where there is a ~/.minicpanrc +{ + + my $filename = 'Changes'; + ok(-e $filename, "file name [$filename] exists"); + + { + no strict 'refs'; + no warnings 'redefine'; + + *{"${class}::__homedir_configfile"} = sub { $filename }; + is($class->__homedir_configfile, + $filename, "__homedir_configfile returns mocked name"); + } + + local $ENV{CPAN_MINI_CONFIG} = undef; + + is($class->config_file, $filename, 'selects default config file name'); +} + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# last ditch case +# this is the case wehre there is no ~/.minicpanrc +{ + local $ENV{CPAN_MINI_CONFIG} = undef; + my $is_there_filename = 'Changes'; + ok(-e $is_there_filename, "file name [$is_there_filename] does exist"); + + { + no strict 'refs'; + no warnings 'redefine'; + + *{"${class}::__homedir_configfile"} = sub { undef }; + is($class->__homedir_configfile, + undef, "__homedir_configfile returns mocked name"); + *{"${class}::__default_configfile"} = sub { $is_there_filename }; + is($class->__default_configfile, + $is_there_filename, "__default_configfile returns mocked name"); + } + + is($class->config_file, $is_there_filename, + 'selects default config file name'); +} + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# everything failed case +{ + local $ENV{CPAN_MINI_CONFIG} = undef; + + { + no strict 'refs'; + no warnings 'redefine'; + + *{"${class}::__homedir_configfile"} = sub { undef }; + is($class->__homedir_configfile, + undef, "__homedir_configfile returns mocked name"); + *{"${class}::__default_configfile"} = sub { undef }; + is($class->__default_configfile, + undef, "__default_configfile returns mocked name"); + } + + is($class->config_file, undef, 'returns undef when no config file is found'); +} diff --git a/t/filter.t b/t/filter.t new file mode 100644 index 0000000..46333fa --- /dev/null +++ b/t/filter.t @@ -0,0 +1,157 @@ +#!perl + +use warnings; +use strict; + +use Test::More tests => 19; + +use CPAN::Mini; + +my $self = { + changes_made => 1, + force => 1, +}; + +bless $self, "CPAN::Mini"; +################################################ +# skip_perl + +$self->{skip_perl} = 1; + +ok($self->_filter_module({ + module => 'perl', + version => '0.01', + path => '/perl-0.01.tar.gz', +}), "perl distro skip check"); + +ok($self->_filter_module({ + module => 'bioperl', + version => '0.01', + path => '/bioperl-0.01.tar.gz', +}), "bioperl distro skip check"); + +ok($self->_filter_module({ + module => 'embperl', + version => '0.01', + path => '/embperl-0.01.tar.gz', +}), "embperl distro skip check"); + +ok(!$self->_filter_module({ + module => 'notperl', + version => '0.01', + path => '/POE-0.01.tar.gz', +}), "POE distro not-skip check"); + +ok($self->_filter_module({ + module => 'ponie', + version => '0.01', + path => '/ponie-0.01.tar.gz', +}), "ponie distro skip check"); + +ok($self->_filter_module({ + module => 'parrot', + version => '0.01', + path => '/parrot-0.01.tar.gz', +}), "parrot distro skip check"); + +delete $self->{skip_perl}; + +ok(!$self->_filter_module({ + module => 'perl', + version => '0.01', + path => '/perl-0.01.tar.gz', +}), "perl distro no-skip check"); + +################################################ +# path_filters + +$self->{path_filters} = qr/skipme/; + +ok($self->_filter_module({ + module => 'skipme', + version => '0.01', + path => '/skipme-0.01.tar.gz', +}), "path_filters skip check skipme 1"); + +ok(!$self->_filter_module({ + module => 'noskip', + version => '0.01', + path => '/noskip-0.01.tar.gz', +}), "path_filters no-skip check"); + +$self->{path_filters} = [ + qr/skipme/, + qr/burnme/, + sub { return $_[0] =~ /subskip/ } +]; + +ok($self->_filter_module({ + module => 'skipme', + version => '0.01', + path => '/skipme-0.01.tar.gz', +}), "path_filters skip check skipme 2"); + +ok($self->_filter_module({ + module => 'burnme', + version => '0.01', + path => '/burnme-0.01.tar.gz', +}), "path_filters skip check burnme"); + +ok($self->_filter_module({ + module => 'submod', + version => '0.01', + path => '/subskip-0.01.tar.gz', +}), "path_filters skip check (by sub)"); + +ok(!$self->_filter_module({ + module => 'noskip', + version => '0.01', + path => '/noskip-0.01.tar.gz', +}), "path_filters no-skip check"); + +################################################ +# module_filters + +$self->{module_filters} = qr/skipme/; + +ok($self->_filter_module({ + module => 'skipme', + version => '0.01', + path => '/skipme-0.01.tar.gz', +}), "module_filters skip check skipme 1"); + +ok(!$self->_filter_module({ + module => 'noskip', + version => '0.01', + path => '/noskip-0.01.tar.gz', +}), "module_filters no-skip check"); + +$self->{module_filters} = [ + qr/skipme/, + qr/burnme/, + sub { $_[0] =~ /submod/ } +]; + +ok($self->_filter_module({ + module => 'skipme', + version => '0.01', + path => '/skipme-0.01.tar.gz', +}), "module_filters skip check skipme 2"); + +ok($self->_filter_module({ + module => 'burnme', + version => '0.01', + path => '/burnme-0.01.tar.gz', +}), "module_filters skip check burnme"); + +ok($self->_filter_module({ + module => 'submod', + version => '0.01', + path => '/subskip-0.01.tar.gz', +}), "module_filters skip check (by sub)"); + +ok(!$self->_filter_module({ + module => 'noskip', + version => '0.01', + path => '/noskip-0.01.tar.gz', +}), "module_filters no-skip check"); diff --git a/xt/fake.t b/xt/fake.t new file mode 100644 index 0000000..1427b46 --- /dev/null +++ b/xt/fake.t @@ -0,0 +1,52 @@ +#!perl +use strict; +use warnings; + +use File::Find::Rule; +use File::Spec; +use File::Temp qw(tempdir); +use CPAN::Mini; + +use Test::More; + +my $tempdir = tempdir(CLEANUP => 1); + +CPAN::Mini->update_mirror( + remote => "http://fakecpan.org/fake/minicpan/1.001/cpan", + local => $tempdir, + log_level => 'fatal', +); + +pass("performed initial mirror"); + +CPAN::Mini->update_mirror( + remote => "http://fakecpan.org/fake/minicpan/1.002/cpan", + local => $tempdir, + log_level => 'fatal', +); + +pass("performed mirror update"); + +my @files = File::Find::Rule->file->in($tempdir); +$_ = File::Spec->abs2rel($_, $tempdir) for @files; + +my @want = qw( + RECENT + authors/01mailrc.txt.gz + authors/id/O/OP/OPRIME/Bug-Gold-9.001.tar.gz + authors/id/O/OP/OPRIME/CHECKSUMS + authors/id/O/OP/OPRIME/XForm-Rollout-1.00.tar.gz + authors/id/X/XY/XYZZY/CHECKSUMS + authors/id/X/XY/XYZZY/Hall-MtKing-0.01.tar.gz + authors/id/X/XY/XYZZY/Y-2.tar.gz + modules/02packages.details.txt.gz + modules/03modlist.data.gz +); + +is_deeply( + [ sort @files ], + [ sort @want ], + "we end up with just the files we expect", +); + +done_testing; diff --git a/xt/release/changes_has_content.t b/xt/release/changes_has_content.t new file mode 100644 index 0000000..c942c33 --- /dev/null +++ b/xt/release/changes_has_content.t @@ -0,0 +1,41 @@ +#!perl + +use Test::More tests => 2; + +note 'Checking Changes'; +my $changes_file = 'Changes'; +my $newver = '1.111016'; +my $trial_token = '-TRIAL'; + +SKIP: { + ok(-e $changes_file, "$changes_file file exists") + or skip 'Changes is missing', 1; + + ok(_get_changes($newver), "$changes_file has content for $newver"); +} + +done_testing; + +# _get_changes copied and adapted from Dist::Zilla::Plugin::Git::Commit +# by Jerome Quelin +sub _get_changes +{ + my $newver = shift; + + # parse changelog to find commit message + open(my $fh, '<', $changes_file) or die "cannot open $changes_file: $!"; + my $changelog = join('', <$fh>); + close $fh; + + my @content = + grep { /^$newver(?:$trial_token)?(?:\s+|$)/ ... /^\S/ } # from newver to un-indented + split /\n/, $changelog; + shift @content; # drop the version line + + # drop unindented last line and trailing blank lines + pop @content while ( @content && $content[-1] =~ /^(?:\S|\s*$)/ ); + + # return number of non-blank lines + return scalar @content; +} + diff --git a/xt/release/pod-syntax.t b/xt/release/pod-syntax.t new file mode 100644 index 0000000..f0468f1 --- /dev/null +++ b/xt/release/pod-syntax.t @@ -0,0 +1,6 @@ +#!perl +# This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests. +use Test::More; +use Test::Pod 1.41; + +all_pod_files_ok(); -- cgit v1.2.1