Skip to content

Commit e89426a

Browse files
committed
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWeb-Front into fix/project
2 parents 5b94d4b + 44bb8b0 commit e89426a

3 files changed

Lines changed: 163 additions & 59 deletions

File tree

app/components/Viewer/ObjectTree/Base/Controls.vue

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -99,22 +99,13 @@ watch(
9999
</v-list>
100100
</v-menu>
101101
<ActionButton
102-
v-if="!isCollapsed"
103-
tooltip="Collapse All"
104-
icon="mdi-collapse-all-outline"
102+
data-testid="CollapseOrExpandAll"
103+
:tooltip="isCollapsed ? 'Expand All' : 'Collapse All'"
104+
:icon="isCollapsed ? 'mdi-expand-all-outline' : 'mdi-collapse-all-outline'"
105105
variant="text"
106106
color="black"
107107
tooltipLocation="bottom"
108-
@click="emit('collapse-all')"
109-
/>
110-
<ActionButton
111-
v-else
112-
tooltip="Expand All"
113-
icon="mdi-expand-all-outline"
114-
variant="text"
115-
color="black"
116-
tooltipLocation="bottom"
117-
@click="emit('expand-all')"
108+
@click="isCollapsed ? emit('expand-all') : emit('collapse-all')"
118109
/>
119110
</div>
120111
</div>

app/utils/local/microservices.js

Lines changed: 39 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,18 @@ import path from "node:path";
55

66
// Third party imports
77
import back_schemas from "@geode/opengeodeweb-back/opengeodeweb_back_schemas.json" with { type: "json" };
8-
import { getPort } from "get-port-please";
9-
import pTimeout from "p-timeout";
108

119
// Local imports
12-
import { commandExistsSync, waitForReady } from "./scripts.js";
10+
import { commandExistsSync, getAvailablePort, waitForReady } from "./scripts.js";
1311
import { microservicesMetadatasPath, projectMicroservices } from "./cleanup.js";
1412
import { executablePath } from "./path.js";
1513

16-
const DEFAULT_TIMEOUT_SECONDS = 120;
1714
const MILLISECONDS_PER_SECOND = 1000;
15+
const DEFAULT_TIMEOUT_SECONDS = 30;
1816

19-
function getAvailablePort() {
20-
return getPort({
21-
host: "localhost",
22-
random: true,
23-
});
17+
function resolveCommand(execPath, execName) {
18+
const command = commandExistsSync(execName) ? execName : executablePath(execPath, execName);
19+
return command;
2420
}
2521

2622
async function runScript(
@@ -30,33 +26,31 @@ async function runScript(
3026
expectedResponse,
3127
timeoutSeconds = DEFAULT_TIMEOUT_SECONDS,
3228
) {
33-
let command = "";
34-
if (commandExistsSync(execName)) {
35-
command = execName;
36-
} else {
37-
command = path.join(executablePath(execPath, execName));
38-
}
29+
const command = resolveCommand(execPath, execName);
3930
console.log("runScript", command, args);
4031

41-
const child = child_process.spawn(process.platform === "win32" ? command : `"${command}"`, args, {
42-
encoding: "utf8",
43-
shell: true,
32+
const child = child_process.spawn(command, args, {
33+
stdio: ["ignore", "pipe", "pipe"],
4434
});
45-
child.stdout.on("data", (data) => console.log(`[${execName}] ${data.toString()}`));
46-
child.stderr.on("data", (data) => console.log(`[${execName}] ${data.toString()}`));
4735

48-
child.on("close", (code) => console.log(`[${execName}] exited with code ${code}`));
49-
child.on("kill", () => {
50-
console.log(`[${execName}] process killed`);
51-
});
5236
child.name = command.replace(/^.*[\\/]/u, "");
5337

38+
child.on("spawn", () => {
39+
console.log(`[${child.name}] spawned, pid=${child.pid}`);
40+
});
41+
42+
const controller = new AbortController();
43+
const timer = setTimeout(() => controller.abort(), timeoutSeconds * MILLISECONDS_PER_SECOND);
44+
if (typeof timer.unref === "function") {
45+
timer.unref();
46+
}
47+
5448
try {
55-
return await pTimeout(waitForReady(child, expectedResponse), {
56-
milliseconds: timeoutSeconds * MILLISECONDS_PER_SECOND,
57-
message: `Timed out after ${timeoutSeconds} seconds`,
58-
});
49+
const result = await waitForReady(child, expectedResponse, controller.signal);
50+
clearTimeout(timer);
51+
return result;
5952
} catch (error) {
53+
clearTimeout(timer);
6054
child.kill();
6155
throw error;
6256
}
@@ -73,11 +67,16 @@ async function runBack(execName, execPath, args = {}) {
7367
}
7468
const port = await getAvailablePort();
7569
const backArgs = [
76-
`--port ${port}`,
77-
`--data_folder_path ${projectFolderPath}`,
78-
`--upload_folder_path ${uploadFolderPath}`,
79-
`--allowed_origin http://localhost:*`,
80-
`--timeout ${0}`,
70+
"--port",
71+
String(port),
72+
"--data_folder_path",
73+
projectFolderPath,
74+
"--upload_folder_path",
75+
uploadFolderPath,
76+
"--allowed_origin",
77+
"http://localhost:*",
78+
"--timeout",
79+
"0",
8180
];
8281
if (process.env.NODE_ENV === "development" || !process.env.NODE_ENV) {
8382
backArgs.push("--debug");
@@ -94,9 +93,12 @@ async function runViewer(execName, execPath, args = {}) {
9493
}
9594
const port = await getAvailablePort();
9695
const viewerArgs = [
97-
`--port ${port}`,
98-
`--data_folder_path ${projectFolderPath}`,
99-
`--timeout ${0}`,
96+
"--port",
97+
String(port),
98+
"--data_folder_path",
99+
projectFolderPath,
100+
"--timeout",
101+
"0",
100102
];
101103
console.log("runViewer", execPath, execName, viewerArgs);
102104
await runScript(execPath, execName, viewerArgs, "Starting factory");
@@ -121,4 +123,4 @@ function addMicroserviceMetadatas(projectFolderPath, serviceObj) {
121123
);
122124
}
123125

124-
export { addMicroserviceMetadatas, getAvailablePort, runBack, runViewer };
126+
export { addMicroserviceMetadatas, runBack, runViewer };

app/utils/local/scripts.js

Lines changed: 120 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,129 @@ import child_process from "node:child_process";
33
import fs from "node:fs";
44
import { on } from "node:events";
55
import path from "node:path";
6+
import readline from "node:readline";
67

8+
// Third party imports
9+
import { getPort } from "get-port-please";
10+
11+
// Local imports
712
import { appMode } from "./app_mode.js";
813

14+
const BYTES_PER_KIBIBYTE = 1024;
15+
const MAX_ERROR_BUFFER_KIBIBYTES = 64;
16+
const MAX_ERROR_BUFFER_BYTES = MAX_ERROR_BUFFER_KIBIBYTES * BYTES_PER_KIBIBYTE;
17+
18+
function getAvailablePort() {
19+
return getPort({
20+
host: "localhost",
21+
random: true,
22+
});
23+
}
24+
925
function commandExistsSync(execName) {
1026
const envPath = process.env.PATH || "";
11-
return envPath.split(path.delimiter).some((dir) => {
12-
const filePath = path.join(dir, execName);
27+
return envPath.split(path.delimiter).some((directory) => {
28+
const filePath = path.join(directory, execName);
1329
return fs.existsSync(filePath) && fs.statSync(filePath).isFile();
1430
});
1531
}
1632

17-
async function waitForReady(child, expectedResponse) {
18-
for await (const [data] of on(child.stdout, "data")) {
19-
if (data.toString().includes(expectedResponse)) {
20-
return child;
33+
const encoder = new TextEncoder();
34+
35+
function byteLength(str) {
36+
return encoder.encode(str).byteLength;
37+
}
38+
39+
// oxlint-disable-next-line max-lines-per-function
40+
function waitForReady(child, expectedResponse, signal) {
41+
// oxlint-disable-next-line promise/avoid-new
42+
return new Promise((resolve, reject) => {
43+
const readlineStdout = readline.createInterface({ input: child.stdout });
44+
const readlineStderr = readline.createInterface({ input: child.stderr });
45+
46+
let recentOutput = "";
47+
48+
function recordOutput(lineOutput) {
49+
const safeLine =
50+
byteLength(lineOutput) > MAX_ERROR_BUFFER_BYTES / 2
51+
? `${lineOutput.slice(0, MAX_ERROR_BUFFER_BYTES / 2)}…[truncated]`
52+
: lineOutput;
53+
54+
recentOutput = `${recentOutput} ${safeLine}\n`;
55+
56+
while (byteLength(recentOutput) > MAX_ERROR_BUFFER_BYTES) {
57+
const newline = recentOutput.indexOf("\n");
58+
if (newline === -1) {
59+
recentOutput = "";
60+
break;
61+
}
62+
recentOutput = recentOutput.slice(newline + 1);
63+
}
2164
}
22-
}
23-
throw new Error("Process closed before signal");
65+
66+
function cleanup() {
67+
readlineStdout.removeListener("line", onLine);
68+
readlineStderr.removeListener("line", onErrLine);
69+
child.removeListener("error", onError);
70+
child.removeListener("close", onClose);
71+
if (signal) {
72+
signal.removeEventListener("abort", onAbort);
73+
}
74+
}
75+
76+
function onLine(lineOutput) {
77+
console.log(`[${child.name}] ${lineOutput}`);
78+
recordOutput(lineOutput);
79+
if (lineOutput.includes(expectedResponse)) {
80+
cleanup();
81+
readlineStdout.on("line", (line) => {
82+
console.log(`[${child.name}] ${line}`);
83+
});
84+
readlineStderr.on("line", (line) => {
85+
console.log(`[${child.name}] ${line}`);
86+
});
87+
child.once("close", (code) => {
88+
console.log(`[${child.name}] exited with code ${code}`);
89+
});
90+
resolve(child);
91+
}
92+
}
93+
94+
function onErrLine(line) {
95+
console.log(`[${child.name}] ${line}`);
96+
recordOutput(line);
97+
}
98+
99+
function onError(err) {
100+
cleanup();
101+
reject(err);
102+
}
103+
104+
function onClose(code) {
105+
console.log(`[${child.name}] exited with code ${code}`);
106+
cleanup();
107+
reject(
108+
new Error(
109+
`[${child.name}] exited with code ${code} before becoming ready.${
110+
recentOutput ? `\nRecent output:\n${recentOutput}` : ""
111+
}`,
112+
),
113+
);
114+
}
115+
116+
function onAbort() {
117+
cleanup();
118+
reject(new Error(`[${child.name}] timed out waiting for "${expectedResponse}"`));
119+
}
120+
121+
readlineStdout.on("line", onLine);
122+
readlineStderr.on("line", onErrLine);
123+
child.once("error", onError);
124+
child.once("close", onClose);
125+
if (signal) {
126+
signal.addEventListener("abort", onAbort, { once: true });
127+
}
128+
});
24129
}
25130

26131
async function waitNuxt(nuxtProcess) {
@@ -49,11 +154,17 @@ async function waitNuxt(nuxtProcess) {
49154
async function runBrowser(scriptName) {
50155
process.env.MODE = appMode.BROWSER;
51156

157+
const port = await getAvailablePort();
158+
52159
const nuxtProcess = child_process.spawn("npm", ["run", scriptName], {
53160
shell: true,
54161
FORCE_COLOR: true,
162+
env: {
163+
...process.env,
164+
PORT: port,
165+
},
55166
});
56167
return await waitNuxt(nuxtProcess);
57168
}
58169

59-
export { runBrowser, waitForReady, commandExistsSync };
170+
export { commandExistsSync, getAvailablePort, runBrowser, waitForReady };

0 commit comments

Comments
 (0)