gdharness 1.3.55 → 1.3.57
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/build/cli.js
CHANGED
|
@@ -1717,7 +1717,6 @@ var init_whole_file = __esm(() => {
|
|
|
1717
1717
|
// src/engine-slots.ts
|
|
1718
1718
|
import {
|
|
1719
1719
|
closeSync as closeSync2,
|
|
1720
|
-
existsSync as existsSync2,
|
|
1721
1720
|
mkdirSync as mkdirSync2,
|
|
1722
1721
|
openSync as openSync2,
|
|
1723
1722
|
readdirSync,
|
|
@@ -1761,8 +1760,14 @@ function machineSlots(asked = {
|
|
|
1761
1760
|
function nonEmpty(value) {
|
|
1762
1761
|
return value === undefined || value === "" ? undefined : value;
|
|
1763
1762
|
}
|
|
1763
|
+
function keptSlotsOf(count) {
|
|
1764
|
+
return Math.max(2, Math.floor(count / 4));
|
|
1765
|
+
}
|
|
1766
|
+
function gamesKeptOf(kept) {
|
|
1767
|
+
return Math.max(0, Math.min(Math.floor(kept / 2), kept - GATE_KEPT - 1));
|
|
1768
|
+
}
|
|
1764
1769
|
function slotsDrawnOn(count, taker, queue) {
|
|
1765
|
-
const gated = Math.max(1, count -
|
|
1770
|
+
const gated = Math.max(1, count - keptSlotsOf(count));
|
|
1766
1771
|
if (taker === "gate") {
|
|
1767
1772
|
return { numbers: Array.from({ length: gated }, (_, slot) => slot), limit: "gate" };
|
|
1768
1773
|
}
|
|
@@ -1774,20 +1779,21 @@ function slotsDrawnOn(count, taker, queue) {
|
|
|
1774
1779
|
if (taker === "tier") {
|
|
1775
1780
|
return { numbers: [...kept].reverse(), limit: "tier" };
|
|
1776
1781
|
}
|
|
1777
|
-
|
|
1778
|
-
return { numbers: [], limit: "held" };
|
|
1779
|
-
}
|
|
1780
|
-
return { numbers: kept.slice(0, 1), limit: "kept" };
|
|
1782
|
+
return { numbers: kept.slice(0, Math.max(1, kept.length - GATE_KEPT)), limit: "kept" };
|
|
1781
1783
|
}
|
|
1782
1784
|
function inAGate(env = process4.env) {
|
|
1783
1785
|
return nonEmpty(env[SHARE_VARIABLE]) !== undefined && nonEmpty(env[SHARE_COUNT_VARIABLE]) !== undefined;
|
|
1784
1786
|
}
|
|
1785
|
-
function inheritsSlot(tree, pid, holder, executable) {
|
|
1787
|
+
function inheritsSlot(tree, pid, holder, executable, engineStarted) {
|
|
1786
1788
|
const program = (name) => name.toLowerCase().replace(/\.(?:exe|cmd|bat|com)$/, "");
|
|
1787
1789
|
const own = program(executable);
|
|
1788
|
-
for (const above of ancestorsIn(tree, pid, holder)) {
|
|
1790
|
+
for (const above of ancestorsIn(tree, pid, holder.pid)) {
|
|
1789
1791
|
if (program(readCommandLine(tree.get(above)?.command ?? "").executable) !== own) {
|
|
1790
|
-
|
|
1792
|
+
if (above === holder.pid) {
|
|
1793
|
+
return true;
|
|
1794
|
+
}
|
|
1795
|
+
const started = tree.get(above)?.startedAt ?? engineStarted;
|
|
1796
|
+
return above === holder.engine?.pid && started !== undefined && Math.abs(started - holder.engine.started) <= START_TOLERANCE_MS;
|
|
1791
1797
|
}
|
|
1792
1798
|
}
|
|
1793
1799
|
return false;
|
|
@@ -1852,15 +1858,29 @@ function holderOf(content) {
|
|
|
1852
1858
|
if (typeof parsed !== "object" || parsed === null) {
|
|
1853
1859
|
return null;
|
|
1854
1860
|
}
|
|
1855
|
-
const {
|
|
1856
|
-
|
|
1861
|
+
const { by, game, engine } = parsed;
|
|
1862
|
+
const named = namedProcess(parsed);
|
|
1863
|
+
if (named === null) {
|
|
1857
1864
|
return null;
|
|
1858
1865
|
}
|
|
1859
|
-
|
|
1866
|
+
const runs = namedProcess(engine);
|
|
1867
|
+
return {
|
|
1868
|
+
...named,
|
|
1869
|
+
...typeof by === "string" && by !== "" ? { by } : {},
|
|
1870
|
+
...game === true ? { game } : {},
|
|
1871
|
+
...runs === null ? {} : { engine: runs }
|
|
1872
|
+
};
|
|
1860
1873
|
} catch {
|
|
1861
1874
|
return null;
|
|
1862
1875
|
}
|
|
1863
1876
|
}
|
|
1877
|
+
function namedProcess(value) {
|
|
1878
|
+
if (typeof value !== "object" || value === null) {
|
|
1879
|
+
return null;
|
|
1880
|
+
}
|
|
1881
|
+
const { pid, started } = value;
|
|
1882
|
+
return typeof pid === "number" && Number.isInteger(pid) && pid > 0 && typeof started === "number" ? { pid, started } : null;
|
|
1883
|
+
}
|
|
1864
1884
|
function lockIsFree(content, writtenAt, now, isAlive, startOf) {
|
|
1865
1885
|
const holder = holderOf(content);
|
|
1866
1886
|
if (holder === null) {
|
|
@@ -1897,7 +1917,7 @@ class EngineSlots {
|
|
|
1897
1917
|
this.taker = taker;
|
|
1898
1918
|
this.drawn = slotsDrawnOn(count, taker(), "none");
|
|
1899
1919
|
}
|
|
1900
|
-
async take(signal, waiting, blocked) {
|
|
1920
|
+
async take(signal, waiting, blocked, game = false) {
|
|
1901
1921
|
mkdirSync2(this.directory, { recursive: true });
|
|
1902
1922
|
const began = Date.now();
|
|
1903
1923
|
let said = Number.NEGATIVE_INFINITY;
|
|
@@ -1906,7 +1926,7 @@ class EngineSlots {
|
|
|
1906
1926
|
try {
|
|
1907
1927
|
for (;; ) {
|
|
1908
1928
|
signal?.throwIfAborted();
|
|
1909
|
-
const lock = await this.takeFree();
|
|
1929
|
+
const lock = await this.takeFree(game);
|
|
1910
1930
|
if (lock !== null) {
|
|
1911
1931
|
return lock;
|
|
1912
1932
|
}
|
|
@@ -1938,7 +1958,7 @@ class EngineSlots {
|
|
|
1938
1958
|
}
|
|
1939
1959
|
}
|
|
1940
1960
|
}
|
|
1941
|
-
async takeFree() {
|
|
1961
|
+
async takeFree(game = false) {
|
|
1942
1962
|
mkdirSync2(this.directory, { recursive: true });
|
|
1943
1963
|
await this.sweep();
|
|
1944
1964
|
const inherited = this.inherited === null ? await this.inheritedLock() : null;
|
|
@@ -1948,9 +1968,18 @@ class EngineSlots {
|
|
|
1948
1968
|
}
|
|
1949
1969
|
const taker = this.taker();
|
|
1950
1970
|
this.drawn = slotsDrawnOn(this.count, taker, taker === "gate" || taker === "timing" ? "none" : await this.gateQueue());
|
|
1971
|
+
if (game && this.drawn.limit === "kept") {
|
|
1972
|
+
const share = slotsDrawnOn(this.count, "tier", "queued").numbers;
|
|
1973
|
+
const games = await this.heldByGames(share);
|
|
1974
|
+
if (games.length >= gamesKeptOf(share.length)) {
|
|
1975
|
+
this.drawn = { numbers: games, limit: "games" };
|
|
1976
|
+
return null;
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
const holder = game ? { ...this.holder, game: true } : this.holder;
|
|
1951
1980
|
for (const slot of this.drawn.numbers) {
|
|
1952
1981
|
const lock = join5(this.directory, `${String(slot)}.lock`);
|
|
1953
|
-
if (this.made(lock) || await this.takenOver(lock)) {
|
|
1982
|
+
if (this.made(lock, holder) || await this.takenOver(lock, holder)) {
|
|
1954
1983
|
this.held.add(lock);
|
|
1955
1984
|
return lock;
|
|
1956
1985
|
}
|
|
@@ -1965,7 +1994,17 @@ class EngineSlots {
|
|
|
1965
1994
|
return null;
|
|
1966
1995
|
}
|
|
1967
1996
|
const tree = await processTree();
|
|
1968
|
-
|
|
1997
|
+
const engine = holder.engine?.pid;
|
|
1998
|
+
const engineStarted = engine === undefined || tree?.get(engine)?.startedAt !== undefined ? undefined : (await startTimesOf([engine])).get(engine);
|
|
1999
|
+
return tree !== undefined && inheritsSlot(tree, process4.pid, holder, basename3(process4.execPath), engineStarted) ? lock : null;
|
|
2000
|
+
}
|
|
2001
|
+
markWaiting() {
|
|
2002
|
+
const mark = this.waitMarked();
|
|
2003
|
+
return () => {
|
|
2004
|
+
if (mark !== undefined && this.marks.delete(mark)) {
|
|
2005
|
+
removeWhole(mark);
|
|
2006
|
+
}
|
|
2007
|
+
};
|
|
1969
2008
|
}
|
|
1970
2009
|
waitMarked() {
|
|
1971
2010
|
const marks = join5(this.directory, WAITING_FOLDER);
|
|
@@ -1982,6 +2021,17 @@ class EngineSlots {
|
|
|
1982
2021
|
this.marks.add(mark);
|
|
1983
2022
|
return mark;
|
|
1984
2023
|
}
|
|
2024
|
+
async heldByGames(numbers) {
|
|
2025
|
+
const games = [];
|
|
2026
|
+
for (const slot of numbers) {
|
|
2027
|
+
const lock = join5(this.directory, `${String(slot)}.lock`);
|
|
2028
|
+
const content = readWhole(lock);
|
|
2029
|
+
if (content !== null && holderOf(content)?.game === true && !await this.free(lock)) {
|
|
2030
|
+
games.push(slot);
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
return games;
|
|
2034
|
+
}
|
|
1985
2035
|
async gateQueue() {
|
|
1986
2036
|
const marks = join5(this.directory, QUEUED_FOLDER);
|
|
1987
2037
|
let names;
|
|
@@ -2000,10 +2050,8 @@ class EngineSlots {
|
|
|
2000
2050
|
if (await this.free(mark)) {
|
|
2001
2051
|
removeWhole(mark);
|
|
2002
2052
|
removeWhole(`${mark}${SEATED_SUFFIX}`);
|
|
2003
|
-
} else
|
|
2004
|
-
live = "
|
|
2005
|
-
} else if (live === "none") {
|
|
2006
|
-
live = "seated";
|
|
2053
|
+
} else {
|
|
2054
|
+
live = "queued";
|
|
2007
2055
|
}
|
|
2008
2056
|
}
|
|
2009
2057
|
return live;
|
|
@@ -2047,7 +2095,7 @@ class EngineSlots {
|
|
|
2047
2095
|
}
|
|
2048
2096
|
return handed;
|
|
2049
2097
|
}
|
|
2050
|
-
made(path) {
|
|
2098
|
+
made(path, holder = this.holder) {
|
|
2051
2099
|
let made;
|
|
2052
2100
|
try {
|
|
2053
2101
|
made = openSync2(path, "wx");
|
|
@@ -2055,7 +2103,7 @@ class EngineSlots {
|
|
|
2055
2103
|
return false;
|
|
2056
2104
|
}
|
|
2057
2105
|
try {
|
|
2058
|
-
writeSync2(made, JSON.stringify(
|
|
2106
|
+
writeSync2(made, JSON.stringify(holder));
|
|
2059
2107
|
} finally {
|
|
2060
2108
|
closeSync2(made);
|
|
2061
2109
|
}
|
|
@@ -2075,10 +2123,10 @@ class EngineSlots {
|
|
|
2075
2123
|
}
|
|
2076
2124
|
}
|
|
2077
2125
|
}
|
|
2078
|
-
takenOver(lock) {
|
|
2079
|
-
return this.cleared(lock, true);
|
|
2126
|
+
takenOver(lock, holder) {
|
|
2127
|
+
return this.cleared(lock, true, holder);
|
|
2080
2128
|
}
|
|
2081
|
-
async cleared(lock, retake) {
|
|
2129
|
+
async cleared(lock, retake, holder = this.holder) {
|
|
2082
2130
|
if (!await this.free(lock)) {
|
|
2083
2131
|
return false;
|
|
2084
2132
|
}
|
|
@@ -2100,7 +2148,7 @@ class EngineSlots {
|
|
|
2100
2148
|
} catch {
|
|
2101
2149
|
return false;
|
|
2102
2150
|
}
|
|
2103
|
-
return retake ? this.made(lock) : true;
|
|
2151
|
+
return retake ? this.made(lock, holder) : true;
|
|
2104
2152
|
} finally {
|
|
2105
2153
|
rmSync4(steal, { force: true });
|
|
2106
2154
|
}
|
|
@@ -2136,7 +2184,47 @@ function handSlot(lock, from, to) {
|
|
|
2136
2184
|
} catch {
|
|
2137
2185
|
return false;
|
|
2138
2186
|
}
|
|
2139
|
-
|
|
2187
|
+
const holder = content === null ? null : holderOf(content);
|
|
2188
|
+
return holder?.pid === from && writeWhole(lock, JSON.stringify(holder.game === true ? { ...to, game: true } : to));
|
|
2189
|
+
}
|
|
2190
|
+
function nameSlotEngine(lock, holder, engine) {
|
|
2191
|
+
let content;
|
|
2192
|
+
try {
|
|
2193
|
+
content = readWhole(lock);
|
|
2194
|
+
} catch {
|
|
2195
|
+
return false;
|
|
2196
|
+
}
|
|
2197
|
+
const named = content === null ? null : holderOf(content);
|
|
2198
|
+
return named?.pid === holder && writeWhole(lock, JSON.stringify({ ...named, engine }));
|
|
2199
|
+
}
|
|
2200
|
+
async function nameSlotEngineOf(lock, holder, pid) {
|
|
2201
|
+
const started = (await startTimesOf([pid])).get(pid);
|
|
2202
|
+
if (started !== undefined) {
|
|
2203
|
+
nameSlotEngine(lock, holder, { pid, started });
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
async function slotEngineNamed(lock, run, pidFile) {
|
|
2207
|
+
if (pidFile === undefined) {
|
|
2208
|
+
if (run.pid !== null) {
|
|
2209
|
+
await nameSlotEngineOf(lock, process4.pid, run.pid);
|
|
2210
|
+
}
|
|
2211
|
+
return;
|
|
2212
|
+
}
|
|
2213
|
+
const state = { settled: false };
|
|
2214
|
+
run.settled.finally(() => {
|
|
2215
|
+
state.settled = true;
|
|
2216
|
+
});
|
|
2217
|
+
while (!state.settled) {
|
|
2218
|
+
let written = Number.NaN;
|
|
2219
|
+
try {
|
|
2220
|
+
written = Number(readFileSync6(pidFile, "utf8").trim());
|
|
2221
|
+
} catch {}
|
|
2222
|
+
if (Number.isInteger(written) && written > 0) {
|
|
2223
|
+
await nameSlotEngineOf(lock, process4.pid, written);
|
|
2224
|
+
return;
|
|
2225
|
+
}
|
|
2226
|
+
await delay2(ENGINE_PID_LOOK_MS);
|
|
2227
|
+
}
|
|
2140
2228
|
}
|
|
2141
2229
|
function giveBackSlot(lock, pid) {
|
|
2142
2230
|
try {
|
|
@@ -2163,15 +2251,12 @@ function nameSlotTaker(by) {
|
|
|
2163
2251
|
}
|
|
2164
2252
|
function slotWaitSaid(waitedMs, count, directory, holders = [], drawn = { numbers: [] }) {
|
|
2165
2253
|
const so = `Waiting${waitedMs >= 1000 ? ` ${String(Math.round(waitedMs / 1000))} s so far` : ""} for an engine`;
|
|
2166
|
-
if (drawn.limit === "held") {
|
|
2167
|
-
return `${so}: ${GATE_UNSEATED} (${directory}), and the engine starts once every queued gate has its seat.`;
|
|
2168
|
-
}
|
|
2169
2254
|
const taking = drawn.limit === undefined ? count : drawn.numbers.length;
|
|
2170
2255
|
const slots = `${slotsSaid(taking, count, directory, drawn.limit)} ${taking === 1 ? "is" : "are"} in use`;
|
|
2171
2256
|
const named = holdersNamed(taking, holders);
|
|
2172
2257
|
const waiting = `${so}: ${slots}`;
|
|
2173
2258
|
const back = `the engine starts when ${taking === 1 ? "it" : "one"} is given back`;
|
|
2174
|
-
const starts = drawn.limit === "kept" || drawn.limit === "tier" ? `${back} or no gate is queued` : back;
|
|
2259
|
+
const starts = drawn.limit === "kept" || drawn.limit === "tier" || drawn.limit === "games" ? `${back} or no gate is queued` : back;
|
|
2175
2260
|
if (named.length === 0) {
|
|
2176
2261
|
return `${waiting}, by a gate or another tool, and ${starts}.`;
|
|
2177
2262
|
}
|
|
@@ -2191,13 +2276,13 @@ function slotsSaid(taking, count, directory, limit) {
|
|
|
2191
2276
|
if (limit === "tier") {
|
|
2192
2277
|
return `${taking === 1 ? "the one engine slot" : `the ${String(taking)} engine slots`} of the ${String(count)} ${where} a gate's own steps take while a gate is queued`;
|
|
2193
2278
|
}
|
|
2279
|
+
if (limit === "games") {
|
|
2280
|
+
return `${taking === 1 ? "the one engine slot" : `the ${String(taking)} engine slots`} of the ${String(count)} ${where} that games editor_run started may hold while a gate is queued, the rest kept for short calls,`;
|
|
2281
|
+
}
|
|
2194
2282
|
return count === 1 ? `the one engine slot ${where}` : `all ${String(count)} engine slots ${where}`;
|
|
2195
2283
|
}
|
|
2196
2284
|
function slotWaitedSaid(waitedMs, count, directory, holders, drawn = { numbers: [] }) {
|
|
2197
2285
|
const waited = `This call waited ${String(Math.round(waitedMs / 1000))} s for an engine slot in all.`;
|
|
2198
|
-
if (drawn.limit === "held") {
|
|
2199
|
-
return `${waited} When it first waited, ${GATE_UNSEATED} (${directory}), and engines outside a gate wait until every queued gate has its seat.`;
|
|
2200
|
-
}
|
|
2201
2286
|
const taking = drawn.limit === undefined ? count : drawn.numbers.length;
|
|
2202
2287
|
const slots = `${slotsSaid(taking, count, directory, drawn.limit)} ${taking === 1 ? "was" : "were"} in use`;
|
|
2203
2288
|
const named = holdersNamed(taking, holders);
|
|
@@ -2220,7 +2305,7 @@ function holdersNamed(count, holders) {
|
|
|
2220
2305
|
function listed(named) {
|
|
2221
2306
|
return named.length === 1 ? named.join("") : `${named.slice(0, -1).join(", ")} and ${named.at(-1) ?? ""}`;
|
|
2222
2307
|
}
|
|
2223
|
-
async function slotForCall() {
|
|
2308
|
+
async function slotForCall(game = false) {
|
|
2224
2309
|
const slots = await processSlots();
|
|
2225
2310
|
const progress = callProgress();
|
|
2226
2311
|
const waits = callSlotWaits();
|
|
@@ -2232,7 +2317,7 @@ async function slotForCall() {
|
|
|
2232
2317
|
}, () => {
|
|
2233
2318
|
blockedBy = slots.holders();
|
|
2234
2319
|
blockedOn = slots.drawn;
|
|
2235
|
-
});
|
|
2320
|
+
}, game);
|
|
2236
2321
|
if (waits !== undefined && blockedBy !== undefined) {
|
|
2237
2322
|
waits.ms += Date.now() - began;
|
|
2238
2323
|
const heldBy = blockedBy;
|
|
@@ -2259,7 +2344,7 @@ async function inASlot(body) {
|
|
|
2259
2344
|
held.release();
|
|
2260
2345
|
}
|
|
2261
2346
|
}
|
|
2262
|
-
var HELD_VARIABLE = "GODOT_ENGINE_HELD", SLOTS_VARIABLE = "GODOT_ENGINE_SLOTS", SLOT_COUNT_VARIABLE = "GODOT_ENGINE_SLOT_COUNT", PROCESSORS_A_SLOT = 2, START_TOLERANCE_MS = 2000, UNWRITTEN_MS = 1e4, SLOT_LOOK_MS = 1000, SLOT_SETTLE_MS = 50, WAIT_SAID_MS = 20000, COMMAND_WAIT_SAID_MS = 2000, START_READ_MS = 1e4, WAITING_FOLDER = "waiting", QUEUED_FOLDER = "queued", SHARE_VARIABLE = "GODOT_ENGINE_SHARE", SHARE_COUNT_VARIABLE = "GODOT_ENGINE_SHARE_COUNT",
|
|
2347
|
+
var HELD_VARIABLE = "GODOT_ENGINE_HELD", SLOTS_VARIABLE = "GODOT_ENGINE_SLOTS", SLOT_COUNT_VARIABLE = "GODOT_ENGINE_SLOT_COUNT", PROCESSORS_A_SLOT = 2, START_TOLERANCE_MS = 2000, UNWRITTEN_MS = 1e4, SLOT_LOOK_MS = 1000, SLOT_SETTLE_MS = 50, WAIT_SAID_MS = 20000, COMMAND_WAIT_SAID_MS = 2000, START_READ_MS = 1e4, WAITING_FOLDER = "waiting", QUEUED_FOLDER = "queued", SHARE_VARIABLE = "GODOT_ENGINE_SHARE", SHARE_COUNT_VARIABLE = "GODOT_ENGINE_SHARE_COUNT", GATE_KEPT = 1, TIMED_VARIABLE = "GODOT_ENGINE_TIMED", TIER_VARIABLE = "GODOT_ENGINE_TIER", SEATED_SUFFIX = ".seated", waitsMarked = 0, ENGINE_PID_LOOK_MS = 100, ours, saidTo, takenBy;
|
|
2263
2348
|
var init_engine_slots = __esm(() => {
|
|
2264
2349
|
init_alive();
|
|
2265
2350
|
init_cache_home();
|
|
@@ -9534,7 +9619,7 @@ var init_config_formats = __esm(() => {
|
|
|
9534
9619
|
});
|
|
9535
9620
|
|
|
9536
9621
|
// src/runner.ts
|
|
9537
|
-
import { existsSync as
|
|
9622
|
+
import { existsSync as existsSync2, realpathSync as realpathSync2 } from "node:fs";
|
|
9538
9623
|
import { delimiter, dirname as dirname3, extname, join as join6, resolve as resolve3 } from "node:path";
|
|
9539
9624
|
import process5 from "node:process";
|
|
9540
9625
|
function currentRunner() {
|
|
@@ -9578,12 +9663,12 @@ function realPath(path) {
|
|
|
9578
9663
|
}
|
|
9579
9664
|
function alongside(execPath, name) {
|
|
9580
9665
|
const runner = join6(dirname3(execPath), process5.platform === "win32" ? `${name}.cmd` : name);
|
|
9581
|
-
return
|
|
9666
|
+
return existsSync2(runner) ? runner : undefined;
|
|
9582
9667
|
}
|
|
9583
9668
|
var init_runner = () => {};
|
|
9584
9669
|
|
|
9585
9670
|
// src/harnesses.ts
|
|
9586
|
-
import { existsSync as
|
|
9671
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readdirSync as readdirSync2, readFileSync as readFileSync8, rmSync as rmSync5, statSync as statSync4, writeFileSync as writeFileSync5 } from "node:fs";
|
|
9587
9672
|
import { homedir as homedir3 } from "node:os";
|
|
9588
9673
|
import { basename as basename4, dirname as dirname4, isAbsolute as isAbsolute2, join as join7, relative as relative2, resolve as resolve4 } from "node:path";
|
|
9589
9674
|
import process6 from "node:process";
|
|
@@ -9674,15 +9759,15 @@ function harnessById(id) {
|
|
|
9674
9759
|
}
|
|
9675
9760
|
function present(harness, projectPath) {
|
|
9676
9761
|
const path = configPath(harness, projectPath);
|
|
9677
|
-
if (
|
|
9762
|
+
if (existsSync3(path)) {
|
|
9678
9763
|
return true;
|
|
9679
9764
|
}
|
|
9680
9765
|
const root = harness.scope === "project" ? projectPath : homedir3();
|
|
9681
9766
|
const own = dirname4(path);
|
|
9682
|
-
if (own !== root &&
|
|
9767
|
+
if (own !== root && existsSync3(own)) {
|
|
9683
9768
|
return true;
|
|
9684
9769
|
}
|
|
9685
|
-
return harness.marker !== undefined &&
|
|
9770
|
+
return harness.marker !== undefined && existsSync3(join7(root, harness.marker));
|
|
9686
9771
|
}
|
|
9687
9772
|
function candidates(projectPath) {
|
|
9688
9773
|
const found = [];
|
|
@@ -9695,7 +9780,7 @@ function candidates(projectPath) {
|
|
|
9695
9780
|
}
|
|
9696
9781
|
if (present(harness, projectPath)) {
|
|
9697
9782
|
found.push({ harness, reason: "configured" });
|
|
9698
|
-
} else if (harness.home !== undefined &&
|
|
9783
|
+
} else if (harness.home !== undefined && existsSync3(join7(homedir3(), harness.home))) {
|
|
9699
9784
|
found.push({ harness, reason: "installed" });
|
|
9700
9785
|
}
|
|
9701
9786
|
}
|
|
@@ -9717,7 +9802,7 @@ function groupByFile(harnesses, projectPath) {
|
|
|
9717
9802
|
}
|
|
9718
9803
|
function registered(harness, projectPath) {
|
|
9719
9804
|
const path = configPath(harness, projectPath);
|
|
9720
|
-
if (harness.snippet !== undefined || !
|
|
9805
|
+
if (harness.snippet !== undefined || !existsSync3(path)) {
|
|
9721
9806
|
return false;
|
|
9722
9807
|
}
|
|
9723
9808
|
const text = readFileSync8(path, "utf8");
|
|
@@ -9746,7 +9831,7 @@ function recordedEnginePath(projectPath) {
|
|
|
9746
9831
|
}
|
|
9747
9832
|
const named = reach(entryEnvironment(harness, projectPath), "GODOT_PATH");
|
|
9748
9833
|
const path = typeof named !== "string" || named === "" ? null : isAbsolute2(named) ? named : resolve4(projectPath, named);
|
|
9749
|
-
if (path !== null &&
|
|
9834
|
+
if (path !== null && existsSync3(path)) {
|
|
9750
9835
|
return path;
|
|
9751
9836
|
}
|
|
9752
9837
|
}
|
|
@@ -9754,7 +9839,7 @@ function recordedEnginePath(projectPath) {
|
|
|
9754
9839
|
}
|
|
9755
9840
|
function mainCheckoutOf(projectPath) {
|
|
9756
9841
|
let top = resolve4(projectPath);
|
|
9757
|
-
while (!
|
|
9842
|
+
while (!existsSync3(join7(top, ".git"))) {
|
|
9758
9843
|
const up = dirname4(top);
|
|
9759
9844
|
if (up === top) {
|
|
9760
9845
|
return null;
|
|
@@ -9771,7 +9856,7 @@ function mainCheckoutOf(projectPath) {
|
|
|
9771
9856
|
}
|
|
9772
9857
|
const entry = resolve4(top, pointer);
|
|
9773
9858
|
const commonFile = join7(entry, "commondir");
|
|
9774
|
-
if (!
|
|
9859
|
+
if (!existsSync3(commonFile)) {
|
|
9775
9860
|
return null;
|
|
9776
9861
|
}
|
|
9777
9862
|
const common = resolve4(entry, readFileSync8(commonFile, "utf8").trim());
|
|
@@ -9779,11 +9864,11 @@ function mainCheckoutOf(projectPath) {
|
|
|
9779
9864
|
return null;
|
|
9780
9865
|
}
|
|
9781
9866
|
const main = join7(dirname4(common), relative2(top, resolve4(projectPath)));
|
|
9782
|
-
return isSameDirectory(main, projectPath) || !
|
|
9867
|
+
return isSameDirectory(main, projectPath) || !existsSync3(join7(main, "project.godot")) ? null : main;
|
|
9783
9868
|
}
|
|
9784
9869
|
function worktreeCheckoutsOf(projectPath) {
|
|
9785
9870
|
let top = resolve4(projectPath);
|
|
9786
|
-
while (!
|
|
9871
|
+
while (!existsSync3(join7(top, ".git"))) {
|
|
9787
9872
|
const up = dirname4(top);
|
|
9788
9873
|
if (up === top) {
|
|
9789
9874
|
return [];
|
|
@@ -9791,18 +9876,18 @@ function worktreeCheckoutsOf(projectPath) {
|
|
|
9791
9876
|
top = up;
|
|
9792
9877
|
}
|
|
9793
9878
|
const listed = join7(top, ".git", "worktrees");
|
|
9794
|
-
if (!statSync4(join7(top, ".git")).isDirectory() || !
|
|
9879
|
+
if (!statSync4(join7(top, ".git")).isDirectory() || !existsSync3(listed)) {
|
|
9795
9880
|
return [];
|
|
9796
9881
|
}
|
|
9797
9882
|
const below = relative2(top, resolve4(projectPath));
|
|
9798
9883
|
return readdirSync2(listed).flatMap((name) => {
|
|
9799
9884
|
const pointer = join7(listed, name, "gitdir");
|
|
9800
|
-
if (!
|
|
9885
|
+
if (!existsSync3(pointer)) {
|
|
9801
9886
|
return [];
|
|
9802
9887
|
}
|
|
9803
9888
|
const checkout = dirname4(resolve4(listed, name, readFileSync8(pointer, "utf8").trim()));
|
|
9804
9889
|
const project = join7(checkout, below);
|
|
9805
|
-
return
|
|
9890
|
+
return existsSync3(join7(project, "project.godot")) ? [project] : [];
|
|
9806
9891
|
});
|
|
9807
9892
|
}
|
|
9808
9893
|
function entryEnvironment(harness, projectPath) {
|
|
@@ -9810,7 +9895,7 @@ function entryEnvironment(harness, projectPath) {
|
|
|
9810
9895
|
return;
|
|
9811
9896
|
}
|
|
9812
9897
|
const path = configPath(harness, projectPath);
|
|
9813
|
-
if (!
|
|
9898
|
+
if (!existsSync3(path)) {
|
|
9814
9899
|
return;
|
|
9815
9900
|
}
|
|
9816
9901
|
let parsed;
|
|
@@ -9831,7 +9916,7 @@ function reach(held, key) {
|
|
|
9831
9916
|
}
|
|
9832
9917
|
function disconnect(harness, projectPath) {
|
|
9833
9918
|
const path = configPath(harness, projectPath);
|
|
9834
|
-
if (!
|
|
9919
|
+
if (!existsSync3(path)) {
|
|
9835
9920
|
return { harness, path, action: "absent" };
|
|
9836
9921
|
}
|
|
9837
9922
|
if (harness.snippet !== undefined) {
|
|
@@ -9918,7 +10003,7 @@ function connect(harness, projectPath, launch) {
|
|
|
9918
10003
|
if (harness.snippet !== undefined) {
|
|
9919
10004
|
return { harness, path, action: "snippet", snippet: harness.snippet(launch) };
|
|
9920
10005
|
}
|
|
9921
|
-
const held =
|
|
10006
|
+
const held = existsSync3(path) ? readFileSync8(path, "utf8") : "";
|
|
9922
10007
|
if (harness.toml !== undefined) {
|
|
9923
10008
|
const already = held.includes(harness.toml.identity ?? harness.toml.header);
|
|
9924
10009
|
return put(harness, path, writeToml(held, harness.toml, launch), already);
|
|
@@ -11084,7 +11169,7 @@ var init_gdscript_source = __esm(() => {
|
|
|
11084
11169
|
});
|
|
11085
11170
|
|
|
11086
11171
|
// src/class-cache.ts
|
|
11087
|
-
import { existsSync as
|
|
11172
|
+
import { existsSync as existsSync4, readdirSync as readdirSync3, readFileSync as readFileSync9, statSync as statSync5 } from "node:fs";
|
|
11088
11173
|
import { join as join8, posix } from "node:path";
|
|
11089
11174
|
function isToolScript(source) {
|
|
11090
11175
|
return TOOL.test(codeOf(source));
|
|
@@ -11148,7 +11233,7 @@ function declaredClassOf(source) {
|
|
|
11148
11233
|
}
|
|
11149
11234
|
function eachScript(projectPath, each) {
|
|
11150
11235
|
const visit = (directory, prefix) => {
|
|
11151
|
-
if (
|
|
11236
|
+
if (existsSync4(join8(directory, ".gdignore"))) {
|
|
11152
11237
|
return;
|
|
11153
11238
|
}
|
|
11154
11239
|
for (const entry of readdirSync3(directory, { withFileTypes: true })) {
|
|
@@ -11544,7 +11629,7 @@ function uncachedForTheEngineNote(projectPath, types) {
|
|
|
11544
11629
|
}
|
|
11545
11630
|
const one = types.length === 1;
|
|
11546
11631
|
const named = types.map((type) => `${type.type} (${type.declaredIn})`).join(", ");
|
|
11547
|
-
const cacheExists =
|
|
11632
|
+
const cacheExists = existsSync4(join8(projectPath, ".godot", "global_script_class_cache.cfg"));
|
|
11548
11633
|
const state = cacheExists ? `missing from .godot/global_script_class_cache.cfg, which is where the engine that compiled these scripts resolves a class name from, so the error is the cache being behind the files rather than the script.` : `the engine that compiled these scripts resolves a class name from .godot/global_script_class_cache.cfg, which has not been written yet, as in a project no editor has opened, so the error is the missing cache rather than the script.`;
|
|
11549
11634
|
return `${named} ${one ? "is" : "are"} declared in this project${cacheExists ? " and" : ", but"} ${state} ` + "project_import refresh_classes writes the cache from the declarations on disk; editor_run start " + "writes it before a game, and an editor opening the project writes it when it scans.";
|
|
11550
11635
|
}
|
|
@@ -11570,7 +11655,7 @@ function declaredSince(projectPath, paths, names, since) {
|
|
|
11570
11655
|
});
|
|
11571
11656
|
}
|
|
11572
11657
|
function cachedAtMissingPaths(cached, projectPath) {
|
|
11573
|
-
return [...cached].filter(([, path]) => path.startsWith("res://") && !
|
|
11658
|
+
return [...cached].filter(([, path]) => path.startsWith("res://") && !existsSync4(join8(projectPath, path.slice("res://".length)))).map(([name]) => name).sort();
|
|
11574
11659
|
}
|
|
11575
11660
|
function staleAgainst(cached, projectPath) {
|
|
11576
11661
|
return [...declaredClasses(projectPath)].filter(([name, path]) => cached.get(name) !== path).map(([name]) => name);
|
|
@@ -12904,7 +12989,7 @@ var init_suite_judge = __esm(() => {
|
|
|
12904
12989
|
// src/engine-launch.ts
|
|
12905
12990
|
import {
|
|
12906
12991
|
closeSync as closeSync4,
|
|
12907
|
-
existsSync as
|
|
12992
|
+
existsSync as existsSync5,
|
|
12908
12993
|
fstatSync as fstatSync2,
|
|
12909
12994
|
openSync as openSync4,
|
|
12910
12995
|
readdirSync as readdirSync4,
|
|
@@ -12944,7 +13029,7 @@ function godotNamed(value, cwd) {
|
|
|
12944
13029
|
return null;
|
|
12945
13030
|
}
|
|
12946
13031
|
const path = resolve5(cwd, value);
|
|
12947
|
-
if (!
|
|
13032
|
+
if (!existsSync5(path) || statSync6(path).isDirectory()) {
|
|
12948
13033
|
throw new EngineUsageError(`--godot names ${path}, which is not an engine executable.`);
|
|
12949
13034
|
}
|
|
12950
13035
|
return path;
|
|
@@ -12975,7 +13060,7 @@ function resPathOf(entry, projectPath, cwd) {
|
|
|
12975
13060
|
const file = caseAt?.[1] ?? entry;
|
|
12976
13061
|
const fromProject = resolve5(projectPath, file);
|
|
12977
13062
|
const fromHere = resolve5(cwd, file);
|
|
12978
|
-
const absolute = isAbsolute3(file) || !
|
|
13063
|
+
const absolute = isAbsolute3(file) || !existsSync5(fromProject) && existsSync5(fromHere) ? fromHere : fromProject;
|
|
12979
13064
|
const inside = relative3(projectPath, absolute);
|
|
12980
13065
|
if (inside.startsWith("..") || isAbsolute3(inside)) {
|
|
12981
13066
|
throw new EngineUsageError(`${entry} is not inside the project at ${projectPath}.`);
|
|
@@ -12987,7 +13072,7 @@ function homeOf(projectPath) {
|
|
|
12987
13072
|
return mainCheckoutOf(projectPath) ?? projectPath;
|
|
12988
13073
|
}
|
|
12989
13074
|
function sweepRunDirectories(runs, kept = KEPT_RUN_DIRECTORIES) {
|
|
12990
|
-
if (!
|
|
13075
|
+
if (!existsSync5(runs)) {
|
|
12991
13076
|
return;
|
|
12992
13077
|
}
|
|
12993
13078
|
const ended = [];
|
|
@@ -13017,6 +13102,9 @@ function roomFor(most, processors, available, said = "of memory free", processor
|
|
|
13017
13102
|
held: byMemory < processors ? `the machine has ${gigabytes(Math.max(0, available))} ${said}, ${gigabytes(MEMORY_KEPT)} of it kept for everything else and ${gigabytes(MEMORY_PER_ENGINE)} taken for each engine` : processorsSaid
|
|
13018
13103
|
};
|
|
13019
13104
|
}
|
|
13105
|
+
function roomForAnother(available, starting) {
|
|
13106
|
+
return available - MEMORY_KEPT - starting * MEMORY_PER_ENGINE >= MEMORY_PER_ENGINE;
|
|
13107
|
+
}
|
|
13020
13108
|
async function memoryAvailable() {
|
|
13021
13109
|
const level = await macMemoryLevel();
|
|
13022
13110
|
if (level !== null) {
|
|
@@ -13155,9 +13243,13 @@ async function watchedEngine(launch, lock, args, directory, log, silenceSeconds,
|
|
|
13155
13243
|
return;
|
|
13156
13244
|
}
|
|
13157
13245
|
};
|
|
13246
|
+
const found = (engine) => {
|
|
13247
|
+
watching(engine, true);
|
|
13248
|
+
nameSlotEngineOf(lock, process7.pid, engine);
|
|
13249
|
+
};
|
|
13158
13250
|
let pid = engineAt();
|
|
13159
13251
|
if (pid !== undefined) {
|
|
13160
|
-
|
|
13252
|
+
found(pid);
|
|
13161
13253
|
}
|
|
13162
13254
|
try {
|
|
13163
13255
|
let size = 0;
|
|
@@ -13172,7 +13264,7 @@ async function watchedEngine(launch, lock, args, directory, log, silenceSeconds,
|
|
|
13172
13264
|
if (pid === undefined) {
|
|
13173
13265
|
pid = engineAt();
|
|
13174
13266
|
if (pid !== undefined) {
|
|
13175
|
-
|
|
13267
|
+
found(pid);
|
|
13176
13268
|
}
|
|
13177
13269
|
}
|
|
13178
13270
|
const taken = await sample();
|
|
@@ -13221,7 +13313,7 @@ async function watchedEngine(launch, lock, args, directory, log, silenceSeconds,
|
|
|
13221
13313
|
continue;
|
|
13222
13314
|
}
|
|
13223
13315
|
const { stoppedIn } = readRun(readLog(log));
|
|
13224
|
-
const unstarted = helper !== null && !
|
|
13316
|
+
const unstarted = helper !== null && !existsSync5(helper.pid) ? `, and it never started ${helper.how}: ${helperStep(helper.step)}` : "";
|
|
13225
13317
|
ended = `the engine printed nothing for ${String(allowed.seconds)} s${countedBy(quiet, silent, at)}${stoppedIn === null ? "" : ` while running ${stoppedIn}`}, so it was ended${unstarted}`;
|
|
13226
13318
|
stop();
|
|
13227
13319
|
}
|
|
@@ -13307,7 +13399,7 @@ var init_engine_launch = __esm(() => {
|
|
|
13307
13399
|
});
|
|
13308
13400
|
|
|
13309
13401
|
// src/detection.ts
|
|
13310
|
-
import { existsSync as
|
|
13402
|
+
import { existsSync as existsSync6, readdirSync as readdirSync5, statSync as statSync7 } from "node:fs";
|
|
13311
13403
|
import { homedir as homedir4 } from "node:os";
|
|
13312
13404
|
import { join as join10 } from "node:path";
|
|
13313
13405
|
function resolveHomeDirectory() {
|
|
@@ -13318,7 +13410,7 @@ function resolveHomeDirectory() {
|
|
|
13318
13410
|
}
|
|
13319
13411
|
}
|
|
13320
13412
|
function scanDirectoryForGodotBinaries(directory, platform) {
|
|
13321
|
-
if (!directory || !
|
|
13413
|
+
if (!directory || !existsSync6(directory)) {
|
|
13322
13414
|
return [];
|
|
13323
13415
|
}
|
|
13324
13416
|
let entries;
|
|
@@ -13586,7 +13678,7 @@ var init_launch = __esm(() => {
|
|
|
13586
13678
|
});
|
|
13587
13679
|
|
|
13588
13680
|
// src/godot-path.ts
|
|
13589
|
-
import { existsSync as
|
|
13681
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
13590
13682
|
import { isAbsolute as isAbsolute4, normalize, resolve as resolve6 } from "node:path";
|
|
13591
13683
|
function versionStartOf(error) {
|
|
13592
13684
|
const failed = error ?? {};
|
|
@@ -13664,7 +13756,7 @@ class GodotLocator {
|
|
|
13664
13756
|
if (known !== undefined) {
|
|
13665
13757
|
return known;
|
|
13666
13758
|
}
|
|
13667
|
-
if (path !== "godot" && !
|
|
13759
|
+
if (path !== "godot" && !existsSync7(path)) {
|
|
13668
13760
|
this.answered.set(path, "does not exist");
|
|
13669
13761
|
return "does not exist";
|
|
13670
13762
|
}
|
|
@@ -13989,6 +14081,9 @@ function runStarted(executable, args, lock, options, signal) {
|
|
|
13989
14081
|
env: onTheSlot(process.env, lock),
|
|
13990
14082
|
...signal === undefined ? {} : { signal }
|
|
13991
14083
|
});
|
|
14084
|
+
if (child.pid !== undefined) {
|
|
14085
|
+
nameSlotEngineOf(lock, process.pid, child.pid);
|
|
14086
|
+
}
|
|
13992
14087
|
child.stdout.on("data", (chunk) => {
|
|
13993
14088
|
log.append("stdout", chunk);
|
|
13994
14089
|
});
|
|
@@ -14046,7 +14141,7 @@ var init_engine_run = __esm(() => {
|
|
|
14046
14141
|
});
|
|
14047
14142
|
|
|
14048
14143
|
// src/doc-cache.ts
|
|
14049
|
-
import { existsSync as
|
|
14144
|
+
import { existsSync as existsSync8, readdirSync as readdirSync6, statSync as statSync8 } from "node:fs";
|
|
14050
14145
|
import { homedir as homedir5 } from "node:os";
|
|
14051
14146
|
import { basename as basename5, dirname as dirname5, isAbsolute as isAbsolute5, join as join11 } from "node:path";
|
|
14052
14147
|
import process9 from "node:process";
|
|
@@ -14054,7 +14149,7 @@ function editorCacheDirectory(godotPath, platform = process9.platform, env = pro
|
|
|
14054
14149
|
const beside = dirname5(godotPath);
|
|
14055
14150
|
const bundle = platform === "darwin" && basename5(beside) === "MacOS" && basename5(dirname5(beside)) === "Contents" ? dirname5(dirname5(dirname5(beside))) : null;
|
|
14056
14151
|
for (const folder of bundle === null ? [beside] : [beside, bundle]) {
|
|
14057
|
-
if (
|
|
14152
|
+
if (existsSync8(join11(folder, "._sc_")) || existsSync8(join11(folder, "_sc_"))) {
|
|
14058
14153
|
return join11(folder, "editor_data", "cache");
|
|
14059
14154
|
}
|
|
14060
14155
|
}
|
|
@@ -14102,7 +14197,7 @@ var init_doc_cache = __esm(() => {
|
|
|
14102
14197
|
});
|
|
14103
14198
|
|
|
14104
14199
|
// src/project-scan.ts
|
|
14105
|
-
import { existsSync as
|
|
14200
|
+
import { existsSync as existsSync9, readdirSync as readdirSync7, readFileSync as readFileSync12, statSync as statSync9 } from "node:fs";
|
|
14106
14201
|
import { basename as basename6, extname as extname2, join as join12, relative as relative4, sep as sep3 } from "node:path";
|
|
14107
14202
|
function skipped(name) {
|
|
14108
14203
|
return name.startsWith(".") || SKIPPED.has(name);
|
|
@@ -14111,10 +14206,10 @@ function steppedOver(directory) {
|
|
|
14111
14206
|
return gdignored(directory) || installedByUs(directory);
|
|
14112
14207
|
}
|
|
14113
14208
|
function gdignored(directory) {
|
|
14114
|
-
return
|
|
14209
|
+
return existsSync9(join12(directory, ".gdignore"));
|
|
14115
14210
|
}
|
|
14116
14211
|
function installedByUs(directory) {
|
|
14117
|
-
return
|
|
14212
|
+
return existsSync9(join12(directory, VERSION_MARKER));
|
|
14118
14213
|
}
|
|
14119
14214
|
function projectStructure(projectPath) {
|
|
14120
14215
|
const structure = { scenes: 0, scripts: 0, assets: 0, other: 0 };
|
|
@@ -14227,7 +14322,7 @@ function scriptsWithoutUid(projectPath) {
|
|
|
14227
14322
|
continue;
|
|
14228
14323
|
}
|
|
14229
14324
|
const extension = entry.name.split(".").pop()?.toLowerCase() ?? "";
|
|
14230
|
-
if (CARRIES_A_UID.has(extension) && !
|
|
14325
|
+
if (CARRIES_A_UID.has(extension) && !existsSync9(join12(directory, `${entry.name}.uid`))) {
|
|
14231
14326
|
found.push(spelled);
|
|
14232
14327
|
}
|
|
14233
14328
|
}
|
|
@@ -14494,7 +14589,7 @@ var init_project_scan = __esm(() => {
|
|
|
14494
14589
|
|
|
14495
14590
|
// src/import-freshness.ts
|
|
14496
14591
|
import { createHash as createHash2 } from "node:crypto";
|
|
14497
|
-
import { existsSync as
|
|
14592
|
+
import { existsSync as existsSync10, readdirSync as readdirSync8, readFileSync as readFileSync13, statSync as statSync10 } from "node:fs";
|
|
14498
14593
|
import { join as join13 } from "node:path";
|
|
14499
14594
|
function md5Of(file) {
|
|
14500
14595
|
let stats;
|
|
@@ -14620,7 +14715,7 @@ function behind(projectPath, resPath, sidecarFile, sidecar, importedFrom) {
|
|
|
14620
14715
|
return "its import file names no imported output, as one written before the engine imports from it does";
|
|
14621
14716
|
}
|
|
14622
14717
|
}
|
|
14623
|
-
if (outputs.some((output) => !
|
|
14718
|
+
if (outputs.some((output) => !existsSync10(onDisk(projectPath, output)))) {
|
|
14624
14719
|
return "its imported output is not on disk";
|
|
14625
14720
|
}
|
|
14626
14721
|
const source = unquoted(deps.get("source_file"));
|
|
@@ -14645,7 +14740,7 @@ function staleImports(projectPath) {
|
|
|
14645
14740
|
const stale = [];
|
|
14646
14741
|
const importedFrom = importedSidecarMd5s(projectPath);
|
|
14647
14742
|
const visit = (directory, resDirectory) => {
|
|
14648
|
-
if (
|
|
14743
|
+
if (existsSync10(join13(directory, ".gdignore")) || existsSync10(join13(directory, VERSION_MARKER))) {
|
|
14649
14744
|
return;
|
|
14650
14745
|
}
|
|
14651
14746
|
let entries;
|
|
@@ -14736,7 +14831,7 @@ var init_import_freshness = __esm(() => {
|
|
|
14736
14831
|
|
|
14737
14832
|
// src/library-copies.ts
|
|
14738
14833
|
import {
|
|
14739
|
-
existsSync as
|
|
14834
|
+
existsSync as existsSync11,
|
|
14740
14835
|
mkdirSync as mkdirSync4,
|
|
14741
14836
|
readdirSync as readdirSync9,
|
|
14742
14837
|
readFileSync as readFileSync14,
|
|
@@ -14754,7 +14849,7 @@ function freeLibraryCopies(projectPath, platform = process.platform) {
|
|
|
14754
14849
|
for (const library of windowsLibraries(projectPath)) {
|
|
14755
14850
|
const folder = dirname6(library);
|
|
14756
14851
|
const copy = `~${basename7(library)}`;
|
|
14757
|
-
if (
|
|
14852
|
+
if (existsSync11(join14(folder, copy))) {
|
|
14758
14853
|
const aside = join14(folder, `${copy}.aside-${process.pid}-${Date.now()}`);
|
|
14759
14854
|
try {
|
|
14760
14855
|
renameSync3(join14(folder, copy), aside);
|
|
@@ -14780,12 +14875,26 @@ function freeLibraryCopies(projectPath, platform = process.platform) {
|
|
|
14780
14875
|
}
|
|
14781
14876
|
function seedExtensionList(projectPath) {
|
|
14782
14877
|
const list = join14(projectPath, ".godot", "extension_list.cfg");
|
|
14783
|
-
if (
|
|
14878
|
+
if (existsSync11(list)) {
|
|
14784
14879
|
return null;
|
|
14785
14880
|
}
|
|
14881
|
+
const found = unlistedExtensions(projectPath);
|
|
14882
|
+
if (found.length === 0) {
|
|
14883
|
+
return [];
|
|
14884
|
+
}
|
|
14885
|
+
mkdirSync4(dirname6(list), { recursive: true });
|
|
14886
|
+
writeFileSync7(list, `${found.join(`
|
|
14887
|
+
`)}
|
|
14888
|
+
`);
|
|
14889
|
+
return found;
|
|
14890
|
+
}
|
|
14891
|
+
function unlistedExtensions(projectPath) {
|
|
14892
|
+
if (existsSync11(join14(projectPath, ".godot", "extension_list.cfg"))) {
|
|
14893
|
+
return [];
|
|
14894
|
+
}
|
|
14786
14895
|
const found = [];
|
|
14787
14896
|
const visit = (directory, resDirectory) => {
|
|
14788
|
-
if (
|
|
14897
|
+
if (existsSync11(join14(directory, ".gdignore"))) {
|
|
14789
14898
|
return;
|
|
14790
14899
|
}
|
|
14791
14900
|
let entries;
|
|
@@ -14806,15 +14915,7 @@ function seedExtensionList(projectPath) {
|
|
|
14806
14915
|
}
|
|
14807
14916
|
};
|
|
14808
14917
|
visit(projectPath, "res://");
|
|
14809
|
-
|
|
14810
|
-
return [];
|
|
14811
|
-
}
|
|
14812
|
-
found.sort();
|
|
14813
|
-
mkdirSync4(dirname6(list), { recursive: true });
|
|
14814
|
-
writeFileSync7(list, `${found.join(`
|
|
14815
|
-
`)}
|
|
14816
|
-
`);
|
|
14817
|
-
return found;
|
|
14918
|
+
return found.sort();
|
|
14818
14919
|
}
|
|
14819
14920
|
function windowsLibraries(projectPath) {
|
|
14820
14921
|
const listed = readOrNull(join14(projectPath, ".godot", "extension_list.cfg"));
|
|
@@ -14864,12 +14965,12 @@ var init_library_copies = () => {};
|
|
|
14864
14965
|
|
|
14865
14966
|
// src/reimport.ts
|
|
14866
14967
|
import { createHash as createHash3 } from "node:crypto";
|
|
14867
|
-
import { existsSync as
|
|
14968
|
+
import { existsSync as existsSync12, readFileSync as readFileSync15, rmSync as rmSync8, statSync as statSync11, utimesSync, writeFileSync as writeFileSync8 } from "node:fs";
|
|
14868
14969
|
import { basename as basename8, join as join15 } from "node:path";
|
|
14869
14970
|
function forceNextImport(projectPath, resourcePath) {
|
|
14870
14971
|
const relative = resourcePath.replace(/^res:\/\//, "");
|
|
14871
14972
|
const sidecar = join15(projectPath, `${relative}.import`);
|
|
14872
|
-
if (!
|
|
14973
|
+
if (!existsSync12(sidecar)) {
|
|
14873
14974
|
return;
|
|
14874
14975
|
}
|
|
14875
14976
|
const { atime, mtimeMs } = statSync11(sidecar);
|
|
@@ -14884,7 +14985,7 @@ function importRecord(projectPath, resourcePath) {
|
|
|
14884
14985
|
var init_reimport = () => {};
|
|
14885
14986
|
|
|
14886
14987
|
// src/scratch.ts
|
|
14887
|
-
import { existsSync as
|
|
14988
|
+
import { existsSync as existsSync13, mkdtempSync as mkdtempSync2, readdirSync as readdirSync10, rmSync as rmSync9 } from "node:fs";
|
|
14888
14989
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
14889
14990
|
import { join as join16 } from "node:path";
|
|
14890
14991
|
import process10 from "node:process";
|
|
@@ -14943,7 +15044,7 @@ function tryAgain(path, attempt) {
|
|
|
14943
15044
|
lastTryOnExit();
|
|
14944
15045
|
}
|
|
14945
15046
|
const after = AGAIN_AFTER_MS[attempt];
|
|
14946
|
-
if (after === undefined || !
|
|
15047
|
+
if (after === undefined || !existsSync13(path)) {
|
|
14947
15048
|
waiting.delete(path);
|
|
14948
15049
|
if (after === undefined) {
|
|
14949
15050
|
atExit.add(path);
|
|
@@ -15099,7 +15200,7 @@ var init_script_origins = __esm(() => {
|
|
|
15099
15200
|
});
|
|
15100
15201
|
|
|
15101
15202
|
// src/headless.ts
|
|
15102
|
-
import { existsSync as
|
|
15203
|
+
import { existsSync as existsSync14, readFileSync as readFileSync16, writeFileSync as writeFileSync9 } from "node:fs";
|
|
15103
15204
|
import { dirname as dirname7, join as join18 } from "node:path";
|
|
15104
15205
|
function snakeCased(params) {
|
|
15105
15206
|
const result = emptyRecord();
|
|
@@ -15388,7 +15489,7 @@ async function operationOutcome(engine, operation, params, projectPath) {
|
|
|
15388
15489
|
};
|
|
15389
15490
|
}
|
|
15390
15491
|
function answerIn(file) {
|
|
15391
|
-
if (!
|
|
15492
|
+
if (!existsSync14(file)) {
|
|
15392
15493
|
return { kind: "none" };
|
|
15393
15494
|
}
|
|
15394
15495
|
const text = readFileSync16(file, "utf8");
|
|
@@ -15417,7 +15518,7 @@ var init_headless = __esm(() => {
|
|
|
15417
15518
|
});
|
|
15418
15519
|
|
|
15419
15520
|
// src/update-check.ts
|
|
15420
|
-
import { existsSync as
|
|
15521
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync5, readFileSync as readFileSync17, writeFileSync as writeFileSync10 } from "node:fs";
|
|
15421
15522
|
import { homedir as homedir6, tmpdir as tmpdir6 } from "node:os";
|
|
15422
15523
|
import { join as join19 } from "node:path";
|
|
15423
15524
|
function packageUrl(root) {
|
|
@@ -15459,7 +15560,7 @@ function cacheFile(environment = process.env) {
|
|
|
15459
15560
|
}
|
|
15460
15561
|
function readCache(path) {
|
|
15461
15562
|
try {
|
|
15462
|
-
if (!
|
|
15563
|
+
if (!existsSync15(path)) {
|
|
15463
15564
|
return null;
|
|
15464
15565
|
}
|
|
15465
15566
|
const parsed = JSON.parse(readFileSync17(path, "utf8"));
|
|
@@ -15939,7 +16040,7 @@ var init_ports = __esm(() => {
|
|
|
15939
16040
|
});
|
|
15940
16041
|
|
|
15941
16042
|
// src/lsp_client.ts
|
|
15942
|
-
import { existsSync as
|
|
16043
|
+
import { existsSync as existsSync16, realpathSync as realpathSync3 } from "node:fs";
|
|
15943
16044
|
import { readFile, realpath } from "node:fs/promises";
|
|
15944
16045
|
import { createConnection } from "node:net";
|
|
15945
16046
|
import { dirname as dirname8, extname as extname3, join as join20, resolve as resolve7 } from "node:path";
|
|
@@ -16620,7 +16721,7 @@ async function resolveLSPPaths(projectPathValue, scriptPathValue) {
|
|
|
16620
16721
|
} catch {
|
|
16621
16722
|
throw new ArgumentRefusal(`Project path does not exist: ${requestedProjectPath}`);
|
|
16622
16723
|
}
|
|
16623
|
-
if (!
|
|
16724
|
+
if (!existsSync16(join20(projectPath, "project.godot"))) {
|
|
16624
16725
|
throw new ArgumentRefusal(`Not a Godot project: ${projectPath}. Point projectPath at the directory holding project.godot.`);
|
|
16625
16726
|
}
|
|
16626
16727
|
const contained = resolveWithinProject(projectPath, scriptPathValue);
|
|
@@ -17134,7 +17235,7 @@ function readParams(params, key) {
|
|
|
17134
17235
|
import { createHash as createHash5 } from "node:crypto";
|
|
17135
17236
|
import {
|
|
17136
17237
|
cpSync,
|
|
17137
|
-
existsSync as
|
|
17238
|
+
existsSync as existsSync18,
|
|
17138
17239
|
mkdirSync as mkdirSync6,
|
|
17139
17240
|
readdirSync as readdirSync12,
|
|
17140
17241
|
readFileSync as readFileSync21,
|
|
@@ -17217,7 +17318,7 @@ function installedRuntimeDigest(projectPath) {
|
|
|
17217
17318
|
}
|
|
17218
17319
|
function digestMarker(projectPath, addon) {
|
|
17219
17320
|
const marker = join22(projectPath, "addons", addon, DIGEST_MARKER);
|
|
17220
|
-
if (!
|
|
17321
|
+
if (!existsSync18(marker)) {
|
|
17221
17322
|
return null;
|
|
17222
17323
|
}
|
|
17223
17324
|
const said = readFileSync21(marker, "utf8").trim();
|
|
@@ -17234,7 +17335,7 @@ function shippedLoader() {
|
|
|
17234
17335
|
}
|
|
17235
17336
|
function loaderState(projectPath) {
|
|
17236
17337
|
const copy = join22(projectPath, ...RUNTIME_AUTOLOAD.path.split("/"));
|
|
17237
|
-
if (!
|
|
17338
|
+
if (!existsSync18(copy)) {
|
|
17238
17339
|
return "missing";
|
|
17239
17340
|
}
|
|
17240
17341
|
const lines = (path) => readFileSync21(path, "utf8").replaceAll(`\r
|
|
@@ -17253,7 +17354,7 @@ function writeLoader(projectPath) {
|
|
|
17253
17354
|
}
|
|
17254
17355
|
function removeLoader(projectPath) {
|
|
17255
17356
|
const copy = join22(projectPath, ...RUNTIME_AUTOLOAD.path.split("/"));
|
|
17256
|
-
if (!
|
|
17357
|
+
if (!existsSync18(copy)) {
|
|
17257
17358
|
return false;
|
|
17258
17359
|
}
|
|
17259
17360
|
rmSync10(copy);
|
|
@@ -17269,10 +17370,10 @@ function shippedListedRunner() {
|
|
|
17269
17370
|
}
|
|
17270
17371
|
function gdUnit4Unusable(projectPath) {
|
|
17271
17372
|
const marker = "addons/gdUnit4/plugin.cfg";
|
|
17272
|
-
if (!
|
|
17373
|
+
if (!existsSync18(join22(projectPath, ...marker.split("/")))) {
|
|
17273
17374
|
return { missing: true, reason: `gdUnit4 is not installed in this project: no ${marker}` };
|
|
17274
17375
|
}
|
|
17275
|
-
if (!
|
|
17376
|
+
if (!existsSync18(join22(projectPath, ...GDUNIT4_CI_RUNNER.split("/")))) {
|
|
17276
17377
|
return {
|
|
17277
17378
|
missing: false,
|
|
17278
17379
|
reason: `gdUnit4 in this project is older than 6.0, which the shipped runner needs: no ${GDUNIT4_CI_RUNNER}`
|
|
@@ -17284,11 +17385,11 @@ function installAddons(projectPath, from = shippedAddonsDirectory()) {
|
|
|
17284
17385
|
const installed = [];
|
|
17285
17386
|
for (const name of ADDONS) {
|
|
17286
17387
|
const source = join22(from, name);
|
|
17287
|
-
if (!
|
|
17388
|
+
if (!existsSync18(join22(source, addonMarking(name)))) {
|
|
17288
17389
|
throw new Error(`The package holds no ${name} addon at ${source}.`);
|
|
17289
17390
|
}
|
|
17290
17391
|
const target = join22(projectPath, "addons", name);
|
|
17291
|
-
const replaced =
|
|
17392
|
+
const replaced = existsSync18(target);
|
|
17292
17393
|
rmSync10(target, { recursive: true, force: true });
|
|
17293
17394
|
mkdirSync6(dirname9(target), { recursive: true });
|
|
17294
17395
|
cpSync(source, target, { recursive: true });
|
|
@@ -17304,7 +17405,7 @@ function installAddons(projectPath, from = shippedAddonsDirectory()) {
|
|
|
17304
17405
|
}
|
|
17305
17406
|
function installedAddonVersion(projectPath) {
|
|
17306
17407
|
const marker = join22(projectPath, "addons", ADDONS[0], VERSION_MARKER);
|
|
17307
|
-
if (!
|
|
17408
|
+
if (!existsSync18(marker)) {
|
|
17308
17409
|
return null;
|
|
17309
17410
|
}
|
|
17310
17411
|
const said = readFileSync21(marker, "utf8").trim();
|
|
@@ -17314,13 +17415,13 @@ function removeAddons(projectPath) {
|
|
|
17314
17415
|
const removed = [];
|
|
17315
17416
|
for (const name of ADDONS) {
|
|
17316
17417
|
const target = join22(projectPath, "addons", name);
|
|
17317
|
-
if (
|
|
17418
|
+
if (existsSync18(target)) {
|
|
17318
17419
|
rmSync10(target, { recursive: true, force: true });
|
|
17319
17420
|
removed.push(target);
|
|
17320
17421
|
}
|
|
17321
17422
|
}
|
|
17322
17423
|
const addons = join22(projectPath, "addons");
|
|
17323
|
-
if (removed.length > 0 &&
|
|
17424
|
+
if (removed.length > 0 && existsSync18(addons) && readdirSync12(addons).length === 0) {
|
|
17324
17425
|
rmdirSync(addons);
|
|
17325
17426
|
removed.push(addons);
|
|
17326
17427
|
}
|
|
@@ -17420,8 +17521,8 @@ function inspectProject(projectPath) {
|
|
|
17420
17521
|
const addons = ADDONS.map((name) => {
|
|
17421
17522
|
const directory = join22(projectPath, "addons", name);
|
|
17422
17523
|
const marker = join22(directory, VERSION_MARKER);
|
|
17423
|
-
const installed =
|
|
17424
|
-
const version =
|
|
17524
|
+
const installed = existsSync18(directory);
|
|
17525
|
+
const version = existsSync18(marker) ? readFileSync21(marker, "utf8").trim() : null;
|
|
17425
17526
|
const current = version === SERVER_VERSION;
|
|
17426
17527
|
if (!installed) {
|
|
17427
17528
|
problems.push(`addons/${name} is not installed; run gdharness setup`);
|
|
@@ -17454,7 +17555,7 @@ function inspectProject(projectPath) {
|
|
|
17454
17555
|
const ignoredAutoloads = [];
|
|
17455
17556
|
const addonMissing = (path) => addons.some((addon) => !addon.installed && path.startsWith(`addons/${addon.name}/`));
|
|
17456
17557
|
for (const [name, path] of named) {
|
|
17457
|
-
if (!
|
|
17558
|
+
if (!existsSync18(join22(projectPath, path))) {
|
|
17458
17559
|
if (!addonMissing(path)) {
|
|
17459
17560
|
problems.push(`the ${name} autoload names res://${path}, which is not in this project, so it boots with a missing script; restore that file, or point the autoload at one that is here`);
|
|
17460
17561
|
}
|
|
@@ -18338,7 +18439,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
18338
18439
|
name: "scene_node",
|
|
18339
18440
|
title: "Scene nodes",
|
|
18340
18441
|
description: `One node in a scene file: add, read, set, duplicate, reparent or delete it, paint TileMap cells, or bake a navigation region. Any ClassDB node type or script class can be added, so a NavigationRegion2D, an AnimationTree or a Camera3D is an add with that nodeType and its properties, and another scene is instanced by an add with instancePath. A set with properties {"name": "Boss"} renames a node, and answers nodePath as its new path. A rename or a reparent carries the node paths naming the node, as the editor's rename does: NodePath values on nodes (in arrays, dictionaries, built-in resources, %unique paths) and the tracks its players' animations hold, saving a library kept in a .tres of its own, and answers each rewrite under retargeted and each path it left under notRetargeted. The move is followed into every other .tscn that instances or inherits this scene at any depth: the editable children, values, added nodes and connections named by the old path are rewritten, since Godot finds a moved node's values by unique_id but editable children only by path and drops the values kept below them on the next save, and that scene's node paths and tracks are carried as above. A delete rewrites no path, and answers under stillNaming what named the deleted node and now names nothing. A property holding a Resource takes the res:// path of one, so a texture, a material or a theme is a set like any other. A write is refused while the editor holds unsaved changes to the scene. A node this scene inherits takes values of this scene's own, and so does a node inside an instance of another scene once that instance's editableChildren is true; neither can be moved, renamed, copied or deleted, since the other scene makes it again on load. ${WITHOUT_AN_EDITOR}`,
|
|
18341
|
-
answer: "get answers nodeType, the node's engine class, with scriptClass when its script declares a class_name; nodePath, its path from the root however it was named; setHere, the properties this scene's own file sets on it; and valuesFrom, the scene every other value comes from, when another scene makes the node. A set that gives a property the value the node has without it (what the scene it comes from gives, or its default) leaves it out of the file, as the editor does, and answers it under notStored, with notStoredNote saying what it follows now. retargeted lists each path a rename or a reparent rewrote, as {scenePath, nodePath, property or animation and track, from, to}, and notRetargeted each it left, with a reason: a track kept in another scene or an imported file, or a value another scene gives that the move left naming nothing. followed names the other scenes a move rewrote, and notFollowed any left as they were, with why. scriptsNaming lists each line of a script that reads a node a rename, a reparent or a delete took by the path it had, as {scenePath, nodePath, script, line, from, to}: the script is on the node at nodePath, or is one that node's script extends, in this scene or one instancing or inheriting it, and to is the path that reaches the node from there now, absent after a delete. It reads $Path, %Unique, and a string handed to get_node, get_node_or_null or has_node on the node itself; a path built at run time is not seen. Scripts are left as they were, as the editor's own rename leaves them, so each line listed fails until it is changed. A 2D bake_navigation that read no obstacle says in its note that all its outlines enclose is walkable, and names the nodes giving obstacles that sit under no region. stillNaming lists each node path and track, here and in the scenes instancing or inheriting this one, that named a deleted node; a property typed as a node, or an array or dictionary of nodes, holds the node itself, so the one that held a deleted node holds null there, as the editor saves it, and its entry adds cleared: true. deletedWithIt lists each node of this scene's own that went with it, the nodes inside an instance going with the instance. groups lists, sorted, every group a node is in, on a get, an add that gave addGroups and every set that changes them; get adds groupsHere, the groups this file puts it in, when another scene puts it in others, and layers, each layer mask it answers (collision_layer, collision_mask, visibility_layer) as the layers it holds, {layer, name} with the name project.godot gives the layer. Each of these lists is answered only when it names anything. add and set answer each property given under properties as the node holds it once written; alsoChanged gives the other properties the engine changed in step with a set, as a Control's offsets with its size, and those a reparent changed to keep the node where it is drawn or that the new parent sets, as a container gives a Control its layout_mode, as {was, now}; namesNoNode, each node path written naming no node; sharedWith, for a property written through a resource built into the scene, each other {node, property} holding it, which changed too; setByScript, what a script that is not a tool set as a headless write ran, which the file does not hold; loadsAs, a value given that the file holds and the node's own script changes as the scene loads, as it loads. get adds placement, a Node3D's position, rotation_degrees and scale from its transform. " + ALSO_SAVED,
|
|
18442
|
+
answer: "get answers nodeType, the node's engine class, with scriptClass when its script declares a class_name; nodePath, its path from the root however it was named; setHere, the properties this scene's own file sets on it; and valuesFrom, the scene every other value comes from, when another scene makes the node. A set that gives a property the value the node has without it (what the scene it comes from gives, or its default) leaves it out of the file, as the editor does, and answers it under notStored, with notStoredNote saying what it follows now. retargeted lists each path a rename or a reparent rewrote, as {scenePath, nodePath, property or animation and track, from, to}, and notRetargeted each it left, with a reason: a track kept in another scene or an imported file, or a value another scene gives that the move left naming nothing. followed names the other scenes a move rewrote, and notFollowed any left as they were, with why. scriptsNaming lists each line of a script that reads a node a rename, a reparent or a delete took by the path it had, as {scenePath, nodePath, script, line, from, to}: the script is on the node at nodePath, or is one that node's script extends, in this scene or one instancing or inheriting it, and to is the path that reaches the node from there now, absent after a delete. It reads $Path, %Unique, and a string handed to get_node, get_node_or_null or has_node on the node itself; a path built at run time is not seen. Scripts are left as they were, as the editor's own rename leaves them, so each line listed fails until it is changed. A 2D bake_navigation that read no obstacle says in its note that all its outlines enclose is walkable, and names the nodes giving obstacles that sit under no region. stillNaming lists each node path and track, here and in the scenes instancing or inheriting this one, that named a deleted node; a property typed as a node, or an array or dictionary of nodes, holds the node itself, so the one that held a deleted node holds null there, as the editor saves it, and its entry adds cleared: true. deletedWithIt lists each node of this scene's own that went with it, the nodes inside an instance going with the instance. connectionsRemoved lists each connection the file held from or to a node a delete took, as {sourceNodePath, signalName, targetNodePath, methodName}. groups lists, sorted, every group a node is in, on a get, an add that gave addGroups and every set that changes them; get adds groupsHere, the groups this file puts it in, when another scene puts it in others, and layers, each layer mask it answers (collision_layer, collision_mask, visibility_layer) as the layers it holds, {layer, name} with the name project.godot gives the layer. Each of these lists is answered only when it names anything. add and set answer each property given under properties as the node holds it once written; alsoChanged gives the other properties the engine changed in step with a set, as a Control's offsets with its size, and those a reparent changed to keep the node where it is drawn or that the new parent sets, as a container gives a Control its layout_mode, as {was, now}; namesNoNode, each node path written naming no node; sharedWith, for a property written through a resource built into the scene, each other {node, property} holding it, which changed too; setByScript, what a script that is not a tool set as a headless write ran, which the file does not hold; loadsAs, a value given that the file holds and the node's own script changes as the scene loads, as it loads. get adds placement, a Node3D's position, rotation_degrees and scale from its transform. " + ALSO_SAVED,
|
|
18342
18443
|
parameters: {
|
|
18343
18444
|
projectPath: PROJECT_PATH,
|
|
18344
18445
|
scenePath: SCENE_PATH,
|
|
@@ -19079,7 +19180,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
19079
19180
|
},
|
|
19080
19181
|
wait: {
|
|
19081
19182
|
effect: "read",
|
|
19082
|
-
summary: "wait for the run to end, then answer as editor_output does",
|
|
19183
|
+
summary: "wait for the run to end, or to be held by its debugger at a breakpoint, a pause or a step, then answer as editor_output does",
|
|
19083
19184
|
requires: []
|
|
19084
19185
|
},
|
|
19085
19186
|
profile: {
|
|
@@ -20025,7 +20126,7 @@ var init_tool_reference = __esm(() => {
|
|
|
20025
20126
|
});
|
|
20026
20127
|
|
|
20027
20128
|
// src/suite-plan.ts
|
|
20028
|
-
import { existsSync as
|
|
20129
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync9, readFileSync as readFileSync24 } from "node:fs";
|
|
20029
20130
|
import { dirname as dirname11, join as join26, posix as posix3 } from "node:path";
|
|
20030
20131
|
function within(path, folder) {
|
|
20031
20132
|
return path === folder || path.startsWith(`${folder}/`);
|
|
@@ -20437,7 +20538,7 @@ function windowNeedsOf(scripts, paths) {
|
|
|
20437
20538
|
}
|
|
20438
20539
|
function capsFrames(projectPath) {
|
|
20439
20540
|
const file = `${projectPath}/project.godot`;
|
|
20440
|
-
if (!
|
|
20541
|
+
if (!existsSync22(file)) {
|
|
20441
20542
|
return false;
|
|
20442
20543
|
}
|
|
20443
20544
|
const cap = parseProjectGodot(readFileSync24(file, "utf8"))["application"]?.["run/max_fps"];
|
|
@@ -20445,14 +20546,14 @@ function capsFrames(projectPath) {
|
|
|
20445
20546
|
}
|
|
20446
20547
|
function gdUnitFailsOnPushErrors(projectPath) {
|
|
20447
20548
|
const file = `${projectPath}/project.godot`;
|
|
20448
|
-
if (!
|
|
20549
|
+
if (!existsSync22(file)) {
|
|
20449
20550
|
return false;
|
|
20450
20551
|
}
|
|
20451
20552
|
return parseProjectGodot(readFileSync24(file, "utf8"))["gdunit4"]?.["report/godot/push_error"] === true;
|
|
20452
20553
|
}
|
|
20453
20554
|
function viewportOf(projectPath) {
|
|
20454
20555
|
const file = `${projectPath}/project.godot`;
|
|
20455
|
-
if (!
|
|
20556
|
+
if (!existsSync22(file)) {
|
|
20456
20557
|
return null;
|
|
20457
20558
|
}
|
|
20458
20559
|
const text = readFileSync24(file, "utf8");
|
|
@@ -42074,7 +42175,7 @@ var init_stdio = __esm(() => {
|
|
|
42074
42175
|
});
|
|
42075
42176
|
|
|
42076
42177
|
// src/autoload-failure.ts
|
|
42077
|
-
import { existsSync as
|
|
42178
|
+
import { existsSync as existsSync24, readFileSync as readFileSync27 } from "node:fs";
|
|
42078
42179
|
import { join as join29 } from "node:path";
|
|
42079
42180
|
function scriptsAutoloaded(projectPath) {
|
|
42080
42181
|
const scripts = new Map;
|
|
@@ -42090,7 +42191,7 @@ function scriptsAutoloaded(projectPath) {
|
|
|
42090
42191
|
continue;
|
|
42091
42192
|
}
|
|
42092
42193
|
const scene = join29(projectPath, path);
|
|
42093
|
-
if (!
|
|
42194
|
+
if (!existsSync24(scene)) {
|
|
42094
42195
|
continue;
|
|
42095
42196
|
}
|
|
42096
42197
|
try {
|
|
@@ -42113,11 +42214,11 @@ var init_autoload_failure = __esm(() => {
|
|
|
42113
42214
|
});
|
|
42114
42215
|
|
|
42115
42216
|
// src/runtime-client.ts
|
|
42116
|
-
import { existsSync as
|
|
42217
|
+
import { existsSync as existsSync25, readdirSync as readdirSync16, readFileSync as readFileSync28, statSync as statSync15, unlinkSync as unlinkSync3 } from "node:fs";
|
|
42117
42218
|
import { createConnection as createConnection2 } from "node:net";
|
|
42118
42219
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
42119
42220
|
import { dirname as dirname14, join as join30, resolve as resolve12 } from "node:path";
|
|
42120
|
-
import { setTimeout as
|
|
42221
|
+
import { setTimeout as delay6 } from "node:timers/promises";
|
|
42121
42222
|
function runtimeDirectory(variables = process.env) {
|
|
42122
42223
|
const explicit = envValue("GDHARNESS_RUNTIME_DIR", variables);
|
|
42123
42224
|
if (explicit) {
|
|
@@ -42137,7 +42238,7 @@ function runtimeDirectories(variables = process.env) {
|
|
|
42137
42238
|
function errorReportOf(pid, directories = runtimeDirectories()) {
|
|
42138
42239
|
for (const directory of directories) {
|
|
42139
42240
|
const path = join30(directory, `runtime-${pid}.log`);
|
|
42140
|
-
if (
|
|
42241
|
+
if (existsSync25(path)) {
|
|
42141
42242
|
return path;
|
|
42142
42243
|
}
|
|
42143
42244
|
}
|
|
@@ -42283,7 +42384,7 @@ function strangersAmong(candidates, now, startTimes = startTimesOf) {
|
|
|
42283
42384
|
}).map((one) => one.file));
|
|
42284
42385
|
}
|
|
42285
42386
|
function announcedIn(directory) {
|
|
42286
|
-
if (!
|
|
42387
|
+
if (!existsSync25(directory)) {
|
|
42287
42388
|
return [];
|
|
42288
42389
|
}
|
|
42289
42390
|
const found = [];
|
|
@@ -42336,7 +42437,7 @@ function announcedIn(directory) {
|
|
|
42336
42437
|
return found;
|
|
42337
42438
|
}
|
|
42338
42439
|
async function announcementEnded(pid, directories = runtimeDirectories()) {
|
|
42339
|
-
const files = directories.map((directory) => join30(directory, `runtime-${pid}.json`)).filter((file) =>
|
|
42440
|
+
const files = directories.map((directory) => join30(directory, `runtime-${pid}.json`)).filter((file) => existsSync25(file));
|
|
42340
42441
|
const first = files[0];
|
|
42341
42442
|
if (first === undefined) {
|
|
42342
42443
|
return;
|
|
@@ -42347,7 +42448,7 @@ async function announcementEnded(pid, directories = runtimeDirectories()) {
|
|
|
42347
42448
|
if (left <= 0) {
|
|
42348
42449
|
return;
|
|
42349
42450
|
}
|
|
42350
|
-
await
|
|
42451
|
+
await delay6(Math.min(LOOK_EVERY_MS, left));
|
|
42351
42452
|
}
|
|
42352
42453
|
wentAway(first, pid);
|
|
42353
42454
|
for (const file of files) {
|
|
@@ -42379,7 +42480,7 @@ async function announcedSince(projectPath, before, waiting = {}) {
|
|
|
42379
42480
|
if (left <= 0 || waiting.giveUp?.() === true) {
|
|
42380
42481
|
return [];
|
|
42381
42482
|
}
|
|
42382
|
-
await
|
|
42483
|
+
await delay6(Math.min(LOOK_EVERY_MS, left));
|
|
42383
42484
|
}
|
|
42384
42485
|
}
|
|
42385
42486
|
function describe2(endpoint) {
|
|
@@ -42915,11 +43016,11 @@ var init_class_note = __esm(() => {
|
|
|
42915
43016
|
});
|
|
42916
43017
|
|
|
42917
43018
|
// src/config-pin.ts
|
|
42918
|
-
import { existsSync as
|
|
43019
|
+
import { existsSync as existsSync26, readFileSync as readFileSync32 } from "node:fs";
|
|
42919
43020
|
import { join as join34 } from "node:path";
|
|
42920
43021
|
function versionsNamedInConfig(projectPath) {
|
|
42921
43022
|
const config = join34(projectPath, ".mcp.json");
|
|
42922
|
-
if (!
|
|
43023
|
+
if (!existsSync26(config)) {
|
|
42923
43024
|
return [];
|
|
42924
43025
|
}
|
|
42925
43026
|
let text;
|
|
@@ -42945,7 +43046,7 @@ var init_config_pin = __esm(() => {
|
|
|
42945
43046
|
});
|
|
42946
43047
|
|
|
42947
43048
|
// src/cut-test-run.ts
|
|
42948
|
-
import { existsSync as
|
|
43049
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync14, readFileSync as readFileSync33, rmSync as rmSync15, writeFileSync as writeFileSync16 } from "node:fs";
|
|
42949
43050
|
import { dirname as dirname18, join as join35 } from "node:path";
|
|
42950
43051
|
function keptAt(projectPath) {
|
|
42951
43052
|
return join35(projectPath, ".godot", "gdharness-reports", "cut-run.json");
|
|
@@ -42960,7 +43061,7 @@ function keepCutTestRun(projectPath, run) {
|
|
|
42960
43061
|
}
|
|
42961
43062
|
function takeCutTestRun(projectPath) {
|
|
42962
43063
|
const path = keptAt(projectPath);
|
|
42963
|
-
if (!
|
|
43064
|
+
if (!existsSync27(path)) {
|
|
42964
43065
|
return null;
|
|
42965
43066
|
}
|
|
42966
43067
|
try {
|
|
@@ -43006,7 +43107,7 @@ var init_game_debugger = __esm(() => {
|
|
|
43006
43107
|
|
|
43007
43108
|
// src/dap_client.ts
|
|
43008
43109
|
import { createConnection as createConnection3 } from "node:net";
|
|
43009
|
-
import { setTimeout as
|
|
43110
|
+
import { setTimeout as delay7 } from "node:timers/promises";
|
|
43010
43111
|
function fileKey(path) {
|
|
43011
43112
|
return process.platform === "win32" ? path.replaceAll("\\", "/").toLowerCase() : path;
|
|
43012
43113
|
}
|
|
@@ -43486,7 +43587,7 @@ class GodotDAPClient {
|
|
|
43486
43587
|
await this.sendRequest(command, { threadId: resolvedThreadId });
|
|
43487
43588
|
const deadline = Date.now() + this.stepPatienceMs;
|
|
43488
43589
|
while (this.stops === before && this.connected && Date.now() < deadline) {
|
|
43489
|
-
await
|
|
43590
|
+
await delay7(50);
|
|
43490
43591
|
}
|
|
43491
43592
|
return this.stops !== before;
|
|
43492
43593
|
}
|
|
@@ -43512,7 +43613,7 @@ class GodotDAPClient {
|
|
|
43512
43613
|
return answered;
|
|
43513
43614
|
}
|
|
43514
43615
|
} catch {}
|
|
43515
|
-
await
|
|
43616
|
+
await delay7(200);
|
|
43516
43617
|
}
|
|
43517
43618
|
return null;
|
|
43518
43619
|
}
|
|
@@ -43533,7 +43634,7 @@ class GodotDAPClient {
|
|
|
43533
43634
|
break;
|
|
43534
43635
|
}
|
|
43535
43636
|
} catch {}
|
|
43536
|
-
await
|
|
43637
|
+
await delay7(200);
|
|
43537
43638
|
}
|
|
43538
43639
|
if (scopes.length === 0) {
|
|
43539
43640
|
throw new ReadRefusal(`The scopes of frame ${String(frame["id"])} did not arrive from the game within ${this.scopesPatienceMs / 1000}s. They come from the game through the editor, so a busy machine can take longer: ask again`);
|
|
@@ -43566,7 +43667,7 @@ class GodotDAPClient {
|
|
|
43566
43667
|
return { frame, value, ...typeof type === "string" ? { type } : {} };
|
|
43567
43668
|
}
|
|
43568
43669
|
} catch {}
|
|
43569
|
-
await
|
|
43670
|
+
await delay7(200);
|
|
43570
43671
|
}
|
|
43571
43672
|
throw new ReadRefusal(`What ${expression} comes to did not arrive from the game within ${this.evaluatePatienceMs / 1000}s. It comes from the game through the editor, and the first expression a game evaluates loads the script of every global class in the project first, static initialisers included, so one of those may still be running: ask again`);
|
|
43572
43673
|
}
|
|
@@ -43728,7 +43829,7 @@ var init_dap_client = __esm(() => {
|
|
|
43728
43829
|
// src/editor-log.ts
|
|
43729
43830
|
import {
|
|
43730
43831
|
closeSync as closeSync5,
|
|
43731
|
-
existsSync as
|
|
43832
|
+
existsSync as existsSync28,
|
|
43732
43833
|
mkdirSync as mkdirSync15,
|
|
43733
43834
|
openSync as openSync5,
|
|
43734
43835
|
readFileSync as readFileSync34,
|
|
@@ -43792,7 +43893,7 @@ function editorConsole(projectPath, editorPid, openedByAServer) {
|
|
|
43792
43893
|
return { kind: "another editor", notedPid: noted?.pid ?? null };
|
|
43793
43894
|
}
|
|
43794
43895
|
const path = editorLogPath(projectPath);
|
|
43795
|
-
if (!
|
|
43896
|
+
if (!existsSync28(path)) {
|
|
43796
43897
|
return { kind: "not written" };
|
|
43797
43898
|
}
|
|
43798
43899
|
const log = new GameLog;
|
|
@@ -44011,7 +44112,7 @@ var init_editor_log = __esm(() => {
|
|
|
44011
44112
|
});
|
|
44012
44113
|
|
|
44013
44114
|
// src/rename.ts
|
|
44014
|
-
import { existsSync as
|
|
44115
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync16, readFileSync as readFileSync35, renameSync as renameSync4, unlinkSync as unlinkSync4, writeFileSync as writeFileSync18 } from "node:fs";
|
|
44015
44116
|
import { dirname as dirname20, posix as posix4 } from "node:path";
|
|
44016
44117
|
|
|
44017
44118
|
class Script {
|
|
@@ -44736,7 +44837,7 @@ function applyRewrites(rewrites) {
|
|
|
44736
44837
|
if (now !== rewrite.before) {
|
|
44737
44838
|
throw new Error(`${rewrite.path} changed on disk while the rename was being worked out; nothing was written`);
|
|
44738
44839
|
}
|
|
44739
|
-
if (rewrite.writeTo !== rewrite.absolute &&
|
|
44840
|
+
if (rewrite.writeTo !== rewrite.absolute && existsSync29(rewrite.writeTo)) {
|
|
44740
44841
|
throw new Error(`${rewrite.writeTo} already exists; nothing was written`);
|
|
44741
44842
|
}
|
|
44742
44843
|
}
|
|
@@ -44750,7 +44851,7 @@ function applyRewrites(rewrites) {
|
|
|
44750
44851
|
let movedUid = false;
|
|
44751
44852
|
if (rewrite.writeTo !== rewrite.absolute) {
|
|
44752
44853
|
unlinkSync4(rewrite.absolute);
|
|
44753
|
-
if (
|
|
44854
|
+
if (existsSync29(`${rewrite.absolute}.uid`)) {
|
|
44754
44855
|
renameSync4(`${rewrite.absolute}.uid`, `${rewrite.writeTo}.uid`);
|
|
44755
44856
|
movedUid = true;
|
|
44756
44857
|
}
|
|
@@ -44796,7 +44897,7 @@ var init_rename = __esm(() => {
|
|
|
44796
44897
|
});
|
|
44797
44898
|
|
|
44798
44899
|
// src/rename-symbol.ts
|
|
44799
|
-
import { existsSync as
|
|
44900
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync17, readdirSync as readdirSync17, realpathSync as realpathSync5, rmSync as rmSync17, writeFileSync as writeFileSync19 } from "node:fs";
|
|
44800
44901
|
import { basename as basename10, dirname as dirname21, join as join37, relative as relative7, resolve as resolve13 } from "node:path";
|
|
44801
44902
|
function resourcePathOf(projectPath, absolute) {
|
|
44802
44903
|
const inside = relative7(onDiskSpelling(projectPath), onDiskSpelling(absolute));
|
|
@@ -44864,7 +44965,7 @@ async function renameSymbol(request, services) {
|
|
|
44864
44965
|
reason: `newScriptPath must be a .gd path inside the project, and ${request.newScriptPath} is not.`
|
|
44865
44966
|
};
|
|
44866
44967
|
}
|
|
44867
|
-
if (
|
|
44968
|
+
if (existsSync30(request.newScriptPath)) {
|
|
44868
44969
|
return { ok: false, reason: `${moveTo} already exists, so the script cannot be moved there.` };
|
|
44869
44970
|
}
|
|
44870
44971
|
}
|
|
@@ -45041,7 +45142,7 @@ async function renameSymbol(request, services) {
|
|
|
45041
45142
|
scripts,
|
|
45042
45143
|
moves: new Map([[declaringPath, moveTo]]),
|
|
45043
45144
|
named: [declaringPath],
|
|
45044
|
-
exists: (path) =>
|
|
45145
|
+
exists: (path) => existsSync30(`${projectPath}/${path.slice("res://".length)}`)
|
|
45045
45146
|
}, plan);
|
|
45046
45147
|
}
|
|
45047
45148
|
plan = mentionIgnored(plan, ignoredTexts(projectPath), symbol, moveTo === null ? [] : [declaringPath]);
|
|
@@ -45316,7 +45417,7 @@ var init_rename_symbol = __esm(() => {
|
|
|
45316
45417
|
|
|
45317
45418
|
// src/file-move.ts
|
|
45318
45419
|
import {
|
|
45319
|
-
existsSync as
|
|
45420
|
+
existsSync as existsSync31,
|
|
45320
45421
|
mkdirSync as mkdirSync18,
|
|
45321
45422
|
readdirSync as readdirSync18,
|
|
45322
45423
|
readFileSync as readFileSync36,
|
|
@@ -45349,7 +45450,7 @@ function unseenByTheEngine(projectPath, path) {
|
|
|
45349
45450
|
}
|
|
45350
45451
|
if (at < steps.length - 1) {
|
|
45351
45452
|
directory = join38(directory, step);
|
|
45352
|
-
if (
|
|
45453
|
+
if (existsSync31(join38(directory, ".gdignore"))) {
|
|
45353
45454
|
return `${path} is under a directory holding a .gdignore, which the engine does not load`;
|
|
45354
45455
|
}
|
|
45355
45456
|
}
|
|
@@ -45361,12 +45462,12 @@ function installedAddonOf(projectPath, path) {
|
|
|
45361
45462
|
if (steps[0] !== "addons" || steps[1] === undefined) {
|
|
45362
45463
|
return null;
|
|
45363
45464
|
}
|
|
45364
|
-
return
|
|
45465
|
+
return existsSync31(join38(projectPath, "addons", steps[1], VERSION_MARKER)) ? `res://addons/${steps[1]}` : null;
|
|
45365
45466
|
}
|
|
45366
45467
|
function binaryResources(projectPath) {
|
|
45367
45468
|
const found = [];
|
|
45368
45469
|
const visit = (directory, prefix) => {
|
|
45369
|
-
if (
|
|
45470
|
+
if (existsSync31(join38(directory, ".gdignore"))) {
|
|
45370
45471
|
return;
|
|
45371
45472
|
}
|
|
45372
45473
|
for (const entry of readdirSync18(directory, { withFileTypes: true })) {
|
|
@@ -45403,7 +45504,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
45403
45504
|
if (to === null) {
|
|
45404
45505
|
return { ok: false, reason: `newPath must be a path inside the project, and ${absoluteTo} is not.` };
|
|
45405
45506
|
}
|
|
45406
|
-
if (!
|
|
45507
|
+
if (!existsSync31(absoluteFrom)) {
|
|
45407
45508
|
return { ok: false, reason: `There is nothing at ${from} to move.` };
|
|
45408
45509
|
}
|
|
45409
45510
|
if (from === to) {
|
|
@@ -45432,7 +45533,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
45432
45533
|
if (isDirectory && to.startsWith(`${from}/`)) {
|
|
45433
45534
|
return { ok: false, reason: `${from} cannot be moved into itself.` };
|
|
45434
45535
|
}
|
|
45435
|
-
if (
|
|
45536
|
+
if (existsSync31(absoluteTo) && !sameFile(absoluteFrom, absoluteTo)) {
|
|
45436
45537
|
return { ok: false, reason: `${to} already exists, so nothing was moved there.` };
|
|
45437
45538
|
}
|
|
45438
45539
|
const unseen = unseenByTheEngine(projectPath, to);
|
|
@@ -45440,7 +45541,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
45440
45541
|
return { ok: false, reason: `${unseen}, so nothing there could load what was moved.` };
|
|
45441
45542
|
}
|
|
45442
45543
|
if (!isDirectory) {
|
|
45443
|
-
const owner = SIDECARS.map((sidecar) => from.endsWith(sidecar) ? from.slice(0, -sidecar.length) : null).find((path) => path !== null &&
|
|
45544
|
+
const owner = SIDECARS.map((sidecar) => from.endsWith(sidecar) ? from.slice(0, -sidecar.length) : null).find((path) => path !== null && existsSync31(join38(projectPath, path.slice("res://".length))));
|
|
45444
45545
|
if (owner !== undefined && owner !== null) {
|
|
45445
45546
|
return { ok: false, reason: `${from} belongs to ${owner} and moves with it: move ${owner} instead.` };
|
|
45446
45547
|
}
|
|
@@ -45462,7 +45563,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
45462
45563
|
} else {
|
|
45463
45564
|
moves.set(from, to);
|
|
45464
45565
|
for (const sidecar of SIDECARS) {
|
|
45465
|
-
if (
|
|
45566
|
+
if (existsSync31(`${absoluteFrom}${sidecar}`)) {
|
|
45466
45567
|
moves.set(`${from}${sidecar}`, `${to}${sidecar}`);
|
|
45467
45568
|
}
|
|
45468
45569
|
}
|
|
@@ -45474,7 +45575,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
45474
45575
|
scripts,
|
|
45475
45576
|
moves,
|
|
45476
45577
|
named: [from],
|
|
45477
|
-
exists: (path) =>
|
|
45578
|
+
exists: (path) => existsSync31(join38(projectPath, path.slice("res://".length)))
|
|
45478
45579
|
}, { edits: [], mentions: [] });
|
|
45479
45580
|
plan = mentionIgnored(plan, ignoredTexts(projectPath), null, [from]);
|
|
45480
45581
|
const binaries = [];
|
|
@@ -45545,13 +45646,13 @@ function applyFileMove(outcome) {
|
|
|
45545
45646
|
}
|
|
45546
45647
|
}
|
|
45547
45648
|
for (const file of outcome.moved) {
|
|
45548
|
-
if (!
|
|
45649
|
+
if (!existsSync31(file.absoluteFrom)) {
|
|
45549
45650
|
throw new Error(`${file.from} is gone from disk; nothing was written`);
|
|
45550
45651
|
}
|
|
45551
45652
|
if (file.text !== null && readFileSync36(file.absoluteFrom, "utf8") !== file.text.before) {
|
|
45552
45653
|
throw new Error(`${file.from} changed on disk while the move was being worked out; nothing was written`);
|
|
45553
45654
|
}
|
|
45554
|
-
if (
|
|
45655
|
+
if (existsSync31(file.absoluteTo) && !sameFile(file.absoluteFrom, file.absoluteTo)) {
|
|
45555
45656
|
throw new Error(`${file.to} already exists; nothing was written`);
|
|
45556
45657
|
}
|
|
45557
45658
|
}
|
|
@@ -50277,10 +50378,10 @@ var init_server_instructions = __esm(() => {
|
|
|
50277
50378
|
});
|
|
50278
50379
|
|
|
50279
50380
|
// src/suites-scene.ts
|
|
50280
|
-
import { existsSync as
|
|
50381
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync22, writeFileSync as writeFileSync22 } from "node:fs";
|
|
50281
50382
|
import { join as join42, relative as relative9, sep as sep5 } from "node:path";
|
|
50282
50383
|
function hasSuitesScene(projectPath) {
|
|
50283
|
-
return
|
|
50384
|
+
return existsSync32(join42(projectPath, SUITES_SCENE));
|
|
50284
50385
|
}
|
|
50285
50386
|
function suitesSceneArgs(projectPath, suites) {
|
|
50286
50387
|
const runs = join42(projectPath, ".godot", "gdharness", "suite-scenes");
|
|
@@ -50315,7 +50416,7 @@ var init_suites_scene = __esm(() => {
|
|
|
50315
50416
|
});
|
|
50316
50417
|
|
|
50317
50418
|
// src/test-selection.ts
|
|
50318
|
-
import { existsSync as
|
|
50419
|
+
import { existsSync as existsSync33 } from "node:fs";
|
|
50319
50420
|
import { basename as basename13, join as join43 } from "node:path";
|
|
50320
50421
|
function casesOutOfPath(projectPath, given, tests) {
|
|
50321
50422
|
const entries = Array.isArray(given) ? given : [given];
|
|
@@ -50360,12 +50461,12 @@ function casesIn(scripts, suite) {
|
|
|
50360
50461
|
}
|
|
50361
50462
|
function scriptsWithoutCases(projectPath, asked) {
|
|
50362
50463
|
const scripts = new ProjectScripts(projectPath);
|
|
50363
|
-
return asked.filter((path) => path.endsWith(".gd") &&
|
|
50464
|
+
return asked.filter((path) => path.endsWith(".gd") && existsSync33(join43(projectPath, path.slice("res://".length))) && casesIn(scripts, path).length === 0);
|
|
50364
50465
|
}
|
|
50365
50466
|
function suitesUnder(projectPath, asked) {
|
|
50366
50467
|
const scripts = projectFiles(projectPath, [".gd"]).map((path) => `res://${path}`);
|
|
50367
50468
|
return [
|
|
50368
|
-
...new Set(asked.flatMap((path) => path.endsWith(".gd") ?
|
|
50469
|
+
...new Set(asked.flatMap((path) => path.endsWith(".gd") ? existsSync33(join43(projectPath, path.slice("res://".length))) ? [path] : [] : scripts.filter((script) => script.startsWith(`${path}/`))))
|
|
50369
50470
|
];
|
|
50370
50471
|
}
|
|
50371
50472
|
function selectTests(projectPath, asked, given) {
|
|
@@ -50431,7 +50532,7 @@ import {
|
|
|
50431
50532
|
closeSync as closeSync6,
|
|
50432
50533
|
constants,
|
|
50433
50534
|
copyFileSync as copyFileSync2,
|
|
50434
|
-
existsSync as
|
|
50535
|
+
existsSync as existsSync34,
|
|
50435
50536
|
fstatSync as fstatSync3,
|
|
50436
50537
|
mkdirSync as mkdirSync23,
|
|
50437
50538
|
openSync as openSync7,
|
|
@@ -50444,7 +50545,7 @@ import {
|
|
|
50444
50545
|
writeFileSync as writeFileSync23
|
|
50445
50546
|
} from "node:fs";
|
|
50446
50547
|
import { basename as basename14, dirname as dirname25, extname as extname6, isAbsolute as isAbsolute8, join as join44, normalize as normalize2, relative as relative10 } from "node:path";
|
|
50447
|
-
import { setTimeout as
|
|
50548
|
+
import { setTimeout as delay8 } from "node:timers/promises";
|
|
50448
50549
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
50449
50550
|
function editorRestartTimeoutMs() {
|
|
50450
50551
|
return waitFromEnv("GDHARNESS_EDITOR_RESTART_TIMEOUT_MS", 90000);
|
|
@@ -50459,7 +50560,7 @@ function greetingWaitMs() {
|
|
|
50459
50560
|
function pictureToSend(pngPath, jpegPath) {
|
|
50460
50561
|
const png = readFileSync40(pngPath);
|
|
50461
50562
|
const beside = pngPath.replace(/\.png$/, ".jpg");
|
|
50462
|
-
const jpeg = jpegPath !== undefined && normalize2(jpegPath) === normalize2(beside) &&
|
|
50563
|
+
const jpeg = jpegPath !== undefined && normalize2(jpegPath) === normalize2(beside) && existsSync34(beside) ? readFileSync40(beside) : null;
|
|
50463
50564
|
const sent = jpeg !== null && jpeg.length < png.length ? jpeg : png;
|
|
50464
50565
|
return {
|
|
50465
50566
|
data: sent.toString("base64"),
|
|
@@ -50499,7 +50600,7 @@ function writtenFileRefusal(path, rule) {
|
|
|
50499
50600
|
return `${named} ${path} does not end in ${rule.extensions.join(" or ")}, which is what ${what} is.`;
|
|
50500
50601
|
}
|
|
50501
50602
|
const directory = realAsFarAsItExists(dirname25(path));
|
|
50502
|
-
if (!
|
|
50603
|
+
if (!existsSync34(directory)) {
|
|
50503
50604
|
return `${named}'s directory ${dirname25(path)} does not exist; ${what} creates no directories.`;
|
|
50504
50605
|
}
|
|
50505
50606
|
const where = join44(directory, basename14(path));
|
|
@@ -50507,7 +50608,7 @@ function writtenFileRefusal(path, rule) {
|
|
|
50507
50608
|
if (inside !== undefined) {
|
|
50508
50609
|
return `${named} ${path} is inside the project at ${inside}; ${what} is saved outside it, so it never becomes part of the game.`;
|
|
50509
50610
|
}
|
|
50510
|
-
const taken = rule.writes(where).find((file) =>
|
|
50611
|
+
const taken = rule.writes(where).find((file) => existsSync34(file));
|
|
50511
50612
|
if (taken !== undefined) {
|
|
50512
50613
|
return taken === where ? `${named} ${path} already exists; ${what} is not written over a file. Name a new one.` : `${named} ${path} would write ${taken}, which already exists; ${what} is not written over a file. Name a new one.`;
|
|
50513
50614
|
}
|
|
@@ -50731,7 +50832,7 @@ async function untilGone(pids, withinMs = stopWaitMs()) {
|
|
|
50731
50832
|
const gone = () => pids.every((pid) => !alive(pid));
|
|
50732
50833
|
const deadline = Date.now() + withinMs;
|
|
50733
50834
|
while (!gone() && Date.now() < deadline) {
|
|
50734
|
-
await
|
|
50835
|
+
await delay8(50);
|
|
50735
50836
|
}
|
|
50736
50837
|
return gone();
|
|
50737
50838
|
}
|
|
@@ -51293,7 +51394,7 @@ function unsavedInEditorNote(scripts) {
|
|
|
51293
51394
|
return `${named} ${one ? "is" : "are"} open in the editor's script ${one ? "tab" : "tabs"} with unsaved edits, and saving ${one ? "that tab" : "them"} there writes ${one ? "its" : "their"} text over what was written here: close ${one ? "it" : "them"} without saving, or save first and edit again.`;
|
|
51294
51395
|
}
|
|
51295
51396
|
function editorAddonMissing(projectPath) {
|
|
51296
|
-
if (!
|
|
51397
|
+
if (!existsSync34(join44(projectPath, "project.godot"))) {
|
|
51297
51398
|
return null;
|
|
51298
51399
|
}
|
|
51299
51400
|
const report = inspectProject(projectPath);
|
|
@@ -51837,7 +51938,7 @@ function uncaughtNote(uncaught) {
|
|
|
51837
51938
|
}
|
|
51838
51939
|
function elsewhereIn(projectPath, asked) {
|
|
51839
51940
|
const wanted = asked.replace(/^res:\/\//, "").replace(/\/+$/, "");
|
|
51840
|
-
if (wanted === "" ||
|
|
51941
|
+
if (wanted === "" || existsSync34(join44(projectPath, wanted))) {
|
|
51841
51942
|
return "";
|
|
51842
51943
|
}
|
|
51843
51944
|
const root = (wanted.split("/")[0] ?? "").toLowerCase();
|
|
@@ -51860,7 +51961,7 @@ function windowNoteFor(needing, sharing) {
|
|
|
51860
51961
|
return `${named(needing)} ${one ? "needs" : "need"} a window, as gdharness test reads ${one ? "it" : "them"}, so the run had one: the engine ran without --headless, at the size project.godot gives its viewport, with no sound${process.platform === "win32" ? ", on a desktop of its own, where its window neither shows nor takes the keyboard" : ""}. ${why}${shared}`;
|
|
51861
51962
|
}
|
|
51862
51963
|
function testPathsIn(projectPath, given, named = "path") {
|
|
51863
|
-
const defaults = TEST_DIRECTORIES.filter((directory) =>
|
|
51964
|
+
const defaults = TEST_DIRECTORIES.filter((directory) => existsSync34(join44(projectPath, directory)));
|
|
51864
51965
|
const entries = given === undefined || given === null || given === "" ? defaults.length > 0 ? defaults : TEST_DIRECTORIES : given;
|
|
51865
51966
|
const listed = Array.isArray(entries) ? entries : [entries];
|
|
51866
51967
|
if (listed.length === 0) {
|
|
@@ -52147,7 +52248,7 @@ class GodotServer {
|
|
|
52147
52248
|
taken = true;
|
|
52148
52249
|
this.logDebug(`Took port ${wanted} over from pid ${announced.pid}`);
|
|
52149
52250
|
} catch {
|
|
52150
|
-
await
|
|
52251
|
+
await delay8(HANDOVER_POLL_MS);
|
|
52151
52252
|
}
|
|
52152
52253
|
}
|
|
52153
52254
|
this.notHandedOverBy = taken ? null : announced.pid;
|
|
@@ -52285,7 +52386,7 @@ class GodotServer {
|
|
|
52285
52386
|
argv: process.argv.slice(1),
|
|
52286
52387
|
cwd,
|
|
52287
52388
|
project: this.ownProject,
|
|
52288
|
-
mcpJson:
|
|
52389
|
+
mcpJson: existsSync34(mcpJson) ? mcpJson : null
|
|
52289
52390
|
});
|
|
52290
52391
|
if (predecessor !== null) {
|
|
52291
52392
|
writeLifecycle("replaced", { project: this.ownProject, predecessor });
|
|
@@ -52427,7 +52528,7 @@ class GodotServer {
|
|
|
52427
52528
|
return checked.response;
|
|
52428
52529
|
}
|
|
52429
52530
|
const named = args["projectPath"];
|
|
52430
|
-
if (typeof named === "string" &&
|
|
52531
|
+
if (typeof named === "string" && existsSync34(join44(named, "project.godot"))) {
|
|
52431
52532
|
this.lastProjectPath = named;
|
|
52432
52533
|
}
|
|
52433
52534
|
this.updates.refresh();
|
|
@@ -53063,7 +53164,7 @@ class GodotServer {
|
|
|
53063
53164
|
return this.createErrorResponse("line is required: the one-based line to stop on.");
|
|
53064
53165
|
}
|
|
53065
53166
|
if (op === "set") {
|
|
53066
|
-
if (!
|
|
53167
|
+
if (!existsSync34(located.absolutePath)) {
|
|
53067
53168
|
return this.missingScript(project.value.path, located.relativePath);
|
|
53068
53169
|
}
|
|
53069
53170
|
const nothing = lineNothingStopsOn(located.absolutePath, located.relativePath, line);
|
|
@@ -53168,7 +53269,7 @@ class GodotServer {
|
|
|
53168
53269
|
return { ok: false, response: this.createErrorResponse("projectPath is required.") };
|
|
53169
53270
|
}
|
|
53170
53271
|
const file = join44(path, "project.godot");
|
|
53171
|
-
if (!
|
|
53272
|
+
if (!existsSync34(file)) {
|
|
53172
53273
|
return {
|
|
53173
53274
|
ok: false,
|
|
53174
53275
|
response: this.createErrorResponse(`Not a Godot project: ${path}`, [
|
|
@@ -53994,7 +54095,7 @@ class GodotServer {
|
|
|
53994
54095
|
if (place !== null && !place.ok) {
|
|
53995
54096
|
return this.createErrorResponse(place.reason);
|
|
53996
54097
|
}
|
|
53997
|
-
if (place !== null && !
|
|
54098
|
+
if (place !== null && !existsSync34(place.absolutePath)) {
|
|
53998
54099
|
const folders = readdirSync20(project.value.path, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name).sort();
|
|
53999
54100
|
return this.createErrorResponse(`There is nothing at res://${place.relativePath} to search.${folders.length === 0 ? "" : ` The project's folders are ${folders.join(", ")}.`}`);
|
|
54000
54101
|
}
|
|
@@ -54185,7 +54286,7 @@ ${platform}`;
|
|
|
54185
54286
|
output.absolutePath
|
|
54186
54287
|
];
|
|
54187
54288
|
this.logDebug(`Exporting: ${engine.value} ${exportArgs.join(" ")}`);
|
|
54188
|
-
const writtenAt = () =>
|
|
54289
|
+
const writtenAt = () => existsSync34(output.absolutePath) ? statSync20(output.absolutePath).mtimeMs : null;
|
|
54189
54290
|
const caches = editorCacheDirectory(engine.value);
|
|
54190
54291
|
const exportOnce = async () => {
|
|
54191
54292
|
const before = writtenAt();
|
|
@@ -54215,7 +54316,7 @@ ${platform}`;
|
|
|
54215
54316
|
return this.createErrorResponse(`Export could not be run: ${ending.failure ?? "the engine gave no exit status"}`);
|
|
54216
54317
|
}
|
|
54217
54318
|
const beside = writtenBeside(listedBefore, filesIn(folder), basename14(output.absolutePath), dirname25(output.relativePath).replaceAll("\\", "/"));
|
|
54218
|
-
return exportAnswer(ending, { preset, outputPath: output.relativePath, debug, ...pack ? { pack } : {} }, before, writtenAt(), beside, docCacheNote,
|
|
54319
|
+
return exportAnswer(ending, { preset, outputPath: output.relativePath, debug, ...pack ? { pack } : {} }, before, writtenAt(), beside, docCacheNote, existsSync34(output.absolutePath) ? statSync20(output.absolutePath).size : null, importedFirstAnswer(imported));
|
|
54219
54320
|
}
|
|
54220
54321
|
reportTestProgress(log) {
|
|
54221
54322
|
const progress = callProgress();
|
|
@@ -54276,7 +54377,7 @@ ${platform}`;
|
|
|
54276
54377
|
if (movie !== null) {
|
|
54277
54378
|
return this.createErrorResponse(movie);
|
|
54278
54379
|
}
|
|
54279
|
-
const missing = paths.value.filter((path) => !
|
|
54380
|
+
const missing = paths.value.filter((path) => !existsSync34(join44(project.value.path, path.slice("res://".length))));
|
|
54280
54381
|
const projectScripts = new ProjectScripts(project.value.path);
|
|
54281
54382
|
const present = paths.value.filter((path) => !missing.includes(path));
|
|
54282
54383
|
const asked = projectScripts.searchedAsTold(present);
|
|
@@ -54468,7 +54569,7 @@ ${platform}`;
|
|
|
54468
54569
|
await untilGone([run.process.pid]);
|
|
54469
54570
|
}
|
|
54470
54571
|
await run.settled;
|
|
54471
|
-
const helperFailed = onDesktop ? helperFailure(helperFiles.error) ?? (
|
|
54572
|
+
const helperFailed = onDesktop ? helperFailure(helperFiles.error) ?? (existsSync34(helperFiles.pid) ? null : `it never started, and ${helperStep(helperFiles.step)}`) : null;
|
|
54472
54573
|
if (helperFailed !== null) {
|
|
54473
54574
|
discard(join44(project.value.path, ".godot", ...ours.split("/")), userData);
|
|
54474
54575
|
return this.createErrorResponse(`No tests ran: ${named(needing)} ${needing.length === 1 ? "needs" : "need"} a window, and the engine could not be started on a desktop of its own: ${helperFailed}`);
|
|
@@ -54484,10 +54585,10 @@ ${platform}`;
|
|
|
54484
54585
|
const reportsDir = join44(project.value.path, ".godot", ...ours.split("/"));
|
|
54485
54586
|
let report = null;
|
|
54486
54587
|
let reportProblem = null;
|
|
54487
|
-
const casePrinted = withNestedErrors(readRun(
|
|
54588
|
+
const casePrinted = withNestedErrors(readRun(existsSync34(engineLog) ? readFileSync40(engineLog, "utf8") : ""), run.log.all);
|
|
54488
54589
|
const declaredErrors = readExpected(expectedFile);
|
|
54489
54590
|
try {
|
|
54490
|
-
const written =
|
|
54591
|
+
const written = existsSync34(reportsDir) && notCompiled === null ? readdirSync20(reportsDir).filter((name) => name.startsWith("report_")).sort((a, b) => Number(a.slice("report_".length)) - Number(b.slice("report_".length))) : [];
|
|
54491
54592
|
const newest = written.at(-1);
|
|
54492
54593
|
if (newest !== undefined) {
|
|
54493
54594
|
report = parseJUnit(readFileSync40(join44(reportsDir, newest, "results.xml"), "utf8"));
|
|
@@ -54814,7 +54915,7 @@ ${error.text}`;
|
|
|
54814
54915
|
if (!location.ok) {
|
|
54815
54916
|
return this.createErrorResponse(location.reason, PATH_SOLUTIONS);
|
|
54816
54917
|
}
|
|
54817
|
-
if (!
|
|
54918
|
+
if (!existsSync34(location.absolutePath)) {
|
|
54818
54919
|
return this.missingScript(project.value.path, location.relativePath);
|
|
54819
54920
|
}
|
|
54820
54921
|
ignored = scriptsUnderGdignore(project.value.path, [location.relativePath]);
|
|
@@ -54904,7 +55005,7 @@ ${error.text}`;
|
|
|
54904
55005
|
const wanted = `res://${relativePath}`;
|
|
54905
55006
|
const folder = dirname25(relativePath.replaceAll("\\", "/"));
|
|
54906
55007
|
const inFolder = join44(projectPath, folder);
|
|
54907
|
-
const beside =
|
|
55008
|
+
const beside = existsSync34(inFolder) ? readdirSync20(inFolder, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => `res://${folder === "." ? "" : `${folder}/`}${entry.name}`) : [];
|
|
54908
55009
|
return this.createErrorResponse(withNearestFiles(`Script file does not exist: ${wanted}`, wanted, scripts, beside));
|
|
54909
55010
|
}
|
|
54910
55011
|
async compileScripts(projectPath, paths) {
|
|
@@ -55032,7 +55133,7 @@ ${error.text}`;
|
|
|
55032
55133
|
const cached = cachedClasses(projectPath);
|
|
55033
55134
|
const sourceOf = (resourcePath) => {
|
|
55034
55135
|
const contained = resolveWithinProject(projectPath, resourcePath);
|
|
55035
|
-
if (!contained.ok || !
|
|
55136
|
+
if (!contained.ok || !existsSync34(contained.absolutePath)) {
|
|
55036
55137
|
return null;
|
|
55037
55138
|
}
|
|
55038
55139
|
try {
|
|
@@ -55126,7 +55227,7 @@ ${error.text}`;
|
|
|
55126
55227
|
}
|
|
55127
55228
|
sourceOfClass(projectPath, resourcePath) {
|
|
55128
55229
|
const contained = resolveWithinProject(projectPath, resourcePath);
|
|
55129
|
-
if (!contained.ok || !
|
|
55230
|
+
if (!contained.ok || !existsSync34(contained.absolutePath)) {
|
|
55130
55231
|
return null;
|
|
55131
55232
|
}
|
|
55132
55233
|
try {
|
|
@@ -55428,7 +55529,7 @@ ${error.text}`;
|
|
|
55428
55529
|
try {
|
|
55429
55530
|
const askedAt = Date.now();
|
|
55430
55531
|
const asked = this.godotBridge.invokeTool("playing_status", {}, { counted: false });
|
|
55431
|
-
const answer = await Promise.race([asked,
|
|
55532
|
+
const answer = await Promise.race([asked, delay8(PLAYING_STATUS_MS).then(() => null)]);
|
|
55432
55533
|
if (answer === null) {
|
|
55433
55534
|
this.logDebug(`playing_status did not answer within ${PLAYING_STATUS_MS}ms`);
|
|
55434
55535
|
asked.then(() => {
|
|
@@ -55453,7 +55554,7 @@ ${error.text}`;
|
|
|
55453
55554
|
try {
|
|
55454
55555
|
const answer = await Promise.race([
|
|
55455
55556
|
this.godotBridge.invokeTool("scan_status", {}, { counted: false }),
|
|
55456
|
-
|
|
55557
|
+
delay8(PLAYING_STATUS_MS).then(() => null)
|
|
55457
55558
|
]);
|
|
55458
55559
|
if (answer === null) {
|
|
55459
55560
|
return null;
|
|
@@ -55595,7 +55696,7 @@ ${error.text}`;
|
|
|
55595
55696
|
if (answer.serversNote === undefined || adapterFailed || Date.now() >= deadline) {
|
|
55596
55697
|
return answer;
|
|
55597
55698
|
}
|
|
55598
|
-
await
|
|
55699
|
+
await delay8(500);
|
|
55599
55700
|
}
|
|
55600
55701
|
}
|
|
55601
55702
|
async rebindTheDebugAdapter(servers) {
|
|
@@ -55856,7 +55957,7 @@ ${error.text}`;
|
|
|
55856
55957
|
if (Date.now() >= deadline) {
|
|
55857
55958
|
return false;
|
|
55858
55959
|
}
|
|
55859
|
-
await
|
|
55960
|
+
await delay8(250);
|
|
55860
55961
|
}
|
|
55861
55962
|
}
|
|
55862
55963
|
async handleLaunchEditor(args) {
|
|
@@ -55994,7 +56095,7 @@ ${error.text}`;
|
|
|
55994
56095
|
if (!paths.ok) {
|
|
55995
56096
|
return refused(paths.reason, PATH_SOLUTIONS);
|
|
55996
56097
|
}
|
|
55997
|
-
const missing = paths.value.filter((path) => !
|
|
56098
|
+
const missing = paths.value.filter((path) => !existsSync34(join44(projectPath, path.slice("res://".length))));
|
|
55998
56099
|
if (missing.length > 0) {
|
|
55999
56100
|
return refused(`Nothing at ${missing.join(" and ")} in the project at ${projectPath}.`, PATH_SOLUTIONS);
|
|
56000
56101
|
}
|
|
@@ -56039,7 +56140,7 @@ ${error.text}`;
|
|
|
56039
56140
|
return this.createErrorResponse(sceneToRun.reason, PATH_SOLUTIONS);
|
|
56040
56141
|
}
|
|
56041
56142
|
const build = readNonEmptyString(args, "executable");
|
|
56042
|
-
if (build === undefined && sceneToRun?.ok && !
|
|
56143
|
+
if (build === undefined && sceneToRun?.ok && !existsSync34(sceneToRun.absolutePath)) {
|
|
56043
56144
|
return this.createErrorResponse(`No scene at res://${sceneToRun.relativePath} in the project at ${project.value.path}.`, PATH_SOLUTIONS);
|
|
56044
56145
|
}
|
|
56045
56146
|
const exported = build === undefined ? null : exportedBuild(project.value.path, build);
|
|
@@ -56167,7 +56268,7 @@ ${error.text}`;
|
|
|
56167
56268
|
}
|
|
56168
56269
|
async runtimeUp(projectPath, before, budget, withArgs) {
|
|
56169
56270
|
const budgetMs = budget.ms;
|
|
56170
|
-
if (!
|
|
56271
|
+
if (!existsSync34(join44(projectPath, RUNTIME_SCRIPT))) {
|
|
56171
56272
|
return runtimeVerdict(null, {
|
|
56172
56273
|
addon: false,
|
|
56173
56274
|
budgetMs,
|
|
@@ -56305,7 +56406,7 @@ ${error.text}`;
|
|
|
56305
56406
|
const sendingFrom = Date.now();
|
|
56306
56407
|
const breakpoints = await this.dapHoldingBreakpointsOf(projectPath).reapplyBreakpoints();
|
|
56307
56408
|
this.logDebug(`Breakpoints were sent again after ${Date.now() - sendingFrom}ms`);
|
|
56308
|
-
const slot = await slotForCall();
|
|
56409
|
+
const slot = await slotForCall(true);
|
|
56309
56410
|
if (profiled) {
|
|
56310
56411
|
const armed = await this.handleViaBridge("profile_start", {
|
|
56311
56412
|
arm: true,
|
|
@@ -56508,7 +56609,7 @@ ${error.text}`;
|
|
|
56508
56609
|
if (Date.now() >= deadline) {
|
|
56509
56610
|
return false;
|
|
56510
56611
|
}
|
|
56511
|
-
await
|
|
56612
|
+
await delay8(100);
|
|
56512
56613
|
}
|
|
56513
56614
|
}
|
|
56514
56615
|
async endActiveGame(reason, going, graceful) {
|
|
@@ -56673,6 +56774,7 @@ ${error.text}`;
|
|
|
56673
56774
|
try {
|
|
56674
56775
|
const run = this.spawnHeld(godotPath, cmdArgs, onTheSlot(env ?? process.env, held.lock), onDesktop);
|
|
56675
56776
|
run.settled.finally(held.release);
|
|
56777
|
+
slotEngineNamed(held.lock, run, onDesktop?.files.pid);
|
|
56676
56778
|
return run;
|
|
56677
56779
|
} catch (error) {
|
|
56678
56780
|
held.release();
|
|
@@ -56768,11 +56870,11 @@ ${error.text}`;
|
|
|
56768
56870
|
return Object.assign(started, { settled, stop });
|
|
56769
56871
|
}
|
|
56770
56872
|
async launchKeptGame(godotPath, cmdArgs, projectPath, env, desktop, profiled = false, debugged = true) {
|
|
56873
|
+
const slot = await slotForCall(true);
|
|
56771
56874
|
const startedAt = Date.now();
|
|
56772
56875
|
const transcript = openTranscript(startedAt);
|
|
56773
56876
|
closeSync6(transcript.fd);
|
|
56774
56877
|
const profile = profiled ? profilePath(startedAt) : undefined;
|
|
56775
|
-
const slot = await slotForCall();
|
|
56776
56878
|
const gameEnv = onTheSlot(profiled ? { ...env ?? process.env, [PROFILE_FROM_START]: "1" } : env ?? process.env, slot.lock);
|
|
56777
56879
|
let launched;
|
|
56778
56880
|
try {
|
|
@@ -57242,7 +57344,7 @@ ${error.text}`;
|
|
|
57242
57344
|
};
|
|
57243
57345
|
const going = await this.runStillGoing(run);
|
|
57244
57346
|
const projectPath = run.projectPath;
|
|
57245
|
-
const projectGone = projectPath !== null && !
|
|
57347
|
+
const projectGone = projectPath !== null && !existsSync34(join44(projectPath, "project.godot"));
|
|
57246
57348
|
if (projectGone && callersName !== undefined) {
|
|
57247
57349
|
return this.createErrorResponse(`callersOf reads the project's scripts, and the run's project at ${projectPath} has no project.godot any more.`, ["editor_run profile without callersOf answers with the profile itself"]);
|
|
57248
57350
|
}
|
|
@@ -57400,7 +57502,7 @@ ${error.text}`;
|
|
|
57400
57502
|
return true;
|
|
57401
57503
|
}
|
|
57402
57504
|
}
|
|
57403
|
-
await
|
|
57505
|
+
await delay8(100);
|
|
57404
57506
|
}
|
|
57405
57507
|
return false;
|
|
57406
57508
|
}
|
|
@@ -57415,14 +57517,33 @@ ${error.text}`;
|
|
|
57415
57517
|
return elsewhere;
|
|
57416
57518
|
}
|
|
57417
57519
|
const budgetMs = readPositiveNumber(args, "timeoutMs") ?? WAIT_FOR_RUN_MS;
|
|
57418
|
-
const
|
|
57520
|
+
const began = Date.now();
|
|
57521
|
+
const until = began + budgetMs;
|
|
57419
57522
|
const cancelled = callSignal();
|
|
57523
|
+
let held = false;
|
|
57524
|
+
let holdAsked = 0;
|
|
57420
57525
|
while (cancelled?.aborted !== true && await this.runStillGoing(run) && Date.now() < until) {
|
|
57421
57526
|
this.drainEditorOutput(run);
|
|
57422
57527
|
this.drainTranscript(run);
|
|
57423
|
-
|
|
57528
|
+
if (Date.now() - holdAsked >= HOLD_ASKED_EVERY_MS) {
|
|
57529
|
+
holdAsked = Date.now();
|
|
57530
|
+
if (await this.heldByItsDebugger(run)) {
|
|
57531
|
+
held = true;
|
|
57532
|
+
break;
|
|
57533
|
+
}
|
|
57534
|
+
}
|
|
57535
|
+
await delay8(RUN_POLL_MS);
|
|
57536
|
+
}
|
|
57537
|
+
if (!await this.runStillGoing(run)) {
|
|
57538
|
+
return await this.handleGetDebugOutput(args);
|
|
57424
57539
|
}
|
|
57425
|
-
return await this.handleGetDebugOutput(args,
|
|
57540
|
+
return await this.handleGetDebugOutput(args, held ? { heldAfterMs: Date.now() - began } : { ranOutMs: budgetMs });
|
|
57541
|
+
}
|
|
57542
|
+
async heldByItsDebugger(run) {
|
|
57543
|
+
if (!run.throughEditor) {
|
|
57544
|
+
return run.keeper !== undefined && await this.keptHold(run.keeper) !== null;
|
|
57545
|
+
}
|
|
57546
|
+
return this.dapClient?.holdIsKnown() === true && this.dapClient.whereItStopped() !== null;
|
|
57426
57547
|
}
|
|
57427
57548
|
async runStillGoing(run, editorSays) {
|
|
57428
57549
|
if (!run.throughEditor) {
|
|
@@ -57473,7 +57594,7 @@ ${error.text}`;
|
|
|
57473
57594
|
if (Date.now() >= until) {
|
|
57474
57595
|
return false;
|
|
57475
57596
|
}
|
|
57476
|
-
await
|
|
57597
|
+
await delay8(50);
|
|
57477
57598
|
}
|
|
57478
57599
|
}
|
|
57479
57600
|
async handleEditorConsole(args) {
|
|
@@ -57571,7 +57692,7 @@ ${error.text}`;
|
|
|
57571
57692
|
"editor_status names every game running on the machine under runtimes"
|
|
57572
57693
|
]);
|
|
57573
57694
|
}
|
|
57574
|
-
async handleGetDebugOutput(args,
|
|
57695
|
+
async handleGetDebugOutput(args, waited) {
|
|
57575
57696
|
if (readString(args, "op") === "editor") {
|
|
57576
57697
|
return this.handleEditorConsole(args);
|
|
57577
57698
|
}
|
|
@@ -57608,8 +57729,11 @@ ${error.text}`;
|
|
|
57608
57729
|
if (wanted && cpuSeconds === undefined && stillRunning(run)) {
|
|
57609
57730
|
notes.push(processToAsk === null ? "cpu was asked for and there is no process to ask: the editor is playing this run and holds it, and the game announced no runtime, so nothing here has its process id. A game with the runtime addon announces one; editor_run start without a connected editor, or with args, starts the game here instead and that run answers cpuSeconds either way." : "cpu was asked for and this platform would not say what the run has used.");
|
|
57610
57731
|
}
|
|
57611
|
-
if (
|
|
57612
|
-
notes.push(`The wait of ${
|
|
57732
|
+
if (waited !== undefined && "ranOutMs" in waited) {
|
|
57733
|
+
notes.push(`The wait of ${waited.ranOutMs}ms ran out and the run is still going, so this is what it had printed by then rather than everything it will print. editor_run wait again to keep waiting.`);
|
|
57734
|
+
}
|
|
57735
|
+
if (waited !== undefined && "heldAfterMs" in waited) {
|
|
57736
|
+
notes.push(`The wait answered after ${waited.heldAfterMs}ms because the game is held by its debugger, where heldAt says, and a held game does not end: debug_control continue lets it go, and editor_run wait then waits on.`);
|
|
57613
57737
|
}
|
|
57614
57738
|
const restarts = run.restartedFrom ?? [];
|
|
57615
57739
|
if (restarts.length > 0) {
|
|
@@ -57627,7 +57751,7 @@ ${error.text}`;
|
|
|
57627
57751
|
notes.push(endedWithoutACode({
|
|
57628
57752
|
throughEditor: run.throughEditor,
|
|
57629
57753
|
announced: announced !== undefined || run.announcedPid !== undefined,
|
|
57630
|
-
couldAnnounce: run.projectPath !== null &&
|
|
57754
|
+
couldAnnounce: run.projectPath !== null && existsSync34(join44(run.projectPath, RUNTIME_SCRIPT)),
|
|
57631
57755
|
endedHere: typeof run.endedHere === "string",
|
|
57632
57756
|
pickedUp: run.pickedUp === true
|
|
57633
57757
|
}));
|
|
@@ -58509,7 +58633,7 @@ ${error.text}`;
|
|
|
58509
58633
|
if (!scriptPath.ok) {
|
|
58510
58634
|
return this.createErrorResponse(scriptPath.reason);
|
|
58511
58635
|
}
|
|
58512
|
-
if (!
|
|
58636
|
+
if (!existsSync34(scriptPath.absolutePath)) {
|
|
58513
58637
|
return this.missingScript(projectPath, scriptPath.relativePath);
|
|
58514
58638
|
}
|
|
58515
58639
|
const asked = readNonEmptyString(args, "newScriptPath");
|
|
@@ -59153,7 +59277,7 @@ ${error.text}`;
|
|
|
59153
59277
|
async ownRunOnItsWay(projectPath, budgetMs) {
|
|
59154
59278
|
const run = await this.currentRun();
|
|
59155
59279
|
const project = projectPath ?? run?.projectPath ?? null;
|
|
59156
|
-
if (run === null || project === null || run.announcedPid !== undefined || run.projectPath !== null && !isSameDirectory(run.projectPath, project) || !
|
|
59280
|
+
if (run === null || project === null || run.announcedPid !== undefined || run.projectPath !== null && !isSameDirectory(run.projectPath, project) || !existsSync34(join44(project, RUNTIME_SCRIPT)) || !await this.runStillGoing(run)) {
|
|
59157
59281
|
return null;
|
|
59158
59282
|
}
|
|
59159
59283
|
const already = runtimesAnnounced().running;
|
|
@@ -59467,7 +59591,7 @@ async function runGodotServer() {
|
|
|
59467
59591
|
const server = new GodotServer;
|
|
59468
59592
|
await server.run();
|
|
59469
59593
|
}
|
|
59470
|
-
var TYPE_ARGUMENTS, UPDATE_NOTICE_EVERY = 500, FEEDBACK_NOTICE_EVERY = 250, FAILED_BUDGET = 1e6, ANSWER_BUDGET = 4000000, __dirname2, PARENT_ASKED_AFTER_MS = 5000, EDITOR_SERVERS_START_MS = 20000, HOLD_PING_MS = 2000, SLOWEST_FRAME_RATE = 20, ALONGSIDE_NOTE = "Another call on this game was running while this one was: calls sent together run together and are answered as each finishes, so this answer is not from after the other. Send a call meant to come after another once that one has answered.", OWN_DEBUGGER = " Its debugger is the keeper holding it rather than the editor, so the debug_* tools answer for it all the same: breakpoints stop it, and debug_control pause breaks into it wherever it is, which the editor offers no way to do.", PLAY_STARTS_WITHIN_MS = 30000, KEEPER_ANSWER_MS = 15000, KEEPER_DEBUG_MS, EXIT_REPORTED_WITHIN_MS = 2000, SUCCESSOR_SOUGHT_WITHIN_MS = 20000, CLOSE_ASK_MS = 3000, LONGEST_BOOT_NOTED_MS, PROFILE_SEND_MS = 5000, MOST_GROUPS = 20, RUNTIME_LISTENING_LINE = "[gdharness] runtime listening on ", VALUE_NAMES, BRIDGE_RETRY_MS = 2000, SUCCESSOR_CHECK_MS = 1e4, CONSOLE_WATCH_MS = 250, BOUNDARY_WAIT_MS = 2000, HANDOVER_MS, HANDOVER_POLL_MS = 250, CACHE_WRITE_MS = 2000, STREAMS_GRACE_MS = 2000, PLAYING_STATUS_MS = 1000, SCAN_SETTLED_MS = 500, SLOW_ANSWER_MS = 1000, REIMPORT_TIMEOUT_MS = 300000, OPS_ELSEWHERE, AUDIO_BUS_OPS, STALLED_AFTER_MS = 30000, TEST_TIMEOUT_MS = 600000, TEST_HEARTBEAT_MS = 20000, DEPENDED_FAILED = "Failed to compile depended scripts", LOOPING_AFTER = 100, WAIT_FOR_RUN_MS = 600000, RUN_POLL_MS = 250, PATH_SOLUTIONS, DESTINATION_ARGUMENTS, OUTPUT_PATH_SOLUTIONS, PROJECT_FILE_ARGUMENTS, DEBUG_STATE_CALLS, PROJECT_INFO_SECTIONS2, RUNNER_DIRECTORY = "addons/gdUnit4/", PROFILE_FUNCTIONS = 30, PROFILER_ON_MS = 3000, PROPERTY_PLACES = "It is a property, so each place says whether it writes it (access write), which runs its set block, or reads it (access read), which runs its get block: withinCalls on a read says nothing of the set block, nor on a write of the get block unless the write is a compound one such as +=. Inside the property's own blocks its name is the value stored, which the engine reads and writes without running them, so those lines are not listed.", CALLERS_FOUND_BY_NAME = "Found by name in the project's scripts, since the engine's profiler counts calls and time per function and records nothing about who made them: a method of the same name on another class is listed too, unless one class was asked about and it is called through another class by name or through a variable declared as one. Each place carries the profile's numbers for the function it is written in.", MOST_ENGINE_ENTRIES = 200, MOST_PRINTED_LINES = 50, MOST_UNDECLARED_ERRORS = 20, ERROR_ASSERT = "GdUnitGodotErrorAssertImpl.gd", RAISED_WARNING = " (Warning treated as error.)", PARSE_ERROR2 = "Parse Error: ", EXTERNAL_MEMBER = 'Could not resolve external class member "', STATIC_LIST_HINT;
|
|
59594
|
+
var TYPE_ARGUMENTS, UPDATE_NOTICE_EVERY = 500, FEEDBACK_NOTICE_EVERY = 250, FAILED_BUDGET = 1e6, ANSWER_BUDGET = 4000000, __dirname2, PARENT_ASKED_AFTER_MS = 5000, EDITOR_SERVERS_START_MS = 20000, HOLD_PING_MS = 2000, SLOWEST_FRAME_RATE = 20, ALONGSIDE_NOTE = "Another call on this game was running while this one was: calls sent together run together and are answered as each finishes, so this answer is not from after the other. Send a call meant to come after another once that one has answered.", OWN_DEBUGGER = " Its debugger is the keeper holding it rather than the editor, so the debug_* tools answer for it all the same: breakpoints stop it, and debug_control pause breaks into it wherever it is, which the editor offers no way to do.", PLAY_STARTS_WITHIN_MS = 30000, KEEPER_ANSWER_MS = 15000, KEEPER_DEBUG_MS, EXIT_REPORTED_WITHIN_MS = 2000, SUCCESSOR_SOUGHT_WITHIN_MS = 20000, CLOSE_ASK_MS = 3000, LONGEST_BOOT_NOTED_MS, PROFILE_SEND_MS = 5000, MOST_GROUPS = 20, RUNTIME_LISTENING_LINE = "[gdharness] runtime listening on ", VALUE_NAMES, BRIDGE_RETRY_MS = 2000, SUCCESSOR_CHECK_MS = 1e4, CONSOLE_WATCH_MS = 250, BOUNDARY_WAIT_MS = 2000, HANDOVER_MS, HANDOVER_POLL_MS = 250, CACHE_WRITE_MS = 2000, STREAMS_GRACE_MS = 2000, PLAYING_STATUS_MS = 1000, SCAN_SETTLED_MS = 500, SLOW_ANSWER_MS = 1000, REIMPORT_TIMEOUT_MS = 300000, OPS_ELSEWHERE, AUDIO_BUS_OPS, STALLED_AFTER_MS = 30000, TEST_TIMEOUT_MS = 600000, TEST_HEARTBEAT_MS = 20000, DEPENDED_FAILED = "Failed to compile depended scripts", LOOPING_AFTER = 100, WAIT_FOR_RUN_MS = 600000, RUN_POLL_MS = 250, HOLD_ASKED_EVERY_MS = 1000, PATH_SOLUTIONS, DESTINATION_ARGUMENTS, OUTPUT_PATH_SOLUTIONS, PROJECT_FILE_ARGUMENTS, DEBUG_STATE_CALLS, PROJECT_INFO_SECTIONS2, RUNNER_DIRECTORY = "addons/gdUnit4/", PROFILE_FUNCTIONS = 30, PROFILER_ON_MS = 3000, PROPERTY_PLACES = "It is a property, so each place says whether it writes it (access write), which runs its set block, or reads it (access read), which runs its get block: withinCalls on a read says nothing of the set block, nor on a write of the get block unless the write is a compound one such as +=. Inside the property's own blocks its name is the value stored, which the engine reads and writes without running them, so those lines are not listed.", CALLERS_FOUND_BY_NAME = "Found by name in the project's scripts, since the engine's profiler counts calls and time per function and records nothing about who made them: a method of the same name on another class is listed too, unless one class was asked about and it is called through another class by name or through a variable declared as one. Each place carries the profile's numbers for the function it is written in.", MOST_ENGINE_ENTRIES = 200, MOST_PRINTED_LINES = 50, MOST_UNDECLARED_ERRORS = 20, ERROR_ASSERT = "GdUnitGodotErrorAssertImpl.gd", RAISED_WARNING = " (Warning treated as error.)", PARSE_ERROR2 = "Parse Error: ", EXTERNAL_MEMBER = 'Could not resolve external class member "', STATIC_LIST_HINT;
|
|
59471
59595
|
var init_server = __esm(() => {
|
|
59472
59596
|
init_dist2();
|
|
59473
59597
|
init_stdio();
|
|
@@ -59606,7 +59730,7 @@ var init_server = __esm(() => {
|
|
|
59606
59730
|
init_bridge_announce();
|
|
59607
59731
|
init_engine_launch();
|
|
59608
59732
|
init_engine_slots();
|
|
59609
|
-
import { existsSync as
|
|
59733
|
+
import { existsSync as existsSync35 } from "node:fs";
|
|
59610
59734
|
import { dirname as dirname26, join as join45, resolve as resolve15 } from "node:path";
|
|
59611
59735
|
|
|
59612
59736
|
// src/error-mode.ts
|
|
@@ -59645,7 +59769,7 @@ init_alive();
|
|
|
59645
59769
|
init_engine_launch();
|
|
59646
59770
|
init_lsp_client();
|
|
59647
59771
|
init_process_children();
|
|
59648
|
-
import { existsSync as
|
|
59772
|
+
import { existsSync as existsSync17, readdirSync as readdirSync11, readFileSync as readFileSync19, unlinkSync as unlinkSync2 } from "node:fs";
|
|
59649
59773
|
import { connect as connect2 } from "node:net";
|
|
59650
59774
|
import { join as join21, resolve as resolve8 } from "node:path";
|
|
59651
59775
|
var EDITOR_RECORD_PROTOCOL = 1;
|
|
@@ -59757,7 +59881,7 @@ function lspOptionsOf(args, cwd) {
|
|
|
59757
59881
|
}
|
|
59758
59882
|
}
|
|
59759
59883
|
const projectPath = resolve8(cwd, named ?? ".");
|
|
59760
|
-
if (!
|
|
59884
|
+
if (!existsSync17(join21(projectPath, "project.godot"))) {
|
|
59761
59885
|
throw new EngineUsageError(`Not a Godot project: ${projectPath} holds no project.godot.`);
|
|
59762
59886
|
}
|
|
59763
59887
|
return { projectPath, port, waitSeconds };
|
|
@@ -59864,7 +59988,7 @@ init_setup();
|
|
|
59864
59988
|
init_setup();
|
|
59865
59989
|
init_tool_definitions();
|
|
59866
59990
|
init_tool_reference();
|
|
59867
|
-
import { existsSync as
|
|
59991
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync7, readdirSync as readdirSync13, rmSync as rmSync11, writeFileSync as writeFileSync12 } from "node:fs";
|
|
59868
59992
|
import { basename as basename9, dirname as dirname10, join as join23 } from "node:path";
|
|
59869
59993
|
var SKILL_NAME = "gdharness";
|
|
59870
59994
|
var SHARED_SKILLS = join23(".agents", "skills");
|
|
@@ -60136,7 +60260,7 @@ function everySkillDirectory(projectPath, harnesses) {
|
|
|
60136
60260
|
function removeSkill(directories, projectPath) {
|
|
60137
60261
|
const removed = [];
|
|
60138
60262
|
for (const directory of directories) {
|
|
60139
|
-
if (
|
|
60263
|
+
if (existsSync19(directory)) {
|
|
60140
60264
|
rmSync11(directory, { recursive: true, force: true });
|
|
60141
60265
|
pruneEmpty(dirname10(directory), projectPath);
|
|
60142
60266
|
removed.push(directory);
|
|
@@ -60158,7 +60282,7 @@ function pruneEmpty(directory, projectPath) {
|
|
|
60158
60282
|
function writeSkill(directories, version) {
|
|
60159
60283
|
const files = skillFiles(version);
|
|
60160
60284
|
return directories.map((directory) => {
|
|
60161
|
-
const replaced =
|
|
60285
|
+
const replaced = existsSync19(directory);
|
|
60162
60286
|
rmSync11(directory, { recursive: true, force: true });
|
|
60163
60287
|
for (const [name, contents] of files) {
|
|
60164
60288
|
const path = join23(directory, name);
|
|
@@ -60175,7 +60299,7 @@ init_engine_slots();
|
|
|
60175
60299
|
init_log_read();
|
|
60176
60300
|
init_setup();
|
|
60177
60301
|
init_suite_judge();
|
|
60178
|
-
import { existsSync as
|
|
60302
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync8, readFileSync as readFileSync22, rmSync as rmSync12 } from "node:fs";
|
|
60179
60303
|
import { availableParallelism as availableParallelism4 } from "node:os";
|
|
60180
60304
|
import { join as join24, resolve as resolve10 } from "node:path";
|
|
60181
60305
|
import process13 from "node:process";
|
|
@@ -60217,9 +60341,9 @@ function spreadOptionsOf(args, cwd) {
|
|
|
60217
60341
|
}
|
|
60218
60342
|
const first = positional[0];
|
|
60219
60343
|
const named = first === undefined ? null : resolve10(cwd, first);
|
|
60220
|
-
const projectNamed = named !== null &&
|
|
60344
|
+
const projectNamed = named !== null && existsSync20(join24(named, "project.godot"));
|
|
60221
60345
|
const projectPath = projectNamed ? named : resolve10(cwd);
|
|
60222
|
-
if (!
|
|
60346
|
+
if (!existsSync20(join24(projectPath, "project.godot"))) {
|
|
60223
60347
|
throw new EngineUsageError(`Not a Godot project: ${projectPath} holds no project.godot.`);
|
|
60224
60348
|
}
|
|
60225
60349
|
const scenes = positional.slice(projectNamed ? 1 : 0);
|
|
@@ -60227,7 +60351,7 @@ function spreadOptionsOf(args, cwd) {
|
|
|
60227
60351
|
throw new EngineUsageError(scenes.length === 0 ? "gdharness spread needs the scene of the bench to play." : `gdharness spread plays one scene, and was given ${String(scenes.length)}: ${scenes.join(", ")}.`);
|
|
60228
60352
|
}
|
|
60229
60353
|
const scene = resPathOf(scenes[0] ?? "", projectPath, cwd);
|
|
60230
|
-
if (!
|
|
60354
|
+
if (!existsSync20(join24(projectPath, scene.slice("res://".length)))) {
|
|
60231
60355
|
throw new EngineUsageError(`Nothing at ${scene} in the project at ${projectPath}.`);
|
|
60232
60356
|
}
|
|
60233
60357
|
const benchArguments = dashes === -1 ? [] : args.slice(dashes + 1);
|
|
@@ -60298,7 +60422,7 @@ function shareFaults(played) {
|
|
|
60298
60422
|
return faults;
|
|
60299
60423
|
}
|
|
60300
60424
|
async function runSpreadCommand(options, godotPath) {
|
|
60301
|
-
if (!
|
|
60425
|
+
if (!existsSync20(join24(options.projectPath, SHARE_SCRIPT))) {
|
|
60302
60426
|
throw new EngineUsageError(`res://${SHARE_SCRIPT} is not in the project, so its bench cannot ask GdhShare for outcomes. Run gdharness setup.`);
|
|
60303
60427
|
}
|
|
60304
60428
|
const startedAt = Date.now();
|
|
@@ -60363,7 +60487,7 @@ async function runSpreadCommand(options, godotPath) {
|
|
|
60363
60487
|
const faults = left.flatMap((worker) => engineFaults(worker, options.godotVersion));
|
|
60364
60488
|
const arms = left.map((_, index) => {
|
|
60365
60489
|
const file = join24(shareDirectory, `worker-${String(index)}.arms`);
|
|
60366
|
-
return
|
|
60490
|
+
return existsSync20(file) ? armsPlayed(readFileSync22(file, "utf8")) : [];
|
|
60367
60491
|
});
|
|
60368
60492
|
faults.push(...shareFaults(arms));
|
|
60369
60493
|
if (faults.length > 0) {
|
|
@@ -60373,7 +60497,7 @@ async function runSpreadCommand(options, godotPath) {
|
|
|
60373
60497
|
console.log(readLog(gather.log).replace(CONTROL_SEQUENCE, "").trimEnd());
|
|
60374
60498
|
const gatherFaults = engineFaults(gather, options.godotVersion);
|
|
60375
60499
|
const gatheredFile = join24(shareDirectory, "gathered.arms");
|
|
60376
|
-
const gathered = new Set((
|
|
60500
|
+
const gathered = new Set((existsSync20(gatheredFile) ? armsPlayed(readFileSync22(gatheredFile, "utf8")) ?? [] : []).map((arm) => arm.arm));
|
|
60377
60501
|
const ungathered = (arms[0] ?? []).filter((arm) => !gathered.has(arm.arm)).map((arm) => arm.arm);
|
|
60378
60502
|
if (ungathered.length > 0) {
|
|
60379
60503
|
gatherFaults.push(`the gathering run never asked for ${ungathered.join(", ")}, which the workers played: it went another way through the arms than they did`);
|
|
@@ -60424,7 +60548,7 @@ function engineFaults(engine, godotVersion) {
|
|
|
60424
60548
|
const said = code === null ? "without an exit code" : code >>> 0 >= WINDOWS_EXCEPTION2 ? exitNamed(code) : String(code);
|
|
60425
60549
|
faults.push(`${engine.name}: the engine exited ${said}`);
|
|
60426
60550
|
}
|
|
60427
|
-
if (!
|
|
60551
|
+
if (!existsSync20(engine.log)) {
|
|
60428
60552
|
return faults;
|
|
60429
60553
|
}
|
|
60430
60554
|
const printed = readRun(readLog(engine.log));
|
|
@@ -60440,7 +60564,7 @@ function engineFaults(engine, godotVersion) {
|
|
|
60440
60564
|
}
|
|
60441
60565
|
function progressOf(logs) {
|
|
60442
60566
|
const each = logs.map((log, index) => {
|
|
60443
|
-
const text =
|
|
60567
|
+
const text = existsSync20(log) ? readLog(log) : "";
|
|
60444
60568
|
const last = [...text.matchAll(PROGRESS)].at(-1);
|
|
60445
60569
|
return last === undefined ? `worker ${String(index)} has played no arm yet` : `worker ${String(index)} at ${last[1] ?? ""} ${last[2] ?? ""} of ${last[3] ?? ""}`;
|
|
60446
60570
|
});
|
|
@@ -60472,7 +60596,7 @@ init_reimport();
|
|
|
60472
60596
|
init_setup();
|
|
60473
60597
|
import {
|
|
60474
60598
|
copyFileSync,
|
|
60475
|
-
existsSync as
|
|
60599
|
+
existsSync as existsSync23,
|
|
60476
60600
|
mkdirSync as mkdirSync10,
|
|
60477
60601
|
readdirSync as readdirSync15,
|
|
60478
60602
|
readFileSync as readFileSync26,
|
|
@@ -60483,12 +60607,13 @@ import {
|
|
|
60483
60607
|
import { availableParallelism as availableParallelism5 } from "node:os";
|
|
60484
60608
|
import { dirname as dirname13, join as join28, relative as relative5, resolve as resolve11, sep as sep4 } from "node:path";
|
|
60485
60609
|
import process14 from "node:process";
|
|
60610
|
+
import { setTimeout as delay5 } from "node:timers/promises";
|
|
60486
60611
|
|
|
60487
60612
|
// src/suite-inputs.ts
|
|
60488
60613
|
init_class_cache();
|
|
60489
60614
|
init_gdscript_source();
|
|
60490
60615
|
import { createHash as createHash6 } from "node:crypto";
|
|
60491
|
-
import { existsSync as
|
|
60616
|
+
import { existsSync as existsSync21, readdirSync as readdirSync14, readFileSync as readFileSync23, statSync as statSync13 } from "node:fs";
|
|
60492
60617
|
import { join as join25, posix as posix2 } from "node:path";
|
|
60493
60618
|
var EVERY_FILE = "res://";
|
|
60494
60619
|
var CACHE_HELD = "cache:";
|
|
@@ -60506,7 +60631,7 @@ var ADDON = /^res:\/\/addons\/[^/]+\//;
|
|
|
60506
60631
|
var TEXT_RESOURCE = /\.(?:tscn|tres|gdextension)$/;
|
|
60507
60632
|
function reachedBySuite(file) {
|
|
60508
60633
|
const bySuite = new Map;
|
|
60509
|
-
if (!
|
|
60634
|
+
if (!existsSync21(file)) {
|
|
60510
60635
|
return bySuite;
|
|
60511
60636
|
}
|
|
60512
60637
|
const paths = (value) => Array.isArray(value) ? value.filter((path) => typeof path === "string") : [];
|
|
@@ -60616,7 +60741,7 @@ ${this.read(path).digest}
|
|
|
60616
60741
|
const hash = createHash6("sha256");
|
|
60617
60742
|
let modified = 0;
|
|
60618
60743
|
const directory = join25(this.scripts.projectPath, root.slice("res://".length));
|
|
60619
|
-
if (
|
|
60744
|
+
if (existsSync21(directory)) {
|
|
60620
60745
|
walkSeen(directory, (file, under, stat) => {
|
|
60621
60746
|
hash.update(`${under}
|
|
60622
60747
|
`).update(readFileSync23(file));
|
|
@@ -60627,7 +60752,7 @@ ${this.read(path).digest}
|
|
|
60627
60752
|
}
|
|
60628
60753
|
readAnew(path) {
|
|
60629
60754
|
const file = join25(this.scripts.projectPath, path.slice("res://".length));
|
|
60630
|
-
if (!
|
|
60755
|
+
if (!existsSync21(file)) {
|
|
60631
60756
|
return { digest: "missing", follows: [], also: [], modified: 0 };
|
|
60632
60757
|
}
|
|
60633
60758
|
const stat = statSync13(file);
|
|
@@ -60638,12 +60763,12 @@ ${this.read(path).digest}
|
|
|
60638
60763
|
}
|
|
60639
60764
|
const bytes = readFileSync23(file);
|
|
60640
60765
|
const digest = createHash6("sha256").update(bytes).digest("hex");
|
|
60641
|
-
const also = [`${path}.import`, `${path}.uid`].filter((beside) =>
|
|
60766
|
+
const also = [`${path}.import`, `${path}.uid`].filter((beside) => existsSync21(join25(this.scripts.projectPath, beside.slice("res://".length))));
|
|
60642
60767
|
const follows = [];
|
|
60643
60768
|
if (TEXT_RESOURCE.test(path)) {
|
|
60644
60769
|
for (const [named] of bytes.toString("latin1").matchAll(RES_LITERAL)) {
|
|
60645
60770
|
const target = join25(this.scripts.projectPath, named.slice("res://".length));
|
|
60646
|
-
(
|
|
60771
|
+
(existsSync21(target) && statSync13(target).isDirectory() ? also : follows).push(named);
|
|
60647
60772
|
}
|
|
60648
60773
|
} else if (path.endsWith(".gd")) {
|
|
60649
60774
|
const reaches = this.scriptReaches(path);
|
|
@@ -60830,7 +60955,7 @@ function joinedString(expression, named) {
|
|
|
60830
60955
|
}
|
|
60831
60956
|
function walkSeen(root, seen) {
|
|
60832
60957
|
const walk = (directory, under) => {
|
|
60833
|
-
if (
|
|
60958
|
+
if (existsSync21(join25(directory, ".gdignore"))) {
|
|
60834
60959
|
return;
|
|
60835
60960
|
}
|
|
60836
60961
|
for (const entry of readdirSync14(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
@@ -60848,7 +60973,7 @@ function walkSeen(root, seen) {
|
|
|
60848
60973
|
}
|
|
60849
60974
|
function extensionsOf(projectPath) {
|
|
60850
60975
|
const list = join25(projectPath, ".godot", "extension_list.cfg");
|
|
60851
|
-
return
|
|
60976
|
+
return existsSync21(list) ? readFileSync23(list, "utf8").split(`
|
|
60852
60977
|
`).map((line) => line.trim()).filter((line) => line.startsWith("res://")) : [];
|
|
60853
60978
|
}
|
|
60854
60979
|
|
|
@@ -60879,6 +61004,7 @@ function getLocalVersion() {
|
|
|
60879
61004
|
|
|
60880
61005
|
// src/suite-run.ts
|
|
60881
61006
|
var LAST_RUN_FILE = "last-run.json";
|
|
61007
|
+
var COMPILED_FILE = "compiled-together.json";
|
|
60882
61008
|
var SLOWEST_NAMED = 5;
|
|
60883
61009
|
var SILENCE_TIMES_TAKEN = 4;
|
|
60884
61010
|
function silenceWhile(running, times, floorSeconds) {
|
|
@@ -60936,9 +61062,9 @@ function testOptionsOf(args, cwd) {
|
|
|
60936
61062
|
}
|
|
60937
61063
|
const first = positional[0];
|
|
60938
61064
|
const named = first === undefined ? null : resolve11(cwd, first);
|
|
60939
|
-
const projectNamed = named !== null &&
|
|
61065
|
+
const projectNamed = named !== null && existsSync23(join28(named, "project.godot"));
|
|
60940
61066
|
const projectPath = projectNamed ? named : resolve11(cwd);
|
|
60941
|
-
if (!
|
|
61067
|
+
if (!existsSync23(join28(projectPath, "project.godot"))) {
|
|
60942
61068
|
throw new EngineUsageError(`Not a Godot project: ${projectPath} holds no project.godot.`);
|
|
60943
61069
|
}
|
|
60944
61070
|
const last = (flag) => valued.get(flag)?.at(-1);
|
|
@@ -60973,12 +61099,12 @@ function seedOf(value) {
|
|
|
60973
61099
|
return seed;
|
|
60974
61100
|
}
|
|
60975
61101
|
function rootsOf(options) {
|
|
60976
|
-
return options.roots.length > 0 ? options.roots : TEST_DIRECTORIES.filter((root) =>
|
|
61102
|
+
return options.roots.length > 0 ? options.roots : TEST_DIRECTORIES.filter((root) => existsSync23(join28(options.projectPath, root))).map((root) => `res://${root}`);
|
|
60977
61103
|
}
|
|
60978
61104
|
function searchedRoots(options) {
|
|
60979
61105
|
return options.selected.length === 0 ? rootsOf(options) : options.selected.filter((entry) => {
|
|
60980
61106
|
const directory = join28(options.projectPath, entry.slice("res://".length));
|
|
60981
|
-
return
|
|
61107
|
+
return existsSync23(directory) && statSync14(directory).isDirectory();
|
|
60982
61108
|
});
|
|
60983
61109
|
}
|
|
60984
61110
|
function selectedSuites(scripts, options) {
|
|
@@ -60995,9 +61121,9 @@ function selectedSuites(scripts, options) {
|
|
|
60995
61121
|
const caseAt = /^(res:\/\/.*\.gd):(\w+)$/.exec(entry);
|
|
60996
61122
|
const path = caseAt?.[1] ?? entry;
|
|
60997
61123
|
const directory = join28(options.projectPath, path.slice(6));
|
|
60998
|
-
const suites =
|
|
61124
|
+
const suites = existsSync23(directory) && statSync14(directory).isDirectory() ? scripts.suitesUnder([path.replace(/\/$/, "")]) : [scripts.suite(path)].filter((suite) => suite !== null);
|
|
60999
61125
|
if (suites.length === 0) {
|
|
61000
|
-
throw new EngineUsageError(
|
|
61126
|
+
throw new EngineUsageError(existsSync23(directory) ? `${path} holds no gdUnit4 suite: nothing there extends GdUnitTestSuite and declares a test_ function.` : `Nothing at ${path} in the project at ${options.projectPath}.`);
|
|
61001
61127
|
}
|
|
61002
61128
|
for (const suite of suites) {
|
|
61003
61129
|
const picked = chosen.get(suite.path) ?? { suite, cases: new Set };
|
|
@@ -61121,11 +61247,11 @@ async function runTestCommand(options, godotPath) {
|
|
|
61121
61247
|
failsOnPushErrors: gdUnitFailsOnPushErrors(options.projectPath)
|
|
61122
61248
|
};
|
|
61123
61249
|
try {
|
|
61124
|
-
const
|
|
61125
|
-
if (
|
|
61126
|
-
console.log(
|
|
61250
|
+
const needed = options.importFirst ? null : importNeeded(options.projectPath);
|
|
61251
|
+
if (needed !== null) {
|
|
61252
|
+
console.log(needed);
|
|
61127
61253
|
}
|
|
61128
|
-
if (options.importFirst ||
|
|
61254
|
+
if (options.importFirst || needed !== null) {
|
|
61129
61255
|
const imported = await importProject(launch);
|
|
61130
61256
|
if (imported !== null) {
|
|
61131
61257
|
logs.keep();
|
|
@@ -61140,9 +61266,10 @@ async function runTestCommand(options, godotPath) {
|
|
|
61140
61266
|
readFileSync26(shippedListedRunner(), "utf8"),
|
|
61141
61267
|
engineSaid(godotPath),
|
|
61142
61268
|
...options.reachAlso.map((path) => `${path}
|
|
61143
|
-
${
|
|
61269
|
+
${existsSync23(path) ? readFileSync26(path, "latin1") : "missing"}`)
|
|
61144
61270
|
];
|
|
61145
61271
|
const everySuite = suites;
|
|
61272
|
+
const compileKept = options.changedOnly ? { file: join28(state, COMPILED_FILE), scripts, always } : null;
|
|
61146
61273
|
if (options.changedOnly) {
|
|
61147
61274
|
const inputs = new SuiteInputs(scripts, always);
|
|
61148
61275
|
const passedBefore = readPassed(passedFile);
|
|
@@ -61156,7 +61283,7 @@ ${existsSync24(path) ? readFileSync26(path, "latin1") : "missing"}`)
|
|
|
61156
61283
|
}
|
|
61157
61284
|
if (suites.length === 0) {
|
|
61158
61285
|
console.log("Nothing has changed since every suite last passed.");
|
|
61159
|
-
const compiled = await
|
|
61286
|
+
const compiled = await compileUnlessUnchanged(launch, everySuite, compileKept);
|
|
61160
61287
|
const problems = [...compiled.faults.map((fault) => `${COMPILE_CHECK}: ${fault}`), ...uncollected];
|
|
61161
61288
|
if (problems.length === 0) {
|
|
61162
61289
|
rmSync13(runDirectory, { recursive: true, force: true });
|
|
@@ -61179,12 +61306,18 @@ ${existsSync24(path) ? readFileSync26(path, "latin1") : "missing"}`)
|
|
|
61179
61306
|
if (memory.unread !== undefined) {
|
|
61180
61307
|
console.log(`Windows did not say how much memory it can still commit (${memory.unread}), so engines are sized by the physical memory free.`);
|
|
61181
61308
|
}
|
|
61182
|
-
const
|
|
61309
|
+
const roomWith = (bytes) => options.cores === null ? roomFor(options.engines, availableParallelism5(), bytes, memory.said) : roomFor(options.engines, options.cores, bytes, memory.said, `--cores holds it to ${plural(options.cores, "processor")}`);
|
|
61310
|
+
const byMemory = roomWith(memory.bytes);
|
|
61311
|
+
const unheld = roomWith(Number.POSITIVE_INFINITY);
|
|
61312
|
+
const unheldUnits = unitsOf(suites, times, splitPastFor(suites, times, unheld.engines));
|
|
61313
|
+
const heldLanes = lanesOf(dealt(unheldUnits, declared, unheld.engines));
|
|
61314
|
+
const memoryHeld = options.order === null && byMemory.engines < heldLanes;
|
|
61315
|
+
const room = memoryHeld ? unheld : byMemory;
|
|
61183
61316
|
if (options.cores !== null && process14.platform === "darwin") {
|
|
61184
61317
|
console.log("macOS offers no way to hold a process to some processors, so --cores holds only the number of engines here.");
|
|
61185
61318
|
}
|
|
61186
61319
|
const splitPast = splitPastFor(suites, times, room.engines);
|
|
61187
|
-
const units = unitsOf(suites, times, splitPast);
|
|
61320
|
+
const units = memoryHeld ? unheldUnits : unitsOf(suites, times, splitPast);
|
|
61188
61321
|
const past = splitPast > SPLIT_PAST_SECONDS ? `an engine's share of this run (${String(Math.round(splitPast))} s)` : `${String(SPLIT_PAST_SECONDS)} s`;
|
|
61189
61322
|
const plans = options.order === null ? dealt(units, declared, room.engines) : [inOneEngine(ordered(units, options.order), declared)];
|
|
61190
61323
|
const functions = suites.reduce((sum, suite) => sum + suite.cases.length, 0);
|
|
@@ -61217,24 +61350,28 @@ ${existsSync24(path) ? readFileSync26(path, "latin1") : "missing"}`)
|
|
|
61217
61350
|
say(`Kept whole in one engine, since ${one ? "it declares" : "each declares"} GDHARNESS_TOGETHER: ${named(keptWhole)}.`);
|
|
61218
61351
|
}
|
|
61219
61352
|
const lanes = [...new Set(plans.map((plan) => plan.lane))].map((lane) => plans.flatMap((plan, index) => plan.lane === lane ? [{ plan, index }] : []));
|
|
61353
|
+
const startable = memoryHeld ? Math.min(byMemory.engines, lanes.length) : lanes.length;
|
|
61220
61354
|
const taken = [];
|
|
61221
|
-
while (taken.length <
|
|
61355
|
+
while (taken.length < startable) {
|
|
61222
61356
|
const lock = await slots.takeFree();
|
|
61223
61357
|
if (lock === null) {
|
|
61224
61358
|
break;
|
|
61225
61359
|
}
|
|
61226
61360
|
taken.push(lock);
|
|
61227
61361
|
}
|
|
61228
|
-
|
|
61229
|
-
|
|
61230
|
-
|
|
61362
|
+
if (memoryHeld) {
|
|
61363
|
+
say(memorySaid(byMemory.engines, lanes.length, byMemory.held ?? ""));
|
|
61364
|
+
}
|
|
61365
|
+
const shared = options.order === null && lanes.length > 1 && (memoryHeld || taken.length < lanes.length);
|
|
61366
|
+
if (shared && taken.length < startable) {
|
|
61367
|
+
say(sharesSaid(taken.length, startable));
|
|
61231
61368
|
}
|
|
61232
61369
|
const handed = new HandedSlot;
|
|
61233
|
-
const compiling =
|
|
61370
|
+
const compiling = compileUnlessUnchanged(launch, everySuite, compileKept, handed);
|
|
61234
61371
|
compiling.catch(() => {
|
|
61235
61372
|
return;
|
|
61236
61373
|
});
|
|
61237
|
-
let ran = shared ? await runShares(launch, units, declared, lanes.length, taken, times, handed) : (await Promise.all(lanes.map((lane, at) => runLane(launch, lane, times, taken[at] ?? null, handed)))).flat().sort((a, b) => a.index - b.index);
|
|
61374
|
+
let ran = shared ? await runShares(launch, units, declared, lanes.length, taken, times, handed, memoryHeld ? new MemoryGate(slots, async () => (await memoryAvailable()).bytes) : undefined) : (await Promise.all(lanes.map((lane, at) => runLane(launch, lane, times, taken[at] ?? null, handed)))).flat().sort((a, b) => a.index - b.index);
|
|
61238
61375
|
if (ran.some((engine) => engine.verdict.starved) && ran.some((engine) => !engine.verdict.passed)) {
|
|
61239
61376
|
say("An engine ran out of memory, so every engine that failed runs again, one at a time.");
|
|
61240
61377
|
const again = [];
|
|
@@ -61261,6 +61398,55 @@ ${existsSync24(path) ? readFileSync26(path, "latin1") : "missing"}`)
|
|
|
61261
61398
|
function sharesSaid(free, lanes) {
|
|
61262
61399
|
return `${free === 0 ? "None" : String(free)} of the ${String(lanes)} slots this run uses ${free === 1 ? "was" : "were"} free as it began, so its engines are handed the suites a share at a time as each starts, and an engine starts as each slot comes free.`;
|
|
61263
61400
|
}
|
|
61401
|
+
function memorySaid(room, lanes, held) {
|
|
61402
|
+
return `Memory had room for ${room === 1 ? "one" : String(room)} of these ${String(lanes)} engines at once as the run began, since ${held}, so its engines are handed the suites a share at a time, and another starts whenever memory has room for it.`;
|
|
61403
|
+
}
|
|
61404
|
+
var MEMORY_LOOK_MS = 2000;
|
|
61405
|
+
var ENGINE_SETTLING_MS = 30000;
|
|
61406
|
+
|
|
61407
|
+
class MemoryGate {
|
|
61408
|
+
slots;
|
|
61409
|
+
read;
|
|
61410
|
+
now;
|
|
61411
|
+
lookMs;
|
|
61412
|
+
going = new Set;
|
|
61413
|
+
turn = Promise.resolve();
|
|
61414
|
+
constructor(slots, read, now = Date.now, lookMs = MEMORY_LOOK_MS) {
|
|
61415
|
+
this.slots = slots;
|
|
61416
|
+
this.read = read;
|
|
61417
|
+
this.now = now;
|
|
61418
|
+
this.lookMs = lookMs;
|
|
61419
|
+
}
|
|
61420
|
+
admit(signal) {
|
|
61421
|
+
const admitted = this.turn.then(() => this.room(signal));
|
|
61422
|
+
this.turn = admitted.catch(() => {
|
|
61423
|
+
return;
|
|
61424
|
+
});
|
|
61425
|
+
return admitted;
|
|
61426
|
+
}
|
|
61427
|
+
async room(signal) {
|
|
61428
|
+
let unmark;
|
|
61429
|
+
try {
|
|
61430
|
+
for (;; ) {
|
|
61431
|
+
signal.throwIfAborted();
|
|
61432
|
+
const at = this.now();
|
|
61433
|
+
const starting = [...this.going].filter((one) => at - one.at < ENGINE_SETTLING_MS).length;
|
|
61434
|
+
if (this.going.size === 0 || roomForAnother(await this.read(), starting)) {
|
|
61435
|
+
break;
|
|
61436
|
+
}
|
|
61437
|
+
unmark ??= this.slots.markWaiting();
|
|
61438
|
+
await delay5(this.lookMs, undefined, { signal });
|
|
61439
|
+
}
|
|
61440
|
+
} finally {
|
|
61441
|
+
unmark?.();
|
|
61442
|
+
}
|
|
61443
|
+
const engine = { at: this.now() };
|
|
61444
|
+
this.going.add(engine);
|
|
61445
|
+
return () => {
|
|
61446
|
+
this.going.delete(engine);
|
|
61447
|
+
};
|
|
61448
|
+
}
|
|
61449
|
+
}
|
|
61264
61450
|
function roomSaid(engines, lanes, unheld, held, asked) {
|
|
61265
61451
|
if (held === undefined || lanes >= unheld) {
|
|
61266
61452
|
return "";
|
|
@@ -61286,7 +61472,7 @@ function readPassed(file) {
|
|
|
61286
61472
|
function recordPassed(file, projectPath, ran, failedAcross, inputs, began) {
|
|
61287
61473
|
const passed = readPassed(file);
|
|
61288
61474
|
for (const path of Object.keys(passed)) {
|
|
61289
|
-
if (!
|
|
61475
|
+
if (!existsSync23(join28(projectPath, path.slice("res://".length)))) {
|
|
61290
61476
|
delete passed[path];
|
|
61291
61477
|
}
|
|
61292
61478
|
}
|
|
@@ -61335,6 +61521,9 @@ class HandedSlot {
|
|
|
61335
61521
|
lock = new Promise((resolve) => {
|
|
61336
61522
|
this.handOver = resolve;
|
|
61337
61523
|
});
|
|
61524
|
+
decline() {
|
|
61525
|
+
this.wanted = false;
|
|
61526
|
+
}
|
|
61338
61527
|
give(lock) {
|
|
61339
61528
|
if (!this.wanted) {
|
|
61340
61529
|
return false;
|
|
@@ -61388,6 +61577,41 @@ async function compileCheck(launch, suites, handed) {
|
|
|
61388
61577
|
}
|
|
61389
61578
|
return { faults: judgeCompile(readRun(readFileSync26(log, "utf8")), end), log };
|
|
61390
61579
|
}
|
|
61580
|
+
function compiledPrint(kept, projectPath, suites) {
|
|
61581
|
+
const inputs = new SuiteInputs(kept.scripts, kept.always);
|
|
61582
|
+
const classes = [...cachedClasses(projectPath)?.values() ?? []];
|
|
61583
|
+
const read = inputs.inputsOf([...suites.map((suite) => suite.path), ...classes]);
|
|
61584
|
+
return { inputs, read, print: inputs.printOf(read) };
|
|
61585
|
+
}
|
|
61586
|
+
async function compileUnlessUnchanged(launch, suites, kept, handed) {
|
|
61587
|
+
if (kept === null) {
|
|
61588
|
+
return compileCheck(launch, suites, handed);
|
|
61589
|
+
}
|
|
61590
|
+
const before = compiledPrint(kept, launch.projectPath, suites).print;
|
|
61591
|
+
if (readKeptPrint(kept.file) === before) {
|
|
61592
|
+
handed?.decline();
|
|
61593
|
+
console.log("Every script compiled together on these same files when last checked, so it is not compiled again.");
|
|
61594
|
+
return { faults: [], log: "" };
|
|
61595
|
+
}
|
|
61596
|
+
const began = Date.now();
|
|
61597
|
+
const compiled = await compileCheck(launch, suites, handed);
|
|
61598
|
+
const after = compiledPrint(kept, launch.projectPath, suites);
|
|
61599
|
+
if (compiled.faults.length === 0 && !after.inputs.modifiedAfter(after.read, began)) {
|
|
61600
|
+
writeJson(kept.file, { print: after.print });
|
|
61601
|
+
} else {
|
|
61602
|
+
rmSync13(kept.file, { force: true });
|
|
61603
|
+
}
|
|
61604
|
+
return compiled;
|
|
61605
|
+
}
|
|
61606
|
+
function readKeptPrint(file) {
|
|
61607
|
+
try {
|
|
61608
|
+
const parsed = JSON.parse(readFileSync26(file, "utf8"));
|
|
61609
|
+
const print = parsed?.print;
|
|
61610
|
+
return typeof print === "string" ? print : null;
|
|
61611
|
+
} catch {
|
|
61612
|
+
return null;
|
|
61613
|
+
}
|
|
61614
|
+
}
|
|
61391
61615
|
function printCompiled(compiled, logs) {
|
|
61392
61616
|
if (compiled.faults.length === 0) {
|
|
61393
61617
|
return;
|
|
@@ -61412,6 +61636,21 @@ function importFault(printed) {
|
|
|
61412
61636
|
].join(" and ");
|
|
61413
61637
|
return `it printed ${counted}, the first ${first.warning ? "warning" : "error"} ${JSON.stringify(first.text)}`;
|
|
61414
61638
|
}
|
|
61639
|
+
function importNeeded(projectPath) {
|
|
61640
|
+
const cached = cachedClasses(projectPath);
|
|
61641
|
+
if (cached === null) {
|
|
61642
|
+
return "The project has never been imported, so it is imported first.";
|
|
61643
|
+
}
|
|
61644
|
+
const unlisted = unlistedExtensions(projectPath);
|
|
61645
|
+
if (unlisted.length > 0) {
|
|
61646
|
+
return `No import has listed the project's extensions, ${named(unlisted)}, so the engine would load none of them, and the project is imported first.`;
|
|
61647
|
+
}
|
|
61648
|
+
const uncached = staleAgainst(cached, projectPath).sort();
|
|
61649
|
+
if (uncached.length > 0) {
|
|
61650
|
+
return `The class cache does not list ${named(uncached)} where the scripts declare ${uncached.length === 1 ? "it" : "them"}, so the project is imported first.`;
|
|
61651
|
+
}
|
|
61652
|
+
return null;
|
|
61653
|
+
}
|
|
61415
61654
|
async function importProject(launch) {
|
|
61416
61655
|
const seeded = seedExtensionList(launch.projectPath);
|
|
61417
61656
|
if (seeded !== null && seeded.length > 0) {
|
|
@@ -61459,35 +61698,48 @@ async function runLane(launch, lane, times, taken, handed) {
|
|
|
61459
61698
|
doneWith(launch, lock, handed);
|
|
61460
61699
|
}
|
|
61461
61700
|
}
|
|
61462
|
-
async function runShares(launch, units, declared, lanes, taken, times, handed) {
|
|
61701
|
+
async function runShares(launch, units, declared, lanes, taken, times, handed, memory) {
|
|
61463
61702
|
const shares = new Shares(units, declared, lanes);
|
|
61464
61703
|
const handedOut = new AbortController;
|
|
61465
61704
|
let engines = 0;
|
|
61705
|
+
const empty = () => shares.empty;
|
|
61466
61706
|
const lane = async (at) => {
|
|
61467
61707
|
let lock = taken[at] ?? null;
|
|
61468
|
-
|
|
61469
|
-
try {
|
|
61470
|
-
lock = await launch.slots.take(handedOut.signal);
|
|
61471
|
-
} catch (error) {
|
|
61472
|
-
if (handedOut.signal.aborted) {
|
|
61473
|
-
return [];
|
|
61474
|
-
}
|
|
61475
|
-
throw error;
|
|
61476
|
-
}
|
|
61477
|
-
}
|
|
61708
|
+
const ran = [];
|
|
61478
61709
|
try {
|
|
61479
|
-
|
|
61480
|
-
|
|
61481
|
-
|
|
61710
|
+
while (!empty()) {
|
|
61711
|
+
let ended;
|
|
61712
|
+
try {
|
|
61713
|
+
ended = await memory?.admit(handedOut.signal);
|
|
61714
|
+
lock ??= await launch.slots.take(handedOut.signal);
|
|
61715
|
+
} catch (error) {
|
|
61716
|
+
ended?.();
|
|
61717
|
+
if (handedOut.signal.aborted) {
|
|
61718
|
+
break;
|
|
61719
|
+
}
|
|
61720
|
+
throw error;
|
|
61721
|
+
}
|
|
61722
|
+
const plan = shares.next(at);
|
|
61723
|
+
if (plan === null) {
|
|
61724
|
+
ended?.();
|
|
61725
|
+
break;
|
|
61726
|
+
}
|
|
61727
|
+
if (empty()) {
|
|
61482
61728
|
handedOut.abort();
|
|
61483
61729
|
}
|
|
61484
61730
|
const index = engines;
|
|
61485
61731
|
engines += 1;
|
|
61486
|
-
|
|
61732
|
+
try {
|
|
61733
|
+
ran.push(await runEngine2(launch, plan, index, times, "", lock));
|
|
61734
|
+
} finally {
|
|
61735
|
+
ended?.();
|
|
61736
|
+
}
|
|
61487
61737
|
}
|
|
61488
61738
|
return ran;
|
|
61489
61739
|
} finally {
|
|
61490
|
-
|
|
61740
|
+
if (lock !== null) {
|
|
61741
|
+
doneWith(launch, lock, handed);
|
|
61742
|
+
}
|
|
61491
61743
|
}
|
|
61492
61744
|
};
|
|
61493
61745
|
return (await Promise.all(Array.from({ length: lanes }, (_, at) => lane(at)))).flat().sort((a, b) => a.index - b.index);
|
|
@@ -61582,7 +61834,7 @@ async function runEngine2(launch, plan, index, times, again = "", slot = null) {
|
|
|
61582
61834
|
}
|
|
61583
61835
|
var REPORT_FILES_NAMED = 3;
|
|
61584
61836
|
function reportsFault(reports) {
|
|
61585
|
-
const files =
|
|
61837
|
+
const files = existsSync23(reports) ? readdirSync15(reports, { recursive: true, encoding: "utf8" }).filter((file) => statSync14(join28(reports, file)).isFile()).sort() : [];
|
|
61586
61838
|
if (files.length === 0) {
|
|
61587
61839
|
return null;
|
|
61588
61840
|
}
|
|
@@ -61595,7 +61847,7 @@ function report(ran, compiled, across, uncollected, startedAt, logs, printOutput
|
|
|
61595
61847
|
for (const engine of ran) {
|
|
61596
61848
|
console.log("");
|
|
61597
61849
|
console.log(`--- what engine ${String(engine.index)} printed, running ${named(engine.plan.suites.map((suite) => suite.path))}:`);
|
|
61598
|
-
console.log(
|
|
61850
|
+
console.log(existsSync23(engine.log) ? readLog(engine.log).replace(CONTROL_SEQUENCE, "").trimEnd() : "(no log was written)");
|
|
61599
61851
|
}
|
|
61600
61852
|
}
|
|
61601
61853
|
const failed = ran.filter((engine) => !engine.verdict.passed);
|
|
@@ -61606,7 +61858,7 @@ function report(ran, compiled, across, uncollected, startedAt, logs, printOutput
|
|
|
61606
61858
|
for (const fault of engine.verdict.faults) {
|
|
61607
61859
|
console.log(` ${fault}`);
|
|
61608
61860
|
}
|
|
61609
|
-
if (
|
|
61861
|
+
if (existsSync23(engine.log)) {
|
|
61610
61862
|
const verdict = [
|
|
61611
61863
|
`gdharness: ${heading.slice(4)}`,
|
|
61612
61864
|
...engine.verdict.faults.map((fault) => ` ${fault}`)
|
|
@@ -61701,6 +61953,9 @@ function report(ran, compiled, across, uncollected, startedAt, logs, printOutput
|
|
|
61701
61953
|
const problems = failed.reduce((sum, engine) => sum + engine.verdict.faults.length, compiled.faults.length + across.length + uncollected.length);
|
|
61702
61954
|
console.log(`Failed: ${plural(problems, "problem")}, listed above. Ran ${totals}`);
|
|
61703
61955
|
console.log(`Every engine's output is kept under ${logs.shown} until ${String(KEPT_RUN_DIRECTORIES)} later runs have failed.`);
|
|
61956
|
+
if (logs.shown !== logs.directory) {
|
|
61957
|
+
console.log(`That is a copy beside the main checkout. The run wrote them under ${logs.directory} in this worktree, and they go with it when the worktree is removed.`);
|
|
61958
|
+
}
|
|
61704
61959
|
return 1;
|
|
61705
61960
|
}
|
|
61706
61961
|
function writeEarlyResult(targets, startedAt, problems, logs) {
|
|
@@ -61742,7 +61997,7 @@ class UsageError extends Refusal {
|
|
|
61742
61997
|
function projectArgument(at) {
|
|
61743
61998
|
const named = args.slice(at).find((value) => !value.startsWith("--"));
|
|
61744
61999
|
const projectPath = resolve15(named ?? ".");
|
|
61745
|
-
if (!
|
|
62000
|
+
if (!existsSync35(join45(projectPath, "project.godot"))) {
|
|
61746
62001
|
throw new UsageError(`Not a Godot project: ${projectPath} holds no project.godot.`);
|
|
61747
62002
|
}
|
|
61748
62003
|
return projectPath;
|
|
@@ -61806,7 +62061,7 @@ async function registerRuntime(godot, projectPath) {
|
|
|
61806
62061
|
}
|
|
61807
62062
|
const path = (named ?? "").replace(/^res:\/\//, "");
|
|
61808
62063
|
console.log(`${RUNTIME_AUTOLOAD.name} autoload left at ${named}, which this project registers itself`);
|
|
61809
|
-
if (!
|
|
62064
|
+
if (!existsSync35(join45(projectPath, path))) {
|
|
61810
62065
|
console.log(" that file is not in this project, so it boots with a missing script");
|
|
61811
62066
|
}
|
|
61812
62067
|
console.log(` ${useTheShippedLoader(RUNTIME_AUTOLOAD.name, path)}`);
|
|
@@ -61939,7 +62194,7 @@ async function setup() {
|
|
|
61939
62194
|
console.log("no harness configured; name one yourself, and gdharness harnesses lists them all");
|
|
61940
62195
|
}
|
|
61941
62196
|
if (!args.includes("--no-skill")) {
|
|
61942
|
-
const directories = skillDirectories(chosen.harnesses, projectPath,
|
|
62197
|
+
const directories = skillDirectories(chosen.harnesses, projectPath, existsSync35);
|
|
61943
62198
|
for (const written of writeSkill(directories, getLocalVersion())) {
|
|
61944
62199
|
console.log(`skill: ${written.replaced ? "replaced" : "written"} ${written.path}`);
|
|
61945
62200
|
}
|
|
@@ -62059,7 +62314,7 @@ async function upgrade() {
|
|
|
62059
62314
|
moved.push(took.from);
|
|
62060
62315
|
}
|
|
62061
62316
|
}
|
|
62062
|
-
for (const written of writeSkill(skillDirectories(already, projectPath,
|
|
62317
|
+
for (const written of writeSkill(skillDirectories(already, projectPath, existsSync35), version)) {
|
|
62063
62318
|
console.log(`skill: ${written.replaced ? "replaced" : "written"} ${written.path}`);
|
|
62064
62319
|
}
|
|
62065
62320
|
console.log(`
|