chore(command): set command handle by ipc server or not (#2660)

* chore: tmp commit

* feat: app command

* chore: return error when not handle by ipc server

* chore: command handle by ipc server

* chore: api name

* Update pm.ts

---------

Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
ChengLei Shao 2023-09-19 14:39:54 +08:00 committed by GitHub
parent 4fffa07998
commit 630c6f2d79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 131 additions and 21 deletions

View File

@ -0,0 +1,43 @@
import { DataTypes, mockDatabase } from '@nocobase/database';
import Application, { ApplicationOptions } from '../application';
const mockServer = (options?: ApplicationOptions) => {
return new Application({
database: mockDatabase(),
acl: false,
...options,
});
};
describe('app command', () => {
let app: Application;
afterEach(async () => {
if (app) {
await app.destroy();
}
});
beforeEach(async () => {
app = mockServer();
await app.load();
await app.install();
});
it('should test command should handle by IPC Server or not', () => {
app.command('testaa').ipc();
app.command('testbb');
expect(app.cli.parseHandleByIPCServer(['node', 'cli', 'nocobase', 'testaa'])).toBeTruthy();
expect(app.cli.parseHandleByIPCServer(['node', 'cli', 'nocobase', 'testbb'])).toBeFalsy();
});
it('should test sub command should handle by IPC Server or not', () => {
const subParent = app.command('subparent');
subParent.command('testaa').ipc();
subParent.command('testbb');
expect(app.cli.parseHandleByIPCServer(['node', 'cli', 'nocobase', 'subparent', 'testaa'])).toBeTruthy();
expect(app.cli.parseHandleByIPCServer(['node', 'cli', 'nocobase', 'subparent', 'testbb'])).toBeFalsy();
});
});

View File

@ -0,0 +1,41 @@
import { Command } from 'commander';
export class AppCommand extends Command {
private _handleByIPCServer = false;
ipc() {
this._handleByIPCServer = true;
return this;
}
isHandleByIPCServer() {
return this._handleByIPCServer;
}
createCommand(name?: string): AppCommand {
return new AppCommand(name);
}
parseHandleByIPCServer(argv, parseOptions?): Boolean {
//@ts-ignore
const userArgs = this._prepareUserArgs(argv, parseOptions);
if (userArgs[0] === 'nocobase') {
userArgs.shift();
}
let lastCommand = this;
for (const arg of userArgs) {
// @ts-ignore
const subCommand = lastCommand._findCommand(arg);
if (subCommand) {
lastCommand = subCommand;
} else {
break;
}
}
return lastCommand && lastCommand.isHandleByIPCServer();
}
}

View File

@ -22,6 +22,7 @@ import { ApplicationVersion } from './helpers/application-version';
import { Locale } from './locale'; import { Locale } from './locale';
import { Plugin } from './plugin'; import { Plugin } from './plugin';
import { InstallOptions, PluginManager } from './plugin-manager'; import { InstallOptions, PluginManager } from './plugin-manager';
import { AppCommand } from './app-command';
const packageJson = require('../package.json'); const packageJson = require('../package.json');
@ -163,7 +164,7 @@ export class Application<StateT = DefaultState, ContextT = DefaultContext> exten
return this._cache; return this._cache;
} }
protected _cli: Command; protected _cli: AppCommand;
get cli() { get cli() {
return this._cli; return this._cli;
@ -286,7 +287,7 @@ export class Application<StateT = DefaultState, ContextT = DefaultContext> exten
return this.resourcer.registerActions(handlers); return this.resourcer.registerActions(handlers);
} }
command(name: string, desc?: string, opts?: CommandOptions): Command { command(name: string, desc?: string, opts?: CommandOptions): AppCommand {
return this.cli.command(name, desc, opts).allowUnknownOption(); return this.cli.command(name, desc, opts).allowUnknownOption();
} }
@ -363,7 +364,7 @@ export class Application<StateT = DefaultState, ContextT = DefaultContext> exten
} }
createCli() { createCli() {
const command = new Command('nocobase') const command = new AppCommand('nocobase')
.usage('[command] [options]') .usage('[command] [options]')
.hook('preAction', async (_, actionCommand) => { .hook('preAction', async (_, actionCommand) => {
this._actionCommand = actionCommand; this._actionCommand = actionCommand;

View File

@ -3,6 +3,7 @@ import Application from '../application';
export default (app: Application) => { export default (app: Application) => {
app app
.command('install') .command('install')
.ipc()
.option('-f, --force') .option('-f, --force')
.option('-c, --clean') .option('-c, --clean')
.action(async (...cliArgs) => { .action(async (...cliArgs) => {

View File

@ -6,18 +6,19 @@ export default (app: Application) => {
const pm = app.command('pm'); const pm = app.command('pm');
pm.command('create') pm.command('create')
.ipc()
.arguments('plugin') .arguments('plugin')
.action(async (plugin) => { .action(async (plugin) => {
await app.pm.create(plugin); await app.pm.create(plugin);
}); });
pm.command('add') pm.command('add')
.ipc()
.argument('<pkg>') .argument('<pkg>')
.option('--registry [registry]') .option('--registry [registry]')
.option('--auth-token [authToken]') .option('--auth-token [authToken]')
.option('--version [version]') .option('--version [version]')
.action(async (name, options, cli) => { .action(async (name, options, cli) => {
console.log('pm.add', name, options);
try { try {
await app.pm.addViaCLI(name, _.cloneDeep(options)); await app.pm.addViaCLI(name, _.cloneDeep(options));
} catch (error) { } catch (error) {
@ -26,6 +27,7 @@ export default (app: Application) => {
}); });
pm.command('update') pm.command('update')
.ipc()
.argument('<packageName>') .argument('<packageName>')
.option('--path [path]') .option('--path [path]')
.option('--url [url]') .option('--url [url]')
@ -44,6 +46,7 @@ export default (app: Application) => {
}); });
pm.command('enable') pm.command('enable')
.ipc()
.arguments('<plugins...>') .arguments('<plugins...>')
.action(async (plugins) => { .action(async (plugins) => {
try { try {
@ -54,6 +57,7 @@ export default (app: Application) => {
}); });
pm.command('disable') pm.command('disable')
.ipc()
.arguments('<plugins...>') .arguments('<plugins...>')
.action(async (plugins) => { .action(async (plugins) => {
try { try {
@ -64,6 +68,7 @@ export default (app: Application) => {
}); });
pm.command('remove') pm.command('remove')
.ipc()
.arguments('<plugins...>') .arguments('<plugins...>')
.action(async (plugins) => { .action(async (plugins) => {
await app.pm.remove(plugins); await app.pm.remove(plugins);

View File

@ -1,7 +1,10 @@
import Application from '../application'; import Application from '../application';
export default (app: Application) => { export default (app: Application) => {
app.command('restart').action(async (...cliArgs) => { app
.command('restart')
.ipc()
.action(async (...cliArgs) => {
await app.restart({ await app.restart({
cliArgs, cliArgs,
}); });

View File

@ -1,7 +1,10 @@
import Application from '../application'; import Application from '../application';
export default (app: Application) => { export default (app: Application) => {
app.command('stop').action(async (...cliArgs) => { app
.command('stop')
.ipc()
.action(async (...cliArgs) => {
await app.stop({ await app.stop({
cliArgs, cliArgs,
}); });

View File

@ -5,7 +5,10 @@ import Application from '../application';
* TODO * TODO
*/ */
export default (app: Application) => { export default (app: Application) => {
app.command('upgrade').action(async (...cliArgs) => { app
.command('upgrade')
.ipc()
.action(async (...cliArgs) => {
const [opts] = cliArgs; const [opts] = cliArgs;
console.log('upgrading...'); console.log('upgrading...');
await app.upgrade(); await app.upgrade();

View File

@ -228,12 +228,14 @@ export class Gateway extends EventEmitter {
ipcClient = await this.tryConnectToIPCServer(); ipcClient = await this.tryConnectToIPCServer();
if (ipcClient) { if (ipcClient) {
await ipcClient.write({ type: 'passCliArgv', payload: { argv: process.argv } }); const response: any = await ipcClient.write({ type: 'passCliArgv', payload: { argv: process.argv } });
// should wait for server response
ipcClient.close(); ipcClient.close();
if (response.type !== 'error' || response.payload.message !== 'Not handle by ipc server') {
return; return;
} }
} }
}
if (isStart || !ipcClient) { if (isStart || !ipcClient) {
await createStoragePluginsSymlink(); await createStoragePluginsSymlink();

View File

@ -66,6 +66,14 @@ export class IPCSocketServer {
const argv = payload.argv; const argv = payload.argv;
const mainApp = await AppSupervisor.getInstance().getApp('main'); const mainApp = await AppSupervisor.getInstance().getApp('main');
const cli = mainApp.cli;
if (
!cli.parseHandleByIPCServer(argv, {
from: 'node',
})
) {
throw new Error('Not handle by ipc server');
}
return mainApp.runAsCLI(argv, { return mainApp.runAsCLI(argv, {
from: 'node', from: 'node',