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