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