Introduce basic optdeps group inclusion mechanism, simplify many declarations
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Optional / Dependencies.pm
CommitLineData
8057ed01 1package DBIx::Class::Optional::Dependencies;
2
3use warnings;
4use strict;
5
3f5e367a 6use Carp;
fb39747c 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
3ade80ee 14# NOTE: the rationale for 2 JSON::Any versions is that
15# we need the newer only to work around JSON::XS, which
16# itself is an optional dep
17my $min_json_any = {
be855469 18 'JSON::Any' => '1.23',
2a2a7b23 19};
3ade80ee 20my $test_and_dist_json_any = {
21 'JSON::Any' => '1.31',
22};
2a2a7b23 23
2b48ebff 24my $moose_basic = {
68de9438 25 'Moose' => '0.98',
26 'MooseX::Types' => '0.21',
d401ab6b 27 'MooseX::Types::LoadableClass' => '0.011',
68de9438 28};
29
31c31b8d 30my $dbic_reqs = {
8057ed01 31 replicated => {
e163f484 32 req => $moose_basic,
f6b26571 33 pod => {
34 title => 'Storage::Replicated',
35 desc => 'Modules required for L<DBIx::Class::Storage::DBI::Replicated>',
36 },
8057ed01 37 },
38
68de9438 39 test_replicated => {
e163f484 40 include => 'replicated',
68de9438 41 req => {
e163f484 42 'Test::Moose' => '0',
68de9438 43 },
44 },
45
8057ed01 46 admin => {
2b48ebff 47 req => {
e163f484 48 %$moose_basic,
49 %$min_json_any,
50 'MooseX::Types::Path::Class' => '0.05',
51 'MooseX::Types::JSON' => '0.02',
ebcd0e4f 52 },
53 pod => {
54 title => 'DBIx::Class::Admin',
55 desc => 'Modules required for the DBIx::Class administrative library',
56 },
57 },
58
a4a02f15 59 admin_script => {
e163f484 60 include => 'admin',
ebcd0e4f 61 req => {
e163f484 62 'Getopt::Long::Descriptive' => '0.081',
63 'Text::CSV' => '1.16',
2b48ebff 64 },
e144415f 65 pod => {
66 title => 'dbicadmin',
67 desc => 'Modules required for the CLI DBIx::Class interface dbicadmin',
68 },
8057ed01 69 },
70
71 deploy => {
f6b26571 72 req => {
08ac7648 73 'SQL::Translator' => '0.11018',
f6b26571 74 },
75 pod => {
76 title => 'Storage::DBI::deploy()',
5529838f 77 desc => 'Modules required for L<DBIx::Class::Storage::DBI/deployment_statements> and L<DBIx::Class::Schema/deploy>',
f6b26571 78 },
8057ed01 79 },
80
c7d50a7d 81 id_shortener => {
e163f484 82 req => {
83 'Math::BigInt' => '1.80',
84 'Math::Base36' => '0.07',
85 },
c7d50a7d 86 },
87
0d374214 88 test_component_accessor => {
89 req => {
90 'Class::Unload' => '0.07',
91 },
92 },
93
a109c954 94 test_pod => {
f6b26571 95 req => {
cbb19edf 96 'Test::Pod' => '1.42',
a109c954 97 },
98 },
99
100 test_podcoverage => {
101 req => {
f6b26571 102 'Test::Pod::Coverage' => '1.08',
103 'Pod::Coverage' => '0.20',
a109c954 104 },
105 },
106
ffce4b65 107 test_whitespace => {
a109c954 108 req => {
8273e845 109 'Test::EOL' => '1.0',
ffce4b65 110 'Test::NoTabs' => '0.9',
f6b26571 111 },
8057ed01 112 },
113
4a233f30 114 test_strictures => {
115 req => {
b2c1212f 116 'Test::Strict' => '0.20',
4a233f30 117 },
118 },
119
2a2a7b23 120 test_prettydebug => {
3ade80ee 121 req => $min_json_any,
2a2a7b23 122 },
123
99503754 124 test_admin_script => {
e163f484 125 include => 'admin_script',
99503754 126 req => {
3ade80ee 127 %$test_and_dist_json_any,
99503754 128 'JSON' => 0,
be855469 129 'JSON::PP' => 0,
130 'Cpanel::JSON::XS' => 0,
99503754 131 'JSON::XS' => 0,
132 $^O eq 'MSWin32'
133 # for t/admin/10script.t
134 ? ('Win32::ShellQuote' => 0)
135 # DWIW does not compile (./configure even) on win32
136 : ('JSON::DWIW' => 0 )
137 ,
138 }
139 },
140
556c4fe6 141 test_leaks_heavy => {
f6b26571 142 req => {
556c4fe6 143 'Class::MethodCache' => '0.02',
144 'PadWalker' => '1.06',
a109c954 145 },
146 },
f6b26571 147
68de9438 148 test_dt => {
e163f484 149 req => {
150 'DateTime' => '0.55',
151 'DateTime::Format::Strptime' => '1.2',
152 },
68de9438 153 },
154
155 test_dt_sqlite => {
e163f484 156 include => 'test_dt',
a109c954 157 req => {
f6b26571 158 # t/36datetime.t
159 # t/60core.t
160 'DateTime::Format::SQLite' => '0',
68de9438 161 },
162 },
f6b26571 163
68de9438 164 test_dt_mysql => {
e163f484 165 include => 'test_dt',
68de9438 166 req => {
9c92bb1c 167 # t/inflate/datetime_mysql.t
168 # (doesn't need Mysql itself)
68de9438 169 'DateTime::Format::MySQL' => '0',
170 },
171 },
9c92bb1c 172
68de9438 173 test_dt_pg => {
e163f484 174 include => 'test_dt',
68de9438 175 req => {
9c92bb1c 176 # t/inflate/datetime_pg.t
177 # (doesn't need PG itself)
ab35aeab 178 'DateTime::Format::Pg' => '0.16004',
f6b26571 179 },
8057ed01 180 },
181
68de9438 182 test_cdbicompat => {
e163f484 183 include => 'test_dt',
f6b26571 184 req => {
f6b26571 185 'Class::DBI::Plugin::DeepAbstractSearch' => '0',
f6b26571 186 'Time::Piece::MySQL' => '0',
f6b26571 187 'Date::Simple' => '3.03',
188 },
8057ed01 189 },
190
e163f484 191 rdbms_generic_odbc => {
192 req => {
193 'DBD::ODBC' => 0,
194 }
195 },
196
197 rdbms_generic_ado => {
198 req => {
199 'DBD::ADO' => 0,
200 }
201 },
202
be68095d 203 # this is just for completeness as SQLite
204 # is a core dep of DBIC for testing
205 rdbms_sqlite => {
206 req => {
e163f484 207 'DBD::SQLite' => 0,
be68095d 208 },
209 pod => {
210 title => 'SQLite support',
211 desc => 'Modules required to connect to SQLite',
212 },
213 },
214
215 rdbms_pg => {
216 req => {
a4fc1239 217 # when changing this list make sure to adjust xt/optional_deps.t
e163f484 218 'DBD::Pg' => 0,
be68095d 219 },
220 pod => {
221 title => 'PostgreSQL support',
222 desc => 'Modules required to connect to PostgreSQL',
223 },
224 },
225
226 rdbms_mssql_odbc => {
e163f484 227 include => 'rdbms_generic_odbc',
be68095d 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 => {
e163f484 236 'DBD::Sybase' => 0,
be68095d 237 },
238 pod => {
239 title => 'MSSQL support via DBD::Sybase',
56dca25f 240 desc => 'Modules required to connect to MSSQL via DBD::Sybase',
241 },
242 },
243
244 rdbms_mssql_ado => {
e163f484 245 include => 'rdbms_generic_ado',
56dca25f 246 pod => {
247 title => 'MSSQL support via DBD::ADO (Windows only)',
248 desc => 'Modules required to connect to MSSQL via DBD::ADO. This particular DBD is available on Windows only',
be68095d 249 },
250 },
251
726c8f65 252 rdbms_msaccess_odbc => {
e163f484 253 include => 'rdbms_generic_odbc',
726c8f65 254 pod => {
255 title => 'MS Access support via DBD::ODBC',
256 desc => 'Modules required to connect to MS Access via DBD::ODBC',
257 },
258 },
259
260 rdbms_msaccess_ado => {
e163f484 261 include => 'rdbms_generic_ado',
726c8f65 262 pod => {
263 title => 'MS Access support via DBD::ADO (Windows only)',
264 desc => 'Modules required to connect to MS Access via DBD::ADO. This particular DBD is available on Windows only',
265 },
266 },
267
be68095d 268 rdbms_mysql => {
269 req => {
e163f484 270 'DBD::mysql' => 0,
be68095d 271 },
272 pod => {
273 title => 'MySQL support',
274 desc => 'Modules required to connect to MySQL',
275 },
276 },
277
278 rdbms_oracle => {
e163f484 279 include => 'id_shortener',
be68095d 280 req => {
e163f484 281 'DBD::Oracle' => 0,
be68095d 282 },
283 pod => {
284 title => 'Oracle support',
285 desc => 'Modules required to connect to Oracle',
286 },
287 },
288
289 rdbms_ase => {
290 req => {
e163f484 291 'DBD::Sybase' => 0,
be68095d 292 },
293 pod => {
294 title => 'Sybase ASE support',
295 desc => 'Modules required to connect to Sybase ASE',
296 },
297 },
298
299 rdbms_db2 => {
300 req => {
e163f484 301 'DBD::DB2' => 0,
be68095d 302 },
303 pod => {
304 title => 'DB2 support',
305 desc => 'Modules required to connect to DB2',
306 },
307 },
308
199fbc45 309 rdbms_db2_400 => {
e163f484 310 include => 'rdbms_generic_odbc',
199fbc45 311 pod => {
312 title => 'DB2 on AS/400 support',
313 desc => 'Modules required to connect to DB2 on AS/400',
314 },
315 },
316
317 rdbms_informix => {
318 req => {
e163f484 319 'DBD::Informix' => 0,
199fbc45 320 },
321 pod => {
322 title => 'Informix support',
323 desc => 'Modules required to connect to Informix',
324 },
8273e845 325 },
199fbc45 326
327 rdbms_sqlanywhere => {
328 req => {
e163f484 329 'DBD::SQLAnywhere' => 0,
199fbc45 330 },
331 pod => {
332 title => 'SQLAnywhere support',
333 desc => 'Modules required to connect to SQLAnywhere',
334 },
8273e845 335 },
199fbc45 336
337 rdbms_sqlanywhere_odbc => {
e163f484 338 include => 'rdbms_generic_odbc',
199fbc45 339 pod => {
340 title => 'SQLAnywhere support via DBD::ODBC',
341 desc => 'Modules required to connect to SQLAnywhere via DBD::ODBC',
342 },
8273e845 343 },
199fbc45 344
345 rdbms_firebird => {
346 req => {
e163f484 347 'DBD::Firebird' => 0,
199fbc45 348 },
349 pod => {
350 title => 'Firebird support',
351 desc => 'Modules required to connect to Firebird',
352 },
8273e845 353 },
199fbc45 354
355 rdbms_firebird_interbase => {
356 req => {
e163f484 357 'DBD::InterBase' => 0,
199fbc45 358 },
359 pod => {
360 title => 'Firebird support via DBD::InterBase',
361 desc => 'Modules required to connect to Firebird via DBD::InterBase',
362 },
8273e845 363 },
199fbc45 364
365 rdbms_firebird_odbc => {
e163f484 366 include => 'rdbms_generic_odbc',
199fbc45 367 pod => {
368 title => 'Firebird support via DBD::ODBC',
369 desc => 'Modules required to connect to Firebird via DBD::ODBC',
370 },
8273e845 371 },
199fbc45 372
68de9438 373 test_rdbms_pg => {
e163f484 374 include => 'rdbms_pg',
e3a7746c 375 env => [
376 DBICTEST_PG_DSN => 1,
377 DBICTEST_PG_USER => 0,
378 DBICTEST_PG_PASS => 0,
379 ],
f6b26571 380 req => {
e3a7746c 381 # the order does matter because the rdbms support group might require
382 # a different version that the test group
383 #
384 # when changing this list make sure to adjust xt/optional_deps.t
e3a7746c 385 'DBD::Pg' => '2.009002', # specific version to test bytea
f6b26571 386 },
8057ed01 387 },
388
afae8507 389 test_rdbms_mssql_odbc => {
e163f484 390 include => 'rdbms_mssql_odbc',
e3a7746c 391 env => [
392 DBICTEST_MSSQL_ODBC_DSN => 1,
393 DBICTEST_MSSQL_ODBC_USER => 0,
394 DBICTEST_MSSQL_ODBC_PASS => 0,
395 ],
afae8507 396 },
397
56dca25f 398 test_rdbms_mssql_ado => {
e163f484 399 include => 'rdbms_mssql_ado',
e3a7746c 400 env => [
401 DBICTEST_MSSQL_ADO_DSN => 1,
402 DBICTEST_MSSQL_ADO_USER => 0,
403 DBICTEST_MSSQL_ADO_PASS => 0,
404 ],
56dca25f 405 },
406
afae8507 407 test_rdbms_mssql_sybase => {
e163f484 408 include => 'rdbms_mssql_sybase',
e3a7746c 409 env => [
410 DBICTEST_MSSQL_DSN => 1,
411 DBICTEST_MSSQL_USER => 0,
412 DBICTEST_MSSQL_PASS => 0,
413 ],
afae8507 414 },
415
726c8f65 416 test_rdbms_msaccess_odbc => {
e163f484 417 include => [qw(rdbms_msaccess_odbc test_dt)],
e3a7746c 418 env => [
419 DBICTEST_MSACCESS_ODBC_DSN => 1,
420 DBICTEST_MSACCESS_ODBC_USER => 0,
421 DBICTEST_MSACCESS_ODBC_PASS => 0,
422 ],
726c8f65 423 req => {
e3a7746c 424 'Data::GUID' => '0',
726c8f65 425 },
426 },
427
428 test_rdbms_msaccess_ado => {
e163f484 429 include => [qw(rdbms_msaccess_ado test_dt)],
e3a7746c 430 env => [
431 DBICTEST_MSACCESS_ADO_DSN => 1,
432 DBICTEST_MSACCESS_ADO_USER => 0,
433 DBICTEST_MSACCESS_ADO_PASS => 0,
434 ],
726c8f65 435 req => {
e3a7746c 436 'Data::GUID' => 0,
726c8f65 437 },
438 },
439
68de9438 440 test_rdbms_mysql => {
e163f484 441 include => 'rdbms_mysql',
e3a7746c 442 env => [
443 DBICTEST_MYSQL_DSN => 1,
444 DBICTEST_MYSQL_USER => 0,
445 DBICTEST_MYSQL_PASS => 0,
446 ],
8057ed01 447 },
448
68de9438 449 test_rdbms_oracle => {
e163f484 450 include => 'rdbms_oracle',
e3a7746c 451 env => [
452 DBICTEST_ORA_DSN => 1,
453 DBICTEST_ORA_USER => 0,
454 DBICTEST_ORA_PASS => 0,
455 ],
f6b26571 456 req => {
e3a7746c 457 'DateTime::Format::Oracle' => '0',
458 'DBD::Oracle' => '1.24',
f6b26571 459 },
8057ed01 460 },
461
68de9438 462 test_rdbms_ase => {
e163f484 463 include => 'rdbms_ase',
e3a7746c 464 env => [
465 DBICTEST_SYBASE_DSN => 1,
466 DBICTEST_SYBASE_USER => 0,
467 DBICTEST_SYBASE_PASS => 0,
468 ],
8057ed01 469 },
470
68de9438 471 test_rdbms_db2 => {
e163f484 472 include => 'rdbms_db2',
e3a7746c 473 env => [
474 DBICTEST_DB2_DSN => 1,
475 DBICTEST_DB2_USER => 0,
476 DBICTEST_DB2_PASS => 0,
477 ],
f58a165c 478 },
479
199fbc45 480 test_rdbms_db2_400 => {
e163f484 481 include => 'rdbms_db2_400',
e3a7746c 482 env => [
483 DBICTEST_DB2_400_DSN => 1,
484 DBICTEST_DB2_400_USER => 0,
485 DBICTEST_DB2_400_PASS => 0,
486 ],
199fbc45 487 },
488
489 test_rdbms_informix => {
e163f484 490 include => 'rdbms_informix',
e3a7746c 491 env => [
492 DBICTEST_INFORMIX_DSN => 1,
493 DBICTEST_INFORMIX_USER => 0,
494 DBICTEST_INFORMIX_PASS => 0,
495 ],
199fbc45 496 },
497
498 test_rdbms_sqlanywhere => {
e163f484 499 include => 'rdbms_sqlanywhere',
e3a7746c 500 env => [
501 DBICTEST_SQLANYWHERE_DSN => 1,
502 DBICTEST_SQLANYWHERE_USER => 0,
503 DBICTEST_SQLANYWHERE_PASS => 0,
504 ],
199fbc45 505 },
506
507 test_rdbms_sqlanywhere_odbc => {
e163f484 508 include => 'rdbms_sqlanywhere_odbc',
e3a7746c 509 env => [
510 DBICTEST_SQLANYWHERE_ODBC_DSN => 1,
511 DBICTEST_SQLANYWHERE_ODBC_USER => 0,
512 DBICTEST_SQLANYWHERE_ODBC_PASS => 0,
513 ],
199fbc45 514 },
515
516 test_rdbms_firebird => {
e163f484 517 include => 'rdbms_firebird',
e3a7746c 518 env => [
519 DBICTEST_FIREBIRD_DSN => 1,
520 DBICTEST_FIREBIRD_USER => 0,
521 DBICTEST_FIREBIRD_PASS => 0,
522 ],
199fbc45 523 },
524
525 test_rdbms_firebird_interbase => {
e163f484 526 include => 'rdbms_firebird_interbase',
e3a7746c 527 env => [
528 DBICTEST_FIREBIRD_INTERBASE_DSN => 1,
529 DBICTEST_FIREBIRD_INTERBASE_USER => 0,
530 DBICTEST_FIREBIRD_INTERBASE_PASS => 0,
531 ],
199fbc45 532 },
533
e02b39b4 534 test_rdbms_firebird_odbc => {
e163f484 535 include => 'rdbms_firebird_odbc',
e3a7746c 536 env => [
537 DBICTEST_FIREBIRD_ODBC_DSN => 1,
538 DBICTEST_FIREBIRD_ODBC_USER => 0,
539 DBICTEST_FIREBIRD_ODBC_PASS => 0,
540 ],
e02b39b4 541 },
542
42168332 543 test_memcached => {
e3a7746c 544 env => [
545 DBICTEST_MEMCACHED => 1,
546 ],
42168332 547 req => {
e3a7746c 548 'Cache::Memcached' => 0,
42168332 549 },
550 },
551
344f1f52 552 dist_dir => {
553 req => {
3ade80ee 554 %$test_and_dist_json_any,
b81d8515 555 'ExtUtils::MakeMaker' => '6.64',
06fc872a 556 'Pod::Inherit' => '0.91',
557 },
344f1f52 558 },
559
560 dist_upload => {
561 req => {
562 'CPAN::Uploader' => '0.103001',
563 },
564 },
8057ed01 565};
566
f6b26571 567
3ca0dcf0 568
569### Public API
570
571# OO for (mistakenly considered) ease of extensibility, not due to any need to
572# carry state of any sort. This API is currently used outside, so leave as-is.
573# FIXME - make sure to not propagate this further if module is extracted as a
574# standalone library - keep the stupidity to a DBIC-secific shim!
575#
fb39747c 576sub req_list_for {
e3a7746c 577 shift->_groups_to_reqs(@_)->{effective_modreqs};
578}
579
580sub modreq_list_for {
31c31b8d 581 shift->_groups_to_reqs(@_)->{modreqs};
fb39747c 582}
583
3ca0dcf0 584sub req_group_list {
31c31b8d 585 +{ map
586 { $_ => $_[0]->_groups_to_reqs($_) }
587 keys %$dbic_reqs
588 }
3ca0dcf0 589}
fb39747c 590
5ffa39c7 591sub req_errorlist_for { shift->modreq_errorlist_for(@_) } # deprecated
592sub modreq_errorlist_for {
31c31b8d 593 my $self = shift;
594 $self->_errorlist_for_modreqs( $self->_groups_to_reqs(@_)->{modreqs} );
344f1f52 595}
596
fb39747c 597sub req_ok_for {
e3a7746c 598 shift->req_missing_for(@_) ? 0 : 1;
599}
600
601sub req_missing_for {
31c31b8d 602 my $self = shift;
e3a7746c 603
604 my $reqs = $self->_groups_to_reqs(@_);
605 my $mods_missing = $self->modreq_missing_for(@_);
606
607 return '' if
608 ! $mods_missing
609 and
610 ! $reqs->{missing_envvars}
31c31b8d 611 ;
e3a7746c 612
613 my @res = $mods_missing || ();
614
615 push @res, 'the following group(s) of environment variables: ' . join ' and ', map
616 { __envvar_group_desc($_) }
617 @{$reqs->{missing_envvars}}
618 if $reqs->{missing_envvars};
619
620 return (
621 ( join ' as well as ', @res )
622 .
623 ( $reqs->{modreqs_fully_documented} ? " (see @{[ ref $self || $self ]} documentation for details)" : '' ),
624 );
fb39747c 625}
626
e3a7746c 627sub modreq_missing_for {
31c31b8d 628 my $self = shift;
fb39747c 629
31c31b8d 630 my $reqs = $self->_groups_to_reqs(@_);
e3a7746c 631 my $modreq_errors = $self->_errorlist_for_modreqs($reqs->{modreqs})
632 or return '';
fb39747c 633
e3a7746c 634 join ' ', map
635 { $reqs->{modreqs}{$_} ? qq("$_~>=$reqs->{modreqs}{$_}") : $_ }
636 sort { lc($a) cmp lc($b) } keys %$modreq_errors
31c31b8d 637 ;
fb39747c 638}
639
3ca0dcf0 640sub die_unless_req_ok_for {
31c31b8d 641 if (my $err = shift->req_missing_for(@_) ) {
e3a7746c 642 die "Unable to continue due to missing requirements: $err\n";
31c31b8d 643 }
fb39747c 644}
645
3ca0dcf0 646
647
e3a7746c 648### Private functions
649
650# potentially shorten group desc
651sub __envvar_group_desc {
652 my @envs = @{$_[0]};
653
654 my (@res, $last_prefix);
655 while (my $ev = shift @envs) {
656 my ($pref, $sep, $suff) = split / ([\_\-]) (?= [^\_\-]+ \z )/x, $ev;
657
658 if ( defined $sep and ($last_prefix||'') eq $pref ) {
659 push @res, "...${sep}${suff}"
660 }
661 else {
662 push @res, $ev;
663 }
664
665 $last_prefix = $pref if $sep;
666 }
667
668 join '/', @res;
669}
670
671
672
79b1bf0a 673### Private OO API
31c31b8d 674our %req_unavailability_cache;
675
e3a7746c 676# this method is just a lister and envvar/metadata checker - it does not try to load anything
e163f484 677my $processed_groups = {};
31c31b8d 678sub _groups_to_reqs {
679 my ($self, $groups) = @_;
680
681 $groups = [ $groups || () ]
682 unless ref $groups eq 'ARRAY';
683
684 croak "@{[ (caller(1))[3] ]}() expects a requirement group name or arrayref of group names"
685 unless @$groups;
686
687 my $ret = {
688 modreqs => {},
689 modreqs_fully_documented => 1,
690 };
3ca0dcf0 691
e163f484 692 for my $group ( grep { ! $processed_groups->{$_} } @$groups ) {
d8799bab 693
31c31b8d 694 $group =~ /\A [A-Za-z][0-9A-Z_a-z]* \z/x
695 or croak "Invalid requirement group name '$group': only ascii alphanumerics and _ are allowed";
d8799bab 696
e163f484 697 croak "Requirement group '$group' is not defined" unless defined $dbic_reqs->{$group};
698
699 my $group_reqs = $dbic_reqs->{$group}{req};
d8799bab 700
31c31b8d 701 # sanity-check
702 for (keys %$group_reqs) {
d8799bab 703
31c31b8d 704 $_ =~ /\A [A-Z_a-z][0-9A-Z_a-z]* (?:::[0-9A-Z_a-z]+)* \z /x
705 or croak "Requirement '$_' in group '$group' is not a valid module name";
706
707 # !!!DO NOT CHANGE!!!
708 # remember - version.pm may not be available on the system
709 croak "Requirement '$_' in group '$group' specifies an invalid version '$group_reqs->{$_}' (only plain non-underscored floating point decimals are supported)"
710 if ( ($group_reqs->{$_}||0) !~ / \A [0-9]+ (?: \. [0-9]+ )? \z /x );
d8799bab 711 }
712
e3a7746c 713 # check if we have all required envvars if such names are defined
714 my ($some_envs_required, $some_envs_missing);
715 if (my @e = @{$dbic_reqs->{$group}{env} || [] }) {
716
717 croak "Unexpected 'env' attribute under group '$group' (only allowed in test_* groups)"
718 unless $group =~ /^test_/;
719
720 croak "Unexpected *odd* list in 'env' under group '$group'"
721 if @e % 2;
722
723 my @group_envnames_list;
724
725 # deconstruct the whole thing
726 while (@e) {
727 push @group_envnames_list, my $envname = shift @e;
728
729 # env required or not
730 next unless shift @e;
731
732 $some_envs_required ||= 1;
733
734 $some_envs_missing ||= (
735 ! defined $ENV{$envname}
736 or
737 ! length $ENV{$envname}
738 );
739 }
740
741 croak "None of the envvars in group '$group' declared as required, making the requirement moot"
742 unless $some_envs_required;
743
744 push @{$ret->{missing_envvars}}, \@group_envnames_list if $some_envs_missing;
745 }
746
e163f484 747 # get the reqs for includes if any
748 my $inc_reqs;
749 if (my $incs = $dbic_reqs->{$group}{include}) {
750 $incs = [ $incs ] unless ref $incs eq 'ARRAY';
751
752 croak "Malformed 'include' for group '$group': must be another existing group name or arrayref of existing group names"
753 unless @$incs;
754
755 local $processed_groups->{$group} = 1;
756
757 my $subreqs = $self->_groups_to_reqs($incs);
758
759 croak "Includes with variable effective_modreqs not yet supported"
760 if $subreqs->{effective_modreqs_differ};
761
762 $inc_reqs = $subreqs->{modreqs};
763
764 }
765
31c31b8d 766 # assemble into the final ret
e3a7746c 767 for my $type (
768 'modreqs',
769 $some_envs_missing ? () : 'effective_modreqs'
770 ) {
e163f484 771 for my $req_bag ($group_reqs, $inc_reqs||()) {
772 for my $mod (keys %$req_bag) {
31c31b8d 773
e163f484 774 $ret->{$type}{$mod} = $req_bag->{$mod}||0 if (
31c31b8d 775
e163f484 776 ! exists $ret->{$type}{$mod}
777 or
778 # we sanitized the version to be numeric above - we can just -gt it
779 ($req_bag->{$mod}||0) > $ret->{$type}{$mod}
fb39747c 780
e163f484 781 );
782 }
e3a7746c 783 }
fb39747c 784 }
31c31b8d 785
e163f484 786 $ret->{effective_modreqs_differ} ||= !!$some_envs_missing;
787
31c31b8d 788 $ret->{modreqs_fully_documented} &&= !!$dbic_reqs->{$group}{pod};
789 }
790
791 return $ret;
792}
793
794
795# this method tries to load specified modreqs and returns a hashref of
796# module/loaderror pairs for anything that failed
797sub _errorlist_for_modreqs {
798 # args supposedly already went through _groups_to_reqs and are therefore sanitized
799 # safe to eval at will
800 my ($self, $reqs) = @_;
801
802 my $ret;
803
804 for my $m ( keys %$reqs ) {
805 my $v = $reqs->{$m};
806
807 if (! exists $req_unavailability_cache{$m}{$v} ) {
808 local $@;
809 eval( "require $m;" . ( $v ? "$m->VERSION(q($v))" : '' ) );
810 $req_unavailability_cache{$m}{$v} = $@;
fb39747c 811 }
812
31c31b8d 813 $ret->{$m} = $req_unavailability_cache{$m}{$v}
814 if $req_unavailability_cache{$m}{$v};
815 }
816
817 $ret;
fb39747c 818}
819
31c31b8d 820
e3fc11e1 821# This is to be called by the author only (automatically in Makefile.PL)
f6b26571 822sub _gen_pod {
47589465 823 my ($class, $distver, $pod_dir) = @_;
31fa1764 824
47589465 825 die "No POD root dir supplied" unless $pod_dir;
31fa1764 826
ccebe1f1 827 $distver ||=
31fa1764 828 eval { require DBIx::Class; DBIx::Class->VERSION; }
829 ||
ccebe1f1 830 die
31fa1764 831"\n\n---------------------------------------------------------------------\n" .
832'Unable to load core DBIx::Class module to determine current version, '.
833'possibly due to missing dependencies. Author-mode autodocumentation ' .
834"halted\n\n" . $@ .
835"\n\n---------------------------------------------------------------------\n"
31fa1764 836 ;
837
3d4c5a84 838 # do not ask for a recent version, use 1.x API calls
47589465 839 # this *may* execute on a smoker with old perl or whatnot
840 require File::Path;
841
842 (my $modfn = __PACKAGE__ . '.pm') =~ s|::|/|g;
843
844 (my $podfn = "$pod_dir/$modfn") =~ s/\.pm$/\.pod/;
845 (my $dir = $podfn) =~ s|/[^/]+$||;
846
847 File::Path::mkpath([$dir]);
848
31c31b8d 849 my $sqltver = $class->req_list_for('deploy')->{'SQL::Translator'}
e3fc11e1 850 or die "Hrmm? No sqlt dep?";
7e3dc46f 851
3ca0dcf0 852
853 my @chunks;
854
855#@@
856#@@ HEADER
857#@@
79b1bf0a 858 push @chunks, <<"EOC";
af4ac504 859#########################################################################
860##################### A U T O G E N E R A T E D ########################
861#########################################################################
862#
863# The contents of this POD file are auto-generated. Any changes you make
864# will be lost. If you need to change the generated text edit _gen_pod()
865# at the end of $modfn
866#
79b1bf0a 867
868=head1 NAME
869
870$class - Optional module dependency specifications (for module authors)
af4ac504 871EOC
3ca0dcf0 872
873
874#@@
875#@@ SYNOPSIS HEADING
876#@@
79b1bf0a 877 push @chunks, <<"EOC";
878=head1 SYNOPSIS
879
880Somewhere in your build-file (e.g. L<ExtUtils::MakeMaker>'s F<Makefile.PL>):
7e3dc46f 881
882 ...
883
79b1bf0a 884 \$EUMM_ARGS{CONFIGURE_REQUIRES} = {
885 \%{ \$EUMM_ARGS{CONFIGURE_REQUIRES} || {} },
886 'DBIx::Class' => '$distver',
887 };
7e3dc46f 888
79b1bf0a 889 ...
7e3dc46f 890
79b1bf0a 891 my %DBIC_DEPLOY_DEPS = %{ eval {
892 require $class;
893 $class->req_list_for('deploy');
894 } || {} };
7e3dc46f 895
79b1bf0a 896 \$EUMM_ARGS{PREREQ_PM} = {
897 \%DBIC_DEPLOY_DEPS,
898 \%{ \$EUMM_ARGS{PREREQ_PM} || {} },
899 };
7e3dc46f 900
901 ...
902
79b1bf0a 903 ExtUtils::MakeMaker::WriteMakefile(\%EUMM_ARGS);
904
905B<Note>: The C<eval> protection within the example is due to support for
906requirements during L<the C<configure> build phase|CPAN::Meta::Spec/Phases>
907not being available on a sufficient portion of production installations of
908Perl. Robust support for such dependency requirements is available in the
909L<CPAN> installer only since version C<1.94_56> first made available for
910production with perl version C<5.12>. It is the belief of the current
911maintainer that support for requirements during the C<configure> build phase
912will not be sufficiently ubiquitous until the B<year 2020> at the earliest,
913hence the extra care demonstrated above. It should also be noted that some
9143rd party installers (e.g. L<cpanminus|App::cpanminus>) do the right thing
915with configure requirements independent from the versions of perl and CPAN
916available.
917EOC
3ca0dcf0 918
919
920#@@
921#@@ DESCRIPTION HEADING
922#@@
79b1bf0a 923 push @chunks, <<'EOC';
924=head1 DESCRIPTION
925
f6b26571 926Some of the less-frequently used features of L<DBIx::Class> have external
927module dependencies on their own. In order not to burden the average user
79b1bf0a 928with modules they will never use, these optional dependencies are not included
f6b26571 929in the base Makefile.PL. Instead an exception with a descriptive message is
79b1bf0a 930thrown when a specific feature can't find one or several modules required for
931its operation. This module is the central holding place for the current list
7e3dc46f 932of such dependencies, for DBIx::Class core authors, and DBIx::Class extension
933authors alike.
79b1bf0a 934
935Dependencies are organized in L<groups|/CURRENT REQUIREMENT GROUPS> where each
936group can list one or more required modules, with an optional minimum version
e3a7746c 937(or 0 for any version). In addition groups prefixed with C<test_> can specify
938a set of environment variables, some (or all) of which are marked as required
939for the group to be considered by L</req_list_for>
940
941Each group name (or a combination thereof) can be used in the
942L<public methods|/METHODS> as described below.
79b1bf0a 943EOC
3ca0dcf0 944
945
946#@@
947#@@ REQUIREMENT GROUPLIST HEADING
948#@@
79b1bf0a 949 push @chunks, '=head1 CURRENT REQUIREMENT GROUPS';
f6b26571 950
31c31b8d 951 for my $group (sort keys %$dbic_reqs) {
952 my $p = $dbic_reqs->{$group}{pod}
f6b26571 953 or next;
954
e163f484 955 my $modlist = $class->modreq_list_for($group);
f6b26571 956
957 next unless keys %$modlist;
958
959 push @chunks, (
960 "=head2 $p->{title}",
961 "$p->{desc}",
962 '=over',
963 ( map { "=item * $_" . ($modlist->{$_} ? " >= $modlist->{$_}" : '') } (sort keys %$modlist) ),
964 '=back',
965 "Requirement group: B<$group>",
966 );
967 }
968
3ca0dcf0 969
970#@@
971#@@ API DOCUMENTATION HEADING
972#@@
79b1bf0a 973 push @chunks, <<'EOC';
974
975=head1 METHODS
976
977=head2 req_group_list
978
979=over
980
981=item Arguments: none
982
983=item Return Value: \%list_of_requirement_groups
984
985=back
986
e3fc11e1 987This method should be used by DBIx::Class packagers, to get a hashref of all
31c31b8d 988dependencies B<keyed> by dependency group. Each key (group name), or a combination
989thereof (as an arrayref) can be supplied to the methods below.
79b1bf0a 990The B<values> of the returned hash are currently a set of options B<without a
991well defined structure>. If you have use for any of the contents - contact the
992maintainers, instead of treating this as public (left alone stable) API.
993
994=head2 req_list_for
995
996=over
997
31c31b8d 998=item Arguments: $group_name | \@group_names
79b1bf0a 999
31c31b8d 1000=item Return Value: \%set_of_module_version_pairs
79b1bf0a 1001
1002=back
1003
f6b26571 1004This method should be used by DBIx::Class extension authors, to determine the
31c31b8d 1005version of modules a specific set of features requires for this version of
e3a7746c 1006DBIx::Class (regardless of their availability on the system).
1007See the L</SYNOPSIS> for a real-world example.
1008
1009When handling C<test_*> groups this method behaves B<differently> from
1010L</modreq_list_for> below (and is the only such inconsistency among the
1011C<req_*> methods). If a particular group declares as requirements some
1012C<environment variables> and these requirements are not satisfied (the envvars
1013are unset) - then the C<module requirements> of this group are not included in
1014the returned list.
1015
1016=head2 modreq_list_for
1017
1018=over
1019
1020=item Arguments: $group_name | \@group_names
1021
1022=item Return Value: \%set_of_module_version_pairs
1023
1024=back
1025
1026Same as L</req_list_for> but does not take into consideration any
1027C<environment variable requirements> - returns just the list of required
1028modules.
79b1bf0a 1029
1030=head2 req_ok_for
1031
1032=over
1033
31c31b8d 1034=item Arguments: $group_name | \@group_names
79b1bf0a 1035
1036=item Return Value: 1|0
1037
1038=back
1039
e3a7746c 1040Returns true or false depending on whether all modules/envvars required by
1041the group(s) are loadable/set on the system.
79b1bf0a 1042
1043=head2 req_missing_for
1044
1045=over
1046
31c31b8d 1047=item Arguments: $group_name | \@group_names
79b1bf0a 1048
1049=item Return Value: $error_message_string
1050
1051=back
1052
31c31b8d 1053Returns a single-line string suitable for inclusion in larger error messages.
e3a7746c 1054This method would normally be used by DBIx::Class core features, to indicate to
1055the user that they need to install specific modules and/or set specific
1056environment variables before being able to use a specific feature set.
f6b26571 1057
e3fc11e1 1058For example if some of the requirements for C<deploy> are not available,
1059the returned string could look like:
79b1bf0a 1060EOC
f6b26571 1061
79b1bf0a 1062 push @chunks, qq{ "SQL::Translator~>=$sqltver" (see $class documentation for details)};
f6b26571 1063
79b1bf0a 1064 push @chunks, <<'EOC';
f6b26571 1065The author is expected to prepend the necessary text to this message before
e3a7746c 1066returning the actual error seen by the user. See also L</modreq_missing_for>
1067
1068=head2 modreq_missing_for
f6b26571 1069
e3a7746c 1070=over
1071
1072=item Arguments: $group_name | \@group_names
1073
1074=item Return Value: $error_message_string
1075
1076=back
1077
1078Same as L</req_missing_for> except that the error string is guaranteed to be
1079either empty, or contain a set of module requirement specifications suitable
1080for piping to e.g. L<cpanminus|App::cpanminus>. The method explicitly does not
1081attempt to validate the state of required environment variables (if any).
1082
1083For instance if some of the requirements for C<deploy> are not available,
1084the returned string could look like:
1085EOC
1086
1087 push @chunks, qq{ "SQL::Translator~>=$sqltver"};
1088
1089 push @chunks, <<'EOC';
79b1bf0a 1090=head2 die_unless_req_ok_for
1091
1092=over
1093
31c31b8d 1094=item Arguments: $group_name | \@group_names
79b1bf0a 1095
1096=back
1097
31c31b8d 1098Checks if L</req_ok_for> passes for the supplied group(s), and
344f1f52 1099in case of failure throws an exception including the information
1100from L</req_missing_for>.
79b1bf0a 1101
5ffa39c7 1102=head2 modreq_errorlist_for
79b1bf0a 1103
1104=over
1105
31c31b8d 1106=item Arguments: $group_name | \@group_names
79b1bf0a 1107
31c31b8d 1108=item Return Value: \%set_of_loaderrors_per_module
79b1bf0a 1109
1110=back
1111
4a0eed52 1112Returns a hashref containing the actual errors that occurred while attempting
31c31b8d 1113to load each module in the requirement group(s).
5ffa39c7 1114
1115=head2 req_errorlist_for
1116
1117Deprecated method name, equivalent (via proxy) to L</modreq_errorlist_for>.
1118
79b1bf0a 1119EOC
3ca0dcf0 1120
1121#@@
1122#@@ FOOTER
1123#@@
79b1bf0a 1124 push @chunks, <<'EOC';
1125=head1 FURTHER QUESTIONS?
1126
1127Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
1128
1129=head1 COPYRIGHT AND LICENSE
1130
a2bd3796 1131This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
1132by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
1133redistribute it and/or modify it under the same terms as the
1134L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.
79b1bf0a 1135EOC
3ca0dcf0 1136
3f5e367a 1137 eval {
1138 open (my $fh, '>', $podfn) or die;
1139 print $fh join ("\n\n", @chunks) or die;
1140 print $fh "\n" or die;
1141 close ($fh) or die;
1142 } or croak( "Unable to write $podfn: " . ( $! || $@ || 'unknown error') );
f6b26571 1143}
1144
8057ed01 11451;