@runium/cli 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{lib/commands → commands}/index.js +0 -0
- package/{lib/commands → commands}/project/project-start.js +1 -1
- package/{lib/constants → constants}/index.js +0 -0
- package/{lib/macros → macros}/index.js +0 -0
- package/package.json +7 -30
- package/{lib/services → services}/index.js +0 -0
- package/services/plugin-context.js +1 -0
- package/services/shutdown.js +1 -0
- package/{lib/utils → utils}/index.js +0 -0
- package/.eslintrc.json +0 -31
- package/.prettierrc.json +0 -10
- package/README.md +0 -3
- package/build.js +0 -104
- package/lib/package.json +0 -21
- package/lib/services/plugin-context.js +0 -1
- package/lib/services/shutdown.js +0 -1
- package/src/app.ts +0 -175
- package/src/commands/index.ts +0 -2
- package/src/commands/plugin/plugin-add.ts +0 -48
- package/src/commands/plugin/plugin-command.ts +0 -36
- package/src/commands/plugin/plugin-disable.ts +0 -46
- package/src/commands/plugin/plugin-enable.ts +0 -50
- package/src/commands/plugin/plugin-list.ts +0 -61
- package/src/commands/plugin/plugin-remove.ts +0 -42
- package/src/commands/plugin/plugin.ts +0 -41
- package/src/commands/project/project-add.ts +0 -46
- package/src/commands/project/project-command.ts +0 -36
- package/src/commands/project/project-list.ts +0 -32
- package/src/commands/project/project-remove.ts +0 -41
- package/src/commands/project/project-start.ts +0 -152
- package/src/commands/project/project-state-command.ts +0 -68
- package/src/commands/project/project-status.ts +0 -103
- package/src/commands/project/project-stop.ts +0 -55
- package/src/commands/project/project-validate.ts +0 -43
- package/src/commands/project/project.ts +0 -45
- package/src/commands/runium-command.ts +0 -50
- package/src/constants/error-code.ts +0 -15
- package/src/constants/index.ts +0 -1
- package/src/index.ts +0 -21
- package/src/macros/conditional.ts +0 -31
- package/src/macros/empty.ts +0 -6
- package/src/macros/env.ts +0 -8
- package/src/macros/index.ts +0 -12
- package/src/macros/path.ts +0 -9
- package/src/services/config.ts +0 -76
- package/src/services/index.ts +0 -7
- package/src/services/output.ts +0 -201
- package/src/services/plugin-context.ts +0 -81
- package/src/services/plugin.ts +0 -144
- package/src/services/profile.ts +0 -211
- package/src/services/project.ts +0 -114
- package/src/services/shutdown.ts +0 -130
- package/src/utils/convert-path-to-valid-file-name.ts +0 -39
- package/src/utils/debounce.ts +0 -23
- package/src/utils/format-timestamp.ts +0 -17
- package/src/utils/index.ts +0 -3
- package/tsconfig.json +0 -40
- /package/{lib/app.js → app.js} +0 -0
- /package/{lib/commands → commands}/plugin/plugin-add.js +0 -0
- /package/{lib/commands → commands}/plugin/plugin-command.js +0 -0
- /package/{lib/commands → commands}/plugin/plugin-disable.js +0 -0
- /package/{lib/commands → commands}/plugin/plugin-enable.js +0 -0
- /package/{lib/commands → commands}/plugin/plugin-list.js +0 -0
- /package/{lib/commands → commands}/plugin/plugin-remove.js +0 -0
- /package/{lib/commands → commands}/plugin/plugin.js +0 -0
- /package/{lib/commands → commands}/project/project-add.js +0 -0
- /package/{lib/commands → commands}/project/project-command.js +0 -0
- /package/{lib/commands → commands}/project/project-list.js +0 -0
- /package/{lib/commands → commands}/project/project-remove.js +0 -0
- /package/{lib/commands → commands}/project/project-state-command.js +0 -0
- /package/{lib/commands → commands}/project/project-status.js +0 -0
- /package/{lib/commands → commands}/project/project-stop.js +0 -0
- /package/{lib/commands → commands}/project/project-validate.js +0 -0
- /package/{lib/commands → commands}/project/project.js +0 -0
- /package/{lib/commands → commands}/runium-command.js +0 -0
- /package/{lib/constants → constants}/error-code.js +0 -0
- /package/{lib/index.js → index.js} +0 -0
- /package/{lib/macros → macros}/conditional.js +0 -0
- /package/{lib/macros → macros}/empty.js +0 -0
- /package/{lib/macros → macros}/env.js +0 -0
- /package/{lib/macros → macros}/path.js +0 -0
- /package/{lib/services → services}/config.js +0 -0
- /package/{lib/services → services}/output.js +0 -0
- /package/{lib/services → services}/plugin.js +0 -0
- /package/{lib/services → services}/profile.js +0 -0
- /package/{lib/services → services}/project.js +0 -0
- /package/{lib/utils → utils}/convert-path-to-valid-file-name.js +0 -0
- /package/{lib/utils → utils}/debounce.js +0 -0
- /package/{lib/utils → utils}/format-timestamp.js +0 -0
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { Option } from 'commander';
|
|
2
|
-
import { PluginCommand } from './plugin-command.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Plugin list command
|
|
6
|
-
*/
|
|
7
|
-
export class PluginListCommand extends PluginCommand {
|
|
8
|
-
/**
|
|
9
|
-
* Config command
|
|
10
|
-
*/
|
|
11
|
-
protected config(): void {
|
|
12
|
-
this.command
|
|
13
|
-
.name('list')
|
|
14
|
-
.addOption(
|
|
15
|
-
new Option('-d, --disabled', 'show only disabled plugins').conflicts(
|
|
16
|
-
'enabled'
|
|
17
|
-
)
|
|
18
|
-
)
|
|
19
|
-
.addOption(
|
|
20
|
-
new Option('-e, --enabled', 'show only enabled plugins').conflicts(
|
|
21
|
-
'disabled'
|
|
22
|
-
)
|
|
23
|
-
)
|
|
24
|
-
.option('-s, --sort', 'sort by name')
|
|
25
|
-
.description('list plugins');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Handle command
|
|
30
|
-
*/
|
|
31
|
-
protected async handle({
|
|
32
|
-
disabled,
|
|
33
|
-
enabled,
|
|
34
|
-
sort,
|
|
35
|
-
}: {
|
|
36
|
-
disabled: boolean;
|
|
37
|
-
enabled: boolean;
|
|
38
|
-
sort: boolean;
|
|
39
|
-
}): Promise<void> {
|
|
40
|
-
let plugins = this.profileService.getPlugins();
|
|
41
|
-
if (disabled) {
|
|
42
|
-
plugins = plugins.filter(p => p.disabled === true);
|
|
43
|
-
}
|
|
44
|
-
if (enabled) {
|
|
45
|
-
plugins = plugins.filter(p => p.disabled === false);
|
|
46
|
-
}
|
|
47
|
-
if (sort) {
|
|
48
|
-
plugins.sort((a, b) => a.name.localeCompare(b.name));
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (plugins.length !== 0) {
|
|
52
|
-
this.outputService.table(plugins, [
|
|
53
|
-
'name',
|
|
54
|
-
'path',
|
|
55
|
-
...(disabled || enabled ? [] : ['disabled']),
|
|
56
|
-
]);
|
|
57
|
-
} else {
|
|
58
|
-
this.outputService.warn('No plugins found');
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { PluginCommand } from './plugin-command.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Plugin remove command
|
|
5
|
-
*/
|
|
6
|
-
export class PluginRemoveCommand extends PluginCommand {
|
|
7
|
-
/**
|
|
8
|
-
* Config command
|
|
9
|
-
*/
|
|
10
|
-
protected config(): void {
|
|
11
|
-
this.command
|
|
12
|
-
.name('remove')
|
|
13
|
-
.description('remove plugin')
|
|
14
|
-
.option('-a, --all', 'remove all plugins')
|
|
15
|
-
.argument('[plugin...]', 'plugin names');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Handle command
|
|
20
|
-
* @param names
|
|
21
|
-
* @param all
|
|
22
|
-
*/
|
|
23
|
-
protected async handle(
|
|
24
|
-
names: string[],
|
|
25
|
-
{ all }: { all: boolean }
|
|
26
|
-
): Promise<void> {
|
|
27
|
-
if (names.length === 0 && !all) {
|
|
28
|
-
this.outputService.warn('No plugins specified to remove');
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
if (all) {
|
|
32
|
-
names = this.profileService.getPlugins().map(p => p.name);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
for (const name of names) {
|
|
36
|
-
this.ensureProfilePlugin(name);
|
|
37
|
-
await this.profileService.removePlugin(name);
|
|
38
|
-
await this.pluginService.unloadPlugin(name);
|
|
39
|
-
this.outputService.success(`Plugin "%s" successfully removed`, name);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { RuniumCommand } from '@commands/runium-command.js';
|
|
2
|
-
import { PluginAddCommand } from './plugin-add.js';
|
|
3
|
-
import { PluginDisableCommand } from './plugin-disable.js';
|
|
4
|
-
import { PluginEnableCommand } from './plugin-enable.js';
|
|
5
|
-
import { PluginListCommand } from './plugin-list.js';
|
|
6
|
-
import { PluginRemoveCommand } from './plugin-remove.js';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Plugin group command
|
|
10
|
-
*/
|
|
11
|
-
export class PluginCommand extends RuniumCommand {
|
|
12
|
-
/**
|
|
13
|
-
* Config command
|
|
14
|
-
*/
|
|
15
|
-
protected config(): void {
|
|
16
|
-
this.command.name('plugin').description('manage plugins');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Handle command
|
|
21
|
-
*/
|
|
22
|
-
protected async handle(): Promise<void> {
|
|
23
|
-
this.command.help();
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Add subcommands
|
|
28
|
-
*/
|
|
29
|
-
protected addSubcommands(): void {
|
|
30
|
-
const constructors = [
|
|
31
|
-
PluginListCommand,
|
|
32
|
-
PluginAddCommand,
|
|
33
|
-
PluginRemoveCommand,
|
|
34
|
-
PluginDisableCommand,
|
|
35
|
-
PluginEnableCommand,
|
|
36
|
-
];
|
|
37
|
-
for (const CommandConstructor of constructors) {
|
|
38
|
-
this.subcommands.push(new CommandConstructor(this.command));
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { RuniumError } from '@runium/core';
|
|
2
|
-
import { ErrorCode } from '@constants';
|
|
3
|
-
import { ProjectCommand } from './project-command.js';
|
|
4
|
-
/**
|
|
5
|
-
* Project add command
|
|
6
|
-
*/
|
|
7
|
-
export class ProjectAddCommand extends ProjectCommand {
|
|
8
|
-
/**
|
|
9
|
-
* Config command
|
|
10
|
-
*/
|
|
11
|
-
protected config(): void {
|
|
12
|
-
this.command
|
|
13
|
-
.name('add')
|
|
14
|
-
.description('add project')
|
|
15
|
-
.argument('<path>', 'project file path')
|
|
16
|
-
.argument('[name]', 'project name (default: project config id)');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Handle command
|
|
21
|
-
* @param path
|
|
22
|
-
* @param name
|
|
23
|
-
*/
|
|
24
|
-
protected async handle(path: string, name?: string): Promise<void> {
|
|
25
|
-
const projectPath = this.projectService.resolvePath(path);
|
|
26
|
-
const project = await this.projectService.initProject(projectPath);
|
|
27
|
-
if (project) {
|
|
28
|
-
await this.profileService.addProject({
|
|
29
|
-
// TODO validate name
|
|
30
|
-
// optionally save project file to profile
|
|
31
|
-
name: name ?? project.getConfig().id,
|
|
32
|
-
path: projectPath,
|
|
33
|
-
});
|
|
34
|
-
this.outputService.success(
|
|
35
|
-
`Project "%s" successfully added`,
|
|
36
|
-
name ?? project.getConfig().id
|
|
37
|
-
);
|
|
38
|
-
} else {
|
|
39
|
-
throw new RuniumError(
|
|
40
|
-
`Failed to add project "${projectPath}"`,
|
|
41
|
-
ErrorCode.PROJECT_NOT_FOUND,
|
|
42
|
-
{ path: projectPath }
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { Container } from 'typedi';
|
|
3
|
-
import { RuniumError } from '@runium/core';
|
|
4
|
-
import { RuniumCommand } from '@commands/runium-command.js';
|
|
5
|
-
import { ErrorCode } from '@constants';
|
|
6
|
-
import { ProfileService, ProjectService, ProfileProject } from '@services';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Base project command
|
|
10
|
-
*/
|
|
11
|
-
export abstract class ProjectCommand extends RuniumCommand {
|
|
12
|
-
protected projectService: ProjectService;
|
|
13
|
-
protected profileService: ProfileService;
|
|
14
|
-
|
|
15
|
-
constructor(parent: Command) {
|
|
16
|
-
super(parent);
|
|
17
|
-
this.projectService = Container.get(ProjectService);
|
|
18
|
-
this.profileService = Container.get(ProfileService);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Ensure project exists
|
|
23
|
-
* @param name
|
|
24
|
-
*/
|
|
25
|
-
protected ensureProfileProject(name: string): ProfileProject {
|
|
26
|
-
const project = this.profileService.getProjectByName(name);
|
|
27
|
-
if (!project) {
|
|
28
|
-
throw new RuniumError(
|
|
29
|
-
`Project "${name}" not found`,
|
|
30
|
-
ErrorCode.PROJECT_NOT_FOUND,
|
|
31
|
-
{ name }
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
return project;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { ProjectCommand } from './project-command.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Project list command
|
|
5
|
-
*/
|
|
6
|
-
export class ProjectListCommand extends ProjectCommand {
|
|
7
|
-
/**
|
|
8
|
-
* Config command
|
|
9
|
-
*/
|
|
10
|
-
protected config(): void {
|
|
11
|
-
this.command
|
|
12
|
-
.name('list')
|
|
13
|
-
.description('list projects')
|
|
14
|
-
.option('-s, --sort', 'sort by name');
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Handle command
|
|
19
|
-
*/
|
|
20
|
-
protected async handle({ sort }: { sort: boolean }): Promise<void> {
|
|
21
|
-
const projects = this.profileService.getProjects();
|
|
22
|
-
if (sort) {
|
|
23
|
-
projects.sort((a, b) => a.name.localeCompare(b.name));
|
|
24
|
-
}
|
|
25
|
-
// handle empty list
|
|
26
|
-
if (projects.length !== 0) {
|
|
27
|
-
this.outputService.table(projects, ['name', 'path']);
|
|
28
|
-
} else {
|
|
29
|
-
this.outputService.warn('No projects found');
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { ProjectCommand } from './project-command.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Project remove command
|
|
5
|
-
*/
|
|
6
|
-
export class ProjectRemoveCommand extends ProjectCommand {
|
|
7
|
-
/**
|
|
8
|
-
* Config command
|
|
9
|
-
*/
|
|
10
|
-
protected config(): void {
|
|
11
|
-
this.command
|
|
12
|
-
.name('remove')
|
|
13
|
-
.description('remove project')
|
|
14
|
-
.option('-a, --all', 'remove all projects')
|
|
15
|
-
.argument('[name...]', 'project names');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Handle command
|
|
20
|
-
* @param names
|
|
21
|
-
* @param all
|
|
22
|
-
*/
|
|
23
|
-
protected async handle(
|
|
24
|
-
names: string[],
|
|
25
|
-
{ all }: { all: boolean }
|
|
26
|
-
): Promise<void> {
|
|
27
|
-
if (names.length === 0 && !all) {
|
|
28
|
-
this.outputService.warn('No projects specified to remove');
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
if (all) {
|
|
32
|
-
names = this.profileService.getProjects().map(p => p.name);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
for (const name of names) {
|
|
36
|
-
this.ensureProfileProject(name);
|
|
37
|
-
await this.profileService.removeProject(name);
|
|
38
|
-
this.outputService.success(`Project "%s" successfully removed`, name);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import { dirname } from 'node:path';
|
|
2
|
-
import { Command, Option } from 'commander';
|
|
3
|
-
import { Container } from 'typedi';
|
|
4
|
-
import {
|
|
5
|
-
Project,
|
|
6
|
-
ProjectEvent,
|
|
7
|
-
ProjectState,
|
|
8
|
-
RuniumError,
|
|
9
|
-
TaskState,
|
|
10
|
-
} from '@runium/core';
|
|
11
|
-
import { ErrorCode } from '@constants';
|
|
12
|
-
import { ShutdownService } from '@services';
|
|
13
|
-
import { debounce } from '@utils';
|
|
14
|
-
import { ProjectData, ProjectStateCommand } from './project-state-command.js';
|
|
15
|
-
|
|
16
|
-
const WRITE_PROJECT_DATA_DEBOUNCE_WAIT = 100;
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Project start command
|
|
20
|
-
*/
|
|
21
|
-
export class ProjectStartCommand extends ProjectStateCommand {
|
|
22
|
-
protected shutdownService: ShutdownService;
|
|
23
|
-
|
|
24
|
-
constructor(parent: Command) {
|
|
25
|
-
super(parent);
|
|
26
|
-
this.shutdownService = Container.get(ShutdownService);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Config command
|
|
31
|
-
*/
|
|
32
|
-
protected config(): void {
|
|
33
|
-
this.command
|
|
34
|
-
.name('start')
|
|
35
|
-
.description('start project')
|
|
36
|
-
.option('-f, --file', 'use file path instead of project name')
|
|
37
|
-
.option('-o, --output', 'output project state changes')
|
|
38
|
-
.addOption(
|
|
39
|
-
new Option('-w, --working-dir <choice>', 'set working directory')
|
|
40
|
-
.choices(['cwd', 'project'])
|
|
41
|
-
.default('cwd')
|
|
42
|
-
)
|
|
43
|
-
.argument('<name>', 'project name');
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Handle command
|
|
48
|
-
* @param name
|
|
49
|
-
* @param file
|
|
50
|
-
* @param workingDir
|
|
51
|
-
* @param output
|
|
52
|
-
*/
|
|
53
|
-
protected async handle(
|
|
54
|
-
name: string,
|
|
55
|
-
{
|
|
56
|
-
file,
|
|
57
|
-
workingDir,
|
|
58
|
-
output,
|
|
59
|
-
}: { file: boolean; workingDir?: string; output?: boolean }
|
|
60
|
-
): Promise<void> {
|
|
61
|
-
const path = file
|
|
62
|
-
? this.projectService.resolvePath(name)
|
|
63
|
-
: this.ensureProfileProject(name).path;
|
|
64
|
-
|
|
65
|
-
const projectDataFileName = this.getProjectDataFileName(file ? path : name);
|
|
66
|
-
|
|
67
|
-
// check if project is started
|
|
68
|
-
const projectData = await this.readProjectData(projectDataFileName);
|
|
69
|
-
if (projectData && this.isProjectProcessStarted(projectData.pid)) {
|
|
70
|
-
throw new RuniumError(
|
|
71
|
-
`Project "${name}" is already started`,
|
|
72
|
-
ErrorCode.PROJECT_ALREADY_STARTED,
|
|
73
|
-
{ name }
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (workingDir === 'project') {
|
|
78
|
-
const projectDir = dirname(path);
|
|
79
|
-
if (projectDir !== process.cwd()) {
|
|
80
|
-
process.chdir(projectDir);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const project = await this.projectService.initProject(path);
|
|
85
|
-
this.shutdownService.addBlocker(() => project.stop());
|
|
86
|
-
|
|
87
|
-
this.addProjectListeners(project, {
|
|
88
|
-
dataFileName: projectDataFileName,
|
|
89
|
-
projectPath: path,
|
|
90
|
-
output,
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
await project.start();
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Add project listeners
|
|
98
|
-
* @param project
|
|
99
|
-
* @param options
|
|
100
|
-
*/
|
|
101
|
-
protected addProjectListeners(
|
|
102
|
-
project: Project,
|
|
103
|
-
options: { dataFileName: string; projectPath: string; output?: boolean }
|
|
104
|
-
): void {
|
|
105
|
-
const { dataFileName, projectPath, output } = options;
|
|
106
|
-
|
|
107
|
-
const projectData: ProjectData = {
|
|
108
|
-
id: project.getConfig().id,
|
|
109
|
-
pid: process.pid,
|
|
110
|
-
cwd: process.cwd(),
|
|
111
|
-
path: projectPath,
|
|
112
|
-
state: {
|
|
113
|
-
project: [],
|
|
114
|
-
tasks: {},
|
|
115
|
-
},
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
const writeProjectData = debounce(() => {
|
|
119
|
-
this.writeProjectData(projectData, dataFileName);
|
|
120
|
-
}, WRITE_PROJECT_DATA_DEBOUNCE_WAIT);
|
|
121
|
-
|
|
122
|
-
// write initial data
|
|
123
|
-
writeProjectData();
|
|
124
|
-
|
|
125
|
-
project.on(ProjectEvent.STATE_CHANGE, async (state: ProjectState) => {
|
|
126
|
-
projectData.state.project.push(state);
|
|
127
|
-
writeProjectData();
|
|
128
|
-
if (output) {
|
|
129
|
-
this.outputService.info('Project %s', state.status);
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
project.on(
|
|
134
|
-
ProjectEvent.TASK_STATE_CHANGE,
|
|
135
|
-
(taskId: string, state: TaskState) => {
|
|
136
|
-
if (!projectData.state.tasks[taskId]) {
|
|
137
|
-
projectData.state.tasks[taskId] = [];
|
|
138
|
-
}
|
|
139
|
-
projectData.state.tasks[taskId].push(state);
|
|
140
|
-
writeProjectData();
|
|
141
|
-
if (output) {
|
|
142
|
-
this.outputService.info(
|
|
143
|
-
'Task %s %s %s',
|
|
144
|
-
taskId,
|
|
145
|
-
state.status,
|
|
146
|
-
state.exitCode || state.error || ''
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { convertPathToValidFileName } from '@utils';
|
|
2
|
-
import { ProjectCommand } from './project-command.js';
|
|
3
|
-
import { ProjectState, TaskState } from '@runium/core';
|
|
4
|
-
|
|
5
|
-
export interface ProjectData {
|
|
6
|
-
id: string;
|
|
7
|
-
pid: number;
|
|
8
|
-
cwd: string;
|
|
9
|
-
path: string;
|
|
10
|
-
state: {
|
|
11
|
-
project: ProjectState[];
|
|
12
|
-
tasks: Record<string, TaskState[]>;
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Base project state command
|
|
18
|
-
*/
|
|
19
|
-
export abstract class ProjectStateCommand extends ProjectCommand {
|
|
20
|
-
/**
|
|
21
|
-
* Get project data file name
|
|
22
|
-
* @param name
|
|
23
|
-
*/
|
|
24
|
-
protected getProjectDataFileName(name: string): string {
|
|
25
|
-
let fileName = convertPathToValidFileName(name);
|
|
26
|
-
if (!fileName.endsWith('.json')) {
|
|
27
|
-
fileName = fileName + '.json';
|
|
28
|
-
}
|
|
29
|
-
return fileName;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Read project data
|
|
34
|
-
* @param fileName
|
|
35
|
-
*/
|
|
36
|
-
protected async readProjectData(
|
|
37
|
-
fileName: string
|
|
38
|
-
): Promise<ProjectData | null> {
|
|
39
|
-
return this.profileService
|
|
40
|
-
.readJsonFile('projects', fileName)
|
|
41
|
-
.catch(() => null) as Promise<ProjectData | null>;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Write project data
|
|
46
|
-
* @param data
|
|
47
|
-
* @param fileName
|
|
48
|
-
*/
|
|
49
|
-
protected async writeProjectData(
|
|
50
|
-
data: ProjectData,
|
|
51
|
-
fileName: string
|
|
52
|
-
): Promise<void> {
|
|
53
|
-
return this.profileService.writeJsonFile(data, 'projects', fileName);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Checks if a project process is started
|
|
58
|
-
* @param pid
|
|
59
|
-
*/
|
|
60
|
-
protected isProjectProcessStarted(pid: number): boolean {
|
|
61
|
-
// and process started
|
|
62
|
-
try {
|
|
63
|
-
return process.kill(Number(pid), 0);
|
|
64
|
-
} catch (ex) {
|
|
65
|
-
return (ex as { code?: string }).code === 'EPERM';
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { formatTimestamp } from '@utils';
|
|
2
|
-
import { ProjectStateCommand } from './project-state-command.js';
|
|
3
|
-
|
|
4
|
-
interface StateRecord {
|
|
5
|
-
name: string;
|
|
6
|
-
status: string;
|
|
7
|
-
time: string;
|
|
8
|
-
timestamp: number;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Project status command
|
|
13
|
-
*/
|
|
14
|
-
export class ProjectStatusCommand extends ProjectStateCommand {
|
|
15
|
-
/**
|
|
16
|
-
* Config command
|
|
17
|
-
*/
|
|
18
|
-
protected config(): void {
|
|
19
|
-
this.command
|
|
20
|
-
.name('status')
|
|
21
|
-
.description('get project status')
|
|
22
|
-
.option('-f, --file', 'use file path instead of project name')
|
|
23
|
-
.option('-t, --tasks', 'show task status')
|
|
24
|
-
.option('-a, --all', 'show status change history')
|
|
25
|
-
.argument('<name>', 'project name');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Handle command
|
|
30
|
-
* @param name
|
|
31
|
-
* @param file
|
|
32
|
-
* @param tasks
|
|
33
|
-
* @param all
|
|
34
|
-
*/
|
|
35
|
-
protected async handle(
|
|
36
|
-
name: string,
|
|
37
|
-
{ file, tasks, all }: { file: boolean; tasks: boolean; all: boolean }
|
|
38
|
-
): Promise<void> {
|
|
39
|
-
const path = file
|
|
40
|
-
? this.projectService.resolvePath(name)
|
|
41
|
-
: this.ensureProfileProject(name).path;
|
|
42
|
-
|
|
43
|
-
const projectDataFileName = this.getProjectDataFileName(file ? path : name);
|
|
44
|
-
|
|
45
|
-
const projectData = await this.readProjectData(projectDataFileName);
|
|
46
|
-
if (projectData) {
|
|
47
|
-
let { project: projectState = [] } = projectData.state;
|
|
48
|
-
if (!all) {
|
|
49
|
-
projectState =
|
|
50
|
-
projectState.length > 0
|
|
51
|
-
? [projectState[projectState.length - 1]]
|
|
52
|
-
: [];
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (tasks) {
|
|
56
|
-
const projectMappedState = projectState.map(state => {
|
|
57
|
-
return {
|
|
58
|
-
name: 'Project',
|
|
59
|
-
status: state.status,
|
|
60
|
-
time: formatTimestamp(state.timestamp),
|
|
61
|
-
timestamp: state.timestamp,
|
|
62
|
-
};
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
const { tasks: tasksState = [] } = projectData.state;
|
|
66
|
-
|
|
67
|
-
const tasksMappedState: StateRecord[] = [];
|
|
68
|
-
Object.entries(tasksState).forEach(([key, value]) => {
|
|
69
|
-
if (!all) {
|
|
70
|
-
value = value.length > 0 ? [value[value.length - 1]] : [];
|
|
71
|
-
}
|
|
72
|
-
value.forEach(task => {
|
|
73
|
-
tasksMappedState.push({
|
|
74
|
-
name: key,
|
|
75
|
-
status: task.status,
|
|
76
|
-
time: formatTimestamp(task.timestamp),
|
|
77
|
-
timestamp: task.timestamp,
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
const mappedState: StateRecord[] = [
|
|
83
|
-
...projectMappedState,
|
|
84
|
-
...tasksMappedState,
|
|
85
|
-
];
|
|
86
|
-
mappedState.sort((a, b) => a.timestamp - b.timestamp);
|
|
87
|
-
|
|
88
|
-
this.outputService.table(mappedState, ['time', 'name', 'status']);
|
|
89
|
-
} else {
|
|
90
|
-
const mappedState = projectState.map(state => {
|
|
91
|
-
return {
|
|
92
|
-
status: state.status,
|
|
93
|
-
time: formatTimestamp(state.timestamp),
|
|
94
|
-
};
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
this.outputService.table(mappedState, ['time', 'status']);
|
|
98
|
-
}
|
|
99
|
-
} else {
|
|
100
|
-
this.outputService.info(`No project status for "${name}"`);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { RuniumError } from '@runium/core';
|
|
2
|
-
import { ErrorCode } from '@constants';
|
|
3
|
-
import { ProjectStateCommand } from './project-state-command.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Project stop command
|
|
7
|
-
*/
|
|
8
|
-
export class ProjectStopCommand extends ProjectStateCommand {
|
|
9
|
-
/**
|
|
10
|
-
* Config command
|
|
11
|
-
*/
|
|
12
|
-
protected config(): void {
|
|
13
|
-
this.command
|
|
14
|
-
.name('stop')
|
|
15
|
-
.description('stop project')
|
|
16
|
-
.option('-f, --file', 'use file path instead of project name')
|
|
17
|
-
.argument('<name>', 'project name');
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Handle command
|
|
22
|
-
* @param name
|
|
23
|
-
* @param file
|
|
24
|
-
*/
|
|
25
|
-
protected async handle(
|
|
26
|
-
name: string,
|
|
27
|
-
{ file }: { file: boolean }
|
|
28
|
-
): Promise<void> {
|
|
29
|
-
const path = file
|
|
30
|
-
? this.projectService.resolvePath(name)
|
|
31
|
-
: this.ensureProfileProject(name).path;
|
|
32
|
-
|
|
33
|
-
const projectDataFileName = this.getProjectDataFileName(file ? path : name);
|
|
34
|
-
|
|
35
|
-
// check if project is started
|
|
36
|
-
const projectData = await this.readProjectData(projectDataFileName);
|
|
37
|
-
if (!projectData || !this.isProjectProcessStarted(projectData.pid)) {
|
|
38
|
-
throw new RuniumError(
|
|
39
|
-
`Project "${name}" is not started`,
|
|
40
|
-
ErrorCode.PROJECT_NOT_STARTED,
|
|
41
|
-
{ name }
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
try {
|
|
46
|
-
process.kill(projectData.pid, 'SIGTERM');
|
|
47
|
-
} catch (ex) {
|
|
48
|
-
throw new RuniumError(
|
|
49
|
-
`Failed to stop project "${name}"`,
|
|
50
|
-
ErrorCode.PROJECT_STOP_ERROR,
|
|
51
|
-
{ name, original: ex }
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|