Cleanup dependencies / Admin inheritance
[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',
36 'Hash::Merge' => '0.11',
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 => {
69 'SQL::Translator' => '0.11002',
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
77 author => {
f6b26571 78 req => {
79 'Test::Pod' => '1.26',
80 'Test::Pod::Coverage' => '1.08',
81 'Pod::Coverage' => '0.20',
82 #'Test::NoTabs' => '0.9',
83 #'Test::EOL' => '0.6',
84 },
8057ed01 85 },
86
87 core => {
f6b26571 88 req => {
89 # t/52cycle.t
90 'Test::Memory::Cycle' => '0',
91 'Devel::Cycle' => '1.10',
92
93 # t/36datetime.t
94 # t/60core.t
95 'DateTime::Format::SQLite' => '0',
96
97 # t/96_is_deteministic_value.t
98 'DateTime::Format::Strptime'=> '0',
99 },
8057ed01 100 },
101
102 cdbicompat => {
f6b26571 103 req => {
104 'DBIx::ContextualFetch' => '0',
105 'Class::DBI::Plugin::DeepAbstractSearch' => '0',
106 'Class::Trigger' => '0',
107 'Time::Piece::MySQL' => '0',
108 'Clone' => '0',
109 'Date::Simple' => '3.03',
110 },
8057ed01 111 },
112
113 rdbms_pg => {
f6b26571 114 req => {
115 $ENV{DBICTEST_PG_DSN}
116 ? (
117 'Sys::SigAction' => '0',
118 'DBD::Pg' => '2.009002',
119 'DateTime::Format::Pg' => '0',
120 ) : ()
121 },
8057ed01 122 },
123
124 rdbms_mysql => {
f6b26571 125 req => {
126 $ENV{DBICTEST_MYSQL_DSN}
127 ? (
128 'DateTime::Format::MySQL' => '0',
129 'DBD::mysql' => '0',
130 ) : ()
131 },
8057ed01 132 },
133
134 rdbms_oracle => {
f6b26571 135 req => {
136 $ENV{DBICTEST_ORA_DSN}
137 ? (
138 'DateTime::Format::Oracle' => '0',
139 ) : ()
140 },
8057ed01 141 },
142
143 rdbms_ase => {
f6b26571 144 req => {
145 $ENV{DBICTEST_SYBASE_DSN}
146 ? (
147 'DateTime::Format::Sybase' => 0,
148 ) : ()
149 },
8057ed01 150 },
151
152 rdbms_asa => {
f6b26571 153 req => {
154 grep $_, @ENV{qw/DBICTEST_SYBASE_ASA_DSN DBICTEST_SYBASE_ASA_ODBC_DSN/}
155 ? (
156 'DateTime::Format::Strptime' => 0,
157 ) : ()
158 },
8057ed01 159 },
160};
161
f6b26571 162
0d4740b3 163sub _all_optional_requirements {
f6b26571 164 return { map { %{ $reqs->{$_}{req} || {} } } (keys %$reqs) };
8057ed01 165}
166
fb39747c 167sub req_list_for {
168 my ($class, $group) = @_;
169
f6b26571 170 croak "req_list_for() expects a requirement group name"
fb39747c 171 unless $group;
172
f6b26571 173 my $deps = $reqs->{$group}{req}
174 or croak "Requirement group '$group' does not exist";
fb39747c 175
176 return { %$deps };
177}
178
179
180our %req_availability_cache;
181sub req_ok_for {
182 my ($class, $group) = @_;
183
184 croak "req_ok_for() expects a requirement group name"
185 unless $group;
186
187 $class->_check_deps ($group) unless $req_availability_cache{$group};
188
189 return $req_availability_cache{$group}{status};
190}
191
192sub req_missing_for {
193 my ($class, $group) = @_;
194
195 croak "req_missing_for() expects a requirement group name"
196 unless $group;
197
198 $class->_check_deps ($group) unless $req_availability_cache{$group};
199
200 return $req_availability_cache{$group}{missing};
201}
202
203sub req_errorlist_for {
204 my ($class, $group) = @_;
205
206 croak "req_errorlist_for() expects a requirement group name"
207 unless $group;
208
209 $class->_check_deps ($group) unless $req_availability_cache{$group};
210
211 return $req_availability_cache{$group}{errorlist};
212}
213
214sub _check_deps {
215 my ($class, $group) = @_;
216
f6b26571 217 my $deps = $class->req_list_for ($group);
fb39747c 218
219 my %errors;
220 for my $mod (keys %$deps) {
221 if (my $ver = $deps->{$mod}) {
222 eval "use $mod $ver ()";
223 }
224 else {
225 eval "require $mod";
226 }
227
228 $errors{$mod} = $@ if $@;
229 }
230
231 if (keys %errors) {
f6b26571 232 my $missing = join (', ', map { $deps->{$_} ? "$_ >= $deps->{$_}" : $_ } (sort keys %errors) );
233 $missing .= " (see $class for details)" if $reqs->{$group}{pod};
fb39747c 234 $req_availability_cache{$group} = {
235 status => 0,
236 errorlist => { %errors },
f6b26571 237 missing => $missing,
fb39747c 238 };
239 }
240 else {
241 $req_availability_cache{$group} = {
242 status => 1,
243 errorlist => {},
244 missing => '',
245 };
246 }
247}
248
f6b26571 249sub _gen_pod {
250 my $class = shift;
af4ac504 251 my $modfn = __PACKAGE__ . '.pm';
252 $modfn =~ s/\:\:/\//g;
f6b26571 253
254 my @chunks = (
af4ac504 255 <<"EOC",
256#########################################################################
257##################### A U T O G E N E R A T E D ########################
258#########################################################################
259#
260# The contents of this POD file are auto-generated. Any changes you make
261# will be lost. If you need to change the generated text edit _gen_pod()
262# at the end of $modfn
263#
264EOC
f6b26571 265 '=head1 NAME',
266 "$class - Optional module dependency specifications",
267 '=head1 DESCRIPTION',
268 <<'EOD',
269Some of the less-frequently used features of L<DBIx::Class> have external
270module dependencies on their own. In order not to burden the average user
271with modules he will never use, these optional dependencies are not included
272in the base Makefile.PL. Instead an exception with a descriptive message is
273thrown when a specific feature is missing one or several modules required for
274its operation. This module is the central holding place for the current list
275of such dependencies.
276EOD
277 '=head1 CURRENT REQUIREMENT GROUPS',
278 <<'EOD',
279Dependencies are organized in C<groups> and each group can list one or more
280required modules, with an optional minimum version (or 0 for any version).
281The group name can be used in the
282EOD
283 );
284
285 for my $group (sort keys %$reqs) {
286 my $p = $reqs->{$group}{pod}
287 or next;
288
289 my $modlist = $reqs->{$group}{req}
290 or next;
291
292 next unless keys %$modlist;
293
294 push @chunks, (
295 "=head2 $p->{title}",
296 "$p->{desc}",
297 '=over',
298 ( map { "=item * $_" . ($modlist->{$_} ? " >= $modlist->{$_}" : '') } (sort keys %$modlist) ),
299 '=back',
300 "Requirement group: B<$group>",
301 );
302 }
303
304 push @chunks, (
305 '=head1 METHODS',
306 '=head2 req_list_for',
307 '=over',
308 '=item Arguments: $group_name',
309 '=item Returns: \%list_of_module_version_pairs',
310 '=back',
311 <<EOD,
312This method should be used by DBIx::Class extension authors, to determine the
313version of modules which a specific feature requires in the current version of
314DBIx::Class. For example if you write a module/extension that requires
315DBIx::Class and also requires the availability of
316L<DBIx::Class::Storage::DBI/deploy>, you can do the following in your
317C<Makefile.PL> or C<Build.PL>
318
319 require $class;
320 my \$dep_list = $class->req_list_for ('deploy');
321
322Which will give you a list of module/version pairs necessary for the particular
323feature to function with this version of DBIx::Class.
324EOD
325
326 '=head2 req_ok_for',
327 '=over',
328 '=item Arguments: $group_name',
329 '=item Returns: 1|0',
330 '=back',
af4ac504 331 'Returns true or false depending on whether all modules required by C<$group_name> are present on the system and loadable',
f6b26571 332
333 '=head2 req_missing_for',
334 '=over',
335 '=item Arguments: $group_name',
336 '=item Returns: $error_message_string',
337 '=back',
338 <<EOD,
339Returns a single line string suitable for inclusion in larger error messages.
340This method would normally be used by DBIx::Class core-module author, to
341indicate to the user that he needs to install specific modules before he will
342be able to use a specific feature.
343
344For example if the requirements for C<replicated> are not available, the
345returned string would look like:
346
347 Moose >= 0.98, MooseX::Types >= 0.21, namespace::clean (see $class for details)
348
349The author is expected to prepend the necessary text to this message before
350returning the actual error seen by the user.
351EOD
352
353 '=head2 req_errorlist_for',
354 '=over',
355 '=item Arguments: $group_name',
356 '=item Returns: \%list_of_loaderrors_per_module',
357 '=back',
358 <<'EOD',
359Returns a hashref containing the actual errors that occured while attempting
360to load each module in the requirement group.
361EOD
fb8ae353 362 '=head1 AUTHOR',
363 'See L<DBIx::Class/CONTRIBUTORS>.',
364 '=head1 LICENSE',
365 'You may distribute this code under the same terms as Perl itself',
f6b26571 366 );
367
368 my $fn = __FILE__;
369 $fn =~ s/\.pm$/\.pod/;
370
371 open (my $fh, '>', $fn) or croak "Unable to write to $fn: $!";
372 print $fh join ("\n\n", @chunks);
373 close ($fh);
374}
375
8057ed01 3761;