-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathutils.ts
More file actions
153 lines (140 loc) · 4.83 KB
/
utils.ts
File metadata and controls
153 lines (140 loc) · 4.83 KB
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import * as fs from "fs";
import * as path from "path";
import * as net from "net";
import * as child_process from "child_process";
import * as vscode from "vscode";
import { JAVA_BINARY } from "./constants";
import { Range } from "../types/context";
/**
* Finds the Java executable in the system, either in JAVA_HOME or in PATH
* MIT Licensed code from: https://github.com/georgewfraser/vscode-javac
*/
export function findJavaExecutable(): string | null {
const binname = process.platform === "win32" ? `${JAVA_BINARY}.exe` : JAVA_BINARY;
// First search each JAVA_HOME bin folder
if (process.env["JAVA_HOME"]) {
for (const workspace of process.env["JAVA_HOME"].split(path.delimiter)) {
const binpath = path.join(workspace, "bin", binname);
if (fs.existsSync(binpath)) return binpath;
}
}
// Then search PATH parts
if (process.env["PATH"]) {
for (const part of process.env["PATH"].split(path.delimiter)) {
const binpath = path.join(part, binname);
if (fs.existsSync(binpath)) return binpath;
}
}
// Else return null
return null;
}
/**
* Gets an available port in the OS
* @returns A promise to the available port number
*/
export async function getAvailablePort(): Promise<number> {
return new Promise((resolve, reject) => {
const server = net.createServer();
server.listen(0, "localhost", () => {
const port = (server.address() as net.AddressInfo).port;
server.close();
resolve(port);
});
server.on("error", reject);
});
}
/**
* Connects to the process on the given port, retrying until timeout
* @param port The port to connect to
* @param timeout The timeout duration in milliseconds
* @param attemptInterval The interval between connection attempts in milliseconds
* @param connectionTimeout The timeout for each individual connection attempt in milliseconds
* @returns A promise to the connected socket
*/
export async function connectToPort(
port: number,
timeout = 10000,
attemptInterval = 500,
connectionTimeout = 500
): Promise<net.Socket> {
const deadline = Date.now() + timeout;
while (Date.now() < deadline) {
try {
return await new Promise((resolve, reject) => {
const s = net.connect({ port });
// connection timeout
const t = setTimeout(() => {
s.destroy(new Error("connection timeout"));
reject(new Error("connection timeout"));
}, connectionTimeout);
// success
s.once("connect", () => {
clearTimeout(t);
resolve(s);
});
// failure
s.once("error", (e) => {
clearTimeout(t);
reject(e);
});
});
} catch {
// wait and retry
await new Promise((r) => setTimeout(r, attemptInterval));
}
}
throw new Error(`Server not reachable on port ${port} within ${timeout}ms`);
}
/**
* Kills the given process if it is running
* @param proc The process to kill
* @returns A promise that resolves when the process has been killed
*/
export async function killProcess(proc?: child_process.ChildProcess) {
return new Promise<void>((resolve, reject) => {
if (!proc || proc.killed) {
// already killed
resolve();
return;
}
if (process.platform === "win32") {
// Windows
child_process.exec(`taskkill /pid ${proc.pid} /T /F`, (err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
} else {
// Unix
try {
process.kill(proc.pid, "SIGKILL");
resolve();
} catch (err) {
reject(err);
}
}
});
}
export function getSimpleName(qualifiedName: string): string {
const parts = qualifiedName.split(".");
return parts[parts.length - 1];
}
export function getOriginalVariableName(name: string): string {
if (name.startsWith("this#")) return name.replace(/^this#/, '');
if (name.startsWith("#")) return name.split("_")[0].replace(/^#/, '');
return name;
}
export function normalizeFilePath(fsPath: string): string {
// uppercase windows drive letter (c:\ -> C:\)
return path.normalize(fsPath).replace(/^([a-z]):\\/, (_, drive) => drive.toUpperCase() + ':\\');
}
export function toRange(selection: vscode.Selection | vscode.Range): Range {
return {
lineStart: selection.start.line,
colStart: selection.start.character,
lineEnd: selection.end.line,
colEnd: selection.end.character
};
}