From 7785c7ee191c2d4565faf6ff2f8d2b2199d28d3a Mon Sep 17 00:00:00 2001 From: undefined Date: Mon, 23 May 2022 16:40:42 +0800 Subject: [PATCH] core: use cac command parser --- packages/hydrooj/bin/commands.ts | 171 +++++++++++++++---------------- packages/hydrooj/bin/hydrooj.js | 132 +----------------------- packages/hydrooj/package.json | 2 +- 3 files changed, 87 insertions(+), 218 deletions(-) diff --git a/packages/hydrooj/bin/commands.ts b/packages/hydrooj/bin/commands.ts index 6caf16626..f7a15432a 100644 --- a/packages/hydrooj/bin/commands.ts +++ b/packages/hydrooj/bin/commands.ts @@ -1,10 +1,10 @@ import child from 'child_process'; import os from 'os'; import path from 'path'; +import cac from 'cac'; import fs from 'fs-extra'; -import arg from '@hydrooj/utils/lib/arg'; -const argv = arg(); +const argv = cac().parse(); const exec = (...args) => { console.log('Executing: ', args[0], args[1].join(' ')); @@ -13,7 +13,6 @@ const exec = (...args) => { if (res.status) throw new Error(`Error: Exited with code ${res.status}`); return res; }; - function buildUrl(opts) { let mongourl = `${opts.protocol || 'mongodb'}://`; if (opts.username) mongourl += `${opts.username}:${opts.password}@`; @@ -28,56 +27,9 @@ const addonPath = path.resolve(hydroPath, 'addon.json'); if (!fs.existsSync(addonPath)) fs.writeFileSync(addonPath, '[]'); let addons = JSON.parse(fs.readFileSync(addonPath).toString()); -if (argv._[0] === 'db') { - const dbConfig = fs.readFileSync(path.resolve(hydroPath, 'config.json'), 'utf-8'); - const url = buildUrl(JSON.parse(dbConfig)); - child.spawn('mongo', [url], { stdio: 'inherit' }); - process.exit(0); -} - -if (argv._[0] === 'backup') { - const dbConfig = fs.readFileSync(path.resolve(hydroPath, 'config.json'), 'utf-8'); - const url = buildUrl(JSON.parse(dbConfig)); - const dir = `${os.tmpdir()}/${Math.random().toString(36).substring(2)}`; - exec('mongodump', [url, `--out=${dir}/dump`], { stdio: 'inherit' }); - // Do not backup .env & config.json as they are all related to local installation - const env = `${os.homedir()}/.hydro/addon.json`; - if (fs.existsSync(env)) fs.copySync(env, `${dir}/addon.json`); - const target = `${process.cwd()}/backup-${new Date().toISOString().replace(':', '-').split(':')[0]}.zip`; - exec('zip', ['-r', target, 'dump'], { cwd: dir, stdio: 'inherit' }); - if (!argv.dbOnly) { - exec('zip', ['-r', target, 'file'], { cwd: '/data', stdio: 'inherit' }); - } - exec('rm', ['-rf', dir]); - console.log(`Database backup saved at ${target}`); - process.exit(0); -} - -if (argv._[0] === 'restore') { - const dbConfig = fs.readFileSync(path.resolve(hydroPath, 'config.json'), 'utf-8'); - const url = buildUrl(JSON.parse(dbConfig)); - const dir = `${os.tmpdir()}/${Math.random().toString(36).substring(2)}`; - if (!fs.existsSync(argv._[1])) { - console.error('Cannot find file'); - process.exit(1); - } - exec('unzip', [argv._[1], '-d', dir], { stdio: 'inherit' }); - exec('mongorestore', [`--uri=${url}`, `--dir=${dir}/dump/${JSON.parse(dbConfig).name}`, '--drop'], { stdio: 'inherit' }); - if (fs.existsSync(`${dir}/file`)) { - exec('rm', ['-rf', '/data/file/*'], { stdio: 'inherit' }); - exec('bash', ['-c', `mv ${dir}/file/* /data/file`], { stdio: 'inherit' }); - } - if (fs.existsSync(`${dir}/addon.json`)) { - fs.copySync(`${dir}/addon.json`, `${os.homedir()}/.hydro/addon.json`, { overwrite: true }); - } - fs.removeSync(dir); - console.log('Successfully restored.'); - process.exit(0); -} - if (!addons.includes('@hydrooj/ui-default')) { try { - const ui = argv.ui as string || '@hydrooj/ui-default'; + const ui = argv.options.ui || '@hydrooj/ui-default'; require.resolve(ui); addons.push(ui); } catch (e) { @@ -85,46 +37,93 @@ if (!addons.includes('@hydrooj/ui-default')) { } } -if (argv._[0] && argv._[0] !== 'cli') { - const operation = argv._[0]; - const arg1 = argv._[1]; - const arg2 = argv._[2]; - if (operation === 'addon') { - if (arg1 === 'create') { - fs.mkdirSync('/root/addon'); - child.execSync('yarn init -y', { cwd: '/root/addon' }); - fs.mkdirSync('/root/addon/templates'); - fs.mkdirSync('/root/addon/locales'); - fs.mkdirSync('/root/addon/public'); - addons.push('/root/addon'); - } else if (arg1 === 'add') { - for (let i = 0; i < addons.length; i++) { - if (addons[i] === arg2) { - addons.splice(i, 1); - break; - } +if (!argv.args[0] || argv.args[0] === 'cli') { + const hydro = require('../src/loader'); + addons = Array.from(new Set(addons)); + for (const addon of addons) hydro.addon(addon); + (argv.args[0] === 'cli' ? hydro.loadCli : hydro.load)().catch((e) => { + console.error(e); + process.exit(1); + }); +} else { + const cli = cac(); + cli.command('db').action(() => { + const dbConfig = fs.readFileSync(path.resolve(hydroPath, 'config.json'), 'utf-8'); + const url = buildUrl(JSON.parse(dbConfig)); + child.spawn('mongo', [url], { stdio: 'inherit' }); + }); + cli.command('backup').action(() => { + const dbConfig = fs.readFileSync(path.resolve(hydroPath, 'config.json'), 'utf-8'); + const url = buildUrl(JSON.parse(dbConfig)); + const dir = `${os.tmpdir()}/${Math.random().toString(36).substring(2)}`; + exec('mongodump', [url, `--out=${dir}/dump`], { stdio: 'inherit' }); + const env = `${os.homedir()}/.hydro/env`; + if (fs.existsSync(env)) fs.copySync(env, `${dir}/env`); + const target = `${process.cwd()}/backup-${new Date().toISOString().replace(':', '-').split(':')[0]}.zip`; + exec('zip', ['-r', target, 'dump'], { cwd: dir, stdio: 'inherit' }); + if (!argv.options.dbOnly) { + exec('zip', ['-r', target, 'file'], { cwd: '/data', stdio: 'inherit' }); + } + exec('rm', ['-rf', dir]); + console.log(`Database backup saved at ${target}`); + }); + cli.command('restore ').action((filename) => { + const dbConfig = fs.readFileSync(path.resolve(hydroPath, 'config.json'), 'utf-8'); + const url = buildUrl(JSON.parse(dbConfig)); + const dir = `${os.tmpdir()}/${Math.random().toString(36).substring(2)}`; + if (!fs.existsSync(filename)) { + console.error('Cannot find file'); + return; + } + exec('unzip', [filename, '-d', dir], { stdio: 'inherit' }); + exec('mongorestore', [`--uri=${url}`, `--dir=${dir}/dump/hydro`, '--drop'], { stdio: 'inherit' }); + if (fs.existsSync(`${dir}/file`)) { + exec('rm', ['-rf', '/data/file/*'], { stdio: 'inherit' }); + exec('bash', ['-c', `mv ${dir}/file/* /data/file`], { stdio: 'inherit' }); + } + if (fs.existsSync(`${dir}/env`)) { + fs.copySync(`${dir}/env`, `${os.homedir()}/.hydro/env`, { overwrite: true }); + } + fs.removeSync(dir); + console.log('Successfully restored.'); + }); + cli.command('addon add ').action((name) => { + for (let i = 0; i < addons.length; i++) { + if (addons[i] === name) { + addons.splice(i, 1); + break; } - addons.push(arg2); - } else if (arg1 === 'remove') { - for (let i = 0; i < addons.length; i++) { - if (addons[i] === arg2) { - addons.splice(i, 1); - break; - } + } + addons.push(name); + addons = Array.from(new Set(addons)); + console.log('Current Addons: ', addons); + fs.writeFileSync(addonPath, JSON.stringify(addons, null, 2)); + }); + cli.command('addon remove ').action((name) => { + for (let i = 0; i < addons.length; i++) { + if (addons[i] === name) { + addons.splice(i, 1); + break; } } addons = Array.from(new Set(addons)); console.log('Current Addons: ', addons); fs.writeFileSync(addonPath, JSON.stringify(addons, null, 2)); - process.exit(0); - } - console.error('Unknown command: ', argv._[0]); -} else { - const hydro = require('../src/loader'); - addons = Array.from(new Set(addons)); - for (const addon of addons) hydro.addon(addon); - (argv._[0] === 'cli' ? hydro.loadCli : hydro.load)().catch((e) => { - console.error(e); - process.exit(1); }); + cli.command('addon create [name]').action((name) => { + name ||= '/root/addon'; + fs.mkdirSync(name); + child.execSync('yarn init -y', { cwd: name }); + fs.mkdirSync(`${name}/templates`); + fs.mkdirSync(`${name}/locales`); + fs.mkdirSync(`${name}/public`); + addons.push(name); + console.log(`Addon created at ${name}`); + }); + cli.command('addon').action(() => { + console.log('Current Addons: ', addons); + }); + cli.help(); + cli.parse(); + if (!cli.matchedCommand) console.log('Unknown command.'); } diff --git a/packages/hydrooj/bin/hydrooj.js b/packages/hydrooj/bin/hydrooj.js index e4423944c..b37cb4ca0 100755 --- a/packages/hydrooj/bin/hydrooj.js +++ b/packages/hydrooj/bin/hydrooj.js @@ -16,33 +16,18 @@ require('source-map-support').install({ return null; }, }); -const os = require('os'); const path = require('path'); const vm = require('vm'); const fs = require('fs-extra'); -const argv = require('cac')().parse(); -const child = require('child_process'); const esbuild = require('esbuild'); const { default: hook } = require('require-resolve-hook'); const { bypass } = hook(/^hydrooj/, (id) => bypass(() => require.resolve(id))); -const exec = (...args) => { - console.log('Executing: ', args[0], args[1].join(' ')); - const res = child.spawnSync(...args); - if (res.error) throw res.error; - if (res.status) throw new Error(`Error: Exited with code ${res.status}`); - return res; -}; - if (!process.env.NODE_APP_INSTANCE) process.env.NODE_APP_INSTANCE = '0'; const major = +process.version.split('.')[0].split('v')[1]; const minor = +process.version.split('.')[1]; -let transformTimeUsage = 0; -let transformCount = 0; -let displayTimeout; function transform(filename) { - const start = Date.now(); const code = fs.readFileSync(filename, 'utf-8'); const result = esbuild.transformSync(code, { sourcefile: filename, @@ -53,10 +38,6 @@ function transform(filename) { jsx: 'transform', }); if (result.warnings.length) console.warn(result.warnings); - transformTimeUsage += Date.now() - start; - transformCount++; - if (displayTimeout) clearTimeout(displayTimeout); - displayTimeout = setTimeout(() => console.log(`Transformed ${transformCount} files. (${transformTimeUsage}ms)`), 1000); map[filename] = result.map; return result.code; } @@ -103,115 +84,4 @@ require.extensions['.jsc'] = function loader(module, filename) { return compiledWrapper.apply(module.exports, args); }; -function buildUrl(opts) { - let mongourl = `${opts.protocol || 'mongodb'}://`; - if (opts.username) mongourl += `${opts.username}:${opts.password}@`; - mongourl += `${opts.host}:${opts.port}/${opts.name}`; - if (opts.url) mongourl = opts.url; - return mongourl; -} - -const hydroPath = path.resolve(os.homedir(), '.hydro'); -fs.ensureDirSync(hydroPath); -const addonPath = path.resolve(hydroPath, 'addon.json'); -if (!fs.existsSync(addonPath)) fs.writeFileSync(addonPath, '[]'); -let addons = JSON.parse(fs.readFileSync(addonPath).toString()); - -if (argv.args[0] === 'db') { - const dbConfig = fs.readFileSync(path.resolve(hydroPath, 'config.json'), 'utf-8'); - const url = buildUrl(JSON.parse(dbConfig)); - return child.spawn('mongo', [url], { stdio: 'inherit' }); -} - -if (argv.args[0] === 'backup') { - const dbConfig = fs.readFileSync(path.resolve(hydroPath, 'config.json'), 'utf-8'); - const url = buildUrl(JSON.parse(dbConfig)); - const dir = `${os.tmpdir()}/${Math.random().toString(36).substring(2)}`; - exec('mongodump', [url, `--out=${dir}/dump`], { stdio: 'inherit' }); - const env = `${os.homedir()}/.hydro/env`; - if (fs.existsSync(env)) fs.copySync(env, `${dir}/env`); - const target = `${process.cwd()}/backup-${new Date().toISOString().replace(':', '-').split(':')[0]}.zip`; - exec('zip', ['-r', target, 'dump'], { cwd: dir, stdio: 'inherit' }); - if (!argv.options.dbOnly) { - exec('zip', ['-r', target, 'file'], { cwd: '/data', stdio: 'inherit' }); - } - exec('rm', ['-rf', dir]); - console.log(`Database backup saved at ${target}`); - return; -} - -if (argv.args[0] === 'restore') { - const dbConfig = fs.readFileSync(path.resolve(hydroPath, 'config.json'), 'utf-8'); - const url = buildUrl(JSON.parse(dbConfig)); - const dir = `${os.tmpdir()}/${Math.random().toString(36).substring(2)}`; - if (!fs.existsSync(argv.args[1])) { - console.error('Cannot find file'); - return; - } - exec('unzip', [argv.args[1], '-d', dir], { stdio: 'inherit' }); - exec('mongorestore', [`--uri=${url}`, `--dir=${dir}/dump/hydro`, '--drop'], { stdio: 'inherit' }); - if (fs.existsSync(`${dir}/file`)) { - exec('rm', ['-rf', '/data/file/*'], { stdio: 'inherit' }); - exec('bash', ['-c', `mv ${dir}/file/* /data/file`], { stdio: 'inherit' }); - } - if (fs.existsSync(`${dir}/env`)) { - fs.copySync(`${dir}/env`, `${os.homedir()}/.hydro/env`, { overwrite: true }); - } - fs.removeSync(dir); - console.log('Successfully restored.'); - return; -} - -if (!addons.includes('@hydrooj/ui-default')) { - try { - const ui = argv.options.ui || '@hydrooj/ui-default'; - require.resolve(ui); - addons.push(ui); - } catch (e) { - console.error('Please also install @hydrooj/ui-default'); - } -} - -if (argv.args[0] && argv.args[0] !== 'cli') { - const operation = argv.args[0]; - const arg1 = argv.args[1]; - const arg2 = argv.args[2]; - if (operation === 'addon') { - if (arg1 === 'create') { - fs.mkdirSync('/root/addon'); - child.execSync('yarn init -y', { cwd: '/root/addon' }); - fs.mkdirSync('/root/addon/templates'); - fs.mkdirSync('/root/addon/locales'); - fs.mkdirSync('/root/addon/public'); - addons.push('/root/addon'); - } else if (arg1 === 'add') { - for (let i = 0; i < addons.length; i++) { - if (addons[i] === arg2) { - addons.splice(i, 1); - break; - } - } - addons.push(arg2); - } else if (arg1 === 'remove') { - for (let i = 0; i < addons.length; i++) { - if (addons[i] === arg2) { - addons.splice(i, 1); - break; - } - } - } - addons = Array.from(new Set(addons)); - console.log('Current Addons: ', addons); - fs.writeFileSync(addonPath, JSON.stringify(addons, null, 2)); - return; - } - console.error('Unknown command: ', argv.args[0]); -} else { - const hydro = require('../src/loader'); - addons = Array.from(new Set(addons)); - for (const addon of addons) hydro.addon(addon); - (argv.args[0] === 'cli' ? hydro.loadCli : hydro.load)().catch((e) => { - console.error(e); - process.exit(1); - }); -} +require('./commands'); diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index 70887a042..b6e0f1964 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -1,6 +1,6 @@ { "name": "hydrooj", - "version": "3.13.9", + "version": "3.13.10", "bin": "bin/hydrooj.js", "main": "src/loader", "module": "src/loader",