Unmark Opt::Deps experimental and add extra method as per RT55211
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Optional / Dependencies.pm
CommitLineData
8057ed01 1package DBIx::Class::Optional::Dependencies;
2
3use warnings;
4use strict;
5
fb39747c 6use Carp;
7
8# NO EXTERNAL NON-5.8.1 CORE DEPENDENCIES EVER (e.g. C::A::G)
8057ed01 9# This module is to be loaded by Makefile.PM on a pristine system
10
f6b26571 11# POD is generated automatically by calling _gen_pod from the
12# Makefile.PL in $AUTHOR mode
13
2b48ebff 14my $moose_basic = {
15 'Moose' => '0.98',
16 'MooseX::Types' => '0.21',
17};
18
ebcd0e4f 19my $admin_basic = {
20 %$moose_basic,
21 'MooseX::Types::Path::Class' => '0.05',
22 'MooseX::Types::JSON' => '0.02',
cba24c70 23 'JSON::Any' => '1.22',
ebcd0e4f 24 'namespace::autoclean' => '0.09',
ebcd0e4f 25};
26
8057ed01 27my $reqs = {
28 dist => {
29 #'Module::Install::Pod::Inherit' => '0.01',
30 },
31
32 replicated => {
f6b26571 33 req => {
2b48ebff 34 %$moose_basic,
f6b26571 35 'namespace::clean' => '0.11',
e666c5fd 36 'Hash::Merge' => '0.12',
f6b26571 37 },
38 pod => {
39 title => 'Storage::Replicated',
40 desc => 'Modules required for L<DBIx::Class::Storage::DBI::Replicated>',
41 },
8057ed01 42 },
43
44 admin => {
2b48ebff 45 req => {
ebcd0e4f 46 %$admin_basic,
47 },
48 pod => {
49 title => 'DBIx::Class::Admin',
50 desc => 'Modules required for the DBIx::Class administrative library',
51 },
52 },
53
a4a02f15 54 admin_script => {
ebcd0e4f 55 req => {
2b48ebff 56 %$moose_basic,
ebcd0e4f 57 %$admin_basic,
2b48ebff 58 'Getopt::Long::Descriptive' => '0.081',
2b48ebff 59 'Text::CSV' => '1.16',
60 },
e144415f 61 pod => {
62 title => 'dbicadmin',
63 desc => 'Modules required for the CLI DBIx::Class interface dbicadmin',
64 },
8057ed01 65 },
66
67 deploy => {
f6b26571 68 req => {
270edb2b 69 'SQL::Translator' => '0.11005',
f6b26571 70 },
71 pod => {
72 title => 'Storage::DBI::deploy()',
73 desc => 'Modules required for L<DBIx::Class::Storage::DBI/deploy> and L<DBIx::Class::Storage::DBI/deploymen_statements>',
74 },
8057ed01 75 },
76
a109c954 77
78 test_pod => {
f6b26571 79 req => {
14d17d71 80 'Test::Pod' => '1.41',
a109c954 81 },
82 },
83
84 test_podcoverage => {
85 req => {
f6b26571 86 'Test::Pod::Coverage' => '1.08',
87 'Pod::Coverage' => '0.20',
a109c954 88 },
89 },
90
91 test_notabs => {
92 req => {
f6b26571 93 #'Test::NoTabs' => '0.9',
a109c954 94 },
95 },
96
97 test_eol => {
98 req => {
f6b26571 99 #'Test::EOL' => '0.6',
100 },
8057ed01 101 },
102
a109c954 103 test_cycle => {
f6b26571 104 req => {
f6b26571 105 'Test::Memory::Cycle' => '0',
106 'Devel::Cycle' => '1.10',
a109c954 107 },
108 },
f6b26571 109
a109c954 110 test_dtrelated => {
111 req => {
f6b26571 112 # t/36datetime.t
113 # t/60core.t
114 'DateTime::Format::SQLite' => '0',
115
116 # t/96_is_deteministic_value.t
117 'DateTime::Format::Strptime'=> '0',
9c92bb1c 118
119 # t/inflate/datetime_mysql.t
120 # (doesn't need Mysql itself)
121 'DateTime::Format::MySQL' => '0',
122
123 # t/inflate/datetime_pg.t
124 # (doesn't need PG itself)
125 'DateTime::Format::Pg' => '0',
f6b26571 126 },
8057ed01 127 },
128
129 cdbicompat => {
f6b26571 130 req => {
131 'DBIx::ContextualFetch' => '0',
132 'Class::DBI::Plugin::DeepAbstractSearch' => '0',
133 'Class::Trigger' => '0',
134 'Time::Piece::MySQL' => '0',
135 'Clone' => '0',
136 'Date::Simple' => '3.03',
137 },
8057ed01 138 },
139
140 rdbms_pg => {
f6b26571 141 req => {
142 $ENV{DBICTEST_PG_DSN}
143 ? (
144 'Sys::SigAction' => '0',
145 'DBD::Pg' => '2.009002',
f6b26571 146 ) : ()
147 },
8057ed01 148 },
149
150 rdbms_mysql => {
f6b26571 151 req => {
152 $ENV{DBICTEST_MYSQL_DSN}
153 ? (
f6b26571 154 'DBD::mysql' => '0',
155 ) : ()
156 },
8057ed01 157 },
158
159 rdbms_oracle => {
f6b26571 160 req => {
161 $ENV{DBICTEST_ORA_DSN}
162 ? (
163 'DateTime::Format::Oracle' => '0',
164 ) : ()
165 },
8057ed01 166 },
167
168 rdbms_ase => {
f6b26571 169 req => {
170 $ENV{DBICTEST_SYBASE_DSN}
171 ? (
172 'DateTime::Format::Sybase' => 0,
173 ) : ()
174 },
8057ed01 175 },
176
177 rdbms_asa => {
f6b26571 178 req => {
bf9ee8dc 179 (scalar grep { $ENV{$_} } (qw/DBICTEST_SYBASE_ASA_DSN DBICTEST_SYBASE_ASA_ODBC_DSN/) )
f6b26571 180 ? (
181 'DateTime::Format::Strptime' => 0,
182 ) : ()
183 },
8057ed01 184 },
f58a165c 185
186 rdbms_db2 => {
187 req => {
188 $ENV{DBICTEST_DB2_DSN}
189 ? (
190 'DBD::DB2' => 0,
191 ) : ()
192 },
193 },
194
8057ed01 195};
196
f6b26571 197
fb39747c 198sub req_list_for {
199 my ($class, $group) = @_;
200
f6b26571 201 croak "req_list_for() expects a requirement group name"
fb39747c 202 unless $group;
203
f6b26571 204 my $deps = $reqs->{$group}{req}
205 or croak "Requirement group '$group' does not exist";
fb39747c 206
207 return { %$deps };
208}
209
210
211our %req_availability_cache;
212sub req_ok_for {
213 my ($class, $group) = @_;
214
215 croak "req_ok_for() expects a requirement group name"
216 unless $group;
217
218 $class->_check_deps ($group) unless $req_availability_cache{$group};
219
220 return $req_availability_cache{$group}{status};
221}
222
223sub req_missing_for {
224 my ($class, $group) = @_;
225
226 croak "req_missing_for() expects a requirement group name"
227 unless $group;
228
229 $class->_check_deps ($group) unless $req_availability_cache{$group};
230
231 return $req_availability_cache{$group}{missing};
232}
233
234sub req_errorlist_for {
235 my ($class, $group) = @_;
236
237 croak "req_errorlist_for() expects a requirement group name"
238 unless $group;
239
240 $class->_check_deps ($group) unless $req_availability_cache{$group};
241
242 return $req_availability_cache{$group}{errorlist};
243}
244
245sub _check_deps {
246 my ($class, $group) = @_;
247
f6b26571 248 my $deps = $class->req_list_for ($group);
fb39747c 249
250 my %errors;
251 for my $mod (keys %$deps) {
252 if (my $ver = $deps->{$mod}) {
253 eval "use $mod $ver ()";
254 }
255 else {
256 eval "require $mod";
257 }
258
259 $errors{$mod} = $@ if $@;
260 }
261
262 if (keys %errors) {
f6b26571 263 my $missing = join (', ', map { $deps->{$_} ? "$_ >= $deps->{$_}" : $_ } (sort keys %errors) );
264 $missing .= " (see $class for details)" if $reqs->{$group}{pod};
fb39747c 265 $req_availability_cache{$group} = {
266 status => 0,
267 errorlist => { %errors },
f6b26571 268 missing => $missing,
fb39747c 269 };
270 }
271 else {
272 $req_availability_cache{$group} = {
273 status => 1,
274 errorlist => {},
275 missing => '',
276 };
277 }
278}
279
e3fc11e1 280sub req_group_list {
281 return { map { $_ => { %{ $reqs->{$_}{req} || {} } } } (keys %$reqs) };
282}
283
284# This is to be called by the author only (automatically in Makefile.PL)
f6b26571 285sub _gen_pod {
286 my $class = shift;
af4ac504 287 my $modfn = __PACKAGE__ . '.pm';
288 $modfn =~ s/\:\:/\//g;
f6b26571 289
7e3dc46f 290 require DBIx::Class;
291 my $distver = DBIx::Class->VERSION;
e3fc11e1 292 my $sqltver = $class->req_list_for ('deploy')->{'SQL::Translator'}
293 or die "Hrmm? No sqlt dep?";
7e3dc46f 294
f6b26571 295 my @chunks = (
af4ac504 296 <<"EOC",
297#########################################################################
298##################### A U T O G E N E R A T E D ########################
299#########################################################################
300#
301# The contents of this POD file are auto-generated. Any changes you make
302# will be lost. If you need to change the generated text edit _gen_pod()
303# at the end of $modfn
304#
305EOC
f6b26571 306 '=head1 NAME',
7e3dc46f 307 "$class - Optional module dependency specifications (for module authors)",
e3fc11e1 308 '=head1 SYNOPSIS',
7e3dc46f 309 <<EOS,
7e3dc46f 310Somewhere in your build-file (e.g. L<Module::Install>'s Makefile.PL):
311
312 ...
313
314 configure_requires 'DBIx::Class' => '$distver';
315
316 require $class;
317
318 my \$deploy_deps = $class->req_list_for ('deploy');
319
320 for (keys %\$deploy_deps) {
321 requires \$_ => \$deploy_deps->{\$_};
322 }
323
324 ...
325
326Note that there are some caveats regarding C<configure_requires()>, more info
327can be found at L<Module::Install/configure_requires>
328EOS
f6b26571 329 '=head1 DESCRIPTION',
330 <<'EOD',
331Some of the less-frequently used features of L<DBIx::Class> have external
332module dependencies on their own. In order not to burden the average user
333with modules he will never use, these optional dependencies are not included
334in the base Makefile.PL. Instead an exception with a descriptive message is
335thrown when a specific feature is missing one or several modules required for
336its operation. This module is the central holding place for the current list
7e3dc46f 337of such dependencies, for DBIx::Class core authors, and DBIx::Class extension
338authors alike.
f6b26571 339EOD
340 '=head1 CURRENT REQUIREMENT GROUPS',
341 <<'EOD',
342Dependencies are organized in C<groups> and each group can list one or more
343required modules, with an optional minimum version (or 0 for any version).
344The group name can be used in the
345EOD
346 );
347
348 for my $group (sort keys %$reqs) {
349 my $p = $reqs->{$group}{pod}
350 or next;
351
352 my $modlist = $reqs->{$group}{req}
353 or next;
354
355 next unless keys %$modlist;
356
357 push @chunks, (
358 "=head2 $p->{title}",
359 "$p->{desc}",
360 '=over',
361 ( map { "=item * $_" . ($modlist->{$_} ? " >= $modlist->{$_}" : '') } (sort keys %$modlist) ),
362 '=back',
363 "Requirement group: B<$group>",
364 );
365 }
366
367 push @chunks, (
368 '=head1 METHODS',
e3fc11e1 369 '=head2 req_group_list',
370 '=over',
371 '=item Arguments: $none',
372 '=item Returns: \%list_of_requirement_groups',
373 '=back',
374 <<EOD,
375This method should be used by DBIx::Class packagers, to get a hashref of all
376dependencies keyed by dependency group. Each key (group name) can be supplied
377to one of the group-specific methods below.
378EOD
379
f6b26571 380 '=head2 req_list_for',
381 '=over',
382 '=item Arguments: $group_name',
383 '=item Returns: \%list_of_module_version_pairs',
384 '=back',
385 <<EOD,
386This method should be used by DBIx::Class extension authors, to determine the
7e3dc46f 387version of modules a specific feature requires in the B<current> version of
e3fc11e1 388DBIx::Class. See the L</SYNOPSIS> for a real-world
7e3dc46f 389example.
f6b26571 390EOD
391
392 '=head2 req_ok_for',
393 '=over',
394 '=item Arguments: $group_name',
395 '=item Returns: 1|0',
396 '=back',
af4ac504 397 'Returns true or false depending on whether all modules required by C<$group_name> are present on the system and loadable',
f6b26571 398
399 '=head2 req_missing_for',
400 '=over',
401 '=item Arguments: $group_name',
402 '=item Returns: $error_message_string',
403 '=back',
404 <<EOD,
405Returns a single line string suitable for inclusion in larger error messages.
406This method would normally be used by DBIx::Class core-module author, to
407indicate to the user that he needs to install specific modules before he will
408be able to use a specific feature.
409
e3fc11e1 410For example if some of the requirements for C<deploy> are not available,
411the returned string could look like:
f6b26571 412
e3fc11e1 413 SQL::Translator >= $sqltver (see $class for details)
f6b26571 414
415The author is expected to prepend the necessary text to this message before
416returning the actual error seen by the user.
417EOD
418
419 '=head2 req_errorlist_for',
420 '=over',
421 '=item Arguments: $group_name',
422 '=item Returns: \%list_of_loaderrors_per_module',
423 '=back',
424 <<'EOD',
425Returns a hashref containing the actual errors that occured while attempting
426to load each module in the requirement group.
427EOD
fb8ae353 428 '=head1 AUTHOR',
429 'See L<DBIx::Class/CONTRIBUTORS>.',
430 '=head1 LICENSE',
431 'You may distribute this code under the same terms as Perl itself',
f6b26571 432 );
433
434 my $fn = __FILE__;
435 $fn =~ s/\.pm$/\.pod/;
436
437 open (my $fh, '>', $fn) or croak "Unable to write to $fn: $!";
438 print $fh join ("\n\n", @chunks);
439 close ($fh);
440}
441
8057ed01 4421;