refactor: cli/upgrade async/await (#9558)

* refactor: cli/upgrade async/await

async/await cli/upgrade-plugins
remove unused payload.files

* fix: add missing await
v1.18.x
Barış Soner Uşaklı 4 years ago committed by GitHub
parent 1ce595083a
commit ac86937c88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -66,7 +66,7 @@ function installAll() {
} }
} }
} catch (e) { } catch (e) {
// ignore console.error(e);
} }
try { try {
cproc.execSync(command + (prod ? ' --production' : ''), { cproc.execSync(command + (prod ? ' --production' : ''), {

@ -1,6 +1,5 @@
'use strict'; 'use strict';
const async = require('async');
const prompt = require('prompt'); const prompt = require('prompt');
const request = require('request'); const request = require('request');
const cproc = require('child_process'); const cproc = require('child_process');
@ -8,6 +7,7 @@ const semver = require('semver');
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const nconf = require('nconf'); const nconf = require('nconf');
const util = require('util');
const { paths, pluginNamePattern } = require('../constants'); const { paths, pluginNamePattern } = require('../constants');
@ -22,190 +22,147 @@ if (process.platform === 'win32') {
packageManagerExecutable += '.cmd'; packageManagerExecutable += '.cmd';
} }
function getModuleVersions(modules, callback) { async function getModuleVersions(modules) {
const versionHash = {}; const versionHash = {};
const batch = require('../batch');
async.eachLimit(modules, 50, (module, next) => { await batch.processArray(modules, async (moduleNames) => {
fs.readFile(path.join(paths.nodeModules, module, 'package.json'), { encoding: 'utf-8' }, (err, pkg) => { await Promise.all(moduleNames.map(async (module) => {
if (err) { let pkg = await fs.promises.readFile(
return next(err); path.join(paths.nodeModules, module, 'package.json'), { encoding: 'utf-8' }
} );
pkg = JSON.parse(pkg);
try { versionHash[module] = pkg.version;
pkg = JSON.parse(pkg); }));
versionHash[module] = pkg.version; }, {
next(); batch: 50,
} catch (err) {
next(err);
}
});
}, (err) => {
callback(err, versionHash);
}); });
return versionHash;
} }
function getInstalledPlugins(callback) { async function getInstalledPlugins() {
async.parallel({ let [deps, bundled] = await Promise.all([
files: async.apply(fs.readdir, paths.nodeModules), fs.promises.readFile(paths.currentPackage, { encoding: 'utf-8' }),
deps: async.apply(fs.readFile, paths.currentPackage, { encoding: 'utf-8' }), fs.promises.readFile(paths.installPackage, { encoding: 'utf-8' }),
bundled: async.apply(fs.readFile, paths.installPackage, { encoding: 'utf-8' }), ]);
}, (err, payload) => {
if (err) { deps = Object.keys(JSON.parse(deps).dependencies)
return callback(err); .filter(pkgName => pluginNamePattern.test(pkgName));
} bundled = Object.keys(JSON.parse(bundled).dependencies)
.filter(pkgName => pluginNamePattern.test(pkgName));
payload.files = payload.files.filter(file => pluginNamePattern.test(file)); // Whittle down deps to send back only extraneously installed plugins/themes/etc
const checklist = deps.filter((pkgName) => {
if (bundled.includes(pkgName)) {
return false;
}
// Ignore git repositories
try { try {
payload.deps = Object.keys(JSON.parse(payload.deps).dependencies); fs.accessSync(path.join(paths.nodeModules, pkgName, '.git'));
payload.bundled = Object.keys(JSON.parse(payload.bundled).dependencies); return false;
} catch (err) { } catch (e) {
return callback(err); return true;
} }
});
payload.bundled = payload.bundled.filter(pkgName => pluginNamePattern.test(pkgName)); return await getModuleVersions(checklist);
payload.deps = payload.deps.filter(pkgName => pluginNamePattern.test(pkgName)); }
// Whittle down deps to send back only extraneously installed plugins/themes/etc
const checklist = payload.deps.filter((pkgName) => {
if (payload.bundled.includes(pkgName)) {
return false;
}
// Ignore git repositories
try {
fs.accessSync(path.join(paths.nodeModules, pkgName, '.git'));
return false;
} catch (e) {
return true;
}
});
getModuleVersions(checklist, callback); async function getCurrentVersion() {
}); let pkg = await fs.promises.readFile(paths.installPackage, { encoding: 'utf-8' });
pkg = JSON.parse(pkg);
return pkg.version;
} }
function getCurrentVersion(callback) { const getSuggestedModules = util.promisify((nbbVersion, toCheck, cb) => {
fs.readFile(paths.installPackage, { encoding: 'utf-8' }, (err, pkg) => { request({
method: 'GET',
url: `https://packages.nodebb.org/api/v1/suggest?version=${nbbVersion}&package[]=${toCheck.join('&package[]=')}`,
json: true,
}, (err, res, body) => {
if (err) { if (err) {
return callback(err); process.stdout.write('error'.red + ''.reset);
return cb(err);
} }
if (!Array.isArray(body) && toCheck.length === 1) {
try { body = [body];
pkg = JSON.parse(pkg);
} catch (err) {
return callback(err);
} }
callback(null, pkg.version); cb(null, body);
}); });
} });
function checkPlugins(standalone, callback) { async function checkPlugins() {
if (standalone) { process.stdout.write('Checking installed plugins and themes for updates... ');
process.stdout.write('Checking installed plugins and themes for updates... '); const [plugins, nbbVersion] = await Promise.all([
getInstalledPlugins,
getCurrentVersion,
]);
const toCheck = Object.keys(plugins);
if (!toCheck.length) {
process.stdout.write(' OK'.green + ''.reset);
return []; // no extraneous plugins installed
} }
const suggestedModules = await getSuggestedModules(nbbVersion, toCheck);
process.stdout.write(' OK'.green + ''.reset);
let current;
let suggested;
const upgradable = suggestedModules.map((suggestObj) => {
current = plugins[suggestObj.package];
suggested = suggestObj.version;
if (suggestObj.code === 'match-found' && semver.gt(suggested, current)) {
return {
name: suggestObj.package,
current: current,
suggested: suggested,
};
}
return null;
}).filter(Boolean);
async.waterfall([ return upgradable;
async.apply(async.parallel, {
plugins: getInstalledPlugins,
version: getCurrentVersion,
}),
function (payload, next) {
const toCheck = Object.keys(payload.plugins);
if (!toCheck.length) {
process.stdout.write(' OK'.green + ''.reset);
return next(null, []); // no extraneous plugins installed
}
request({
method: 'GET',
url: `https://packages.nodebb.org/api/v1/suggest?version=${payload.version}&package[]=${toCheck.join('&package[]=')}`,
json: true,
}, (err, res, body) => {
if (err) {
process.stdout.write('error'.red + ''.reset);
return next(err);
}
process.stdout.write(' OK'.green + ''.reset);
if (!Array.isArray(body) && toCheck.length === 1) {
body = [body];
}
let current;
let suggested;
const upgradable = body.map((suggestObj) => {
current = payload.plugins[suggestObj.package];
suggested = suggestObj.version;
if (suggestObj.code === 'match-found' && semver.gt(suggested, current)) {
return {
name: suggestObj.package,
current: current,
suggested: suggested,
};
}
return null;
}).filter(Boolean);
next(null, upgradable);
});
},
], callback);
} }
function upgradePlugins(callback) { async function upgradePlugins() {
let standalone = false; try {
if (typeof callback !== 'function') { const found = await checkPlugins();
callback = function () {};
standalone = true;
}
checkPlugins(standalone, (err, found) => {
if (err) {
console.log('Warning'.yellow + ': An unexpected error occured when attempting to verify plugin upgradability'.reset);
return callback(err);
}
if (found && found.length) { if (found && found.length) {
process.stdout.write(`\n\nA total of ${String(found.length).bold} package(s) can be upgraded:\n\n`); process.stdout.write(`\n\nA total of ${String(found.length).bold} package(s) can be upgraded:\n\n`);
found.forEach((suggestObj) => { found.forEach((suggestObj) => {
process.stdout.write(`${' * '.yellow + suggestObj.name.reset} (${suggestObj.current.yellow}${' -> '.reset}${suggestObj.suggested.green}${')\n'.reset}`); process.stdout.write(`${' * '.yellow + suggestObj.name.reset} (${suggestObj.current.yellow}${' -> '.reset}${suggestObj.suggested.green}${')\n'.reset}`);
}); });
} else { } else {
if (standalone) { console.log('\nAll packages up-to-date!'.green + ''.reset);
console.log('\nAll packages up-to-date!'.green + ''.reset); return;
}
return callback();
} }
prompt.message = ''; prompt.message = '';
prompt.delimiter = ''; prompt.delimiter = '';
const promptGet = util.promisify((schema, callback) => prompt.get(schema, callback));
prompt.start(); prompt.start();
prompt.get({ const result = await promptGet({
name: 'upgrade', name: 'upgrade',
description: '\nProceed with upgrade (y|n)?'.reset, description: '\nProceed with upgrade (y|n)?'.reset,
type: 'string', type: 'string',
}, (err, result) => {
if (err) {
return callback(err);
}
if (['y', 'Y', 'yes', 'YES'].includes(result.upgrade)) {
console.log('\nUpgrading packages...');
const args = packageManagerInstallArgs.concat(found.map(suggestObj => `${suggestObj.name}@${suggestObj.suggested}`));
cproc.execFile(packageManagerExecutable, args, { stdio: 'ignore' }, (err) => {
callback(err, false);
});
} else {
console.log('Package upgrades skipped'.yellow + '. Check for upgrades at any time by running "'.reset + './nodebb upgrade -p'.green + '".'.reset);
callback();
}
}); });
});
if (['y', 'Y', 'yes', 'YES'].includes(result.upgrade)) {
console.log('\nUpgrading packages...');
const args = packageManagerInstallArgs.concat(found.map(suggestObj => `${suggestObj.name}@${suggestObj.suggested}`));
cproc.execFileSync(packageManagerExecutable, args, { stdio: 'ignore' });
} else {
console.log('Package upgrades skipped'.yellow + '. Check for upgrades at any time by running "'.reset + './nodebb upgrade -p'.green + '".'.reset);
}
} catch (err) {
console.log('Warning'.yellow + ': An unexpected error occured when attempting to verify plugin upgradability'.reset);
throw err;
}
} }
exports.upgradePlugins = upgradePlugins; exports.upgradePlugins = upgradePlugins;

@ -1,6 +1,5 @@
'use strict'; 'use strict';
const async = require('async');
const nconf = require('nconf'); const nconf = require('nconf');
const packageInstall = require('./package-install'); const packageInstall = require('./package-install');
@ -9,61 +8,52 @@ const { upgradePlugins } = require('./upgrade-plugins');
const steps = { const steps = {
package: { package: {
message: 'Updating package.json file with defaults...', message: 'Updating package.json file with defaults...',
handler: function (next) { handler: function () {
packageInstall.updatePackageFile(); packageInstall.updatePackageFile();
packageInstall.preserveExtraneousPlugins(); packageInstall.preserveExtraneousPlugins();
process.stdout.write(' OK\n'.green); process.stdout.write(' OK\n'.green);
next();
}, },
}, },
install: { install: {
message: 'Bringing base dependencies up to date...', message: 'Bringing base dependencies up to date...',
handler: function (next) { handler: function () {
process.stdout.write(' started\n'.green); process.stdout.write(' started\n'.green);
packageInstall.installAll(); packageInstall.installAll();
next();
}, },
}, },
plugins: { plugins: {
message: 'Checking installed plugins for updates...', message: 'Checking installed plugins for updates...',
handler: function (next) { handler: async function () {
async.series([ await require('../database').init();
require('../database').init, await upgradePlugins();
upgradePlugins,
], next);
}, },
}, },
schema: { schema: {
message: 'Updating NodeBB data store schema...', message: 'Updating NodeBB data store schema...',
handler: function (next) { handler: async function () {
async.series([ await require('../database').init();
require('../database').init, await require('../meta').configs.init();
require('../meta').configs.init, await require('../upgrade').run();
require('../upgrade').run,
], next);
}, },
}, },
build: { build: {
message: 'Rebuilding assets...', message: 'Rebuilding assets...',
handler: require('../meta/build').buildAll, handler: async function () {
await require('../meta/build').buildAll();
},
}, },
}; };
function runSteps(tasks) { async function runSteps(tasks) {
tasks = tasks.map((key, i) => function (next) { try {
process.stdout.write(`\n${(`${i + 1}. `).bold}${steps[key].message.yellow}`); for (let i = 0; i < tasks.length; i++) {
return steps[key].handler((err) => { const step = steps[tasks[i]];
if (err) { return next(err); } if (step && step.message && step.handler) {
next(); process.stdout.write(`\n${(`${i + 1}. `).bold}${step.message.yellow}`);
}); /* eslint-disable-next-line */
}); await step.handler();
}
async.series(tasks, (err) => {
if (err) {
console.error(`Error occurred during upgrade: ${err.stack}`);
throw err;
} }
const message = 'NodeBB Upgrade Complete!'; const message = 'NodeBB Upgrade Complete!';
// some consoles will return undefined/zero columns, // some consoles will return undefined/zero columns,
// so just use 2 spaces in upgrade script if we can't get our column count // so just use 2 spaces in upgrade script if we can't get our column count
@ -73,10 +63,13 @@ function runSteps(tasks) {
console.log(`\n\n${spaces}${message.green.bold}${'\n'.reset}`); console.log(`\n\n${spaces}${message.green.bold}${'\n'.reset}`);
process.exit(); process.exit();
}); } catch (err) {
console.error(`Error occurred during upgrade: ${err.stack}`);
throw err;
}
} }
function runUpgrade(upgrades, options) { async function runUpgrade(upgrades, options) {
console.log('\nUpdating NodeBB...'.cyan); console.log('\nUpdating NodeBB...'.cyan);
options = options || {}; options = options || {};
// disable mongo timeouts during upgrade // disable mongo timeouts during upgrade
@ -88,23 +81,14 @@ function runUpgrade(upgrades, options) {
options.plugins || options.schema || options.build) { options.plugins || options.schema || options.build) {
tasks = tasks.filter(key => options[key]); tasks = tasks.filter(key => options[key]);
} }
runSteps(tasks); await runSteps(tasks);
return; return;
} }
async.series([ await require('../database').init();
require('../database').init, await require('../meta').configs.init();
require('../meta').configs.init, await require('../upgrade').runParticular(upgrades);
async function () { process.exit(0);
await require('../upgrade').runParticular(upgrades);
},
], (err) => {
if (err) {
throw err;
}
process.exit(0);
});
} }
exports.upgrade = runUpgrade; exports.upgrade = runUpgrade;

Loading…
Cancel
Save