Add import-time action stub to OptDeps, switch distbuild checks to it
[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
afb8fc52 571sub import {
572 my $class = shift;
573
574 if (@_) {
575
576 my $action = shift;
577
578 if ($action eq '-die_without') {
579 my $err;
580 {
581 local $@;
582 eval { $class->die_unless_req_ok_for(\@_); 1 }
583 or $err = $@;
584 }
585 die "\n$err\n" if $err;
586 }
587 elsif ($action eq '-list_missing') {
588 print $class->modreq_missing_for(\@_);
589 print "\n";
590 exit 0;
591 }
592 elsif ($action =~ /^-/) {
593 croak "Unknown import-time action '$action'";
594 }
595 else {
596 croak "$class is not an exporter, unable to import '$action'";
597 }
598 }
599
600 1;
601}
602
603sub unimport {
604 croak( __PACKAGE__ . " does not implement unimport" );
605}
606
3ca0dcf0 607# OO for (mistakenly considered) ease of extensibility, not due to any need to
608# carry state of any sort. This API is currently used outside, so leave as-is.
609# FIXME - make sure to not propagate this further if module is extracted as a
610# standalone library - keep the stupidity to a DBIC-secific shim!
611#
fb39747c 612sub req_list_for {
e3a7746c 613 shift->_groups_to_reqs(@_)->{effective_modreqs};
614}
615
616sub modreq_list_for {
31c31b8d 617 shift->_groups_to_reqs(@_)->{modreqs};
fb39747c 618}
619
3ca0dcf0 620sub req_group_list {
31c31b8d 621 +{ map
622 { $_ => $_[0]->_groups_to_reqs($_) }
623 keys %$dbic_reqs
624 }
3ca0dcf0 625}
fb39747c 626
5ffa39c7 627sub req_errorlist_for { shift->modreq_errorlist_for(@_) } # deprecated
628sub modreq_errorlist_for {
31c31b8d 629 my $self = shift;
630 $self->_errorlist_for_modreqs( $self->_groups_to_reqs(@_)->{modreqs} );
344f1f52 631}
632
fb39747c 633sub req_ok_for {
e3a7746c 634 shift->req_missing_for(@_) ? 0 : 1;
635}
636
637sub req_missing_for {
31c31b8d 638 my $self = shift;
e3a7746c 639
640 my $reqs = $self->_groups_to_reqs(@_);
641 my $mods_missing = $self->modreq_missing_for(@_);
642
643 return '' if
644 ! $mods_missing
645 and
646 ! $reqs->{missing_envvars}
31c31b8d 647 ;
e3a7746c 648
649 my @res = $mods_missing || ();
650
651 push @res, 'the following group(s) of environment variables: ' . join ' and ', map
652 { __envvar_group_desc($_) }
653 @{$reqs->{missing_envvars}}
654 if $reqs->{missing_envvars};
655
656 return (
657 ( join ' as well as ', @res )
658 .
659 ( $reqs->{modreqs_fully_documented} ? " (see @{[ ref $self || $self ]} documentation for details)" : '' ),
660 );
fb39747c 661}
662
e3a7746c 663sub modreq_missing_for {
31c31b8d 664 my $self = shift;
fb39747c 665
31c31b8d 666 my $reqs = $self->_groups_to_reqs(@_);
e3a7746c 667 my $modreq_errors = $self->_errorlist_for_modreqs($reqs->{modreqs})
668 or return '';
fb39747c 669
e3a7746c 670 join ' ', map
671 { $reqs->{modreqs}{$_} ? qq("$_~>=$reqs->{modreqs}{$_}") : $_ }
672 sort { lc($a) cmp lc($b) } keys %$modreq_errors
31c31b8d 673 ;
fb39747c 674}
675
3ca0dcf0 676sub die_unless_req_ok_for {
31c31b8d 677 if (my $err = shift->req_missing_for(@_) ) {
e3a7746c 678 die "Unable to continue due to missing requirements: $err\n";
31c31b8d 679 }
fb39747c 680}
681
3ca0dcf0 682
683
e3a7746c 684### Private functions
685
686# potentially shorten group desc
687sub __envvar_group_desc {
688 my @envs = @{$_[0]};
689
690 my (@res, $last_prefix);
691 while (my $ev = shift @envs) {
692 my ($pref, $sep, $suff) = split / ([\_\-]) (?= [^\_\-]+ \z )/x, $ev;
693
694 if ( defined $sep and ($last_prefix||'') eq $pref ) {
695 push @res, "...${sep}${suff}"
696 }
697 else {
698 push @res, $ev;
699 }
700
701 $last_prefix = $pref if $sep;
702 }
703
704 join '/', @res;
705}
706
707
708
79b1bf0a 709### Private OO API
31c31b8d 710our %req_unavailability_cache;
711
e3a7746c 712# this method is just a lister and envvar/metadata checker - it does not try to load anything
e163f484 713my $processed_groups = {};
31c31b8d 714sub _groups_to_reqs {
715 my ($self, $groups) = @_;
716
717 $groups = [ $groups || () ]
718 unless ref $groups eq 'ARRAY';
719
720 croak "@{[ (caller(1))[3] ]}() expects a requirement group name or arrayref of group names"
721 unless @$groups;
722
723 my $ret = {
724 modreqs => {},
725 modreqs_fully_documented => 1,
726 };
3ca0dcf0 727
e163f484 728 for my $group ( grep { ! $processed_groups->{$_} } @$groups ) {
d8799bab 729
31c31b8d 730 $group =~ /\A [A-Za-z][0-9A-Z_a-z]* \z/x
731 or croak "Invalid requirement group name '$group': only ascii alphanumerics and _ are allowed";
d8799bab 732
e163f484 733 croak "Requirement group '$group' is not defined" unless defined $dbic_reqs->{$group};
734
735 my $group_reqs = $dbic_reqs->{$group}{req};
d8799bab 736
31c31b8d 737 # sanity-check
738 for (keys %$group_reqs) {
d8799bab 739
31c31b8d 740 $_ =~ /\A [A-Z_a-z][0-9A-Z_a-z]* (?:::[0-9A-Z_a-z]+)* \z /x
741 or croak "Requirement '$_' in group '$group' is not a valid module name";
742
743 # !!!DO NOT CHANGE!!!
744 # remember - version.pm may not be available on the system
745 croak "Requirement '$_' in group '$group' specifies an invalid version '$group_reqs->{$_}' (only plain non-underscored floating point decimals are supported)"
746 if ( ($group_reqs->{$_}||0) !~ / \A [0-9]+ (?: \. [0-9]+ )? \z /x );
d8799bab 747 }
748
e3a7746c 749 # check if we have all required envvars if such names are defined
750 my ($some_envs_required, $some_envs_missing);
751 if (my @e = @{$dbic_reqs->{$group}{env} || [] }) {
752
753 croak "Unexpected 'env' attribute under group '$group' (only allowed in test_* groups)"
754 unless $group =~ /^test_/;
755
756 croak "Unexpected *odd* list in 'env' under group '$group'"
757 if @e % 2;
758
759 my @group_envnames_list;
760
761 # deconstruct the whole thing
762 while (@e) {
763 push @group_envnames_list, my $envname = shift @e;
764
765 # env required or not
766 next unless shift @e;
767
768 $some_envs_required ||= 1;
769
770 $some_envs_missing ||= (
771 ! defined $ENV{$envname}
772 or
773 ! length $ENV{$envname}
774 );
775 }
776
777 croak "None of the envvars in group '$group' declared as required, making the requirement moot"
778 unless $some_envs_required;
779
780 push @{$ret->{missing_envvars}}, \@group_envnames_list if $some_envs_missing;
781 }
782
e163f484 783 # get the reqs for includes if any
784 my $inc_reqs;
785 if (my $incs = $dbic_reqs->{$group}{include}) {
786 $incs = [ $incs ] unless ref $incs eq 'ARRAY';
787
788 croak "Malformed 'include' for group '$group': must be another existing group name or arrayref of existing group names"
789 unless @$incs;
790
791 local $processed_groups->{$group} = 1;
792
793 my $subreqs = $self->_groups_to_reqs($incs);
794
795 croak "Includes with variable effective_modreqs not yet supported"
796 if $subreqs->{effective_modreqs_differ};
797
798 $inc_reqs = $subreqs->{modreqs};
799
800 }
801
31c31b8d 802 # assemble into the final ret
e3a7746c 803 for my $type (
804 'modreqs',
805 $some_envs_missing ? () : 'effective_modreqs'
806 ) {
e163f484 807 for my $req_bag ($group_reqs, $inc_reqs||()) {
808 for my $mod (keys %$req_bag) {
31c31b8d 809
e163f484 810 $ret->{$type}{$mod} = $req_bag->{$mod}||0 if (
31c31b8d 811
e163f484 812 ! exists $ret->{$type}{$mod}
813 or
814 # we sanitized the version to be numeric above - we can just -gt it
815 ($req_bag->{$mod}||0) > $ret->{$type}{$mod}
fb39747c 816
e163f484 817 );
818 }
e3a7746c 819 }
fb39747c 820 }
31c31b8d 821
e163f484 822 $ret->{effective_modreqs_differ} ||= !!$some_envs_missing;
823
31c31b8d 824 $ret->{modreqs_fully_documented} &&= !!$dbic_reqs->{$group}{pod};
825 }
826
827 return $ret;
828}
829
830
831# this method tries to load specified modreqs and returns a hashref of
832# module/loaderror pairs for anything that failed
833sub _errorlist_for_modreqs {
834 # args supposedly already went through _groups_to_reqs and are therefore sanitized
835 # safe to eval at will
836 my ($self, $reqs) = @_;
837
838 my $ret;
839
840 for my $m ( keys %$reqs ) {
841 my $v = $reqs->{$m};
842
843 if (! exists $req_unavailability_cache{$m}{$v} ) {
844 local $@;
845 eval( "require $m;" . ( $v ? "$m->VERSION(q($v))" : '' ) );
846 $req_unavailability_cache{$m}{$v} = $@;
fb39747c 847 }
848
31c31b8d 849 $ret->{$m} = $req_unavailability_cache{$m}{$v}
850 if $req_unavailability_cache{$m}{$v};
851 }
852
853 $ret;
fb39747c 854}
855
31c31b8d 856
e3fc11e1 857# This is to be called by the author only (automatically in Makefile.PL)
f6b26571 858sub _gen_pod {
47589465 859 my ($class, $distver, $pod_dir) = @_;
31fa1764 860
47589465 861 die "No POD root dir supplied" unless $pod_dir;
31fa1764 862
ccebe1f1 863 $distver ||=
31fa1764 864 eval { require DBIx::Class; DBIx::Class->VERSION; }
865 ||
ccebe1f1 866 die
31fa1764 867"\n\n---------------------------------------------------------------------\n" .
868'Unable to load core DBIx::Class module to determine current version, '.
869'possibly due to missing dependencies. Author-mode autodocumentation ' .
870"halted\n\n" . $@ .
871"\n\n---------------------------------------------------------------------\n"
31fa1764 872 ;
873
3d4c5a84 874 # do not ask for a recent version, use 1.x API calls
47589465 875 # this *may* execute on a smoker with old perl or whatnot
876 require File::Path;
877
878 (my $modfn = __PACKAGE__ . '.pm') =~ s|::|/|g;
879
880 (my $podfn = "$pod_dir/$modfn") =~ s/\.pm$/\.pod/;
881 (my $dir = $podfn) =~ s|/[^/]+$||;
882
883 File::Path::mkpath([$dir]);
884
31c31b8d 885 my $sqltver = $class->req_list_for('deploy')->{'SQL::Translator'}
e3fc11e1 886 or die "Hrmm? No sqlt dep?";
7e3dc46f 887
3ca0dcf0 888
889 my @chunks;
890
891#@@
892#@@ HEADER
893#@@
79b1bf0a 894 push @chunks, <<"EOC";
af4ac504 895#########################################################################
896##################### A U T O G E N E R A T E D ########################
897#########################################################################
898#
899# The contents of this POD file are auto-generated. Any changes you make
900# will be lost. If you need to change the generated text edit _gen_pod()
901# at the end of $modfn
902#
79b1bf0a 903
904=head1 NAME
905
906$class - Optional module dependency specifications (for module authors)
af4ac504 907EOC
3ca0dcf0 908
909
910#@@
911#@@ SYNOPSIS HEADING
912#@@
79b1bf0a 913 push @chunks, <<"EOC";
914=head1 SYNOPSIS
915
916Somewhere in your build-file (e.g. L<ExtUtils::MakeMaker>'s F<Makefile.PL>):
7e3dc46f 917
918 ...
919
79b1bf0a 920 \$EUMM_ARGS{CONFIGURE_REQUIRES} = {
921 \%{ \$EUMM_ARGS{CONFIGURE_REQUIRES} || {} },
922 'DBIx::Class' => '$distver',
923 };
7e3dc46f 924
79b1bf0a 925 ...
7e3dc46f 926
79b1bf0a 927 my %DBIC_DEPLOY_DEPS = %{ eval {
928 require $class;
929 $class->req_list_for('deploy');
930 } || {} };
7e3dc46f 931
79b1bf0a 932 \$EUMM_ARGS{PREREQ_PM} = {
933 \%DBIC_DEPLOY_DEPS,
934 \%{ \$EUMM_ARGS{PREREQ_PM} || {} },
935 };
7e3dc46f 936
937 ...
938
79b1bf0a 939 ExtUtils::MakeMaker::WriteMakefile(\%EUMM_ARGS);
940
941B<Note>: The C<eval> protection within the example is due to support for
942requirements during L<the C<configure> build phase|CPAN::Meta::Spec/Phases>
943not being available on a sufficient portion of production installations of
944Perl. Robust support for such dependency requirements is available in the
945L<CPAN> installer only since version C<1.94_56> first made available for
946production with perl version C<5.12>. It is the belief of the current
947maintainer that support for requirements during the C<configure> build phase
948will not be sufficiently ubiquitous until the B<year 2020> at the earliest,
949hence the extra care demonstrated above. It should also be noted that some
9503rd party installers (e.g. L<cpanminus|App::cpanminus>) do the right thing
951with configure requirements independent from the versions of perl and CPAN
952available.
953EOC
3ca0dcf0 954
955
956#@@
957#@@ DESCRIPTION HEADING
958#@@
79b1bf0a 959 push @chunks, <<'EOC';
960=head1 DESCRIPTION
961
f6b26571 962Some of the less-frequently used features of L<DBIx::Class> have external
963module dependencies on their own. In order not to burden the average user
79b1bf0a 964with modules they will never use, these optional dependencies are not included
f6b26571 965in the base Makefile.PL. Instead an exception with a descriptive message is
79b1bf0a 966thrown when a specific feature can't find one or several modules required for
967its operation. This module is the central holding place for the current list
7e3dc46f 968of such dependencies, for DBIx::Class core authors, and DBIx::Class extension
969authors alike.
79b1bf0a 970
971Dependencies are organized in L<groups|/CURRENT REQUIREMENT GROUPS> where each
972group can list one or more required modules, with an optional minimum version
e3a7746c 973(or 0 for any version). In addition groups prefixed with C<test_> can specify
974a set of environment variables, some (or all) of which are marked as required
975for the group to be considered by L</req_list_for>
976
977Each group name (or a combination thereof) can be used in the
978L<public methods|/METHODS> as described below.
79b1bf0a 979EOC
3ca0dcf0 980
981
982#@@
983#@@ REQUIREMENT GROUPLIST HEADING
984#@@
79b1bf0a 985 push @chunks, '=head1 CURRENT REQUIREMENT GROUPS';
f6b26571 986
31c31b8d 987 for my $group (sort keys %$dbic_reqs) {
988 my $p = $dbic_reqs->{$group}{pod}
f6b26571 989 or next;
990
e163f484 991 my $modlist = $class->modreq_list_for($group);
f6b26571 992
993 next unless keys %$modlist;
994
995 push @chunks, (
996 "=head2 $p->{title}",
997 "$p->{desc}",
998 '=over',
999 ( map { "=item * $_" . ($modlist->{$_} ? " >= $modlist->{$_}" : '') } (sort keys %$modlist) ),
1000 '=back',
1001 "Requirement group: B<$group>",
1002 );
1003 }
1004
3ca0dcf0 1005
1006#@@
1007#@@ API DOCUMENTATION HEADING
1008#@@
79b1bf0a 1009 push @chunks, <<'EOC';
1010
afb8fc52 1011=head1 IMPORT-LIKE ACTIONS
1012
1013Even though this module is not an L<Exporter>, it recognizes several C<actions>
1014supplied to its C<import> method.
1015
1016=head2 -die_without
1017
1018=over
1019
1020=item Arguments: @group_names
1021
1022=back
1023
1024A convenience wrapper around L</die_unless_req_ok_for>:
1025EOC
1026
1027 push @chunks, " use $class -die_without => qw(deploy admin);";
1028
1029 push @chunks, <<'EOC';
1030
1031=head2 -list_missing
1032
1033=over
1034
1035=item Arguments: @group_names
1036
1037=back
1038
1039A convenience wrapper around L</modreq_missing_for>:
1040
1041 perl -Ilib -MDBIx::Class::Optional::Dependencies=-list_missing,deploy,admin | cpanm
1042
79b1bf0a 1043=head1 METHODS
1044
1045=head2 req_group_list
1046
1047=over
1048
1049=item Arguments: none
1050
1051=item Return Value: \%list_of_requirement_groups
1052
1053=back
1054
e3fc11e1 1055This method should be used by DBIx::Class packagers, to get a hashref of all
31c31b8d 1056dependencies B<keyed> by dependency group. Each key (group name), or a combination
1057thereof (as an arrayref) can be supplied to the methods below.
79b1bf0a 1058The B<values> of the returned hash are currently a set of options B<without a
1059well defined structure>. If you have use for any of the contents - contact the
1060maintainers, instead of treating this as public (left alone stable) API.
1061
1062=head2 req_list_for
1063
1064=over
1065
31c31b8d 1066=item Arguments: $group_name | \@group_names
79b1bf0a 1067
31c31b8d 1068=item Return Value: \%set_of_module_version_pairs
79b1bf0a 1069
1070=back
1071
f6b26571 1072This method should be used by DBIx::Class extension authors, to determine the
31c31b8d 1073version of modules a specific set of features requires for this version of
e3a7746c 1074DBIx::Class (regardless of their availability on the system).
1075See the L</SYNOPSIS> for a real-world example.
1076
1077When handling C<test_*> groups this method behaves B<differently> from
1078L</modreq_list_for> below (and is the only such inconsistency among the
1079C<req_*> methods). If a particular group declares as requirements some
1080C<environment variables> and these requirements are not satisfied (the envvars
1081are unset) - then the C<module requirements> of this group are not included in
1082the returned list.
1083
1084=head2 modreq_list_for
1085
1086=over
1087
1088=item Arguments: $group_name | \@group_names
1089
1090=item Return Value: \%set_of_module_version_pairs
1091
1092=back
1093
1094Same as L</req_list_for> but does not take into consideration any
1095C<environment variable requirements> - returns just the list of required
1096modules.
79b1bf0a 1097
1098=head2 req_ok_for
1099
1100=over
1101
31c31b8d 1102=item Arguments: $group_name | \@group_names
79b1bf0a 1103
1104=item Return Value: 1|0
1105
1106=back
1107
e3a7746c 1108Returns true or false depending on whether all modules/envvars required by
1109the group(s) are loadable/set on the system.
79b1bf0a 1110
1111=head2 req_missing_for
1112
1113=over
1114
31c31b8d 1115=item Arguments: $group_name | \@group_names
79b1bf0a 1116
1117=item Return Value: $error_message_string
1118
1119=back
1120
31c31b8d 1121Returns a single-line string suitable for inclusion in larger error messages.
e3a7746c 1122This method would normally be used by DBIx::Class core features, to indicate to
1123the user that they need to install specific modules and/or set specific
1124environment variables before being able to use a specific feature set.
f6b26571 1125
e3fc11e1 1126For example if some of the requirements for C<deploy> are not available,
1127the returned string could look like:
79b1bf0a 1128EOC
f6b26571 1129
79b1bf0a 1130 push @chunks, qq{ "SQL::Translator~>=$sqltver" (see $class documentation for details)};
f6b26571 1131
79b1bf0a 1132 push @chunks, <<'EOC';
f6b26571 1133The author is expected to prepend the necessary text to this message before
e3a7746c 1134returning the actual error seen by the user. See also L</modreq_missing_for>
1135
1136=head2 modreq_missing_for
f6b26571 1137
e3a7746c 1138=over
1139
1140=item Arguments: $group_name | \@group_names
1141
1142=item Return Value: $error_message_string
1143
1144=back
1145
1146Same as L</req_missing_for> except that the error string is guaranteed to be
1147either empty, or contain a set of module requirement specifications suitable
1148for piping to e.g. L<cpanminus|App::cpanminus>. The method explicitly does not
1149attempt to validate the state of required environment variables (if any).
1150
1151For instance if some of the requirements for C<deploy> are not available,
1152the returned string could look like:
1153EOC
1154
1155 push @chunks, qq{ "SQL::Translator~>=$sqltver"};
1156
1157 push @chunks, <<'EOC';
afb8fc52 1158
1159See also L</-list_missing>.
1160
79b1bf0a 1161=head2 die_unless_req_ok_for
1162
1163=over
1164
31c31b8d 1165=item Arguments: $group_name | \@group_names
79b1bf0a 1166
1167=back
1168
31c31b8d 1169Checks if L</req_ok_for> passes for the supplied group(s), and
344f1f52 1170in case of failure throws an exception including the information
afb8fc52 1171from L</req_missing_for>. See also L</-die_without>.
79b1bf0a 1172
5ffa39c7 1173=head2 modreq_errorlist_for
79b1bf0a 1174
1175=over
1176
31c31b8d 1177=item Arguments: $group_name | \@group_names
79b1bf0a 1178
31c31b8d 1179=item Return Value: \%set_of_loaderrors_per_module
79b1bf0a 1180
1181=back
1182
4a0eed52 1183Returns a hashref containing the actual errors that occurred while attempting
31c31b8d 1184to load each module in the requirement group(s).
5ffa39c7 1185
1186=head2 req_errorlist_for
1187
1188Deprecated method name, equivalent (via proxy) to L</modreq_errorlist_for>.
1189
79b1bf0a 1190EOC
3ca0dcf0 1191
1192#@@
1193#@@ FOOTER
1194#@@
79b1bf0a 1195 push @chunks, <<'EOC';
1196=head1 FURTHER QUESTIONS?
1197
1198Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
1199
1200=head1 COPYRIGHT AND LICENSE
1201
a2bd3796 1202This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
1203by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
1204redistribute it and/or modify it under the same terms as the
1205L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.
79b1bf0a 1206EOC
3ca0dcf0 1207
3f5e367a 1208 eval {
1209 open (my $fh, '>', $podfn) or die;
1210 print $fh join ("\n\n", @chunks) or die;
1211 print $fh "\n" or die;
1212 close ($fh) or die;
1213 } or croak( "Unable to write $podfn: " . ( $! || $@ || 'unknown error') );
f6b26571 1214}
1215
8057ed01 12161;