fixup Firebird ODBC driver for DBD::ODBC 1.29
[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.89',
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_mysql = {
61   'DBD::mysql'                    => '0',
62 };
63 my $rdbms_oracle = {
64   'DBD::Oracle'                   => '0',
65   %$id_shortener,
66 };
67 my $rdbms_ase = {
68   'DBD::Sybase'                   => '0',
69 };
70 my $rdbms_db2 = {
71   'DBD::DB2'                      => '0',
72 };
73 my $rdbms_firebird_odbc = {
74   'DBD::ODBC'                     => '0',
75 };
76
77 my $reqs = {
78   dist => {
79     #'Module::Install::Pod::Inherit' => '0.01',
80   },
81
82   replicated => {
83     req => $replicated,
84     pod => {
85       title => 'Storage::Replicated',
86       desc => 'Modules required for L<DBIx::Class::Storage::DBI::Replicated>',
87     },
88   },
89
90   test_replicated => {
91     req => {
92       %$replicated,
93       'Test::Moose'               => '0',
94     },
95   },
96
97
98   admin => {
99     req => {
100       %$admin_basic,
101     },
102     pod => {
103       title => 'DBIx::Class::Admin',
104       desc => 'Modules required for the DBIx::Class administrative library',
105     },
106   },
107
108   admin_script => {
109     req => {
110       %$moose_basic,
111       %$admin_basic,
112       'Getopt::Long::Descriptive' => '0.081',
113       'Text::CSV'                 => '1.16',
114     },
115     pod => {
116       title => 'dbicadmin',
117       desc => 'Modules required for the CLI DBIx::Class interface dbicadmin',
118     },
119   },
120
121   deploy => {
122     req => {
123       'SQL::Translator'           => '0.11006',
124     },
125     pod => {
126       title => 'Storage::DBI::deploy()',
127       desc => 'Modules required for L<DBIx::Class::Storage::DBI/deploy> and L<DBIx::Class::Storage::DBI/deployment_statements>',
128     },
129   },
130
131   id_shortener => {
132     req => $id_shortener,
133   },
134
135   test_pod => {
136     req => {
137       'Test::Pod'                 => '1.41',
138     },
139   },
140
141   test_podcoverage => {
142     req => {
143       'Test::Pod::Coverage'       => '1.08',
144       'Pod::Coverage'             => '0.20',
145     },
146   },
147
148   test_notabs => {
149     req => {
150       'Test::NoTabs'              => '0.9',
151     },
152   },
153
154   test_eol => {
155     req => {
156       'Test::EOL'                 => '0.6',
157     },
158   },
159
160   test_prettydebug => {
161     req => $json_any,
162   },
163
164   test_leaks => {
165     req => {
166       'Test::Memory::Cycle'       => '0',
167       'Devel::Cycle'              => '1.10',
168     },
169   },
170
171   test_dt => {
172     req => $datetime_basic,
173   },
174
175   test_dt_sqlite => {
176     req => {
177       %$datetime_basic,
178       # t/36datetime.t
179       # t/60core.t
180       'DateTime::Format::SQLite'  => '0',
181     },
182   },
183
184   test_dt_mysql => {
185     req => {
186       %$datetime_basic,
187       # t/inflate/datetime_mysql.t
188       # (doesn't need Mysql itself)
189       'DateTime::Format::MySQL'   => '0',
190     },
191   },
192
193   test_dt_pg => {
194     req => {
195       %$datetime_basic,
196       # t/inflate/datetime_pg.t
197       # (doesn't need PG itself)
198       'DateTime::Format::Pg'      => '0.16004',
199     },
200   },
201
202   test_cdbicompat => {
203     req => {
204       'DBIx::ContextualFetch'     => '0',
205       'Class::DBI::Plugin::DeepAbstractSearch' => '0',
206       'Class::Trigger'            => '0',
207       'Time::Piece::MySQL'        => '0',
208       'Clone'                     => '0',
209       'Date::Simple'              => '3.03',
210     },
211   },
212
213   # this is just for completeness as SQLite
214   # is a core dep of DBIC for testing
215   rdbms_sqlite => {
216     req => {
217       %$rdbms_sqlite,
218     },
219     pod => {
220       title => 'SQLite support',
221       desc => 'Modules required to connect to SQLite',
222     },
223   },
224
225   rdbms_pg => {
226     req => {
227       %$rdbms_pg,
228     },
229     pod => {
230       title => 'PostgreSQL support',
231       desc => 'Modules required to connect to PostgreSQL',
232     },
233   },
234
235   rdbms_mssql_odbc => {
236     req => {
237       %$rdbms_mssql_odbc,
238     },
239     pod => {
240       title => 'MSSQL support via DBD::ODBC',
241       desc => 'Modules required to connect to MSSQL via DBD::ODBC',
242     },
243   },
244
245   rdbms_mssql_sybase => {
246     req => {
247       %$rdbms_mssql_sybase,
248     },
249     pod => {
250       title => 'MSSQL support via DBD::Sybase',
251       desc => 'Modules required to connect to MSSQL via DBD::Sybase',
252     },
253   },
254
255   rdbms_mssql_ado => {
256     req => {
257       %$rdbms_mssql_ado,
258     },
259     pod => {
260       title => 'MSSQL support via DBD::ADO (Windows only)',
261       desc => 'Modules required to connect to MSSQL via DBD::ADO. This particular DBD is available on Windows only',
262     },
263   },
264
265   rdbms_mysql => {
266     req => {
267       %$rdbms_mysql,
268     },
269     pod => {
270       title => 'MySQL support',
271       desc => 'Modules required to connect to MySQL',
272     },
273   },
274
275   rdbms_oracle => {
276     req => {
277       %$rdbms_oracle,
278     },
279     pod => {
280       title => 'Oracle support',
281       desc => 'Modules required to connect to Oracle',
282     },
283   },
284
285   rdbms_ase => {
286     req => {
287       %$rdbms_ase,
288     },
289     pod => {
290       title => 'Sybase ASE support',
291       desc => 'Modules required to connect to Sybase ASE',
292     },
293   },
294
295   rdbms_db2 => {
296     req => {
297       %$rdbms_db2,
298     },
299     pod => {
300       title => 'DB2 support',
301       desc => 'Modules required to connect to DB2',
302     },
303   },
304
305 # the order does matter because the rdbms support group might require
306 # a different version that the test group
307   test_rdbms_pg => {
308     req => {
309       $ENV{DBICTEST_PG_DSN}
310         ? (
311           %$rdbms_pg,
312           'Sys::SigAction'        => '0',
313           'DBD::Pg'               => '2.009002',
314         ) : ()
315     },
316   },
317
318   test_rdbms_mssql_odbc => {
319     req => {
320       $ENV{DBICTEST_MSSQL_ODBC_DSN}
321         ? (
322           %$rdbms_mssql_odbc,
323         ) : ()
324     },
325   },
326
327   test_rdbms_mssql_ado => {
328     req => {
329       $ENV{DBICTEST_MSSQL_ADO_DSN}
330         ? (
331           %$rdbms_mssql_ado,
332         ) : ()
333     },
334   },
335
336   test_rdbms_mssql_sybase => {
337     req => {
338       $ENV{DBICTEST_MSSQL_DSN}
339         ? (
340           %$rdbms_mssql_sybase,
341         ) : ()
342     },
343   },
344
345   test_rdbms_mysql => {
346     req => {
347       $ENV{DBICTEST_MYSQL_DSN}
348         ? (
349           %$rdbms_mysql,
350         ) : ()
351     },
352   },
353
354   test_rdbms_oracle => {
355     req => {
356       $ENV{DBICTEST_ORA_DSN}
357         ? (
358           %$rdbms_oracle,
359           'DateTime::Format::Oracle' => '0',
360           'DBD::Oracle'              => '1.24',
361         ) : ()
362     },
363   },
364
365   test_rdbms_ase => {
366     req => {
367       $ENV{DBICTEST_SYBASE_DSN}
368         ? (
369           %$rdbms_ase,
370           'DateTime::Format::Sybase' => '0',
371         ) : ()
372     },
373   },
374
375   test_rdbms_db2 => {
376     req => {
377       $ENV{DBICTEST_DB2_DSN}
378         ? (
379           %$rdbms_db2,
380         ) : ()
381     },
382   },
383
384   test_rdbms_firebird_odbc => {
385     req => {
386       $ENV{DBICTEST_FIREBIRD_ODBC_DSN}
387         ? (
388           %$rdbms_firebird_odbc,
389         ) : ()
390     },
391   },
392
393   test_memcached => {
394     req => {
395       $ENV{DBICTEST_MEMCACHED}
396         ? (
397           'Cache::Memcached' => 0,
398         ) : ()
399     },
400   },
401
402 };
403
404
405 sub req_list_for {
406   my ($class, $group) = @_;
407
408   croak "req_list_for() expects a requirement group name"
409     unless $group;
410
411   my $deps = $reqs->{$group}{req}
412     or croak "Requirement group '$group' does not exist";
413
414   return { %$deps };
415 }
416
417
418 our %req_availability_cache;
419 sub req_ok_for {
420   my ($class, $group) = @_;
421
422   croak "req_ok_for() expects a requirement group name"
423     unless $group;
424
425   return $class->_check_deps($group)->{status};
426 }
427
428 sub req_missing_for {
429   my ($class, $group) = @_;
430
431   croak "req_missing_for() expects a requirement group name"
432     unless $group;
433
434   return $class->_check_deps($group)->{missing};
435 }
436
437 sub req_errorlist_for {
438   my ($class, $group) = @_;
439
440   croak "req_errorlist_for() expects a requirement group name"
441     unless $group;
442
443   return $class->_check_deps($group)->{errorlist};
444 }
445
446 sub _check_deps {
447   my ($class, $group) = @_;
448
449   return $req_availability_cache{$group} ||= do {
450
451     my $deps = $class->req_list_for ($group);
452
453     my %errors;
454     for my $mod (keys %$deps) {
455       my $req_line = "require $mod;";
456       if (my $ver = $deps->{$mod}) {
457         $req_line .= "$mod->VERSION($ver);";
458       }
459
460       eval $req_line;
461
462       $errors{$mod} = $@ if $@;
463     }
464
465     my $res;
466
467     if (keys %errors) {
468       my $missing = join (', ', map { $deps->{$_} ? "$_ >= $deps->{$_}" : $_ } (sort keys %errors) );
469       $missing .= " (see $class for details)" if $reqs->{$group}{pod};
470       $res = {
471         status => 0,
472         errorlist => \%errors,
473         missing => $missing,
474       };
475     }
476     else {
477       $res = {
478         status => 1,
479         errorlist => {},
480         missing => '',
481       };
482     }
483
484     $res;
485   };
486 }
487
488 sub req_group_list {
489   return { map { $_ => { %{ $reqs->{$_}{req} || {} } } } (keys %$reqs) };
490 }
491
492 # This is to be called by the author only (automatically in Makefile.PL)
493 sub _gen_pod {
494   my ($class, $distver) = @_;
495
496   my $modfn = __PACKAGE__ . '.pm';
497   $modfn =~ s/\:\:/\//g;
498
499   my $podfn = __FILE__;
500   $podfn =~ s/\.pm$/\.pod/;
501
502   $distver ||=
503     eval { require DBIx::Class; DBIx::Class->VERSION; }
504       ||
505     die
506 "\n\n---------------------------------------------------------------------\n" .
507 'Unable to load core DBIx::Class module to determine current version, '.
508 'possibly due to missing dependencies. Author-mode autodocumentation ' .
509 "halted\n\n" . $@ .
510 "\n\n---------------------------------------------------------------------\n"
511   ;
512
513   my $sqltver = $class->req_list_for ('deploy')->{'SQL::Translator'}
514     or die "Hrmm? No sqlt dep?";
515
516   my @chunks = (
517     <<'EOC',
518 #########################################################################
519 #####################  A U T O G E N E R A T E D ########################
520 #########################################################################
521 #
522 # The contents of this POD file are auto-generated.  Any changes you make
523 # will be lost. If you need to change the generated text edit _gen_pod()
524 # at the end of $modfn
525 #
526 EOC
527     '=head1 NAME',
528     "$class - Optional module dependency specifications (for module authors)",
529     '=head1 SYNOPSIS',
530     <<"EOS",
531 Somewhere in your build-file (e.g. L<Module::Install>'s Makefile.PL):
532
533   ...
534
535   configure_requires 'DBIx::Class' => '$distver';
536
537   require $class;
538
539   my \$deploy_deps = $class->req_list_for('deploy');
540
541   for (keys %\$deploy_deps) {
542     requires \$_ => \$deploy_deps->{\$_};
543   }
544
545   ...
546
547 Note that there are some caveats regarding C<configure_requires()>, more info
548 can be found at L<Module::Install/configure_requires>
549 EOS
550     '=head1 DESCRIPTION',
551     <<'EOD',
552 Some of the less-frequently used features of L<DBIx::Class> have external
553 module dependencies on their own. In order not to burden the average user
554 with modules he will never use, these optional dependencies are not included
555 in the base Makefile.PL. Instead an exception with a descriptive message is
556 thrown when a specific feature is missing one or several modules required for
557 its operation. This module is the central holding place for  the current list
558 of such dependencies, for DBIx::Class core authors, and DBIx::Class extension
559 authors alike.
560 EOD
561     '=head1 CURRENT REQUIREMENT GROUPS',
562     <<'EOD',
563 Dependencies are organized in C<groups> and each group can list one or more
564 required modules, with an optional minimum version (or 0 for any version).
565 The group name can be used in the
566 EOD
567   );
568
569   for my $group (sort keys %$reqs) {
570     my $p = $reqs->{$group}{pod}
571       or next;
572
573     my $modlist = $reqs->{$group}{req}
574       or next;
575
576     next unless keys %$modlist;
577
578     push @chunks, (
579       "=head2 $p->{title}",
580       "$p->{desc}",
581       '=over',
582       ( map { "=item * $_" . ($modlist->{$_} ? " >= $modlist->{$_}" : '') } (sort keys %$modlist) ),
583       '=back',
584       "Requirement group: B<$group>",
585     );
586   }
587
588   push @chunks, (
589     '=head1 METHODS',
590     '=head2 req_group_list',
591     '=over',
592     '=item Arguments: none',
593     '=item Returns: \%list_of_requirement_groups',
594     '=back',
595     <<'EOD',
596 This method should be used by DBIx::Class packagers, to get a hashref of all
597 dependencies keyed by dependency group. Each key (group name) can be supplied
598 to one of the group-specific methods below.
599 EOD
600
601     '=head2 req_list_for',
602     '=over',
603     '=item Arguments: $group_name',
604     '=item Returns: \%list_of_module_version_pairs',
605     '=back',
606     <<'EOD',
607 This method should be used by DBIx::Class extension authors, to determine the
608 version of modules a specific feature requires in the B<current> version of
609 DBIx::Class. See the L</SYNOPSIS> for a real-world
610 example.
611 EOD
612
613     '=head2 req_ok_for',
614     '=over',
615     '=item Arguments: $group_name',
616     '=item Returns: 1|0',
617     '=back',
618     <<'EOD',
619 Returns true or false depending on whether all modules required by
620 C<$group_name> are present on the system and loadable.
621 EOD
622
623     '=head2 req_missing_for',
624     '=over',
625     '=item Arguments: $group_name',
626     '=item Returns: $error_message_string',
627     '=back',
628     <<"EOD",
629 Returns a single line string suitable for inclusion in larger error messages.
630 This method would normally be used by DBIx::Class core-module author, to
631 indicate to the user that he needs to install specific modules before he will
632 be able to use a specific feature.
633
634 For example if some of the requirements for C<deploy> are not available,
635 the returned string could look like:
636
637  SQL::Translator >= $sqltver (see $class for details)
638
639 The author is expected to prepend the necessary text to this message before
640 returning the actual error seen by the user.
641 EOD
642
643     '=head2 req_errorlist_for',
644     '=over',
645     '=item Arguments: $group_name',
646     '=item Returns: \%list_of_loaderrors_per_module',
647     '=back',
648     <<'EOD',
649 Returns a hashref containing the actual errors that occured while attempting
650 to load each module in the requirement group.
651 EOD
652     '=head1 AUTHOR',
653     'See L<DBIx::Class/CONTRIBUTORS>.',
654     '=head1 LICENSE',
655     'You may distribute this code under the same terms as Perl itself',
656   );
657
658   open (my $fh, '>', $podfn) or croak "Unable to write to $podfn: $!";
659   print $fh join ("\n\n", @chunks);
660   close ($fh);
661 }
662
663 1;