Merge pull request #1843 from xtuple/4_6_x
[xtuple] / scripts / lib / util / init_database.js
1 /*jshint node:true, indent:2, curly:false, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
2 regexp:true, undef:true, strict:true, trailing:true, white:true */
3 /*global _:true */
4
5 (function () {
6   "use strict";
7
8   var async = require("async"),
9     proc = require('child_process'),
10     path = require('path'),
11     os = require('os'),
12     winston = require('winston'),
13     dataSource = require('../../../node-datasource/lib/ext/datasource').dataSource,
14     inspectDatabaseExtensions = require("./inspect_database").inspectDatabaseExtensions;
15
16   //
17   // Wipe out the database
18   // and load it from scratch using pg_restore something.backup unless
19   // we're building from source.
20   //
21   var initDatabase = function (spec, creds, callback) {
22     var databaseName = spec.database,
23       credsClone = JSON.parse(JSON.stringify(creds)),
24       dropDatabase = function (done) {
25         winston.info("Dropping database " + databaseName);
26         // the calls to drop and create the database need to be run against the database "postgres"
27         credsClone.database = "postgres";
28         dataSource.query("drop database if exists " + databaseName + ";", credsClone, done);
29       },
30       createDatabase = function (done) {
31         winston.info("Creating database " + databaseName);
32         dataSource.query("create database " + databaseName + " template template1;", credsClone, done);
33       },
34       buildSchema = function (done) {
35         var schemaPath = path.join(path.dirname(spec.source), "440_schema.sql");
36         winston.info("Building schema for database " + databaseName);
37
38         var process = proc.spawn('psql', [
39           '-q', '-U', creds.username, '-h', creds.hostname, '--single-transaction', '-p',
40           creds.port, '-d', databaseName, '-f', schemaPath
41         ], { stdio: 'inherit' });
42         process.on('exit', done);
43         
44       },
45       populateData = function (done) {
46         winston.info("Populating data for database " + databaseName + " from " + spec.source);
47         var process = proc.spawn('psql', [
48           '-q', '-U', creds.username, '-h', creds.hostname, '--single-transaction', '-p',
49           creds.port, '-d', databaseName, '-f', spec.source
50         ], { stdio: 'inherit'});
51         process.on('exit', done);
52       },
53       // use exec to restore the backup. The alternative, reading the backup file into a string to query
54       // doesn't work because the backup file is binary.
55       restoreBackup = function (done) {
56         var process = proc.spawn('pg_restore', [
57           '-U', creds.username, '-h', creds.hostname, '-p', creds.port, '-d', databaseName,
58           '-j', os.cpus().length, spec.backup
59         ], { stdio: 'inherit' });
60         process.on('exit', function (err, res) {
61           if (err) {
62             console.log("ignoring restore db error", err);
63           }
64           done(null, res);
65         });
66       },
67       finish = function (err, results) {
68         if (err) {
69           winston.error("init database error", err.message, err.stack, err);
70         }
71         callback(err, results);
72       };
73
74     if (spec.source) {
75       async.series([
76         dropDatabase,
77         createDatabase,
78         buildSchema,
79         populateData
80       ], finish);
81     } else {
82       async.series([
83         dropDatabase,
84         createDatabase,
85         restoreBackup,
86         function (done) {
87           credsClone.database = databaseName;
88           inspectDatabaseExtensions(credsClone, function (err, paths) {
89             // in the case of a build-from-backup, we ignore any user desires and dictate the extensions
90             spec.extensions = paths;
91             done();
92           });
93         }
94       ], finish);
95     }
96   };
97
98   exports.initDatabase = initDatabase;
99 }());