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