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