ensembl-hive  2.7.0
schema_patcher.pl
Go to the documentation of this file.
1 #!/usr/bin/env perl
2 # See the NOTICE file distributed with this work for additional information
3 # regarding copyright ownership.
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 
17 
18 use strict;
19 use warnings;
20 
21 use DBI qw( :sql_types );
22 use File::Spec::Functions qw/:ALL/;
23 use Getopt::Long qw( :config no_ignore_case auto_version );
24 use IO::Dir;
25 
26 my $rcsid = '$Revision$';
27 our ($VERSION) = $rcsid =~ /(\d+\.\d+)/;
28 
29 sub usage {
30  my $indent = ' ' x length($0);
31 
32  print <<USAGE_END;
33 Usage:
34 
35  $0 --host=dbhost [ --port=dbport ] \\
36  $indent --user=dbuser [ --pass=dbpass ] \\
37  $indent --type=schema-type | --database=dbname \\
38  $indent [ --release=new-release ] [ --from=old-release ] \\
39  $indent [ --species=dbspecies ] \\
40  $indent [ --gitdir=/some/path ] \\
41  $indent [ --dryrun ] \\
42  $indent [ --interactive 0|1 ]\\
43  $indent [ --verbose ] [ --quiet ] \\
44  $indent [ --mysql=optional_path ] \\
45  $indent [ --fix ] \\
46  $indent [ --fixlast ]
47 
48  $0 --help | --about
49 
50  $0 --version
51 
52  --host / -h\tdatabase host name (required)
53  --port / -P\tdatabase port (optional, default=3306)
54  --user / -u\tdatabase user (required)
55  --pass / -p\tdatabase user password (optional, no default)
56 
57  --type / -t restrict to database schema type
58  (i.e. core, compara, funcgen, gene2phenotype, variation, production or ontology)
59  (required if --database is not specified)
60 
61  --database / -d full name of database, or database name pattern
62  (required if --type is not specified)
63 
64  --release / -r release number (optional, default is the latest
65  release that we can find patches for)
66 
67  --from / -f only consider databases from this release
68  (optional, no default)
69 
70  --species / -s restrict to species (optional, no default)
71 
72  --gitdir the directory where the relevant Ensembl Git repositories
73  have been checked out (optional, default=misc-scripts/../..)
74 
75  --dryrun / -n do not actually modify databases
76  (optional, default=not set)
77 
78  --verbose / -v display extra information
79 
80  --quiet / -q do not display warnings
81 
82  --fix also go through all old patches to find any missing
83  patch (patching starts at release equal to the
84  oldest patch in the database) >>USE WITH CAUTION<<
85 
86  --oldest used in conjunction with --fix, this option allows control
87  over how many releases are included in the fix. This option
88  exists for users who have incomplete meta entries and
89  wish to bring their database automatically up to date.
90 
91  --fixlast an extension of B<--oldest> and B<--fix>. This combines
92  to patch the current and last release only, giving an easy
93  way to patch a database post-handover without worrying
94  about ancient patches.
95 
96  --mysql specify the location of the mysql binary if it is not on
97  \$PATH. Otherwise we default this to mysql
98 
99  --nointeractive specify if you want an non-interactive patching environment
100  (default false). >>USE WITH CAUTION<<
101 
102  --help display this text
103  --about display further information
104  --version display version and quit
105 
106 USAGE_END
107 } ## end sub usage
108 
109 sub about {
110  print <<ABOUT_END;
111 
112  This script patches one or several Ensembl databases from older
113  releases to the release specified by the user on the command line
114  using the --release=NN command line switch, or to the latest release
115  for which the script is able to find a patch if the --release=NN
116  switch is not used. To only patch databases from a particular
117  Ensembl release, the user may use the --from=NN command line
118  switch. In this case, the script will use the value from the
119  'schema_version' meta key or, failing that, from the database name,
120  to determine what databases should be or shouldn't be patched.
121 
122  The script is able to patch databases that have Ensembl Core
123  schemas, Ensembl Compara schemas, Ensembl Regulation schemas,
124  Ensembl Variation schemas, Ensembl Production and Ontology schemas
125  provided that the appropriate Git repositories have been checked out
126  and are available to this script. The Git root directory where
127  all Ensembl Git repositories are located may be specified using the
128  --gitdir=/some/path command line switch if the script is unable to
129  determine it by itself.
130 
131  The user has to specify either a particular database to patch (using
132  --database=XXX) or by giving a schema type (using --type=XXX). In
133  the case where a single database is provided, the script will try to
134  figure out what schema type the database has from the value of the
135  'schema_type' meta key or, failing that, from the database name.
136 
137  If the user gives only a schema type, the script will look for
138  databases with that schema type, again using the value of the
139  'schema_type' meta key or, failing that, using the database names.
140 
141  The --database=XXX command line switch may also be used to specify a
142  pattern to match database names with.
143 
144  To further restrict the set of databases that will be patched,
145  the --species=XXX command line switch may be used. The value
146  will be used to match against the various values of the meta key
147  'species.alias' or, failing that, against the database name.
148 
149  When the --fix command line switch is used, the script will also
150  make it possible to apply older patches that might have been
151  skipped. For example: A database at schema version 65, with patches
152  since release 40, will not only be patched to the appropriate
153  release (specified with --release=NN), but all patches since release
154  40 (inclusively) will be tested. If the patch identifier for an old
155  patch is missing from the meta table of the database, that patch
156  will be applied.
157 
158  Examples
159 
160  The release coordinator patches all Ensembl Core-like databases
161  from release 65 to release 66:
162 
163  $0 -h host -u user -p password \\
164  -t core -f 65 -r 66
165 
166  A genebuilder wishes to patch the same set as specified above but
167  without being prompted to apply patches
168 
169  $0 -h host -u user -p password \\
170  -t core -f 65 -r 66 --nointeractive
171 
172  A genebuilder patches one of her databases to release 66, and
173  wants to look at what the script proposes to do before actually
174  running it for real:
175 
176  $0 -h host -u user -p password \\
177  -d my_database_66 -r 66 --dryrun
178 
179  The release coordinator patches all mouse Core-like databases to
180  the latest release. She has checked out the 'ensembl' Git repo
181  in her ~/src directory:
182 
183  $0 -h host -u user -p password \\
184  -t core -s mouse --gitdir=~/src
185 
186  A genebuilder (username 'my') patches all her human databases to
187  the latest release.
188 
189  $0 -h host -u user -p password \\
190  -s homo_sapiens -d 'my_%'
191 
192  A genebuilder makes sure that all patches up to and including
193  those for release 66 are included in her database, without
194  actually applying any patch (any missing patches needs to be
195  manually checked!):
196 
197  $0 -h host -u user -p password \\
198  -r 66 -d my_database --fix --dryrun
199 
200  The genebuilder above has an evil twin who has mislaid their meta tables.
201  --fix threatens to apply ancient patches but they know their database
202  is correct until halfway through release 64. They wish to apply any
203  missing patches between release 64 and 66.
204 
205  $0 -h host -u user -p password -r 66 \\
206  -d my_database --fix --oldest 64
207 
208  The genebuilder above also has a doppleganger who decided they
209  wanted to patch for the last and current release of Ensembl alone. This
210  is useful for applying late patches. In this situation we will apply
211  patches for the current release (67) and the previous release (66).
212 
213  $0 -h host -u user -p password -r 67 \\
214  -d my_database --fixlast
215 
216 ABOUT_END
217 } ## end sub about
218 
219 my ( $opt_host, $opt_port ) = ( undef, '3306' );
220 my ( $opt_user, $opt_pass ) = ( undef, undef );
221 my ( $opt_species, $opt_type, $opt_release ) = ( undef, undef, undef );
222 my $opt_database;
223 
224 my $opt_gitdir;
225 
226 my $opt_dryrun;
227 my $opt_from;
228 my $opt_fix;
229 my $opt_oldest;
230 my $opt_fixlast;
231 my $opt_mysql = 'mysql';
232 my $opt_interactive = 1;
233 
234 my ( $opt_verbose, $opt_quiet );
235 
236 if ( !GetOptions( 'host|h=s' => \$opt_host,
237  'port|P=i' => \$opt_port,
238  'user|u=s' => \$opt_user,
239  'pass|p=s' => \$opt_pass,
240  'species|s=s' => \$opt_species,
241  'type|t=s' => \$opt_type,
242  'from|f=i' => \$opt_from,
243  'release|r=i' => \$opt_release,
244  'database|d=s' => \$opt_database,
245  'gitdir=s' => \$opt_gitdir,
246  'dryrun|n!' => \$opt_dryrun,
247  'fix!' => \$opt_fix,
248  'fixlast!' => \$opt_fixlast,
249  'oldest=i' => \$opt_oldest,
250  'mysql=s' => \$opt_mysql,
251  'interactive|i!' => \$opt_interactive,
252  'verbose|v!' => \$opt_verbose,
253  'quiet|q!' => \$opt_quiet,
254  'help!' => sub { usage(); exit(0); },
255  'about!' => sub { about(); exit(0); } ) ||
256  !defined($opt_host) ||
257  !defined($opt_user) ||
258  ( !defined($opt_database) && !defined($opt_type) ) )
259 {
260  usage();
261  exit(1);
262 }
263 
264 if ( defined($opt_type) &&
265  $opt_type ne 'core' &&
266  $opt_type ne 'compara' &&
267  $opt_type ne 'funcgen' &&
268  $opt_type ne 'gene2phenotype' &&
269  $opt_type ne 'variation' &&
270  $opt_type ne 'production' &&
271  $opt_type ne 'ontology' )
272 {
273  die( sprintf( "Unknown schema type: %s\n", $opt_type ) );
274 }
275 
276 # turn on autoflush
277 $| = 1;
278 
279 my $latest_release;
280 my %patches;
281 
282 # Get available patches.
283 
284 foreach my $thing ( [ 'ensembl', 'core', 'table.sql' ],
285  [ 'ensembl-compara', 'compara', 'table.sql' ],
286  [ 'ensembl-funcgen', 'funcgen', 'table.sql' ],
287  [ 'ensembl-gene2phenotype', 'gene2phenotype', 'table.sql' ],
288  [ 'ensembl-variation', 'variation', 'table.sql' ],
289  [ 'ensembl-production', 'production', 'table.sql' ],
290  [ 'ensembl-ontology-schema', 'ontology', 'tables.sql' ] )
291 {
292  my ($git_repo, $schema_type, $schema_file) = @{$thing};
293 
294  if ( defined($opt_type) && $schema_type ne $opt_type ) { next }
295 
296  my $sql_dir = _sql_dir($git_repo, $schema_type, $schema_file);
297  if(! defined $sql_dir) {
298  if ( !$opt_quiet ) {
299  warn(sprintf("No SQL directory found for Git repo %s, %s schema type\n", $git_repo, $schema_type));
300  }
301  next;
302  }
303  my $dh = IO::Dir->new($sql_dir);
304 
305  if ( !defined($dh) ) {
306  if ( !$opt_quiet ) {
307  warn(sprintf( "Unable to find SQL directory '%s'\n", $sql_dir ) );
308  }
309  next;
310  }
311 
312  while ( my $file_name = $dh->read() ) {
313  if ( $file_name =~ /^patch_\d+_(\d+)_?[a-z]+?\.sql$/ ) {
314  my $patch_release = $1;
315 
316  if ( !defined($latest_release) ||
317  $latest_release < $patch_release )
318  {
319  $latest_release = $patch_release;
320  }
321 
322  if ($opt_verbose) {
323  printf( "Found %s patch file '%s' for release %d\n",
324  $schema_type, $file_name, $patch_release ) if ! $opt_quiet;
325  }
326 
327  my $full_file_name = catfile( $sql_dir, $file_name );
328 
329  push( @{ $patches{$schema_type}{$patch_release} },
330  { 'patch' => $file_name, 'path' => $full_file_name } );
331  }
332  }
333 
334 } ## end foreach my $thing ( [ 'ensembl'...])
335 
336 
337 if ( defined($opt_release) && $opt_release > $latest_release ) {
338  die( sprintf( "Release %d is too new, " .
339  "last release with patches is release %d\n",
340  $opt_release, $latest_release ) );
341 }
342 
343 if ( !defined($opt_release) ) {
344  if ($opt_verbose) {
345  printf( "Latest release with patches is release %d\n",
346  $latest_release );
347  }
348  $opt_release = $latest_release;
349 }
350 
351 my $dsn = sprintf( "DBI:mysql:host=%s;port=%d", $opt_host, $opt_port );
352 
353 my $dbh = DBI->connect( $dsn, $opt_user, $opt_pass,
354  { 'RaiseError' => 0, 'PrintError' => 0 } );
355 
356 if(! $dbh) {
357  my $pass = ($opt_pass) ? 'with a' : 'with no';
358  warn(sprintf(q{Cannot connect to DSN '%s' with user %s %s password. Check your settings}, $dsn, $opt_user, $pass));
359  exit 1;
360 }
361 
362 # Loop through the databases on the server, patch the ones we want to
363 # patch and filter out the ones that we don't want to patch.
364 
365 my $sth;
366 my $found_databases = 0;
367 
368 if ( defined($opt_database) ) {
369  $sth = $dbh->prepare("SHOW DATABASES LIKE ?");
370  $sth->bind_param( 1, $opt_database, SQL_VARCHAR );
371 }
372 else { $sth = $dbh->prepare("SHOW DATABASES") }
373 
374 $sth->execute();
375 
376 my $database;
377 $sth->bind_col( 1, \$database );
378 
379 DATABASE:
380 while ( $sth->fetch() ) {
381 
382  if ( $database =~ /^(?:information_schema|mysql)$/ ) { next }
383 
384  # Figure out schema version, schema type, and species name from the
385  # database by querying its meta table.
386 
387  my $sth2 = $dbh->prepare(
388  sprintf(
389  "SELECT meta_key, meta_value FROM %s WHERE meta_key IN " .
390  "('schema_version', 'schema_type', " .
391  "'species.alias', 'species.common_name', 'patch')",
392  $dbh->quote_identifier( undef, $database, 'meta' ) ) );
393 
394  $sth2->execute();
395 
396  my ( $key, $value );
397  $sth2->bind_columns( \( $key, $value ) );
398 
399  my ( $schema_version_ok, $schema_type_ok, $species_ok );
400  my ( $schema_version, $schema_type, $species );
401  my %dbpatches;
402 
403  while ( $sth2->fetch() ) {
404  if ( $key eq 'schema_version' ) {
405  $schema_version = $value;
406  if ( defined($opt_from) ) {
407  if ( $schema_version eq $opt_from ) { $schema_version_ok = 1 }
408  else { $schema_version_ok = 0 }
409  }
410  else { $schema_version_ok = 1 }
411  }
412  elsif ( $key eq 'schema_type' ) {
413  $schema_type = $value;
414  if ( defined($opt_type) ) {
415  if ( $schema_type eq $opt_type ) { $schema_type_ok = 1 }
416  else { $schema_type_ok = 0 }
417  }
418  else { $schema_type_ok = 1 }
419  }
420  elsif ( $key eq 'species.alias' ) {
421  if ( defined($opt_species) ) {
422  if ( $value eq $opt_species ) { $species_ok = 1 }
423  }
424  else { $species_ok = 1 }
425  }
426  elsif ( $key eq 'species.common_name' ) {
427  $species = $value;
428  }
429  elsif ( $key eq 'patch' ) {
430  if(index($value, "\n") > -1) {
431  warn "The patch value '$value' in database '$database' has line-breaks. Remove them to silence this message";
432  $value =~ s/\n/ /g;
433  }
434  if($value =~ /^(patch_\d+_(\d+)_?[a-z]+?\.sql)\|(.*)$/) {
435  my $patch_ident = $1;
436  my $patch_release = $2;
437  my $patch_info = $3;
438  $dbpatches{$patch_release}{$patch_ident} = $patch_info;
439  }
440  else {
441  warn "The patch value $value from database $database does not conform to the pattern of 'patch_from_to_tag|description'. Please fix";
442  }
443  }
444  } ## end while ( $sth2->fetch() )
445 
446  # If we haven't yet found out the schema version, schema type, or
447  # species, look to the database name to provide clues.
448 
449 
450  if ( ! $schema_version ) {
451  #remove defined as version maybe empty string
452 
453  if ( $database =~ /^ensembl.+?(\d+)$/ or # this captures compara|eg|ontology|production naming conventions
454  $database =~ /_(\d+)_\w+$/) {
455 
456  $schema_version = $1;
457 
458  if ( defined($opt_from) ) {
459  if ( $schema_version == $opt_from ) { $schema_version_ok = 1 }
460  else { $schema_version_ok = 0 }
461  }
462  else {
463  $schema_version_ok = 1 }
464  }
465  elsif ( ! $opt_quiet ) {
466  $schema_version_ok = 0;
467  warn( sprintf( "Can not determine schema version from '%s'\n",
468  $database ) );
469  }
470  }
471 
472  if ( !defined($schema_type) ) {
473  if ( $database =~ /_(core|funcgen|gene2phenotype|variation|compara|production|ontology)_/ ) {
474  $schema_type = $1;
475  if ( defined($opt_type) ) {
476  if ( $schema_type eq $opt_type ) { $schema_type_ok = 1 }
477  else { $schema_type_ok = 0 }
478  }
479  else { $schema_type_ok = 1 }
480  }
481  elsif ( !$opt_quiet ) {
482  warn( sprintf( "Can not determine schema type from '%s'\n",
483  $database ) );
484  }
485  }
486  if ( !defined($species) ) {
487  if ($database =~ /compara_([a-z][a-z_]+[a-z])?_\d+_\d+/ or # EG case, e.g. ensembl_compara_fungi_18_71
488  $database =~ /ensembl[a-z]?_(?:compara|production|ontology)_/ or
489  $database =~ /_test_db_([a-z_]+)_([a-z])_/ or
490  $database =~ /([a-z][a-z_]+[a-z])_(?:core|funcgen|gene2phenotype|variation)_/)
491  {
492  $species = $1;
493  $species = 'multi' unless defined $species;
494 
495  if ( defined($opt_species) ) {
496  if ( $species eq $opt_species ) { $species_ok = 1 }
497  }
498  else { $species_ok = 1 }
499  }
500  elsif ( $opt_species && !$opt_quiet ) {
501  warn( sprintf( "Can not determine species from '%s'\n", $database ) );
502  }
503  }
504 
505  #Quick check if fix-last is active. If so we will hard-code some values
506  $opt_fix = 1 if $opt_fixlast and defined $schema_version;
507 
508  if ( $schema_version_ok &&
509  $schema_type_ok &&
510  ( !defined($opt_species) ||
511  ( defined($opt_species) && $species_ok ) ) &&
512  ( ( !$opt_fix && $schema_version < $opt_release ) ||
513  ( $opt_fix && $schema_version <= $opt_release ) ) )
514  {
515  $found_databases = 1;
516  print( '-' x ( $ENV{COLUMNS} || 80 ), "\n" );
517  printf( "Considering '%s' [%s,%s,%d]\n",
518  $database, defined($species) ? $species : 'unknown',
519  $schema_type, $schema_version );
520  if ($opt_fixlast) {
521  $opt_oldest = ($schema_version == $latest_release) ? $latest_release : $latest_release - 1;
522 
523  if ($schema_version < $opt_oldest) {
524  printf("Cannot use --fixlast with a schema release too far from the latest release; oldest allowed is $opt_oldest. Skipping $database");
525  next;
526  }
527  printf("--fixlast is active. Will apply patches for version %d and up (if available)\n", $opt_oldest);
528  }
529 
530  }
531  else {
532  if($opt_verbose) {
533  printf("Skipping database %s (type: %s | version: %d)\n", $database, ($schema_type||'-'), ($schema_version || 0));
534  if( $schema_type_ok && $schema_version_ok && $schema_version == $opt_release) {
535  if (defined($opt_type) && $opt_type eq $schema_type) {
536 
537  my $release_patches = join(q{, }, sort map { $_->{patch} } @{$patches{$schema_type}{$schema_version}});
538  my $db_patches = join(q{, }, sort keys %{$dbpatches{$schema_version}});
539 
540  if($release_patches ne $db_patches) {
541  printf("\t%s patches [%s] are not the same as release %i patches [%s]; rerun with --fix and --dryrun\n",
542  $database, $db_patches, $opt_release, $release_patches);
543  }
544  }
545  }
546  if($schema_type_ok && ! exists $patches{$schema_type}) {
547  printf("\t%s patches could not be found. Check your --gitdir option and try again\n", $schema_type);
548  }
549  }
550  next;
551  }
552 
553  # Now figure out what patches we need to apply to this database.
554 
555  my $start_version;
556 
557  if ($opt_fix) {
558  $start_version = $opt_oldest || ( sort { $a <=> $b } keys %dbpatches )[0];
559  if ( !defined($start_version) ) {
560  warn( sprintf( "No patches in database, " .
561  "beginning fix from release %d\n",
562  $schema_version ) );
563  $start_version = $schema_version;
564  }
565  else {
566  printf( "Earliest patch in database '%s' is from release %d\n",
567  $database, $start_version );
568  }
569  }
570  else { $start_version = $schema_version + 1 }
571 
572  my @apply_these;
573  my $schema_version_warning = 0;
574 
575  for ( my $r = $start_version; $r <= $opt_release; ++$r ) {
576  next unless exists $patches{$schema_type}{$r};
577  foreach my $entry ( sort { $a->{'patch'} cmp $b->{'patch'} }
578  @{ $patches{$schema_type}{$r} } )
579  {
580  my $patch = $entry->{'patch'};
581  my $path = $entry->{'path'};
582 
583  if ( exists( $dbpatches{$r}{$patch} ) ) {
584  if ($opt_verbose) {
585  printf( "Patch '%s' (%s) already applied\n",
586  $patch, $schema_type );
587  }
588  }
589  else {
590  if ( !$opt_dryrun ) {
591  printf( "Will apply patch '%s' (%s)\n", $patch,
592  $schema_type );
593  push( @apply_these, $entry );
594 
595  if ( $r < $opt_release && $patch =~ /a\.sql$/ ) {
596  # Warn about possible setting schema_version with an 'a'
597  # patch.
598  $schema_version_warning = 1;
599  }
600  }
601  else {
602  printf( "Would apply patch '%s' (%s)\n",
603  $patch, $schema_type );
604  }
605  }
606  } ## end foreach my $entry ( sort { ...})
607 
608  } ## end for ( my $r = $start_version...)
609 
610  if ( $opt_dryrun || !@apply_these ) { print("\n"); next }
611 
612  my $apply_patches;
613  local $| = 1;
614  if($opt_interactive) {
615  print("Proceed with applying these patches? (y/N): ");
616  my $yesno = <STDIN>;
617  chomp($yesno);
618  $apply_patches = (lc($yesno) =~ /^y(?:es)?$/) ? 1 : 0;
619  }
620  else {
621  $apply_patches = 1;
622  print "Enterning non-interative mode. Will apply patches\n";
623  }
624 
625  if ( $apply_patches ) {
626  PATCH:
627  foreach my $entry (@apply_these) {
628  my $patch = $entry->{'patch'};
629  my $path = $entry->{'path'};
630 
631  my @cmd_list = ( $opt_mysql,
632  "--host=$opt_host",
633  "--user=$opt_user");
634  push(@cmd_list, "--password=$opt_pass") if $opt_pass;
635  push(@cmd_list, "--port=$opt_port",
636  "--database=$database",
637  "--verbose",
638  "--execute=source $path" );
639 
640  printf( "Executing the following command:\n%s\n",
641  join( ' ', @cmd_list ) );
642 
643  if ( system(@cmd_list) ) {
644  warn( sprintf( "Failed to apply patch '%s' to database '%s'!\n",
645  $patch, $database ) );
646 
647  if(!$opt_interactive) {
648  warn('In non-interative mode; aborting current run');
649  exit(1);
650  }
651  print("Next patch, next database, or abort? (p/d/A): ");
652 
653  my $response = <STDIN>;
654  chomp($response);
655 
656  if ( lc($response) =~ /^p(?:atch)?$/ ) { next PATCH }
657  elsif ( lc($response) =~ /^d(?:atabase)?$/ ) { next DATABASE }
658  else { exit(1) }
659  }
660  } ## end foreach my $entry (@apply_these)
661 
662  if ( !$opt_quiet && $schema_version_warning ) {
663  warn( "Applied one or several 'a' patches, " .
664  "schema_version might have been updated\n" );
665  }
666 
667  } ## end if ( lc($yesno) =~ /^y(?:es)?$/)
668 
669  print("\n");
670 
671 } ## end while ( $sth->fetch() )
672 
673 if(!$found_databases) {
674  printf(('-'x80)."\n");
675  printf("No databases considered. Check your --database/--type/--release flags\n");
676  printf(('-'x80)."\n");
677 }
678 
679 $dbh->disconnect();
680 
681 sub _sql_dir {
682  my ($git_repo, $schema_type, $schema_file) = @_;
683  my $git_dir;
684  if($opt_gitdir) {
685  $git_dir = $opt_gitdir;
686  }
687  else {
688  my ($volume, $directories, $file) = splitpath(__FILE__);
689  $directories = curdir() unless $directories;
690  $git_dir = catdir($directories, updir(), updir());
691  }
692  my $sql_dir = rel2abs(canonpath( catdir( $git_dir, $git_repo, 'sql' ) ));
693  my $schema_location = catfile($sql_dir, $schema_file);
694  if(! -f $schema_location) {
695  if($opt_verbose) {
696  printf("Could not find the schema file '%s' for E! module %s", $schema_location, $git_repo);
697  printf("\tTry using --gitdir if your checkouts are in a non-standard location\n") if $opt_gitdir;
698  }
699  return;
700  }
701  printf("Using '%s' as our SQL directory\n", $sql_dir) if ! $opt_quiet;
702  return $sql_dir;
703 }
map
public map()
about
public about()
_sql_dir
protected _sql_dir()
usage
public usage()