File Coverage

blib/lib/DBIx/Class/Schema/Loader/Optional/Dependencies.pm
Criterion Covered Total %
statement 133 244 54.5
branch 78 174 44.8
condition 30 89 33.7
subroutine 10 20 50.0
pod 10 11 90.9
total 261 538 48.5


line stmt bran cond sub pod time code
1             package DBIx::Class::Schema::Loader::Optional::Dependencies;
2              
3             ### This may look crazy, but it in fact tangibly ( by 50(!)% ) shortens
4             # the skip-test time when everything requested is unavailable
5             BEGIN {
6 38 50   38   359217 if ( $ENV{RELEASE_TESTING} ) {
7 0 0       0 require warnings and warnings->import;
8 0 0       0 require strict and strict->import;
9             }
10             }
11              
12             sub croak {
13 0     0 0 0 require Carp;
14 0         0 Carp::croak(@_);
15             };
16             ###
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              
24             my $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 (without only_autoclean)',
36             },
37             },
38             use_moose_only_autoclean => {
39             req => {
40             'Moose' => '2.1400',
41             'MooseX::NonMoose' => '0.25',
42             'namespace::autoclean' => '0.09',
43             },
44             pod => {
45             title => 'use_moose_only_autoclean',
46             desc => 'Modules required for the use_moose + only_autoclean options',
47             },
48             },
49              
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,
248             },
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              
493             };
494              
495              
496              
497             ### Public API
498              
499             sub import {
500 18     18   219 my $class = shift;
501              
502 18 100       103 if (@_) {
503              
504 17         35 my $action = shift;
505              
506 17 50       101 if ($action eq '-die_without') {
    50          
    50          
    0          
507 0         0 my $err;
508             {
509 0         0 local $@;
  0         0  
510 0 0       0 eval { $class->die_unless_req_ok_for(\@_); 1 }
  0         0  
  0         0  
511             or $err = $@;
512             }
513 0 0       0 die "\n$err\n" if $err;
514             }
515             elsif ($action eq '-list_missing') {
516 0         0 print $class->modreq_missing_for(\@_);
517 0         0 print "\n";
518 0         0 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 17 50       41 do {
524 17         48 local $@;
525 17         50 defined eval {
526 17 0       354 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 17 50       76 if ( my $missing = $class->req_missing_for(\@_) ) {
533              
534             die ("\nMandatory requirements not satisfied during release-testing: $missing\n\n")
535 17 0 33     64 if $ENV{RELEASE_TESTING} and $class->_groups_to_reqs(\@_)->{release_testing_mandatory};
536              
537 17         148 print "1..0 # SKIP requirements not satisfied: $missing\n";
538 17         11485 exit 0;
539             }
540             }
541             elsif ($action =~ /^-/) {
542 0         0 croak "Unknown import-time action '$action'";
543             }
544             else {
545 0         0 croak "$class is not an exporter, unable to import '$action'";
546             }
547             }
548              
549 1         30 1;
550             }
551              
552             sub unimport {
553 0     0   0 croak( __PACKAGE__ . " does not implement unimport" );
554             }
555              
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             #
561             sub req_list_for {
562 0     0 1 0 shift->_groups_to_reqs(shift)->{effective_modreqs};
563             }
564              
565             sub modreq_list_for {
566 0     0 1 0 shift->_groups_to_reqs(shift)->{modreqs};
567             }
568              
569             sub req_group_list {
570             +{ map
571 0         0 { $_ => $_[0]->_groups_to_reqs($_) }
572 0     0 1 0 grep { $_ !~ /^_/ } keys %$dbic_reqs
  0         0  
573             }
574             }
575              
576 0     0 1 0 sub req_errorlist_for { shift->modreq_errorlist_for(shift) } # deprecated
577             sub modreq_errorlist_for {
578 0     0 1 0 my ($self, $groups) = @_;
579 0         0 $self->_errorlist_for_modreqs( $self->_groups_to_reqs($groups)->{modreqs} );
580             }
581              
582             sub req_ok_for {
583 1 50   1 1 123 shift->req_missing_for(shift) ? 0 : 1;
584             }
585              
586             sub req_missing_for {
587 18     18 1 102 my ($self, $groups) = @_;
588              
589 18         56 my $reqs = $self->_groups_to_reqs($groups);
590              
591             my $mods_missing = $reqs->{missing_envvars}
592             ? $self->_list_physically_missing_modules( $reqs->{modreqs} )
593 18 100       88 : $self->modreq_missing_for($groups)
594             ;
595              
596             return '' if
597             ! $mods_missing
598             and
599             ! $reqs->{missing_envvars}
600 18 50 66     131 ;
601              
602 18   66     69 my @res = $mods_missing || ();
603              
604             push @res, 'the following group(s) of environment variables: ' . join ' and ', sort map
605 19         48 { __envvar_group_desc($_) }
606 15         37 @{$reqs->{missing_envvars}}
607 18 100       60 if $reqs->{missing_envvars};
608              
609             return (
610             ( join ' as well as ', @res )
611             .
612 18 100 33     145 ( $reqs->{modreqs_fully_documented} ? " (see @{[ ref $self || $self ]} documentation for details)" : '' ),
  3         38  
613             );
614             }
615              
616             sub modreq_missing_for {
617 3     3 1 7 my ($self, $groups) = @_;
618              
619 3         19 my $reqs = $self->_groups_to_reqs($groups);
620             my $modreq_errors = $self->_errorlist_for_modreqs($reqs->{modreqs})
621 3 50       20 or return '';
622              
623             join ' ', map
624 9 100       53 { $reqs->{modreqs}{$_} ? "$_~$reqs->{modreqs}{$_}" : $_ }
625 3         23 sort { lc($a) cmp lc($b) } keys %$modreq_errors
  9         31  
626             ;
627             }
628              
629             my $tb;
630             sub skip_without {
631 0     0 1 0 my ($self, $groups) = @_;
632              
633 0 0 0     0 $tb ||= do { local $@; eval { Test::Builder->new } }
  0         0  
  0         0  
  0         0  
634             or croak "Calling skip_without() before loading Test::Builder makes no sense";
635              
636 0 0       0 if ( my $err = $self->req_missing_for($groups) ) {
637 0         0 my ($fn, $ln) = (caller(0))[1,2];
638 0         0 $tb->skip("block in $fn around line $ln requires $err");
639 0         0 local $^W = 0;
640 0         0 last SKIP;
641             }
642              
643 0         0 1;
644             }
645              
646             sub die_unless_req_ok_for {
647 0 0   0 1 0 if (my $err = shift->req_missing_for(shift) ) {
648 0         0 die "Unable to continue due to missing requirements: $err\n";
649             }
650             }
651              
652              
653              
654             ### Private functions
655              
656             # potentially shorten group desc
657             sub __envvar_group_desc {
658 19     19   33 my @envs = @{$_[0]};
  19         47  
659              
660 19         368 my (@res, $last_prefix);
661 19         62 while (my $ev = shift @envs) {
662 39         277 my ($pref, $sep, $suff) = split / ([\_\-]) (?= [^\_\-]+ \z )/x, $ev;
663              
664 39 100 100     219 if ( defined $sep and ($last_prefix||'') eq $pref ) {
      66        
665 20         53 push @res, "...${sep}${suff}"
666             }
667             else {
668 19         45 push @res, $ev;
669             }
670              
671 39 50       144 $last_prefix = $pref if $sep;
672             }
673              
674 19         124 join '/', @res;
675             }
676              
677             my $groupname_re = qr/ [a-z_] [0-9_a-z]* /x;
678             my $modname_re = qr/ [A-Z_a-z] [0-9A-Z_a-z]* (?:::[0-9A-Z_a-z]+)* /x;
679             my $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)
686             sub __expand_includes {
687 35     35   85 my ($groups, $seen) = @_;
688              
689             # !! DIFFERENT !! behavior and return depending on invocation mode
690             # (easier to recurse this way)
691 35 100       117 my $is_toplevel = $seen
692             ? 0
693             : !! ($seen = {})
694             ;
695              
696 35         69 my ($res_per_type, $missing_envvars);
697              
698             # breadth-first evaluation, with non-variable includes on top
699 35         72 for my $g (@$groups) {
700              
701 39 50       487 croak "Invalid requirement group name '$g': only ascii alphanumerics and _ are allowed"
702             if $g !~ qr/ \A $groupname_re \z/x;
703              
704 39 50       170 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 39 50 66     169 if ( $r->{env} and ! $is_toplevel );
710              
711 39 50       176 next if $seen->{$g}++;
712              
713 39         80 my $req_type = 'static';
714              
715 39 100       65 if ( my @e = @{$r->{env}||[]} ) {
  39 100       208  
716              
717 19 50       76 croak "Unexpected 'env' attribute under group '$g' (only allowed in test_* groups)"
718             unless $g =~ /^test_/;
719              
720 19 50       87 croak "Unexpected *odd* list in 'env' under group '$g'"
721             if @e % 2;
722              
723             # deconstruct the whole thing
724 19         40 my (@group_envnames_list, $some_envs_required, $some_required_missing);
725 19         47 while (@e) {
726 39         85 push @group_envnames_list, my $envname = shift @e;
727              
728             # env required or not
729 39 100       107 next unless shift @e;
730              
731 19   50     99 $some_envs_required ||= 1;
732              
733             $some_required_missing ||= (
734             ! defined $ENV{$envname}
735             or
736 19   33     138 ! length $ENV{$envname}
      33        
737             );
738             }
739              
740 19 50       52 croak "None of the envvars in group '$g' declared as required, making the requirement moot"
741             unless $some_envs_required;
742              
743 19 50       43 if ($some_required_missing) {
744 19         31 push @{$missing_envvars->{$g}}, \@group_envnames_list;
  19         67  
745 19         60 $req_type = 'variable';
746             }
747             }
748              
749 39         73 push @{$res_per_type->{"base_${req_type}"}}, $g;
  39         136  
750              
751 39 100       146 if (my $i = $dbic_reqs->{$g}{include}) {
752 14 50       50 $i = [ $i ] unless ref $i eq 'ARRAY';
753              
754 14 50       37 croak "Malformed 'include' for group '$g': must be another existing group name or arrayref of existing group names"
755             unless @$i;
756              
757 14         36 push @{$res_per_type->{"incs_${req_type}"}}, @$i;
  14         63  
758             }
759             }
760              
761             my @ret = map {
762 35 100       85 @{ $res_per_type->{"base_${_}"} || [] },
  70         499  
763 70 100       110 ( $res_per_type->{"incs_${_}"} ? __expand_includes( $res_per_type->{"incs_${_}"}, $seen ) : () ),
764             } qw(static variable);
765              
766 35 100       148 return ! $is_toplevel ? @ret : do {
767 21         50 my $rv = {};
768             $rv->{$_} = {
769             idx => 1 + keys %$rv,
770             missing_envvars => $missing_envvars->{$_},
771 21         150 } for @ret;
772 21         147 $rv->{$_}{user_requested} = 1 for @$groups;
773 21         96 $rv;
774             };
775             }
776              
777             ### Private OO API
778             our %req_unavailability_cache;
779              
780             # this method is just a lister and envvar/metadata checker - it does not try to load anything
781             sub _groups_to_reqs {
782 21     21   50 my ($self, $want) = @_;
783              
784 21 100 33     97 $want = [ $want || () ]
785             unless ref $want eq 'ARRAY';
786              
787 21 50       61 croak "@{[ (caller(1))[3] ]}() expects a requirement group name or arrayref of group names"
  0         0  
788             unless @$want;
789              
790 21         67 my $ret = {
791             modreqs => {},
792             modreqs_fully_documented => 1,
793             };
794              
795 21         39 my $groups;
796 21         63 for my $piece (@$want) {
797 25 50       606 if ($piece =~ qr/ \A $groupname_re \z /x) {
    0          
798 25         124 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 0 0       0 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 0 0 0     0 $dbic_reqs->{test_adhoc}{req}{$mod} < $ver
808             );
809              
810 0         0 $ret->{modreqs}{$mod} = $ver;
811 0         0 $ret->{modreqs_fully_documented} = 0;
812             }
813             else {
814 0         0 croak "Unsupported argument '$piece' supplied to @{[ (caller(1))[3] ]}()"
  0         0  
815             }
816             }
817              
818 21         68 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 21         84 my $augmentations;
826 21         75 for my $requesting_group (keys %$all_groups) {
827 39 100       193 if (my $ag = $dbic_reqs->{$requesting_group}{augment}) {
828 2         6 for my $target_group (keys %$ag) {
829              
830             croak "Group '$requesting_group' claims to augment a non-existent group '$target_group'"
831 0 0       0 unless $dbic_reqs->{$target_group};
832              
833             croak "Augmentation combined with variable effective_modreqs currently unsupported for group '$requesting_group'"
834 0 0       0 if $dbic_reqs->{$requesting_group}{env};
835              
836             croak "Augmentation of group '$target_group' with variable effective_modreqs unsupported (requested by '$requesting_group')"
837 0 0       0 if $dbic_reqs->{$target_group}{env};
838              
839 0 0       0 if (my @foreign = grep { $_ ne 'req' } keys %{$ag->{$target_group}} ) {
  0         0  
  0         0  
840 0         0 croak "Only 'req' augmentations are currently supported (group '$requesting_group' attempts to alter '$foreign[0]' of group '$target_group'";
841             }
842              
843 0         0 $ret->{augments}{$target_group} = 1;
844              
845             # no augmentation for stuff that hasn't been selected
846 0 0 0     0 if ( $all_groups->{$target_group} and my $ar = $ag->{$target_group}{req} ) {
847 0         0 push @{$augmentations->{
848             ( $all_groups->{$requesting_group}{idx} < $all_groups->{$target_group}{idx} )
849 0 0       0 ? $target_group
850             : $requesting_group
851             }}, $ar;
852             }
853             }
854             }
855             }
856              
857 21         159 for my $group (sort { $all_groups->{$a}{idx} <=> $all_groups->{$b}{idx} } keys %$all_groups ) {
  23         97  
858              
859 39         87 my $group_reqs = $dbic_reqs->{$group}{req};
860              
861             # sanity-check
862 39 50       73 for my $req_bag ($group_reqs, @{ $augmentations->{$group} || [] } ) {
  39         169  
863 39         116 for (keys %$req_bag) {
864              
865 38 50       508 $_ =~ / \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 38 50 100     602 if ( ($req_bag->{$_}||0) !~ qr/ \A $modver_re \z /x );
872             }
873             }
874              
875 39 100       152 if (my $e = $all_groups->{$group}{missing_envvars}) {
876 19         36 push @{$ret->{missing_envvars}}, @$e;
  19         49  
877             }
878              
879             # assemble into the final ret
880 39 100       143 for my $type (
881             'modreqs',
882             ( $ret->{missing_envvars} ? () : 'effective_modreqs' ),
883             ) {
884 47 50       82 for my $req_bag ($group_reqs, @{ $augmentations->{$group} || [] } ) {
  47         183  
885 47         121 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 58 100 100     315 ($req_bag->{$mod}||0) > $ret->{$type}{$mod}
      50        
      66        
893              
894             );
895             }
896             }
897             }
898              
899             $ret->{modreqs_fully_documented} &&= !!$dbic_reqs->{$group}{pod}
900 39 100 100     199 if $all_groups->{$group}{user_requested};
901              
902 39   33     202 $ret->{release_testing_mandatory} ||= !!$dbic_reqs->{$group}{release_testing_mandatory};
903             }
904              
905 21         104 return $ret;
906             }
907              
908              
909             # this method tries to find/load specified modreqs and returns a hashref of
910             # module/loaderror pairs for anything that failed
911             sub _errorlist_for_modreqs {
912             # args supposedly already went through _groups_to_reqs and are therefore sanitized
913             # safe to eval at will
914 3     3   10 my ($self, $reqs) = @_;
915              
916 3         6 my $ret;
917              
918 3         10 for my $m ( keys %$reqs ) {
919 10         23 my $v = $reqs->{$m};
920              
921 10 50       30 if (! exists $req_unavailability_cache{$m}{$v} ) {
922 10         20 local $@;
923 10 100       774 eval( "require $m;" . ( $v ? "$m->VERSION(q($v))" : '' ) );
924 10         11572 $req_unavailability_cache{$m}{$v} = $@;
925             }
926              
927             $ret->{$m} = $req_unavailability_cache{$m}{$v}
928 10 100       47 if $req_unavailability_cache{$m}{$v};
929             }
930              
931 3         22 $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)
940             sub _list_physically_missing_modules {
941 15     15   44 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 15 50       35 return '' if grep { length ref $_ } @INC;
  165         320  
946              
947 15         29 my @definitely_missing;
948 15         43 for my $mod (keys %$modreqs) {
949 14         85 (my $fn = $mod . '.pm') =~ s|::|/|g;
950              
951             push @definitely_missing, $mod unless grep
952             # this should work on any combination of slashes
953 14 100 33     36 { $_ and -d $_ and -f "$_/$fn" and -r "$_/$fn" }
  154 100 66     3737  
954             @INC
955             ;
956             }
957              
958             join ' ', map
959 12 100       82 { $modreqs->{$_} ? "$_~$modreqs->{$_}" : $_ }
960 15         65 sort { lc($a) cmp lc($b) } @definitely_missing
  2         15  
961             ;
962             }
963              
964              
965             # This is to be called by the author only (automatically in Makefile.PL)
966             sub _gen_pod {
967 0     0     my ($class, $distver, $pod_dir) = @_;
968              
969 0 0         die "No POD root dir supplied" unless $pod_dir;
970              
971             $distver ||=
972 0   0       eval {
      0        
973             require DBIx::Class::Schema::Loader;
974             DBIx::Class::Schema::Loader->VERSION;
975             } ||
976             die
977             "\n\n---------------------------------------------------------------------\n" .
978             'Unable to load core DBIx::Class::Schema::Loader module to determine current version, '.
979             'possibly due to missing dependencies. Author-mode autodocumentation ' .
980             "halted\n\n" . $@ .
981             "\n\n---------------------------------------------------------------------\n"
982             ;
983              
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 0           require File::Path;
987              
988 0           (my $modfn = __PACKAGE__ . '.pm') =~ s|::|/|g;
989              
990 0           (my $podfn = "$pod_dir/$modfn") =~ s/\.pm$/\.pod/;
991 0           (my $dir = $podfn) =~ s|/[^/]+$||;
992              
993 0           File::Path::mkpath([$dir]);
994              
995             # used in example pod
996 0 0         my $moosever = $class->req_list_for('use_moose')->{'Moose'}
997             or die "Hrmm? No Moose dep?";
998              
999              
1000 0           my @chunks;
1001              
1002             #@@
1003             #@@ HEADER
1004             #@@
1005 0           push @chunks, <<"EOC";
1006             #########################################################################
1007             ##################### A U T O G E N E R A T E D ########################
1008             #########################################################################
1009             #
1010             # The contents of this POD file are auto-generated. Any changes you make
1011             # will be lost. If you need to change the generated text edit _gen_pod()
1012             # at the end of $modfn
1013             #
1014              
1015             =head1 NAME
1016              
1017             $class - Optional module dependency specifications (for module authors)
1018             EOC
1019              
1020              
1021             #@@
1022             #@@ SYNOPSIS HEADING
1023             #@@
1024 0           push @chunks, <<"EOC";
1025             =head1 SYNOPSIS
1026              
1027             Somewhere in your build-file (e.g. L's F):
1028              
1029             ...
1030              
1031             \$EUMM_ARGS{CONFIGURE_REQUIRES} = {
1032             \%{ \$EUMM_ARGS{CONFIGURE_REQUIRES} || {} },
1033             'DBIx::Class::Schema::Loader' => '$distver',
1034             };
1035              
1036             ...
1037              
1038             my %DBIC_CONFIG_AND_ORACLE_DEPS = %{ eval {
1039             require $class;
1040             $class->req_list_for([qw( dbicdump_config rdbms_oracle )]);
1041             } || {} };
1042              
1043             \$EUMM_ARGS{PREREQ_PM} = {
1044             \%DBIC_CONFIG_AND_ORACLE_DEPS,
1045             \%{ \$EUMM_ARGS{PREREQ_PM} || {} },
1046             };
1047              
1048             ...
1049              
1050             ExtUtils::MakeMaker::WriteMakefile(\%EUMM_ARGS);
1051              
1052             B: The C protection within the example is due to support for
1053             requirements during L build phase|CPAN::Meta::Spec/Phases>
1054             not being available on a sufficient portion of production installations of
1055             Perl. Robust support for such dependency requirements is available in the
1056             L installer only since version C<1.94_56> first made available for
1057             production with perl version C<5.12>. It is the belief of the current
1058             maintainer that support for requirements during the C build phase
1059             will not be sufficiently ubiquitous until the B at the earliest,
1060             hence the extra care demonstrated above. It should also be noted that some
1061             3rd party installers (e.g. L) do the right thing
1062             with configure requirements independent from the versions of perl and CPAN
1063             available.
1064             EOC
1065              
1066              
1067             #@@
1068             #@@ DESCRIPTION HEADING
1069             #@@
1070 0           push @chunks, <<'EOC';
1071             =head1 DESCRIPTION
1072              
1073             Some of the less-frequently used features of L have external
1074             module dependencies on their own. In order not to burden the average user
1075             with modules they will never use, these optional dependencies are not included
1076             in the base Makefile.PL. Instead an exception with a descriptive message is
1077             thrown when a specific feature can't find one or several modules required for
1078             its operation. This module is the central holding place for the current list
1079             of such dependencies, for DBIx::Class::Schema::Loader core authors, and DBIx::Class::Schema::Loader extension
1080             authors alike.
1081              
1082             Dependencies are organized in L where each
1083             group can list one or more required modules, with an optional minimum version
1084             (or 0 for any version). In addition groups prefixed with C can specify
1085             a set of environment variables, some (or all) of which are marked as required
1086             for the group to be considered by L
1087              
1088             Each group name (or a combination thereof) can be used in the
1089             L as described below.
1090             EOC
1091              
1092              
1093             #@@
1094             #@@ REQUIREMENT GROUPLIST HEADING
1095             #@@
1096 0           push @chunks, '=head1 CURRENT REQUIREMENT GROUPS';
1097              
1098 0           my $standalone_info;
1099              
1100 0           for my $group (sort keys %$dbic_reqs) {
1101              
1102 0   0       my $info = $standalone_info->{$group} ||= $class->_groups_to_reqs($group);
1103              
1104             next unless (
1105             $info->{modreqs_fully_documented}
1106             and
1107             ( $info->{augments} or $info->{modreqs} )
1108 0 0 0       );
      0        
1109              
1110 0           my $p = $dbic_reqs->{$group}{pod};
1111              
1112             push @chunks, (
1113             "=head2 $p->{title}",
1114             "=head3 $group",
1115             $p->{desc},
1116 0           '=over',
1117             );
1118              
1119 0 0         if ( keys %{ $info->{modreqs}||{} } ) {
  0 0          
1120             push @chunks, map
1121 0 0         { "=item * $_" . ($info->{modreqs}{$_} ? " >= $info->{modreqs}{$_}" : '') }
1122 0           ( sort keys %{ $info->{modreqs} } )
  0            
1123             ;
1124             }
1125             else {
1126 0           push @chunks, '=item * No standalone requirements',
1127             }
1128              
1129 0           push @chunks, '=back';
1130              
1131 0 0         for my $ag ( sort keys %{ $info->{augments} || {} } ) {
  0            
1132 0   0       my $ag_info = $standalone_info->{$ag} ||= $class->_groups_to_reqs($ag);
1133              
1134 0           my $newreqs = $class->modreq_list_for([ $group, $ag ]);
1135 0           for (keys %$newreqs) {
1136             delete $newreqs->{$_} if (
1137             ( defined $info->{modreqs}{$_} and $info->{modreqs}{$_} == $newreqs->{$_} )
1138             or
1139 0 0 0       ( defined $ag_info->{modreqs}{$_} and $ag_info->{modreqs}{$_} == $newreqs->{$_} )
      0        
      0        
1140             );
1141             }
1142              
1143 0 0         if (keys %$newreqs) {
1144             push @chunks, (
1145             "Combined with L additionally requires:",
1146             '=over',
1147             ( map
1148 0 0         { "=item * $_" . ($newreqs->{$_} ? " >= $newreqs->{$_}" : '') }
  0            
1149             ( sort keys %$newreqs )
1150             ),
1151             '=back',
1152             );
1153             }
1154             }
1155             }
1156              
1157              
1158             #@@
1159             #@@ API DOCUMENTATION HEADING
1160             #@@
1161 0           push @chunks, <<'EOC';
1162              
1163             =head1 IMPORT-LIKE ACTIONS
1164              
1165             Even though this module is not an L, it recognizes several C
1166             supplied to its C method.
1167              
1168             =head2 -skip_all_without
1169              
1170             =over
1171              
1172             =item Arguments: @group_names
1173              
1174             =back
1175              
1176             A convenience wrapper for use during testing:
1177             EOC
1178              
1179 0           push @chunks, " use $class -skip_all_without => qw(admin test_rdbms_mysql);";
1180              
1181 0           push @chunks, 'Roughly equivalent to the following code:';
1182              
1183 0           push @chunks, sprintf <<'EOS', ($class) x 2;
1184              
1185             BEGIN {
1186             require %s;
1187             if ( my $missing = %s->req_missing_for(\@group_names_) ) {
1188             print "1..0 # SKIP requirements not satisfied: $missing\n";
1189             exit 0;
1190             }
1191             }
1192             EOS
1193              
1194 0           push @chunks, <<'EOC';
1195              
1196             It also takes into account the C environment variable and
1197             behaves like L for any requirement groups marked as
1198             C.
1199              
1200             =head2 -die_without
1201              
1202             =over
1203              
1204             =item Arguments: @group_names
1205              
1206             =back
1207              
1208             A convenience wrapper around L:
1209             EOC
1210              
1211 0           push @chunks, " use $class -die_without => qw(deploy admin);";
1212              
1213 0           push @chunks, <<'EOC';
1214              
1215             =head2 -list_missing
1216              
1217             =over
1218              
1219             =item Arguments: @group_names
1220              
1221             =back
1222              
1223             A convenience wrapper around L:
1224              
1225             perl -Ilib -MDBIx::Class::Schema::Loader::Optional::Dependencies=-list_missing,dbicdump_config,rdbms_oracle | cpanm
1226              
1227             =head1 METHODS
1228              
1229             =head2 req_group_list
1230              
1231             =over
1232              
1233             =item Arguments: none
1234              
1235             =item Return Value: \%list_of_requirement_groups
1236              
1237             =back
1238              
1239             This method should be used by DBIx::Class::Schema::Loader packagers, to get a hashref of all
1240             dependencies B by dependency group. Each key (group name), or a combination
1241             thereof (as an arrayref) can be supplied to the methods below.
1242             The B of the returned hash are currently a set of options B
1243             well defined structure>. If you have use for any of the contents - contact the
1244             maintainers, instead of treating this as public (left alone stable) API.
1245              
1246             =head2 req_list_for
1247              
1248             =over
1249              
1250             =item Arguments: $group_name | \@group_names
1251              
1252             =item Return Value: \%set_of_module_version_pairs
1253              
1254             =back
1255              
1256             This method should be used by DBIx::Class::Schema::Loader extension authors, to determine the
1257             version of modules a specific set of features requires for this version of
1258             DBIx::Class::Schema::Loader (regardless of their availability on the system).
1259             See the L for a real-world example.
1260              
1261             When handling C groups this method behaves B from
1262             L below (and is the only such inconsistency among the
1263             C methods). If a particular group declares as requirements some
1264             C and these requirements are not satisfied (the envvars
1265             are unset) - then the C of this group are not included in
1266             the returned list.
1267              
1268             =head2 modreq_list_for
1269              
1270             =over
1271              
1272             =item Arguments: $group_name | \@group_names
1273              
1274             =item Return Value: \%set_of_module_version_pairs
1275              
1276             =back
1277              
1278             Same as L but does not take into consideration any
1279             C - returns just the list of required
1280             modules.
1281              
1282             =head2 req_ok_for
1283              
1284             =over
1285              
1286             =item Arguments: $group_name | \@group_names
1287              
1288             =item Return Value: 1|0
1289              
1290             =back
1291              
1292             Returns true or false depending on whether all modules/envvars required by
1293             the group(s) are loadable/set on the system.
1294              
1295             =head2 req_missing_for
1296              
1297             =over
1298              
1299             =item Arguments: $group_name | \@group_names
1300              
1301             =item Return Value: $error_message_string
1302              
1303             =back
1304              
1305             Returns a single-line string suitable for inclusion in larger error messages.
1306             This method would normally be used by DBIx::Class::Schema::Loader core features, to indicate to
1307             the user that they need to install specific modules and/or set specific
1308             environment variables before being able to use a specific feature set.
1309              
1310             For example if some of the requirements for C are not available,
1311             the returned string could look like:
1312             EOC
1313              
1314 0           push @chunks, qq{ "Moose~$moosever" (see $class documentation for details)};
1315              
1316 0           push @chunks, <<'EOC';
1317             The author is expected to prepend the necessary text to this message before
1318             returning the actual error seen by the user. See also L
1319              
1320             =head2 modreq_missing_for
1321              
1322             =over
1323              
1324             =item Arguments: $group_name | \@group_names
1325              
1326             =item Return Value: $error_message_string
1327              
1328             =back
1329              
1330             Same as L except that the error string is guaranteed to be
1331             either empty, or contain a set of module requirement specifications suitable
1332             for piping to e.g. L. The method explicitly does not
1333             attempt to validate the state of required environment variables (if any).
1334              
1335             For instance if some of the requirements for C are not available,
1336             the returned string could look like:
1337             EOC
1338              
1339 0           push @chunks, qq{ "Moose~$moosever"};
1340              
1341 0           push @chunks, <<'EOC';
1342              
1343             See also L.
1344              
1345             =head2 skip_without
1346              
1347             =over
1348              
1349             =item Arguments: $group_name | \@group_names
1350              
1351             =back
1352              
1353             A convenience wrapper around L. It does not take neither
1354             a reason (it is generated by L) nor an amount of skipped tests
1355             (it is always C<1>, thus mandating unconditional use of
1356             L). Most useful in combination with ad hoc
1357             requirement specifications:
1358             EOC
1359              
1360 0           push @chunks, <
1361             SKIP: {
1362             $class->skip_without([ deploy YAML>=0.90 ]);
1363              
1364             ...
1365             }
1366             EOC
1367              
1368 0           push @chunks, <<'EOC';
1369              
1370             =head2 die_unless_req_ok_for
1371              
1372             =over
1373              
1374             =item Arguments: $group_name | \@group_names
1375              
1376             =back
1377              
1378             Checks if L passes for the supplied group(s), and
1379             in case of failure throws an exception including the information
1380             from L. See also L.
1381              
1382             =head2 modreq_errorlist_for
1383              
1384             =over
1385              
1386             =item Arguments: $group_name | \@group_names
1387              
1388             =item Return Value: \%set_of_loaderrors_per_module
1389              
1390             =back
1391              
1392             Returns a hashref containing the actual errors that occurred while attempting
1393             to load each module in the requirement group(s).
1394              
1395             =head2 req_errorlist_for
1396              
1397             Deprecated method name, equivalent (via proxy) to L.
1398              
1399             EOC
1400              
1401             #@@
1402             #@@ FOOTER
1403             #@@
1404 0           push @chunks, <<'EOC';
1405             =head1 FURTHER QUESTIONS?
1406              
1407             Check the list of L.
1408              
1409             =head1 COPYRIGHT AND LICENSE
1410              
1411             This module is free software L
1412             by the L.
1413             You can redistribute it and/or modify it under the same terms as the
1414             L.
1415             EOC
1416              
1417 0 0 0       eval {
1418 0 0         open (my $fh, '>', $podfn) or die;
1419 0 0         print $fh join ("\n\n", @chunks) or die;
1420 0 0         print $fh "\n" or die;
1421 0 0         close ($fh) or die;
1422             } or croak( "Unable to write $podfn: " . ( $! || $@ || 'unknown error') );
1423             }
1424              
1425             1;