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 Backbone:true, _:true, XM:true, XT:true*/
5 var _ = require('underscore'),
6 async = require('async'),
7 buildDatabase = require("./build_database"),
8 buildDictionary = require("./build_dictionary"),
9 buildClient = require("./build_client").buildClient,
10 defaultExtensions = require("./util/default_extensions").extensions,
11 dataSource = require('../../node-datasource/lib/ext/datasource').dataSource,
12 exec = require('child_process').exec,
14 initDatabase = require("./util/init_database").initDatabase,
15 inspectDatabaseExtensions = require("./util/inspect_database").inspectDatabaseExtensions,
17 path = require('path'),
18 unregister = require("./util/unregister").unregister,
19 winston = require('winston');
22 This is the point of entry for both the lightweight CLI entry-point and
23 programmatic calls to build, such as from mocha. Most of the work in this
24 file is in determining what the defaults mean. For example, if the
25 user does not specify an extension, we install the core and all registered
26 extensions, which requires a call to xt.ext.
28 We delegate the work of actually building the database and building the
29 client to build_database.js and build_client.js.
37 var buildAll = function (specs, creds, buildAllCallback) {
40 // step 0: init the database, if requested
42 if (specs.length === 1 &&
43 specs[0].initialize &&
44 (specs[0].backup || specs[0].source)) {
46 // The user wants to initialize the database first (i.e. Step 0)
47 // Do that, then call this function again
48 initDatabase(specs[0], creds, function (err, res) {
49 specs[0].wasInitialized = true;
59 // step 1: npm install extension if necessary
60 // an alternate approach would be only npm install these
61 // extensions on an npm install.
62 var allExtensions = _.reduce(specs, function (memo, spec) {
63 memo.push(spec.extensions);
64 return _.flatten(memo);
66 var npmExtensions = _.filter(allExtensions, function (extName) {
67 return extName && extName.indexOf("node_modules") >= 0;
69 if (npmExtensions.length === 0) {
73 npm.load(function (err, res) {
78 npm.on("log", function (message) {
79 // log the progress of the installation
82 async.map(npmExtensions, function (extName, next) {
83 npm.commands.install([path.basename(extName)], next);
88 // step 2: build the client
89 buildClient(specs, done);
92 // step 3: build the database
93 buildDatabase.buildDatabase(specs, creds, function (databaseErr, databaseRes) {
95 buildAllCallback(databaseErr);
98 var returnMessage = "\n";
99 _.each(specs, function (spec) {
100 returnMessage += "Database: " + spec.database + '\nDirectories:\n';
101 _.each(spec.extensions, function (ext) {
102 returnMessage += ' ' + ext + '\n';
105 done(null, "Build succeeded." + returnMessage);
109 // step 4: import all dictionary files
110 if (specs[0].clientOnly || specs[0].databaseOnly) {
111 // don't build dictionaries if the user doesn't want us to
112 console.log("Not importing the dictionaries");
115 var databases = _.map(specs, function (spec) {
116 return spec.database;
118 async.map(databases, buildDictionary.importAllDictionaries, done);
120 ], function (err, results) {
121 buildAllCallback(err, results && results[results.length - 2]);
125 exports.build = function (options, callback) {
129 getRegisteredExtensions = function (database, callback) {
130 var credsClone = JSON.parse(JSON.stringify(creds));
131 credsClone.database = database;
132 inspectDatabaseExtensions(credsClone, function (err, paths) {
136 keepSql: options.keepSql,
137 populateData: options.populateData,
138 wipeViews: options.wipeViews,
139 clientOnly: options.clientOnly,
140 databaseOnly: options.databaseOnly
146 if (options.config) {
147 config = require(path.resolve(process.cwd(), options.config));
149 config = require(path.resolve(__dirname, "../../node-datasource/config.js"));
151 creds = config.databaseServer;
152 creds.encryptionKeyFile = config.datasource.encryptionKeyFile;
153 creds.host = creds.hostname; // adapt our lingo to node-postgres lingo
154 creds.username = creds.user; // adapt our lingo to orm installer lingo
156 if (options.database) {
157 // the user has specified a particular database
158 databases.push(options.database);
160 // build all the databases in node-datasource/config.js
161 databases = config.datasource.databases;
164 if (options.clientOnly && options.databaseOnly) {
165 // This request doesn't make any sense.
166 callback("Make up your mind.");
168 } else if (options.backup && options.source) {
169 callback("You can build from backup or from source but not both.");
171 } else if (options.backup && options.extension) {
172 callback("When you're building from a backup you get whatever extensions the backup merits.");
174 } else if (options.initialize &&
175 (options.backup || options.source) &&
177 (!options.extension || options.extension === 'foundation-database')) {
178 // Initialize the database. This is serious business, and we only do it if
179 // the user does all the arguments correctly. It must be on one database only,
180 // with no extensions, with the initialize flag, and with a backup file.
182 buildSpecs.database = options.database;
183 if (options.backup) {
184 buildSpecs.backup = path.resolve(process.cwd(), options.backup);
185 buildSpecs.extensions = false;
186 // we'll determine the extensions by looking at the db after restore
188 if (options.source) {
189 buildSpecs.source = path.resolve(process.cwd(), options.source);
190 // if we initialize with the foundation, that means we want
191 // an unmobilized build
192 buildSpecs.extensions = options.extension ?
193 [options.extension] :
196 buildSpecs.initialize = true;
197 buildSpecs.keepSql = options.keepSql;
198 buildSpecs.populateData = options.populateData;
199 buildSpecs.wipeViews = options.wipeViews;
200 buildSpecs.clientOnly = options.clientOnly;
201 buildSpecs.databaseOnly = options.databaseOnly;
202 buildAll([buildSpecs], creds, callback);
204 } else if (options.initialize || options.backup || options.source) {
205 // The user has not been sufficiently serious.
206 callback("If you want to initialize the database, you must specifify " +
207 " a database, and use no extensions, and use both the init and either the backup or source flags");
209 } else if (options.extension) {
210 // the user has specified an extension to build or unregister
211 // extensions are assumed to be specified relative to the cwd
212 buildSpecs = _.map(databases, function (database) {
213 var extension = path.resolve(process.cwd(), options.extension);
216 frozen: options.frozen,
217 keepSql: options.keepSql,
218 populateData: options.populateData,
219 wipeViews: options.wipeViews,
220 clientOnly: options.clientOnly,
221 databaseOnly: options.databaseOnly,
222 extensions: [extension]
226 if (options.unregister) {
227 unregister(buildSpecs, creds, callback);
230 buildAll(buildSpecs, creds, callback);
233 // build all registered extensions for the database
234 async.map(databases, getRegisteredExtensions, function (err, results) {
236 buildAll(results, creds, callback);