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