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