UNPKG

11 kBJavaScriptView Raw
1var nodemiral = require('nodemiral');
2var path = require('path');
3var fs = require('fs');
4// var exec = require( 'child_process' ).exec;
5var exec = require('executive');
6var spawn = require('child_process').spawn;
7var uuid = require('uuid');
8var rimraf = require('rimraf');
9var format = require('util').format;
10var extend = require('util')._extend;
11var _ = require('underscore');
12var async = require('async');
13var cjson = require('cjson');
14var Config = require('./config');
15var buildApp = require('./build.js');
16require('colors');
17module.exports = Actions;
18global.notification = "finished";
19
20function Actions(pwd, options) {
21 this.pwd = pwd;
22 this.options = options;
23}
24// ================================================
25// 创建一个 ssh 连接 ===============================
26// ================================================
27Actions.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 // console.log(auth);
37 return nodemiral.session(host, auth, nodemiralOptions);
38};
39// ================================================
40// 创建一个 ssh 连接
41// ================================================
42Actions.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 // console.log(auth);
57 return nodemiral.session(host, auth, nodemiralOptions);
58};
59// ================================================
60// deploy
61// ================================================
62Actions.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 // function(){process.exit(0);}
97 whenAfterDeployed(buildLocation))
98 }
99 });
100};
101// ================================================
102// setup
103// ================================================
104Actions.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 // console.log(config);
110 var appPath = this.pwd;
111 // console.log(('Started installation server').bold.blue);
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// push
127// ================================================
128Actions.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 // console.log(buildOptions);
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// logs
162// ================================================
163Actions.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// mongo
195// ================================================
196Actions.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// test
218// ================================================
219Actions.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 // var command = "curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.1/install.sh | bash && . ~/.bashrc && env && nvm --version";
237 // session.execute( command, options, callback );
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// 找到用户目录 ~
249function resolveHome(filepath) {
250 if (filepath[0] === '~') {
251 return path.join(process.env.HOME, filepath.slice(1));
252 }
253 return path;
254}
255// 任务完成时,删除临时文件
256function whenAfterDeployed(buildLocation) {
257 return function(error, summaryMaps) {
258 rimraf.sync(buildLocation);
259 whenAfterCompleted(error, summaryMaps);
260 };
261}
262
263function whenAfterCompleted(error, summaryMaps) {
264 var errorCode = error || haveSummaryMapsErrors(summaryMaps) ? 1 : 0;
265 say(global.notification);
266 process.exit(errorCode);
267}
268
269function haveSummaryMapsErrors(summaryMaps) {
270 return _.some(summaryMaps, hasSummaryMapErrors);
271}
272
273function hasSummaryMapErrors(summaryMap) {
274 return _.some(summaryMap, function(summary) {
275 return summary.error;
276 })
277}
278
279function escapeshell(cmd) {
280 //http://stackoverflow.com/a/7685469
281 return '"' + cmd.replace(/(["\s'$`\\])/g, '\\$1') + '"';
282};
283
284function say(string) {
285 var os = require('os');
286 if (os.type() == 'Darwin') {
287 exec("say " + escapeshell(string));
288 }
289}