aboutsummaryrefslogtreecommitdiff
path: root/bin/db
diff options
context:
space:
mode:
Diffstat (limited to 'bin/db')
-rw-r--r--bin/db215
1 files changed, 215 insertions, 0 deletions
diff --git a/bin/db b/bin/db
new file mode 100644
index 0000000..600afc7
--- /dev/null
+++ b/bin/db
@@ -0,0 +1,215 @@
+#!/usr/bin/perl -w
+# Copyright (C) 2014-2016 Miquel Sabaté Solà <mikisabate@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This script allows us to connect with psql properly for the given environment.
+#
+# The environments that we can use have to be specified in a JSON file. This
+# JSON file has to be specified in the "$json" configurable value (by default
+# is "db/database.json"). This JSON file has to specify the environments
+# available and a set of values. Each environment has to specify the following
+# values:
+#
+# * dbname: the name of the database.
+# * host: the host to be used.
+# * user: the user that is accessing the database.
+# * password: the password for the user@host.
+#
+# More values can be specified, but they will be ignored by this script. You
+# can find an example of this in the examples/database.json file.
+#
+# You can call this script with the following optional arguments:
+#
+# -e name
+# This argument can be used to specify the environment that we want to
+# connect to. If this argument has not been passed, it will take the
+# value of the "$default" configurable value ("development" by default).
+# Note that this argument can be used in combination with other
+# arguments.
+#
+# -m, --migrate
+# This argument can be used to migrate a set of .sql files into the
+# database. The path to these files can be set with the "$migrate"
+# configurable value (by default it is "db/migrate"). Keep in mind that
+# migration files can have the comment "-- ignore." in the beginning of
+# the file (other previous comments or blank lines will be ignored). This
+# comment tells this script to ignore this migration file.
+#
+# -b, --backup
+# Spit to the STDOUT a backup of the database.
+#
+# Therefore, this command has the following usage:
+#
+# $ db [-e name] [[-m | --migrate] | [-b | --backup]]
+#
+
+use strict;
+use File::Basename;
+use Cwd 'abs_path', 'getcwd';
+
+
+##
+# Config values. Ideally you should only modify these values to adapt this
+# script to your project.
+#
+# NOTE: path values should *not* start and/or end with a slash.
+
+
+# The base path that this script will use. By default it picks the current
+# working directory.
+my $base = abs_path(getcwd);
+
+# The relative path to the json file (including the name of the json file
+# itself).
+my $json = 'db/database.json';
+
+# The default environment. This is the environment to be used when no
+# environment has been given through the '-e' option.
+my $default = 'development';
+
+# The relative path with migration files. Migration files are plain .sql files
+# that will be used with the '-m' option.
+my $migrate = 'db/migrate';
+
+
+##
+# And here starts the program itself.
+
+
+# Show the usage string and exit.
+sub usage {
+ print "Usage: db [-e name] [[-m | --migrate] | [-b | --backup]]\n";
+ print " -e Specify an environment.\n";
+ print " -m Migrate all the files from the db/migrate directory.\n";
+ print " -b Backup the proper DB.\n";
+ exit(1);
+}
+
+# Check that a given value has been defined in the given hash.
+sub check {
+ my ($ary, $value) = @_;
+ if (!defined($ary->{$value})) {
+ print "ERROR: you haven't defined the '$value' value.\n";
+ exit(1);
+ }
+}
+
+# Returns true if we should ignore the given migration.
+sub should_ignore {
+ my ($path) = @_;
+ my $res = 0;
+
+ if (open(MIGRATION, $path)) {
+ while (<MIGRATION>) {
+ if ($_ =~ /^--\s*ignore\.?/) {
+ # Ok boss, let's ignore it.
+ $res = 1;
+ last;
+ } elsif ($_ =~ /^\s*$/) {
+ # It's a blank line, next.
+ next;
+ } elsif ($_ =~ /^--/) {
+ # It's an SQL comment, next.
+ next;
+ }
+ last;
+ }
+ close(MIGRATION);
+ }
+ return $res;
+}
+
+# Apply all the migrations if needed.
+sub migrate {
+ my ($cmd, $path) = @_;
+
+ print "Starting migration\n";
+ opendir(DIR, $path) or die $!;
+ while (my $file = readdir(DIR)) {
+ next if ($file =~ m/^\./);
+ next if ($file !~ m/\.sql$/);
+
+ if (should_ignore("$path/$file")) {
+ print "Ignoring migration: $file\n";
+ } else {
+ print "Applying migration: $file\n";
+ system("$cmd < $path/$file\n");
+ }
+ }
+ closedir(DIR);
+}
+
+# Parsing options.
+my %opts = ('e', $default, 'm', 0, 'b', 0);
+for (my $it = 0; $it < @ARGV; $it++) {
+ if ($ARGV[$it] eq '-e') {
+ usage() if (!$ARGV[$it + 1]);
+ $opts{e} = $ARGV[$it + 1];
+ $it++;
+ } elsif ($ARGV[$it] eq '-m' || $ARGV[$it] eq '--migrate') {
+ $opts{m} = 1;
+ } elsif ($ARGV[$it] eq '-b' || $ARGV[$it] eq '--backup') {
+ $opts{b} = 1;
+ } else {
+ if ($ARGV[$it] ne '-h' && $ARGV[$it] ne '--help') {
+ print "Unknown option `$ARGV[$it]'\n\n";
+ }
+ usage();
+ }
+}
+
+# Let's fetch the configuration of the environment.
+my $config = "$base/$json";
+if (!-f $config) {
+ print "ERROR: the $config file does not exist!\n";
+ exit(1)
+}
+
+open(FILE, $config);
+my $file = '';
+while (<FILE>) {
+ my $line = $_;
+ chomp($line);
+ $file .= " $line";
+}
+close(FILE);
+
+# Fetch the values.
+$file =~ m/"$opts{e}":\s?({(.*?)})/;
+my $contents = $1;
+if (!defined($contents)) {
+ print "The `$opts{e}' environment does not exist.\n";
+ exit(1);
+}
+
+# Setup the command.
+my %ary = ();
+$ary{$1} = $2 while ($contents =~ /"(\w+)":\s?"([\w\-]*)"/g);
+foreach (qw{dbname user host password}) {
+ check(\%ary, $_);
+}
+
+my $opts = "-d $ary{'dbname'} -U $ary{'user'} -h $ary{'host'}";
+my $cmd = "PGPASSWORD=$ary{'password'} psql $opts";
+
+# Now execute the command properly.
+if ($opts{m}) {
+ migrate($cmd, "$base/$migrate");
+} elsif ($opts{b}) {
+ my $opts = "-d $ary{'dbname'} -U $ary{'user'}";
+ system("PGPASSWORD=$ary{'password'} pg_dump $opts");
+} else {
+ system("$cmd");
+}