diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2014-08-08 22:52:09 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2014-08-08 22:52:09 +0000 |
commit | 2a051e40a3fc09bba24c335060e8df327d313e55 (patch) | |
tree | 4ab817c1ef19de5ef30213d9accb8786b0b69302 | |
download | CPAN-Mini-tarball-2a051e40a3fc09bba24c335060e8df327d313e55.tar.gz |
CPAN-Mini-1.111016HEADCPAN-Mini-1.111016master
-rw-r--r-- | Changes | 232 | ||||
-rw-r--r-- | LICENSE | 379 | ||||
-rw-r--r-- | MANIFEST | 21 | ||||
-rw-r--r-- | MANIFEST.SKIP | 2 | ||||
-rw-r--r-- | META.json | 512 | ||||
-rw-r--r-- | META.yml | 376 | ||||
-rw-r--r-- | Makefile.PL | 83 | ||||
-rw-r--r-- | README | 15 | ||||
-rw-r--r-- | bin/minicpan | 185 | ||||
-rw-r--r-- | dist.ini | 13 | ||||
-rw-r--r-- | lib/CPAN/Mini.pm | 1311 | ||||
-rw-r--r-- | lib/CPAN/Mini/App.pm | 209 | ||||
-rw-r--r-- | t/00-load.t | 7 | ||||
-rw-r--r-- | t/000-report-versions-tiny.t | 86 | ||||
-rw-r--r-- | t/app.t | 132 | ||||
-rw-r--r-- | t/config-file.t | 108 | ||||
-rw-r--r-- | t/filter.t | 157 | ||||
-rw-r--r-- | xt/fake.t | 52 | ||||
-rw-r--r-- | xt/release/changes_has_content.t | 41 | ||||
-rw-r--r-- | xt/release/pod-syntax.t | 6 |
20 files changed, 3927 insertions, 0 deletions
@@ -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 @@ -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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + 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. + + <signature of Ty Coon>, 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 <rjbs@cpan.org>", + "Randal Schwartz <merlyn@stonehenge.com>" + ], + "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 <rjbs@cpan.org>' + - 'Randal Schwartz <merlyn@stonehenge.com>' +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 <rjbs\@cpan.org>, Randal Schwartz <merlyn\@stonehenge.com>", + "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); + + + @@ -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<minicpan> 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<minicpan> 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<CPAN_MINI_CONFIG> environment variable + +=item * Use F<~/.minicpanrc> + +=item * Use F<CPAN/Mini/minicpan.conf> + +=back + +If the selected file does not exist, C<minicpan> does not keep looking. + +You can override this process with a C<config_file> method in your subclass. + +See C<CPAN::Mini> 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 <rjbs@cpan.org> + +=item * + +Randal Schwartz <merlyn@stonehenge.com> + +=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<minicpan> 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<minicpan> 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<CPAN_MINI_CONFIG> environment variable +#pod +#pod =item * Use F<~/.minicpanrc> +#pod +#pod =item * Use F<CPAN/Mini/minicpan.conf> +#pod +#pod =back +#pod +#pod If the selected file does not exist, C<minicpan> does not keep looking. +#pod +#pod You can override this process with a C<config_file> method in your subclass. +#pod +#pod See C<CPAN::Mini> 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 <rjbs@cpan.org> +author = Randal Schwartz <merlyn@stonehenge.com> +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<minicpan> 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<update_mirror> 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<local> +#pod +#pod This is the local file path where the mirror will be written or updated. +#pod +#pod * C<remote> +#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<http://www.cpan.org/SITES.html> +#pod +#pod * C<dirmode> +#pod +#pod Generally an octal number, this option sets the permissions of created +#pod directories. It defaults to 0711. +#pod +#pod * C<exact_mirror> +#pod +#pod If true, the C<files_allowed> method will allow all extra files to be mirrored. +#pod +#pod * C<ignore_source_control> +#pod +#pod If true, CPAN::Mini will not try to remove source control files during +#pod cleanup. See C<clean_unmirrored> for details. +#pod +#pod * C<force> +#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<skip_perl> +#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<log_level> +#pod +#pod This defines the minimum level of message to log: debug, info, warn, or fatal +#pod +#pod * C<errors> +#pod +#pod If true, CPAN::Mini will warn with status messages on errors. (default: true) +#pod +#pod * C<path_filters> +#pod +#pod This options provides a set of rules for filtering paths. If a distribution +#pod matches one of the rules in C<path_filters>, 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<module_filters> +#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<path_filters>.) 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<also_mirror> +#pod +#pod This option should be an arrayref of extra files in the remote CPAN to mirror +#pod locally. +#pod +#pod * C<skip_cleanup> +#pod +#pod If this option is true, CPAN::Mini will not try delete unmirrored files when it +#pod has finished mirroring +#pod +#pod * C<offline> +#pod +#pod If offline, CPAN::Mini will not attempt to contact remote resources. +#pod +#pod * C<no_conn_cache> +#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<update_mirror>. +#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<update_mirror> takes an optional +#pod set of filter parameters. As C<update_mirror> 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<exact_mirror> 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<file_allowed> method), +#pod C<clean_file> is called on the file. +#pod +#pod If you set C<ignore_source_control> 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<clean_unmirrored>, 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<log>, which logs at the I<info> level, may also be called as C<trace> 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<new> or C<update_mirror> methods. It will look for a file called +#pod F<.minicpanrc> in the user's home directory as determined by +#pod L<File::HomeDir|File::HomeDir>. +#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<config_file> setting, then the C<CPAN_MINI_CONFIG> environment +#pod variable, then the default F<~/.minicpanrc>, and finally the +#pod F<CPAN/Mini/minicpan.conf>. 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<CPAN::Mini> 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<CPANPLUS::Backend>, which provides the C<local_mirror> 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<minicpan> 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<update_mirror> 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<local> + +This is the local file path where the mirror will be written or updated. + +=item * + +C<remote> + +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<http://www.cpan.org/SITES.html> + +=item * + +C<dirmode> + +Generally an octal number, this option sets the permissions of created +directories. It defaults to 0711. + +=item * + +C<exact_mirror> + +If true, the C<files_allowed> method will allow all extra files to be mirrored. + +=item * + +C<ignore_source_control> + +If true, CPAN::Mini will not try to remove source control files during +cleanup. See C<clean_unmirrored> for details. + +=item * + +C<force> + +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<skip_perl> + +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<log_level> + +This defines the minimum level of message to log: debug, info, warn, or fatal + +=item * + +C<errors> + +If true, CPAN::Mini will warn with status messages on errors. (default: true) + +=item * + +C<path_filters> + +This options provides a set of rules for filtering paths. If a distribution +matches one of the rules in C<path_filters>, 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<module_filters> + +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<path_filters>.) For example, this setting will skip any +distribution containing only modules with the word "Acme" in them: + + module_filters => [ qr/Acme/i ] + +=item * + +C<also_mirror> + +This option should be an arrayref of extra files in the remote CPAN to mirror +locally. + +=item * + +C<skip_cleanup> + +If this option is true, CPAN::Mini will not try delete unmirrored files when it +has finished mirroring + +=item * + +C<offline> + +If offline, CPAN::Mini will not attempt to contact remote resources. + +=item * + +C<no_conn_cache> + +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<update_mirror>. + +=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<exact_mirror> 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<file_allowed> method), +C<clean_file> is called on the file. + +If you set C<ignore_source_control> 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<clean_unmirrored>, 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<log>, which logs at the I<info> level, may also be called as C<trace> 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<new> or C<update_mirror> methods. It will look for a file called +F<.minicpanrc> in the user's home directory as determined by +L<File::HomeDir|File::HomeDir>. + +=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<config_file> setting, then the C<CPAN_MINI_CONFIG> environment +variable, then the default F<~/.minicpanrc>, and finally the +F<CPAN/Mini/minicpan.conf>. 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<CPAN::Mini> 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<update_mirror> takes an optional +set of filter parameters. As C<update_mirror> 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<CPANPLUS::Backend>, which provides the C<local_mirror> 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 <rjbs@cpan.org> + +=item * + +Randal Schwartz <merlyn@stonehenge.com> + +=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<minicpan> 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<minicpan> 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 <rjbs@cpan.org> + +=item * + +Randal Schwartz <merlyn@stonehenge.com> + +=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 = '<undef>'; + } + } + + # 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; @@ -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(); |