forked from railsware/upterm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCommandExecutor.ts
108 lines (91 loc) · 3.5 KB
/
CommandExecutor.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import Job from "./Job";
import Command from "./Command";
import PTY from "./PTY";
import * as Path from "path";
import {executablesInPaths, resolveFile, isWindows, filterAsync, exists} from "./utils/Common";
import {loginShell} from "./utils/Shell";
abstract class CommandExecutionStrategy {
protected args: string[];
static async canExecute(job: Job): Promise<boolean> {
return false;
}
constructor(protected job: Job) {
this.args = job.prompt.arguments.filter(argument => argument.length > 0);
}
abstract startExecution(): Promise<{}>;
}
class BuiltInCommandExecutionStrategy extends CommandExecutionStrategy {
static async canExecute(job: Job) {
return Command.isBuiltIn(job.prompt.commandName);
}
startExecution() {
return new Promise((resolve, reject) => {
try {
Command.executor(this.job.prompt.commandName)(this.job, this.args);
resolve();
} catch (error) {
reject(error.message);
}
});
}
}
class ShellExecutionStrategy extends CommandExecutionStrategy {
static async canExecute(job: Job) {
return loginShell.preCommandModifiers.includes(job.prompt.commandName) ||
await this.isExecutableFromPath(job) ||
await this.isPathOfExecutable(job);
}
private static async isExecutableFromPath(job: Job): Promise<boolean> {
return (await executablesInPaths(job.environment.path) ).includes(job.prompt.commandName);
}
private static async isPathOfExecutable(job: Job): Promise<boolean> {
return await exists(resolveFile(job.session.directory, job.prompt.commandName));
}
startExecution() {
return new Promise((resolve, reject) => {
this.job.command = new PTY(
this.job.prompt.commandName, this.args, this.job.environment.toObject(), this.job.dimensions,
(data: string) => this.job.parser.parse(data),
(exitCode: number) => exitCode === 0 ? resolve() : reject()
);
});
}
}
class WindowsShellExecutionStrategy extends CommandExecutionStrategy {
static async canExecute(job: Job) {
return isWindows();
}
startExecution() {
return new Promise((resolve) => {
this.job.command = new PTY(
this.cmdPath, ["/s", "/c", this.job.prompt.expanded.join(" ")], this.job.environment.toObject(), this.job.dimensions,
(data: string) => this.job.parser.parse(data),
(exitCode: number) => resolve()
);
});
}
private get cmdPath(): string {
if (this.job.environment.has("comspec")) {
return this.job.environment.get("comspec");
} else if (this.job.environment.has("SystemRoot")) {
return Path.join(this.job.environment.get("SystemRoot"), "System32", "cmd.exe");
} else {
return "cmd.exe";
}
}
}
export default class CommandExecutor {
private static executors = [
BuiltInCommandExecutionStrategy,
WindowsShellExecutionStrategy,
ShellExecutionStrategy,
];
static async execute(job: Job): Promise<{}> {
const applicableExecutors = await filterAsync(this.executors, executor => executor.canExecute(job));
if (applicableExecutors.length) {
return new applicableExecutors[0](job).startExecution();
} else {
throw `Black Screen: command "${job.prompt.commandName}" not found.\n`;
}
}
}