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