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