Upgrade feature backend
This commit is contained in:
		| @@ -1,10 +1,14 @@ | |||||||
| 'use strict' | 'use strict' | ||||||
|  |  | ||||||
| const Promise = require('bluebird') | const Promise = require('bluebird') | ||||||
| const https = require('follow-redirects').https | const crypto = require('crypto') | ||||||
| const fs = Promise.promisifyAll(require('fs-extra')) | const fs = Promise.promisifyAll(require('fs-extra')) | ||||||
|  | const https = require('follow-redirects').https | ||||||
|  | const klaw = require('klaw') | ||||||
| const path = require('path') | const path = require('path') | ||||||
|  | const pm2 = Promise.promisifyAll(require('pm2')) | ||||||
| const tar = require('tar') | const tar = require('tar') | ||||||
|  | const through2 = require('through2') | ||||||
| const zlib = require('zlib') | const zlib = require('zlib') | ||||||
| const _ = require('lodash') | const _ = require('lodash') | ||||||
|  |  | ||||||
| @@ -13,30 +17,118 @@ module.exports = { | |||||||
|   _remoteFile: 'https://github.com/Requarks/wiki/releases/download/{0}/wiki-js.tar.gz', |   _remoteFile: 'https://github.com/Requarks/wiki/releases/download/{0}/wiki-js.tar.gz', | ||||||
|   _installDir: '', |   _installDir: '', | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Install a version of Wiki.js | ||||||
|  |    * | ||||||
|  |    * @param {any} targetTag The version to install | ||||||
|  |    * @returns {Promise} Promise of the operation | ||||||
|  |    */ | ||||||
|   install (targetTag) { |   install (targetTag) { | ||||||
|     let self = this |     let self = this | ||||||
|  |  | ||||||
|     self._installDir = path.resolve(ROOTPATH, appconfig.paths.data, 'install') |     self._installDir = path.resolve(ROOTPATH, appconfig.paths.data, 'install') | ||||||
|  |  | ||||||
|     return fs.ensureDirAsync(self._installDir).then(() => { |     return fs.ensureDirAsync(self._installDir).then(() => { | ||||||
|  |       return fs.emptyDirAsync(self._installDir) | ||||||
|  |     }).then(() => { | ||||||
|       let remoteURL = _.replace(self._remoteFile, '{0}', targetTag) |       let remoteURL = _.replace(self._remoteFile, '{0}', targetTag) | ||||||
|  |  | ||||||
|       return new Promise((resolve, reject) => { |       return new Promise((resolve, reject) => { | ||||||
|  |         /** | ||||||
|  |          * Fetch tarball and extract to temporary folder | ||||||
|  |          */ | ||||||
|         https.get(remoteURL, resp => { |         https.get(remoteURL, resp => { | ||||||
|           if (resp.statusCode !== 200) { |           if (resp.statusCode !== 200) { | ||||||
|             return reject(new Error('Remote file not found')) |             return reject(new Error('Remote file not found')) | ||||||
|           } |           } | ||||||
|  |           winston.info('[SERVER.System] Install tarball found. Downloading...') | ||||||
|  |  | ||||||
|           resp.pipe(zlib.createGunzip()) |           resp.pipe(zlib.createGunzip()) | ||||||
|           .pipe(tar.Extract({ path: self._installDir })) |           .pipe(tar.Extract({ path: self._installDir })) | ||||||
|           .on('error', err => reject(err)) |           .on('error', err => reject(err)) | ||||||
|           .on('end', () => { |           .on('end', () => { | ||||||
|  |             winston.info('[SERVER.System] Tarball extracted. Comparing files...') | ||||||
|  |             /** | ||||||
|  |              * Replace old files | ||||||
|  |              */ | ||||||
|  |             klaw(self._installDir) | ||||||
|  |             .on('error', err => reject(err)) | ||||||
|  |             .on('end', () => { | ||||||
|  |               winston.info('[SERVER.System] All files were updated successfully.') | ||||||
|               resolve(true) |               resolve(true) | ||||||
|             }) |             }) | ||||||
|  |             .pipe(self.replaceFile()) | ||||||
|  |           }) | ||||||
|  |         }) | ||||||
|       }) |       }) | ||||||
|     }).then(() => { |     }).then(() => { | ||||||
|  |       winston.info('[SERVER.System] Cleaning install leftovers...') | ||||||
|  |       return fs.removeAsync(self._installDir).then(() => { | ||||||
|  |         winston.info('[SERVER.System] Restarting Wiki.js...') | ||||||
|  |         return pm2.restartAsync('wiki').catch(err => { | ||||||
|  |           winston.error('Unable to restart Wiki.js via pm2... Do a manual restart!') | ||||||
|  |           process.exit() | ||||||
|  |         }) | ||||||
|  |       }) | ||||||
|  |     }).catch(err => { | ||||||
|  |       winston.warn(err) | ||||||
|  |     }) | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Replace file if different | ||||||
|  |    */ | ||||||
|  |   replaceFile () { | ||||||
|  |     let self = this | ||||||
|  |     return through2.obj((item, enc, next) => { | ||||||
|  |       if (!item.stats.isDirectory()) { | ||||||
|  |         self.digestFile(item.path).then(sourceHash => { | ||||||
|  |           let destFilePath = _.replace(item.path, self._installDir, ROOTPATH) | ||||||
|  |           return self.digestFile(destFilePath).then(targetHash => { | ||||||
|  |             if (sourceHash === targetHash) { | ||||||
|  |               winston.log('verbose', '[SERVER.System] Skipping ' + destFilePath) | ||||||
|  |               return fs.removeAsync(item.path).then(() => { | ||||||
|  |                 return next() || true | ||||||
|               }) |               }) | ||||||
|  |             } else { | ||||||
|  |               winston.log('verbose', '[SERVER.System] Updating ' + destFilePath + '...') | ||||||
|  |               return fs.moveAsync(item.path, destFilePath, { overwrite: true }).then(() => { | ||||||
|  |                 return next() || true | ||||||
|  |               }) | ||||||
|  |             } | ||||||
|  |           }) | ||||||
|  |         }).catch(err => { | ||||||
|  |           throw err | ||||||
|  |         }) | ||||||
|  |       } else { | ||||||
|  |         next() | ||||||
|  |       } | ||||||
|  |     }) | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Generate the hash of a file | ||||||
|  |    * | ||||||
|  |    * @param {String} filePath The absolute path of the file | ||||||
|  |    * @return {Promise<String>} Promise of the hash result | ||||||
|  |    */ | ||||||
|  |   digestFile: (filePath) => { | ||||||
|  |     return new Promise((resolve, reject) => { | ||||||
|  |       let hash = crypto.createHash('sha1') | ||||||
|  |       hash.setEncoding('hex') | ||||||
|  |       fs.createReadStream(filePath) | ||||||
|  |       .on('error', err => { reject(err) }) | ||||||
|  |       .on('end', () => { | ||||||
|  |         hash.end() | ||||||
|  |         resolve(hash.read()) | ||||||
|  |       }) | ||||||
|  |       .pipe(hash) | ||||||
|  |     }).catch(err => { | ||||||
|  |       if (err.code === 'ENOENT') { | ||||||
|  |         return '0' | ||||||
|  |       } else { | ||||||
|  |         throw err | ||||||
|  |       } | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -82,6 +82,7 @@ | |||||||
|     "passport-local": "^1.0.0", |     "passport-local": "^1.0.0", | ||||||
|     "passport-windowslive": "^1.0.2", |     "passport-windowslive": "^1.0.2", | ||||||
|     "passport.socketio": "^3.7.0", |     "passport.socketio": "^3.7.0", | ||||||
|  |     "pm2": "^2.4.0", | ||||||
|     "pug": "^2.0.0-beta11", |     "pug": "^2.0.0-beta11", | ||||||
|     "read-chunk": "^2.0.0", |     "read-chunk": "^2.0.0", | ||||||
|     "remove-markdown": "^0.1.0", |     "remove-markdown": "^0.1.0", | ||||||
| @@ -96,6 +97,7 @@ | |||||||
|     "stopword": "^0.1.1", |     "stopword": "^0.1.1", | ||||||
|     "stream-to-promise": "^2.2.0", |     "stream-to-promise": "^2.2.0", | ||||||
|     "tar": "^2.2.1", |     "tar": "^2.2.1", | ||||||
|  |     "through2": "^2.0.3", | ||||||
|     "validator": "^6.2.0", |     "validator": "^6.2.0", | ||||||
|     "validator-as-promised": "^1.0.2", |     "validator-as-promised": "^1.0.2", | ||||||
|     "winston": "^2.3.0" |     "winston": "^2.3.0" | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user