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