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',
41 # a common placeholder for engines with IC::DT support based off DT::F::S
42 _ic_dt_strptime_based => {
46 'DateTime::Format::Strptime' => '1.2',
52 _rdbms_generic_odbc => {
58 _rdbms_generic_ado => {
64 # must list any dep used by adhoc testing
65 # this prevents the "skips due to forgotten deps" issue
68 'Class::DBI::Plugin::DeepAbstractSearch' => '0',
69 'Class::DBI' => '3.000005',
70 'Date::Simple' => '3.03',
72 'Class::Unload' => '0.07',
74 'Time::Piece::MySQL' => '0',
80 'Class::Load' => '0.20',
83 title => 'Storage::Replicated',
84 desc => 'Modules required for L<DBIx::Class::Storage::DBI::Replicated>',
89 include => 'replicated',
93 include => '_json_any',
95 title => 'DBIx::Class::Admin',
96 desc => 'Modules required for the DBIx::Class administrative library',
103 'Getopt::Long::Descriptive' => '0.081',
104 'Text::CSV' => '1.16',
107 title => 'dbicadmin',
108 desc => 'Modules required for the CLI DBIx::Class interface dbicadmin',
114 'SQL::Translator' => '0.11018',
117 title => 'Storage::DBI::deploy()',
118 desc => 'Modules required for L<DBIx::Class::Storage::DBI/deployment_statements> and L<DBIx::Class::Schema/deploy>',
124 'DateTime' => '0.55',
125 'DateTime::TimeZone::OlsonDB' => 0,
128 title => 'InflateColumn::DateTime support',
130 'Modules required for L<DBIx::Class::InflateColumn::DateTime>. '
131 . 'Note that this group does not require much on its own, but '
132 . 'instead is augmented by various RDBMS-specific groups. See the '
133 . 'documentation of each C<rbms_*> group for details',
139 'Math::BigInt' => '1.80',
140 'Math::Base36' => '0.07',
146 'Class::Data::Inheritable' => '0',
147 'Class::Trigger' => '0',
148 'DBIx::ContextualFetch' => '0',
152 title => 'DBIx::Class::CDBICompat support',
153 desc => 'Modules required for L<DBIx::Class::CDBICompat>'
159 'Test::Pod' => '1.42',
161 release_testing_mandatory => 1,
164 test_podcoverage => {
166 'Test::Pod::Coverage' => '1.08',
167 'Pod::Coverage' => '0.20',
169 release_testing_mandatory => 1,
174 'Test::EOL' => '1.0',
175 'Test::NoTabs' => '0.9',
177 release_testing_mandatory => 1,
182 'Test::Strict' => '0.24',
184 release_testing_mandatory => 1,
187 test_prettydebug => {
188 include => '_json_any',
191 test_admin_script => {
192 include => [qw( admin_script _json_xs_compatible_json_any )],
196 'Cpanel::JSON::XS' => 0,
199 # for t/admin/10script.t
200 ? ('Win32::ShellQuote' => 0)
201 # DWIW does not compile (./configure even) on win32
202 : ('JSON::DWIW' => 0 )
207 test_leaks_heavy => {
209 'Class::MethodCache' => '0.02',
210 'PadWalker' => '1.06',
215 # this is just for completeness as SQLite
216 # is a core dep of DBIC for testing
222 title => 'SQLite support',
223 desc => 'Modules required to connect to SQLite',
228 'DateTime::Format::SQLite' => '0',
234 # centralize the specification, as we have ICDT tests which can
235 # test the full behavior of RDBMS-specific ICDT on top of bare SQLite
240 'DateTime::Format::Pg' => '0.16004',
247 include => [qw( ic_dt _ic_dt_pg_base )],
251 include => '_ic_dt_pg_base',
253 # when changing this list make sure to adjust xt/optional_deps.t
257 title => 'PostgreSQL support',
258 desc => 'Modules required to connect to PostgreSQL',
262 _rdbms_mssql_common => {
263 include => '_ic_dt_strptime_based',
266 rdbms_mssql_odbc => {
267 include => [qw( _rdbms_generic_odbc _rdbms_mssql_common )],
269 title => 'MSSQL support via DBD::ODBC',
270 desc => 'Modules required to connect to MSSQL via DBD::ODBC',
274 rdbms_mssql_sybase => {
275 include => '_rdbms_mssql_common',
280 title => 'MSSQL support via DBD::Sybase',
281 desc => 'Modules required to connect to MSSQL via DBD::Sybase',
286 include => [qw( _rdbms_generic_ado _rdbms_mssql_common )],
288 title => 'MSSQL support via DBD::ADO (Windows only)',
289 desc => 'Modules required to connect to MSSQL via DBD::ADO. This particular DBD is available on Windows only',
293 _rdbms_msaccess_common => {
294 include => '_ic_dt_strptime_based',
297 rdbms_msaccess_odbc => {
298 include => [qw( _rdbms_generic_odbc _rdbms_msaccess_common )],
300 title => 'MS Access support via DBD::ODBC',
301 desc => 'Modules required to connect to MS Access via DBD::ODBC',
305 rdbms_msaccess_ado => {
306 include => [qw( _rdbms_generic_ado _rdbms_msaccess_common )],
308 title => 'MS Access support via DBD::ADO (Windows only)',
309 desc => 'Modules required to connect to MS Access via DBD::ADO. This particular DBD is available on Windows only',
313 # centralize the specification, as we have ICDT tests which can
314 # test the full behavior of RDBMS-specific ICDT on top of bare SQLite
315 _ic_dt_mysql_base => {
319 'DateTime::Format::MySQL' => '0',
326 include => [qw( ic_dt _ic_dt_mysql_base )],
330 include => '_ic_dt_mysql_base',
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 => '_ic_dt_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 => '_ic_dt_strptime_based',
401 'DBD::Informix' => 0,
404 title => 'Informix support',
405 desc => 'Modules required to connect to Informix',
409 _rdbms_sqlanywhere_common => {
410 include => '_ic_dt_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 => '_ic_dt_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
663 _json_xs_compatible_json_any
672 'ExtUtils::MakeMaker' => '6.64',
673 'Module::Install' => '1.06',
674 'Pod::Inherit' => '0.91',
680 'CPAN::Uploader' => '0.103001',
696 if ($action eq '-die_without') {
700 eval { $class->die_unless_req_ok_for(\@_); 1 }
703 die "\n$err\n" if $err;
705 elsif ($action eq '-list_missing') {
706 print $class->modreq_missing_for(\@_);
710 elsif ($action eq '-skip_all_without') {
712 # sanity check - make sure ->current_test is 0 and no plan has been declared
716 Test::Builder->new->current_test
718 Test::Builder->new->has_plan
720 } and croak("Unable to invoke -skip_all_without after testing has started");
722 if ( my $missing = $class->req_missing_for(\@_) ) {
724 die ("\nMandatory requirements not satisfied during release-testing: $missing\n\n")
725 if $ENV{RELEASE_TESTING} and $class->_groups_to_reqs(\@_)->{release_testing_mandatory};
727 print "1..0 # SKIP requirements not satisfied: $missing\n";
731 elsif ($action =~ /^-/) {
732 croak "Unknown import-time action '$action'";
735 croak "$class is not an exporter, unable to import '$action'";
743 croak( __PACKAGE__ . " does not implement unimport" );
746 # OO for (mistakenly considered) ease of extensibility, not due to any need to
747 # carry state of any sort. This API is currently used outside, so leave as-is.
748 # FIXME - make sure to not propagate this further if module is extracted as a
749 # standalone library - keep the stupidity to a DBIC-secific shim!
752 shift->_groups_to_reqs(shift)->{effective_modreqs};
755 sub modreq_list_for {
756 shift->_groups_to_reqs(shift)->{modreqs};
761 { $_ => $_[0]->_groups_to_reqs($_) }
762 grep { $_ !~ /^_/ } keys %$dbic_reqs
766 sub req_errorlist_for { shift->modreq_errorlist_for(shift) } # deprecated
767 sub modreq_errorlist_for {
768 my ($self, $groups) = @_;
769 $self->_errorlist_for_modreqs( $self->_groups_to_reqs($groups)->{modreqs} );
773 shift->req_missing_for(shift) ? 0 : 1;
776 sub req_missing_for {
777 my ($self, $groups) = @_;
779 my $reqs = $self->_groups_to_reqs($groups);
781 my $mods_missing = $reqs->{missing_envvars}
782 ? $self->_list_physically_missing_modules( $reqs->{modreqs} )
783 : $self->modreq_missing_for($groups)
789 ! $reqs->{missing_envvars}
792 my @res = $mods_missing || ();
794 push @res, 'the following group(s) of environment variables: ' . join ' and ', sort map
795 { __envvar_group_desc($_) }
796 @{$reqs->{missing_envvars}}
797 if $reqs->{missing_envvars};
800 ( join ' as well as ', @res )
802 ( $reqs->{modreqs_fully_documented} ? " (see @{[ ref $self || $self ]} documentation for details)" : '' ),
806 sub modreq_missing_for {
807 my ($self, $groups) = @_;
809 my $reqs = $self->_groups_to_reqs($groups);
810 my $modreq_errors = $self->_errorlist_for_modreqs($reqs->{modreqs})
814 { $reqs->{modreqs}{$_} ? "$_~$reqs->{modreqs}{$_}" : $_ }
815 sort { lc($a) cmp lc($b) } keys %$modreq_errors
821 my ($self, $groups) = @_;
823 $tb ||= do { local $@; eval { Test::Builder->new } }
824 or croak "Calling skip_without() before loading Test::Builder makes no sense";
826 if ( my $err = $self->req_missing_for($groups) ) {
827 my ($fn, $ln) = (caller(0))[1,2];
828 $tb->skip("block in $fn around line $ln requires $err");
836 sub die_unless_req_ok_for {
837 if (my $err = shift->req_missing_for(shift) ) {
838 die "Unable to continue due to missing requirements: $err\n";
844 ### Private functions
846 # potentially shorten group desc
847 sub __envvar_group_desc {
850 my (@res, $last_prefix);
851 while (my $ev = shift @envs) {
852 my ($pref, $sep, $suff) = split / ([\_\-]) (?= [^\_\-]+ \z )/x, $ev;
854 if ( defined $sep and ($last_prefix||'') eq $pref ) {
855 push @res, "...${sep}${suff}"
861 $last_prefix = $pref if $sep;
867 my $groupname_re = qr/ [a-z_] [0-9_a-z]* /x;
868 my $modname_re = qr/ [A-Z_a-z] [0-9A-Z_a-z]* (?:::[0-9A-Z_a-z]+)* /x;
869 my $modver_re = qr/ [0-9]+ (?: \. [0-9]+ )? /x;
871 # Expand includes from a random group in a specific order:
872 # nonvariable groups first, then their includes, then the variable groups,
873 # then their includes.
874 # This allows reliably marking the rest of the mod reqs as variable (this is
875 # also why variable includes are currently not allowed)
876 sub __expand_includes {
877 my ($groups, $seen) = @_;
879 # !! DIFFERENT !! behavior and return depending on invocation mode
880 # (easier to recurse this way)
881 my $is_toplevel = $seen
886 my ($res_per_type, $missing_envvars);
888 # breadth-first evaluation, with non-variable includes on top
889 for my $g (@$groups) {
891 croak "Invalid requirement group name '$g': only ascii alphanumerics and _ are allowed"
892 if $g !~ qr/ \A $groupname_re \z/x;
894 my $r = $dbic_reqs->{$g}
895 or croak "Requirement group '$g' is not defined";
897 # always do this check *before* the $seen check
898 croak "Group '$g' with variable effective_modreqs can not be specified as an 'include'"
899 if ( $r->{env} and ! $is_toplevel );
901 next if $seen->{$g}++;
903 my $req_type = 'static';
905 if ( my @e = @{$r->{env}||[]} ) {
907 croak "Unexpected 'env' attribute under group '$g' (only allowed in test_* groups)"
908 unless $g =~ /^test_/;
910 croak "Unexpected *odd* list in 'env' under group '$g'"
913 # deconstruct the whole thing
914 my (@group_envnames_list, $some_envs_required, $some_required_missing);
916 push @group_envnames_list, my $envname = shift @e;
918 # env required or not
919 next unless shift @e;
921 $some_envs_required ||= 1;
923 $some_required_missing ||= (
924 ! defined $ENV{$envname}
926 ! length $ENV{$envname}
930 croak "None of the envvars in group '$g' declared as required, making the requirement moot"
931 unless $some_envs_required;
933 if ($some_required_missing) {
934 push @{$missing_envvars->{$g}}, \@group_envnames_list;
935 $req_type = 'variable';
939 push @{$res_per_type->{"base_${req_type}"}}, $g;
941 if (my $i = $dbic_reqs->{$g}{include}) {
942 $i = [ $i ] unless ref $i eq 'ARRAY';
944 croak "Malformed 'include' for group '$g': must be another existing group name or arrayref of existing group names"
947 push @{$res_per_type->{"incs_${req_type}"}}, @$i;
952 @{ $res_per_type->{"base_${_}"} || [] },
953 ( $res_per_type->{"incs_${_}"} ? __expand_includes( $res_per_type->{"incs_${_}"}, $seen ) : () ),
954 } qw(static variable);
956 return ! $is_toplevel ? @ret : do {
959 idx => 1 + keys %$rv,
960 missing_envvars => $missing_envvars->{$_},
962 $rv->{$_}{user_requested} = 1 for @$groups;
968 our %req_unavailability_cache;
970 # this method is just a lister and envvar/metadata checker - it does not try to load anything
971 sub _groups_to_reqs {
972 my ($self, $want) = @_;
974 $want = [ $want || () ]
975 unless ref $want eq 'ARRAY';
977 croak "@{[ (caller(1))[3] ]}() expects a requirement group name or arrayref of group names"
982 modreqs_fully_documented => 1,
986 for my $piece (@$want) {
987 if ($piece =~ qr/ \A $groupname_re \z /x) {
988 push @$groups, $piece;
990 elsif ( my ($mod, $ver) = $piece =~ qr/ \A ($modname_re) \>\= ($modver_re) \z /x ) {
991 croak "Ad hoc module specification lists '$mod' twice"
992 if exists $ret->{modreqs}{$mod};
994 croak "Ad hoc module specification '${mod} >= $ver' (or greater) not listed in the test_adhoc optdep group" if (
995 ! defined $dbic_reqs->{test_adhoc}{req}{$mod}
997 $dbic_reqs->{test_adhoc}{req}{$mod} < $ver
1000 $ret->{modreqs}{$mod} = $ver;
1001 $ret->{modreqs_fully_documented} = 0;
1004 croak "Unsupported argument '$piece' supplied to @{[ (caller(1))[3] ]}()"
1008 my $all_groups = __expand_includes($groups);
1010 # pre-assemble list of augmentations, perform basic sanity checks
1011 # Note that below we *DO NOT* respect the source/target reationship, but
1012 # instead always default to augment the "later" group
1013 # This is done so that the "stable/variable" boundary keeps working as
1016 for my $requesting_group (keys %$all_groups) {
1017 if (my $ag = $dbic_reqs->{$requesting_group}{augment}) {
1018 for my $target_group (keys %$ag) {
1020 croak "Group '$requesting_group' claims to augment a non-existent group '$target_group'"
1021 unless $dbic_reqs->{$target_group};
1023 croak "Augmentation combined with variable effective_modreqs currently unsupported for group '$requesting_group'"
1024 if $dbic_reqs->{$requesting_group}{env};
1026 croak "Augmentation of group '$target_group' with variable effective_modreqs unsupported (requested by '$requesting_group')"
1027 if $dbic_reqs->{$target_group}{env};
1029 if (my @foreign = grep { $_ ne 'req' } keys %{$ag->{$target_group}} ) {
1030 croak "Only 'req' augmentations are currently supported (group '$requesting_group' attempts to alter '$foreign[0]' of group '$target_group'";
1033 $ret->{augments}{$target_group} = 1;
1035 # no augmentation for stuff that hasn't been selected
1036 if ( $all_groups->{$target_group} and my $ar = $ag->{$target_group}{req} ) {
1037 push @{$augmentations->{
1038 ( $all_groups->{$requesting_group}{idx} < $all_groups->{$target_group}{idx} )
1047 for my $group (sort { $all_groups->{$a}{idx} <=> $all_groups->{$b}{idx} } keys %$all_groups ) {
1049 my $group_reqs = $dbic_reqs->{$group}{req};
1052 for my $req_bag ($group_reqs, @{ $augmentations->{$group} || [] } ) {
1053 for (keys %$req_bag) {
1055 $_ =~ / \A $modname_re \z /x
1056 or croak "Requirement '$_' in group '$group' is not a valid module name";
1058 # !!!DO NOT CHANGE!!!
1059 # remember - version.pm may not be available on the system
1060 croak "Requirement '$_' in group '$group' specifies an invalid version '$req_bag->{$_}' (only plain non-underscored floating point decimals are supported)"
1061 if ( ($req_bag->{$_}||0) !~ qr/ \A $modver_re \z /x );
1065 if (my $e = $all_groups->{$group}{missing_envvars}) {
1066 push @{$ret->{missing_envvars}}, @$e;
1069 # assemble into the final ret
1072 ( $ret->{missing_envvars} ? () : 'effective_modreqs' ),
1074 for my $req_bag ($group_reqs, @{ $augmentations->{$group} || [] } ) {
1075 for my $mod (keys %$req_bag) {
1077 $ret->{$type}{$mod} = $req_bag->{$mod}||0 if (
1079 ! exists $ret->{$type}{$mod}
1081 # we sanitized the version to be numeric above - we can just -gt it
1082 ($req_bag->{$mod}||0) > $ret->{$type}{$mod}
1089 $ret->{modreqs_fully_documented} &&= !!$dbic_reqs->{$group}{pod}
1090 if $all_groups->{$group}{user_requested};
1092 $ret->{release_testing_mandatory} ||= !!$dbic_reqs->{$group}{release_testing_mandatory};
1099 # this method tries to find/load specified modreqs and returns a hashref of
1100 # module/loaderror pairs for anything that failed
1101 sub _errorlist_for_modreqs {
1102 # args supposedly already went through _groups_to_reqs and are therefore sanitized
1103 # safe to eval at will
1104 my ($self, $reqs) = @_;
1108 for my $m ( keys %$reqs ) {
1109 my $v = $reqs->{$m};
1111 if (! exists $req_unavailability_cache{$m}{$v} ) {
1113 eval( "require $m;" . ( $v ? "$m->VERSION(q($v))" : '' ) );
1114 $req_unavailability_cache{$m}{$v} = $@;
1117 $ret->{$m} = $req_unavailability_cache{$m}{$v}
1118 if $req_unavailability_cache{$m}{$v};
1124 # Unlike the above DO NOT try to load anything
1125 # This is executed when some needed envvars are not available
1126 # which in turn means a module load will never be reached anyway
1127 # This is important because some modules (especially DBDs) can be
1128 # *really* fickle when a require() is attempted, with pretty confusing
1129 # side-effects (especially on windows)
1130 sub _list_physically_missing_modules {
1131 my ($self, $modreqs) = @_;
1133 # in case there is a coderef in @INC there is nothing we can definitively prove
1134 # so short circuit directly
1135 return '' if grep { length ref $_ } @INC;
1137 my @definitely_missing;
1138 for my $mod (keys %$modreqs) {
1139 (my $fn = $mod . '.pm') =~ s|::|/|g;
1141 push @definitely_missing, $mod unless grep
1142 # this should work on any combination of slashes
1143 { $_ and -d $_ and -f "$_/$fn" and -r "$_/$fn" }
1149 { $modreqs->{$_} ? "$_~$modreqs->{$_}" : $_ }
1150 sort { lc($a) cmp lc($b) } @definitely_missing
1155 # This is to be called by the author only (automatically in Makefile.PL)
1157 my ($class, $distver, $pod_dir) = @_;
1159 die "No POD root dir supplied" unless $pod_dir;
1162 eval { require DBIx::Class; DBIx::Class->VERSION; }
1165 "\n\n---------------------------------------------------------------------\n" .
1166 'Unable to load core DBIx::Class module to determine current version, '.
1167 'possibly due to missing dependencies. Author-mode autodocumentation ' .
1169 "\n\n---------------------------------------------------------------------\n"
1172 # do not ask for a recent version, use 1.x API calls
1173 # this *may* execute on a smoker with old perl or whatnot
1176 (my $modfn = __PACKAGE__ . '.pm') =~ s|::|/|g;
1178 (my $podfn = "$pod_dir/$modfn") =~ s/\.pm$/\.pod/;
1179 (my $dir = $podfn) =~ s|/[^/]+$||;
1181 File::Path::mkpath([$dir]);
1183 my $sqltver = $class->req_list_for('deploy')->{'SQL::Translator'}
1184 or die "Hrmm? No sqlt dep?";
1192 push @chunks, <<"EOC";
1193 #########################################################################
1194 ##################### A U T O G E N E R A T E D ########################
1195 #########################################################################
1197 # The contents of this POD file are auto-generated. Any changes you make
1198 # will be lost. If you need to change the generated text edit _gen_pod()
1199 # at the end of $modfn
1204 $class - Optional module dependency specifications (for module authors)
1209 #@@ SYNOPSIS HEADING
1211 push @chunks, <<"EOC";
1214 Somewhere in your build-file (e.g. L<ExtUtils::MakeMaker>'s F<Makefile.PL>):
1218 \$EUMM_ARGS{CONFIGURE_REQUIRES} = {
1219 \%{ \$EUMM_ARGS{CONFIGURE_REQUIRES} || {} },
1220 'DBIx::Class' => '$distver',
1225 my %DBIC_DEPLOY_AND_ORACLE_DEPS = %{ eval {
1227 $class->req_list_for([qw( deploy rdbms_oracle ic_dt )]);
1230 \$EUMM_ARGS{PREREQ_PM} = {
1231 \%DBIC_DEPLOY_AND_ORACLE_DEPS,
1232 \%{ \$EUMM_ARGS{PREREQ_PM} || {} },
1237 ExtUtils::MakeMaker::WriteMakefile(\%EUMM_ARGS);
1239 B<Note>: The C<eval> protection within the example is due to support for
1240 requirements during L<the C<configure> build phase|CPAN::Meta::Spec/Phases>
1241 not being available on a sufficient portion of production installations of
1242 Perl. Robust support for such dependency requirements is available in the
1243 L<CPAN> installer only since version C<1.94_56> first made available for
1244 production with perl version C<5.12>. It is the belief of the current
1245 maintainer that support for requirements during the C<configure> build phase
1246 will not be sufficiently ubiquitous until the B<year 2020> at the earliest,
1247 hence the extra care demonstrated above. It should also be noted that some
1248 3rd party installers (e.g. L<cpanminus|App::cpanminus>) do the right thing
1249 with configure requirements independent from the versions of perl and CPAN
1255 #@@ DESCRIPTION HEADING
1257 push @chunks, <<'EOC';
1260 Some of the less-frequently used features of L<DBIx::Class> have external
1261 module dependencies on their own. In order not to burden the average user
1262 with modules they will never use, these optional dependencies are not included
1263 in the base Makefile.PL. Instead an exception with a descriptive message is
1264 thrown when a specific feature can't find one or several modules required for
1265 its operation. This module is the central holding place for the current list
1266 of such dependencies, for DBIx::Class core authors, and DBIx::Class extension
1269 Dependencies are organized in L<groups|/CURRENT REQUIREMENT GROUPS> where each
1270 group can list one or more required modules, with an optional minimum version
1271 (or 0 for any version). In addition groups prefixed with C<test_> can specify
1272 a set of environment variables, some (or all) of which are marked as required
1273 for the group to be considered by L</req_list_for>
1275 Each group name (or a combination thereof) can be used in the
1276 L<public methods|/METHODS> as described below.
1281 #@@ REQUIREMENT GROUPLIST HEADING
1283 push @chunks, '=head1 CURRENT REQUIREMENT GROUPS';
1285 my $standalone_info;
1287 for my $group (sort keys %$dbic_reqs) {
1289 my $info = $standalone_info->{$group} ||= $class->_groups_to_reqs($group);
1292 $info->{modreqs_fully_documented}
1294 ( $info->{augments} or $info->{modreqs} )
1297 my $p = $dbic_reqs->{$group}{pod};
1300 "=head2 $p->{title}",
1306 if ( keys %{ $info->{modreqs}||{} } ) {
1308 { "=item * $_" . ($info->{modreqs}{$_} ? " >= $info->{modreqs}{$_}" : '') }
1309 ( sort keys %{ $info->{modreqs} } )
1313 push @chunks, '=item * No standalone requirements',
1316 push @chunks, '=back';
1318 for my $ag ( sort keys %{ $info->{augments} || {} } ) {
1319 my $ag_info = $standalone_info->{$ag} ||= $class->_groups_to_reqs($ag);
1321 my $newreqs = $class->modreq_list_for([ $group, $ag ]);
1322 for (keys %$newreqs) {
1323 delete $newreqs->{$_} if (
1324 ( defined $info->{modreqs}{$_} and $info->{modreqs}{$_} == $newreqs->{$_} )
1326 ( defined $ag_info->{modreqs}{$_} and $ag_info->{modreqs}{$_} == $newreqs->{$_} )
1330 if (keys %$newreqs) {
1332 "Combined with L</$ag> additionally requires:",
1335 { "=item * $_" . ($newreqs->{$_} ? " >= $newreqs->{$_}" : '') }
1336 ( sort keys %$newreqs )
1346 #@@ API DOCUMENTATION HEADING
1348 push @chunks, <<'EOC';
1350 =head1 IMPORT-LIKE ACTIONS
1352 Even though this module is not an L<Exporter>, it recognizes several C<actions>
1353 supplied to its C<import> method.
1355 =head2 -skip_all_without
1359 =item Arguments: @group_names
1363 A convenience wrapper for use during testing:
1366 push @chunks, " use $class -skip_all_without => qw(admin test_rdbms_mysql);";
1368 push @chunks, 'Roughly equivalent to the following code:';
1370 push @chunks, sprintf <<'EOS', ($class) x 2;
1374 if ( my $missing = %s->req_missing_for(\@group_names_) ) {
1375 print "1..0 # SKIP requirements not satisfied: $missing\n";
1381 push @chunks, <<'EOC';
1383 It also takes into account the C<RELEASE_TESTING> environment variable and
1384 behaves like L</-die_without> for any requirement groups marked as
1385 C<release_testing_mandatory>.
1391 =item Arguments: @group_names
1395 A convenience wrapper around L</die_unless_req_ok_for>:
1398 push @chunks, " use $class -die_without => qw(deploy admin);";
1400 push @chunks, <<'EOC';
1402 =head2 -list_missing
1406 =item Arguments: @group_names
1410 A convenience wrapper around L</modreq_missing_for>:
1412 perl -Ilib -MDBIx::Class::Optional::Dependencies=-list_missing,deploy,admin | cpanm
1416 =head2 req_group_list
1420 =item Arguments: none
1422 =item Return Value: \%list_of_requirement_groups
1426 This method should be used by DBIx::Class packagers, to get a hashref of all
1427 dependencies B<keyed> by dependency group. Each key (group name), or a combination
1428 thereof (as an arrayref) can be supplied to the methods below.
1429 The B<values> of the returned hash are currently a set of options B<without a
1430 well defined structure>. If you have use for any of the contents - contact the
1431 maintainers, instead of treating this as public (left alone stable) API.
1437 =item Arguments: $group_name | \@group_names
1439 =item Return Value: \%set_of_module_version_pairs
1443 This method should be used by DBIx::Class extension authors, to determine the
1444 version of modules a specific set of features requires for this version of
1445 DBIx::Class (regardless of their availability on the system).
1446 See the L</SYNOPSIS> for a real-world example.
1448 When handling C<test_*> groups this method behaves B<differently> from
1449 L</modreq_list_for> below (and is the only such inconsistency among the
1450 C<req_*> methods). If a particular group declares as requirements some
1451 C<environment variables> and these requirements are not satisfied (the envvars
1452 are unset) - then the C<module requirements> of this group are not included in
1455 =head2 modreq_list_for
1459 =item Arguments: $group_name | \@group_names
1461 =item Return Value: \%set_of_module_version_pairs
1465 Same as L</req_list_for> but does not take into consideration any
1466 C<environment variable requirements> - returns just the list of required
1473 =item Arguments: $group_name | \@group_names
1475 =item Return Value: 1|0
1479 Returns true or false depending on whether all modules/envvars required by
1480 the group(s) are loadable/set on the system.
1482 =head2 req_missing_for
1486 =item Arguments: $group_name | \@group_names
1488 =item Return Value: $error_message_string
1492 Returns a single-line string suitable for inclusion in larger error messages.
1493 This method would normally be used by DBIx::Class core features, to indicate to
1494 the user that they need to install specific modules and/or set specific
1495 environment variables before being able to use a specific feature set.
1497 For example if some of the requirements for C<deploy> are not available,
1498 the returned string could look like:
1501 push @chunks, qq{ "SQL::Translator~$sqltver" (see $class documentation for details)};
1503 push @chunks, <<'EOC';
1504 The author is expected to prepend the necessary text to this message before
1505 returning the actual error seen by the user. See also L</modreq_missing_for>
1507 =head2 modreq_missing_for
1511 =item Arguments: $group_name | \@group_names
1513 =item Return Value: $error_message_string
1517 Same as L</req_missing_for> except that the error string is guaranteed to be
1518 either empty, or contain a set of module requirement specifications suitable
1519 for piping to e.g. L<cpanminus|App::cpanminus>. The method explicitly does not
1520 attempt to validate the state of required environment variables (if any).
1522 For instance if some of the requirements for C<deploy> are not available,
1523 the returned string could look like:
1526 push @chunks, qq{ "SQL::Translator~$sqltver"};
1528 push @chunks, <<'EOC';
1530 See also L</-list_missing>.
1536 =item Arguments: $group_name | \@group_names
1540 A convenience wrapper around L<skip|Test::More/SKIP>. It does not take neither
1541 a reason (it is generated by L</req_missing_for>) nor an amount of skipped tests
1542 (it is always C<1>, thus mandating unconditional use of
1543 L<done_testing|Test::More/done_testing>). Most useful in combination with ad hoc
1544 requirement specifications:
1547 push @chunks, <<EOC;
1549 $class->skip_without([ deploy YAML>=0.90 ]);
1555 push @chunks, <<'EOC';
1557 =head2 die_unless_req_ok_for
1561 =item Arguments: $group_name | \@group_names
1565 Checks if L</req_ok_for> passes for the supplied group(s), and
1566 in case of failure throws an exception including the information
1567 from L</req_missing_for>. See also L</-die_without>.
1569 =head2 modreq_errorlist_for
1573 =item Arguments: $group_name | \@group_names
1575 =item Return Value: \%set_of_loaderrors_per_module
1579 Returns a hashref containing the actual errors that occurred while attempting
1580 to load each module in the requirement group(s).
1582 =head2 req_errorlist_for
1584 Deprecated method name, equivalent (via proxy) to L</modreq_errorlist_for>.
1591 push @chunks, <<'EOC';
1592 =head1 FURTHER QUESTIONS?
1594 Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
1596 =head1 COPYRIGHT AND LICENSE
1598 This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
1599 by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
1600 redistribute it and/or modify it under the same terms as the
1601 L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.
1605 open (my $fh, '>', $podfn) or die;
1606 print $fh join ("\n\n", @chunks) or die;
1607 print $fh "\n" or die;
1609 } or croak( "Unable to write $podfn: " . ( $! || $@ || 'unknown error') );