Move generated POD to its own dir
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Optional / Dependencies.pm
1 package DBIx::Class::Optional::Dependencies;
2
3 use warnings;
4 use strict;
5
6 use Carp ();
7
8 # NO EXTERNAL NON-5.8.1 CORE DEPENDENCIES EVER (e.g. C::A::G)
9 # This module is to be loaded by Makefile.PM on a pristine system
10
11 # POD is generated automatically by calling _gen_pod from the
12 # Makefile.PL in $AUTHOR mode
13
14 my $json_any = {
15   'JSON::Any'                     => '1.22',
16 };
17
18 my $moose_basic = {
19   'Moose'                         => '0.98',
20   'MooseX::Types'                 => '0.21',
21 };
22
23 my $replicated = {
24   %$moose_basic,
25 };
26
27 my $admin_basic = {
28   %$moose_basic,
29   %$json_any,
30   'MooseX::Types::Path::Class'    => '0.05',
31   'MooseX::Types::JSON'           => '0.02',
32   'namespace::autoclean'          => '0.09',
33 };
34
35 my $admin_script = {
36   %$moose_basic,
37   %$admin_basic,
38   'Getopt::Long::Descriptive' => '0.081',
39   'Text::CSV'                 => '1.16',
40 };
41
42 my $datetime_basic = {
43   'DateTime'                      => '0.55',
44   'DateTime::Format::Strptime'    => '1.2',
45 };
46
47 my $id_shortener = {
48   'Math::BigInt'                  => '1.80',
49   'Math::Base36'                  => '0.07',
50 };
51
52 my $rdbms_sqlite = {
53   'DBD::SQLite'                   => '0',
54 };
55 my $rdbms_pg = {
56   'DBD::Pg'                       => '0',
57 };
58 my $rdbms_mssql_odbc = {
59   'DBD::ODBC'                     => '0',
60 };
61 my $rdbms_mssql_sybase = {
62   'DBD::Sybase'                   => '0',
63 };
64 my $rdbms_mssql_ado = {
65   'DBD::ADO'                      => '0',
66 };
67 my $rdbms_msaccess_odbc = {
68   'DBD::ODBC'                     => '0',
69 };
70 my $rdbms_msaccess_ado = {
71   'DBD::ADO'                      => '0',
72 };
73 my $rdbms_mysql = {
74   'DBD::mysql'                    => '0',
75 };
76 my $rdbms_oracle = {
77   'DBD::Oracle'                   => '0',
78   %$id_shortener,
79 };
80 my $rdbms_ase = {
81   'DBD::Sybase'                   => '0',
82 };
83 my $rdbms_db2 = {
84   'DBD::DB2'                      => '0',
85 };
86 my $rdbms_db2_400 = {
87   'DBD::ODBC'                     => '0',
88 };
89 my $rdbms_informix = {
90   'DBD::Informix'                 => '0',
91 };
92 my $rdbms_sqlanywhere = {
93   'DBD::SQLAnywhere'              => '0',
94 };
95 my $rdbms_sqlanywhere_odbc = {
96   'DBD::ODBC'                     => '0',
97 };
98 my $rdbms_firebird = {
99   'DBD::Firebird'                 => '0',
100 };
101 my $rdbms_firebird_interbase = {
102   'DBD::InterBase'                => '0',
103 };
104 my $rdbms_firebird_odbc = {
105   'DBD::ODBC'                     => '0',
106 };
107
108 my $reqs = {
109   dist => {
110     #'Module::Install::Pod::Inherit' => '0.01',
111   },
112
113   replicated => {
114     req => $replicated,
115     pod => {
116       title => 'Storage::Replicated',
117       desc => 'Modules required for L<DBIx::Class::Storage::DBI::Replicated>',
118     },
119   },
120
121   test_replicated => {
122     req => {
123       %$replicated,
124       'Test::Moose'               => '0',
125     },
126   },
127
128
129   admin => {
130     req => {
131       %$admin_basic,
132     },
133     pod => {
134       title => 'DBIx::Class::Admin',
135       desc => 'Modules required for the DBIx::Class administrative library',
136     },
137   },
138
139   admin_script => {
140     req => {
141       %$admin_script,
142     },
143     pod => {
144       title => 'dbicadmin',
145       desc => 'Modules required for the CLI DBIx::Class interface dbicadmin',
146     },
147   },
148
149   test_admin_script => {
150     req => {
151       %$admin_script,
152       ($^O eq 'MSWin32' ? ('Win32::ShellQuote' => 0) : ()),
153     }
154   },
155
156   deploy => {
157     req => {
158       'SQL::Translator'           => '0.11006',
159     },
160     pod => {
161       title => 'Storage::DBI::deploy()',
162       desc => 'Modules required for L<DBIx::Class::Storage::DBI/deploy> and L<DBIx::Class::Storage::DBI/deployment_statements>',
163     },
164   },
165
166   id_shortener => {
167     req => $id_shortener,
168   },
169
170   test_component_accessor => {
171     req => {
172       'Class::Unload'             => '0.07',
173     },
174   },
175
176   test_pod => {
177     req => {
178       'Test::Pod'                 => '1.41',
179     },
180   },
181
182   test_podcoverage => {
183     req => {
184       'Test::Pod::Coverage'       => '1.08',
185       'Pod::Coverage'             => '0.20',
186     },
187   },
188
189   test_notabs => {
190     req => {
191       'Test::NoTabs'              => '0.9',
192     },
193   },
194
195   test_eol => {
196     req => {
197       'Test::EOL'                 => '1.0',
198     },
199   },
200
201   test_prettydebug => {
202     req => $json_any,
203   },
204
205   test_leaks => {
206     req => {
207       'Test::Memory::Cycle'       => '0',
208       'Devel::Cycle'              => '1.10',
209     },
210   },
211
212   test_dt => {
213     req => $datetime_basic,
214   },
215
216   test_dt_sqlite => {
217     req => {
218       %$datetime_basic,
219       # t/36datetime.t
220       # t/60core.t
221       'DateTime::Format::SQLite'  => '0',
222     },
223   },
224
225   test_dt_mysql => {
226     req => {
227       %$datetime_basic,
228       # t/inflate/datetime_mysql.t
229       # (doesn't need Mysql itself)
230       'DateTime::Format::MySQL'   => '0',
231     },
232   },
233
234   test_dt_pg => {
235     req => {
236       %$datetime_basic,
237       # t/inflate/datetime_pg.t
238       # (doesn't need PG itself)
239       'DateTime::Format::Pg'      => '0.16004',
240     },
241   },
242
243   test_cdbicompat => {
244     req => {
245       'Class::DBI' => 0,
246       'Class::DBI::Plugin::DeepAbstractSearch' => '0',
247       %$datetime_basic,
248       'Time::Piece::MySQL'        => '0',
249       'Date::Simple'              => '3.03',
250     },
251   },
252
253   # this is just for completeness as SQLite
254   # is a core dep of DBIC for testing
255   rdbms_sqlite => {
256     req => {
257       %$rdbms_sqlite,
258     },
259     pod => {
260       title => 'SQLite support',
261       desc => 'Modules required to connect to SQLite',
262     },
263   },
264
265   rdbms_pg => {
266     req => {
267       # when changing this list make sure to adjust xt/optional_deps.t
268       %$rdbms_pg,
269     },
270     pod => {
271       title => 'PostgreSQL support',
272       desc => 'Modules required to connect to PostgreSQL',
273     },
274   },
275
276   rdbms_mssql_odbc => {
277     req => {
278       %$rdbms_mssql_odbc,
279     },
280     pod => {
281       title => 'MSSQL support via DBD::ODBC',
282       desc => 'Modules required to connect to MSSQL via DBD::ODBC',
283     },
284   },
285
286   rdbms_mssql_sybase => {
287     req => {
288       %$rdbms_mssql_sybase,
289     },
290     pod => {
291       title => 'MSSQL support via DBD::Sybase',
292       desc => 'Modules required to connect to MSSQL via DBD::Sybase',
293     },
294   },
295
296   rdbms_mssql_ado => {
297     req => {
298       %$rdbms_mssql_ado,
299     },
300     pod => {
301       title => 'MSSQL support via DBD::ADO (Windows only)',
302       desc => 'Modules required to connect to MSSQL via DBD::ADO. This particular DBD is available on Windows only',
303     },
304   },
305
306   rdbms_msaccess_odbc => {
307     req => {
308       %$rdbms_msaccess_odbc,
309     },
310     pod => {
311       title => 'MS Access support via DBD::ODBC',
312       desc => 'Modules required to connect to MS Access via DBD::ODBC',
313     },
314   },
315
316   rdbms_msaccess_ado => {
317     req => {
318       %$rdbms_msaccess_ado,
319     },
320     pod => {
321       title => 'MS Access support via DBD::ADO (Windows only)',
322       desc => 'Modules required to connect to MS Access via DBD::ADO. This particular DBD is available on Windows only',
323     },
324   },
325
326   rdbms_mysql => {
327     req => {
328       %$rdbms_mysql,
329     },
330     pod => {
331       title => 'MySQL support',
332       desc => 'Modules required to connect to MySQL',
333     },
334   },
335
336   rdbms_oracle => {
337     req => {
338       %$rdbms_oracle,
339     },
340     pod => {
341       title => 'Oracle support',
342       desc => 'Modules required to connect to Oracle',
343     },
344   },
345
346   rdbms_ase => {
347     req => {
348       %$rdbms_ase,
349     },
350     pod => {
351       title => 'Sybase ASE support',
352       desc => 'Modules required to connect to Sybase ASE',
353     },
354   },
355
356   rdbms_db2 => {
357     req => {
358       %$rdbms_db2,
359     },
360     pod => {
361       title => 'DB2 support',
362       desc => 'Modules required to connect to DB2',
363     },
364   },
365
366   rdbms_db2_400 => {
367     req => {
368       %$rdbms_db2_400,
369     },
370     pod => {
371       title => 'DB2 on AS/400 support',
372       desc => 'Modules required to connect to DB2 on AS/400',
373     },
374   },
375
376   rdbms_informix => {
377     req => {
378       %$rdbms_informix,
379     },
380     pod => {
381       title => 'Informix support',
382       desc => 'Modules required to connect to Informix',
383     },
384   },
385
386   rdbms_sqlanywhere => {
387     req => {
388       %$rdbms_sqlanywhere,
389     },
390     pod => {
391       title => 'SQLAnywhere support',
392       desc => 'Modules required to connect to SQLAnywhere',
393     },
394   },
395
396   rdbms_sqlanywhere_odbc => {
397     req => {
398       %$rdbms_sqlanywhere_odbc,
399     },
400     pod => {
401       title => 'SQLAnywhere support via DBD::ODBC',
402       desc => 'Modules required to connect to SQLAnywhere via DBD::ODBC',
403     },
404   },
405
406   rdbms_firebird => {
407     req => {
408       %$rdbms_firebird,
409     },
410     pod => {
411       title => 'Firebird support',
412       desc => 'Modules required to connect to Firebird',
413     },
414   },
415
416   rdbms_firebird_interbase => {
417     req => {
418       %$rdbms_firebird_interbase,
419     },
420     pod => {
421       title => 'Firebird support via DBD::InterBase',
422       desc => 'Modules required to connect to Firebird via DBD::InterBase',
423     },
424   },
425
426   rdbms_firebird_odbc => {
427     req => {
428       %$rdbms_firebird_odbc,
429     },
430     pod => {
431       title => 'Firebird support via DBD::ODBC',
432       desc => 'Modules required to connect to Firebird via DBD::ODBC',
433     },
434   },
435
436 # the order does matter because the rdbms support group might require
437 # a different version that the test group
438   test_rdbms_pg => {
439     req => {
440       $ENV{DBICTEST_PG_DSN}
441         ? (
442           # when changing this list make sure to adjust xt/optional_deps.t
443           %$rdbms_pg,
444           ($^O ne 'MSWin32' ? ('Sys::SigAction' => '0') : ()),
445           'DBD::Pg'               => '2.009002',
446         ) : ()
447     },
448   },
449
450   test_rdbms_mssql_odbc => {
451     req => {
452       $ENV{DBICTEST_MSSQL_ODBC_DSN}
453         ? (
454           %$rdbms_mssql_odbc,
455         ) : ()
456     },
457   },
458
459   test_rdbms_mssql_ado => {
460     req => {
461       $ENV{DBICTEST_MSSQL_ADO_DSN}
462         ? (
463           %$rdbms_mssql_ado,
464         ) : ()
465     },
466   },
467
468   test_rdbms_mssql_sybase => {
469     req => {
470       $ENV{DBICTEST_MSSQL_DSN}
471         ? (
472           %$rdbms_mssql_sybase,
473         ) : ()
474     },
475   },
476
477   test_rdbms_msaccess_odbc => {
478     req => {
479       $ENV{DBICTEST_MSACCESS_ODBC_DSN}
480         ? (
481           %$rdbms_msaccess_odbc,
482           %$datetime_basic,
483           'Data::GUID' => '0',
484         ) : ()
485     },
486   },
487
488   test_rdbms_msaccess_ado => {
489     req => {
490       $ENV{DBICTEST_MSACCESS_ADO_DSN}
491         ? (
492           %$rdbms_msaccess_ado,
493           %$datetime_basic,
494           'Data::GUID' => 0,
495         ) : ()
496     },
497   },
498
499   test_rdbms_mysql => {
500     req => {
501       $ENV{DBICTEST_MYSQL_DSN}
502         ? (
503           %$rdbms_mysql,
504         ) : ()
505     },
506   },
507
508   test_rdbms_oracle => {
509     req => {
510       $ENV{DBICTEST_ORA_DSN}
511         ? (
512           %$rdbms_oracle,
513           'DateTime::Format::Oracle' => '0',
514           'DBD::Oracle'              => '1.24',
515         ) : ()
516     },
517   },
518
519   test_rdbms_ase => {
520     req => {
521       $ENV{DBICTEST_SYBASE_DSN}
522         ? (
523           %$rdbms_ase,
524         ) : ()
525     },
526   },
527
528   test_rdbms_db2 => {
529     req => {
530       $ENV{DBICTEST_DB2_DSN}
531         ? (
532           %$rdbms_db2,
533         ) : ()
534     },
535   },
536
537   test_rdbms_db2_400 => {
538     req => {
539       $ENV{DBICTEST_DB2_400_DSN}
540         ? (
541           %$rdbms_db2_400,
542         ) : ()
543     },
544   },
545
546   test_rdbms_informix => {
547     req => {
548       $ENV{DBICTEST_INFORMIX_DSN}
549         ? (
550           %$rdbms_informix,
551         ) : ()
552     },
553   },
554
555   test_rdbms_sqlanywhere => {
556     req => {
557       $ENV{DBICTEST_SQLANYWHERE_DSN}
558         ? (
559           %$rdbms_sqlanywhere,
560         ) : ()
561     },
562   },
563
564   test_rdbms_sqlanywhere_odbc => {
565     req => {
566       $ENV{DBICTEST_SQLANYWHERE_ODBC_DSN}
567         ? (
568           %$rdbms_sqlanywhere_odbc,
569         ) : ()
570     },
571   },
572
573   test_rdbms_firebird => {
574     req => {
575       $ENV{DBICTEST_FIREBIRD_DSN}
576         ? (
577           %$rdbms_firebird,
578         ) : ()
579     },
580   },
581
582   test_rdbms_firebird_interbase => {
583     req => {
584       $ENV{DBICTEST_FIREBIRD_INTERBASE_DSN}
585         ? (
586           %$rdbms_firebird_interbase,
587         ) : ()
588     },
589   },
590
591   test_rdbms_firebird_odbc => {
592     req => {
593       $ENV{DBICTEST_FIREBIRD_ODBC_DSN}
594         ? (
595           %$rdbms_firebird_odbc,
596         ) : ()
597     },
598   },
599
600   test_memcached => {
601     req => {
602       $ENV{DBICTEST_MEMCACHED}
603         ? (
604           'Cache::Memcached' => 0,
605         ) : ()
606     },
607   },
608
609 };
610
611
612 sub req_list_for {
613   my ($class, $group) = @_;
614
615   Carp::croak "req_list_for() expects a requirement group name"
616     unless $group;
617
618   my $deps = $reqs->{$group}{req}
619     or Carp::croak "Requirement group '$group' does not exist";
620
621   return { %$deps };
622 }
623
624
625 our %req_availability_cache;
626 sub req_ok_for {
627   my ($class, $group) = @_;
628
629   Carp::croak "req_ok_for() expects a requirement group name"
630     unless $group;
631
632   return $class->_check_deps($group)->{status};
633 }
634
635 sub req_missing_for {
636   my ($class, $group) = @_;
637
638   Carp::croak "req_missing_for() expects a requirement group name"
639     unless $group;
640
641   return $class->_check_deps($group)->{missing};
642 }
643
644 sub req_errorlist_for {
645   my ($class, $group) = @_;
646
647   Carp::croak "req_errorlist_for() expects a requirement group name"
648     unless $group;
649
650   return $class->_check_deps($group)->{errorlist};
651 }
652
653 sub _check_deps {
654   my ($class, $group) = @_;
655
656   return $req_availability_cache{$group} ||= do {
657
658     my $deps = $class->req_list_for ($group);
659
660     my %errors;
661     for my $mod (keys %$deps) {
662       my $req_line = "require $mod;";
663       if (my $ver = $deps->{$mod}) {
664         $req_line .= "$mod->VERSION($ver);";
665       }
666
667       eval $req_line;
668
669       $errors{$mod} = $@ if $@;
670     }
671
672     my $res;
673
674     if (keys %errors) {
675       my $missing = join (', ', map { $deps->{$_} ? "$_ >= $deps->{$_}" : $_ } (sort keys %errors) );
676       $missing .= " (see $class for details)" if $reqs->{$group}{pod};
677       $res = {
678         status => 0,
679         errorlist => \%errors,
680         missing => $missing,
681       };
682     }
683     else {
684       $res = {
685         status => 1,
686         errorlist => {},
687         missing => '',
688       };
689     }
690
691     $res;
692   };
693 }
694
695 sub req_group_list {
696   return { map { $_ => { %{ $reqs->{$_}{req} || {} } } } (keys %$reqs) };
697 }
698
699 # This is to be called by the author only (automatically in Makefile.PL)
700 sub _gen_pod {
701   my ($class, $distver, $pod_dir) = @_;
702
703   die "No POD root dir supplied" unless $pod_dir;
704
705   $distver ||=
706     eval { require DBIx::Class; DBIx::Class->VERSION; }
707       ||
708     die
709 "\n\n---------------------------------------------------------------------\n" .
710 'Unable to load core DBIx::Class module to determine current version, '.
711 'possibly due to missing dependencies. Author-mode autodocumentation ' .
712 "halted\n\n" . $@ .
713 "\n\n---------------------------------------------------------------------\n"
714   ;
715
716   # do not ask for a recet version, use 1.x API calls
717   # this *may* execute on a smoker with old perl or whatnot
718   require File::Path;
719
720   (my $modfn = __PACKAGE__ . '.pm') =~ s|::|/|g;
721
722   (my $podfn = "$pod_dir/$modfn") =~ s/\.pm$/\.pod/;
723   (my $dir = $podfn) =~ s|/[^/]+$||;
724
725   File::Path::mkpath([$dir]);
726
727   my $sqltver = $class->req_list_for ('deploy')->{'SQL::Translator'}
728     or die "Hrmm? No sqlt dep?";
729
730   my @chunks = (
731     <<"EOC",
732 #########################################################################
733 #####################  A U T O G E N E R A T E D ########################
734 #########################################################################
735 #
736 # The contents of this POD file are auto-generated.  Any changes you make
737 # will be lost. If you need to change the generated text edit _gen_pod()
738 # at the end of $modfn
739 #
740 EOC
741     '=head1 NAME',
742     "$class - Optional module dependency specifications (for module authors)",
743     '=head1 SYNOPSIS',
744     <<"EOS",
745 Somewhere in your build-file (e.g. L<Module::Install>'s Makefile.PL):
746
747   ...
748
749   configure_requires 'DBIx::Class' => '$distver';
750
751   require $class;
752
753   my \$deploy_deps = $class->req_list_for('deploy');
754
755   for (keys %\$deploy_deps) {
756     requires \$_ => \$deploy_deps->{\$_};
757   }
758
759   ...
760
761 Note that there are some caveats regarding C<configure_requires()>, more info
762 can be found at L<Module::Install/configure_requires>
763 EOS
764     '=head1 DESCRIPTION',
765     <<'EOD',
766 Some of the less-frequently used features of L<DBIx::Class> have external
767 module dependencies on their own. In order not to burden the average user
768 with modules he will never use, these optional dependencies are not included
769 in the base Makefile.PL. Instead an exception with a descriptive message is
770 thrown when a specific feature is missing one or several modules required for
771 its operation. This module is the central holding place for  the current list
772 of such dependencies, for DBIx::Class core authors, and DBIx::Class extension
773 authors alike.
774 EOD
775     '=head1 CURRENT REQUIREMENT GROUPS',
776     <<'EOD',
777 Dependencies are organized in C<groups> and each group can list one or more
778 required modules, with an optional minimum version (or 0 for any version).
779 The group name can be used in the
780 EOD
781   );
782
783   for my $group (sort keys %$reqs) {
784     my $p = $reqs->{$group}{pod}
785       or next;
786
787     my $modlist = $reqs->{$group}{req}
788       or next;
789
790     next unless keys %$modlist;
791
792     push @chunks, (
793       "=head2 $p->{title}",
794       "$p->{desc}",
795       '=over',
796       ( map { "=item * $_" . ($modlist->{$_} ? " >= $modlist->{$_}" : '') } (sort keys %$modlist) ),
797       '=back',
798       "Requirement group: B<$group>",
799     );
800   }
801
802   push @chunks, (
803     '=head1 METHODS',
804     '=head2 req_group_list',
805     '=over',
806     '=item Arguments: none',
807     '=item Returns: \%list_of_requirement_groups',
808     '=back',
809     <<'EOD',
810 This method should be used by DBIx::Class packagers, to get a hashref of all
811 dependencies keyed by dependency group. Each key (group name) can be supplied
812 to one of the group-specific methods below.
813 EOD
814
815     '=head2 req_list_for',
816     '=over',
817     '=item Arguments: $group_name',
818     '=item Returns: \%list_of_module_version_pairs',
819     '=back',
820     <<'EOD',
821 This method should be used by DBIx::Class extension authors, to determine the
822 version of modules a specific feature requires in the B<current> version of
823 DBIx::Class. See the L</SYNOPSIS> for a real-world
824 example.
825 EOD
826
827     '=head2 req_ok_for',
828     '=over',
829     '=item Arguments: $group_name',
830     '=item Returns: 1|0',
831     '=back',
832     <<'EOD',
833 Returns true or false depending on whether all modules required by
834 C<$group_name> are present on the system and loadable.
835 EOD
836
837     '=head2 req_missing_for',
838     '=over',
839     '=item Arguments: $group_name',
840     '=item Returns: $error_message_string',
841     '=back',
842     <<"EOD",
843 Returns a single line string suitable for inclusion in larger error messages.
844 This method would normally be used by DBIx::Class core-module author, to
845 indicate to the user that he needs to install specific modules before he will
846 be able to use a specific feature.
847
848 For example if some of the requirements for C<deploy> are not available,
849 the returned string could look like:
850
851  SQL::Translator >= $sqltver (see $class for details)
852
853 The author is expected to prepend the necessary text to this message before
854 returning the actual error seen by the user.
855 EOD
856
857     '=head2 req_errorlist_for',
858     '=over',
859     '=item Arguments: $group_name',
860     '=item Returns: \%list_of_loaderrors_per_module',
861     '=back',
862     <<'EOD',
863 Returns a hashref containing the actual errors that occured while attempting
864 to load each module in the requirement group.
865 EOD
866     '=head1 AUTHOR',
867     'See L<DBIx::Class/CONTRIBUTORS>.',
868     '=head1 LICENSE',
869     'You may distribute this code under the same terms as Perl itself',
870   );
871
872   open (my $fh, '>', $podfn) or Carp::croak "Unable to write to $podfn: $!";
873   print $fh join ("\n\n", @chunks);
874   print $fh "\n";
875   close ($fh);
876 }
877
878 1;