File Coverage

blib/lib/App/DH.pm
Criterion Covered Total %
statement 52 64 81.2
branch 3 8 37.5
condition n/a
subroutine 15 18 83.3
pod 0 6 0.0
total 70 96 72.9


line stmt bran cond sub pod time code
1 2     2   78175 use 5.006; # our
  2         7  
2 2     2   12 use strict;
  2         3  
  2         60  
3 2     2   11 use warnings;
  2         11  
  2         181  
4              
5             package App::DH;
6              
7             our $VERSION = '0.004001';
8              
9             # ABSTRACT: Deploy your DBIx::Class Schema to DDL/Database via DBIx::Class::DeploymentHandler
10              
11             our $AUTHORITY = 'cpan:MSTROUT'; # AUTHORITY
12              
13 2     2   12 use Carp qw( croak );
  2         2  
  2         148  
14 2     2   1453 use DBIx::Class::DeploymentHandler;
  2         2552736  
  2         78  
15 2     2   15 use Moose qw( with has around );
  2         3  
  2         14  
16 2     2   9089 use MooseX::Getopt 0.48 ();
  2         285697  
  2         110  
17 2     2   1217 use PerlX::Maybe qw( maybe );
  2         3504  
  2         2312  
18              
19             with 'MooseX::Getopt';
20              
21              
22              
23              
24              
25              
26              
27              
28              
29              
30              
31              
32              
33              
34             has connection_name => (
35             traits => ['Getopt'],
36             is => ro =>,
37             isa => Str =>,
38             required => 1,
39             cmd_aliases => c =>,
40             default => sub { 'development' },
41             documentation => 'either a valid DBI DSN or an alias configured by DBIx::Class::Schema::Config',
42             );
43              
44              
45              
46              
47              
48              
49              
50              
51              
52             has force => (
53             traits => ['Getopt'],
54             is => ro =>,
55             isa => Bool =>,
56             default => sub { 0 },
57             cmd_aliases => f =>,
58             documentation => 'forcefully replace existing DDLs. [DANGER]',
59             );
60              
61              
62              
63              
64              
65              
66              
67              
68              
69              
70              
71              
72             has schema => (
73             traits => ['Getopt'],
74             is => ro =>,
75             isa => Str =>,
76             required => 1,
77             cmd_aliases => s =>,
78             documentation => 'the class name of the schema to generate DDLs/deploy for',
79             );
80              
81              
82              
83              
84              
85              
86              
87              
88              
89              
90              
91              
92              
93              
94             has include => (
95             traits => ['Getopt'],
96             is => ro =>,
97             isa => ArrayRef =>,
98             default => sub { [] },
99             cmd_aliases => I =>,
100             documentation => 'paths to load into INC',
101             );
102              
103              
104              
105              
106              
107              
108              
109              
110              
111              
112              
113              
114              
115              
116             has script_dir => (
117             traits => ['Getopt'],
118             is => ro =>,
119             isa => Str =>,
120             default => sub { 'share/ddl' },
121             cmd_aliases => o =>,
122             documentation => 'output path',
123             );
124              
125              
126              
127              
128              
129              
130              
131              
132              
133              
134              
135              
136              
137              
138              
139              
140             has database => (
141             traits => ['Getopt'],
142             is => 'ro',
143             lazy => 1,
144             builder => '_build_database',
145             isa => ArrayRef =>,
146             cmd_aliases => d =>,
147             documentation => 'SQL::Translator::Producer::* database backends to generate DDLs for',
148             );
149              
150              
151              
152              
153              
154              
155              
156              
157              
158              
159              
160             has target => (
161             traits => ['Getopt'],
162             isa => 'Str',
163             is => 'ro',
164             predicate => 'has_target',
165             cmd_aliases => 'v',
166             documentation => 'version to install/upgrade to',
167             );
168              
169             has _dh => ( is => 'ro', lazy => 1, builder => '_build__dh' );
170             has _schema => ( is => 'ro', lazy => 1, builder => '_build__schema' );
171              
172             sub _build__schema {
173 3     3   4 my ($self) = @_;
174 3         563 require lib;
175 3         489 lib->import($_) for @{ $self->include };
  3         81  
176 3         316 require Module::Runtime;
177 3         88 my $class = Module::Runtime::use_module( $self->schema );
178 3         5701 return $class->connect( $self->connection_name );
179             }
180              
181             sub _build__dh {
182 3     3   6 my ($self) = @_;
183 3         78 return DBIx::Class::DeploymentHandler->new(
184             {
185             schema => $self->_schema,
186             force_overwrite => $self->force,
187             script_directory => $self->script_dir,
188             databases => $self->database,
189             maybe to_version => $self->target,
190             },
191             );
192             }
193              
194             sub _build_database {
195 3     3   8 my ($self) = @_;
196 3         89 my $type = $self->_schema->storage->sqlt_type;
197              
198             # Note: This seemingly needless stringification
199             # exists to solve an incredibly complex problem on bleadperl
200             # with COW, and for some reason, the string sqlt_type
201             # returns as the flag 'IsCOW',
202             # which for some reason causes a warning when the invoking
203             # perl interpreter terminates.
204             #
205             # If you can solve the bug in bleadperl, I'll
206             # gladly remove the forced stringification of the COW string.
207             #
208             # -- kentnl @ Feb 16/2013
209             # -- perl (v5.17.9 (v5.17.8-156-g012528a))
210 3         10338 return ["$type"];
211             }
212              
213              
214              
215              
216              
217              
218              
219              
220              
221             sub cmd_write_ddl {
222 0     0 0 0 my ($self) = @_;
223 0         0 $self->_dh->prepare_install;
224 0         0 my $v = $self->_dh->schema_version;
225 0 0       0 if ( $v > 1 ) {
226 0         0 $self->_dh->prepare_upgrade(
227             {
228             from_version => $v - 1,
229             to_version => $v,
230             },
231             );
232             }
233 0         0 return;
234             }
235              
236              
237              
238              
239              
240              
241              
242              
243              
244             sub cmd_install {
245 1     1 0 2 my $self = shift;
246 1         20 $self->_dh->install;
247 1         339996 return;
248             }
249              
250              
251              
252              
253              
254              
255              
256              
257              
258             sub cmd_upgrade {
259 2     2 0 3 my $self = shift;
260 2         70 $self->_dh->upgrade;
261 2         58447 return;
262             }
263              
264              
265              
266              
267              
268              
269              
270             sub cmd_database_version {
271 0     0 0 0 my $self = shift;
272              
273             ## no critic (RequireCheckedSyscalls)
274 0         0 print $self->_dh->database_version . "\n";
275              
276 0         0 return;
277             }
278              
279              
280              
281              
282              
283              
284              
285              
286              
287             sub cmd_schema_version {
288 0     0 0 0 my $self = shift;
289              
290             ## no critic (RequireCheckedSyscalls)
291 0         0 print $self->_dh->schema_version . "\n";
292              
293 0         0 return;
294             }
295              
296             my (%cmds) = (
297             write_ddl => \&cmd_write_ddl,
298             install => \&cmd_install,
299             upgrade => \&cmd_upgrade,
300             database_version => \&cmd_database_version,
301             schema_version => \&cmd_schema_version,
302             );
303             my (%cmd_desc) = (
304             write_ddl => 'only write ddl files',
305             install => 'install to the specified database connection',
306             upgrade => 'upgrade the specified database connection',
307             database_version => 'report the version of the specified database connection',
308             schema_version => 'report the version of the schema class',
309             );
310             my $list_cmds = join q[ ], sort keys %cmds;
311             my $list_cmds_opt = '(' . ( join q{|}, sort keys %cmds ) . ')';
312             my $list_cmds_usage =
313             ( join qq{\n}, q{}, qq{\tcommands:}, q{}, ( map { ( sprintf qq{\t%-30s%s}, $_, $cmd_desc{$_} ) } sort keys %cmds ), q{} );
314              
315              
316              
317              
318              
319              
320              
321              
322              
323              
324              
325              
326              
327              
328             around print_usage_text => sub {
329             my ( undef, undef, $usage ) = @_;
330             my ($text) = $usage->text();
331             $text =~ s{
332             ( long\s+options[.]+[]] )
333             } {
334             $1 . ' ' . $list_cmds_opt
335             }msex;
336             $text .= qq{\n} . $text . $list_cmds_usage . qq{\n};
337             print $text or croak q[Cannot write to STDOUT];
338             exit 0;
339             };
340              
341             sub run {
342 3     3 0 44 my ($self) = @_;
343 3         6 my ( $cmd, @what ) = @{ $self->extra_argv };
  3         97  
344 3 50       24 croak "Must supply a command\nCommands: $list_cmds\nFailed" unless $cmd;
345 3 50       8 croak "Extra argv detected - command only please\nFailed" if @what;
346             croak "No such command ${cmd}\nCommands: $list_cmds\nFailed"
347 3 50       14 unless exists $cmds{$cmd};
348 3         6 my $code = $cmds{$cmd};
349 3         9 return $self->$code();
350             }
351              
352             __PACKAGE__->meta->make_immutable;
353 2     2   13 no Moose;
  2         3  
  2         16  
354              
355             1;
356              
357             __END__
358              
359             =pod
360              
361             =encoding UTF-8
362              
363             =head1 NAME
364              
365             App::DH - Deploy your DBIx::Class Schema to DDL/Database via DBIx::Class::DeploymentHandler
366              
367             =head1 VERSION
368              
369             version 0.004001
370              
371             =head1 SYNOPSIS
372              
373             Basic usage:
374              
375             #!/usr/bin/env perl
376             #
377             # dh.pl
378              
379             use App::DH;
380             App::DH->new_with_options->run;
381              
382             --
383              
384             usage: dh.pl [-?cdfhIos] [long options...] (install|upgrade|write_ddl)
385             -h -? --usage --help Prints this usage information.
386             -c --connection_name either a valid DBI DSN or an alias
387             configured by DBIx::Class::Schema::Config
388             -f --force forcefully replace existing DDLs. [DANGER]
389             -s --schema the class name of the schema to generate
390             DDLs/deploy for
391             -I --include paths to load into @INC
392             -o --script_dir output path
393             -d --database database backends to generate DDLs for. See
394             SQL::Translator::Producer::* for valid values
395              
396             commands:
397              
398             install install to the specified database connection
399             upgrade upgrade the specified database connection
400             write_ddl only write ddl files
401              
402             If you don't like any of the defaults, you can subclass to override
403              
404             use App::DH;
405             {
406             package MyApp;
407             use Moose;
408             extends 'App::DH';
409              
410             has '+connection_name' => ( default => sub { 'production' } );
411             has '+schema' => ( default => sub { 'MyApp::Schema' } );
412             __PACKAGE__->meta->make_immutable;
413             }
414             MyApp->new_with_options->run;
415              
416             =head1 DESCRIPTION
417              
418             App::DH is a basic skeleton of a command line interface for the excellent
419             L<< C<DBIx::Class::DeploymentHandler>|DBIx::Class::DeploymentHandler >>, to make executing database deployment stages easier.
420              
421             =head1 COMMANDS
422              
423             =head2 write_ddl
424              
425             Only generate ddls for deploy/upgrade
426              
427             dh.pl [...params] write_ddl
428              
429             =head2 install
430              
431             Install to connection L</--connection_name>
432              
433             dh.pl [...params] install
434              
435             =head2 upgrade
436              
437             Upgrade connection L</--connection_name>
438              
439             dh.pl [...params] upgrade
440              
441             =head2 database_version
442              
443             Report database_version of L</--connection>
444              
445             =head2 schema_version
446              
447             Report schema_version of L</--schema>
448              
449             dh.pl [...params] schema_version
450              
451             =head1 PARAMETERS
452              
453             =head2 --connection_name
454              
455             -c/--connection_name
456              
457             Specify the connection details to use for deployment.
458             Can be a name of a configuration in a C<DBIx::Class::Schema::Config> configuration if the L</--schema> uses it.
459              
460             --connection_name 'dbi:SQLite:/path/to/db'
461              
462             -cdevelopment
463              
464             =head2 --force
465              
466             Overwrite existing DDL files of the same version.
467              
468             -f/--force
469              
470             =head2 --schema
471              
472             -s/--schema
473              
474             The class name of the schema to load for DDL/Deployment
475              
476             -sMyProject::Schema
477             --schema MyProject::Schema
478              
479             =head2 --include
480              
481             -I/--include
482              
483             Add a given library path to @INC prior to loading C<schema>
484              
485             -I../lib
486             --include ../lib
487              
488             May be specified multiple times.
489              
490             =head2 --script_dir
491              
492             -o/--script_dir
493              
494             Specify where to write the per-backend DDL's.
495              
496             Default is ./share/ddl
497              
498             -o/tmp/ddl
499             --script_dir /tmp/ddl
500              
501             =head2 --database
502              
503             -d/--database
504              
505             Specify the C<SQL::Translator::Producer::*> backend to use for generating DDLs.
506              
507             -dSQLite
508             --database PostgreSQL
509              
510             Can be specified multiple times.
511              
512             Default is introspected from looking at whatever L</--connection_name> connects to.
513              
514             =head2 --target
515              
516             --target
517              
518             Specify which version to install/upgrade to.
519              
520             If not specified, defaults to the latest version.
521              
522             =for Pod::Coverage cmd_write_ddl
523             cmd_install
524             cmd_upgrade
525             cmd_database_version
526             cmd_schema_version
527             run
528              
529             =head1 CREDITS
530              
531             This module is mostly code by mst, sponsored by L<nordaaker.com|http://nordaaker.com>, and I've only tidied it up and made it
532             more CPAN Friendly.
533              
534             =head1 SPONSORS
535              
536             The authoring of the initial incarnation of this code is kindly sponsored by L<nordaaker.com|http://nordaaker.com>.
537              
538             =head1 AUTHORS
539              
540             =over 4
541              
542             =item *
543              
544             kentnl - Kent Fredric (cpan:KENTNL) <kentnl@cpan.org>
545              
546             =item *
547              
548             mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
549              
550             =back
551              
552             =head1 COPYRIGHT AND LICENSE
553              
554             This software is copyright (c) 2017 by The App::DH Authors, Contributors, and Sponsors.
555              
556             This is free software; you can redistribute it and/or modify it under
557             the same terms as the Perl 5 programming language system itself.
558              
559             =cut