228 lines
6.1 KiB
JavaScript
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);
|
|
}
|
|
}
|
|
})();
|