1 package DBIx::Class::Optional::Dependencies;
3 ### This may look crazy, but it in fact tangibly ( by 50(!)% ) shortens
4 # the skip-test time when everything requested is unavailable
6 if ( $ENV{RELEASE_TESTING} ) {
7 require warnings and warnings->import;
8 require strict and strict->import;
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
21 # POD is generated automatically by calling _gen_pod from the
22 # Makefile.PL in $AUTHOR mode
26 # NOTE: the rationale for 2 JSON::Any versions is that
27 # we need the newer only to work around JSON::XS, which
28 # itself is an optional dep
31 'JSON::Any' => '1.23',
35 _json_xs_compatible_json_any => {
37 'JSON::Any' => '1.31',
44 'Type::Library' => '0',
45 'Types::Standard' => '0',
46 'Types::LoadableClass' => '0',
50 # a common placeholder for engines with IC::DT support based off DT::F::S
51 _icdt_strptime_based => {
55 'DateTime::Format::Strptime' => '1.2',
61 _rdbms_generic_odbc => {
67 _rdbms_generic_ado => {
73 # must list any dep used by adhoc testing
74 # this prevents the "skips due to forgotten deps" issue
77 'Class::DBI::Plugin::DeepAbstractSearch' => '0',
78 'Class::DBI' => '3.000005',
79 'Date::Simple' => '3.03',
81 'Class::Unload' => '0.07',
83 'Time::Piece::MySQL' => '0',
88 include => '_types_common',
90 title => 'Storage::Replicated',
91 desc => 'Modules required for L<DBIx::Class::Storage::DBI::Replicated>',
96 include => 'replicated',
100 include => [qw(_json_any _types_common)],
102 title => 'DBIx::Class::Admin',
103 desc => 'Modules required for the DBIx::Class administrative library',
110 'Getopt::Long::Descriptive' => '0.081',
111 'Text::CSV' => '1.16',
114 title => 'dbicadmin',
115 desc => 'Modules required for the CLI DBIx::Class interface dbicadmin',
121 'SQL::Translator' => '0.11018',
124 title => 'Storage::DBI::deploy()',
125 desc => 'Modules required for L<DBIx::Class::Storage::DBI/deployment_statements> and L<DBIx::Class::Schema/deploy>',
131 'DateTime' => '0.55',
134 title => 'InflateColumn::DateTime support',
136 'Modules required for L<DBIx::Class::InflateColumn::DateTime>. '
137 . 'Note that this group does not require much on its own, but '
138 . 'instead is augmented by various RDBMS-specific groups. See the '
139 . 'documentation of each C<rbms_*> group for details',
145 'Math::BigInt' => '1.80',
146 'Math::Base36' => '0.07',
152 'Class::Data::Inheritable' => '0',
153 'Class::Trigger' => '0',
154 'DBIx::ContextualFetch' => '0',
158 title => 'DBIx::Class::CDBICompat support',
159 desc => 'Modules required for L<DBIx::Class::CDBICompat>'
165 'Test::Pod' => '1.42',
167 release_testing_mandatory => 1,
170 test_podcoverage => {
172 'Test::Pod::Coverage' => '1.08',
173 'Pod::Coverage' => '0.20',
175 release_testing_mandatory => 1,
180 'Test::EOL' => '1.0',
181 'Test::NoTabs' => '0.9',
183 release_testing_mandatory => 1,
188 'Test::Strict' => '0.24',
190 release_testing_mandatory => 1,
193 test_prettydebug => {
194 include => '_json_any',
197 test_admin_script => {
198 include => [qw( admin_script _json_xs_compatible_json_any )],
202 'Cpanel::JSON::XS' => 0,
205 # for t/admin/10script.t
206 ? ('Win32::ShellQuote' => 0)
207 # DWIW does not compile (./configure even) on win32
208 : ('JSON::DWIW' => 0 )
213 test_leaks_heavy => {
215 'Class::MethodCache' => '0.02',
216 'PadWalker' => '1.06',
221 # this is just for completeness as SQLite
222 # is a core dep of DBIC for testing
228 title => 'SQLite support',
229 desc => 'Modules required to connect to SQLite',
234 'DateTime::Format::SQLite' => '0',
240 # centralize the specification, as we have ICDT tests which can
241 # test the full behavior of RDBMS-specific ICDT on top of bare SQLite
242 # not _-prefixed so that it will show up under req_group_list
247 'DateTime::Format::Pg' => '0.16004',
254 include => 'icdt_pg',
256 # when changing this list make sure to adjust xt/optional_deps.t
260 title => 'PostgreSQL support',
261 desc => 'Modules required to connect to PostgreSQL',
265 _rdbms_mssql_common => {
266 include => '_icdt_strptime_based',
269 rdbms_mssql_odbc => {
270 include => [qw( _rdbms_generic_odbc _rdbms_mssql_common )],
272 title => 'MSSQL support via DBD::ODBC',
273 desc => 'Modules required to connect to MSSQL via DBD::ODBC',
277 rdbms_mssql_sybase => {
278 include => '_rdbms_mssql_common',
283 title => 'MSSQL support via DBD::Sybase',
284 desc => 'Modules required to connect to MSSQL via DBD::Sybase',
289 include => [qw( _rdbms_generic_ado _rdbms_mssql_common )],
291 title => 'MSSQL support via DBD::ADO (Windows only)',
292 desc => 'Modules required to connect to MSSQL via DBD::ADO. This particular DBD is available on Windows only',
296 _rdbms_msaccess_common => {
297 include => '_icdt_strptime_based',
300 rdbms_msaccess_odbc => {
301 include => [qw( _rdbms_generic_odbc _rdbms_msaccess_common )],
303 title => 'MS Access support via DBD::ODBC',
304 desc => 'Modules required to connect to MS Access via DBD::ODBC',
308 rdbms_msaccess_ado => {
309 include => [qw( _rdbms_generic_ado _rdbms_msaccess_common )],
311 title => 'MS Access support via DBD::ADO (Windows only)',
312 desc => 'Modules required to connect to MS Access via DBD::ADO. This particular DBD is available on Windows only',
316 # centralize the specification, as we have ICDT tests which can
317 # test the full behavior of RDBMS-specific ICDT on top of bare SQLite
318 # not _-prefixed so that it will show up under req_group_list
323 'DateTime::Format::MySQL' => '0',
330 include => 'icdt_mysql',
335 title => 'MySQL support',
336 desc => 'Modules required to connect to MySQL',
341 include => 'id_shortener',
346 title => 'Oracle support',
347 desc => 'Modules required to connect to Oracle',
352 'DateTime::Format::Oracle' => '0',
359 include => '_icdt_strptime_based',
364 title => 'Sybase ASE support',
365 desc => 'Modules required to connect to Sybase ASE',
369 _rdbms_db2_common => {
373 'DateTime::Format::DB2' => '0',
380 include => '_rdbms_db2_common',
385 title => 'DB2 support',
386 desc => 'Modules required to connect to DB2',
391 include => [qw( _rdbms_generic_odbc _rdbms_db2_common )],
393 title => 'DB2 on AS/400 support',
394 desc => 'Modules required to connect to DB2 on AS/400',
399 include => '_icdt_strptime_based',
401 'DBD::Informix' => 0,
404 title => 'Informix support',
405 desc => 'Modules required to connect to Informix',
409 _rdbms_sqlanywhere_common => {
410 inclide => '_icdt_strptime_based',
413 rdbms_sqlanywhere => {
414 include => '_rdbms_sqlanywhere_common',
416 'DBD::SQLAnywhere' => 0,
419 title => 'SQLAnywhere support',
420 desc => 'Modules required to connect to SQLAnywhere',
424 rdbms_sqlanywhere_odbc => {
425 include => [qw( _rdbms_generic_odbc _rdbms_sqlanywhere_common )],
427 title => 'SQLAnywhere support via DBD::ODBC',
428 desc => 'Modules required to connect to SQLAnywhere via DBD::ODBC',
432 _rdbms_firebird_common => {
433 include => '_icdt_strptime_based',
437 include => '_rdbms_firebird_common',
439 'DBD::Firebird' => 0,
442 title => 'Firebird support',
443 desc => 'Modules required to connect to Firebird',
447 rdbms_firebird_interbase => {
448 include => '_rdbms_firebird_common',
450 'DBD::InterBase' => 0,
453 title => 'Firebird support via DBD::InterBase',
454 desc => 'Modules required to connect to Firebird via DBD::InterBase',
458 rdbms_firebird_odbc => {
459 include => [qw( _rdbms_generic_odbc _rdbms_firebird_common )],
461 title => 'Firebird support via DBD::ODBC',
462 desc => 'Modules required to connect to Firebird via DBD::ODBC',
466 test_rdbms_sqlite => {
467 include => 'rdbms_sqlite',
470 ### IMPORTANT - do not raise this dependency
471 ### even though many bugfixes are present in newer versions, the general DBIC
472 ### rule is to bend over backwards for available DBDs (given upgrading them is
473 ### often *not* easy or even possible)
475 'DBD::SQLite' => '1.29',
480 include => 'rdbms_pg',
482 DBICTEST_PG_DSN => 1,
483 DBICTEST_PG_USER => 0,
484 DBICTEST_PG_PASS => 0,
487 # the order does matter because the rdbms support group might require
488 # a different version that the test group
490 # when changing this list make sure to adjust xt/optional_deps.t
491 'DBD::Pg' => '2.009002', # specific version to test bytea
495 test_rdbms_mssql_odbc => {
496 include => 'rdbms_mssql_odbc',
498 DBICTEST_MSSQL_ODBC_DSN => 1,
499 DBICTEST_MSSQL_ODBC_USER => 0,
500 DBICTEST_MSSQL_ODBC_PASS => 0,
504 test_rdbms_mssql_ado => {
505 include => 'rdbms_mssql_ado',
507 DBICTEST_MSSQL_ADO_DSN => 1,
508 DBICTEST_MSSQL_ADO_USER => 0,
509 DBICTEST_MSSQL_ADO_PASS => 0,
513 test_rdbms_mssql_sybase => {
514 include => 'rdbms_mssql_sybase',
516 DBICTEST_MSSQL_DSN => 1,
517 DBICTEST_MSSQL_USER => 0,
518 DBICTEST_MSSQL_PASS => 0,
522 test_rdbms_msaccess_odbc => {
523 include => 'rdbms_msaccess_odbc',
525 DBICTEST_MSACCESS_ODBC_DSN => 1,
526 DBICTEST_MSACCESS_ODBC_USER => 0,
527 DBICTEST_MSACCESS_ODBC_PASS => 0,
534 test_rdbms_msaccess_ado => {
535 include => 'rdbms_msaccess_ado',
537 DBICTEST_MSACCESS_ADO_DSN => 1,
538 DBICTEST_MSACCESS_ADO_USER => 0,
539 DBICTEST_MSACCESS_ADO_PASS => 0,
546 test_rdbms_mysql => {
547 include => 'rdbms_mysql',
549 DBICTEST_MYSQL_DSN => 1,
550 DBICTEST_MYSQL_USER => 0,
551 DBICTEST_MYSQL_PASS => 0,
555 test_rdbms_oracle => {
556 include => 'rdbms_oracle',
558 DBICTEST_ORA_DSN => 1,
559 DBICTEST_ORA_USER => 0,
560 DBICTEST_ORA_PASS => 0,
563 'DBD::Oracle' => '1.24',
568 include => 'rdbms_ase',
570 DBICTEST_SYBASE_DSN => 1,
571 DBICTEST_SYBASE_USER => 0,
572 DBICTEST_SYBASE_PASS => 0,
577 include => 'rdbms_db2',
579 DBICTEST_DB2_DSN => 1,
580 DBICTEST_DB2_USER => 0,
581 DBICTEST_DB2_PASS => 0,
585 test_rdbms_db2_400 => {
586 include => 'rdbms_db2_400',
588 DBICTEST_DB2_400_DSN => 1,
589 DBICTEST_DB2_400_USER => 0,
590 DBICTEST_DB2_400_PASS => 0,
594 test_rdbms_informix => {
595 include => 'rdbms_informix',
597 DBICTEST_INFORMIX_DSN => 1,
598 DBICTEST_INFORMIX_USER => 0,
599 DBICTEST_INFORMIX_PASS => 0,
603 test_rdbms_sqlanywhere => {
604 include => 'rdbms_sqlanywhere',
606 DBICTEST_SQLANYWHERE_DSN => 1,
607 DBICTEST_SQLANYWHERE_USER => 0,
608 DBICTEST_SQLANYWHERE_PASS => 0,
612 test_rdbms_sqlanywhere_odbc => {
613 include => 'rdbms_sqlanywhere_odbc',
615 DBICTEST_SQLANYWHERE_ODBC_DSN => 1,
616 DBICTEST_SQLANYWHERE_ODBC_USER => 0,
617 DBICTEST_SQLANYWHERE_ODBC_PASS => 0,
621 test_rdbms_firebird => {
622 include => 'rdbms_firebird',
624 DBICTEST_FIREBIRD_DSN => 1,
625 DBICTEST_FIREBIRD_USER => 0,
626 DBICTEST_FIREBIRD_PASS => 0,
630 test_rdbms_firebird_interbase => {
631 include => 'rdbms_firebird_interbase',
633 DBICTEST_FIREBIRD_INTERBASE_DSN => 1,
634 DBICTEST_FIREBIRD_INTERBASE_USER => 0,
635 DBICTEST_FIREBIRD_INTERBASE_PASS => 0,
639 test_rdbms_firebird_odbc => {
640 include => 'rdbms_firebird_odbc',
642 DBICTEST_FIREBIRD_ODBC_DSN => 1,
643 DBICTEST_FIREBIRD_ODBC_USER => 0,
644 DBICTEST_FIREBIRD_ODBC_PASS => 0,
650 DBICTEST_MEMCACHED => 1,
653 'Cache::Memcached' => 0,
658 # we need to run the dbicadmin so we can self-generate its POD
659 # also we do not want surprises in case JSON::XS is in the path
660 # so make sure we get an always-working JSON::Any
661 include => [qw( admin_script _json_xs_compatible_json_any )],
663 'ExtUtils::MakeMaker' => '6.64',
664 'Pod::Inherit' => '0.91',
670 'CPAN::Uploader' => '0.103001',
686 if ($action eq '-die_without') {
690 eval { $class->die_unless_req_ok_for(\@_); 1 }
693 die "\n$err\n" if $err;
695 elsif ($action eq '-list_missing') {
696 print $class->modreq_missing_for(\@_);
700 elsif ($action eq '-skip_all_without') {
702 # sanity check - make sure ->current_test is 0 and no plan has been declared
706 Test::Builder->new->current_test
708 Test::Builder->new->has_plan
710 } and croak("Unable to invoke -skip_all_without after testing has started");
712 if ( my $missing = $class->req_missing_for(\@_) ) {
714 die ("\nMandatory requirements not satisfied during release-testing: $missing\n\n")
715 if $ENV{RELEASE_TESTING} and $class->_groups_to_reqs(\@_)->{release_testing_mandatory};
717 print "1..0 # SKIP requirements not satisfied: $missing\n";
721 elsif ($action =~ /^-/) {
722 croak "Unknown import-time action '$action'";
725 croak "$class is not an exporter, unable to import '$action'";
733 croak( __PACKAGE__ . " does not implement unimport" );
736 # OO for (mistakenly considered) ease of extensibility, not due to any need to
737 # carry state of any sort. This API is currently used outside, so leave as-is.
738 # FIXME - make sure to not propagate this further if module is extracted as a
739 # standalone library - keep the stupidity to a DBIC-secific shim!
742 shift->_groups_to_reqs(shift)->{effective_modreqs};
745 sub modreq_list_for {
746 shift->_groups_to_reqs(shift)->{modreqs};
751 { $_ => $_[0]->_groups_to_reqs($_) }
752 grep { $_ !~ /^_/ } keys %$dbic_reqs
756 sub req_errorlist_for { shift->modreq_errorlist_for(shift) } # deprecated
757 sub modreq_errorlist_for {
758 my ($self, $groups) = @_;
759 $self->_errorlist_for_modreqs( $self->_groups_to_reqs($groups)->{modreqs} );
763 shift->req_missing_for(shift) ? 0 : 1;
766 sub req_missing_for {
767 my ($self, $groups) = @_;
769 my $reqs = $self->_groups_to_reqs($groups);
771 my $mods_missing = $reqs->{missing_envvars}
772 ? $self->_list_physically_missing_modules( $reqs->{modreqs} )
773 : $self->modreq_missing_for($groups)
779 ! $reqs->{missing_envvars}
782 my @res = $mods_missing || ();
784 push @res, 'the following group(s) of environment variables: ' . join ' and ', sort map
785 { __envvar_group_desc($_) }
786 @{$reqs->{missing_envvars}}
787 if $reqs->{missing_envvars};
790 ( join ' as well as ', @res )
792 ( $reqs->{modreqs_fully_documented} ? " (see @{[ ref $self || $self ]} documentation for details)" : '' ),
796 sub modreq_missing_for {
797 my ($self, $groups) = @_;
799 my $reqs = $self->_groups_to_reqs($groups);
800 my $modreq_errors = $self->_errorlist_for_modreqs($reqs->{modreqs})
804 { $reqs->{modreqs}{$_} ? qq("$_~>=$reqs->{modreqs}{$_}") : $_ }
805 sort { lc($a) cmp lc($b) } keys %$modreq_errors
811 my ($self, $groups) = @_;
813 $tb ||= do { local $@; eval { Test::Builder->new } }
814 or croak "Calling skip_without() before loading Test::Builder makes no sense";
816 if ( my $err = $self->req_missing_for($groups) ) {
817 my ($fn, $ln) = (caller(0))[1,2];
818 $tb->skip("block in $fn around line $ln requires $err");
826 sub die_unless_req_ok_for {
827 if (my $err = shift->req_missing_for(shift) ) {
828 die "Unable to continue due to missing requirements: $err\n";
834 ### Private functions
836 # potentially shorten group desc
837 sub __envvar_group_desc {
840 my (@res, $last_prefix);
841 while (my $ev = shift @envs) {
842 my ($pref, $sep, $suff) = split / ([\_\-]) (?= [^\_\-]+ \z )/x, $ev;
844 if ( defined $sep and ($last_prefix||'') eq $pref ) {
845 push @res, "...${sep}${suff}"
851 $last_prefix = $pref if $sep;
857 my $groupname_re = qr/ [A-Z_a-z][0-9A-Z_a-z]* /x;
858 my $modname_re = qr/ [A-Z_a-z] [0-9A-Z_a-z]* (?:::[0-9A-Z_a-z]+)* /x;
859 my $modver_re = qr/ [0-9]+ (?: \. [0-9]+ )? /x;
861 # Expand includes from a random group in a specific order:
862 # nonvariable groups first, then their includes, then the variable groups,
863 # then their includes.
864 # This allows reliably marking the rest of the mod reqs as variable (this is
865 # also why variable includes are currently not allowed)
866 sub __expand_includes {
867 my ($groups, $seen) = @_;
869 # !! DIFFERENT !! behavior and return depending on invocation mode
870 # (easier to recurse this way)
871 my $is_toplevel = $seen
876 my ($res_per_type, $missing_envvars);
878 # breadth-first evaluation, with non-variable includes on top
879 for my $g (@$groups) {
881 croak "Invalid requirement group name '$g': only ascii alphanumerics and _ are allowed"
882 if $g !~ qr/ \A $groupname_re \z/x;
884 my $r = $dbic_reqs->{$g}
885 or croak "Requirement group '$g' is not defined";
887 # always do this check *before* the $seen check
888 croak "Group '$g' with variable effective_modreqs can not be specified as an 'include'"
889 if ( $r->{env} and ! $is_toplevel );
891 next if $seen->{$g}++;
893 my $req_type = 'static';
895 if ( my @e = @{$r->{env}||[]} ) {
897 croak "Unexpected 'env' attribute under group '$g' (only allowed in test_* groups)"
898 unless $g =~ /^test_/;
900 croak "Unexpected *odd* list in 'env' under group '$g'"
903 # deconstruct the whole thing
904 my (@group_envnames_list, $some_envs_required, $some_required_missing);
906 push @group_envnames_list, my $envname = shift @e;
908 # env required or not
909 next unless shift @e;
911 $some_envs_required ||= 1;
913 $some_required_missing ||= (
914 ! defined $ENV{$envname}
916 ! length $ENV{$envname}
920 croak "None of the envvars in group '$g' declared as required, making the requirement moot"
921 unless $some_envs_required;
923 if ($some_required_missing) {
924 push @{$missing_envvars->{$g}}, \@group_envnames_list;
925 $req_type = 'variable';
929 push @{$res_per_type->{"base_${req_type}"}}, $g;
931 if (my $i = $dbic_reqs->{$g}{include}) {
932 $i = [ $i ] unless ref $i eq 'ARRAY';
934 croak "Malformed 'include' for group '$g': must be another existing group name or arrayref of existing group names"
937 push @{$res_per_type->{"incs_${req_type}"}}, @$i;
942 @{ $res_per_type->{"base_${_}"} || [] },
943 ( $res_per_type->{"incs_${_}"} ? __expand_includes( $res_per_type->{"incs_${_}"}, $seen ) : () ),
944 } qw(static variable);
946 return ! $is_toplevel ? @ret : do {
949 idx => 1 + keys %$rv,
950 missing_envvars => $missing_envvars->{$_},
952 $rv->{$_}{user_requested} = 1 for @$groups;
958 our %req_unavailability_cache;
960 # this method is just a lister and envvar/metadata checker - it does not try to load anything
961 sub _groups_to_reqs {
962 my ($self, $want) = @_;
964 $want = [ $want || () ]
965 unless ref $want eq 'ARRAY';
967 croak "@{[ (caller(1))[3] ]}() expects a requirement group name or arrayref of group names"
972 modreqs_fully_documented => 1,
976 for my $piece (@$want) {
977 if ($piece =~ qr/ \A $groupname_re \z /x) {
978 push @$groups, $piece;
980 elsif ( my ($mod, $ver) = $piece =~ qr/ \A ($modname_re) \>\= ($modver_re) \z /x ) {
981 croak "Ad hoc module specification lists '$mod' twice"
982 if exists $ret->{modreqs}{$mod};
984 croak "Ad hoc module specification '${mod} >= $ver' (or greater) not listed in the test_adhoc optdep group" if (
985 ! defined $dbic_reqs->{test_adhoc}{req}{$mod}
987 $dbic_reqs->{test_adhoc}{req}{$mod} < $ver
990 $ret->{modreqs}{$mod} = $ver;
991 $ret->{modreqs_fully_documented} = 0;
994 croak "Unsupported argument '$piece' supplied to @{[ (caller(1))[3] ]}()"
998 my $all_groups = __expand_includes($groups);
1000 # pre-assemble list of augmentations, perform basic sanity checks
1001 # Note that below we *DO NOT* respect the source/target reationship, but
1002 # instead always default to augment the "later" group
1003 # This is done so that the "stable/variable" boundary keeps working as
1006 for my $requesting_group (keys %$all_groups) {
1007 if (my $ag = $dbic_reqs->{$requesting_group}{augment}) {
1008 for my $target_group (keys %$ag) {
1010 croak "Group '$requesting_group' claims to augment a non-existent group '$target_group'"
1011 unless $dbic_reqs->{$target_group};
1013 croak "Augmentation combined with variable effective_modreqs currently unsupported for group '$requesting_group'"
1014 if $dbic_reqs->{$requesting_group}{env};
1016 croak "Augmentation of group '$target_group' with variable effective_modreqs unsupported (requested by '$requesting_group')"
1017 if $dbic_reqs->{$target_group}{env};
1019 if (my @foreign = grep { $_ ne 'req' } keys %{$ag->{$target_group}} ) {
1020 croak "Only 'req' augmentations are currently supported (group '$requesting_group' attempts to alter '$foreign[0]' of group '$target_group'";
1023 $ret->{augments}{$target_group} = 1;
1025 # no augmentation for stuff that hasn't been selected
1026 if ( $all_groups->{$target_group} and my $ar = $ag->{$target_group}{req} ) {
1027 push @{$augmentations->{
1028 ( $all_groups->{$requesting_group}{idx} < $all_groups->{$target_group}{idx} )
1037 for my $group (sort { $all_groups->{$a}{idx} <=> $all_groups->{$b}{idx} } keys %$all_groups ) {
1039 my $group_reqs = $dbic_reqs->{$group}{req};
1042 for my $req_bag ($group_reqs, @{ $augmentations->{$group} || [] } ) {
1043 for (keys %$req_bag) {
1045 $_ =~ / \A $modname_re \z /x
1046 or croak "Requirement '$_' in group '$group' is not a valid module name";
1048 # !!!DO NOT CHANGE!!!
1049 # remember - version.pm may not be available on the system
1050 croak "Requirement '$_' in group '$group' specifies an invalid version '$req_bag->{$_}' (only plain non-underscored floating point decimals are supported)"
1051 if ( ($req_bag->{$_}||0) !~ qr/ \A $modver_re \z /x );
1055 if (my $e = $all_groups->{$group}{missing_envvars}) {
1056 push @{$ret->{missing_envvars}}, @$e;
1059 # assemble into the final ret
1062 ( $ret->{missing_envvars} ? () : 'effective_modreqs' ),
1064 for my $req_bag ($group_reqs, @{ $augmentations->{$group} || [] } ) {
1065 for my $mod (keys %$req_bag) {
1067 $ret->{$type}{$mod} = $req_bag->{$mod}||0 if (
1069 ! exists $ret->{$type}{$mod}
1071 # we sanitized the version to be numeric above - we can just -gt it
1072 ($req_bag->{$mod}||0) > $ret->{$type}{$mod}
1079 $ret->{modreqs_fully_documented} &&= !!$dbic_reqs->{$group}{pod}
1080 if $all_groups->{$group}{user_requested};
1082 $ret->{release_testing_mandatory} ||= !!$dbic_reqs->{$group}{release_testing_mandatory};
1089 # this method tries to find/load specified modreqs and returns a hashref of
1090 # module/loaderror pairs for anything that failed
1091 sub _errorlist_for_modreqs {
1092 # args supposedly already went through _groups_to_reqs and are therefore sanitized
1093 # safe to eval at will
1094 my ($self, $reqs) = @_;
1098 for my $m ( keys %$reqs ) {
1099 my $v = $reqs->{$m};
1101 if (! exists $req_unavailability_cache{$m}{$v} ) {
1103 eval( "require $m;" . ( $v ? "$m->VERSION(q($v))" : '' ) );
1104 $req_unavailability_cache{$m}{$v} = $@;
1107 $ret->{$m} = $req_unavailability_cache{$m}{$v}
1108 if $req_unavailability_cache{$m}{$v};
1114 # Unlike the above DO NOT try to load anything
1115 # This is executed when some needed envvars are not available
1116 # which in turn means a module load will never be reached anyway
1117 # This is important because some modules (especially DBDs) can be
1118 # *really* fickle when a require() is attempted, with pretty confusing
1119 # side-effects (especially on windows)
1120 sub _list_physically_missing_modules {
1121 my ($self, $modreqs) = @_;
1123 # in case there is a coderef in @INC there is nothing we can definitively prove
1124 # so short circuit directly
1125 return '' if grep { length ref $_ } @INC;
1127 my @definitely_missing;
1128 for my $mod (keys %$modreqs) {
1129 (my $fn = $mod . '.pm') =~ s|::|/|g;
1131 push @definitely_missing, $mod unless grep
1132 # this should work on any combination of slashes
1133 { $_ and -d $_ and -f "$_/$fn" and -r "$_/$fn" }
1139 { $modreqs->{$_} ? qq("$_~>=$modreqs->{$_}") : $_ }
1140 sort { lc($a) cmp lc($b) } @definitely_missing
1145 # This is to be called by the author only (automatically in Makefile.PL)
1147 my ($class, $distver, $pod_dir) = @_;
1149 die "No POD root dir supplied" unless $pod_dir;
1152 eval { require DBIx::Class; DBIx::Class->VERSION; }
1155 "\n\n---------------------------------------------------------------------\n" .
1156 'Unable to load core DBIx::Class module to determine current version, '.
1157 'possibly due to missing dependencies. Author-mode autodocumentation ' .
1159 "\n\n---------------------------------------------------------------------\n"
1162 # do not ask for a recent version, use 1.x API calls
1163 # this *may* execute on a smoker with old perl or whatnot
1166 (my $modfn = __PACKAGE__ . '.pm') =~ s|::|/|g;
1168 (my $podfn = "$pod_dir/$modfn") =~ s/\.pm$/\.pod/;
1169 (my $dir = $podfn) =~ s|/[^/]+$||;
1171 File::Path::mkpath([$dir]);
1173 my $sqltver = $class->req_list_for('deploy')->{'SQL::Translator'}
1174 or die "Hrmm? No sqlt dep?";
1182 push @chunks, <<"EOC";
1183 #########################################################################
1184 ##################### A U T O G E N E R A T E D ########################
1185 #########################################################################
1187 # The contents of this POD file are auto-generated. Any changes you make
1188 # will be lost. If you need to change the generated text edit _gen_pod()
1189 # at the end of $modfn
1194 $class - Optional module dependency specifications (for module authors)
1199 #@@ SYNOPSIS HEADING
1201 push @chunks, <<"EOC";
1204 Somewhere in your build-file (e.g. L<ExtUtils::MakeMaker>'s F<Makefile.PL>):
1208 \$EUMM_ARGS{CONFIGURE_REQUIRES} = {
1209 \%{ \$EUMM_ARGS{CONFIGURE_REQUIRES} || {} },
1210 'DBIx::Class' => '$distver',
1215 my %DBIC_DEPLOY_AND_ORACLE_DEPS = %{ eval {
1217 $class->req_list_for([qw( deploy rdbms_oracle icdt )]);
1220 \$EUMM_ARGS{PREREQ_PM} = {
1221 \%DBIC_DEPLOY_AND_ORACLE_DEPS,
1222 \%{ \$EUMM_ARGS{PREREQ_PM} || {} },
1227 ExtUtils::MakeMaker::WriteMakefile(\%EUMM_ARGS);
1229 B<Note>: The C<eval> protection within the example is due to support for
1230 requirements during L<the C<configure> build phase|CPAN::Meta::Spec/Phases>
1231 not being available on a sufficient portion of production installations of
1232 Perl. Robust support for such dependency requirements is available in the
1233 L<CPAN> installer only since version C<1.94_56> first made available for
1234 production with perl version C<5.12>. It is the belief of the current
1235 maintainer that support for requirements during the C<configure> build phase
1236 will not be sufficiently ubiquitous until the B<year 2020> at the earliest,
1237 hence the extra care demonstrated above. It should also be noted that some
1238 3rd party installers (e.g. L<cpanminus|App::cpanminus>) do the right thing
1239 with configure requirements independent from the versions of perl and CPAN
1245 #@@ DESCRIPTION HEADING
1247 push @chunks, <<'EOC';
1250 Some of the less-frequently used features of L<DBIx::Class> have external
1251 module dependencies on their own. In order not to burden the average user
1252 with modules they will never use, these optional dependencies are not included
1253 in the base Makefile.PL. Instead an exception with a descriptive message is
1254 thrown when a specific feature can't find one or several modules required for
1255 its operation. This module is the central holding place for the current list
1256 of such dependencies, for DBIx::Class core authors, and DBIx::Class extension
1259 Dependencies are organized in L<groups|/CURRENT REQUIREMENT GROUPS> where each
1260 group can list one or more required modules, with an optional minimum version
1261 (or 0 for any version). In addition groups prefixed with C<test_> can specify
1262 a set of environment variables, some (or all) of which are marked as required
1263 for the group to be considered by L</req_list_for>
1265 Each group name (or a combination thereof) can be used in the
1266 L<public methods|/METHODS> as described below.
1271 #@@ REQUIREMENT GROUPLIST HEADING
1273 push @chunks, '=head1 CURRENT REQUIREMENT GROUPS';
1275 my $standalone_info;
1277 for my $group (sort keys %$dbic_reqs) {
1279 my $info = $standalone_info->{$group} ||= $class->_groups_to_reqs($group);
1282 $info->{modreqs_fully_documented}
1284 ( $info->{augments} or $info->{modreqs} )
1287 my $p = $dbic_reqs->{$group}{pod};
1290 "=head2 $p->{title}",
1296 if ( keys %{ $info->{modreqs}||{} } ) {
1298 { "=item * $_" . ($info->{modreqs}{$_} ? " >= $info->{modreqs}{$_}" : '') }
1299 ( sort keys %{ $info->{modreqs} } )
1303 push @chunks, '=item * No standalone requirements',
1306 push @chunks, '=back';
1308 for my $ag ( sort keys %{ $info->{augments} || {} } ) {
1309 my $ag_info = $standalone_info->{$ag} ||= $class->_groups_to_reqs($ag);
1311 my $newreqs = $class->modreq_list_for([ $group, $ag ]);
1312 for (keys %$newreqs) {
1313 delete $newreqs->{$_} if (
1314 ( defined $info->{modreqs}{$_} and $info->{modreqs}{$_} == $newreqs->{$_} )
1316 ( defined $ag_info->{modreqs}{$_} and $ag_info->{modreqs}{$_} == $newreqs->{$_} )
1320 if (keys %$newreqs) {
1322 "Combined with L</$ag> additionally requires:",
1325 { "=item * $_" . ($newreqs->{$_} ? " >= $newreqs->{$_}" : '') }
1326 ( sort keys %$newreqs )
1336 #@@ API DOCUMENTATION HEADING
1338 push @chunks, <<'EOC';
1340 =head1 IMPORT-LIKE ACTIONS
1342 Even though this module is not an L<Exporter>, it recognizes several C<actions>
1343 supplied to its C<import> method.
1345 =head2 -skip_all_without
1349 =item Arguments: @group_names
1353 A convenience wrapper for use during testing:
1356 push @chunks, " use $class -skip_all_without => qw(admin test_rdbms_mysql);";
1358 push @chunks, 'Roughly equivalent to the following code:';
1360 push @chunks, sprintf <<'EOS', ($class) x 2;
1364 if ( my $missing = %s->req_missing_for(\@group_names_) ) {
1365 print "1..0 # SKIP requirements not satisfied: $missing\n";
1371 push @chunks, <<'EOC';
1373 It also takes into account the C<RELEASE_TESTING> environment variable and
1374 behaves like L</-die_without> for any requirement groups marked as
1375 C<release_testing_mandatory>.
1381 =item Arguments: @group_names
1385 A convenience wrapper around L</die_unless_req_ok_for>:
1388 push @chunks, " use $class -die_without => qw(deploy admin);";
1390 push @chunks, <<'EOC';
1392 =head2 -list_missing
1396 =item Arguments: @group_names
1400 A convenience wrapper around L</modreq_missing_for>:
1402 perl -Ilib -MDBIx::Class::Optional::Dependencies=-list_missing,deploy,admin | cpanm
1406 =head2 req_group_list
1410 =item Arguments: none
1412 =item Return Value: \%list_of_requirement_groups
1416 This method should be used by DBIx::Class packagers, to get a hashref of all
1417 dependencies B<keyed> by dependency group. Each key (group name), or a combination
1418 thereof (as an arrayref) can be supplied to the methods below.
1419 The B<values> of the returned hash are currently a set of options B<without a
1420 well defined structure>. If you have use for any of the contents - contact the
1421 maintainers, instead of treating this as public (left alone stable) API.
1427 =item Arguments: $group_name | \@group_names
1429 =item Return Value: \%set_of_module_version_pairs
1433 This method should be used by DBIx::Class extension authors, to determine the
1434 version of modules a specific set of features requires for this version of
1435 DBIx::Class (regardless of their availability on the system).
1436 See the L</SYNOPSIS> for a real-world example.
1438 When handling C<test_*> groups this method behaves B<differently> from
1439 L</modreq_list_for> below (and is the only such inconsistency among the
1440 C<req_*> methods). If a particular group declares as requirements some
1441 C<environment variables> and these requirements are not satisfied (the envvars
1442 are unset) - then the C<module requirements> of this group are not included in
1445 =head2 modreq_list_for
1449 =item Arguments: $group_name | \@group_names
1451 =item Return Value: \%set_of_module_version_pairs
1455 Same as L</req_list_for> but does not take into consideration any
1456 C<environment variable requirements> - returns just the list of required
1463 =item Arguments: $group_name | \@group_names
1465 =item Return Value: 1|0
1469 Returns true or false depending on whether all modules/envvars required by
1470 the group(s) are loadable/set on the system.
1472 =head2 req_missing_for
1476 =item Arguments: $group_name | \@group_names
1478 =item Return Value: $error_message_string
1482 Returns a single-line string suitable for inclusion in larger error messages.
1483 This method would normally be used by DBIx::Class core features, to indicate to
1484 the user that they need to install specific modules and/or set specific
1485 environment variables before being able to use a specific feature set.
1487 For example if some of the requirements for C<deploy> are not available,
1488 the returned string could look like:
1491 push @chunks, qq{ "SQL::Translator~>=$sqltver" (see $class documentation for details)};
1493 push @chunks, <<'EOC';
1494 The author is expected to prepend the necessary text to this message before
1495 returning the actual error seen by the user. See also L</modreq_missing_for>
1497 =head2 modreq_missing_for
1501 =item Arguments: $group_name | \@group_names
1503 =item Return Value: $error_message_string
1507 Same as L</req_missing_for> except that the error string is guaranteed to be
1508 either empty, or contain a set of module requirement specifications suitable
1509 for piping to e.g. L<cpanminus|App::cpanminus>. The method explicitly does not
1510 attempt to validate the state of required environment variables (if any).
1512 For instance if some of the requirements for C<deploy> are not available,
1513 the returned string could look like:
1516 push @chunks, qq{ "SQL::Translator~>=$sqltver"};
1518 push @chunks, <<'EOC';
1520 See also L</-list_missing>.
1526 =item Arguments: $group_name | \@group_names
1530 A convenience wrapper around L<skip|Test::More/SKIP>. It does not take neither
1531 a reason (it is generated by L</req_missing_for>) nor an amount of skipped tests
1532 (it is always C<1>, thus mandating unconditional use of
1533 L<done_testing|Test::More/done_testing>). Most useful in combination with ad hoc
1534 requirement specifications:
1537 push @chunks, <<EOC;
1539 $class->skip_without([ deploy YAML>=0.90 ]);
1545 push @chunks, <<'EOC';
1547 =head2 die_unless_req_ok_for
1551 =item Arguments: $group_name | \@group_names
1555 Checks if L</req_ok_for> passes for the supplied group(s), and
1556 in case of failure throws an exception including the information
1557 from L</req_missing_for>. See also L</-die_without>.
1559 =head2 modreq_errorlist_for
1563 =item Arguments: $group_name | \@group_names
1565 =item Return Value: \%set_of_loaderrors_per_module
1569 Returns a hashref containing the actual errors that occurred while attempting
1570 to load each module in the requirement group(s).
1572 =head2 req_errorlist_for
1574 Deprecated method name, equivalent (via proxy) to L</modreq_errorlist_for>.
1581 push @chunks, <<'EOC';
1582 =head1 FURTHER QUESTIONS?
1584 Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
1586 =head1 COPYRIGHT AND LICENSE
1588 This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
1589 by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
1590 redistribute it and/or modify it under the same terms as the
1591 L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.
1595 open (my $fh, '>', $podfn) or die;
1596 print $fh join ("\n\n", @chunks) or die;
1597 print $fh "\n" or die;
1599 } or croak( "Unable to write $podfn: " . ( $! || $@ || 'unknown error') );