Files
explorer-api/plugins/hyperion-plugin-manager.js
Igor Lins e Silva 279f5d9474 merge 3.3.5 to master
2022-09-11 03:42:18 -03:00

228 lines
6.1 KiB
JavaScript

const fs = require('fs');
const got = require('got');
const path = require('path');
const readline = require('readline');
const {spawn} = require('child_process');
const crypto = require('crypto');
const command = process.argv[2];
const pluginName = process.argv[3];
const flags = [];
process.argv.forEach(value => {
if (value.startsWith('--')) {
flags.push(value.slice(2));
}
});
if (command === 'install') {
if (!pluginName) {
console.log('Please inform a plugin name!\n"npm run plugin-manager install PLUGIN_NAME"');
console.log('Exiting now!');
process.exit(0);
}
}
console.log(`Hyperion Plugin Manager`);
console.log(`>> ${command} ${pluginName}`);
let catalog;
async function hashItem(item) {
if (fs.lstatSync(item).isDirectory()) {
const dir = fs.readdirSync(item);
const sha = crypto.createHash('sha1');
for (const file of dir) {
if (file === '.git' && fs.lstatSync(path.join(item, file)).isDirectory()) {
sha.update('');
} else {
const hash = await hashItem(path.join(item, file));
sha.update(hash.toString());
}
}
return sha.digest('hex');
} else {
const sha = crypto.createHash('sha1');
const reader = fs.createReadStream(item);
return new Promise(resolve => {
reader.on('data', chunk => {
sha.update(chunk);
});
reader.on('close', () => {
resolve(sha.digest('hex'));
});
});
}
}
async function verifyInstallation(data) {
console.log('Verifying integrity...');
const hash = await hashItem(data.installPath);
console.log(`SHA1 Hash: ${hash}`);
if (!flags.includes('skip-validation')) {
if (hash !== data['integrityHash']) {
console.log('WARNING! Integrity hash dos not match!');
console.log(`Expected:\t${data['integrityHash']}`);
console.log(`Current:\t${hash}`);
process.exit(0);
}
const installedFiles = fs.readdirSync(data.installPath);
if (!installedFiles.includes('package.json')) {
console.log('package.json not found!');
process.exit(0);
}
}
}
function startInstallation(data) {
const installPath = path.join(__dirname, 'repos', data.name);
data['installPath'] = installPath;
let clone = false;
if (fs.existsSync(installPath)) {
if (flags.includes('reinstall')) {
console.log('Removing installed plugin...');
fs.rmdirSync(installPath, {recursive: true});
clone = true;
}
} else {
clone = true;
}
if (clone) {
const gitClone = spawn('git', ['clone', data['repo'], installPath]);
gitClone.stdout.on('data', chunk => {
console.log(`->> ${chunk}`);
});
gitClone.stderr.on('data', chunk => {
console.log(`->> ${chunk}`);
});
gitClone.on('close', (code) => {
if (code !== 0) {
console.log(`process exited with code ${code}`);
}
verifyInstallation(data).catch(console.log);
});
} else {
verifyInstallation(data).catch(console.log);
}
}
async function installCommand() {
const cachedCatalogPath = path.join(__dirname, 'catalog.cache');
if (fs.existsSync(cachedCatalogPath)) {
const cachedCatalogStat = fs.statSync(cachedCatalogPath);
if (Date.now() - cachedCatalogStat.ctimeMs < (60 * 60 * 1000)) {
catalog = JSON.parse(fs.readFileSync(cachedCatalogPath).toString());
}
}
if (flags.includes('ignore-cache')) {
console.log(`Ignoring current catalog cache!`);
catalog = null;
}
if (!catalog) {
// update catalog
console.log(`Updating catalog...`);
catalog = await got.get('https://raw.githubusercontent.com/eosrio/hyperion-plugins/main/catalog.json').json();
if (!catalog) {
console.log('Error loading catalog!');
process.exit(1);
}
fs.writeFileSync(cachedCatalogPath, JSON.stringify(catalog));
}
const pluginData = catalog.plugins.find((p) => {
return p.name === pluginName;
});
if (pluginData) {
console.log(`Plugin found!`);
console.log(` Description:\t${pluginData['desc']}`);
console.log(` Version:\t${pluginData['tag']}`);
console.log(` Repository:\t${pluginData['repo']}`);
const rl = readline.createInterface({input: process.stdin, output: process.stdout});
// confirm installation
rl.question(`Confirm installation of ${pluginData.name} ${pluginData.tag}? [Y/n] (default=Y) `, answer => {
if (!answer || answer.toUpperCase() === 'Y') {
console.log('Downloading plugin...');
startInstallation(pluginData);
} else {
console.log('Aborted!');
}
rl.close();
});
} else {
console.log(`Plugin "${pluginName}" not found!`);
console.log('Similar results:');
for (const plugin of catalog.plugins) {
if (plugin.name.startsWith(pluginName.slice(0, 2))) {
console.log(`\t - ${plugin.name}\n\t\t${plugin.desc}\n`);
}
}
}
}
async function buildPlugin(path, name) {
console.log(`-------- ⚒ ${name} -----------`);
// run npm install
await new Promise(resolve => {
const npmInstall = spawn('npm', ['install'], {
cwd: path,
stdio: 'inherit',
});
npmInstall.on('close', (code) => {
if (code !== 0) {
console.log(`process exited with code ${code}`);
}
resolve(true);
});
});
// typescript build
await new Promise(resolve => {
const npmInstall = spawn('npm', ['run', 'build'], {
cwd: path,
stdio: 'inherit',
});
npmInstall.on('close', (code) => {
if (code !== 0) {
console.log(`process exited with code ${code}`);
}
resolve(true);
});
});
console.log('-------------------------------');
}
async function buildAllCommand() {
const installPath = path.join(__dirname, 'repos');
const installedPlugins = fs.readdirSync(installPath);
for (const pluginDir of installedPlugins) {
await buildPlugin(path.join(installPath, pluginDir), pluginDir);
}
}
(async () => {
switch (command) {
case 'install': {
await installCommand();
break;
}
case 'build-all': {
await buildAllCommand();
console.log('Build All completed!');
break;
}
default: {
console.log(`Unknown command: ${command}. Exiting now!`);
process.exit(1);
}
}
})();