Version.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. var cst = require('../../constants.js');
  2. var Common = require('../Common.js');
  3. var fs = require('fs');
  4. var eachSeries = require('async/eachSeries');
  5. var child = require('child_process');
  6. var printError = Common.printError;
  7. var printOut = Common.printOut;
  8. module.exports = function(CLI) {
  9. var EXEC_TIMEOUT = 60000; // Default: 1 min
  10. CLI.prototype._pull = function(opts, cb) {
  11. var that = this;
  12. var process_name = opts.process_name;
  13. var reload_type = opts.action;
  14. printOut(cst.PREFIX_MSG + 'Updating repository for process name %s', process_name);
  15. that.Client.getProcessByNameOrId(process_name, function (err, processes) {
  16. if (err || processes.length === 0) {
  17. printError('No processes with this name or id : %s', process_name);
  18. return cb ? cb({msg: 'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT);
  19. }
  20. var proc = processes[0];
  21. if (!proc.pm2_env.versioning) {
  22. printOut(cst.PREFIX_MSG + 'No versioning system found for process %s', process_name);
  23. return cb ? cb({success:false, msg: 'No versioning system found for process'}) : that.exitCli(cst.SUCCESS_EXIT);
  24. }
  25. require('vizion').update({
  26. folder: proc.pm2_env.versioning.repo_path
  27. }, function(err, meta) {
  28. if (err !== null) {
  29. return cb ? cb({msg:err}) : that.exitCli(cst.ERROR_EXIT);
  30. }
  31. if (meta.success === true) {
  32. getPostUpdateCmds(proc.pm2_env.versioning.repo_path, process_name, function (command_list) {
  33. execCommands(proc.pm2_env.versioning.repo_path, command_list, function(err, res) {
  34. if (err !== null) {
  35. printError(err);
  36. return cb ? cb({msg: meta.output + err}) : that.exitCli(cst.ERROR_EXIT);
  37. }
  38. else {
  39. printOut(cst.PREFIX_MSG + 'Process successfully updated %s', process_name);
  40. printOut(cst.PREFIX_MSG + 'Current commit %s', meta.current_revision);
  41. return that[reload_type](process_name, function(err, procs) {
  42. if (err && cb) return cb(err);
  43. if (err) console.error(err);
  44. return cb ? cb(null, meta.output + res) : that.exitCli(cst.SUCCESS_EXIT);
  45. });
  46. }
  47. });
  48. });
  49. }
  50. else {
  51. printOut(cst.PREFIX_MSG + 'Already up-to-date or an error occured for app: %s', process_name);
  52. return cb ? cb({success:false, msg : 'Already up to date'}) : that.exitCli(cst.SUCCESS_EXIT);
  53. }
  54. return false;
  55. });
  56. return false;
  57. });
  58. };
  59. /**
  60. * CLI method for updating a repository to a specific commit id
  61. * @method pullCommitId
  62. * @param {string} process_name
  63. * @param {string} commit_id
  64. * @return
  65. */
  66. CLI.prototype.pullCommitId = function(process_name, commit_id, cb) {
  67. var reload_type = 'reload';
  68. var that = this;
  69. printOut(cst.PREFIX_MSG + 'Updating repository for process name %s', process_name);
  70. that.Client.getProcessByNameOrId(process_name, function (err, processes) {
  71. if (err || processes.length === 0) {
  72. printError('No processes with this name or id : %s', process_name);
  73. return cb ? cb({msg: 'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT);
  74. }
  75. var proc = processes[0];
  76. if (proc.pm2_env.versioning) {
  77. require('vizion').isUpToDate({folder: proc.pm2_env.versioning.repo_path}, function(err, meta) {
  78. if (err !== null)
  79. return cb ? cb({msg:err}) : that.exitCli(cst.ERROR_EXIT);
  80. require('vizion').revertTo(
  81. {revision: commit_id,
  82. folder: proc.pm2_env.versioning.repo_path},
  83. function(err2, meta2) {
  84. if (!err2 && meta2.success) {
  85. getPostUpdateCmds(proc.pm2_env.versioning.repo_path, process_name, function (command_list) {
  86. execCommands(proc.pm2_env.versioning.repo_path, command_list, function(err, res) {
  87. if (err !== null)
  88. {
  89. printError(err);
  90. return cb ? cb({msg:err}) : that.exitCli(cst.ERROR_EXIT);
  91. }
  92. else {
  93. printOut(cst.PREFIX_MSG + 'Process successfully updated %s', process_name);
  94. printOut(cst.PREFIX_MSG + 'Current commit %s', commit_id);
  95. return that[reload_type](process_name, cb);
  96. }
  97. });
  98. });
  99. }
  100. else {
  101. printOut(cst.PREFIX_MSG + 'Already up-to-date or an error occured: %s', process_name);
  102. return cb ? cb(null, {success:meta.success}) : that.exitCli(cst.SUCCESS_EXIT);
  103. }
  104. });
  105. });
  106. }
  107. else {
  108. printOut(cst.PREFIX_MSG + 'No versioning system found for process %s', process_name);
  109. return cb ? cb(null, {success:false}) : that.exitCli(cst.SUCCESS_EXIT);
  110. }
  111. });
  112. };
  113. /**
  114. * CLI method for downgrading a repository to the previous commit (older)
  115. * @method backward
  116. * @param {string} process_name
  117. * @return
  118. */
  119. CLI.prototype.backward = function(process_name, cb) {
  120. var that = this;
  121. printOut(cst.PREFIX_MSG + 'Downgrading to previous commit repository for process name %s', process_name);
  122. that.Client.getProcessByNameOrId(process_name, function (err, processes) {
  123. if (err || processes.length === 0) {
  124. printError('No processes with this name or id : %s', process_name);
  125. return cb ? cb({msg: 'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT);
  126. }
  127. var proc = processes[0];
  128. // in case user searched by id/pid
  129. process_name = proc.name;
  130. if (proc.pm2_env.versioning === undefined ||
  131. proc.pm2_env.versioning === null)
  132. return cb({msg : 'Versioning unknown'});
  133. require('vizion').prev({
  134. folder: proc.pm2_env.versioning.repo_path
  135. }, function(err, meta) {
  136. if (err)
  137. return cb ? cb({msg:err, data : meta}) : that.exitCli(cst.ERROR_EXIT);
  138. if (meta.success !== true) {
  139. printOut(cst.PREFIX_MSG + 'No versioning system found for process %s', process_name);
  140. return cb ? cb({msg:err, data : meta}) : that.exitCli(cst.ERROR_EXIT);
  141. }
  142. getPostUpdateCmds(proc.pm2_env.versioning.repo_path, process_name, function (command_list) {
  143. execCommands(proc.pm2_env.versioning.repo_path, command_list, function(err, res) {
  144. if (err !== null) {
  145. require('vizion').next({folder: proc.pm2_env.versioning.repo_path}, function(err2, meta2) {
  146. printError(err);
  147. return cb ? cb({msg: meta.output + err}) : that.exitCli(cst.ERROR_EXIT);
  148. });
  149. return false;
  150. }
  151. printOut(cst.PREFIX_MSG + 'Process successfully updated %s', process_name);
  152. printOut(cst.PREFIX_MSG + 'Current commit %s', meta.current_revision);
  153. that.reload(process_name, function(err, procs) {
  154. if (err) return cb(err);
  155. return cb ? cb(null, meta.output + res) : that.exitCli(cst.SUCCESS_EXIT);
  156. });
  157. });
  158. });
  159. });
  160. });
  161. };
  162. /**
  163. * CLI method for updating a repository to the next commit (more recent)
  164. * @method forward
  165. * @param {string} process_name
  166. * @return
  167. */
  168. CLI.prototype.forward = function(process_name, cb) {
  169. var that = this;
  170. printOut(cst.PREFIX_MSG + 'Updating to next commit repository for process name %s', process_name);
  171. that.Client.getProcessByNameOrId(process_name, function (err, processes) {
  172. if (err || processes.length === 0) {
  173. printError('No processes with this name or id: %s', process_name);
  174. return cb ? cb({msg: 'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT);
  175. }
  176. var proc = processes[0];
  177. // in case user searched by id/pid
  178. process_name = proc.name;
  179. if (proc.pm2_env.versioning) {
  180. require('vizion').next({folder: proc.pm2_env.versioning.repo_path}, function(err, meta) {
  181. if (err !== null)
  182. return cb ? cb({msg:err}) : that.exitCli(cst.ERROR_EXIT);
  183. if (meta.success === true) {
  184. getPostUpdateCmds(proc.pm2_env.versioning.repo_path, process_name, function (command_list) {
  185. execCommands(proc.pm2_env.versioning.repo_path, command_list, function(err, res) {
  186. if (err !== null)
  187. {
  188. require('vizion').prev({folder: proc.pm2_env.versioning.repo_path}, function(err2, meta2) {
  189. printError(err);
  190. return cb ? cb({msg:meta.output + err}) : that.exitCli(cst.ERROR_EXIT);
  191. });
  192. }
  193. else {
  194. printOut(cst.PREFIX_MSG + 'Process successfully updated %s', process_name);
  195. printOut(cst.PREFIX_MSG + 'Current commit %s', meta.current_revision);
  196. that.reload(process_name, function(err, procs) {
  197. if (err) return cb(err);
  198. return cb ? cb(null, meta.output + res) : that.exitCli(cst.SUCCESS_EXIT);
  199. });
  200. }
  201. });
  202. });
  203. }
  204. else {
  205. printOut(cst.PREFIX_MSG + 'Already up-to-date or an error occured: %s', process_name);
  206. return cb ? cb(null, {success:meta.success}) : that.exitCli(cst.SUCCESS_EXIT);
  207. }
  208. });
  209. }
  210. else {
  211. printOut(cst.PREFIX_MSG + 'No versioning system found for process %s', process_name);
  212. return cb ? cb({success:false, msg: 'No versioning system found'}) : that.exitCli(cst.SUCCESS_EXIT);
  213. }
  214. });
  215. };
  216. var exec = function (cmd, callback) {
  217. var output = '';
  218. var c = child.exec(cmd, {
  219. env: process.env,
  220. maxBuffer: 3*1024*1024,
  221. timeout: EXEC_TIMEOUT
  222. }, function(err) {
  223. if (callback)
  224. callback(err ? err.code : 0, output);
  225. });
  226. c.stdout.on('data', function(data) {
  227. output += data;
  228. });
  229. c.stderr.on('data', function(data) {
  230. output += data;
  231. });
  232. };
  233. /**
  234. *
  235. * @method execCommands
  236. * @param {string} repo_path
  237. * @param {object} command_list
  238. * @return
  239. */
  240. var execCommands = function(repo_path, command_list, cb) {
  241. var stdout = '';
  242. eachSeries(command_list, function(command, callback) {
  243. stdout += '\n' + command;
  244. exec('cd '+repo_path+';'+command,
  245. function(code, output) {
  246. stdout += '\n' + output;
  247. if (code === 0)
  248. callback();
  249. else
  250. callback('`'+command+'` failed');
  251. });
  252. }, function(err) {
  253. if (err)
  254. return cb(stdout + '\n' + err);
  255. return cb(null, stdout);
  256. });
  257. }
  258. /**
  259. * Description Search process.json for post-update commands
  260. * @method getPostUpdateCmds
  261. * @param {string} repo_path
  262. * @param {string} proc_name
  263. * @return
  264. */
  265. var getPostUpdateCmds = function(repo_path, proc_name, cb) {
  266. if (typeof repo_path !== 'string')
  267. return cb([]);
  268. if (repo_path[repo_path.length - 1] !== '/')
  269. repo_path += '/';
  270. var searchForCommands = function(file, callback) {
  271. fs.exists(repo_path+file, function(exists) {
  272. if (exists) {
  273. try {
  274. var conf_string = fs.readFileSync(repo_path + file);
  275. var data = Common.parseConfig(conf_string, repo_path + file);
  276. } catch (e) {
  277. console.error(e.message || e);
  278. }
  279. if (data && data.apps) {
  280. eachSeries(data.apps, function(item, callb) {
  281. if (item.name && item.name === proc_name) {
  282. if (item.post_update && typeof(item.post_update) === 'object') {
  283. if (item.exec_timeout)
  284. EXEC_TIMEOUT = parseInt(item.exec_timeout);
  285. return callb(item.post_update);
  286. }
  287. else {
  288. return callb();
  289. }
  290. }
  291. else
  292. return callb();
  293. }, function(final) {
  294. return callback(final);
  295. });
  296. }
  297. else {
  298. return callback();
  299. }
  300. }
  301. else {
  302. return callback();
  303. }
  304. });
  305. };
  306. eachSeries(['ecosystem.json', 'process.json', 'package.json'], searchForCommands,
  307. function(final) {
  308. return cb(final ? final : []);
  309. });
  310. };
  311. /**
  312. * CLI method for updating a repository
  313. * @method pullAndRestart
  314. * @param {string} process_name name of processes to pull
  315. * @return
  316. */
  317. CLI.prototype.pullAndRestart = function (process_name, cb) {
  318. this._pull({process_name: process_name, action: 'reload'}, cb);
  319. };
  320. /**
  321. * CLI method for updating a repository
  322. * @method pullAndReload
  323. * @param {string} process_name name of processes to pull
  324. * @return
  325. */
  326. CLI.prototype.pullAndReload = function (process_name, cb) {
  327. this._pull({process_name: process_name, action: 'reload'}, cb);
  328. };
  329. /**
  330. * CLI method for updating a repository to a specific commit id
  331. * @method pullCommitId
  332. * @param {object} opts
  333. * @return
  334. */
  335. CLI.prototype._pullCommitId = function (opts, cb) {
  336. this.pullCommitId(opts.pm2_name, opts.commit_id, cb);
  337. };
  338. }