gdharness 1.3.55 → 1.3.56
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,10 +1779,7 @@ 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;
|
|
@@ -1852,11 +1854,16 @@ function holderOf(content) {
|
|
|
1852
1854
|
if (typeof parsed !== "object" || parsed === null) {
|
|
1853
1855
|
return null;
|
|
1854
1856
|
}
|
|
1855
|
-
const { pid, started, by } = parsed;
|
|
1857
|
+
const { pid, started, by, game } = parsed;
|
|
1856
1858
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || typeof started !== "number") {
|
|
1857
1859
|
return null;
|
|
1858
1860
|
}
|
|
1859
|
-
return
|
|
1861
|
+
return {
|
|
1862
|
+
pid,
|
|
1863
|
+
started,
|
|
1864
|
+
...typeof by === "string" && by !== "" ? { by } : {},
|
|
1865
|
+
...game === true ? { game } : {}
|
|
1866
|
+
};
|
|
1860
1867
|
} catch {
|
|
1861
1868
|
return null;
|
|
1862
1869
|
}
|
|
@@ -1897,7 +1904,7 @@ class EngineSlots {
|
|
|
1897
1904
|
this.taker = taker;
|
|
1898
1905
|
this.drawn = slotsDrawnOn(count, taker(), "none");
|
|
1899
1906
|
}
|
|
1900
|
-
async take(signal, waiting, blocked) {
|
|
1907
|
+
async take(signal, waiting, blocked, game = false) {
|
|
1901
1908
|
mkdirSync2(this.directory, { recursive: true });
|
|
1902
1909
|
const began = Date.now();
|
|
1903
1910
|
let said = Number.NEGATIVE_INFINITY;
|
|
@@ -1906,7 +1913,7 @@ class EngineSlots {
|
|
|
1906
1913
|
try {
|
|
1907
1914
|
for (;; ) {
|
|
1908
1915
|
signal?.throwIfAborted();
|
|
1909
|
-
const lock = await this.takeFree();
|
|
1916
|
+
const lock = await this.takeFree(game);
|
|
1910
1917
|
if (lock !== null) {
|
|
1911
1918
|
return lock;
|
|
1912
1919
|
}
|
|
@@ -1938,7 +1945,7 @@ class EngineSlots {
|
|
|
1938
1945
|
}
|
|
1939
1946
|
}
|
|
1940
1947
|
}
|
|
1941
|
-
async takeFree() {
|
|
1948
|
+
async takeFree(game = false) {
|
|
1942
1949
|
mkdirSync2(this.directory, { recursive: true });
|
|
1943
1950
|
await this.sweep();
|
|
1944
1951
|
const inherited = this.inherited === null ? await this.inheritedLock() : null;
|
|
@@ -1948,9 +1955,18 @@ class EngineSlots {
|
|
|
1948
1955
|
}
|
|
1949
1956
|
const taker = this.taker();
|
|
1950
1957
|
this.drawn = slotsDrawnOn(this.count, taker, taker === "gate" || taker === "timing" ? "none" : await this.gateQueue());
|
|
1958
|
+
if (game && this.drawn.limit === "kept") {
|
|
1959
|
+
const share = slotsDrawnOn(this.count, "tier", "queued").numbers;
|
|
1960
|
+
const games = await this.heldByGames(share);
|
|
1961
|
+
if (games.length >= gamesKeptOf(share.length)) {
|
|
1962
|
+
this.drawn = { numbers: games, limit: "games" };
|
|
1963
|
+
return null;
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
const holder = game ? { ...this.holder, game: true } : this.holder;
|
|
1951
1967
|
for (const slot of this.drawn.numbers) {
|
|
1952
1968
|
const lock = join5(this.directory, `${String(slot)}.lock`);
|
|
1953
|
-
if (this.made(lock) || await this.takenOver(lock)) {
|
|
1969
|
+
if (this.made(lock, holder) || await this.takenOver(lock, holder)) {
|
|
1954
1970
|
this.held.add(lock);
|
|
1955
1971
|
return lock;
|
|
1956
1972
|
}
|
|
@@ -1967,6 +1983,14 @@ class EngineSlots {
|
|
|
1967
1983
|
const tree = await processTree();
|
|
1968
1984
|
return tree !== undefined && inheritsSlot(tree, process4.pid, holder.pid, basename3(process4.execPath)) ? lock : null;
|
|
1969
1985
|
}
|
|
1986
|
+
markWaiting() {
|
|
1987
|
+
const mark = this.waitMarked();
|
|
1988
|
+
return () => {
|
|
1989
|
+
if (mark !== undefined && this.marks.delete(mark)) {
|
|
1990
|
+
removeWhole(mark);
|
|
1991
|
+
}
|
|
1992
|
+
};
|
|
1993
|
+
}
|
|
1970
1994
|
waitMarked() {
|
|
1971
1995
|
const marks = join5(this.directory, WAITING_FOLDER);
|
|
1972
1996
|
waitsMarked += 1;
|
|
@@ -1982,6 +2006,17 @@ class EngineSlots {
|
|
|
1982
2006
|
this.marks.add(mark);
|
|
1983
2007
|
return mark;
|
|
1984
2008
|
}
|
|
2009
|
+
async heldByGames(numbers) {
|
|
2010
|
+
const games = [];
|
|
2011
|
+
for (const slot of numbers) {
|
|
2012
|
+
const lock = join5(this.directory, `${String(slot)}.lock`);
|
|
2013
|
+
const content = readWhole(lock);
|
|
2014
|
+
if (content !== null && holderOf(content)?.game === true && !await this.free(lock)) {
|
|
2015
|
+
games.push(slot);
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
return games;
|
|
2019
|
+
}
|
|
1985
2020
|
async gateQueue() {
|
|
1986
2021
|
const marks = join5(this.directory, QUEUED_FOLDER);
|
|
1987
2022
|
let names;
|
|
@@ -2000,10 +2035,8 @@ class EngineSlots {
|
|
|
2000
2035
|
if (await this.free(mark)) {
|
|
2001
2036
|
removeWhole(mark);
|
|
2002
2037
|
removeWhole(`${mark}${SEATED_SUFFIX}`);
|
|
2003
|
-
} else
|
|
2004
|
-
live = "
|
|
2005
|
-
} else if (live === "none") {
|
|
2006
|
-
live = "seated";
|
|
2038
|
+
} else {
|
|
2039
|
+
live = "queued";
|
|
2007
2040
|
}
|
|
2008
2041
|
}
|
|
2009
2042
|
return live;
|
|
@@ -2047,7 +2080,7 @@ class EngineSlots {
|
|
|
2047
2080
|
}
|
|
2048
2081
|
return handed;
|
|
2049
2082
|
}
|
|
2050
|
-
made(path) {
|
|
2083
|
+
made(path, holder = this.holder) {
|
|
2051
2084
|
let made;
|
|
2052
2085
|
try {
|
|
2053
2086
|
made = openSync2(path, "wx");
|
|
@@ -2055,7 +2088,7 @@ class EngineSlots {
|
|
|
2055
2088
|
return false;
|
|
2056
2089
|
}
|
|
2057
2090
|
try {
|
|
2058
|
-
writeSync2(made, JSON.stringify(
|
|
2091
|
+
writeSync2(made, JSON.stringify(holder));
|
|
2059
2092
|
} finally {
|
|
2060
2093
|
closeSync2(made);
|
|
2061
2094
|
}
|
|
@@ -2075,10 +2108,10 @@ class EngineSlots {
|
|
|
2075
2108
|
}
|
|
2076
2109
|
}
|
|
2077
2110
|
}
|
|
2078
|
-
takenOver(lock) {
|
|
2079
|
-
return this.cleared(lock, true);
|
|
2111
|
+
takenOver(lock, holder) {
|
|
2112
|
+
return this.cleared(lock, true, holder);
|
|
2080
2113
|
}
|
|
2081
|
-
async cleared(lock, retake) {
|
|
2114
|
+
async cleared(lock, retake, holder = this.holder) {
|
|
2082
2115
|
if (!await this.free(lock)) {
|
|
2083
2116
|
return false;
|
|
2084
2117
|
}
|
|
@@ -2100,7 +2133,7 @@ class EngineSlots {
|
|
|
2100
2133
|
} catch {
|
|
2101
2134
|
return false;
|
|
2102
2135
|
}
|
|
2103
|
-
return retake ? this.made(lock) : true;
|
|
2136
|
+
return retake ? this.made(lock, holder) : true;
|
|
2104
2137
|
} finally {
|
|
2105
2138
|
rmSync4(steal, { force: true });
|
|
2106
2139
|
}
|
|
@@ -2136,7 +2169,8 @@ function handSlot(lock, from, to) {
|
|
|
2136
2169
|
} catch {
|
|
2137
2170
|
return false;
|
|
2138
2171
|
}
|
|
2139
|
-
|
|
2172
|
+
const holder = content === null ? null : holderOf(content);
|
|
2173
|
+
return holder?.pid === from && writeWhole(lock, JSON.stringify(holder.game === true ? { ...to, game: true } : to));
|
|
2140
2174
|
}
|
|
2141
2175
|
function giveBackSlot(lock, pid) {
|
|
2142
2176
|
try {
|
|
@@ -2163,15 +2197,12 @@ function nameSlotTaker(by) {
|
|
|
2163
2197
|
}
|
|
2164
2198
|
function slotWaitSaid(waitedMs, count, directory, holders = [], drawn = { numbers: [] }) {
|
|
2165
2199
|
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
2200
|
const taking = drawn.limit === undefined ? count : drawn.numbers.length;
|
|
2170
2201
|
const slots = `${slotsSaid(taking, count, directory, drawn.limit)} ${taking === 1 ? "is" : "are"} in use`;
|
|
2171
2202
|
const named = holdersNamed(taking, holders);
|
|
2172
2203
|
const waiting = `${so}: ${slots}`;
|
|
2173
2204
|
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;
|
|
2205
|
+
const starts = drawn.limit === "kept" || drawn.limit === "tier" || drawn.limit === "games" ? `${back} or no gate is queued` : back;
|
|
2175
2206
|
if (named.length === 0) {
|
|
2176
2207
|
return `${waiting}, by a gate or another tool, and ${starts}.`;
|
|
2177
2208
|
}
|
|
@@ -2191,13 +2222,13 @@ function slotsSaid(taking, count, directory, limit) {
|
|
|
2191
2222
|
if (limit === "tier") {
|
|
2192
2223
|
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
2224
|
}
|
|
2225
|
+
if (limit === "games") {
|
|
2226
|
+
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,`;
|
|
2227
|
+
}
|
|
2194
2228
|
return count === 1 ? `the one engine slot ${where}` : `all ${String(count)} engine slots ${where}`;
|
|
2195
2229
|
}
|
|
2196
2230
|
function slotWaitedSaid(waitedMs, count, directory, holders, drawn = { numbers: [] }) {
|
|
2197
2231
|
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
2232
|
const taking = drawn.limit === undefined ? count : drawn.numbers.length;
|
|
2202
2233
|
const slots = `${slotsSaid(taking, count, directory, drawn.limit)} ${taking === 1 ? "was" : "were"} in use`;
|
|
2203
2234
|
const named = holdersNamed(taking, holders);
|
|
@@ -2220,7 +2251,7 @@ function holdersNamed(count, holders) {
|
|
|
2220
2251
|
function listed(named) {
|
|
2221
2252
|
return named.length === 1 ? named.join("") : `${named.slice(0, -1).join(", ")} and ${named.at(-1) ?? ""}`;
|
|
2222
2253
|
}
|
|
2223
|
-
async function slotForCall() {
|
|
2254
|
+
async function slotForCall(game = false) {
|
|
2224
2255
|
const slots = await processSlots();
|
|
2225
2256
|
const progress = callProgress();
|
|
2226
2257
|
const waits = callSlotWaits();
|
|
@@ -2232,7 +2263,7 @@ async function slotForCall() {
|
|
|
2232
2263
|
}, () => {
|
|
2233
2264
|
blockedBy = slots.holders();
|
|
2234
2265
|
blockedOn = slots.drawn;
|
|
2235
|
-
});
|
|
2266
|
+
}, game);
|
|
2236
2267
|
if (waits !== undefined && blockedBy !== undefined) {
|
|
2237
2268
|
waits.ms += Date.now() - began;
|
|
2238
2269
|
const heldBy = blockedBy;
|
|
@@ -2259,7 +2290,7 @@ async function inASlot(body) {
|
|
|
2259
2290
|
held.release();
|
|
2260
2291
|
}
|
|
2261
2292
|
}
|
|
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",
|
|
2293
|
+
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, ours, saidTo, takenBy;
|
|
2263
2294
|
var init_engine_slots = __esm(() => {
|
|
2264
2295
|
init_alive();
|
|
2265
2296
|
init_cache_home();
|
|
@@ -9534,7 +9565,7 @@ var init_config_formats = __esm(() => {
|
|
|
9534
9565
|
});
|
|
9535
9566
|
|
|
9536
9567
|
// src/runner.ts
|
|
9537
|
-
import { existsSync as
|
|
9568
|
+
import { existsSync as existsSync2, realpathSync as realpathSync2 } from "node:fs";
|
|
9538
9569
|
import { delimiter, dirname as dirname3, extname, join as join6, resolve as resolve3 } from "node:path";
|
|
9539
9570
|
import process5 from "node:process";
|
|
9540
9571
|
function currentRunner() {
|
|
@@ -9578,12 +9609,12 @@ function realPath(path) {
|
|
|
9578
9609
|
}
|
|
9579
9610
|
function alongside(execPath, name) {
|
|
9580
9611
|
const runner = join6(dirname3(execPath), process5.platform === "win32" ? `${name}.cmd` : name);
|
|
9581
|
-
return
|
|
9612
|
+
return existsSync2(runner) ? runner : undefined;
|
|
9582
9613
|
}
|
|
9583
9614
|
var init_runner = () => {};
|
|
9584
9615
|
|
|
9585
9616
|
// src/harnesses.ts
|
|
9586
|
-
import { existsSync as
|
|
9617
|
+
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
9618
|
import { homedir as homedir3 } from "node:os";
|
|
9588
9619
|
import { basename as basename4, dirname as dirname4, isAbsolute as isAbsolute2, join as join7, relative as relative2, resolve as resolve4 } from "node:path";
|
|
9589
9620
|
import process6 from "node:process";
|
|
@@ -9674,15 +9705,15 @@ function harnessById(id) {
|
|
|
9674
9705
|
}
|
|
9675
9706
|
function present(harness, projectPath) {
|
|
9676
9707
|
const path = configPath(harness, projectPath);
|
|
9677
|
-
if (
|
|
9708
|
+
if (existsSync3(path)) {
|
|
9678
9709
|
return true;
|
|
9679
9710
|
}
|
|
9680
9711
|
const root = harness.scope === "project" ? projectPath : homedir3();
|
|
9681
9712
|
const own = dirname4(path);
|
|
9682
|
-
if (own !== root &&
|
|
9713
|
+
if (own !== root && existsSync3(own)) {
|
|
9683
9714
|
return true;
|
|
9684
9715
|
}
|
|
9685
|
-
return harness.marker !== undefined &&
|
|
9716
|
+
return harness.marker !== undefined && existsSync3(join7(root, harness.marker));
|
|
9686
9717
|
}
|
|
9687
9718
|
function candidates(projectPath) {
|
|
9688
9719
|
const found = [];
|
|
@@ -9695,7 +9726,7 @@ function candidates(projectPath) {
|
|
|
9695
9726
|
}
|
|
9696
9727
|
if (present(harness, projectPath)) {
|
|
9697
9728
|
found.push({ harness, reason: "configured" });
|
|
9698
|
-
} else if (harness.home !== undefined &&
|
|
9729
|
+
} else if (harness.home !== undefined && existsSync3(join7(homedir3(), harness.home))) {
|
|
9699
9730
|
found.push({ harness, reason: "installed" });
|
|
9700
9731
|
}
|
|
9701
9732
|
}
|
|
@@ -9717,7 +9748,7 @@ function groupByFile(harnesses, projectPath) {
|
|
|
9717
9748
|
}
|
|
9718
9749
|
function registered(harness, projectPath) {
|
|
9719
9750
|
const path = configPath(harness, projectPath);
|
|
9720
|
-
if (harness.snippet !== undefined || !
|
|
9751
|
+
if (harness.snippet !== undefined || !existsSync3(path)) {
|
|
9721
9752
|
return false;
|
|
9722
9753
|
}
|
|
9723
9754
|
const text = readFileSync8(path, "utf8");
|
|
@@ -9746,7 +9777,7 @@ function recordedEnginePath(projectPath) {
|
|
|
9746
9777
|
}
|
|
9747
9778
|
const named = reach(entryEnvironment(harness, projectPath), "GODOT_PATH");
|
|
9748
9779
|
const path = typeof named !== "string" || named === "" ? null : isAbsolute2(named) ? named : resolve4(projectPath, named);
|
|
9749
|
-
if (path !== null &&
|
|
9780
|
+
if (path !== null && existsSync3(path)) {
|
|
9750
9781
|
return path;
|
|
9751
9782
|
}
|
|
9752
9783
|
}
|
|
@@ -9754,7 +9785,7 @@ function recordedEnginePath(projectPath) {
|
|
|
9754
9785
|
}
|
|
9755
9786
|
function mainCheckoutOf(projectPath) {
|
|
9756
9787
|
let top = resolve4(projectPath);
|
|
9757
|
-
while (!
|
|
9788
|
+
while (!existsSync3(join7(top, ".git"))) {
|
|
9758
9789
|
const up = dirname4(top);
|
|
9759
9790
|
if (up === top) {
|
|
9760
9791
|
return null;
|
|
@@ -9771,7 +9802,7 @@ function mainCheckoutOf(projectPath) {
|
|
|
9771
9802
|
}
|
|
9772
9803
|
const entry = resolve4(top, pointer);
|
|
9773
9804
|
const commonFile = join7(entry, "commondir");
|
|
9774
|
-
if (!
|
|
9805
|
+
if (!existsSync3(commonFile)) {
|
|
9775
9806
|
return null;
|
|
9776
9807
|
}
|
|
9777
9808
|
const common = resolve4(entry, readFileSync8(commonFile, "utf8").trim());
|
|
@@ -9779,11 +9810,11 @@ function mainCheckoutOf(projectPath) {
|
|
|
9779
9810
|
return null;
|
|
9780
9811
|
}
|
|
9781
9812
|
const main = join7(dirname4(common), relative2(top, resolve4(projectPath)));
|
|
9782
|
-
return isSameDirectory(main, projectPath) || !
|
|
9813
|
+
return isSameDirectory(main, projectPath) || !existsSync3(join7(main, "project.godot")) ? null : main;
|
|
9783
9814
|
}
|
|
9784
9815
|
function worktreeCheckoutsOf(projectPath) {
|
|
9785
9816
|
let top = resolve4(projectPath);
|
|
9786
|
-
while (!
|
|
9817
|
+
while (!existsSync3(join7(top, ".git"))) {
|
|
9787
9818
|
const up = dirname4(top);
|
|
9788
9819
|
if (up === top) {
|
|
9789
9820
|
return [];
|
|
@@ -9791,18 +9822,18 @@ function worktreeCheckoutsOf(projectPath) {
|
|
|
9791
9822
|
top = up;
|
|
9792
9823
|
}
|
|
9793
9824
|
const listed = join7(top, ".git", "worktrees");
|
|
9794
|
-
if (!statSync4(join7(top, ".git")).isDirectory() || !
|
|
9825
|
+
if (!statSync4(join7(top, ".git")).isDirectory() || !existsSync3(listed)) {
|
|
9795
9826
|
return [];
|
|
9796
9827
|
}
|
|
9797
9828
|
const below = relative2(top, resolve4(projectPath));
|
|
9798
9829
|
return readdirSync2(listed).flatMap((name) => {
|
|
9799
9830
|
const pointer = join7(listed, name, "gitdir");
|
|
9800
|
-
if (!
|
|
9831
|
+
if (!existsSync3(pointer)) {
|
|
9801
9832
|
return [];
|
|
9802
9833
|
}
|
|
9803
9834
|
const checkout = dirname4(resolve4(listed, name, readFileSync8(pointer, "utf8").trim()));
|
|
9804
9835
|
const project = join7(checkout, below);
|
|
9805
|
-
return
|
|
9836
|
+
return existsSync3(join7(project, "project.godot")) ? [project] : [];
|
|
9806
9837
|
});
|
|
9807
9838
|
}
|
|
9808
9839
|
function entryEnvironment(harness, projectPath) {
|
|
@@ -9810,7 +9841,7 @@ function entryEnvironment(harness, projectPath) {
|
|
|
9810
9841
|
return;
|
|
9811
9842
|
}
|
|
9812
9843
|
const path = configPath(harness, projectPath);
|
|
9813
|
-
if (!
|
|
9844
|
+
if (!existsSync3(path)) {
|
|
9814
9845
|
return;
|
|
9815
9846
|
}
|
|
9816
9847
|
let parsed;
|
|
@@ -9831,7 +9862,7 @@ function reach(held, key) {
|
|
|
9831
9862
|
}
|
|
9832
9863
|
function disconnect(harness, projectPath) {
|
|
9833
9864
|
const path = configPath(harness, projectPath);
|
|
9834
|
-
if (!
|
|
9865
|
+
if (!existsSync3(path)) {
|
|
9835
9866
|
return { harness, path, action: "absent" };
|
|
9836
9867
|
}
|
|
9837
9868
|
if (harness.snippet !== undefined) {
|
|
@@ -9918,7 +9949,7 @@ function connect(harness, projectPath, launch) {
|
|
|
9918
9949
|
if (harness.snippet !== undefined) {
|
|
9919
9950
|
return { harness, path, action: "snippet", snippet: harness.snippet(launch) };
|
|
9920
9951
|
}
|
|
9921
|
-
const held =
|
|
9952
|
+
const held = existsSync3(path) ? readFileSync8(path, "utf8") : "";
|
|
9922
9953
|
if (harness.toml !== undefined) {
|
|
9923
9954
|
const already = held.includes(harness.toml.identity ?? harness.toml.header);
|
|
9924
9955
|
return put(harness, path, writeToml(held, harness.toml, launch), already);
|
|
@@ -11084,7 +11115,7 @@ var init_gdscript_source = __esm(() => {
|
|
|
11084
11115
|
});
|
|
11085
11116
|
|
|
11086
11117
|
// src/class-cache.ts
|
|
11087
|
-
import { existsSync as
|
|
11118
|
+
import { existsSync as existsSync4, readdirSync as readdirSync3, readFileSync as readFileSync9, statSync as statSync5 } from "node:fs";
|
|
11088
11119
|
import { join as join8, posix } from "node:path";
|
|
11089
11120
|
function isToolScript(source) {
|
|
11090
11121
|
return TOOL.test(codeOf(source));
|
|
@@ -11148,7 +11179,7 @@ function declaredClassOf(source) {
|
|
|
11148
11179
|
}
|
|
11149
11180
|
function eachScript(projectPath, each) {
|
|
11150
11181
|
const visit = (directory, prefix) => {
|
|
11151
|
-
if (
|
|
11182
|
+
if (existsSync4(join8(directory, ".gdignore"))) {
|
|
11152
11183
|
return;
|
|
11153
11184
|
}
|
|
11154
11185
|
for (const entry of readdirSync3(directory, { withFileTypes: true })) {
|
|
@@ -11544,7 +11575,7 @@ function uncachedForTheEngineNote(projectPath, types) {
|
|
|
11544
11575
|
}
|
|
11545
11576
|
const one = types.length === 1;
|
|
11546
11577
|
const named = types.map((type) => `${type.type} (${type.declaredIn})`).join(", ");
|
|
11547
|
-
const cacheExists =
|
|
11578
|
+
const cacheExists = existsSync4(join8(projectPath, ".godot", "global_script_class_cache.cfg"));
|
|
11548
11579
|
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
11580
|
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
11581
|
}
|
|
@@ -11570,7 +11601,7 @@ function declaredSince(projectPath, paths, names, since) {
|
|
|
11570
11601
|
});
|
|
11571
11602
|
}
|
|
11572
11603
|
function cachedAtMissingPaths(cached, projectPath) {
|
|
11573
|
-
return [...cached].filter(([, path]) => path.startsWith("res://") && !
|
|
11604
|
+
return [...cached].filter(([, path]) => path.startsWith("res://") && !existsSync4(join8(projectPath, path.slice("res://".length)))).map(([name]) => name).sort();
|
|
11574
11605
|
}
|
|
11575
11606
|
function staleAgainst(cached, projectPath) {
|
|
11576
11607
|
return [...declaredClasses(projectPath)].filter(([name, path]) => cached.get(name) !== path).map(([name]) => name);
|
|
@@ -12904,7 +12935,7 @@ var init_suite_judge = __esm(() => {
|
|
|
12904
12935
|
// src/engine-launch.ts
|
|
12905
12936
|
import {
|
|
12906
12937
|
closeSync as closeSync4,
|
|
12907
|
-
existsSync as
|
|
12938
|
+
existsSync as existsSync5,
|
|
12908
12939
|
fstatSync as fstatSync2,
|
|
12909
12940
|
openSync as openSync4,
|
|
12910
12941
|
readdirSync as readdirSync4,
|
|
@@ -12944,7 +12975,7 @@ function godotNamed(value, cwd) {
|
|
|
12944
12975
|
return null;
|
|
12945
12976
|
}
|
|
12946
12977
|
const path = resolve5(cwd, value);
|
|
12947
|
-
if (!
|
|
12978
|
+
if (!existsSync5(path) || statSync6(path).isDirectory()) {
|
|
12948
12979
|
throw new EngineUsageError(`--godot names ${path}, which is not an engine executable.`);
|
|
12949
12980
|
}
|
|
12950
12981
|
return path;
|
|
@@ -12975,7 +13006,7 @@ function resPathOf(entry, projectPath, cwd) {
|
|
|
12975
13006
|
const file = caseAt?.[1] ?? entry;
|
|
12976
13007
|
const fromProject = resolve5(projectPath, file);
|
|
12977
13008
|
const fromHere = resolve5(cwd, file);
|
|
12978
|
-
const absolute = isAbsolute3(file) || !
|
|
13009
|
+
const absolute = isAbsolute3(file) || !existsSync5(fromProject) && existsSync5(fromHere) ? fromHere : fromProject;
|
|
12979
13010
|
const inside = relative3(projectPath, absolute);
|
|
12980
13011
|
if (inside.startsWith("..") || isAbsolute3(inside)) {
|
|
12981
13012
|
throw new EngineUsageError(`${entry} is not inside the project at ${projectPath}.`);
|
|
@@ -12987,7 +13018,7 @@ function homeOf(projectPath) {
|
|
|
12987
13018
|
return mainCheckoutOf(projectPath) ?? projectPath;
|
|
12988
13019
|
}
|
|
12989
13020
|
function sweepRunDirectories(runs, kept = KEPT_RUN_DIRECTORIES) {
|
|
12990
|
-
if (!
|
|
13021
|
+
if (!existsSync5(runs)) {
|
|
12991
13022
|
return;
|
|
12992
13023
|
}
|
|
12993
13024
|
const ended = [];
|
|
@@ -13017,6 +13048,9 @@ function roomFor(most, processors, available, said = "of memory free", processor
|
|
|
13017
13048
|
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
13049
|
};
|
|
13019
13050
|
}
|
|
13051
|
+
function roomForAnother(available, starting) {
|
|
13052
|
+
return available - MEMORY_KEPT - starting * MEMORY_PER_ENGINE >= MEMORY_PER_ENGINE;
|
|
13053
|
+
}
|
|
13020
13054
|
async function memoryAvailable() {
|
|
13021
13055
|
const level = await macMemoryLevel();
|
|
13022
13056
|
if (level !== null) {
|
|
@@ -13221,7 +13255,7 @@ async function watchedEngine(launch, lock, args, directory, log, silenceSeconds,
|
|
|
13221
13255
|
continue;
|
|
13222
13256
|
}
|
|
13223
13257
|
const { stoppedIn } = readRun(readLog(log));
|
|
13224
|
-
const unstarted = helper !== null && !
|
|
13258
|
+
const unstarted = helper !== null && !existsSync5(helper.pid) ? `, and it never started ${helper.how}: ${helperStep(helper.step)}` : "";
|
|
13225
13259
|
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
13260
|
stop();
|
|
13227
13261
|
}
|
|
@@ -13307,7 +13341,7 @@ var init_engine_launch = __esm(() => {
|
|
|
13307
13341
|
});
|
|
13308
13342
|
|
|
13309
13343
|
// src/detection.ts
|
|
13310
|
-
import { existsSync as
|
|
13344
|
+
import { existsSync as existsSync6, readdirSync as readdirSync5, statSync as statSync7 } from "node:fs";
|
|
13311
13345
|
import { homedir as homedir4 } from "node:os";
|
|
13312
13346
|
import { join as join10 } from "node:path";
|
|
13313
13347
|
function resolveHomeDirectory() {
|
|
@@ -13318,7 +13352,7 @@ function resolveHomeDirectory() {
|
|
|
13318
13352
|
}
|
|
13319
13353
|
}
|
|
13320
13354
|
function scanDirectoryForGodotBinaries(directory, platform) {
|
|
13321
|
-
if (!directory || !
|
|
13355
|
+
if (!directory || !existsSync6(directory)) {
|
|
13322
13356
|
return [];
|
|
13323
13357
|
}
|
|
13324
13358
|
let entries;
|
|
@@ -13586,7 +13620,7 @@ var init_launch = __esm(() => {
|
|
|
13586
13620
|
});
|
|
13587
13621
|
|
|
13588
13622
|
// src/godot-path.ts
|
|
13589
|
-
import { existsSync as
|
|
13623
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
13590
13624
|
import { isAbsolute as isAbsolute4, normalize, resolve as resolve6 } from "node:path";
|
|
13591
13625
|
function versionStartOf(error) {
|
|
13592
13626
|
const failed = error ?? {};
|
|
@@ -13664,7 +13698,7 @@ class GodotLocator {
|
|
|
13664
13698
|
if (known !== undefined) {
|
|
13665
13699
|
return known;
|
|
13666
13700
|
}
|
|
13667
|
-
if (path !== "godot" && !
|
|
13701
|
+
if (path !== "godot" && !existsSync7(path)) {
|
|
13668
13702
|
this.answered.set(path, "does not exist");
|
|
13669
13703
|
return "does not exist";
|
|
13670
13704
|
}
|
|
@@ -14046,7 +14080,7 @@ var init_engine_run = __esm(() => {
|
|
|
14046
14080
|
});
|
|
14047
14081
|
|
|
14048
14082
|
// src/doc-cache.ts
|
|
14049
|
-
import { existsSync as
|
|
14083
|
+
import { existsSync as existsSync8, readdirSync as readdirSync6, statSync as statSync8 } from "node:fs";
|
|
14050
14084
|
import { homedir as homedir5 } from "node:os";
|
|
14051
14085
|
import { basename as basename5, dirname as dirname5, isAbsolute as isAbsolute5, join as join11 } from "node:path";
|
|
14052
14086
|
import process9 from "node:process";
|
|
@@ -14054,7 +14088,7 @@ function editorCacheDirectory(godotPath, platform = process9.platform, env = pro
|
|
|
14054
14088
|
const beside = dirname5(godotPath);
|
|
14055
14089
|
const bundle = platform === "darwin" && basename5(beside) === "MacOS" && basename5(dirname5(beside)) === "Contents" ? dirname5(dirname5(dirname5(beside))) : null;
|
|
14056
14090
|
for (const folder of bundle === null ? [beside] : [beside, bundle]) {
|
|
14057
|
-
if (
|
|
14091
|
+
if (existsSync8(join11(folder, "._sc_")) || existsSync8(join11(folder, "_sc_"))) {
|
|
14058
14092
|
return join11(folder, "editor_data", "cache");
|
|
14059
14093
|
}
|
|
14060
14094
|
}
|
|
@@ -14102,7 +14136,7 @@ var init_doc_cache = __esm(() => {
|
|
|
14102
14136
|
});
|
|
14103
14137
|
|
|
14104
14138
|
// src/project-scan.ts
|
|
14105
|
-
import { existsSync as
|
|
14139
|
+
import { existsSync as existsSync9, readdirSync as readdirSync7, readFileSync as readFileSync12, statSync as statSync9 } from "node:fs";
|
|
14106
14140
|
import { basename as basename6, extname as extname2, join as join12, relative as relative4, sep as sep3 } from "node:path";
|
|
14107
14141
|
function skipped(name) {
|
|
14108
14142
|
return name.startsWith(".") || SKIPPED.has(name);
|
|
@@ -14111,10 +14145,10 @@ function steppedOver(directory) {
|
|
|
14111
14145
|
return gdignored(directory) || installedByUs(directory);
|
|
14112
14146
|
}
|
|
14113
14147
|
function gdignored(directory) {
|
|
14114
|
-
return
|
|
14148
|
+
return existsSync9(join12(directory, ".gdignore"));
|
|
14115
14149
|
}
|
|
14116
14150
|
function installedByUs(directory) {
|
|
14117
|
-
return
|
|
14151
|
+
return existsSync9(join12(directory, VERSION_MARKER));
|
|
14118
14152
|
}
|
|
14119
14153
|
function projectStructure(projectPath) {
|
|
14120
14154
|
const structure = { scenes: 0, scripts: 0, assets: 0, other: 0 };
|
|
@@ -14227,7 +14261,7 @@ function scriptsWithoutUid(projectPath) {
|
|
|
14227
14261
|
continue;
|
|
14228
14262
|
}
|
|
14229
14263
|
const extension = entry.name.split(".").pop()?.toLowerCase() ?? "";
|
|
14230
|
-
if (CARRIES_A_UID.has(extension) && !
|
|
14264
|
+
if (CARRIES_A_UID.has(extension) && !existsSync9(join12(directory, `${entry.name}.uid`))) {
|
|
14231
14265
|
found.push(spelled);
|
|
14232
14266
|
}
|
|
14233
14267
|
}
|
|
@@ -14494,7 +14528,7 @@ var init_project_scan = __esm(() => {
|
|
|
14494
14528
|
|
|
14495
14529
|
// src/import-freshness.ts
|
|
14496
14530
|
import { createHash as createHash2 } from "node:crypto";
|
|
14497
|
-
import { existsSync as
|
|
14531
|
+
import { existsSync as existsSync10, readdirSync as readdirSync8, readFileSync as readFileSync13, statSync as statSync10 } from "node:fs";
|
|
14498
14532
|
import { join as join13 } from "node:path";
|
|
14499
14533
|
function md5Of(file) {
|
|
14500
14534
|
let stats;
|
|
@@ -14620,7 +14654,7 @@ function behind(projectPath, resPath, sidecarFile, sidecar, importedFrom) {
|
|
|
14620
14654
|
return "its import file names no imported output, as one written before the engine imports from it does";
|
|
14621
14655
|
}
|
|
14622
14656
|
}
|
|
14623
|
-
if (outputs.some((output) => !
|
|
14657
|
+
if (outputs.some((output) => !existsSync10(onDisk(projectPath, output)))) {
|
|
14624
14658
|
return "its imported output is not on disk";
|
|
14625
14659
|
}
|
|
14626
14660
|
const source = unquoted(deps.get("source_file"));
|
|
@@ -14645,7 +14679,7 @@ function staleImports(projectPath) {
|
|
|
14645
14679
|
const stale = [];
|
|
14646
14680
|
const importedFrom = importedSidecarMd5s(projectPath);
|
|
14647
14681
|
const visit = (directory, resDirectory) => {
|
|
14648
|
-
if (
|
|
14682
|
+
if (existsSync10(join13(directory, ".gdignore")) || existsSync10(join13(directory, VERSION_MARKER))) {
|
|
14649
14683
|
return;
|
|
14650
14684
|
}
|
|
14651
14685
|
let entries;
|
|
@@ -14736,7 +14770,7 @@ var init_import_freshness = __esm(() => {
|
|
|
14736
14770
|
|
|
14737
14771
|
// src/library-copies.ts
|
|
14738
14772
|
import {
|
|
14739
|
-
existsSync as
|
|
14773
|
+
existsSync as existsSync11,
|
|
14740
14774
|
mkdirSync as mkdirSync4,
|
|
14741
14775
|
readdirSync as readdirSync9,
|
|
14742
14776
|
readFileSync as readFileSync14,
|
|
@@ -14754,7 +14788,7 @@ function freeLibraryCopies(projectPath, platform = process.platform) {
|
|
|
14754
14788
|
for (const library of windowsLibraries(projectPath)) {
|
|
14755
14789
|
const folder = dirname6(library);
|
|
14756
14790
|
const copy = `~${basename7(library)}`;
|
|
14757
|
-
if (
|
|
14791
|
+
if (existsSync11(join14(folder, copy))) {
|
|
14758
14792
|
const aside = join14(folder, `${copy}.aside-${process.pid}-${Date.now()}`);
|
|
14759
14793
|
try {
|
|
14760
14794
|
renameSync3(join14(folder, copy), aside);
|
|
@@ -14780,12 +14814,26 @@ function freeLibraryCopies(projectPath, platform = process.platform) {
|
|
|
14780
14814
|
}
|
|
14781
14815
|
function seedExtensionList(projectPath) {
|
|
14782
14816
|
const list = join14(projectPath, ".godot", "extension_list.cfg");
|
|
14783
|
-
if (
|
|
14817
|
+
if (existsSync11(list)) {
|
|
14784
14818
|
return null;
|
|
14785
14819
|
}
|
|
14820
|
+
const found = unlistedExtensions(projectPath);
|
|
14821
|
+
if (found.length === 0) {
|
|
14822
|
+
return [];
|
|
14823
|
+
}
|
|
14824
|
+
mkdirSync4(dirname6(list), { recursive: true });
|
|
14825
|
+
writeFileSync7(list, `${found.join(`
|
|
14826
|
+
`)}
|
|
14827
|
+
`);
|
|
14828
|
+
return found;
|
|
14829
|
+
}
|
|
14830
|
+
function unlistedExtensions(projectPath) {
|
|
14831
|
+
if (existsSync11(join14(projectPath, ".godot", "extension_list.cfg"))) {
|
|
14832
|
+
return [];
|
|
14833
|
+
}
|
|
14786
14834
|
const found = [];
|
|
14787
14835
|
const visit = (directory, resDirectory) => {
|
|
14788
|
-
if (
|
|
14836
|
+
if (existsSync11(join14(directory, ".gdignore"))) {
|
|
14789
14837
|
return;
|
|
14790
14838
|
}
|
|
14791
14839
|
let entries;
|
|
@@ -14806,15 +14854,7 @@ function seedExtensionList(projectPath) {
|
|
|
14806
14854
|
}
|
|
14807
14855
|
};
|
|
14808
14856
|
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;
|
|
14857
|
+
return found.sort();
|
|
14818
14858
|
}
|
|
14819
14859
|
function windowsLibraries(projectPath) {
|
|
14820
14860
|
const listed = readOrNull(join14(projectPath, ".godot", "extension_list.cfg"));
|
|
@@ -14864,12 +14904,12 @@ var init_library_copies = () => {};
|
|
|
14864
14904
|
|
|
14865
14905
|
// src/reimport.ts
|
|
14866
14906
|
import { createHash as createHash3 } from "node:crypto";
|
|
14867
|
-
import { existsSync as
|
|
14907
|
+
import { existsSync as existsSync12, readFileSync as readFileSync15, rmSync as rmSync8, statSync as statSync11, utimesSync, writeFileSync as writeFileSync8 } from "node:fs";
|
|
14868
14908
|
import { basename as basename8, join as join15 } from "node:path";
|
|
14869
14909
|
function forceNextImport(projectPath, resourcePath) {
|
|
14870
14910
|
const relative = resourcePath.replace(/^res:\/\//, "");
|
|
14871
14911
|
const sidecar = join15(projectPath, `${relative}.import`);
|
|
14872
|
-
if (!
|
|
14912
|
+
if (!existsSync12(sidecar)) {
|
|
14873
14913
|
return;
|
|
14874
14914
|
}
|
|
14875
14915
|
const { atime, mtimeMs } = statSync11(sidecar);
|
|
@@ -14884,7 +14924,7 @@ function importRecord(projectPath, resourcePath) {
|
|
|
14884
14924
|
var init_reimport = () => {};
|
|
14885
14925
|
|
|
14886
14926
|
// src/scratch.ts
|
|
14887
|
-
import { existsSync as
|
|
14927
|
+
import { existsSync as existsSync13, mkdtempSync as mkdtempSync2, readdirSync as readdirSync10, rmSync as rmSync9 } from "node:fs";
|
|
14888
14928
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
14889
14929
|
import { join as join16 } from "node:path";
|
|
14890
14930
|
import process10 from "node:process";
|
|
@@ -14943,7 +14983,7 @@ function tryAgain(path, attempt) {
|
|
|
14943
14983
|
lastTryOnExit();
|
|
14944
14984
|
}
|
|
14945
14985
|
const after = AGAIN_AFTER_MS[attempt];
|
|
14946
|
-
if (after === undefined || !
|
|
14986
|
+
if (after === undefined || !existsSync13(path)) {
|
|
14947
14987
|
waiting.delete(path);
|
|
14948
14988
|
if (after === undefined) {
|
|
14949
14989
|
atExit.add(path);
|
|
@@ -15099,7 +15139,7 @@ var init_script_origins = __esm(() => {
|
|
|
15099
15139
|
});
|
|
15100
15140
|
|
|
15101
15141
|
// src/headless.ts
|
|
15102
|
-
import { existsSync as
|
|
15142
|
+
import { existsSync as existsSync14, readFileSync as readFileSync16, writeFileSync as writeFileSync9 } from "node:fs";
|
|
15103
15143
|
import { dirname as dirname7, join as join18 } from "node:path";
|
|
15104
15144
|
function snakeCased(params) {
|
|
15105
15145
|
const result = emptyRecord();
|
|
@@ -15388,7 +15428,7 @@ async function operationOutcome(engine, operation, params, projectPath) {
|
|
|
15388
15428
|
};
|
|
15389
15429
|
}
|
|
15390
15430
|
function answerIn(file) {
|
|
15391
|
-
if (!
|
|
15431
|
+
if (!existsSync14(file)) {
|
|
15392
15432
|
return { kind: "none" };
|
|
15393
15433
|
}
|
|
15394
15434
|
const text = readFileSync16(file, "utf8");
|
|
@@ -15417,7 +15457,7 @@ var init_headless = __esm(() => {
|
|
|
15417
15457
|
});
|
|
15418
15458
|
|
|
15419
15459
|
// src/update-check.ts
|
|
15420
|
-
import { existsSync as
|
|
15460
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync5, readFileSync as readFileSync17, writeFileSync as writeFileSync10 } from "node:fs";
|
|
15421
15461
|
import { homedir as homedir6, tmpdir as tmpdir6 } from "node:os";
|
|
15422
15462
|
import { join as join19 } from "node:path";
|
|
15423
15463
|
function packageUrl(root) {
|
|
@@ -15459,7 +15499,7 @@ function cacheFile(environment = process.env) {
|
|
|
15459
15499
|
}
|
|
15460
15500
|
function readCache(path) {
|
|
15461
15501
|
try {
|
|
15462
|
-
if (!
|
|
15502
|
+
if (!existsSync15(path)) {
|
|
15463
15503
|
return null;
|
|
15464
15504
|
}
|
|
15465
15505
|
const parsed = JSON.parse(readFileSync17(path, "utf8"));
|
|
@@ -15939,7 +15979,7 @@ var init_ports = __esm(() => {
|
|
|
15939
15979
|
});
|
|
15940
15980
|
|
|
15941
15981
|
// src/lsp_client.ts
|
|
15942
|
-
import { existsSync as
|
|
15982
|
+
import { existsSync as existsSync16, realpathSync as realpathSync3 } from "node:fs";
|
|
15943
15983
|
import { readFile, realpath } from "node:fs/promises";
|
|
15944
15984
|
import { createConnection } from "node:net";
|
|
15945
15985
|
import { dirname as dirname8, extname as extname3, join as join20, resolve as resolve7 } from "node:path";
|
|
@@ -16620,7 +16660,7 @@ async function resolveLSPPaths(projectPathValue, scriptPathValue) {
|
|
|
16620
16660
|
} catch {
|
|
16621
16661
|
throw new ArgumentRefusal(`Project path does not exist: ${requestedProjectPath}`);
|
|
16622
16662
|
}
|
|
16623
|
-
if (!
|
|
16663
|
+
if (!existsSync16(join20(projectPath, "project.godot"))) {
|
|
16624
16664
|
throw new ArgumentRefusal(`Not a Godot project: ${projectPath}. Point projectPath at the directory holding project.godot.`);
|
|
16625
16665
|
}
|
|
16626
16666
|
const contained = resolveWithinProject(projectPath, scriptPathValue);
|
|
@@ -17134,7 +17174,7 @@ function readParams(params, key) {
|
|
|
17134
17174
|
import { createHash as createHash5 } from "node:crypto";
|
|
17135
17175
|
import {
|
|
17136
17176
|
cpSync,
|
|
17137
|
-
existsSync as
|
|
17177
|
+
existsSync as existsSync18,
|
|
17138
17178
|
mkdirSync as mkdirSync6,
|
|
17139
17179
|
readdirSync as readdirSync12,
|
|
17140
17180
|
readFileSync as readFileSync21,
|
|
@@ -17217,7 +17257,7 @@ function installedRuntimeDigest(projectPath) {
|
|
|
17217
17257
|
}
|
|
17218
17258
|
function digestMarker(projectPath, addon) {
|
|
17219
17259
|
const marker = join22(projectPath, "addons", addon, DIGEST_MARKER);
|
|
17220
|
-
if (!
|
|
17260
|
+
if (!existsSync18(marker)) {
|
|
17221
17261
|
return null;
|
|
17222
17262
|
}
|
|
17223
17263
|
const said = readFileSync21(marker, "utf8").trim();
|
|
@@ -17234,7 +17274,7 @@ function shippedLoader() {
|
|
|
17234
17274
|
}
|
|
17235
17275
|
function loaderState(projectPath) {
|
|
17236
17276
|
const copy = join22(projectPath, ...RUNTIME_AUTOLOAD.path.split("/"));
|
|
17237
|
-
if (!
|
|
17277
|
+
if (!existsSync18(copy)) {
|
|
17238
17278
|
return "missing";
|
|
17239
17279
|
}
|
|
17240
17280
|
const lines = (path) => readFileSync21(path, "utf8").replaceAll(`\r
|
|
@@ -17253,7 +17293,7 @@ function writeLoader(projectPath) {
|
|
|
17253
17293
|
}
|
|
17254
17294
|
function removeLoader(projectPath) {
|
|
17255
17295
|
const copy = join22(projectPath, ...RUNTIME_AUTOLOAD.path.split("/"));
|
|
17256
|
-
if (!
|
|
17296
|
+
if (!existsSync18(copy)) {
|
|
17257
17297
|
return false;
|
|
17258
17298
|
}
|
|
17259
17299
|
rmSync10(copy);
|
|
@@ -17269,10 +17309,10 @@ function shippedListedRunner() {
|
|
|
17269
17309
|
}
|
|
17270
17310
|
function gdUnit4Unusable(projectPath) {
|
|
17271
17311
|
const marker = "addons/gdUnit4/plugin.cfg";
|
|
17272
|
-
if (!
|
|
17312
|
+
if (!existsSync18(join22(projectPath, ...marker.split("/")))) {
|
|
17273
17313
|
return { missing: true, reason: `gdUnit4 is not installed in this project: no ${marker}` };
|
|
17274
17314
|
}
|
|
17275
|
-
if (!
|
|
17315
|
+
if (!existsSync18(join22(projectPath, ...GDUNIT4_CI_RUNNER.split("/")))) {
|
|
17276
17316
|
return {
|
|
17277
17317
|
missing: false,
|
|
17278
17318
|
reason: `gdUnit4 in this project is older than 6.0, which the shipped runner needs: no ${GDUNIT4_CI_RUNNER}`
|
|
@@ -17284,11 +17324,11 @@ function installAddons(projectPath, from = shippedAddonsDirectory()) {
|
|
|
17284
17324
|
const installed = [];
|
|
17285
17325
|
for (const name of ADDONS) {
|
|
17286
17326
|
const source = join22(from, name);
|
|
17287
|
-
if (!
|
|
17327
|
+
if (!existsSync18(join22(source, addonMarking(name)))) {
|
|
17288
17328
|
throw new Error(`The package holds no ${name} addon at ${source}.`);
|
|
17289
17329
|
}
|
|
17290
17330
|
const target = join22(projectPath, "addons", name);
|
|
17291
|
-
const replaced =
|
|
17331
|
+
const replaced = existsSync18(target);
|
|
17292
17332
|
rmSync10(target, { recursive: true, force: true });
|
|
17293
17333
|
mkdirSync6(dirname9(target), { recursive: true });
|
|
17294
17334
|
cpSync(source, target, { recursive: true });
|
|
@@ -17304,7 +17344,7 @@ function installAddons(projectPath, from = shippedAddonsDirectory()) {
|
|
|
17304
17344
|
}
|
|
17305
17345
|
function installedAddonVersion(projectPath) {
|
|
17306
17346
|
const marker = join22(projectPath, "addons", ADDONS[0], VERSION_MARKER);
|
|
17307
|
-
if (!
|
|
17347
|
+
if (!existsSync18(marker)) {
|
|
17308
17348
|
return null;
|
|
17309
17349
|
}
|
|
17310
17350
|
const said = readFileSync21(marker, "utf8").trim();
|
|
@@ -17314,13 +17354,13 @@ function removeAddons(projectPath) {
|
|
|
17314
17354
|
const removed = [];
|
|
17315
17355
|
for (const name of ADDONS) {
|
|
17316
17356
|
const target = join22(projectPath, "addons", name);
|
|
17317
|
-
if (
|
|
17357
|
+
if (existsSync18(target)) {
|
|
17318
17358
|
rmSync10(target, { recursive: true, force: true });
|
|
17319
17359
|
removed.push(target);
|
|
17320
17360
|
}
|
|
17321
17361
|
}
|
|
17322
17362
|
const addons = join22(projectPath, "addons");
|
|
17323
|
-
if (removed.length > 0 &&
|
|
17363
|
+
if (removed.length > 0 && existsSync18(addons) && readdirSync12(addons).length === 0) {
|
|
17324
17364
|
rmdirSync(addons);
|
|
17325
17365
|
removed.push(addons);
|
|
17326
17366
|
}
|
|
@@ -17420,8 +17460,8 @@ function inspectProject(projectPath) {
|
|
|
17420
17460
|
const addons = ADDONS.map((name) => {
|
|
17421
17461
|
const directory = join22(projectPath, "addons", name);
|
|
17422
17462
|
const marker = join22(directory, VERSION_MARKER);
|
|
17423
|
-
const installed =
|
|
17424
|
-
const version =
|
|
17463
|
+
const installed = existsSync18(directory);
|
|
17464
|
+
const version = existsSync18(marker) ? readFileSync21(marker, "utf8").trim() : null;
|
|
17425
17465
|
const current = version === SERVER_VERSION;
|
|
17426
17466
|
if (!installed) {
|
|
17427
17467
|
problems.push(`addons/${name} is not installed; run gdharness setup`);
|
|
@@ -17454,7 +17494,7 @@ function inspectProject(projectPath) {
|
|
|
17454
17494
|
const ignoredAutoloads = [];
|
|
17455
17495
|
const addonMissing = (path) => addons.some((addon) => !addon.installed && path.startsWith(`addons/${addon.name}/`));
|
|
17456
17496
|
for (const [name, path] of named) {
|
|
17457
|
-
if (!
|
|
17497
|
+
if (!existsSync18(join22(projectPath, path))) {
|
|
17458
17498
|
if (!addonMissing(path)) {
|
|
17459
17499
|
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
17500
|
}
|
|
@@ -18338,7 +18378,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
18338
18378
|
name: "scene_node",
|
|
18339
18379
|
title: "Scene nodes",
|
|
18340
18380
|
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,
|
|
18381
|
+
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
18382
|
parameters: {
|
|
18343
18383
|
projectPath: PROJECT_PATH,
|
|
18344
18384
|
scenePath: SCENE_PATH,
|
|
@@ -20025,7 +20065,7 @@ var init_tool_reference = __esm(() => {
|
|
|
20025
20065
|
});
|
|
20026
20066
|
|
|
20027
20067
|
// src/suite-plan.ts
|
|
20028
|
-
import { existsSync as
|
|
20068
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync9, readFileSync as readFileSync24 } from "node:fs";
|
|
20029
20069
|
import { dirname as dirname11, join as join26, posix as posix3 } from "node:path";
|
|
20030
20070
|
function within(path, folder) {
|
|
20031
20071
|
return path === folder || path.startsWith(`${folder}/`);
|
|
@@ -20437,7 +20477,7 @@ function windowNeedsOf(scripts, paths) {
|
|
|
20437
20477
|
}
|
|
20438
20478
|
function capsFrames(projectPath) {
|
|
20439
20479
|
const file = `${projectPath}/project.godot`;
|
|
20440
|
-
if (!
|
|
20480
|
+
if (!existsSync22(file)) {
|
|
20441
20481
|
return false;
|
|
20442
20482
|
}
|
|
20443
20483
|
const cap = parseProjectGodot(readFileSync24(file, "utf8"))["application"]?.["run/max_fps"];
|
|
@@ -20445,14 +20485,14 @@ function capsFrames(projectPath) {
|
|
|
20445
20485
|
}
|
|
20446
20486
|
function gdUnitFailsOnPushErrors(projectPath) {
|
|
20447
20487
|
const file = `${projectPath}/project.godot`;
|
|
20448
|
-
if (!
|
|
20488
|
+
if (!existsSync22(file)) {
|
|
20449
20489
|
return false;
|
|
20450
20490
|
}
|
|
20451
20491
|
return parseProjectGodot(readFileSync24(file, "utf8"))["gdunit4"]?.["report/godot/push_error"] === true;
|
|
20452
20492
|
}
|
|
20453
20493
|
function viewportOf(projectPath) {
|
|
20454
20494
|
const file = `${projectPath}/project.godot`;
|
|
20455
|
-
if (!
|
|
20495
|
+
if (!existsSync22(file)) {
|
|
20456
20496
|
return null;
|
|
20457
20497
|
}
|
|
20458
20498
|
const text = readFileSync24(file, "utf8");
|
|
@@ -42074,7 +42114,7 @@ var init_stdio = __esm(() => {
|
|
|
42074
42114
|
});
|
|
42075
42115
|
|
|
42076
42116
|
// src/autoload-failure.ts
|
|
42077
|
-
import { existsSync as
|
|
42117
|
+
import { existsSync as existsSync24, readFileSync as readFileSync27 } from "node:fs";
|
|
42078
42118
|
import { join as join29 } from "node:path";
|
|
42079
42119
|
function scriptsAutoloaded(projectPath) {
|
|
42080
42120
|
const scripts = new Map;
|
|
@@ -42090,7 +42130,7 @@ function scriptsAutoloaded(projectPath) {
|
|
|
42090
42130
|
continue;
|
|
42091
42131
|
}
|
|
42092
42132
|
const scene = join29(projectPath, path);
|
|
42093
|
-
if (!
|
|
42133
|
+
if (!existsSync24(scene)) {
|
|
42094
42134
|
continue;
|
|
42095
42135
|
}
|
|
42096
42136
|
try {
|
|
@@ -42113,11 +42153,11 @@ var init_autoload_failure = __esm(() => {
|
|
|
42113
42153
|
});
|
|
42114
42154
|
|
|
42115
42155
|
// src/runtime-client.ts
|
|
42116
|
-
import { existsSync as
|
|
42156
|
+
import { existsSync as existsSync25, readdirSync as readdirSync16, readFileSync as readFileSync28, statSync as statSync15, unlinkSync as unlinkSync3 } from "node:fs";
|
|
42117
42157
|
import { createConnection as createConnection2 } from "node:net";
|
|
42118
42158
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
42119
42159
|
import { dirname as dirname14, join as join30, resolve as resolve12 } from "node:path";
|
|
42120
|
-
import { setTimeout as
|
|
42160
|
+
import { setTimeout as delay6 } from "node:timers/promises";
|
|
42121
42161
|
function runtimeDirectory(variables = process.env) {
|
|
42122
42162
|
const explicit = envValue("GDHARNESS_RUNTIME_DIR", variables);
|
|
42123
42163
|
if (explicit) {
|
|
@@ -42137,7 +42177,7 @@ function runtimeDirectories(variables = process.env) {
|
|
|
42137
42177
|
function errorReportOf(pid, directories = runtimeDirectories()) {
|
|
42138
42178
|
for (const directory of directories) {
|
|
42139
42179
|
const path = join30(directory, `runtime-${pid}.log`);
|
|
42140
|
-
if (
|
|
42180
|
+
if (existsSync25(path)) {
|
|
42141
42181
|
return path;
|
|
42142
42182
|
}
|
|
42143
42183
|
}
|
|
@@ -42283,7 +42323,7 @@ function strangersAmong(candidates, now, startTimes = startTimesOf) {
|
|
|
42283
42323
|
}).map((one) => one.file));
|
|
42284
42324
|
}
|
|
42285
42325
|
function announcedIn(directory) {
|
|
42286
|
-
if (!
|
|
42326
|
+
if (!existsSync25(directory)) {
|
|
42287
42327
|
return [];
|
|
42288
42328
|
}
|
|
42289
42329
|
const found = [];
|
|
@@ -42336,7 +42376,7 @@ function announcedIn(directory) {
|
|
|
42336
42376
|
return found;
|
|
42337
42377
|
}
|
|
42338
42378
|
async function announcementEnded(pid, directories = runtimeDirectories()) {
|
|
42339
|
-
const files = directories.map((directory) => join30(directory, `runtime-${pid}.json`)).filter((file) =>
|
|
42379
|
+
const files = directories.map((directory) => join30(directory, `runtime-${pid}.json`)).filter((file) => existsSync25(file));
|
|
42340
42380
|
const first = files[0];
|
|
42341
42381
|
if (first === undefined) {
|
|
42342
42382
|
return;
|
|
@@ -42347,7 +42387,7 @@ async function announcementEnded(pid, directories = runtimeDirectories()) {
|
|
|
42347
42387
|
if (left <= 0) {
|
|
42348
42388
|
return;
|
|
42349
42389
|
}
|
|
42350
|
-
await
|
|
42390
|
+
await delay6(Math.min(LOOK_EVERY_MS, left));
|
|
42351
42391
|
}
|
|
42352
42392
|
wentAway(first, pid);
|
|
42353
42393
|
for (const file of files) {
|
|
@@ -42379,7 +42419,7 @@ async function announcedSince(projectPath, before, waiting = {}) {
|
|
|
42379
42419
|
if (left <= 0 || waiting.giveUp?.() === true) {
|
|
42380
42420
|
return [];
|
|
42381
42421
|
}
|
|
42382
|
-
await
|
|
42422
|
+
await delay6(Math.min(LOOK_EVERY_MS, left));
|
|
42383
42423
|
}
|
|
42384
42424
|
}
|
|
42385
42425
|
function describe2(endpoint) {
|
|
@@ -42915,11 +42955,11 @@ var init_class_note = __esm(() => {
|
|
|
42915
42955
|
});
|
|
42916
42956
|
|
|
42917
42957
|
// src/config-pin.ts
|
|
42918
|
-
import { existsSync as
|
|
42958
|
+
import { existsSync as existsSync26, readFileSync as readFileSync32 } from "node:fs";
|
|
42919
42959
|
import { join as join34 } from "node:path";
|
|
42920
42960
|
function versionsNamedInConfig(projectPath) {
|
|
42921
42961
|
const config = join34(projectPath, ".mcp.json");
|
|
42922
|
-
if (!
|
|
42962
|
+
if (!existsSync26(config)) {
|
|
42923
42963
|
return [];
|
|
42924
42964
|
}
|
|
42925
42965
|
let text;
|
|
@@ -42945,7 +42985,7 @@ var init_config_pin = __esm(() => {
|
|
|
42945
42985
|
});
|
|
42946
42986
|
|
|
42947
42987
|
// src/cut-test-run.ts
|
|
42948
|
-
import { existsSync as
|
|
42988
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync14, readFileSync as readFileSync33, rmSync as rmSync15, writeFileSync as writeFileSync16 } from "node:fs";
|
|
42949
42989
|
import { dirname as dirname18, join as join35 } from "node:path";
|
|
42950
42990
|
function keptAt(projectPath) {
|
|
42951
42991
|
return join35(projectPath, ".godot", "gdharness-reports", "cut-run.json");
|
|
@@ -42960,7 +43000,7 @@ function keepCutTestRun(projectPath, run) {
|
|
|
42960
43000
|
}
|
|
42961
43001
|
function takeCutTestRun(projectPath) {
|
|
42962
43002
|
const path = keptAt(projectPath);
|
|
42963
|
-
if (!
|
|
43003
|
+
if (!existsSync27(path)) {
|
|
42964
43004
|
return null;
|
|
42965
43005
|
}
|
|
42966
43006
|
try {
|
|
@@ -43006,7 +43046,7 @@ var init_game_debugger = __esm(() => {
|
|
|
43006
43046
|
|
|
43007
43047
|
// src/dap_client.ts
|
|
43008
43048
|
import { createConnection as createConnection3 } from "node:net";
|
|
43009
|
-
import { setTimeout as
|
|
43049
|
+
import { setTimeout as delay7 } from "node:timers/promises";
|
|
43010
43050
|
function fileKey(path) {
|
|
43011
43051
|
return process.platform === "win32" ? path.replaceAll("\\", "/").toLowerCase() : path;
|
|
43012
43052
|
}
|
|
@@ -43486,7 +43526,7 @@ class GodotDAPClient {
|
|
|
43486
43526
|
await this.sendRequest(command, { threadId: resolvedThreadId });
|
|
43487
43527
|
const deadline = Date.now() + this.stepPatienceMs;
|
|
43488
43528
|
while (this.stops === before && this.connected && Date.now() < deadline) {
|
|
43489
|
-
await
|
|
43529
|
+
await delay7(50);
|
|
43490
43530
|
}
|
|
43491
43531
|
return this.stops !== before;
|
|
43492
43532
|
}
|
|
@@ -43512,7 +43552,7 @@ class GodotDAPClient {
|
|
|
43512
43552
|
return answered;
|
|
43513
43553
|
}
|
|
43514
43554
|
} catch {}
|
|
43515
|
-
await
|
|
43555
|
+
await delay7(200);
|
|
43516
43556
|
}
|
|
43517
43557
|
return null;
|
|
43518
43558
|
}
|
|
@@ -43533,7 +43573,7 @@ class GodotDAPClient {
|
|
|
43533
43573
|
break;
|
|
43534
43574
|
}
|
|
43535
43575
|
} catch {}
|
|
43536
|
-
await
|
|
43576
|
+
await delay7(200);
|
|
43537
43577
|
}
|
|
43538
43578
|
if (scopes.length === 0) {
|
|
43539
43579
|
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 +43606,7 @@ class GodotDAPClient {
|
|
|
43566
43606
|
return { frame, value, ...typeof type === "string" ? { type } : {} };
|
|
43567
43607
|
}
|
|
43568
43608
|
} catch {}
|
|
43569
|
-
await
|
|
43609
|
+
await delay7(200);
|
|
43570
43610
|
}
|
|
43571
43611
|
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
43612
|
}
|
|
@@ -43728,7 +43768,7 @@ var init_dap_client = __esm(() => {
|
|
|
43728
43768
|
// src/editor-log.ts
|
|
43729
43769
|
import {
|
|
43730
43770
|
closeSync as closeSync5,
|
|
43731
|
-
existsSync as
|
|
43771
|
+
existsSync as existsSync28,
|
|
43732
43772
|
mkdirSync as mkdirSync15,
|
|
43733
43773
|
openSync as openSync5,
|
|
43734
43774
|
readFileSync as readFileSync34,
|
|
@@ -43792,7 +43832,7 @@ function editorConsole(projectPath, editorPid, openedByAServer) {
|
|
|
43792
43832
|
return { kind: "another editor", notedPid: noted?.pid ?? null };
|
|
43793
43833
|
}
|
|
43794
43834
|
const path = editorLogPath(projectPath);
|
|
43795
|
-
if (!
|
|
43835
|
+
if (!existsSync28(path)) {
|
|
43796
43836
|
return { kind: "not written" };
|
|
43797
43837
|
}
|
|
43798
43838
|
const log = new GameLog;
|
|
@@ -44011,7 +44051,7 @@ var init_editor_log = __esm(() => {
|
|
|
44011
44051
|
});
|
|
44012
44052
|
|
|
44013
44053
|
// src/rename.ts
|
|
44014
|
-
import { existsSync as
|
|
44054
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync16, readFileSync as readFileSync35, renameSync as renameSync4, unlinkSync as unlinkSync4, writeFileSync as writeFileSync18 } from "node:fs";
|
|
44015
44055
|
import { dirname as dirname20, posix as posix4 } from "node:path";
|
|
44016
44056
|
|
|
44017
44057
|
class Script {
|
|
@@ -44736,7 +44776,7 @@ function applyRewrites(rewrites) {
|
|
|
44736
44776
|
if (now !== rewrite.before) {
|
|
44737
44777
|
throw new Error(`${rewrite.path} changed on disk while the rename was being worked out; nothing was written`);
|
|
44738
44778
|
}
|
|
44739
|
-
if (rewrite.writeTo !== rewrite.absolute &&
|
|
44779
|
+
if (rewrite.writeTo !== rewrite.absolute && existsSync29(rewrite.writeTo)) {
|
|
44740
44780
|
throw new Error(`${rewrite.writeTo} already exists; nothing was written`);
|
|
44741
44781
|
}
|
|
44742
44782
|
}
|
|
@@ -44750,7 +44790,7 @@ function applyRewrites(rewrites) {
|
|
|
44750
44790
|
let movedUid = false;
|
|
44751
44791
|
if (rewrite.writeTo !== rewrite.absolute) {
|
|
44752
44792
|
unlinkSync4(rewrite.absolute);
|
|
44753
|
-
if (
|
|
44793
|
+
if (existsSync29(`${rewrite.absolute}.uid`)) {
|
|
44754
44794
|
renameSync4(`${rewrite.absolute}.uid`, `${rewrite.writeTo}.uid`);
|
|
44755
44795
|
movedUid = true;
|
|
44756
44796
|
}
|
|
@@ -44796,7 +44836,7 @@ var init_rename = __esm(() => {
|
|
|
44796
44836
|
});
|
|
44797
44837
|
|
|
44798
44838
|
// src/rename-symbol.ts
|
|
44799
|
-
import { existsSync as
|
|
44839
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync17, readdirSync as readdirSync17, realpathSync as realpathSync5, rmSync as rmSync17, writeFileSync as writeFileSync19 } from "node:fs";
|
|
44800
44840
|
import { basename as basename10, dirname as dirname21, join as join37, relative as relative7, resolve as resolve13 } from "node:path";
|
|
44801
44841
|
function resourcePathOf(projectPath, absolute) {
|
|
44802
44842
|
const inside = relative7(onDiskSpelling(projectPath), onDiskSpelling(absolute));
|
|
@@ -44864,7 +44904,7 @@ async function renameSymbol(request, services) {
|
|
|
44864
44904
|
reason: `newScriptPath must be a .gd path inside the project, and ${request.newScriptPath} is not.`
|
|
44865
44905
|
};
|
|
44866
44906
|
}
|
|
44867
|
-
if (
|
|
44907
|
+
if (existsSync30(request.newScriptPath)) {
|
|
44868
44908
|
return { ok: false, reason: `${moveTo} already exists, so the script cannot be moved there.` };
|
|
44869
44909
|
}
|
|
44870
44910
|
}
|
|
@@ -45041,7 +45081,7 @@ async function renameSymbol(request, services) {
|
|
|
45041
45081
|
scripts,
|
|
45042
45082
|
moves: new Map([[declaringPath, moveTo]]),
|
|
45043
45083
|
named: [declaringPath],
|
|
45044
|
-
exists: (path) =>
|
|
45084
|
+
exists: (path) => existsSync30(`${projectPath}/${path.slice("res://".length)}`)
|
|
45045
45085
|
}, plan);
|
|
45046
45086
|
}
|
|
45047
45087
|
plan = mentionIgnored(plan, ignoredTexts(projectPath), symbol, moveTo === null ? [] : [declaringPath]);
|
|
@@ -45316,7 +45356,7 @@ var init_rename_symbol = __esm(() => {
|
|
|
45316
45356
|
|
|
45317
45357
|
// src/file-move.ts
|
|
45318
45358
|
import {
|
|
45319
|
-
existsSync as
|
|
45359
|
+
existsSync as existsSync31,
|
|
45320
45360
|
mkdirSync as mkdirSync18,
|
|
45321
45361
|
readdirSync as readdirSync18,
|
|
45322
45362
|
readFileSync as readFileSync36,
|
|
@@ -45349,7 +45389,7 @@ function unseenByTheEngine(projectPath, path) {
|
|
|
45349
45389
|
}
|
|
45350
45390
|
if (at < steps.length - 1) {
|
|
45351
45391
|
directory = join38(directory, step);
|
|
45352
|
-
if (
|
|
45392
|
+
if (existsSync31(join38(directory, ".gdignore"))) {
|
|
45353
45393
|
return `${path} is under a directory holding a .gdignore, which the engine does not load`;
|
|
45354
45394
|
}
|
|
45355
45395
|
}
|
|
@@ -45361,12 +45401,12 @@ function installedAddonOf(projectPath, path) {
|
|
|
45361
45401
|
if (steps[0] !== "addons" || steps[1] === undefined) {
|
|
45362
45402
|
return null;
|
|
45363
45403
|
}
|
|
45364
|
-
return
|
|
45404
|
+
return existsSync31(join38(projectPath, "addons", steps[1], VERSION_MARKER)) ? `res://addons/${steps[1]}` : null;
|
|
45365
45405
|
}
|
|
45366
45406
|
function binaryResources(projectPath) {
|
|
45367
45407
|
const found = [];
|
|
45368
45408
|
const visit = (directory, prefix) => {
|
|
45369
|
-
if (
|
|
45409
|
+
if (existsSync31(join38(directory, ".gdignore"))) {
|
|
45370
45410
|
return;
|
|
45371
45411
|
}
|
|
45372
45412
|
for (const entry of readdirSync18(directory, { withFileTypes: true })) {
|
|
@@ -45403,7 +45443,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
45403
45443
|
if (to === null) {
|
|
45404
45444
|
return { ok: false, reason: `newPath must be a path inside the project, and ${absoluteTo} is not.` };
|
|
45405
45445
|
}
|
|
45406
|
-
if (!
|
|
45446
|
+
if (!existsSync31(absoluteFrom)) {
|
|
45407
45447
|
return { ok: false, reason: `There is nothing at ${from} to move.` };
|
|
45408
45448
|
}
|
|
45409
45449
|
if (from === to) {
|
|
@@ -45432,7 +45472,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
45432
45472
|
if (isDirectory && to.startsWith(`${from}/`)) {
|
|
45433
45473
|
return { ok: false, reason: `${from} cannot be moved into itself.` };
|
|
45434
45474
|
}
|
|
45435
|
-
if (
|
|
45475
|
+
if (existsSync31(absoluteTo) && !sameFile(absoluteFrom, absoluteTo)) {
|
|
45436
45476
|
return { ok: false, reason: `${to} already exists, so nothing was moved there.` };
|
|
45437
45477
|
}
|
|
45438
45478
|
const unseen = unseenByTheEngine(projectPath, to);
|
|
@@ -45440,7 +45480,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
45440
45480
|
return { ok: false, reason: `${unseen}, so nothing there could load what was moved.` };
|
|
45441
45481
|
}
|
|
45442
45482
|
if (!isDirectory) {
|
|
45443
|
-
const owner = SIDECARS.map((sidecar) => from.endsWith(sidecar) ? from.slice(0, -sidecar.length) : null).find((path) => path !== null &&
|
|
45483
|
+
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
45484
|
if (owner !== undefined && owner !== null) {
|
|
45445
45485
|
return { ok: false, reason: `${from} belongs to ${owner} and moves with it: move ${owner} instead.` };
|
|
45446
45486
|
}
|
|
@@ -45462,7 +45502,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
45462
45502
|
} else {
|
|
45463
45503
|
moves.set(from, to);
|
|
45464
45504
|
for (const sidecar of SIDECARS) {
|
|
45465
|
-
if (
|
|
45505
|
+
if (existsSync31(`${absoluteFrom}${sidecar}`)) {
|
|
45466
45506
|
moves.set(`${from}${sidecar}`, `${to}${sidecar}`);
|
|
45467
45507
|
}
|
|
45468
45508
|
}
|
|
@@ -45474,7 +45514,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
45474
45514
|
scripts,
|
|
45475
45515
|
moves,
|
|
45476
45516
|
named: [from],
|
|
45477
|
-
exists: (path) =>
|
|
45517
|
+
exists: (path) => existsSync31(join38(projectPath, path.slice("res://".length)))
|
|
45478
45518
|
}, { edits: [], mentions: [] });
|
|
45479
45519
|
plan = mentionIgnored(plan, ignoredTexts(projectPath), null, [from]);
|
|
45480
45520
|
const binaries = [];
|
|
@@ -45545,13 +45585,13 @@ function applyFileMove(outcome) {
|
|
|
45545
45585
|
}
|
|
45546
45586
|
}
|
|
45547
45587
|
for (const file of outcome.moved) {
|
|
45548
|
-
if (!
|
|
45588
|
+
if (!existsSync31(file.absoluteFrom)) {
|
|
45549
45589
|
throw new Error(`${file.from} is gone from disk; nothing was written`);
|
|
45550
45590
|
}
|
|
45551
45591
|
if (file.text !== null && readFileSync36(file.absoluteFrom, "utf8") !== file.text.before) {
|
|
45552
45592
|
throw new Error(`${file.from} changed on disk while the move was being worked out; nothing was written`);
|
|
45553
45593
|
}
|
|
45554
|
-
if (
|
|
45594
|
+
if (existsSync31(file.absoluteTo) && !sameFile(file.absoluteFrom, file.absoluteTo)) {
|
|
45555
45595
|
throw new Error(`${file.to} already exists; nothing was written`);
|
|
45556
45596
|
}
|
|
45557
45597
|
}
|
|
@@ -50277,10 +50317,10 @@ var init_server_instructions = __esm(() => {
|
|
|
50277
50317
|
});
|
|
50278
50318
|
|
|
50279
50319
|
// src/suites-scene.ts
|
|
50280
|
-
import { existsSync as
|
|
50320
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync22, writeFileSync as writeFileSync22 } from "node:fs";
|
|
50281
50321
|
import { join as join42, relative as relative9, sep as sep5 } from "node:path";
|
|
50282
50322
|
function hasSuitesScene(projectPath) {
|
|
50283
|
-
return
|
|
50323
|
+
return existsSync32(join42(projectPath, SUITES_SCENE));
|
|
50284
50324
|
}
|
|
50285
50325
|
function suitesSceneArgs(projectPath, suites) {
|
|
50286
50326
|
const runs = join42(projectPath, ".godot", "gdharness", "suite-scenes");
|
|
@@ -50315,7 +50355,7 @@ var init_suites_scene = __esm(() => {
|
|
|
50315
50355
|
});
|
|
50316
50356
|
|
|
50317
50357
|
// src/test-selection.ts
|
|
50318
|
-
import { existsSync as
|
|
50358
|
+
import { existsSync as existsSync33 } from "node:fs";
|
|
50319
50359
|
import { basename as basename13, join as join43 } from "node:path";
|
|
50320
50360
|
function casesOutOfPath(projectPath, given, tests) {
|
|
50321
50361
|
const entries = Array.isArray(given) ? given : [given];
|
|
@@ -50360,12 +50400,12 @@ function casesIn(scripts, suite) {
|
|
|
50360
50400
|
}
|
|
50361
50401
|
function scriptsWithoutCases(projectPath, asked) {
|
|
50362
50402
|
const scripts = new ProjectScripts(projectPath);
|
|
50363
|
-
return asked.filter((path) => path.endsWith(".gd") &&
|
|
50403
|
+
return asked.filter((path) => path.endsWith(".gd") && existsSync33(join43(projectPath, path.slice("res://".length))) && casesIn(scripts, path).length === 0);
|
|
50364
50404
|
}
|
|
50365
50405
|
function suitesUnder(projectPath, asked) {
|
|
50366
50406
|
const scripts = projectFiles(projectPath, [".gd"]).map((path) => `res://${path}`);
|
|
50367
50407
|
return [
|
|
50368
|
-
...new Set(asked.flatMap((path) => path.endsWith(".gd") ?
|
|
50408
|
+
...new Set(asked.flatMap((path) => path.endsWith(".gd") ? existsSync33(join43(projectPath, path.slice("res://".length))) ? [path] : [] : scripts.filter((script) => script.startsWith(`${path}/`))))
|
|
50369
50409
|
];
|
|
50370
50410
|
}
|
|
50371
50411
|
function selectTests(projectPath, asked, given) {
|
|
@@ -50431,7 +50471,7 @@ import {
|
|
|
50431
50471
|
closeSync as closeSync6,
|
|
50432
50472
|
constants,
|
|
50433
50473
|
copyFileSync as copyFileSync2,
|
|
50434
|
-
existsSync as
|
|
50474
|
+
existsSync as existsSync34,
|
|
50435
50475
|
fstatSync as fstatSync3,
|
|
50436
50476
|
mkdirSync as mkdirSync23,
|
|
50437
50477
|
openSync as openSync7,
|
|
@@ -50444,7 +50484,7 @@ import {
|
|
|
50444
50484
|
writeFileSync as writeFileSync23
|
|
50445
50485
|
} from "node:fs";
|
|
50446
50486
|
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
|
|
50487
|
+
import { setTimeout as delay8 } from "node:timers/promises";
|
|
50448
50488
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
50449
50489
|
function editorRestartTimeoutMs() {
|
|
50450
50490
|
return waitFromEnv("GDHARNESS_EDITOR_RESTART_TIMEOUT_MS", 90000);
|
|
@@ -50459,7 +50499,7 @@ function greetingWaitMs() {
|
|
|
50459
50499
|
function pictureToSend(pngPath, jpegPath) {
|
|
50460
50500
|
const png = readFileSync40(pngPath);
|
|
50461
50501
|
const beside = pngPath.replace(/\.png$/, ".jpg");
|
|
50462
|
-
const jpeg = jpegPath !== undefined && normalize2(jpegPath) === normalize2(beside) &&
|
|
50502
|
+
const jpeg = jpegPath !== undefined && normalize2(jpegPath) === normalize2(beside) && existsSync34(beside) ? readFileSync40(beside) : null;
|
|
50463
50503
|
const sent = jpeg !== null && jpeg.length < png.length ? jpeg : png;
|
|
50464
50504
|
return {
|
|
50465
50505
|
data: sent.toString("base64"),
|
|
@@ -50499,7 +50539,7 @@ function writtenFileRefusal(path, rule) {
|
|
|
50499
50539
|
return `${named} ${path} does not end in ${rule.extensions.join(" or ")}, which is what ${what} is.`;
|
|
50500
50540
|
}
|
|
50501
50541
|
const directory = realAsFarAsItExists(dirname25(path));
|
|
50502
|
-
if (!
|
|
50542
|
+
if (!existsSync34(directory)) {
|
|
50503
50543
|
return `${named}'s directory ${dirname25(path)} does not exist; ${what} creates no directories.`;
|
|
50504
50544
|
}
|
|
50505
50545
|
const where = join44(directory, basename14(path));
|
|
@@ -50507,7 +50547,7 @@ function writtenFileRefusal(path, rule) {
|
|
|
50507
50547
|
if (inside !== undefined) {
|
|
50508
50548
|
return `${named} ${path} is inside the project at ${inside}; ${what} is saved outside it, so it never becomes part of the game.`;
|
|
50509
50549
|
}
|
|
50510
|
-
const taken = rule.writes(where).find((file) =>
|
|
50550
|
+
const taken = rule.writes(where).find((file) => existsSync34(file));
|
|
50511
50551
|
if (taken !== undefined) {
|
|
50512
50552
|
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
50553
|
}
|
|
@@ -50731,7 +50771,7 @@ async function untilGone(pids, withinMs = stopWaitMs()) {
|
|
|
50731
50771
|
const gone = () => pids.every((pid) => !alive(pid));
|
|
50732
50772
|
const deadline = Date.now() + withinMs;
|
|
50733
50773
|
while (!gone() && Date.now() < deadline) {
|
|
50734
|
-
await
|
|
50774
|
+
await delay8(50);
|
|
50735
50775
|
}
|
|
50736
50776
|
return gone();
|
|
50737
50777
|
}
|
|
@@ -51293,7 +51333,7 @@ function unsavedInEditorNote(scripts) {
|
|
|
51293
51333
|
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
51334
|
}
|
|
51295
51335
|
function editorAddonMissing(projectPath) {
|
|
51296
|
-
if (!
|
|
51336
|
+
if (!existsSync34(join44(projectPath, "project.godot"))) {
|
|
51297
51337
|
return null;
|
|
51298
51338
|
}
|
|
51299
51339
|
const report = inspectProject(projectPath);
|
|
@@ -51837,7 +51877,7 @@ function uncaughtNote(uncaught) {
|
|
|
51837
51877
|
}
|
|
51838
51878
|
function elsewhereIn(projectPath, asked) {
|
|
51839
51879
|
const wanted = asked.replace(/^res:\/\//, "").replace(/\/+$/, "");
|
|
51840
|
-
if (wanted === "" ||
|
|
51880
|
+
if (wanted === "" || existsSync34(join44(projectPath, wanted))) {
|
|
51841
51881
|
return "";
|
|
51842
51882
|
}
|
|
51843
51883
|
const root = (wanted.split("/")[0] ?? "").toLowerCase();
|
|
@@ -51860,7 +51900,7 @@ function windowNoteFor(needing, sharing) {
|
|
|
51860
51900
|
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
51901
|
}
|
|
51862
51902
|
function testPathsIn(projectPath, given, named = "path") {
|
|
51863
|
-
const defaults = TEST_DIRECTORIES.filter((directory) =>
|
|
51903
|
+
const defaults = TEST_DIRECTORIES.filter((directory) => existsSync34(join44(projectPath, directory)));
|
|
51864
51904
|
const entries = given === undefined || given === null || given === "" ? defaults.length > 0 ? defaults : TEST_DIRECTORIES : given;
|
|
51865
51905
|
const listed = Array.isArray(entries) ? entries : [entries];
|
|
51866
51906
|
if (listed.length === 0) {
|
|
@@ -52147,7 +52187,7 @@ class GodotServer {
|
|
|
52147
52187
|
taken = true;
|
|
52148
52188
|
this.logDebug(`Took port ${wanted} over from pid ${announced.pid}`);
|
|
52149
52189
|
} catch {
|
|
52150
|
-
await
|
|
52190
|
+
await delay8(HANDOVER_POLL_MS);
|
|
52151
52191
|
}
|
|
52152
52192
|
}
|
|
52153
52193
|
this.notHandedOverBy = taken ? null : announced.pid;
|
|
@@ -52285,7 +52325,7 @@ class GodotServer {
|
|
|
52285
52325
|
argv: process.argv.slice(1),
|
|
52286
52326
|
cwd,
|
|
52287
52327
|
project: this.ownProject,
|
|
52288
|
-
mcpJson:
|
|
52328
|
+
mcpJson: existsSync34(mcpJson) ? mcpJson : null
|
|
52289
52329
|
});
|
|
52290
52330
|
if (predecessor !== null) {
|
|
52291
52331
|
writeLifecycle("replaced", { project: this.ownProject, predecessor });
|
|
@@ -52427,7 +52467,7 @@ class GodotServer {
|
|
|
52427
52467
|
return checked.response;
|
|
52428
52468
|
}
|
|
52429
52469
|
const named = args["projectPath"];
|
|
52430
|
-
if (typeof named === "string" &&
|
|
52470
|
+
if (typeof named === "string" && existsSync34(join44(named, "project.godot"))) {
|
|
52431
52471
|
this.lastProjectPath = named;
|
|
52432
52472
|
}
|
|
52433
52473
|
this.updates.refresh();
|
|
@@ -53063,7 +53103,7 @@ class GodotServer {
|
|
|
53063
53103
|
return this.createErrorResponse("line is required: the one-based line to stop on.");
|
|
53064
53104
|
}
|
|
53065
53105
|
if (op === "set") {
|
|
53066
|
-
if (!
|
|
53106
|
+
if (!existsSync34(located.absolutePath)) {
|
|
53067
53107
|
return this.missingScript(project.value.path, located.relativePath);
|
|
53068
53108
|
}
|
|
53069
53109
|
const nothing = lineNothingStopsOn(located.absolutePath, located.relativePath, line);
|
|
@@ -53168,7 +53208,7 @@ class GodotServer {
|
|
|
53168
53208
|
return { ok: false, response: this.createErrorResponse("projectPath is required.") };
|
|
53169
53209
|
}
|
|
53170
53210
|
const file = join44(path, "project.godot");
|
|
53171
|
-
if (!
|
|
53211
|
+
if (!existsSync34(file)) {
|
|
53172
53212
|
return {
|
|
53173
53213
|
ok: false,
|
|
53174
53214
|
response: this.createErrorResponse(`Not a Godot project: ${path}`, [
|
|
@@ -53994,7 +54034,7 @@ class GodotServer {
|
|
|
53994
54034
|
if (place !== null && !place.ok) {
|
|
53995
54035
|
return this.createErrorResponse(place.reason);
|
|
53996
54036
|
}
|
|
53997
|
-
if (place !== null && !
|
|
54037
|
+
if (place !== null && !existsSync34(place.absolutePath)) {
|
|
53998
54038
|
const folders = readdirSync20(project.value.path, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name).sort();
|
|
53999
54039
|
return this.createErrorResponse(`There is nothing at res://${place.relativePath} to search.${folders.length === 0 ? "" : ` The project's folders are ${folders.join(", ")}.`}`);
|
|
54000
54040
|
}
|
|
@@ -54185,7 +54225,7 @@ ${platform}`;
|
|
|
54185
54225
|
output.absolutePath
|
|
54186
54226
|
];
|
|
54187
54227
|
this.logDebug(`Exporting: ${engine.value} ${exportArgs.join(" ")}`);
|
|
54188
|
-
const writtenAt = () =>
|
|
54228
|
+
const writtenAt = () => existsSync34(output.absolutePath) ? statSync20(output.absolutePath).mtimeMs : null;
|
|
54189
54229
|
const caches = editorCacheDirectory(engine.value);
|
|
54190
54230
|
const exportOnce = async () => {
|
|
54191
54231
|
const before = writtenAt();
|
|
@@ -54215,7 +54255,7 @@ ${platform}`;
|
|
|
54215
54255
|
return this.createErrorResponse(`Export could not be run: ${ending.failure ?? "the engine gave no exit status"}`);
|
|
54216
54256
|
}
|
|
54217
54257
|
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,
|
|
54258
|
+
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
54259
|
}
|
|
54220
54260
|
reportTestProgress(log) {
|
|
54221
54261
|
const progress = callProgress();
|
|
@@ -54276,7 +54316,7 @@ ${platform}`;
|
|
|
54276
54316
|
if (movie !== null) {
|
|
54277
54317
|
return this.createErrorResponse(movie);
|
|
54278
54318
|
}
|
|
54279
|
-
const missing = paths.value.filter((path) => !
|
|
54319
|
+
const missing = paths.value.filter((path) => !existsSync34(join44(project.value.path, path.slice("res://".length))));
|
|
54280
54320
|
const projectScripts = new ProjectScripts(project.value.path);
|
|
54281
54321
|
const present = paths.value.filter((path) => !missing.includes(path));
|
|
54282
54322
|
const asked = projectScripts.searchedAsTold(present);
|
|
@@ -54468,7 +54508,7 @@ ${platform}`;
|
|
|
54468
54508
|
await untilGone([run.process.pid]);
|
|
54469
54509
|
}
|
|
54470
54510
|
await run.settled;
|
|
54471
|
-
const helperFailed = onDesktop ? helperFailure(helperFiles.error) ?? (
|
|
54511
|
+
const helperFailed = onDesktop ? helperFailure(helperFiles.error) ?? (existsSync34(helperFiles.pid) ? null : `it never started, and ${helperStep(helperFiles.step)}`) : null;
|
|
54472
54512
|
if (helperFailed !== null) {
|
|
54473
54513
|
discard(join44(project.value.path, ".godot", ...ours.split("/")), userData);
|
|
54474
54514
|
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 +54524,10 @@ ${platform}`;
|
|
|
54484
54524
|
const reportsDir = join44(project.value.path, ".godot", ...ours.split("/"));
|
|
54485
54525
|
let report = null;
|
|
54486
54526
|
let reportProblem = null;
|
|
54487
|
-
const casePrinted = withNestedErrors(readRun(
|
|
54527
|
+
const casePrinted = withNestedErrors(readRun(existsSync34(engineLog) ? readFileSync40(engineLog, "utf8") : ""), run.log.all);
|
|
54488
54528
|
const declaredErrors = readExpected(expectedFile);
|
|
54489
54529
|
try {
|
|
54490
|
-
const written =
|
|
54530
|
+
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
54531
|
const newest = written.at(-1);
|
|
54492
54532
|
if (newest !== undefined) {
|
|
54493
54533
|
report = parseJUnit(readFileSync40(join44(reportsDir, newest, "results.xml"), "utf8"));
|
|
@@ -54814,7 +54854,7 @@ ${error.text}`;
|
|
|
54814
54854
|
if (!location.ok) {
|
|
54815
54855
|
return this.createErrorResponse(location.reason, PATH_SOLUTIONS);
|
|
54816
54856
|
}
|
|
54817
|
-
if (!
|
|
54857
|
+
if (!existsSync34(location.absolutePath)) {
|
|
54818
54858
|
return this.missingScript(project.value.path, location.relativePath);
|
|
54819
54859
|
}
|
|
54820
54860
|
ignored = scriptsUnderGdignore(project.value.path, [location.relativePath]);
|
|
@@ -54904,7 +54944,7 @@ ${error.text}`;
|
|
|
54904
54944
|
const wanted = `res://${relativePath}`;
|
|
54905
54945
|
const folder = dirname25(relativePath.replaceAll("\\", "/"));
|
|
54906
54946
|
const inFolder = join44(projectPath, folder);
|
|
54907
|
-
const beside =
|
|
54947
|
+
const beside = existsSync34(inFolder) ? readdirSync20(inFolder, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => `res://${folder === "." ? "" : `${folder}/`}${entry.name}`) : [];
|
|
54908
54948
|
return this.createErrorResponse(withNearestFiles(`Script file does not exist: ${wanted}`, wanted, scripts, beside));
|
|
54909
54949
|
}
|
|
54910
54950
|
async compileScripts(projectPath, paths) {
|
|
@@ -55032,7 +55072,7 @@ ${error.text}`;
|
|
|
55032
55072
|
const cached = cachedClasses(projectPath);
|
|
55033
55073
|
const sourceOf = (resourcePath) => {
|
|
55034
55074
|
const contained = resolveWithinProject(projectPath, resourcePath);
|
|
55035
|
-
if (!contained.ok || !
|
|
55075
|
+
if (!contained.ok || !existsSync34(contained.absolutePath)) {
|
|
55036
55076
|
return null;
|
|
55037
55077
|
}
|
|
55038
55078
|
try {
|
|
@@ -55126,7 +55166,7 @@ ${error.text}`;
|
|
|
55126
55166
|
}
|
|
55127
55167
|
sourceOfClass(projectPath, resourcePath) {
|
|
55128
55168
|
const contained = resolveWithinProject(projectPath, resourcePath);
|
|
55129
|
-
if (!contained.ok || !
|
|
55169
|
+
if (!contained.ok || !existsSync34(contained.absolutePath)) {
|
|
55130
55170
|
return null;
|
|
55131
55171
|
}
|
|
55132
55172
|
try {
|
|
@@ -55428,7 +55468,7 @@ ${error.text}`;
|
|
|
55428
55468
|
try {
|
|
55429
55469
|
const askedAt = Date.now();
|
|
55430
55470
|
const asked = this.godotBridge.invokeTool("playing_status", {}, { counted: false });
|
|
55431
|
-
const answer = await Promise.race([asked,
|
|
55471
|
+
const answer = await Promise.race([asked, delay8(PLAYING_STATUS_MS).then(() => null)]);
|
|
55432
55472
|
if (answer === null) {
|
|
55433
55473
|
this.logDebug(`playing_status did not answer within ${PLAYING_STATUS_MS}ms`);
|
|
55434
55474
|
asked.then(() => {
|
|
@@ -55453,7 +55493,7 @@ ${error.text}`;
|
|
|
55453
55493
|
try {
|
|
55454
55494
|
const answer = await Promise.race([
|
|
55455
55495
|
this.godotBridge.invokeTool("scan_status", {}, { counted: false }),
|
|
55456
|
-
|
|
55496
|
+
delay8(PLAYING_STATUS_MS).then(() => null)
|
|
55457
55497
|
]);
|
|
55458
55498
|
if (answer === null) {
|
|
55459
55499
|
return null;
|
|
@@ -55595,7 +55635,7 @@ ${error.text}`;
|
|
|
55595
55635
|
if (answer.serversNote === undefined || adapterFailed || Date.now() >= deadline) {
|
|
55596
55636
|
return answer;
|
|
55597
55637
|
}
|
|
55598
|
-
await
|
|
55638
|
+
await delay8(500);
|
|
55599
55639
|
}
|
|
55600
55640
|
}
|
|
55601
55641
|
async rebindTheDebugAdapter(servers) {
|
|
@@ -55856,7 +55896,7 @@ ${error.text}`;
|
|
|
55856
55896
|
if (Date.now() >= deadline) {
|
|
55857
55897
|
return false;
|
|
55858
55898
|
}
|
|
55859
|
-
await
|
|
55899
|
+
await delay8(250);
|
|
55860
55900
|
}
|
|
55861
55901
|
}
|
|
55862
55902
|
async handleLaunchEditor(args) {
|
|
@@ -55994,7 +56034,7 @@ ${error.text}`;
|
|
|
55994
56034
|
if (!paths.ok) {
|
|
55995
56035
|
return refused(paths.reason, PATH_SOLUTIONS);
|
|
55996
56036
|
}
|
|
55997
|
-
const missing = paths.value.filter((path) => !
|
|
56037
|
+
const missing = paths.value.filter((path) => !existsSync34(join44(projectPath, path.slice("res://".length))));
|
|
55998
56038
|
if (missing.length > 0) {
|
|
55999
56039
|
return refused(`Nothing at ${missing.join(" and ")} in the project at ${projectPath}.`, PATH_SOLUTIONS);
|
|
56000
56040
|
}
|
|
@@ -56039,7 +56079,7 @@ ${error.text}`;
|
|
|
56039
56079
|
return this.createErrorResponse(sceneToRun.reason, PATH_SOLUTIONS);
|
|
56040
56080
|
}
|
|
56041
56081
|
const build = readNonEmptyString(args, "executable");
|
|
56042
|
-
if (build === undefined && sceneToRun?.ok && !
|
|
56082
|
+
if (build === undefined && sceneToRun?.ok && !existsSync34(sceneToRun.absolutePath)) {
|
|
56043
56083
|
return this.createErrorResponse(`No scene at res://${sceneToRun.relativePath} in the project at ${project.value.path}.`, PATH_SOLUTIONS);
|
|
56044
56084
|
}
|
|
56045
56085
|
const exported = build === undefined ? null : exportedBuild(project.value.path, build);
|
|
@@ -56167,7 +56207,7 @@ ${error.text}`;
|
|
|
56167
56207
|
}
|
|
56168
56208
|
async runtimeUp(projectPath, before, budget, withArgs) {
|
|
56169
56209
|
const budgetMs = budget.ms;
|
|
56170
|
-
if (!
|
|
56210
|
+
if (!existsSync34(join44(projectPath, RUNTIME_SCRIPT))) {
|
|
56171
56211
|
return runtimeVerdict(null, {
|
|
56172
56212
|
addon: false,
|
|
56173
56213
|
budgetMs,
|
|
@@ -56305,7 +56345,7 @@ ${error.text}`;
|
|
|
56305
56345
|
const sendingFrom = Date.now();
|
|
56306
56346
|
const breakpoints = await this.dapHoldingBreakpointsOf(projectPath).reapplyBreakpoints();
|
|
56307
56347
|
this.logDebug(`Breakpoints were sent again after ${Date.now() - sendingFrom}ms`);
|
|
56308
|
-
const slot = await slotForCall();
|
|
56348
|
+
const slot = await slotForCall(true);
|
|
56309
56349
|
if (profiled) {
|
|
56310
56350
|
const armed = await this.handleViaBridge("profile_start", {
|
|
56311
56351
|
arm: true,
|
|
@@ -56508,7 +56548,7 @@ ${error.text}`;
|
|
|
56508
56548
|
if (Date.now() >= deadline) {
|
|
56509
56549
|
return false;
|
|
56510
56550
|
}
|
|
56511
|
-
await
|
|
56551
|
+
await delay8(100);
|
|
56512
56552
|
}
|
|
56513
56553
|
}
|
|
56514
56554
|
async endActiveGame(reason, going, graceful) {
|
|
@@ -56768,11 +56808,11 @@ ${error.text}`;
|
|
|
56768
56808
|
return Object.assign(started, { settled, stop });
|
|
56769
56809
|
}
|
|
56770
56810
|
async launchKeptGame(godotPath, cmdArgs, projectPath, env, desktop, profiled = false, debugged = true) {
|
|
56811
|
+
const slot = await slotForCall(true);
|
|
56771
56812
|
const startedAt = Date.now();
|
|
56772
56813
|
const transcript = openTranscript(startedAt);
|
|
56773
56814
|
closeSync6(transcript.fd);
|
|
56774
56815
|
const profile = profiled ? profilePath(startedAt) : undefined;
|
|
56775
|
-
const slot = await slotForCall();
|
|
56776
56816
|
const gameEnv = onTheSlot(profiled ? { ...env ?? process.env, [PROFILE_FROM_START]: "1" } : env ?? process.env, slot.lock);
|
|
56777
56817
|
let launched;
|
|
56778
56818
|
try {
|
|
@@ -57242,7 +57282,7 @@ ${error.text}`;
|
|
|
57242
57282
|
};
|
|
57243
57283
|
const going = await this.runStillGoing(run);
|
|
57244
57284
|
const projectPath = run.projectPath;
|
|
57245
|
-
const projectGone = projectPath !== null && !
|
|
57285
|
+
const projectGone = projectPath !== null && !existsSync34(join44(projectPath, "project.godot"));
|
|
57246
57286
|
if (projectGone && callersName !== undefined) {
|
|
57247
57287
|
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
57288
|
}
|
|
@@ -57400,7 +57440,7 @@ ${error.text}`;
|
|
|
57400
57440
|
return true;
|
|
57401
57441
|
}
|
|
57402
57442
|
}
|
|
57403
|
-
await
|
|
57443
|
+
await delay8(100);
|
|
57404
57444
|
}
|
|
57405
57445
|
return false;
|
|
57406
57446
|
}
|
|
@@ -57420,7 +57460,7 @@ ${error.text}`;
|
|
|
57420
57460
|
while (cancelled?.aborted !== true && await this.runStillGoing(run) && Date.now() < until) {
|
|
57421
57461
|
this.drainEditorOutput(run);
|
|
57422
57462
|
this.drainTranscript(run);
|
|
57423
|
-
await
|
|
57463
|
+
await delay8(RUN_POLL_MS);
|
|
57424
57464
|
}
|
|
57425
57465
|
return await this.handleGetDebugOutput(args, await this.runStillGoing(run) ? budgetMs : undefined);
|
|
57426
57466
|
}
|
|
@@ -57473,7 +57513,7 @@ ${error.text}`;
|
|
|
57473
57513
|
if (Date.now() >= until) {
|
|
57474
57514
|
return false;
|
|
57475
57515
|
}
|
|
57476
|
-
await
|
|
57516
|
+
await delay8(50);
|
|
57477
57517
|
}
|
|
57478
57518
|
}
|
|
57479
57519
|
async handleEditorConsole(args) {
|
|
@@ -57627,7 +57667,7 @@ ${error.text}`;
|
|
|
57627
57667
|
notes.push(endedWithoutACode({
|
|
57628
57668
|
throughEditor: run.throughEditor,
|
|
57629
57669
|
announced: announced !== undefined || run.announcedPid !== undefined,
|
|
57630
|
-
couldAnnounce: run.projectPath !== null &&
|
|
57670
|
+
couldAnnounce: run.projectPath !== null && existsSync34(join44(run.projectPath, RUNTIME_SCRIPT)),
|
|
57631
57671
|
endedHere: typeof run.endedHere === "string",
|
|
57632
57672
|
pickedUp: run.pickedUp === true
|
|
57633
57673
|
}));
|
|
@@ -58509,7 +58549,7 @@ ${error.text}`;
|
|
|
58509
58549
|
if (!scriptPath.ok) {
|
|
58510
58550
|
return this.createErrorResponse(scriptPath.reason);
|
|
58511
58551
|
}
|
|
58512
|
-
if (!
|
|
58552
|
+
if (!existsSync34(scriptPath.absolutePath)) {
|
|
58513
58553
|
return this.missingScript(projectPath, scriptPath.relativePath);
|
|
58514
58554
|
}
|
|
58515
58555
|
const asked = readNonEmptyString(args, "newScriptPath");
|
|
@@ -59153,7 +59193,7 @@ ${error.text}`;
|
|
|
59153
59193
|
async ownRunOnItsWay(projectPath, budgetMs) {
|
|
59154
59194
|
const run = await this.currentRun();
|
|
59155
59195
|
const project = projectPath ?? run?.projectPath ?? null;
|
|
59156
|
-
if (run === null || project === null || run.announcedPid !== undefined || run.projectPath !== null && !isSameDirectory(run.projectPath, project) || !
|
|
59196
|
+
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
59197
|
return null;
|
|
59158
59198
|
}
|
|
59159
59199
|
const already = runtimesAnnounced().running;
|
|
@@ -59606,7 +59646,7 @@ var init_server = __esm(() => {
|
|
|
59606
59646
|
init_bridge_announce();
|
|
59607
59647
|
init_engine_launch();
|
|
59608
59648
|
init_engine_slots();
|
|
59609
|
-
import { existsSync as
|
|
59649
|
+
import { existsSync as existsSync35 } from "node:fs";
|
|
59610
59650
|
import { dirname as dirname26, join as join45, resolve as resolve15 } from "node:path";
|
|
59611
59651
|
|
|
59612
59652
|
// src/error-mode.ts
|
|
@@ -59645,7 +59685,7 @@ init_alive();
|
|
|
59645
59685
|
init_engine_launch();
|
|
59646
59686
|
init_lsp_client();
|
|
59647
59687
|
init_process_children();
|
|
59648
|
-
import { existsSync as
|
|
59688
|
+
import { existsSync as existsSync17, readdirSync as readdirSync11, readFileSync as readFileSync19, unlinkSync as unlinkSync2 } from "node:fs";
|
|
59649
59689
|
import { connect as connect2 } from "node:net";
|
|
59650
59690
|
import { join as join21, resolve as resolve8 } from "node:path";
|
|
59651
59691
|
var EDITOR_RECORD_PROTOCOL = 1;
|
|
@@ -59757,7 +59797,7 @@ function lspOptionsOf(args, cwd) {
|
|
|
59757
59797
|
}
|
|
59758
59798
|
}
|
|
59759
59799
|
const projectPath = resolve8(cwd, named ?? ".");
|
|
59760
|
-
if (!
|
|
59800
|
+
if (!existsSync17(join21(projectPath, "project.godot"))) {
|
|
59761
59801
|
throw new EngineUsageError(`Not a Godot project: ${projectPath} holds no project.godot.`);
|
|
59762
59802
|
}
|
|
59763
59803
|
return { projectPath, port, waitSeconds };
|
|
@@ -59864,7 +59904,7 @@ init_setup();
|
|
|
59864
59904
|
init_setup();
|
|
59865
59905
|
init_tool_definitions();
|
|
59866
59906
|
init_tool_reference();
|
|
59867
|
-
import { existsSync as
|
|
59907
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync7, readdirSync as readdirSync13, rmSync as rmSync11, writeFileSync as writeFileSync12 } from "node:fs";
|
|
59868
59908
|
import { basename as basename9, dirname as dirname10, join as join23 } from "node:path";
|
|
59869
59909
|
var SKILL_NAME = "gdharness";
|
|
59870
59910
|
var SHARED_SKILLS = join23(".agents", "skills");
|
|
@@ -60136,7 +60176,7 @@ function everySkillDirectory(projectPath, harnesses) {
|
|
|
60136
60176
|
function removeSkill(directories, projectPath) {
|
|
60137
60177
|
const removed = [];
|
|
60138
60178
|
for (const directory of directories) {
|
|
60139
|
-
if (
|
|
60179
|
+
if (existsSync19(directory)) {
|
|
60140
60180
|
rmSync11(directory, { recursive: true, force: true });
|
|
60141
60181
|
pruneEmpty(dirname10(directory), projectPath);
|
|
60142
60182
|
removed.push(directory);
|
|
@@ -60158,7 +60198,7 @@ function pruneEmpty(directory, projectPath) {
|
|
|
60158
60198
|
function writeSkill(directories, version) {
|
|
60159
60199
|
const files = skillFiles(version);
|
|
60160
60200
|
return directories.map((directory) => {
|
|
60161
|
-
const replaced =
|
|
60201
|
+
const replaced = existsSync19(directory);
|
|
60162
60202
|
rmSync11(directory, { recursive: true, force: true });
|
|
60163
60203
|
for (const [name, contents] of files) {
|
|
60164
60204
|
const path = join23(directory, name);
|
|
@@ -60175,7 +60215,7 @@ init_engine_slots();
|
|
|
60175
60215
|
init_log_read();
|
|
60176
60216
|
init_setup();
|
|
60177
60217
|
init_suite_judge();
|
|
60178
|
-
import { existsSync as
|
|
60218
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync8, readFileSync as readFileSync22, rmSync as rmSync12 } from "node:fs";
|
|
60179
60219
|
import { availableParallelism as availableParallelism4 } from "node:os";
|
|
60180
60220
|
import { join as join24, resolve as resolve10 } from "node:path";
|
|
60181
60221
|
import process13 from "node:process";
|
|
@@ -60217,9 +60257,9 @@ function spreadOptionsOf(args, cwd) {
|
|
|
60217
60257
|
}
|
|
60218
60258
|
const first = positional[0];
|
|
60219
60259
|
const named = first === undefined ? null : resolve10(cwd, first);
|
|
60220
|
-
const projectNamed = named !== null &&
|
|
60260
|
+
const projectNamed = named !== null && existsSync20(join24(named, "project.godot"));
|
|
60221
60261
|
const projectPath = projectNamed ? named : resolve10(cwd);
|
|
60222
|
-
if (!
|
|
60262
|
+
if (!existsSync20(join24(projectPath, "project.godot"))) {
|
|
60223
60263
|
throw new EngineUsageError(`Not a Godot project: ${projectPath} holds no project.godot.`);
|
|
60224
60264
|
}
|
|
60225
60265
|
const scenes = positional.slice(projectNamed ? 1 : 0);
|
|
@@ -60227,7 +60267,7 @@ function spreadOptionsOf(args, cwd) {
|
|
|
60227
60267
|
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
60268
|
}
|
|
60229
60269
|
const scene = resPathOf(scenes[0] ?? "", projectPath, cwd);
|
|
60230
|
-
if (!
|
|
60270
|
+
if (!existsSync20(join24(projectPath, scene.slice("res://".length)))) {
|
|
60231
60271
|
throw new EngineUsageError(`Nothing at ${scene} in the project at ${projectPath}.`);
|
|
60232
60272
|
}
|
|
60233
60273
|
const benchArguments = dashes === -1 ? [] : args.slice(dashes + 1);
|
|
@@ -60298,7 +60338,7 @@ function shareFaults(played) {
|
|
|
60298
60338
|
return faults;
|
|
60299
60339
|
}
|
|
60300
60340
|
async function runSpreadCommand(options, godotPath) {
|
|
60301
|
-
if (!
|
|
60341
|
+
if (!existsSync20(join24(options.projectPath, SHARE_SCRIPT))) {
|
|
60302
60342
|
throw new EngineUsageError(`res://${SHARE_SCRIPT} is not in the project, so its bench cannot ask GdhShare for outcomes. Run gdharness setup.`);
|
|
60303
60343
|
}
|
|
60304
60344
|
const startedAt = Date.now();
|
|
@@ -60363,7 +60403,7 @@ async function runSpreadCommand(options, godotPath) {
|
|
|
60363
60403
|
const faults = left.flatMap((worker) => engineFaults(worker, options.godotVersion));
|
|
60364
60404
|
const arms = left.map((_, index) => {
|
|
60365
60405
|
const file = join24(shareDirectory, `worker-${String(index)}.arms`);
|
|
60366
|
-
return
|
|
60406
|
+
return existsSync20(file) ? armsPlayed(readFileSync22(file, "utf8")) : [];
|
|
60367
60407
|
});
|
|
60368
60408
|
faults.push(...shareFaults(arms));
|
|
60369
60409
|
if (faults.length > 0) {
|
|
@@ -60373,7 +60413,7 @@ async function runSpreadCommand(options, godotPath) {
|
|
|
60373
60413
|
console.log(readLog(gather.log).replace(CONTROL_SEQUENCE, "").trimEnd());
|
|
60374
60414
|
const gatherFaults = engineFaults(gather, options.godotVersion);
|
|
60375
60415
|
const gatheredFile = join24(shareDirectory, "gathered.arms");
|
|
60376
|
-
const gathered = new Set((
|
|
60416
|
+
const gathered = new Set((existsSync20(gatheredFile) ? armsPlayed(readFileSync22(gatheredFile, "utf8")) ?? [] : []).map((arm) => arm.arm));
|
|
60377
60417
|
const ungathered = (arms[0] ?? []).filter((arm) => !gathered.has(arm.arm)).map((arm) => arm.arm);
|
|
60378
60418
|
if (ungathered.length > 0) {
|
|
60379
60419
|
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 +60464,7 @@ function engineFaults(engine, godotVersion) {
|
|
|
60424
60464
|
const said = code === null ? "without an exit code" : code >>> 0 >= WINDOWS_EXCEPTION2 ? exitNamed(code) : String(code);
|
|
60425
60465
|
faults.push(`${engine.name}: the engine exited ${said}`);
|
|
60426
60466
|
}
|
|
60427
|
-
if (!
|
|
60467
|
+
if (!existsSync20(engine.log)) {
|
|
60428
60468
|
return faults;
|
|
60429
60469
|
}
|
|
60430
60470
|
const printed = readRun(readLog(engine.log));
|
|
@@ -60440,7 +60480,7 @@ function engineFaults(engine, godotVersion) {
|
|
|
60440
60480
|
}
|
|
60441
60481
|
function progressOf(logs) {
|
|
60442
60482
|
const each = logs.map((log, index) => {
|
|
60443
|
-
const text =
|
|
60483
|
+
const text = existsSync20(log) ? readLog(log) : "";
|
|
60444
60484
|
const last = [...text.matchAll(PROGRESS)].at(-1);
|
|
60445
60485
|
return last === undefined ? `worker ${String(index)} has played no arm yet` : `worker ${String(index)} at ${last[1] ?? ""} ${last[2] ?? ""} of ${last[3] ?? ""}`;
|
|
60446
60486
|
});
|
|
@@ -60472,7 +60512,7 @@ init_reimport();
|
|
|
60472
60512
|
init_setup();
|
|
60473
60513
|
import {
|
|
60474
60514
|
copyFileSync,
|
|
60475
|
-
existsSync as
|
|
60515
|
+
existsSync as existsSync23,
|
|
60476
60516
|
mkdirSync as mkdirSync10,
|
|
60477
60517
|
readdirSync as readdirSync15,
|
|
60478
60518
|
readFileSync as readFileSync26,
|
|
@@ -60483,12 +60523,13 @@ import {
|
|
|
60483
60523
|
import { availableParallelism as availableParallelism5 } from "node:os";
|
|
60484
60524
|
import { dirname as dirname13, join as join28, relative as relative5, resolve as resolve11, sep as sep4 } from "node:path";
|
|
60485
60525
|
import process14 from "node:process";
|
|
60526
|
+
import { setTimeout as delay5 } from "node:timers/promises";
|
|
60486
60527
|
|
|
60487
60528
|
// src/suite-inputs.ts
|
|
60488
60529
|
init_class_cache();
|
|
60489
60530
|
init_gdscript_source();
|
|
60490
60531
|
import { createHash as createHash6 } from "node:crypto";
|
|
60491
|
-
import { existsSync as
|
|
60532
|
+
import { existsSync as existsSync21, readdirSync as readdirSync14, readFileSync as readFileSync23, statSync as statSync13 } from "node:fs";
|
|
60492
60533
|
import { join as join25, posix as posix2 } from "node:path";
|
|
60493
60534
|
var EVERY_FILE = "res://";
|
|
60494
60535
|
var CACHE_HELD = "cache:";
|
|
@@ -60506,7 +60547,7 @@ var ADDON = /^res:\/\/addons\/[^/]+\//;
|
|
|
60506
60547
|
var TEXT_RESOURCE = /\.(?:tscn|tres|gdextension)$/;
|
|
60507
60548
|
function reachedBySuite(file) {
|
|
60508
60549
|
const bySuite = new Map;
|
|
60509
|
-
if (!
|
|
60550
|
+
if (!existsSync21(file)) {
|
|
60510
60551
|
return bySuite;
|
|
60511
60552
|
}
|
|
60512
60553
|
const paths = (value) => Array.isArray(value) ? value.filter((path) => typeof path === "string") : [];
|
|
@@ -60616,7 +60657,7 @@ ${this.read(path).digest}
|
|
|
60616
60657
|
const hash = createHash6("sha256");
|
|
60617
60658
|
let modified = 0;
|
|
60618
60659
|
const directory = join25(this.scripts.projectPath, root.slice("res://".length));
|
|
60619
|
-
if (
|
|
60660
|
+
if (existsSync21(directory)) {
|
|
60620
60661
|
walkSeen(directory, (file, under, stat) => {
|
|
60621
60662
|
hash.update(`${under}
|
|
60622
60663
|
`).update(readFileSync23(file));
|
|
@@ -60627,7 +60668,7 @@ ${this.read(path).digest}
|
|
|
60627
60668
|
}
|
|
60628
60669
|
readAnew(path) {
|
|
60629
60670
|
const file = join25(this.scripts.projectPath, path.slice("res://".length));
|
|
60630
|
-
if (!
|
|
60671
|
+
if (!existsSync21(file)) {
|
|
60631
60672
|
return { digest: "missing", follows: [], also: [], modified: 0 };
|
|
60632
60673
|
}
|
|
60633
60674
|
const stat = statSync13(file);
|
|
@@ -60638,12 +60679,12 @@ ${this.read(path).digest}
|
|
|
60638
60679
|
}
|
|
60639
60680
|
const bytes = readFileSync23(file);
|
|
60640
60681
|
const digest = createHash6("sha256").update(bytes).digest("hex");
|
|
60641
|
-
const also = [`${path}.import`, `${path}.uid`].filter((beside) =>
|
|
60682
|
+
const also = [`${path}.import`, `${path}.uid`].filter((beside) => existsSync21(join25(this.scripts.projectPath, beside.slice("res://".length))));
|
|
60642
60683
|
const follows = [];
|
|
60643
60684
|
if (TEXT_RESOURCE.test(path)) {
|
|
60644
60685
|
for (const [named] of bytes.toString("latin1").matchAll(RES_LITERAL)) {
|
|
60645
60686
|
const target = join25(this.scripts.projectPath, named.slice("res://".length));
|
|
60646
|
-
(
|
|
60687
|
+
(existsSync21(target) && statSync13(target).isDirectory() ? also : follows).push(named);
|
|
60647
60688
|
}
|
|
60648
60689
|
} else if (path.endsWith(".gd")) {
|
|
60649
60690
|
const reaches = this.scriptReaches(path);
|
|
@@ -60830,7 +60871,7 @@ function joinedString(expression, named) {
|
|
|
60830
60871
|
}
|
|
60831
60872
|
function walkSeen(root, seen) {
|
|
60832
60873
|
const walk = (directory, under) => {
|
|
60833
|
-
if (
|
|
60874
|
+
if (existsSync21(join25(directory, ".gdignore"))) {
|
|
60834
60875
|
return;
|
|
60835
60876
|
}
|
|
60836
60877
|
for (const entry of readdirSync14(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
@@ -60848,7 +60889,7 @@ function walkSeen(root, seen) {
|
|
|
60848
60889
|
}
|
|
60849
60890
|
function extensionsOf(projectPath) {
|
|
60850
60891
|
const list = join25(projectPath, ".godot", "extension_list.cfg");
|
|
60851
|
-
return
|
|
60892
|
+
return existsSync21(list) ? readFileSync23(list, "utf8").split(`
|
|
60852
60893
|
`).map((line) => line.trim()).filter((line) => line.startsWith("res://")) : [];
|
|
60853
60894
|
}
|
|
60854
60895
|
|
|
@@ -60879,6 +60920,7 @@ function getLocalVersion() {
|
|
|
60879
60920
|
|
|
60880
60921
|
// src/suite-run.ts
|
|
60881
60922
|
var LAST_RUN_FILE = "last-run.json";
|
|
60923
|
+
var COMPILED_FILE = "compiled-together.json";
|
|
60882
60924
|
var SLOWEST_NAMED = 5;
|
|
60883
60925
|
var SILENCE_TIMES_TAKEN = 4;
|
|
60884
60926
|
function silenceWhile(running, times, floorSeconds) {
|
|
@@ -60936,9 +60978,9 @@ function testOptionsOf(args, cwd) {
|
|
|
60936
60978
|
}
|
|
60937
60979
|
const first = positional[0];
|
|
60938
60980
|
const named = first === undefined ? null : resolve11(cwd, first);
|
|
60939
|
-
const projectNamed = named !== null &&
|
|
60981
|
+
const projectNamed = named !== null && existsSync23(join28(named, "project.godot"));
|
|
60940
60982
|
const projectPath = projectNamed ? named : resolve11(cwd);
|
|
60941
|
-
if (!
|
|
60983
|
+
if (!existsSync23(join28(projectPath, "project.godot"))) {
|
|
60942
60984
|
throw new EngineUsageError(`Not a Godot project: ${projectPath} holds no project.godot.`);
|
|
60943
60985
|
}
|
|
60944
60986
|
const last = (flag) => valued.get(flag)?.at(-1);
|
|
@@ -60973,12 +61015,12 @@ function seedOf(value) {
|
|
|
60973
61015
|
return seed;
|
|
60974
61016
|
}
|
|
60975
61017
|
function rootsOf(options) {
|
|
60976
|
-
return options.roots.length > 0 ? options.roots : TEST_DIRECTORIES.filter((root) =>
|
|
61018
|
+
return options.roots.length > 0 ? options.roots : TEST_DIRECTORIES.filter((root) => existsSync23(join28(options.projectPath, root))).map((root) => `res://${root}`);
|
|
60977
61019
|
}
|
|
60978
61020
|
function searchedRoots(options) {
|
|
60979
61021
|
return options.selected.length === 0 ? rootsOf(options) : options.selected.filter((entry) => {
|
|
60980
61022
|
const directory = join28(options.projectPath, entry.slice("res://".length));
|
|
60981
|
-
return
|
|
61023
|
+
return existsSync23(directory) && statSync14(directory).isDirectory();
|
|
60982
61024
|
});
|
|
60983
61025
|
}
|
|
60984
61026
|
function selectedSuites(scripts, options) {
|
|
@@ -60995,9 +61037,9 @@ function selectedSuites(scripts, options) {
|
|
|
60995
61037
|
const caseAt = /^(res:\/\/.*\.gd):(\w+)$/.exec(entry);
|
|
60996
61038
|
const path = caseAt?.[1] ?? entry;
|
|
60997
61039
|
const directory = join28(options.projectPath, path.slice(6));
|
|
60998
|
-
const suites =
|
|
61040
|
+
const suites = existsSync23(directory) && statSync14(directory).isDirectory() ? scripts.suitesUnder([path.replace(/\/$/, "")]) : [scripts.suite(path)].filter((suite) => suite !== null);
|
|
60999
61041
|
if (suites.length === 0) {
|
|
61000
|
-
throw new EngineUsageError(
|
|
61042
|
+
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
61043
|
}
|
|
61002
61044
|
for (const suite of suites) {
|
|
61003
61045
|
const picked = chosen.get(suite.path) ?? { suite, cases: new Set };
|
|
@@ -61121,11 +61163,11 @@ async function runTestCommand(options, godotPath) {
|
|
|
61121
61163
|
failsOnPushErrors: gdUnitFailsOnPushErrors(options.projectPath)
|
|
61122
61164
|
};
|
|
61123
61165
|
try {
|
|
61124
|
-
const
|
|
61125
|
-
if (
|
|
61126
|
-
console.log(
|
|
61166
|
+
const needed = options.importFirst ? null : importNeeded(options.projectPath);
|
|
61167
|
+
if (needed !== null) {
|
|
61168
|
+
console.log(needed);
|
|
61127
61169
|
}
|
|
61128
|
-
if (options.importFirst ||
|
|
61170
|
+
if (options.importFirst || needed !== null) {
|
|
61129
61171
|
const imported = await importProject(launch);
|
|
61130
61172
|
if (imported !== null) {
|
|
61131
61173
|
logs.keep();
|
|
@@ -61140,9 +61182,10 @@ async function runTestCommand(options, godotPath) {
|
|
|
61140
61182
|
readFileSync26(shippedListedRunner(), "utf8"),
|
|
61141
61183
|
engineSaid(godotPath),
|
|
61142
61184
|
...options.reachAlso.map((path) => `${path}
|
|
61143
|
-
${
|
|
61185
|
+
${existsSync23(path) ? readFileSync26(path, "latin1") : "missing"}`)
|
|
61144
61186
|
];
|
|
61145
61187
|
const everySuite = suites;
|
|
61188
|
+
const compileKept = options.changedOnly ? { file: join28(state, COMPILED_FILE), scripts, always } : null;
|
|
61146
61189
|
if (options.changedOnly) {
|
|
61147
61190
|
const inputs = new SuiteInputs(scripts, always);
|
|
61148
61191
|
const passedBefore = readPassed(passedFile);
|
|
@@ -61156,7 +61199,7 @@ ${existsSync24(path) ? readFileSync26(path, "latin1") : "missing"}`)
|
|
|
61156
61199
|
}
|
|
61157
61200
|
if (suites.length === 0) {
|
|
61158
61201
|
console.log("Nothing has changed since every suite last passed.");
|
|
61159
|
-
const compiled = await
|
|
61202
|
+
const compiled = await compileUnlessUnchanged(launch, everySuite, compileKept);
|
|
61160
61203
|
const problems = [...compiled.faults.map((fault) => `${COMPILE_CHECK}: ${fault}`), ...uncollected];
|
|
61161
61204
|
if (problems.length === 0) {
|
|
61162
61205
|
rmSync13(runDirectory, { recursive: true, force: true });
|
|
@@ -61179,12 +61222,18 @@ ${existsSync24(path) ? readFileSync26(path, "latin1") : "missing"}`)
|
|
|
61179
61222
|
if (memory.unread !== undefined) {
|
|
61180
61223
|
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
61224
|
}
|
|
61182
|
-
const
|
|
61225
|
+
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")}`);
|
|
61226
|
+
const byMemory = roomWith(memory.bytes);
|
|
61227
|
+
const unheld = roomWith(Number.POSITIVE_INFINITY);
|
|
61228
|
+
const unheldUnits = unitsOf(suites, times, splitPastFor(suites, times, unheld.engines));
|
|
61229
|
+
const heldLanes = lanesOf(dealt(unheldUnits, declared, unheld.engines));
|
|
61230
|
+
const memoryHeld = options.order === null && byMemory.engines < heldLanes;
|
|
61231
|
+
const room = memoryHeld ? unheld : byMemory;
|
|
61183
61232
|
if (options.cores !== null && process14.platform === "darwin") {
|
|
61184
61233
|
console.log("macOS offers no way to hold a process to some processors, so --cores holds only the number of engines here.");
|
|
61185
61234
|
}
|
|
61186
61235
|
const splitPast = splitPastFor(suites, times, room.engines);
|
|
61187
|
-
const units = unitsOf(suites, times, splitPast);
|
|
61236
|
+
const units = memoryHeld ? unheldUnits : unitsOf(suites, times, splitPast);
|
|
61188
61237
|
const past = splitPast > SPLIT_PAST_SECONDS ? `an engine's share of this run (${String(Math.round(splitPast))} s)` : `${String(SPLIT_PAST_SECONDS)} s`;
|
|
61189
61238
|
const plans = options.order === null ? dealt(units, declared, room.engines) : [inOneEngine(ordered(units, options.order), declared)];
|
|
61190
61239
|
const functions = suites.reduce((sum, suite) => sum + suite.cases.length, 0);
|
|
@@ -61217,24 +61266,28 @@ ${existsSync24(path) ? readFileSync26(path, "latin1") : "missing"}`)
|
|
|
61217
61266
|
say(`Kept whole in one engine, since ${one ? "it declares" : "each declares"} GDHARNESS_TOGETHER: ${named(keptWhole)}.`);
|
|
61218
61267
|
}
|
|
61219
61268
|
const lanes = [...new Set(plans.map((plan) => plan.lane))].map((lane) => plans.flatMap((plan, index) => plan.lane === lane ? [{ plan, index }] : []));
|
|
61269
|
+
const startable = memoryHeld ? Math.min(byMemory.engines, lanes.length) : lanes.length;
|
|
61220
61270
|
const taken = [];
|
|
61221
|
-
while (taken.length <
|
|
61271
|
+
while (taken.length < startable) {
|
|
61222
61272
|
const lock = await slots.takeFree();
|
|
61223
61273
|
if (lock === null) {
|
|
61224
61274
|
break;
|
|
61225
61275
|
}
|
|
61226
61276
|
taken.push(lock);
|
|
61227
61277
|
}
|
|
61228
|
-
|
|
61229
|
-
|
|
61230
|
-
|
|
61278
|
+
if (memoryHeld) {
|
|
61279
|
+
say(memorySaid(byMemory.engines, lanes.length, byMemory.held ?? ""));
|
|
61280
|
+
}
|
|
61281
|
+
const shared = options.order === null && lanes.length > 1 && (memoryHeld || taken.length < lanes.length);
|
|
61282
|
+
if (shared && taken.length < startable) {
|
|
61283
|
+
say(sharesSaid(taken.length, startable));
|
|
61231
61284
|
}
|
|
61232
61285
|
const handed = new HandedSlot;
|
|
61233
|
-
const compiling =
|
|
61286
|
+
const compiling = compileUnlessUnchanged(launch, everySuite, compileKept, handed);
|
|
61234
61287
|
compiling.catch(() => {
|
|
61235
61288
|
return;
|
|
61236
61289
|
});
|
|
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);
|
|
61290
|
+
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
61291
|
if (ran.some((engine) => engine.verdict.starved) && ran.some((engine) => !engine.verdict.passed)) {
|
|
61239
61292
|
say("An engine ran out of memory, so every engine that failed runs again, one at a time.");
|
|
61240
61293
|
const again = [];
|
|
@@ -61261,6 +61314,55 @@ ${existsSync24(path) ? readFileSync26(path, "latin1") : "missing"}`)
|
|
|
61261
61314
|
function sharesSaid(free, lanes) {
|
|
61262
61315
|
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
61316
|
}
|
|
61317
|
+
function memorySaid(room, lanes, held) {
|
|
61318
|
+
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.`;
|
|
61319
|
+
}
|
|
61320
|
+
var MEMORY_LOOK_MS = 2000;
|
|
61321
|
+
var ENGINE_SETTLING_MS = 30000;
|
|
61322
|
+
|
|
61323
|
+
class MemoryGate {
|
|
61324
|
+
slots;
|
|
61325
|
+
read;
|
|
61326
|
+
now;
|
|
61327
|
+
lookMs;
|
|
61328
|
+
going = new Set;
|
|
61329
|
+
turn = Promise.resolve();
|
|
61330
|
+
constructor(slots, read, now = Date.now, lookMs = MEMORY_LOOK_MS) {
|
|
61331
|
+
this.slots = slots;
|
|
61332
|
+
this.read = read;
|
|
61333
|
+
this.now = now;
|
|
61334
|
+
this.lookMs = lookMs;
|
|
61335
|
+
}
|
|
61336
|
+
admit(signal) {
|
|
61337
|
+
const admitted = this.turn.then(() => this.room(signal));
|
|
61338
|
+
this.turn = admitted.catch(() => {
|
|
61339
|
+
return;
|
|
61340
|
+
});
|
|
61341
|
+
return admitted;
|
|
61342
|
+
}
|
|
61343
|
+
async room(signal) {
|
|
61344
|
+
let unmark;
|
|
61345
|
+
try {
|
|
61346
|
+
for (;; ) {
|
|
61347
|
+
signal.throwIfAborted();
|
|
61348
|
+
const at = this.now();
|
|
61349
|
+
const starting = [...this.going].filter((one) => at - one.at < ENGINE_SETTLING_MS).length;
|
|
61350
|
+
if (this.going.size === 0 || roomForAnother(await this.read(), starting)) {
|
|
61351
|
+
break;
|
|
61352
|
+
}
|
|
61353
|
+
unmark ??= this.slots.markWaiting();
|
|
61354
|
+
await delay5(this.lookMs, undefined, { signal });
|
|
61355
|
+
}
|
|
61356
|
+
} finally {
|
|
61357
|
+
unmark?.();
|
|
61358
|
+
}
|
|
61359
|
+
const engine = { at: this.now() };
|
|
61360
|
+
this.going.add(engine);
|
|
61361
|
+
return () => {
|
|
61362
|
+
this.going.delete(engine);
|
|
61363
|
+
};
|
|
61364
|
+
}
|
|
61365
|
+
}
|
|
61264
61366
|
function roomSaid(engines, lanes, unheld, held, asked) {
|
|
61265
61367
|
if (held === undefined || lanes >= unheld) {
|
|
61266
61368
|
return "";
|
|
@@ -61286,7 +61388,7 @@ function readPassed(file) {
|
|
|
61286
61388
|
function recordPassed(file, projectPath, ran, failedAcross, inputs, began) {
|
|
61287
61389
|
const passed = readPassed(file);
|
|
61288
61390
|
for (const path of Object.keys(passed)) {
|
|
61289
|
-
if (!
|
|
61391
|
+
if (!existsSync23(join28(projectPath, path.slice("res://".length)))) {
|
|
61290
61392
|
delete passed[path];
|
|
61291
61393
|
}
|
|
61292
61394
|
}
|
|
@@ -61335,6 +61437,9 @@ class HandedSlot {
|
|
|
61335
61437
|
lock = new Promise((resolve) => {
|
|
61336
61438
|
this.handOver = resolve;
|
|
61337
61439
|
});
|
|
61440
|
+
decline() {
|
|
61441
|
+
this.wanted = false;
|
|
61442
|
+
}
|
|
61338
61443
|
give(lock) {
|
|
61339
61444
|
if (!this.wanted) {
|
|
61340
61445
|
return false;
|
|
@@ -61388,6 +61493,41 @@ async function compileCheck(launch, suites, handed) {
|
|
|
61388
61493
|
}
|
|
61389
61494
|
return { faults: judgeCompile(readRun(readFileSync26(log, "utf8")), end), log };
|
|
61390
61495
|
}
|
|
61496
|
+
function compiledPrint(kept, projectPath, suites) {
|
|
61497
|
+
const inputs = new SuiteInputs(kept.scripts, kept.always);
|
|
61498
|
+
const classes = [...cachedClasses(projectPath)?.values() ?? []];
|
|
61499
|
+
const read = inputs.inputsOf([...suites.map((suite) => suite.path), ...classes]);
|
|
61500
|
+
return { inputs, read, print: inputs.printOf(read) };
|
|
61501
|
+
}
|
|
61502
|
+
async function compileUnlessUnchanged(launch, suites, kept, handed) {
|
|
61503
|
+
if (kept === null) {
|
|
61504
|
+
return compileCheck(launch, suites, handed);
|
|
61505
|
+
}
|
|
61506
|
+
const before = compiledPrint(kept, launch.projectPath, suites).print;
|
|
61507
|
+
if (readKeptPrint(kept.file) === before) {
|
|
61508
|
+
handed?.decline();
|
|
61509
|
+
console.log("Every script compiled together on these same files when last checked, so it is not compiled again.");
|
|
61510
|
+
return { faults: [], log: "" };
|
|
61511
|
+
}
|
|
61512
|
+
const began = Date.now();
|
|
61513
|
+
const compiled = await compileCheck(launch, suites, handed);
|
|
61514
|
+
const after = compiledPrint(kept, launch.projectPath, suites);
|
|
61515
|
+
if (compiled.faults.length === 0 && !after.inputs.modifiedAfter(after.read, began)) {
|
|
61516
|
+
writeJson(kept.file, { print: after.print });
|
|
61517
|
+
} else {
|
|
61518
|
+
rmSync13(kept.file, { force: true });
|
|
61519
|
+
}
|
|
61520
|
+
return compiled;
|
|
61521
|
+
}
|
|
61522
|
+
function readKeptPrint(file) {
|
|
61523
|
+
try {
|
|
61524
|
+
const parsed = JSON.parse(readFileSync26(file, "utf8"));
|
|
61525
|
+
const print = parsed?.print;
|
|
61526
|
+
return typeof print === "string" ? print : null;
|
|
61527
|
+
} catch {
|
|
61528
|
+
return null;
|
|
61529
|
+
}
|
|
61530
|
+
}
|
|
61391
61531
|
function printCompiled(compiled, logs) {
|
|
61392
61532
|
if (compiled.faults.length === 0) {
|
|
61393
61533
|
return;
|
|
@@ -61412,6 +61552,21 @@ function importFault(printed) {
|
|
|
61412
61552
|
].join(" and ");
|
|
61413
61553
|
return `it printed ${counted}, the first ${first.warning ? "warning" : "error"} ${JSON.stringify(first.text)}`;
|
|
61414
61554
|
}
|
|
61555
|
+
function importNeeded(projectPath) {
|
|
61556
|
+
const cached = cachedClasses(projectPath);
|
|
61557
|
+
if (cached === null) {
|
|
61558
|
+
return "The project has never been imported, so it is imported first.";
|
|
61559
|
+
}
|
|
61560
|
+
const unlisted = unlistedExtensions(projectPath);
|
|
61561
|
+
if (unlisted.length > 0) {
|
|
61562
|
+
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.`;
|
|
61563
|
+
}
|
|
61564
|
+
const uncached = staleAgainst(cached, projectPath).sort();
|
|
61565
|
+
if (uncached.length > 0) {
|
|
61566
|
+
return `The class cache does not list ${named(uncached)} where the scripts declare ${uncached.length === 1 ? "it" : "them"}, so the project is imported first.`;
|
|
61567
|
+
}
|
|
61568
|
+
return null;
|
|
61569
|
+
}
|
|
61415
61570
|
async function importProject(launch) {
|
|
61416
61571
|
const seeded = seedExtensionList(launch.projectPath);
|
|
61417
61572
|
if (seeded !== null && seeded.length > 0) {
|
|
@@ -61459,35 +61614,48 @@ async function runLane(launch, lane, times, taken, handed) {
|
|
|
61459
61614
|
doneWith(launch, lock, handed);
|
|
61460
61615
|
}
|
|
61461
61616
|
}
|
|
61462
|
-
async function runShares(launch, units, declared, lanes, taken, times, handed) {
|
|
61617
|
+
async function runShares(launch, units, declared, lanes, taken, times, handed, memory) {
|
|
61463
61618
|
const shares = new Shares(units, declared, lanes);
|
|
61464
61619
|
const handedOut = new AbortController;
|
|
61465
61620
|
let engines = 0;
|
|
61621
|
+
const empty = () => shares.empty;
|
|
61466
61622
|
const lane = async (at) => {
|
|
61467
61623
|
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
|
-
}
|
|
61624
|
+
const ran = [];
|
|
61478
61625
|
try {
|
|
61479
|
-
|
|
61480
|
-
|
|
61481
|
-
|
|
61626
|
+
while (!empty()) {
|
|
61627
|
+
let ended;
|
|
61628
|
+
try {
|
|
61629
|
+
ended = await memory?.admit(handedOut.signal);
|
|
61630
|
+
lock ??= await launch.slots.take(handedOut.signal);
|
|
61631
|
+
} catch (error) {
|
|
61632
|
+
ended?.();
|
|
61633
|
+
if (handedOut.signal.aborted) {
|
|
61634
|
+
break;
|
|
61635
|
+
}
|
|
61636
|
+
throw error;
|
|
61637
|
+
}
|
|
61638
|
+
const plan = shares.next(at);
|
|
61639
|
+
if (plan === null) {
|
|
61640
|
+
ended?.();
|
|
61641
|
+
break;
|
|
61642
|
+
}
|
|
61643
|
+
if (empty()) {
|
|
61482
61644
|
handedOut.abort();
|
|
61483
61645
|
}
|
|
61484
61646
|
const index = engines;
|
|
61485
61647
|
engines += 1;
|
|
61486
|
-
|
|
61648
|
+
try {
|
|
61649
|
+
ran.push(await runEngine2(launch, plan, index, times, "", lock));
|
|
61650
|
+
} finally {
|
|
61651
|
+
ended?.();
|
|
61652
|
+
}
|
|
61487
61653
|
}
|
|
61488
61654
|
return ran;
|
|
61489
61655
|
} finally {
|
|
61490
|
-
|
|
61656
|
+
if (lock !== null) {
|
|
61657
|
+
doneWith(launch, lock, handed);
|
|
61658
|
+
}
|
|
61491
61659
|
}
|
|
61492
61660
|
};
|
|
61493
61661
|
return (await Promise.all(Array.from({ length: lanes }, (_, at) => lane(at)))).flat().sort((a, b) => a.index - b.index);
|
|
@@ -61582,7 +61750,7 @@ async function runEngine2(launch, plan, index, times, again = "", slot = null) {
|
|
|
61582
61750
|
}
|
|
61583
61751
|
var REPORT_FILES_NAMED = 3;
|
|
61584
61752
|
function reportsFault(reports) {
|
|
61585
|
-
const files =
|
|
61753
|
+
const files = existsSync23(reports) ? readdirSync15(reports, { recursive: true, encoding: "utf8" }).filter((file) => statSync14(join28(reports, file)).isFile()).sort() : [];
|
|
61586
61754
|
if (files.length === 0) {
|
|
61587
61755
|
return null;
|
|
61588
61756
|
}
|
|
@@ -61595,7 +61763,7 @@ function report(ran, compiled, across, uncollected, startedAt, logs, printOutput
|
|
|
61595
61763
|
for (const engine of ran) {
|
|
61596
61764
|
console.log("");
|
|
61597
61765
|
console.log(`--- what engine ${String(engine.index)} printed, running ${named(engine.plan.suites.map((suite) => suite.path))}:`);
|
|
61598
|
-
console.log(
|
|
61766
|
+
console.log(existsSync23(engine.log) ? readLog(engine.log).replace(CONTROL_SEQUENCE, "").trimEnd() : "(no log was written)");
|
|
61599
61767
|
}
|
|
61600
61768
|
}
|
|
61601
61769
|
const failed = ran.filter((engine) => !engine.verdict.passed);
|
|
@@ -61606,7 +61774,7 @@ function report(ran, compiled, across, uncollected, startedAt, logs, printOutput
|
|
|
61606
61774
|
for (const fault of engine.verdict.faults) {
|
|
61607
61775
|
console.log(` ${fault}`);
|
|
61608
61776
|
}
|
|
61609
|
-
if (
|
|
61777
|
+
if (existsSync23(engine.log)) {
|
|
61610
61778
|
const verdict = [
|
|
61611
61779
|
`gdharness: ${heading.slice(4)}`,
|
|
61612
61780
|
...engine.verdict.faults.map((fault) => ` ${fault}`)
|
|
@@ -61701,6 +61869,9 @@ function report(ran, compiled, across, uncollected, startedAt, logs, printOutput
|
|
|
61701
61869
|
const problems = failed.reduce((sum, engine) => sum + engine.verdict.faults.length, compiled.faults.length + across.length + uncollected.length);
|
|
61702
61870
|
console.log(`Failed: ${plural(problems, "problem")}, listed above. Ran ${totals}`);
|
|
61703
61871
|
console.log(`Every engine's output is kept under ${logs.shown} until ${String(KEPT_RUN_DIRECTORIES)} later runs have failed.`);
|
|
61872
|
+
if (logs.shown !== logs.directory) {
|
|
61873
|
+
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.`);
|
|
61874
|
+
}
|
|
61704
61875
|
return 1;
|
|
61705
61876
|
}
|
|
61706
61877
|
function writeEarlyResult(targets, startedAt, problems, logs) {
|
|
@@ -61742,7 +61913,7 @@ class UsageError extends Refusal {
|
|
|
61742
61913
|
function projectArgument(at) {
|
|
61743
61914
|
const named = args.slice(at).find((value) => !value.startsWith("--"));
|
|
61744
61915
|
const projectPath = resolve15(named ?? ".");
|
|
61745
|
-
if (!
|
|
61916
|
+
if (!existsSync35(join45(projectPath, "project.godot"))) {
|
|
61746
61917
|
throw new UsageError(`Not a Godot project: ${projectPath} holds no project.godot.`);
|
|
61747
61918
|
}
|
|
61748
61919
|
return projectPath;
|
|
@@ -61806,7 +61977,7 @@ async function registerRuntime(godot, projectPath) {
|
|
|
61806
61977
|
}
|
|
61807
61978
|
const path = (named ?? "").replace(/^res:\/\//, "");
|
|
61808
61979
|
console.log(`${RUNTIME_AUTOLOAD.name} autoload left at ${named}, which this project registers itself`);
|
|
61809
|
-
if (!
|
|
61980
|
+
if (!existsSync35(join45(projectPath, path))) {
|
|
61810
61981
|
console.log(" that file is not in this project, so it boots with a missing script");
|
|
61811
61982
|
}
|
|
61812
61983
|
console.log(` ${useTheShippedLoader(RUNTIME_AUTOLOAD.name, path)}`);
|
|
@@ -61939,7 +62110,7 @@ async function setup() {
|
|
|
61939
62110
|
console.log("no harness configured; name one yourself, and gdharness harnesses lists them all");
|
|
61940
62111
|
}
|
|
61941
62112
|
if (!args.includes("--no-skill")) {
|
|
61942
|
-
const directories = skillDirectories(chosen.harnesses, projectPath,
|
|
62113
|
+
const directories = skillDirectories(chosen.harnesses, projectPath, existsSync35);
|
|
61943
62114
|
for (const written of writeSkill(directories, getLocalVersion())) {
|
|
61944
62115
|
console.log(`skill: ${written.replaced ? "replaced" : "written"} ${written.path}`);
|
|
61945
62116
|
}
|
|
@@ -62059,7 +62230,7 @@ async function upgrade() {
|
|
|
62059
62230
|
moved.push(took.from);
|
|
62060
62231
|
}
|
|
62061
62232
|
}
|
|
62062
|
-
for (const written of writeSkill(skillDirectories(already, projectPath,
|
|
62233
|
+
for (const written of writeSkill(skillDirectories(already, projectPath, existsSync35), version)) {
|
|
62063
62234
|
console.log(`skill: ${written.replaced ? "replaced" : "written"} ${written.path}`);
|
|
62064
62235
|
}
|
|
62065
62236
|
console.log(`
|