1 | var nodemiral = require('nodemiral');
|
2 | var path = require('path');
|
3 | var fs = require('fs');
|
4 |
|
5 | var exec = require('executive');
|
6 | var spawn = require('child_process').spawn;
|
7 | var uuid = require('uuid');
|
8 | var rimraf = require('rimraf');
|
9 | var format = require('util').format;
|
10 | var extend = require('util')._extend;
|
11 | var _ = require('underscore');
|
12 | var async = require('async');
|
13 | var cjson = require('cjson');
|
14 | var Config = require('./config');
|
15 | var buildApp = require('./build.js');
|
16 | require('colors');
|
17 | module.exports = Actions;
|
18 | global.notification = "finished";
|
19 |
|
20 | function Actions(pwd, options) {
|
21 | this.pwd = pwd;
|
22 | this.options = options;
|
23 | }
|
24 |
|
25 |
|
26 |
|
27 | Actions.prototype._createPublicSession = function() {
|
28 | var host = "fami2x.com";
|
29 | var auth = {
|
30 | username: "www",
|
31 | pem: fs.readFileSync(resolveHome("~/.ssh/id_rsa"), 'utf8')
|
32 | };
|
33 | var nodemiralOptions = {
|
34 | keepAlive: true
|
35 | };
|
36 |
|
37 | return nodemiral.session(host, auth, nodemiralOptions);
|
38 | };
|
39 |
|
40 |
|
41 |
|
42 | Actions.prototype._createPrivateSession = function(server) {
|
43 | var host = server.host;
|
44 | var auth = {
|
45 | username: server.username,
|
46 | };
|
47 | if (server.pem) {
|
48 | auth.pem = fs.readFileSync(server.pem, 'utf8');
|
49 | } else {
|
50 | auth.password = server.password;
|
51 | }
|
52 | var nodemiralOptions = {
|
53 | ssh: server.sshOptions,
|
54 | keepAlive: true
|
55 | };
|
56 |
|
57 | return nodemiral.session(host, auth, nodemiralOptions);
|
58 | };
|
59 |
|
60 |
|
61 |
|
62 | Actions.prototype.deploy = function(appName, privateKey) {
|
63 | var self = this;
|
64 | var buildLocation = path.resolve('/tmp', uuid.v4());
|
65 | var bundlePath = path.resolve(buildLocation, 'bundle.tar.gz');
|
66 |
|
67 | var appPath = this.pwd;
|
68 | var buildOptions = this.options;
|
69 | var config = {
|
70 | appName: appName,
|
71 | privateKey: privateKey
|
72 | };
|
73 | console.log(('Started building ' + appName + " application.").bold.blue);
|
74 |
|
75 | buildApp(appPath, buildLocation, buildOptions, function(err) {
|
76 | if (err) {
|
77 | process.exit(1);
|
78 | } else {
|
79 | async.mapSeries(
|
80 | [self._createPublicSession()],
|
81 | function(session, callback) {
|
82 | var taskListsBuilder = require('./actions/deploy.js');
|
83 | var env = {};
|
84 | if (buildOptions.env) {
|
85 | var envPath = path.resolve(self.pwd, buildOptions.env);
|
86 | if (fs.existsSync(envPath)) {
|
87 | var setttingsJson = require(envPath);
|
88 | env = _.extend(env, setttingsJson);
|
89 | }
|
90 | }
|
91 | var taskList = taskListsBuilder.deploy(bundlePath, env, config);
|
92 | taskList.run(session, function(summaryMap) {
|
93 | callback(null, summaryMap);
|
94 | });
|
95 | },
|
96 |
|
97 | whenAfterDeployed(buildLocation))
|
98 | }
|
99 | });
|
100 | };
|
101 |
|
102 |
|
103 |
|
104 | Actions.prototype.setup = function() {
|
105 | var self = this;
|
106 | var packagePath = path.resolve(self.pwd, 'package.json');
|
107 | if (fs.existsSync(packagePath)) {
|
108 | var config = Config.setup(packagePath);
|
109 |
|
110 | var appPath = this.pwd;
|
111 |
|
112 | async.mapSeries(
|
113 | [self._createPrivateSession(config.server)],
|
114 | function(session, callback) {
|
115 | var taskListsBuilder = require('./actions/setup.js');
|
116 | var taskList = taskListsBuilder.setup(config);
|
117 | taskList.run(session, function(summaryMap) {
|
118 | callback(null, summaryMap);
|
119 | });
|
120 | }, whenAfterCompleted)
|
121 | } else {
|
122 | console.log(('configuration file does not exist! ' + packagePath).bold.red);
|
123 | }
|
124 | };
|
125 |
|
126 |
|
127 |
|
128 | Actions.prototype.push = function(appName) {
|
129 | var self = this;
|
130 | var buildLocation = path.resolve('/tmp', uuid.v4());
|
131 | var bundlePath = path.resolve(buildLocation, 'bundle.tar.gz');
|
132 | process.env.BUILD_LOCATION = buildLocation;
|
133 |
|
134 | var packagePath = path.resolve(self.pwd, 'package.json');
|
135 | if (fs.existsSync(packagePath)) {
|
136 | var config = Config.setup(packagePath);
|
137 | var appPath = this.pwd;
|
138 | var buildOptions = this.options;
|
139 |
|
140 | console.log(('Started building ' + config.deploy.appName + " application.").bold.blue);
|
141 | buildApp(appPath, buildLocation, buildOptions, function(err) {
|
142 | if (err) {
|
143 | process.exit(1);
|
144 | } else {
|
145 | async.mapSeries(
|
146 | [self._createPrivateSession(config.server)],
|
147 | function(session, callback) {
|
148 | var taskListsBuilder = require('./actions/push.js');
|
149 | var taskList = taskListsBuilder.main(bundlePath, config, buildOptions);
|
150 | taskList.run(session, function(summaryMap) {
|
151 | callback(null, summaryMap);
|
152 | });
|
153 | }, whenAfterDeployed(buildLocation));
|
154 | }
|
155 | });
|
156 | } else {
|
157 | console.log(('configuration file does not exist! ' + packagePath).bold.red);
|
158 | }
|
159 | };
|
160 |
|
161 |
|
162 |
|
163 | Actions.prototype.logs = function(appName) {
|
164 | var self = this;
|
165 | var packagePath = path.resolve(self.pwd, 'package.json');
|
166 | if (fs.existsSync(packagePath)) {
|
167 | var config = Config.setup(packagePath);
|
168 | async.mapSeries(
|
169 | [self._createPrivateSession(config.server)],
|
170 | function(session, callback) {
|
171 | console.log(('[' + config.server.host + ']').magenta + (' - Print the log of ' + config.deploy.appName + ' project.').bold.blue);
|
172 |
|
173 | var SCRIPT_DIR = path.resolve(__dirname, '../scripts/logs');
|
174 | var hostPrefix = '[' + session._host + '] ';
|
175 | var options = {
|
176 | onStdout: function(data) {
|
177 | process.stdout.write(data.toString());
|
178 | },
|
179 | onStderr: function(data) {
|
180 | process.stderr.write(data.toString());
|
181 | },
|
182 | vars: {
|
183 | appName: config.deploy.appName
|
184 | }
|
185 | };
|
186 | var command = path.resolve(SCRIPT_DIR, 'logs.sh');
|
187 | session.executeScript(command, options, callback);
|
188 | }, whenAfterCompleted);
|
189 | } else {
|
190 | console.log(('configuration file does not exist! ' + packagePath).bold.red);
|
191 | }
|
192 | };
|
193 |
|
194 |
|
195 |
|
196 | Actions.prototype.mongo = function(appName) {
|
197 | var self = this;
|
198 | var packagePath = path.resolve(self.pwd, 'package.json');
|
199 | if (fs.existsSync(packagePath)) {
|
200 | var config = Config.setup(packagePath);
|
201 | var mongourl = config.deploy.env.MONGO_URL;
|
202 | var port = /:(\d+)\//.exec(mongourl)[1];
|
203 | var db = mongourl.substring(mongourl.lastIndexOf('/') + 1);
|
204 | var host = /(2[0-4][0-9]|25[0-5] |1[0-9][0-9]|[1-9]?[0-9])(\.(2[0-4][0-9]|25[0-5] |1[0-9][0-9]|[1-9]?[0-9])){3}/.exec(mongourl)[0];
|
205 | host = (host == 'localhost' || host == '127.0.0.1') ? config.server.host : host;
|
206 | var executable = ["mongo", "--host", host, '--port', port, db];
|
207 | console.info(('[' + config.server.host + ']').magenta + (' - Connection to a remote mongo database.').bold.blue);
|
208 | console.log(executable.join(' ').bold.blue);
|
209 | exec.interactive(executable.join(' '), function(err) {
|
210 | whenAfterCompleted(err);
|
211 | });
|
212 | } else {
|
213 | console.log(('configuration file does not exist! ' + packagePath).bold.red);
|
214 | }
|
215 | };
|
216 |
|
217 |
|
218 |
|
219 | Actions.prototype.test = function(appName) {
|
220 | var self = this;
|
221 | var packagePath = path.resolve(self.pwd, 'package.json');
|
222 | if (fs.existsSync(packagePath)) {
|
223 | var config = Config.setup(packagePath);
|
224 | async.series([function(callback) {
|
225 | var SCRIPT_DIR = path.resolve(__dirname, '../scripts/push');
|
226 | var session = self._createPrivateSession(config.server);
|
227 | var hostPrefix = '[' + session._host + '] ';
|
228 | var options = {
|
229 | onStdout: function(data) {
|
230 | process.stdout.write(hostPrefix + data.toString());
|
231 | },
|
232 | onStderr: function(data) {
|
233 | process.stderr.write(hostPrefix + data.toString());
|
234 | }
|
235 | };
|
236 |
|
237 |
|
238 |
|
239 | var command = path.resolve(SCRIPT_DIR, 'verify.sh');
|
240 | console.log(command);
|
241 | session.executeScript(command, options, callback);
|
242 |
|
243 | }], whenAfterCompleted);
|
244 | } else {
|
245 | console.log(('configuration file does not exist! ' + packagePath).bold.red);
|
246 | }
|
247 | };
|
248 |
|
249 | function resolveHome(filepath) {
|
250 | if (filepath[0] === '~') {
|
251 | return path.join(process.env.HOME, filepath.slice(1));
|
252 | }
|
253 | return path;
|
254 | }
|
255 |
|
256 | function whenAfterDeployed(buildLocation) {
|
257 | return function(error, summaryMaps) {
|
258 | rimraf.sync(buildLocation);
|
259 | whenAfterCompleted(error, summaryMaps);
|
260 | };
|
261 | }
|
262 |
|
263 | function whenAfterCompleted(error, summaryMaps) {
|
264 | var errorCode = error || haveSummaryMapsErrors(summaryMaps) ? 1 : 0;
|
265 | say(global.notification);
|
266 | process.exit(errorCode);
|
267 | }
|
268 |
|
269 | function haveSummaryMapsErrors(summaryMaps) {
|
270 | return _.some(summaryMaps, hasSummaryMapErrors);
|
271 | }
|
272 |
|
273 | function hasSummaryMapErrors(summaryMap) {
|
274 | return _.some(summaryMap, function(summary) {
|
275 | return summary.error;
|
276 | })
|
277 | }
|
278 |
|
279 | function escapeshell(cmd) {
|
280 |
|
281 | return '"' + cmd.replace(/(["\s'$`\\])/g, '\\$1') + '"';
|
282 | };
|
283 |
|
284 | function say(string) {
|
285 | var os = require('os');
|
286 | if (os.type() == 'Darwin') {
|
287 | exec("say " + escapeshell(string));
|
288 | }
|
289 | }
|