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