gdharness 1.3.54 → 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
|
@@ -800,6 +800,30 @@ public static class GdhProcessTable
|
|
|
800
800
|
return "";
|
|
801
801
|
}
|
|
802
802
|
|
|
803
|
+
/// <summary>"pid seconds" on a line for each running one of the comma-separated pids, from one snapshot.</summary>
|
|
804
|
+
public static string ProcessorSecondsOf(string pids)
|
|
805
|
+
{
|
|
806
|
+
HashSet<int> wanted = new HashSet<int>();
|
|
807
|
+
foreach (string one in pids.Split(','))
|
|
808
|
+
{
|
|
809
|
+
int pid;
|
|
810
|
+
if (int.TryParse(one, NumberStyles.Integer, CultureInfo.InvariantCulture, out pid))
|
|
811
|
+
{
|
|
812
|
+
wanted.Add(pid);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
StringBuilder said = new StringBuilder();
|
|
816
|
+
foreach (Entry entry in Snapshot())
|
|
817
|
+
{
|
|
818
|
+
if (wanted.Contains(entry.Pid))
|
|
819
|
+
{
|
|
820
|
+
said.Append(Number(entry.Pid)).Append(' ')
|
|
821
|
+
.Append((entry.Processor / 1e7).ToString("R", CultureInfo.InvariantCulture)).Append('\n');
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
return said.ToString();
|
|
825
|
+
}
|
|
826
|
+
|
|
803
827
|
/// <summary>How many more bytes Windows will commit.</summary>
|
|
804
828
|
public static string CommitLeft()
|
|
805
829
|
{
|
|
@@ -1693,7 +1717,6 @@ var init_whole_file = __esm(() => {
|
|
|
1693
1717
|
// src/engine-slots.ts
|
|
1694
1718
|
import {
|
|
1695
1719
|
closeSync as closeSync2,
|
|
1696
|
-
existsSync as existsSync2,
|
|
1697
1720
|
mkdirSync as mkdirSync2,
|
|
1698
1721
|
openSync as openSync2,
|
|
1699
1722
|
readdirSync,
|
|
@@ -1737,8 +1760,14 @@ function machineSlots(asked = {
|
|
|
1737
1760
|
function nonEmpty(value) {
|
|
1738
1761
|
return value === undefined || value === "" ? undefined : value;
|
|
1739
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
|
+
}
|
|
1740
1769
|
function slotsDrawnOn(count, taker, queue) {
|
|
1741
|
-
const gated = Math.max(1, count -
|
|
1770
|
+
const gated = Math.max(1, count - keptSlotsOf(count));
|
|
1742
1771
|
if (taker === "gate") {
|
|
1743
1772
|
return { numbers: Array.from({ length: gated }, (_, slot) => slot), limit: "gate" };
|
|
1744
1773
|
}
|
|
@@ -1750,10 +1779,7 @@ function slotsDrawnOn(count, taker, queue) {
|
|
|
1750
1779
|
if (taker === "tier") {
|
|
1751
1780
|
return { numbers: [...kept].reverse(), limit: "tier" };
|
|
1752
1781
|
}
|
|
1753
|
-
|
|
1754
|
-
return { numbers: [], limit: "held" };
|
|
1755
|
-
}
|
|
1756
|
-
return { numbers: kept.slice(0, 1), limit: "kept" };
|
|
1782
|
+
return { numbers: kept.slice(0, Math.max(1, kept.length - GATE_KEPT)), limit: "kept" };
|
|
1757
1783
|
}
|
|
1758
1784
|
function inAGate(env = process4.env) {
|
|
1759
1785
|
return nonEmpty(env[SHARE_VARIABLE]) !== undefined && nonEmpty(env[SHARE_COUNT_VARIABLE]) !== undefined;
|
|
@@ -1828,11 +1854,16 @@ function holderOf(content) {
|
|
|
1828
1854
|
if (typeof parsed !== "object" || parsed === null) {
|
|
1829
1855
|
return null;
|
|
1830
1856
|
}
|
|
1831
|
-
const { pid, started, by } = parsed;
|
|
1857
|
+
const { pid, started, by, game } = parsed;
|
|
1832
1858
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || typeof started !== "number") {
|
|
1833
1859
|
return null;
|
|
1834
1860
|
}
|
|
1835
|
-
return
|
|
1861
|
+
return {
|
|
1862
|
+
pid,
|
|
1863
|
+
started,
|
|
1864
|
+
...typeof by === "string" && by !== "" ? { by } : {},
|
|
1865
|
+
...game === true ? { game } : {}
|
|
1866
|
+
};
|
|
1836
1867
|
} catch {
|
|
1837
1868
|
return null;
|
|
1838
1869
|
}
|
|
@@ -1873,7 +1904,7 @@ class EngineSlots {
|
|
|
1873
1904
|
this.taker = taker;
|
|
1874
1905
|
this.drawn = slotsDrawnOn(count, taker(), "none");
|
|
1875
1906
|
}
|
|
1876
|
-
async take(signal, waiting, blocked) {
|
|
1907
|
+
async take(signal, waiting, blocked, game = false) {
|
|
1877
1908
|
mkdirSync2(this.directory, { recursive: true });
|
|
1878
1909
|
const began = Date.now();
|
|
1879
1910
|
let said = Number.NEGATIVE_INFINITY;
|
|
@@ -1882,7 +1913,7 @@ class EngineSlots {
|
|
|
1882
1913
|
try {
|
|
1883
1914
|
for (;; ) {
|
|
1884
1915
|
signal?.throwIfAborted();
|
|
1885
|
-
const lock = await this.takeFree();
|
|
1916
|
+
const lock = await this.takeFree(game);
|
|
1886
1917
|
if (lock !== null) {
|
|
1887
1918
|
return lock;
|
|
1888
1919
|
}
|
|
@@ -1914,7 +1945,7 @@ class EngineSlots {
|
|
|
1914
1945
|
}
|
|
1915
1946
|
}
|
|
1916
1947
|
}
|
|
1917
|
-
async takeFree() {
|
|
1948
|
+
async takeFree(game = false) {
|
|
1918
1949
|
mkdirSync2(this.directory, { recursive: true });
|
|
1919
1950
|
await this.sweep();
|
|
1920
1951
|
const inherited = this.inherited === null ? await this.inheritedLock() : null;
|
|
@@ -1924,9 +1955,18 @@ class EngineSlots {
|
|
|
1924
1955
|
}
|
|
1925
1956
|
const taker = this.taker();
|
|
1926
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;
|
|
1927
1967
|
for (const slot of this.drawn.numbers) {
|
|
1928
1968
|
const lock = join5(this.directory, `${String(slot)}.lock`);
|
|
1929
|
-
if (this.made(lock) || await this.takenOver(lock)) {
|
|
1969
|
+
if (this.made(lock, holder) || await this.takenOver(lock, holder)) {
|
|
1930
1970
|
this.held.add(lock);
|
|
1931
1971
|
return lock;
|
|
1932
1972
|
}
|
|
@@ -1943,6 +1983,14 @@ class EngineSlots {
|
|
|
1943
1983
|
const tree = await processTree();
|
|
1944
1984
|
return tree !== undefined && inheritsSlot(tree, process4.pid, holder.pid, basename3(process4.execPath)) ? lock : null;
|
|
1945
1985
|
}
|
|
1986
|
+
markWaiting() {
|
|
1987
|
+
const mark = this.waitMarked();
|
|
1988
|
+
return () => {
|
|
1989
|
+
if (mark !== undefined && this.marks.delete(mark)) {
|
|
1990
|
+
removeWhole(mark);
|
|
1991
|
+
}
|
|
1992
|
+
};
|
|
1993
|
+
}
|
|
1946
1994
|
waitMarked() {
|
|
1947
1995
|
const marks = join5(this.directory, WAITING_FOLDER);
|
|
1948
1996
|
waitsMarked += 1;
|
|
@@ -1958,6 +2006,17 @@ class EngineSlots {
|
|
|
1958
2006
|
this.marks.add(mark);
|
|
1959
2007
|
return mark;
|
|
1960
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
|
+
}
|
|
1961
2020
|
async gateQueue() {
|
|
1962
2021
|
const marks = join5(this.directory, QUEUED_FOLDER);
|
|
1963
2022
|
let names;
|
|
@@ -1976,10 +2035,8 @@ class EngineSlots {
|
|
|
1976
2035
|
if (await this.free(mark)) {
|
|
1977
2036
|
removeWhole(mark);
|
|
1978
2037
|
removeWhole(`${mark}${SEATED_SUFFIX}`);
|
|
1979
|
-
} else
|
|
1980
|
-
live = "
|
|
1981
|
-
} else if (live === "none") {
|
|
1982
|
-
live = "seated";
|
|
2038
|
+
} else {
|
|
2039
|
+
live = "queued";
|
|
1983
2040
|
}
|
|
1984
2041
|
}
|
|
1985
2042
|
return live;
|
|
@@ -2023,7 +2080,7 @@ class EngineSlots {
|
|
|
2023
2080
|
}
|
|
2024
2081
|
return handed;
|
|
2025
2082
|
}
|
|
2026
|
-
made(path) {
|
|
2083
|
+
made(path, holder = this.holder) {
|
|
2027
2084
|
let made;
|
|
2028
2085
|
try {
|
|
2029
2086
|
made = openSync2(path, "wx");
|
|
@@ -2031,7 +2088,7 @@ class EngineSlots {
|
|
|
2031
2088
|
return false;
|
|
2032
2089
|
}
|
|
2033
2090
|
try {
|
|
2034
|
-
writeSync2(made, JSON.stringify(
|
|
2091
|
+
writeSync2(made, JSON.stringify(holder));
|
|
2035
2092
|
} finally {
|
|
2036
2093
|
closeSync2(made);
|
|
2037
2094
|
}
|
|
@@ -2051,10 +2108,10 @@ class EngineSlots {
|
|
|
2051
2108
|
}
|
|
2052
2109
|
}
|
|
2053
2110
|
}
|
|
2054
|
-
takenOver(lock) {
|
|
2055
|
-
return this.cleared(lock, true);
|
|
2111
|
+
takenOver(lock, holder) {
|
|
2112
|
+
return this.cleared(lock, true, holder);
|
|
2056
2113
|
}
|
|
2057
|
-
async cleared(lock, retake) {
|
|
2114
|
+
async cleared(lock, retake, holder = this.holder) {
|
|
2058
2115
|
if (!await this.free(lock)) {
|
|
2059
2116
|
return false;
|
|
2060
2117
|
}
|
|
@@ -2076,7 +2133,7 @@ class EngineSlots {
|
|
|
2076
2133
|
} catch {
|
|
2077
2134
|
return false;
|
|
2078
2135
|
}
|
|
2079
|
-
return retake ? this.made(lock) : true;
|
|
2136
|
+
return retake ? this.made(lock, holder) : true;
|
|
2080
2137
|
} finally {
|
|
2081
2138
|
rmSync4(steal, { force: true });
|
|
2082
2139
|
}
|
|
@@ -2112,7 +2169,8 @@ function handSlot(lock, from, to) {
|
|
|
2112
2169
|
} catch {
|
|
2113
2170
|
return false;
|
|
2114
2171
|
}
|
|
2115
|
-
|
|
2172
|
+
const holder = content === null ? null : holderOf(content);
|
|
2173
|
+
return holder?.pid === from && writeWhole(lock, JSON.stringify(holder.game === true ? { ...to, game: true } : to));
|
|
2116
2174
|
}
|
|
2117
2175
|
function giveBackSlot(lock, pid) {
|
|
2118
2176
|
try {
|
|
@@ -2139,15 +2197,12 @@ function nameSlotTaker(by) {
|
|
|
2139
2197
|
}
|
|
2140
2198
|
function slotWaitSaid(waitedMs, count, directory, holders = [], drawn = { numbers: [] }) {
|
|
2141
2199
|
const so = `Waiting${waitedMs >= 1000 ? ` ${String(Math.round(waitedMs / 1000))} s so far` : ""} for an engine`;
|
|
2142
|
-
if (drawn.limit === "held") {
|
|
2143
|
-
return `${so}: ${GATE_UNSEATED} (${directory}), and the engine starts once every queued gate has its seat.`;
|
|
2144
|
-
}
|
|
2145
2200
|
const taking = drawn.limit === undefined ? count : drawn.numbers.length;
|
|
2146
2201
|
const slots = `${slotsSaid(taking, count, directory, drawn.limit)} ${taking === 1 ? "is" : "are"} in use`;
|
|
2147
2202
|
const named = holdersNamed(taking, holders);
|
|
2148
2203
|
const waiting = `${so}: ${slots}`;
|
|
2149
2204
|
const back = `the engine starts when ${taking === 1 ? "it" : "one"} is given back`;
|
|
2150
|
-
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;
|
|
2151
2206
|
if (named.length === 0) {
|
|
2152
2207
|
return `${waiting}, by a gate or another tool, and ${starts}.`;
|
|
2153
2208
|
}
|
|
@@ -2167,13 +2222,13 @@ function slotsSaid(taking, count, directory, limit) {
|
|
|
2167
2222
|
if (limit === "tier") {
|
|
2168
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`;
|
|
2169
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
|
+
}
|
|
2170
2228
|
return count === 1 ? `the one engine slot ${where}` : `all ${String(count)} engine slots ${where}`;
|
|
2171
2229
|
}
|
|
2172
2230
|
function slotWaitedSaid(waitedMs, count, directory, holders, drawn = { numbers: [] }) {
|
|
2173
2231
|
const waited = `This call waited ${String(Math.round(waitedMs / 1000))} s for an engine slot in all.`;
|
|
2174
|
-
if (drawn.limit === "held") {
|
|
2175
|
-
return `${waited} When it first waited, ${GATE_UNSEATED} (${directory}), and engines outside a gate wait until every queued gate has its seat.`;
|
|
2176
|
-
}
|
|
2177
2232
|
const taking = drawn.limit === undefined ? count : drawn.numbers.length;
|
|
2178
2233
|
const slots = `${slotsSaid(taking, count, directory, drawn.limit)} ${taking === 1 ? "was" : "were"} in use`;
|
|
2179
2234
|
const named = holdersNamed(taking, holders);
|
|
@@ -2196,7 +2251,7 @@ function holdersNamed(count, holders) {
|
|
|
2196
2251
|
function listed(named) {
|
|
2197
2252
|
return named.length === 1 ? named.join("") : `${named.slice(0, -1).join(", ")} and ${named.at(-1) ?? ""}`;
|
|
2198
2253
|
}
|
|
2199
|
-
async function slotForCall() {
|
|
2254
|
+
async function slotForCall(game = false) {
|
|
2200
2255
|
const slots = await processSlots();
|
|
2201
2256
|
const progress = callProgress();
|
|
2202
2257
|
const waits = callSlotWaits();
|
|
@@ -2208,7 +2263,7 @@ async function slotForCall() {
|
|
|
2208
2263
|
}, () => {
|
|
2209
2264
|
blockedBy = slots.holders();
|
|
2210
2265
|
blockedOn = slots.drawn;
|
|
2211
|
-
});
|
|
2266
|
+
}, game);
|
|
2212
2267
|
if (waits !== undefined && blockedBy !== undefined) {
|
|
2213
2268
|
waits.ms += Date.now() - began;
|
|
2214
2269
|
const heldBy = blockedBy;
|
|
@@ -2235,7 +2290,7 @@ async function inASlot(body) {
|
|
|
2235
2290
|
held.release();
|
|
2236
2291
|
}
|
|
2237
2292
|
}
|
|
2238
|
-
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;
|
|
2239
2294
|
var init_engine_slots = __esm(() => {
|
|
2240
2295
|
init_alive();
|
|
2241
2296
|
init_cache_home();
|
|
@@ -2245,6 +2300,184 @@ var init_engine_slots = __esm(() => {
|
|
|
2245
2300
|
init_whole_file();
|
|
2246
2301
|
});
|
|
2247
2302
|
|
|
2303
|
+
// src/process-time.ts
|
|
2304
|
+
async function cpuSecondsOf(pid) {
|
|
2305
|
+
try {
|
|
2306
|
+
return process.platform === "win32" ? await secondsOnWindows(pid) : await askPosix2(pid);
|
|
2307
|
+
} catch {
|
|
2308
|
+
return;
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
async function secondsOnWindows(pid) {
|
|
2312
|
+
const said = (await askProcessTable(`ProcessorSeconds(${pid})`, ASK_TIMEOUT_MS2)).trim();
|
|
2313
|
+
const seconds = Number(said);
|
|
2314
|
+
return said !== "" && Number.isFinite(seconds) ? seconds : undefined;
|
|
2315
|
+
}
|
|
2316
|
+
async function askPosix2(pid) {
|
|
2317
|
+
const { stdout } = await runHidden("ps", ["-o", "time=", "-p", String(pid)], { timeout: ASK_TIMEOUT_MS2 });
|
|
2318
|
+
return secondsFromClock(stdout.trim());
|
|
2319
|
+
}
|
|
2320
|
+
function secondsFromClock(printed) {
|
|
2321
|
+
if (printed === "") {
|
|
2322
|
+
return;
|
|
2323
|
+
}
|
|
2324
|
+
const dashed = printed.includes("-");
|
|
2325
|
+
const days = dashed ? printed.slice(0, printed.indexOf("-")) : null;
|
|
2326
|
+
const clock = dashed ? printed.slice(printed.indexOf("-") + 1) : printed;
|
|
2327
|
+
const parts = clock.split(":").map((part) => Number(part));
|
|
2328
|
+
if (parts.length === 0 || parts.some((part) => !Number.isFinite(part))) {
|
|
2329
|
+
return;
|
|
2330
|
+
}
|
|
2331
|
+
const seconds = parts.reduce((total, part) => total * 60 + part, 0);
|
|
2332
|
+
const extra = days === null ? 0 : Number(days) * 86400;
|
|
2333
|
+
return Number.isFinite(extra) ? seconds + extra : undefined;
|
|
2334
|
+
}
|
|
2335
|
+
var ASK_TIMEOUT_MS2 = 6000;
|
|
2336
|
+
var init_process_time = __esm(() => {
|
|
2337
|
+
init_process_table();
|
|
2338
|
+
init_spawn();
|
|
2339
|
+
});
|
|
2340
|
+
|
|
2341
|
+
// src/engine-spent.ts
|
|
2342
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
2343
|
+
import { availableParallelism as availableParallelism2, cpus } from "node:os";
|
|
2344
|
+
import { performance as performance2 } from "node:perf_hooks";
|
|
2345
|
+
function crowded(stretch, work, busy, cores) {
|
|
2346
|
+
return stretch > 0 && Math.max(0, busy - work) / (stretch * cores) >= BUSY;
|
|
2347
|
+
}
|
|
2348
|
+
|
|
2349
|
+
class Spent {
|
|
2350
|
+
byClock = 0;
|
|
2351
|
+
byWork = 0;
|
|
2352
|
+
since;
|
|
2353
|
+
cores;
|
|
2354
|
+
last;
|
|
2355
|
+
constructor(since, first, pid, cores = availableParallelism2()) {
|
|
2356
|
+
this.since = since;
|
|
2357
|
+
this.cores = cores;
|
|
2358
|
+
this.last = {
|
|
2359
|
+
at: since,
|
|
2360
|
+
machine: first?.machine ?? Number.NaN,
|
|
2361
|
+
processor: pid === undefined ? undefined : first?.processors?.get(pid)
|
|
2362
|
+
};
|
|
2363
|
+
}
|
|
2364
|
+
counted(sample, pid) {
|
|
2365
|
+
if (sample.at <= this.last.at) {
|
|
2366
|
+
return;
|
|
2367
|
+
}
|
|
2368
|
+
const stretch = sample.at - this.last.at;
|
|
2369
|
+
const processor = pid === undefined ? undefined : sample.processors?.get(pid);
|
|
2370
|
+
const work = processor === undefined || this.last.processor === undefined ? undefined : Math.max(0, processor - this.last.processor);
|
|
2371
|
+
if (work !== undefined && crowded(stretch, work, sample.machine - this.last.machine, this.cores)) {
|
|
2372
|
+
this.byWork += Math.min(work, stretch);
|
|
2373
|
+
} else {
|
|
2374
|
+
this.byClock += stretch;
|
|
2375
|
+
}
|
|
2376
|
+
this.last = { at: sample.at, machine: sample.machine, processor };
|
|
2377
|
+
}
|
|
2378
|
+
restart(at) {
|
|
2379
|
+
this.since = at;
|
|
2380
|
+
this.byClock = 0;
|
|
2381
|
+
this.byWork = 0;
|
|
2382
|
+
this.last = { ...this.last, at: Math.max(this.last.at, at) };
|
|
2383
|
+
}
|
|
2384
|
+
clock(now) {
|
|
2385
|
+
return now - this.since;
|
|
2386
|
+
}
|
|
2387
|
+
past(limit, now) {
|
|
2388
|
+
if (this.clock(now) > limit * STARVED) {
|
|
2389
|
+
return "clock";
|
|
2390
|
+
}
|
|
2391
|
+
return this.byClock + this.byWork > limit ? "own" : null;
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
function nowSeconds() {
|
|
2395
|
+
return performance2.now() / 1000;
|
|
2396
|
+
}
|
|
2397
|
+
function machineSeconds() {
|
|
2398
|
+
return cpus().reduce((sum, core) => sum + core.times.user + core.times.nice + core.times.sys + core.times.irq, 0) / 1000;
|
|
2399
|
+
}
|
|
2400
|
+
function watching(pid, on) {
|
|
2401
|
+
if (on) {
|
|
2402
|
+
watched.add(pid);
|
|
2403
|
+
} else {
|
|
2404
|
+
watched.delete(pid);
|
|
2405
|
+
}
|
|
2406
|
+
}
|
|
2407
|
+
function sampled() {
|
|
2408
|
+
const now = Date.now();
|
|
2409
|
+
if (latest === null || now - latest.taken >= SAMPLE_MS) {
|
|
2410
|
+
latest = { taken: now, sample: take() };
|
|
2411
|
+
}
|
|
2412
|
+
return latest.sample;
|
|
2413
|
+
}
|
|
2414
|
+
async function take() {
|
|
2415
|
+
const at = nowSeconds();
|
|
2416
|
+
const machine = machineSeconds();
|
|
2417
|
+
const previous = quietAt;
|
|
2418
|
+
quietAt = { at, machine, processors: null };
|
|
2419
|
+
const share = previous === null || at <= previous.at ? 1 : (machine - previous.machine) / ((at - previous.at) * availableParallelism2());
|
|
2420
|
+
if (share < BUSY || watched.size === 0) {
|
|
2421
|
+
return quietAt;
|
|
2422
|
+
}
|
|
2423
|
+
return { at, machine, processors: await processorSecondsOf([...watched]) };
|
|
2424
|
+
}
|
|
2425
|
+
async function processorSecondsOf(pids) {
|
|
2426
|
+
const found = new Map;
|
|
2427
|
+
try {
|
|
2428
|
+
if (process.platform === "win32") {
|
|
2429
|
+
const said = await askProcessTable(`ProcessorSecondsOf('${pids.join(",")}')`, ASK_TIMEOUT_MS3);
|
|
2430
|
+
for (const line of said.split(/\r?\n/)) {
|
|
2431
|
+
const [pid, seconds] = line.trim().split(" ").map(Number);
|
|
2432
|
+
if (pid !== undefined && seconds !== undefined && Number.isFinite(pid) && Number.isFinite(seconds)) {
|
|
2433
|
+
found.set(pid, seconds);
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
} else if (process.platform === "linux") {
|
|
2437
|
+
const ticks = await ticksASecond();
|
|
2438
|
+
for (const pid of pids) {
|
|
2439
|
+
try {
|
|
2440
|
+
const fields = (readFileSync7(`/proc/${String(pid)}/stat`, "utf8").split(")").pop() ?? "").trim().split(/\s+/);
|
|
2441
|
+
const used = Number(fields[11]) + Number(fields[12]);
|
|
2442
|
+
if (Number.isFinite(used)) {
|
|
2443
|
+
found.set(pid, used / ticks);
|
|
2444
|
+
}
|
|
2445
|
+
} catch {}
|
|
2446
|
+
}
|
|
2447
|
+
} else {
|
|
2448
|
+
const asked = (some) => runHidden("ps", ["-o", "pid=,time=", "-p", some.join(",")], { timeout: ASK_TIMEOUT_MS3 }).then((done) => done.stdout, (error) => {
|
|
2449
|
+
const printed = error.stdout;
|
|
2450
|
+
return typeof printed === "string" ? printed : "";
|
|
2451
|
+
});
|
|
2452
|
+
let stdout = await asked(pids);
|
|
2453
|
+
if (stdout.trim() === "" && pids.length > 1) {
|
|
2454
|
+
stdout = (await Promise.all(pids.map((pid) => asked([pid])))).join(`
|
|
2455
|
+
`);
|
|
2456
|
+
}
|
|
2457
|
+
for (const line of stdout.split(`
|
|
2458
|
+
`)) {
|
|
2459
|
+
const [pid, time] = line.trim().split(/\s+/);
|
|
2460
|
+
const seconds = time === undefined ? undefined : secondsFromClock(time);
|
|
2461
|
+
if (pid !== undefined && seconds !== undefined) {
|
|
2462
|
+
found.set(Number(pid), seconds);
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
} catch {}
|
|
2467
|
+
return found;
|
|
2468
|
+
}
|
|
2469
|
+
function ticksASecond() {
|
|
2470
|
+
ticks ??= runHidden("getconf", ["CLK_TCK"], { timeout: ASK_TIMEOUT_MS3 }).then(({ stdout }) => Number(stdout.trim()) || 100).catch(() => 100);
|
|
2471
|
+
return ticks;
|
|
2472
|
+
}
|
|
2473
|
+
var STARVED = 8, BUSY = 0.25, SAMPLE_MS = 1000, ASK_TIMEOUT_MS3 = 3000, watched, latest = null, quietAt = null, ticks = null;
|
|
2474
|
+
var init_engine_spent = __esm(() => {
|
|
2475
|
+
init_process_table();
|
|
2476
|
+
init_process_time();
|
|
2477
|
+
init_spawn();
|
|
2478
|
+
watched = new Set;
|
|
2479
|
+
});
|
|
2480
|
+
|
|
2248
2481
|
// node_modules/yaml/dist/nodes/identity.js
|
|
2249
2482
|
var require_identity = __commonJS(function(exports) {
|
|
2250
2483
|
var ALIAS = Symbol.for("yaml.alias");
|
|
@@ -9332,7 +9565,7 @@ var init_config_formats = __esm(() => {
|
|
|
9332
9565
|
});
|
|
9333
9566
|
|
|
9334
9567
|
// src/runner.ts
|
|
9335
|
-
import { existsSync as
|
|
9568
|
+
import { existsSync as existsSync2, realpathSync as realpathSync2 } from "node:fs";
|
|
9336
9569
|
import { delimiter, dirname as dirname3, extname, join as join6, resolve as resolve3 } from "node:path";
|
|
9337
9570
|
import process5 from "node:process";
|
|
9338
9571
|
function currentRunner() {
|
|
@@ -9376,12 +9609,12 @@ function realPath(path) {
|
|
|
9376
9609
|
}
|
|
9377
9610
|
function alongside(execPath, name) {
|
|
9378
9611
|
const runner = join6(dirname3(execPath), process5.platform === "win32" ? `${name}.cmd` : name);
|
|
9379
|
-
return
|
|
9612
|
+
return existsSync2(runner) ? runner : undefined;
|
|
9380
9613
|
}
|
|
9381
9614
|
var init_runner = () => {};
|
|
9382
9615
|
|
|
9383
9616
|
// src/harnesses.ts
|
|
9384
|
-
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";
|
|
9385
9618
|
import { homedir as homedir3 } from "node:os";
|
|
9386
9619
|
import { basename as basename4, dirname as dirname4, isAbsolute as isAbsolute2, join as join7, relative as relative2, resolve as resolve4 } from "node:path";
|
|
9387
9620
|
import process6 from "node:process";
|
|
@@ -9472,15 +9705,15 @@ function harnessById(id) {
|
|
|
9472
9705
|
}
|
|
9473
9706
|
function present(harness, projectPath) {
|
|
9474
9707
|
const path = configPath(harness, projectPath);
|
|
9475
|
-
if (
|
|
9708
|
+
if (existsSync3(path)) {
|
|
9476
9709
|
return true;
|
|
9477
9710
|
}
|
|
9478
9711
|
const root = harness.scope === "project" ? projectPath : homedir3();
|
|
9479
9712
|
const own = dirname4(path);
|
|
9480
|
-
if (own !== root &&
|
|
9713
|
+
if (own !== root && existsSync3(own)) {
|
|
9481
9714
|
return true;
|
|
9482
9715
|
}
|
|
9483
|
-
return harness.marker !== undefined &&
|
|
9716
|
+
return harness.marker !== undefined && existsSync3(join7(root, harness.marker));
|
|
9484
9717
|
}
|
|
9485
9718
|
function candidates(projectPath) {
|
|
9486
9719
|
const found = [];
|
|
@@ -9493,7 +9726,7 @@ function candidates(projectPath) {
|
|
|
9493
9726
|
}
|
|
9494
9727
|
if (present(harness, projectPath)) {
|
|
9495
9728
|
found.push({ harness, reason: "configured" });
|
|
9496
|
-
} else if (harness.home !== undefined &&
|
|
9729
|
+
} else if (harness.home !== undefined && existsSync3(join7(homedir3(), harness.home))) {
|
|
9497
9730
|
found.push({ harness, reason: "installed" });
|
|
9498
9731
|
}
|
|
9499
9732
|
}
|
|
@@ -9515,10 +9748,10 @@ function groupByFile(harnesses, projectPath) {
|
|
|
9515
9748
|
}
|
|
9516
9749
|
function registered(harness, projectPath) {
|
|
9517
9750
|
const path = configPath(harness, projectPath);
|
|
9518
|
-
if (harness.snippet !== undefined || !
|
|
9751
|
+
if (harness.snippet !== undefined || !existsSync3(path)) {
|
|
9519
9752
|
return false;
|
|
9520
9753
|
}
|
|
9521
|
-
const text =
|
|
9754
|
+
const text = readFileSync8(path, "utf8");
|
|
9522
9755
|
if (harness.toml !== undefined) {
|
|
9523
9756
|
return text.includes(harness.toml.identity ?? harness.toml.header);
|
|
9524
9757
|
}
|
|
@@ -9544,7 +9777,7 @@ function recordedEnginePath(projectPath) {
|
|
|
9544
9777
|
}
|
|
9545
9778
|
const named = reach(entryEnvironment(harness, projectPath), "GODOT_PATH");
|
|
9546
9779
|
const path = typeof named !== "string" || named === "" ? null : isAbsolute2(named) ? named : resolve4(projectPath, named);
|
|
9547
|
-
if (path !== null &&
|
|
9780
|
+
if (path !== null && existsSync3(path)) {
|
|
9548
9781
|
return path;
|
|
9549
9782
|
}
|
|
9550
9783
|
}
|
|
@@ -9552,7 +9785,7 @@ function recordedEnginePath(projectPath) {
|
|
|
9552
9785
|
}
|
|
9553
9786
|
function mainCheckoutOf(projectPath) {
|
|
9554
9787
|
let top = resolve4(projectPath);
|
|
9555
|
-
while (!
|
|
9788
|
+
while (!existsSync3(join7(top, ".git"))) {
|
|
9556
9789
|
const up = dirname4(top);
|
|
9557
9790
|
if (up === top) {
|
|
9558
9791
|
return null;
|
|
@@ -9563,25 +9796,25 @@ function mainCheckoutOf(projectPath) {
|
|
|
9563
9796
|
if (!statSync4(marker).isFile()) {
|
|
9564
9797
|
return null;
|
|
9565
9798
|
}
|
|
9566
|
-
const pointer = /^gitdir:\s*(.+)$/m.exec(
|
|
9799
|
+
const pointer = /^gitdir:\s*(.+)$/m.exec(readFileSync8(marker, "utf8"))?.[1]?.trim();
|
|
9567
9800
|
if (pointer === undefined) {
|
|
9568
9801
|
return null;
|
|
9569
9802
|
}
|
|
9570
9803
|
const entry = resolve4(top, pointer);
|
|
9571
9804
|
const commonFile = join7(entry, "commondir");
|
|
9572
|
-
if (!
|
|
9805
|
+
if (!existsSync3(commonFile)) {
|
|
9573
9806
|
return null;
|
|
9574
9807
|
}
|
|
9575
|
-
const common = resolve4(entry,
|
|
9808
|
+
const common = resolve4(entry, readFileSync8(commonFile, "utf8").trim());
|
|
9576
9809
|
if (basename4(common) !== ".git") {
|
|
9577
9810
|
return null;
|
|
9578
9811
|
}
|
|
9579
9812
|
const main = join7(dirname4(common), relative2(top, resolve4(projectPath)));
|
|
9580
|
-
return isSameDirectory(main, projectPath) || !
|
|
9813
|
+
return isSameDirectory(main, projectPath) || !existsSync3(join7(main, "project.godot")) ? null : main;
|
|
9581
9814
|
}
|
|
9582
9815
|
function worktreeCheckoutsOf(projectPath) {
|
|
9583
9816
|
let top = resolve4(projectPath);
|
|
9584
|
-
while (!
|
|
9817
|
+
while (!existsSync3(join7(top, ".git"))) {
|
|
9585
9818
|
const up = dirname4(top);
|
|
9586
9819
|
if (up === top) {
|
|
9587
9820
|
return [];
|
|
@@ -9589,18 +9822,18 @@ function worktreeCheckoutsOf(projectPath) {
|
|
|
9589
9822
|
top = up;
|
|
9590
9823
|
}
|
|
9591
9824
|
const listed = join7(top, ".git", "worktrees");
|
|
9592
|
-
if (!statSync4(join7(top, ".git")).isDirectory() || !
|
|
9825
|
+
if (!statSync4(join7(top, ".git")).isDirectory() || !existsSync3(listed)) {
|
|
9593
9826
|
return [];
|
|
9594
9827
|
}
|
|
9595
9828
|
const below = relative2(top, resolve4(projectPath));
|
|
9596
9829
|
return readdirSync2(listed).flatMap((name) => {
|
|
9597
9830
|
const pointer = join7(listed, name, "gitdir");
|
|
9598
|
-
if (!
|
|
9831
|
+
if (!existsSync3(pointer)) {
|
|
9599
9832
|
return [];
|
|
9600
9833
|
}
|
|
9601
|
-
const checkout = dirname4(resolve4(listed, name,
|
|
9834
|
+
const checkout = dirname4(resolve4(listed, name, readFileSync8(pointer, "utf8").trim()));
|
|
9602
9835
|
const project = join7(checkout, below);
|
|
9603
|
-
return
|
|
9836
|
+
return existsSync3(join7(project, "project.godot")) ? [project] : [];
|
|
9604
9837
|
});
|
|
9605
9838
|
}
|
|
9606
9839
|
function entryEnvironment(harness, projectPath) {
|
|
@@ -9608,12 +9841,12 @@ function entryEnvironment(harness, projectPath) {
|
|
|
9608
9841
|
return;
|
|
9609
9842
|
}
|
|
9610
9843
|
const path = configPath(harness, projectPath);
|
|
9611
|
-
if (!
|
|
9844
|
+
if (!existsSync3(path)) {
|
|
9612
9845
|
return;
|
|
9613
9846
|
}
|
|
9614
9847
|
let parsed;
|
|
9615
9848
|
try {
|
|
9616
|
-
parsed = JSON.parse(
|
|
9849
|
+
parsed = JSON.parse(readFileSync8(path, "utf8"));
|
|
9617
9850
|
} catch {
|
|
9618
9851
|
return;
|
|
9619
9852
|
}
|
|
@@ -9629,13 +9862,13 @@ function reach(held, key) {
|
|
|
9629
9862
|
}
|
|
9630
9863
|
function disconnect(harness, projectPath) {
|
|
9631
9864
|
const path = configPath(harness, projectPath);
|
|
9632
|
-
if (!
|
|
9865
|
+
if (!existsSync3(path)) {
|
|
9633
9866
|
return { harness, path, action: "absent" };
|
|
9634
9867
|
}
|
|
9635
9868
|
if (harness.snippet !== undefined) {
|
|
9636
9869
|
return { harness, path, action: "manual" };
|
|
9637
9870
|
}
|
|
9638
|
-
const text =
|
|
9871
|
+
const text = readFileSync8(path, "utf8");
|
|
9639
9872
|
if (harness.toml !== undefined) {
|
|
9640
9873
|
return taken(harness, path, text, removeToml(text, harness.toml));
|
|
9641
9874
|
}
|
|
@@ -9644,7 +9877,7 @@ function disconnect(harness, projectPath) {
|
|
|
9644
9877
|
}
|
|
9645
9878
|
let existing;
|
|
9646
9879
|
try {
|
|
9647
|
-
existing = JSON.parse(
|
|
9880
|
+
existing = JSON.parse(readFileSync8(path, "utf8"));
|
|
9648
9881
|
} catch {
|
|
9649
9882
|
return { harness, path, action: "absent" };
|
|
9650
9883
|
}
|
|
@@ -9716,7 +9949,7 @@ function connect(harness, projectPath, launch) {
|
|
|
9716
9949
|
if (harness.snippet !== undefined) {
|
|
9717
9950
|
return { harness, path, action: "snippet", snippet: harness.snippet(launch) };
|
|
9718
9951
|
}
|
|
9719
|
-
const held =
|
|
9952
|
+
const held = existsSync3(path) ? readFileSync8(path, "utf8") : "";
|
|
9720
9953
|
if (harness.toml !== undefined) {
|
|
9721
9954
|
const already = held.includes(harness.toml.identity ?? harness.toml.header);
|
|
9722
9955
|
return put(harness, path, writeToml(held, harness.toml, launch), already);
|
|
@@ -10882,7 +11115,7 @@ var init_gdscript_source = __esm(() => {
|
|
|
10882
11115
|
});
|
|
10883
11116
|
|
|
10884
11117
|
// src/class-cache.ts
|
|
10885
|
-
import { existsSync as
|
|
11118
|
+
import { existsSync as existsSync4, readdirSync as readdirSync3, readFileSync as readFileSync9, statSync as statSync5 } from "node:fs";
|
|
10886
11119
|
import { join as join8, posix } from "node:path";
|
|
10887
11120
|
function isToolScript(source) {
|
|
10888
11121
|
return TOOL.test(codeOf(source));
|
|
@@ -10946,7 +11179,7 @@ function declaredClassOf(source) {
|
|
|
10946
11179
|
}
|
|
10947
11180
|
function eachScript(projectPath, each) {
|
|
10948
11181
|
const visit = (directory, prefix) => {
|
|
10949
|
-
if (
|
|
11182
|
+
if (existsSync4(join8(directory, ".gdignore"))) {
|
|
10950
11183
|
return;
|
|
10951
11184
|
}
|
|
10952
11185
|
for (const entry of readdirSync3(directory, { withFileTypes: true })) {
|
|
@@ -10957,7 +11190,7 @@ function eachScript(projectPath, each) {
|
|
|
10957
11190
|
if (entry.isDirectory()) {
|
|
10958
11191
|
visit(path, `${prefix}${entry.name}/`);
|
|
10959
11192
|
} else if (entry.isFile() && entry.name.endsWith(".gd")) {
|
|
10960
|
-
each(`res://${prefix}${entry.name}`,
|
|
11193
|
+
each(`res://${prefix}${entry.name}`, readFileSync9(path, "utf8"));
|
|
10961
11194
|
}
|
|
10962
11195
|
}
|
|
10963
11196
|
};
|
|
@@ -11342,7 +11575,7 @@ function uncachedForTheEngineNote(projectPath, types) {
|
|
|
11342
11575
|
}
|
|
11343
11576
|
const one = types.length === 1;
|
|
11344
11577
|
const named = types.map((type) => `${type.type} (${type.declaredIn})`).join(", ");
|
|
11345
|
-
const cacheExists =
|
|
11578
|
+
const cacheExists = existsSync4(join8(projectPath, ".godot", "global_script_class_cache.cfg"));
|
|
11346
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.`;
|
|
11347
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.";
|
|
11348
11581
|
}
|
|
@@ -11368,7 +11601,7 @@ function declaredSince(projectPath, paths, names, since) {
|
|
|
11368
11601
|
});
|
|
11369
11602
|
}
|
|
11370
11603
|
function cachedAtMissingPaths(cached, projectPath) {
|
|
11371
|
-
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();
|
|
11372
11605
|
}
|
|
11373
11606
|
function staleAgainst(cached, projectPath) {
|
|
11374
11607
|
return [...declaredClasses(projectPath)].filter(([name, path]) => cached.get(name) !== path).map(([name]) => name);
|
|
@@ -12095,7 +12328,7 @@ var init_junit = __esm(() => {
|
|
|
12095
12328
|
});
|
|
12096
12329
|
|
|
12097
12330
|
// src/suite-judge.ts
|
|
12098
|
-
import { readFileSync as
|
|
12331
|
+
import { readFileSync as readFileSync10 } from "node:fs";
|
|
12099
12332
|
import { stripVTControlCharacters } from "node:util";
|
|
12100
12333
|
function secondsOf(time) {
|
|
12101
12334
|
let ms = 0;
|
|
@@ -12272,7 +12505,7 @@ function readRun(printed) {
|
|
|
12272
12505
|
settleAfterCase("after");
|
|
12273
12506
|
const joined = lines.join(`
|
|
12274
12507
|
`);
|
|
12275
|
-
const starved =
|
|
12508
|
+
const starved = STARVED2.flatMap((pattern) => [...joined.matchAll(pattern)].map((found) => found[0]));
|
|
12276
12509
|
const unloadable = scriptErrorsPrinted(lines).map((error) => `${error.path}${error.line === null ? "" : `:${String(error.line)}`}: ${error.message}`);
|
|
12277
12510
|
return {
|
|
12278
12511
|
lines,
|
|
@@ -12306,7 +12539,7 @@ function versionFault(said, wanted) {
|
|
|
12306
12539
|
function readExpected(file) {
|
|
12307
12540
|
const declared = (value) => typeof value === "object" && value !== null ? value : {};
|
|
12308
12541
|
try {
|
|
12309
|
-
const parsed = JSON.parse(
|
|
12542
|
+
const parsed = JSON.parse(readFileSync10(file, "utf8"));
|
|
12310
12543
|
const read = typeof parsed === "object" && parsed !== null ? parsed : {};
|
|
12311
12544
|
return { errors: declared(read["errors"]), warnings: declared(read["warnings"]) };
|
|
12312
12545
|
} catch {
|
|
@@ -12652,7 +12885,7 @@ ${String(error.warning)}`);
|
|
|
12652
12885
|
const neverPrinted = [...owed.values()].flatMap((debt) => debt.texts.map((text) => ({ suite: debt.suite, during: debt.during, text, warning: debt.warning })));
|
|
12653
12886
|
return { printed: unexpected, neverPrinted };
|
|
12654
12887
|
}
|
|
12655
|
-
var SUITE_OPENED, TIME, CASE_LINE, STATISTICS, ERROR_LINE, WARNING_LINE, EXECUTED, MISMATCHED_ROW, UNRUNNABLE_CASE, BANNER, LEFT_OUT, DRIVER_FALLBACK, MACHINE_WARNED, ORPHANS_REPORTED,
|
|
12888
|
+
var SUITE_OPENED, TIME, CASE_LINE, STATISTICS, ERROR_LINE, WARNING_LINE, EXECUTED, MISMATCHED_ROW, UNRUNNABLE_CASE, BANNER, LEFT_OUT, DRIVER_FALLBACK, MACHINE_WARNED, ORPHANS_REPORTED, STARVED2, NESTED_ERROR = "While attempting to print an error, another error was printed:", WINDOWS_EXITS, MEMORY_EXITS, GDUNIT_FAILED = 100, GDUNIT_ORPHANS = 101, GDUNIT_EXITS, GODOT_EXITS, CRASH_HEADER, CRASH_BUILD, QUEUE_OVERFLOW_LINE = "Object was deleted while awaiting a callback.", QUEUE_OVERFLOW_FRAMES, TAIL = 60, MOST_NAMED = 8, COMPILED_SAID = "gdharness compiled every script together";
|
|
12656
12889
|
var init_suite_judge = __esm(() => {
|
|
12657
12890
|
init_engine_leaks();
|
|
12658
12891
|
init_junit();
|
|
@@ -12670,7 +12903,7 @@ var init_suite_judge = __esm(() => {
|
|
|
12670
12903
|
DRIVER_FALLBACK = /^\s*WARNING: Your video card drivers .*, switching to /;
|
|
12671
12904
|
MACHINE_WARNED = /^\s*at: .*\((?:\.\/)?(?:platform|drivers)\//;
|
|
12672
12905
|
ORPHANS_REPORTED = /^\s*WARNING: Detected \d+ (?:possible )?orphan nodes\.\s*$/;
|
|
12673
|
-
|
|
12906
|
+
STARVED2 = [
|
|
12674
12907
|
/Parameter "mem(?:_new)?" is null\.?\s*\n\s*at: \w+ \((?:\.\/)?core\/(?:os\/memory\.cpp|templates\/cowdata\.h):/g,
|
|
12675
12908
|
/ERROR: Failed decoding WebP image\.\s*\n\s*at: _webp_unpack/g
|
|
12676
12909
|
];
|
|
@@ -12702,20 +12935,28 @@ var init_suite_judge = __esm(() => {
|
|
|
12702
12935
|
// src/engine-launch.ts
|
|
12703
12936
|
import {
|
|
12704
12937
|
closeSync as closeSync4,
|
|
12705
|
-
existsSync as
|
|
12938
|
+
existsSync as existsSync5,
|
|
12706
12939
|
fstatSync as fstatSync2,
|
|
12707
12940
|
openSync as openSync4,
|
|
12708
12941
|
readdirSync as readdirSync4,
|
|
12942
|
+
readFileSync as readFileSync11,
|
|
12709
12943
|
readSync as readSync2,
|
|
12710
12944
|
rmSync as rmSync7,
|
|
12711
12945
|
statSync as statSync6,
|
|
12712
12946
|
writeFileSync as writeFileSync6,
|
|
12713
12947
|
writeSync as writeSync4
|
|
12714
12948
|
} from "node:fs";
|
|
12715
|
-
import { availableParallelism as
|
|
12949
|
+
import { availableParallelism as availableParallelism3, freemem, totalmem } from "node:os";
|
|
12716
12950
|
import { isAbsolute as isAbsolute3, join as join9, relative as relative3, resolve as resolve5, sep as sep2 } from "node:path";
|
|
12717
12951
|
import process7 from "node:process";
|
|
12718
12952
|
import { setTimeout as delay3 } from "node:timers/promises";
|
|
12953
|
+
function countedBy(spent, past, at) {
|
|
12954
|
+
const clock = Math.round(spent.clock(at));
|
|
12955
|
+
if (past === "clock") {
|
|
12956
|
+
return `, ${String(STARVED)} times over on the clock (${String(clock)} s), the machine kept busy by other work`;
|
|
12957
|
+
}
|
|
12958
|
+
return spent.byWork === 0 ? "" : ` of its own, counted by its processor time while other work kept the machine busy (${String(clock)} s on the clock)`;
|
|
12959
|
+
}
|
|
12719
12960
|
function plural(count, noun) {
|
|
12720
12961
|
return `${String(count)} ${noun}${count === 1 ? "" : "s"}`;
|
|
12721
12962
|
}
|
|
@@ -12734,14 +12975,14 @@ function godotNamed(value, cwd) {
|
|
|
12734
12975
|
return null;
|
|
12735
12976
|
}
|
|
12736
12977
|
const path = resolve5(cwd, value);
|
|
12737
|
-
if (!
|
|
12978
|
+
if (!existsSync5(path) || statSync6(path).isDirectory()) {
|
|
12738
12979
|
throw new EngineUsageError(`--godot names ${path}, which is not an engine executable.`);
|
|
12739
12980
|
}
|
|
12740
12981
|
return path;
|
|
12741
12982
|
}
|
|
12742
12983
|
function coresNamed(value) {
|
|
12743
12984
|
const cores = wholeFlag(value, "--cores");
|
|
12744
|
-
const most = Math.min(
|
|
12985
|
+
const most = Math.min(availableParallelism3(), 64);
|
|
12745
12986
|
if (cores !== null && cores > most) {
|
|
12746
12987
|
throw new EngineUsageError(`--cores ${String(cores)} is more than the ${String(most)} processors a run can be held to here.`);
|
|
12747
12988
|
}
|
|
@@ -12765,7 +13006,7 @@ function resPathOf(entry, projectPath, cwd) {
|
|
|
12765
13006
|
const file = caseAt?.[1] ?? entry;
|
|
12766
13007
|
const fromProject = resolve5(projectPath, file);
|
|
12767
13008
|
const fromHere = resolve5(cwd, file);
|
|
12768
|
-
const absolute = isAbsolute3(file) || !
|
|
13009
|
+
const absolute = isAbsolute3(file) || !existsSync5(fromProject) && existsSync5(fromHere) ? fromHere : fromProject;
|
|
12769
13010
|
const inside = relative3(projectPath, absolute);
|
|
12770
13011
|
if (inside.startsWith("..") || isAbsolute3(inside)) {
|
|
12771
13012
|
throw new EngineUsageError(`${entry} is not inside the project at ${projectPath}.`);
|
|
@@ -12777,7 +13018,7 @@ function homeOf(projectPath) {
|
|
|
12777
13018
|
return mainCheckoutOf(projectPath) ?? projectPath;
|
|
12778
13019
|
}
|
|
12779
13020
|
function sweepRunDirectories(runs, kept = KEPT_RUN_DIRECTORIES) {
|
|
12780
|
-
if (!
|
|
13021
|
+
if (!existsSync5(runs)) {
|
|
12781
13022
|
return;
|
|
12782
13023
|
}
|
|
12783
13024
|
const ended = [];
|
|
@@ -12807,6 +13048,9 @@ function roomFor(most, processors, available, said = "of memory free", processor
|
|
|
12807
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
|
|
12808
13049
|
};
|
|
12809
13050
|
}
|
|
13051
|
+
function roomForAnother(available, starting) {
|
|
13052
|
+
return available - MEMORY_KEPT - starting * MEMORY_PER_ENGINE >= MEMORY_PER_ENGINE;
|
|
13053
|
+
}
|
|
12810
13054
|
async function memoryAvailable() {
|
|
12811
13055
|
const level = await macMemoryLevel();
|
|
12812
13056
|
if (level !== null) {
|
|
@@ -12932,19 +13176,49 @@ async function watchedEngine(launch, lock, args, directory, log, silenceSeconds,
|
|
|
12932
13176
|
exited.then(() => {
|
|
12933
13177
|
finished.now = true;
|
|
12934
13178
|
});
|
|
13179
|
+
const hasFinished = () => finished.now;
|
|
12935
13180
|
const reading = openSync4(log, "r");
|
|
13181
|
+
const engineAt = () => {
|
|
13182
|
+
if (helper === null) {
|
|
13183
|
+
return child.pid;
|
|
13184
|
+
}
|
|
13185
|
+
try {
|
|
13186
|
+
const pid = Number(readFileSync11(helper.pid, "utf8").trim());
|
|
13187
|
+
return Number.isInteger(pid) && pid > 0 ? pid : undefined;
|
|
13188
|
+
} catch {
|
|
13189
|
+
return;
|
|
13190
|
+
}
|
|
13191
|
+
};
|
|
13192
|
+
let pid = engineAt();
|
|
13193
|
+
if (pid !== undefined) {
|
|
13194
|
+
watching(pid, true);
|
|
13195
|
+
}
|
|
12936
13196
|
try {
|
|
12937
13197
|
let size = 0;
|
|
12938
|
-
const
|
|
12939
|
-
|
|
13198
|
+
const sample = launch.sample ?? sampled;
|
|
13199
|
+
const first = await sample();
|
|
13200
|
+
const running = new Spent(nowSeconds(), first, pid);
|
|
13201
|
+
const quiet = new Spent(nowSeconds(), first, pid);
|
|
12940
13202
|
let carried = "";
|
|
12941
13203
|
let allowed = { size: -1, seconds: silenceSeconds };
|
|
12942
13204
|
while (!finished.now) {
|
|
12943
13205
|
await delay3(LOOK_MS);
|
|
13206
|
+
if (pid === undefined) {
|
|
13207
|
+
pid = engineAt();
|
|
13208
|
+
if (pid !== undefined) {
|
|
13209
|
+
watching(pid, true);
|
|
13210
|
+
}
|
|
13211
|
+
}
|
|
13212
|
+
const taken = await sample();
|
|
13213
|
+
running.counted(taken, pid);
|
|
13214
|
+
quiet.counted(taken, pid);
|
|
13215
|
+
const at = nowSeconds();
|
|
13216
|
+
const gone = hasFinished() || pid !== undefined && !alive(pid);
|
|
12944
13217
|
const deadline = launch.deadlineSeconds;
|
|
12945
|
-
|
|
13218
|
+
const over = deadline === null || gone ? null : running.past(deadline, at);
|
|
13219
|
+
if (ended === null && deadline !== null && over !== null) {
|
|
12946
13220
|
const stoppedIn = readRun(readLog(log)).stoppedIn;
|
|
12947
|
-
ended = `the engine ran past the ${String(deadline)} s deadline${stoppedIn === null ? "" : ` while running ${stoppedIn}`}, so it was ended`;
|
|
13221
|
+
ended = `the engine ran past the ${String(deadline)} s deadline${countedBy(running, over, at)}${stoppedIn === null ? "" : ` while running ${stoppedIn}`}, so it was ended`;
|
|
12948
13222
|
stop();
|
|
12949
13223
|
}
|
|
12950
13224
|
const now = fstatSync2(reading).size;
|
|
@@ -12964,24 +13238,25 @@ async function watchedEngine(launch, lock, args, directory, log, silenceSeconds,
|
|
|
12964
13238
|
at += got;
|
|
12965
13239
|
}
|
|
12966
13240
|
size = now;
|
|
12967
|
-
|
|
13241
|
+
quiet.restart(at);
|
|
12968
13242
|
if (ended === null && size > LOG_LIMIT_BYTES) {
|
|
12969
13243
|
ended = `the engine printed more than the ${String(LOG_LIMIT_BYTES / 1024 / 1024)} MiB a log may hold, so it was ended`;
|
|
12970
13244
|
stop();
|
|
12971
13245
|
}
|
|
12972
|
-
} else if (ended === null &&
|
|
13246
|
+
} else if (ended === null && !gone && quiet.past(silenceSeconds, at) !== null) {
|
|
12973
13247
|
if (allowed.size !== size) {
|
|
12974
13248
|
allowed = {
|
|
12975
13249
|
size,
|
|
12976
13250
|
seconds: silenceIn === undefined ? silenceSeconds : Math.max(silenceSeconds, silenceIn(readRun(readLog(log))))
|
|
12977
13251
|
};
|
|
12978
13252
|
}
|
|
12979
|
-
|
|
13253
|
+
const silent = quiet.past(allowed.seconds, at);
|
|
13254
|
+
if (silent === null) {
|
|
12980
13255
|
continue;
|
|
12981
13256
|
}
|
|
12982
13257
|
const { stoppedIn } = readRun(readLog(log));
|
|
12983
|
-
const unstarted = helper !== null && !
|
|
12984
|
-
ended = `the engine printed nothing for ${String(allowed.seconds)} s${stoppedIn === null ? "" : ` while running ${stoppedIn}`}, so it was ended${unstarted}`;
|
|
13258
|
+
const unstarted = helper !== null && !existsSync5(helper.pid) ? `, and it never started ${helper.how}: ${helperStep(helper.step)}` : "";
|
|
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}`;
|
|
12985
13260
|
stop();
|
|
12986
13261
|
}
|
|
12987
13262
|
}
|
|
@@ -12991,6 +13266,9 @@ async function watchedEngine(launch, lock, args, directory, log, silenceSeconds,
|
|
|
12991
13266
|
} finally {
|
|
12992
13267
|
closeSync4(reading);
|
|
12993
13268
|
launch.running.delete(stop);
|
|
13269
|
+
if (pid !== undefined) {
|
|
13270
|
+
watching(pid, false);
|
|
13271
|
+
}
|
|
12994
13272
|
}
|
|
12995
13273
|
const { code, signal } = await exited;
|
|
12996
13274
|
const freeBytes = code !== null && code >>> 0 >= WINDOWS_EXCEPTION ? freemem() : undefined;
|
|
@@ -13047,6 +13325,7 @@ var init_engine_launch = __esm(() => {
|
|
|
13047
13325
|
init_alive();
|
|
13048
13326
|
init_desktop();
|
|
13049
13327
|
init_engine_slots();
|
|
13328
|
+
init_engine_spent();
|
|
13050
13329
|
init_errors();
|
|
13051
13330
|
init_harnesses();
|
|
13052
13331
|
init_log_read();
|
|
@@ -13062,7 +13341,7 @@ var init_engine_launch = __esm(() => {
|
|
|
13062
13341
|
});
|
|
13063
13342
|
|
|
13064
13343
|
// src/detection.ts
|
|
13065
|
-
import { existsSync as
|
|
13344
|
+
import { existsSync as existsSync6, readdirSync as readdirSync5, statSync as statSync7 } from "node:fs";
|
|
13066
13345
|
import { homedir as homedir4 } from "node:os";
|
|
13067
13346
|
import { join as join10 } from "node:path";
|
|
13068
13347
|
function resolveHomeDirectory() {
|
|
@@ -13073,7 +13352,7 @@ function resolveHomeDirectory() {
|
|
|
13073
13352
|
}
|
|
13074
13353
|
}
|
|
13075
13354
|
function scanDirectoryForGodotBinaries(directory, platform) {
|
|
13076
|
-
if (!directory || !
|
|
13355
|
+
if (!directory || !existsSync6(directory)) {
|
|
13077
13356
|
return [];
|
|
13078
13357
|
}
|
|
13079
13358
|
let entries;
|
|
@@ -13341,7 +13620,7 @@ var init_launch = __esm(() => {
|
|
|
13341
13620
|
});
|
|
13342
13621
|
|
|
13343
13622
|
// src/godot-path.ts
|
|
13344
|
-
import { existsSync as
|
|
13623
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
13345
13624
|
import { isAbsolute as isAbsolute4, normalize, resolve as resolve6 } from "node:path";
|
|
13346
13625
|
function versionStartOf(error) {
|
|
13347
13626
|
const failed = error ?? {};
|
|
@@ -13419,7 +13698,7 @@ class GodotLocator {
|
|
|
13419
13698
|
if (known !== undefined) {
|
|
13420
13699
|
return known;
|
|
13421
13700
|
}
|
|
13422
|
-
if (path !== "godot" && !
|
|
13701
|
+
if (path !== "godot" && !existsSync7(path)) {
|
|
13423
13702
|
this.answered.set(path, "does not exist");
|
|
13424
13703
|
return "does not exist";
|
|
13425
13704
|
}
|
|
@@ -13801,7 +14080,7 @@ var init_engine_run = __esm(() => {
|
|
|
13801
14080
|
});
|
|
13802
14081
|
|
|
13803
14082
|
// src/doc-cache.ts
|
|
13804
|
-
import { existsSync as
|
|
14083
|
+
import { existsSync as existsSync8, readdirSync as readdirSync6, statSync as statSync8 } from "node:fs";
|
|
13805
14084
|
import { homedir as homedir5 } from "node:os";
|
|
13806
14085
|
import { basename as basename5, dirname as dirname5, isAbsolute as isAbsolute5, join as join11 } from "node:path";
|
|
13807
14086
|
import process9 from "node:process";
|
|
@@ -13809,7 +14088,7 @@ function editorCacheDirectory(godotPath, platform = process9.platform, env = pro
|
|
|
13809
14088
|
const beside = dirname5(godotPath);
|
|
13810
14089
|
const bundle = platform === "darwin" && basename5(beside) === "MacOS" && basename5(dirname5(beside)) === "Contents" ? dirname5(dirname5(dirname5(beside))) : null;
|
|
13811
14090
|
for (const folder of bundle === null ? [beside] : [beside, bundle]) {
|
|
13812
|
-
if (
|
|
14091
|
+
if (existsSync8(join11(folder, "._sc_")) || existsSync8(join11(folder, "_sc_"))) {
|
|
13813
14092
|
return join11(folder, "editor_data", "cache");
|
|
13814
14093
|
}
|
|
13815
14094
|
}
|
|
@@ -13857,7 +14136,7 @@ var init_doc_cache = __esm(() => {
|
|
|
13857
14136
|
});
|
|
13858
14137
|
|
|
13859
14138
|
// src/project-scan.ts
|
|
13860
|
-
import { existsSync as
|
|
14139
|
+
import { existsSync as existsSync9, readdirSync as readdirSync7, readFileSync as readFileSync12, statSync as statSync9 } from "node:fs";
|
|
13861
14140
|
import { basename as basename6, extname as extname2, join as join12, relative as relative4, sep as sep3 } from "node:path";
|
|
13862
14141
|
function skipped(name) {
|
|
13863
14142
|
return name.startsWith(".") || SKIPPED.has(name);
|
|
@@ -13866,10 +14145,10 @@ function steppedOver(directory) {
|
|
|
13866
14145
|
return gdignored(directory) || installedByUs(directory);
|
|
13867
14146
|
}
|
|
13868
14147
|
function gdignored(directory) {
|
|
13869
|
-
return
|
|
14148
|
+
return existsSync9(join12(directory, ".gdignore"));
|
|
13870
14149
|
}
|
|
13871
14150
|
function installedByUs(directory) {
|
|
13872
|
-
return
|
|
14151
|
+
return existsSync9(join12(directory, VERSION_MARKER));
|
|
13873
14152
|
}
|
|
13874
14153
|
function projectStructure(projectPath) {
|
|
13875
14154
|
const structure = { scenes: 0, scripts: 0, assets: 0, other: 0 };
|
|
@@ -13982,7 +14261,7 @@ function scriptsWithoutUid(projectPath) {
|
|
|
13982
14261
|
continue;
|
|
13983
14262
|
}
|
|
13984
14263
|
const extension = entry.name.split(".").pop()?.toLowerCase() ?? "";
|
|
13985
|
-
if (CARRIES_A_UID.has(extension) && !
|
|
14264
|
+
if (CARRIES_A_UID.has(extension) && !existsSync9(join12(directory, `${entry.name}.uid`))) {
|
|
13986
14265
|
found.push(spelled);
|
|
13987
14266
|
}
|
|
13988
14267
|
}
|
|
@@ -13993,7 +14272,7 @@ function scriptsWithoutUid(projectPath) {
|
|
|
13993
14272
|
function pathsInUidCache(projectPath) {
|
|
13994
14273
|
let data;
|
|
13995
14274
|
try {
|
|
13996
|
-
data =
|
|
14275
|
+
data = readFileSync12(join12(projectPath, ".godot", "uid_cache.bin"));
|
|
13997
14276
|
} catch {
|
|
13998
14277
|
return null;
|
|
13999
14278
|
}
|
|
@@ -14055,7 +14334,7 @@ function projectTexts(projectPath) {
|
|
|
14055
14334
|
if (!entry.isFile() || BINARY_EXTENSIONS.has(extension)) {
|
|
14056
14335
|
continue;
|
|
14057
14336
|
}
|
|
14058
|
-
const bytes =
|
|
14337
|
+
const bytes = readFileSync12(absolute);
|
|
14059
14338
|
if (!isBinary(bytes)) {
|
|
14060
14339
|
found.push({ path: `res://${spelled}`, absolute, text: bytes.toString("utf8") });
|
|
14061
14340
|
}
|
|
@@ -14085,7 +14364,7 @@ function ignoredTexts(projectPath) {
|
|
|
14085
14364
|
if (!under || !entry.isFile() || BINARY_EXTENSIONS.has(extension) || entry.name === ".gdignore") {
|
|
14086
14365
|
continue;
|
|
14087
14366
|
}
|
|
14088
|
-
const bytes =
|
|
14367
|
+
const bytes = readFileSync12(absolute);
|
|
14089
14368
|
if (!isBinary(bytes)) {
|
|
14090
14369
|
found.push({ path: `res://${spelled}`, absolute, text: bytes.toString("utf8") });
|
|
14091
14370
|
}
|
|
@@ -14133,7 +14412,7 @@ function searchProject(projectPath, options) {
|
|
|
14133
14412
|
if (extensions !== null && !extensions.has(extension)) {
|
|
14134
14413
|
return;
|
|
14135
14414
|
}
|
|
14136
|
-
const bytes =
|
|
14415
|
+
const bytes = readFileSync12(entryPath);
|
|
14137
14416
|
if (extensions === null && isBinary(bytes)) {
|
|
14138
14417
|
return;
|
|
14139
14418
|
}
|
|
@@ -14249,7 +14528,7 @@ var init_project_scan = __esm(() => {
|
|
|
14249
14528
|
|
|
14250
14529
|
// src/import-freshness.ts
|
|
14251
14530
|
import { createHash as createHash2 } from "node:crypto";
|
|
14252
|
-
import { existsSync as
|
|
14531
|
+
import { existsSync as existsSync10, readdirSync as readdirSync8, readFileSync as readFileSync13, statSync as statSync10 } from "node:fs";
|
|
14253
14532
|
import { join as join13 } from "node:path";
|
|
14254
14533
|
function md5Of(file) {
|
|
14255
14534
|
let stats;
|
|
@@ -14264,7 +14543,7 @@ function md5Of(file) {
|
|
|
14264
14543
|
}
|
|
14265
14544
|
let md5;
|
|
14266
14545
|
try {
|
|
14267
|
-
md5 = createHash2("md5").update(
|
|
14546
|
+
md5 = createHash2("md5").update(readFileSync13(file)).digest("hex");
|
|
14268
14547
|
} catch {
|
|
14269
14548
|
return null;
|
|
14270
14549
|
}
|
|
@@ -14298,7 +14577,7 @@ function importedIntoTheProject(projectPath, resPaths) {
|
|
|
14298
14577
|
for (const resPath of resPaths) {
|
|
14299
14578
|
let sidecar;
|
|
14300
14579
|
try {
|
|
14301
|
-
sidecar =
|
|
14580
|
+
sidecar = readFileSync13(`${onDisk(projectPath, resPath)}.import`, "utf8");
|
|
14302
14581
|
} catch {
|
|
14303
14582
|
continue;
|
|
14304
14583
|
}
|
|
@@ -14331,7 +14610,7 @@ function importedSidecarMd5s(projectPath) {
|
|
|
14331
14610
|
}
|
|
14332
14611
|
let text;
|
|
14333
14612
|
try {
|
|
14334
|
-
text =
|
|
14613
|
+
text = readFileSync13(join13(editor, `filesystem_cache${newest}`), "utf8");
|
|
14335
14614
|
} catch {
|
|
14336
14615
|
return found;
|
|
14337
14616
|
}
|
|
@@ -14375,7 +14654,7 @@ function behind(projectPath, resPath, sidecarFile, sidecar, importedFrom) {
|
|
|
14375
14654
|
return "its import file names no imported output, as one written before the engine imports from it does";
|
|
14376
14655
|
}
|
|
14377
14656
|
}
|
|
14378
|
-
if (outputs.some((output) => !
|
|
14657
|
+
if (outputs.some((output) => !existsSync10(onDisk(projectPath, output)))) {
|
|
14379
14658
|
return "its imported output is not on disk";
|
|
14380
14659
|
}
|
|
14381
14660
|
const source = unquoted(deps.get("source_file"));
|
|
@@ -14386,7 +14665,7 @@ function behind(projectPath, resPath, sidecarFile, sidecar, importedFrom) {
|
|
|
14386
14665
|
const record = join13(projectPath, ".godot", "imported", `${name}-${createHash2("md5").update(resPath, "utf8").digest("hex")}.md5`);
|
|
14387
14666
|
let recorded = "";
|
|
14388
14667
|
try {
|
|
14389
|
-
recorded = /^source_md5="([0-9a-f]*)"/m.exec(
|
|
14668
|
+
recorded = /^source_md5="([0-9a-f]*)"/m.exec(readFileSync13(record, "utf8"))?.[1] ?? "";
|
|
14390
14669
|
} catch {
|
|
14391
14670
|
recorded = "";
|
|
14392
14671
|
}
|
|
@@ -14400,7 +14679,7 @@ function staleImports(projectPath) {
|
|
|
14400
14679
|
const stale = [];
|
|
14401
14680
|
const importedFrom = importedSidecarMd5s(projectPath);
|
|
14402
14681
|
const visit = (directory, resDirectory) => {
|
|
14403
|
-
if (
|
|
14682
|
+
if (existsSync10(join13(directory, ".gdignore")) || existsSync10(join13(directory, VERSION_MARKER))) {
|
|
14404
14683
|
return;
|
|
14405
14684
|
}
|
|
14406
14685
|
let entries;
|
|
@@ -14430,7 +14709,7 @@ function staleImports(projectPath) {
|
|
|
14430
14709
|
const sidecarFile = join13(directory, entry.name);
|
|
14431
14710
|
let sidecar;
|
|
14432
14711
|
try {
|
|
14433
|
-
sidecar =
|
|
14712
|
+
sidecar = readFileSync13(sidecarFile, "utf8");
|
|
14434
14713
|
} catch {
|
|
14435
14714
|
continue;
|
|
14436
14715
|
}
|
|
@@ -14491,10 +14770,10 @@ var init_import_freshness = __esm(() => {
|
|
|
14491
14770
|
|
|
14492
14771
|
// src/library-copies.ts
|
|
14493
14772
|
import {
|
|
14494
|
-
existsSync as
|
|
14773
|
+
existsSync as existsSync11,
|
|
14495
14774
|
mkdirSync as mkdirSync4,
|
|
14496
14775
|
readdirSync as readdirSync9,
|
|
14497
|
-
readFileSync as
|
|
14776
|
+
readFileSync as readFileSync14,
|
|
14498
14777
|
renameSync as renameSync3,
|
|
14499
14778
|
unlinkSync,
|
|
14500
14779
|
writeFileSync as writeFileSync7
|
|
@@ -14509,7 +14788,7 @@ function freeLibraryCopies(projectPath, platform = process.platform) {
|
|
|
14509
14788
|
for (const library of windowsLibraries(projectPath)) {
|
|
14510
14789
|
const folder = dirname6(library);
|
|
14511
14790
|
const copy = `~${basename7(library)}`;
|
|
14512
|
-
if (
|
|
14791
|
+
if (existsSync11(join14(folder, copy))) {
|
|
14513
14792
|
const aside = join14(folder, `${copy}.aside-${process.pid}-${Date.now()}`);
|
|
14514
14793
|
try {
|
|
14515
14794
|
renameSync3(join14(folder, copy), aside);
|
|
@@ -14535,12 +14814,26 @@ function freeLibraryCopies(projectPath, platform = process.platform) {
|
|
|
14535
14814
|
}
|
|
14536
14815
|
function seedExtensionList(projectPath) {
|
|
14537
14816
|
const list = join14(projectPath, ".godot", "extension_list.cfg");
|
|
14538
|
-
if (
|
|
14817
|
+
if (existsSync11(list)) {
|
|
14539
14818
|
return null;
|
|
14540
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
|
+
}
|
|
14541
14834
|
const found = [];
|
|
14542
14835
|
const visit = (directory, resDirectory) => {
|
|
14543
|
-
if (
|
|
14836
|
+
if (existsSync11(join14(directory, ".gdignore"))) {
|
|
14544
14837
|
return;
|
|
14545
14838
|
}
|
|
14546
14839
|
let entries;
|
|
@@ -14561,15 +14854,7 @@ function seedExtensionList(projectPath) {
|
|
|
14561
14854
|
}
|
|
14562
14855
|
};
|
|
14563
14856
|
visit(projectPath, "res://");
|
|
14564
|
-
|
|
14565
|
-
return [];
|
|
14566
|
-
}
|
|
14567
|
-
found.sort();
|
|
14568
|
-
mkdirSync4(dirname6(list), { recursive: true });
|
|
14569
|
-
writeFileSync7(list, `${found.join(`
|
|
14570
|
-
`)}
|
|
14571
|
-
`);
|
|
14572
|
-
return found;
|
|
14857
|
+
return found.sort();
|
|
14573
14858
|
}
|
|
14574
14859
|
function windowsLibraries(projectPath) {
|
|
14575
14860
|
const listed = readOrNull(join14(projectPath, ".godot", "extension_list.cfg"));
|
|
@@ -14610,7 +14895,7 @@ function resolveResource(projectPath, relativeTo, path) {
|
|
|
14610
14895
|
}
|
|
14611
14896
|
function readOrNull(path) {
|
|
14612
14897
|
try {
|
|
14613
|
-
return
|
|
14898
|
+
return readFileSync14(path, "utf8");
|
|
14614
14899
|
} catch {
|
|
14615
14900
|
return null;
|
|
14616
14901
|
}
|
|
@@ -14619,16 +14904,16 @@ var init_library_copies = () => {};
|
|
|
14619
14904
|
|
|
14620
14905
|
// src/reimport.ts
|
|
14621
14906
|
import { createHash as createHash3 } from "node:crypto";
|
|
14622
|
-
import { existsSync as
|
|
14907
|
+
import { existsSync as existsSync12, readFileSync as readFileSync15, rmSync as rmSync8, statSync as statSync11, utimesSync, writeFileSync as writeFileSync8 } from "node:fs";
|
|
14623
14908
|
import { basename as basename8, join as join15 } from "node:path";
|
|
14624
14909
|
function forceNextImport(projectPath, resourcePath) {
|
|
14625
14910
|
const relative = resourcePath.replace(/^res:\/\//, "");
|
|
14626
14911
|
const sidecar = join15(projectPath, `${relative}.import`);
|
|
14627
|
-
if (!
|
|
14912
|
+
if (!existsSync12(sidecar)) {
|
|
14628
14913
|
return;
|
|
14629
14914
|
}
|
|
14630
14915
|
const { atime, mtimeMs } = statSync11(sidecar);
|
|
14631
|
-
writeFileSync8(sidecar,
|
|
14916
|
+
writeFileSync8(sidecar, readFileSync15(sidecar, "utf8").replace(/^valid=false\r?\n/m, ""));
|
|
14632
14917
|
utimesSync(sidecar, atime, new Date(mtimeMs + 2000));
|
|
14633
14918
|
rmSync8(importRecord(projectPath, resourcePath), { force: true });
|
|
14634
14919
|
}
|
|
@@ -14639,7 +14924,7 @@ function importRecord(projectPath, resourcePath) {
|
|
|
14639
14924
|
var init_reimport = () => {};
|
|
14640
14925
|
|
|
14641
14926
|
// src/scratch.ts
|
|
14642
|
-
import { existsSync as
|
|
14927
|
+
import { existsSync as existsSync13, mkdtempSync as mkdtempSync2, readdirSync as readdirSync10, rmSync as rmSync9 } from "node:fs";
|
|
14643
14928
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
14644
14929
|
import { join as join16 } from "node:path";
|
|
14645
14930
|
import process10 from "node:process";
|
|
@@ -14698,7 +14983,7 @@ function tryAgain(path, attempt) {
|
|
|
14698
14983
|
lastTryOnExit();
|
|
14699
14984
|
}
|
|
14700
14985
|
const after = AGAIN_AFTER_MS[attempt];
|
|
14701
|
-
if (after === undefined || !
|
|
14986
|
+
if (after === undefined || !existsSync13(path)) {
|
|
14702
14987
|
waiting.delete(path);
|
|
14703
14988
|
if (after === undefined) {
|
|
14704
14989
|
atExit.add(path);
|
|
@@ -14854,7 +15139,7 @@ var init_script_origins = __esm(() => {
|
|
|
14854
15139
|
});
|
|
14855
15140
|
|
|
14856
15141
|
// src/headless.ts
|
|
14857
|
-
import { existsSync as
|
|
15142
|
+
import { existsSync as existsSync14, readFileSync as readFileSync16, writeFileSync as writeFileSync9 } from "node:fs";
|
|
14858
15143
|
import { dirname as dirname7, join as join18 } from "node:path";
|
|
14859
15144
|
function snakeCased(params) {
|
|
14860
15145
|
const result = emptyRecord();
|
|
@@ -15143,10 +15428,10 @@ async function operationOutcome(engine, operation, params, projectPath) {
|
|
|
15143
15428
|
};
|
|
15144
15429
|
}
|
|
15145
15430
|
function answerIn(file) {
|
|
15146
|
-
if (!
|
|
15431
|
+
if (!existsSync14(file)) {
|
|
15147
15432
|
return { kind: "none" };
|
|
15148
15433
|
}
|
|
15149
|
-
const text =
|
|
15434
|
+
const text = readFileSync16(file, "utf8");
|
|
15150
15435
|
try {
|
|
15151
15436
|
const parsed = JSON.parse(text);
|
|
15152
15437
|
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? { kind: "answer", payload: parsed } : { kind: "unreadable", why: `it is JSON but not an object: ${text.slice(0, 200)}` };
|
|
@@ -15172,7 +15457,7 @@ var init_headless = __esm(() => {
|
|
|
15172
15457
|
});
|
|
15173
15458
|
|
|
15174
15459
|
// src/update-check.ts
|
|
15175
|
-
import { existsSync as
|
|
15460
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync5, readFileSync as readFileSync17, writeFileSync as writeFileSync10 } from "node:fs";
|
|
15176
15461
|
import { homedir as homedir6, tmpdir as tmpdir6 } from "node:os";
|
|
15177
15462
|
import { join as join19 } from "node:path";
|
|
15178
15463
|
function packageUrl(root) {
|
|
@@ -15214,10 +15499,10 @@ function cacheFile(environment = process.env) {
|
|
|
15214
15499
|
}
|
|
15215
15500
|
function readCache(path) {
|
|
15216
15501
|
try {
|
|
15217
|
-
if (!
|
|
15502
|
+
if (!existsSync15(path)) {
|
|
15218
15503
|
return null;
|
|
15219
15504
|
}
|
|
15220
|
-
const parsed = JSON.parse(
|
|
15505
|
+
const parsed = JSON.parse(readFileSync17(path, "utf8"));
|
|
15221
15506
|
if (typeof parsed !== "object" || parsed === null) {
|
|
15222
15507
|
return null;
|
|
15223
15508
|
}
|
|
@@ -15365,7 +15650,7 @@ var init_update_check = __esm(() => {
|
|
|
15365
15650
|
});
|
|
15366
15651
|
|
|
15367
15652
|
// src/server-version.ts
|
|
15368
|
-
import { readFileSync as
|
|
15653
|
+
import { readFileSync as readFileSync18 } from "node:fs";
|
|
15369
15654
|
function staleAddon(addonDigest, shippedDigest) {
|
|
15370
15655
|
return addonDigest !== shippedDigest;
|
|
15371
15656
|
}
|
|
@@ -15424,7 +15709,7 @@ var init_server_version = __esm(() => {
|
|
|
15424
15709
|
DEBUG_MODE = process.env["GDHARNESS_DEBUG"] === "1";
|
|
15425
15710
|
SERVER_VERSION = (() => {
|
|
15426
15711
|
try {
|
|
15427
|
-
const pkg = JSON.parse(
|
|
15712
|
+
const pkg = JSON.parse(readFileSync18(new URL("../package.json", import.meta.url), "utf8"));
|
|
15428
15713
|
return typeof pkg.version === "string" ? pkg.version : "0.0.0";
|
|
15429
15714
|
} catch {
|
|
15430
15715
|
return "0.0.0";
|
|
@@ -15694,7 +15979,7 @@ var init_ports = __esm(() => {
|
|
|
15694
15979
|
});
|
|
15695
15980
|
|
|
15696
15981
|
// src/lsp_client.ts
|
|
15697
|
-
import { existsSync as
|
|
15982
|
+
import { existsSync as existsSync16, realpathSync as realpathSync3 } from "node:fs";
|
|
15698
15983
|
import { readFile, realpath } from "node:fs/promises";
|
|
15699
15984
|
import { createConnection } from "node:net";
|
|
15700
15985
|
import { dirname as dirname8, extname as extname3, join as join20, resolve as resolve7 } from "node:path";
|
|
@@ -16375,7 +16660,7 @@ async function resolveLSPPaths(projectPathValue, scriptPathValue) {
|
|
|
16375
16660
|
} catch {
|
|
16376
16661
|
throw new ArgumentRefusal(`Project path does not exist: ${requestedProjectPath}`);
|
|
16377
16662
|
}
|
|
16378
|
-
if (!
|
|
16663
|
+
if (!existsSync16(join20(projectPath, "project.godot"))) {
|
|
16379
16664
|
throw new ArgumentRefusal(`Not a Godot project: ${projectPath}. Point projectPath at the directory holding project.godot.`);
|
|
16380
16665
|
}
|
|
16381
16666
|
const contained = resolveWithinProject(projectPath, scriptPathValue);
|
|
@@ -16540,7 +16825,7 @@ var init_lsp_client = __esm(() => {
|
|
|
16540
16825
|
});
|
|
16541
16826
|
|
|
16542
16827
|
// src/resources.ts
|
|
16543
|
-
import { readFileSync as
|
|
16828
|
+
import { readFileSync as readFileSync20, realpathSync as realpathSync4 } from "node:fs";
|
|
16544
16829
|
import { extname as extname4, resolve as resolve9 } from "node:path";
|
|
16545
16830
|
function ensureProjectPath(getProjectPath) {
|
|
16546
16831
|
const projectPath = getProjectPath();
|
|
@@ -16736,7 +17021,7 @@ function readResourceText(uri, getProjectPath) {
|
|
|
16736
17021
|
const parsedUri = parseGodotUri(uri);
|
|
16737
17022
|
if (parsedUri.kind === "project-info") {
|
|
16738
17023
|
const projectFilePath = resolveProjectFile(projectPath, "project.godot");
|
|
16739
|
-
const rawProject =
|
|
17024
|
+
const rawProject = readFileSync20(projectFilePath, "utf-8");
|
|
16740
17025
|
const parsedProject = parseProjectGodot(rawProject);
|
|
16741
17026
|
return {
|
|
16742
17027
|
mimeType: "application/json",
|
|
@@ -16745,7 +17030,7 @@ function readResourceText(uri, getProjectPath) {
|
|
|
16745
17030
|
}
|
|
16746
17031
|
const filePath = resolveProjectFile(projectPath, parsedUri.resourcePath);
|
|
16747
17032
|
ensureAllowedExtension(parsedUri.kind, filePath);
|
|
16748
|
-
const text =
|
|
17033
|
+
const text = readFileSync20(filePath, "utf-8");
|
|
16749
17034
|
return {
|
|
16750
17035
|
mimeType: parsedUri.kind === "script" ? "text/x-gdscript" : "text/plain",
|
|
16751
17036
|
text
|
|
@@ -16889,10 +17174,10 @@ function readParams(params, key) {
|
|
|
16889
17174
|
import { createHash as createHash5 } from "node:crypto";
|
|
16890
17175
|
import {
|
|
16891
17176
|
cpSync,
|
|
16892
|
-
existsSync as
|
|
17177
|
+
existsSync as existsSync18,
|
|
16893
17178
|
mkdirSync as mkdirSync6,
|
|
16894
17179
|
readdirSync as readdirSync12,
|
|
16895
|
-
readFileSync as
|
|
17180
|
+
readFileSync as readFileSync21,
|
|
16896
17181
|
rmdirSync,
|
|
16897
17182
|
rmSync as rmSync10,
|
|
16898
17183
|
statSync as statSync12,
|
|
@@ -16926,7 +17211,7 @@ function addonsDigest(names, from) {
|
|
|
16926
17211
|
} else {
|
|
16927
17212
|
hash.update(`${inside}
|
|
16928
17213
|
`);
|
|
16929
|
-
hash.update(
|
|
17214
|
+
hash.update(readFileSync21(path));
|
|
16930
17215
|
hash.update(`
|
|
16931
17216
|
`);
|
|
16932
17217
|
}
|
|
@@ -16972,10 +17257,10 @@ function installedRuntimeDigest(projectPath) {
|
|
|
16972
17257
|
}
|
|
16973
17258
|
function digestMarker(projectPath, addon) {
|
|
16974
17259
|
const marker = join22(projectPath, "addons", addon, DIGEST_MARKER);
|
|
16975
|
-
if (!
|
|
17260
|
+
if (!existsSync18(marker)) {
|
|
16976
17261
|
return null;
|
|
16977
17262
|
}
|
|
16978
|
-
const said =
|
|
17263
|
+
const said = readFileSync21(marker, "utf8").trim();
|
|
16979
17264
|
return said === "" ? null : said;
|
|
16980
17265
|
}
|
|
16981
17266
|
function shippedAddonsDirectory() {
|
|
@@ -16989,10 +17274,10 @@ function shippedLoader() {
|
|
|
16989
17274
|
}
|
|
16990
17275
|
function loaderState(projectPath) {
|
|
16991
17276
|
const copy = join22(projectPath, ...RUNTIME_AUTOLOAD.path.split("/"));
|
|
16992
|
-
if (!
|
|
17277
|
+
if (!existsSync18(copy)) {
|
|
16993
17278
|
return "missing";
|
|
16994
17279
|
}
|
|
16995
|
-
const lines = (path) =>
|
|
17280
|
+
const lines = (path) => readFileSync21(path, "utf8").replaceAll(`\r
|
|
16996
17281
|
`, `
|
|
16997
17282
|
`);
|
|
16998
17283
|
return lines(copy) === lines(shippedLoader()) ? "current" : "differs";
|
|
@@ -17003,12 +17288,12 @@ function writeLoader(projectPath) {
|
|
|
17003
17288
|
}
|
|
17004
17289
|
const copy = join22(projectPath, ...RUNTIME_AUTOLOAD.path.split("/"));
|
|
17005
17290
|
mkdirSync6(dirname9(copy), { recursive: true });
|
|
17006
|
-
writeFileSync11(copy,
|
|
17291
|
+
writeFileSync11(copy, readFileSync21(shippedLoader()));
|
|
17007
17292
|
return true;
|
|
17008
17293
|
}
|
|
17009
17294
|
function removeLoader(projectPath) {
|
|
17010
17295
|
const copy = join22(projectPath, ...RUNTIME_AUTOLOAD.path.split("/"));
|
|
17011
|
-
if (!
|
|
17296
|
+
if (!existsSync18(copy)) {
|
|
17012
17297
|
return false;
|
|
17013
17298
|
}
|
|
17014
17299
|
rmSync10(copy);
|
|
@@ -17024,10 +17309,10 @@ function shippedListedRunner() {
|
|
|
17024
17309
|
}
|
|
17025
17310
|
function gdUnit4Unusable(projectPath) {
|
|
17026
17311
|
const marker = "addons/gdUnit4/plugin.cfg";
|
|
17027
|
-
if (!
|
|
17312
|
+
if (!existsSync18(join22(projectPath, ...marker.split("/")))) {
|
|
17028
17313
|
return { missing: true, reason: `gdUnit4 is not installed in this project: no ${marker}` };
|
|
17029
17314
|
}
|
|
17030
|
-
if (!
|
|
17315
|
+
if (!existsSync18(join22(projectPath, ...GDUNIT4_CI_RUNNER.split("/")))) {
|
|
17031
17316
|
return {
|
|
17032
17317
|
missing: false,
|
|
17033
17318
|
reason: `gdUnit4 in this project is older than 6.0, which the shipped runner needs: no ${GDUNIT4_CI_RUNNER}`
|
|
@@ -17039,11 +17324,11 @@ function installAddons(projectPath, from = shippedAddonsDirectory()) {
|
|
|
17039
17324
|
const installed = [];
|
|
17040
17325
|
for (const name of ADDONS) {
|
|
17041
17326
|
const source = join22(from, name);
|
|
17042
|
-
if (!
|
|
17327
|
+
if (!existsSync18(join22(source, addonMarking(name)))) {
|
|
17043
17328
|
throw new Error(`The package holds no ${name} addon at ${source}.`);
|
|
17044
17329
|
}
|
|
17045
17330
|
const target = join22(projectPath, "addons", name);
|
|
17046
|
-
const replaced =
|
|
17331
|
+
const replaced = existsSync18(target);
|
|
17047
17332
|
rmSync10(target, { recursive: true, force: true });
|
|
17048
17333
|
mkdirSync6(dirname9(target), { recursive: true });
|
|
17049
17334
|
cpSync(source, target, { recursive: true });
|
|
@@ -17059,23 +17344,23 @@ function installAddons(projectPath, from = shippedAddonsDirectory()) {
|
|
|
17059
17344
|
}
|
|
17060
17345
|
function installedAddonVersion(projectPath) {
|
|
17061
17346
|
const marker = join22(projectPath, "addons", ADDONS[0], VERSION_MARKER);
|
|
17062
|
-
if (!
|
|
17347
|
+
if (!existsSync18(marker)) {
|
|
17063
17348
|
return null;
|
|
17064
17349
|
}
|
|
17065
|
-
const said =
|
|
17350
|
+
const said = readFileSync21(marker, "utf8").trim();
|
|
17066
17351
|
return said === "" ? null : said;
|
|
17067
17352
|
}
|
|
17068
17353
|
function removeAddons(projectPath) {
|
|
17069
17354
|
const removed = [];
|
|
17070
17355
|
for (const name of ADDONS) {
|
|
17071
17356
|
const target = join22(projectPath, "addons", name);
|
|
17072
|
-
if (
|
|
17357
|
+
if (existsSync18(target)) {
|
|
17073
17358
|
rmSync10(target, { recursive: true, force: true });
|
|
17074
17359
|
removed.push(target);
|
|
17075
17360
|
}
|
|
17076
17361
|
}
|
|
17077
17362
|
const addons = join22(projectPath, "addons");
|
|
17078
|
-
if (removed.length > 0 &&
|
|
17363
|
+
if (removed.length > 0 && existsSync18(addons) && readdirSync12(addons).length === 0) {
|
|
17079
17364
|
rmdirSync(addons);
|
|
17080
17365
|
removed.push(addons);
|
|
17081
17366
|
}
|
|
@@ -17117,7 +17402,7 @@ function loaderAmong(projectPath, named) {
|
|
|
17117
17402
|
}
|
|
17118
17403
|
let source = null;
|
|
17119
17404
|
try {
|
|
17120
|
-
source =
|
|
17405
|
+
source = readFileSync21(join22(projectPath, path), "utf8");
|
|
17121
17406
|
} catch {}
|
|
17122
17407
|
if (source?.includes(RUNTIME_SCRIPT)) {
|
|
17123
17408
|
return { name: entry, path, exists: true };
|
|
@@ -17175,8 +17460,8 @@ function inspectProject(projectPath) {
|
|
|
17175
17460
|
const addons = ADDONS.map((name) => {
|
|
17176
17461
|
const directory = join22(projectPath, "addons", name);
|
|
17177
17462
|
const marker = join22(directory, VERSION_MARKER);
|
|
17178
|
-
const installed =
|
|
17179
|
-
const version =
|
|
17463
|
+
const installed = existsSync18(directory);
|
|
17464
|
+
const version = existsSync18(marker) ? readFileSync21(marker, "utf8").trim() : null;
|
|
17180
17465
|
const current = version === SERVER_VERSION;
|
|
17181
17466
|
if (!installed) {
|
|
17182
17467
|
problems.push(`addons/${name} is not installed; run gdharness setup`);
|
|
@@ -17185,7 +17470,7 @@ function inspectProject(projectPath) {
|
|
|
17185
17470
|
}
|
|
17186
17471
|
return { name, installed, version, current };
|
|
17187
17472
|
});
|
|
17188
|
-
const settings = parseProjectGodot(
|
|
17473
|
+
const settings = parseProjectGodot(readFileSync21(join22(projectPath, "project.godot"), "utf8"));
|
|
17189
17474
|
const pluginsEnabled = enabledPlugins(settings);
|
|
17190
17475
|
for (const name of EDITOR_PLUGINS) {
|
|
17191
17476
|
if (!pluginsEnabled.includes(name)) {
|
|
@@ -17209,7 +17494,7 @@ function inspectProject(projectPath) {
|
|
|
17209
17494
|
const ignoredAutoloads = [];
|
|
17210
17495
|
const addonMissing = (path) => addons.some((addon) => !addon.installed && path.startsWith(`addons/${addon.name}/`));
|
|
17211
17496
|
for (const [name, path] of named) {
|
|
17212
|
-
if (!
|
|
17497
|
+
if (!existsSync18(join22(projectPath, path))) {
|
|
17213
17498
|
if (!addonMissing(path)) {
|
|
17214
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`);
|
|
17215
17500
|
}
|
|
@@ -17905,7 +18190,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
17905
18190
|
{
|
|
17906
18191
|
name: "project_export",
|
|
17907
18192
|
title: "Export",
|
|
17908
|
-
description: "Export presets and exports. add_preset writes a preset to export_presets.cfg with the keys the editor's Project > Export writes for a new one and every option a new preset of its platform shows, each at its default, and makes it the platform's runnable preset when the platform has none. set_preset changes a preset's export path, its resource filter and the files it lists, its include and exclude filters, its custom features and its platform's options, and answers under changed what each held before and holds now, and under unchanged what already held the value given, with saved false when that is all of it, since the file is then not written; nothing is written when any of it is refused. The option names are the exporter's own, as the Export dialog's Options tab shows them by their paths, such as binary_format/embed_pck, and a name the platform does not have is refused with the nearest it has, or all of them when none is near. An option the dialog shows only while another is on, such as codesign/identity behind codesign/enable, is taken when the preset has that one on or the same call turns it on, and otherwise refused naming what shows it. A secret option, such as a signing password, is written to .godot/export_credentials.cfg, where the editor keeps secrets out of the committed file, and its value is never answered. A file an option names that is not there is written and listed under missing_files, or for a secret its option under secretsNamingNoFile. remove_preset takes a preset out, and when it was its platform's runnable preset the next of that platform becomes it, under runnableNow, which is null when the platform has no other; a secret it held is taken out with it. It answers where this engine's export templates belong and whether the preset's platform has them, since an export needs them; list says the same for every preset. An editor open on the project does not see a preset added this way until it restarts. run answers bytes, the size of the output it wrote, and names, as alsoWritten, what else the export wrote beside its output, such as the .pck a Windows or Linux build cannot start without. Its entries are the errors and warnings the export printed, the newest two hundred distinct ones, one printed more than once carrying times, and errors and warnings count them; exported is true only when this run wrote the output and printed no error.",
|
|
18193
|
+
description: "Export presets and exports. add_preset writes a preset to export_presets.cfg with the keys the editor's Project > Export writes for a new one and every option a new preset of its platform shows, each at its default, and makes it the platform's runnable preset when the platform has none. set_preset changes a preset's export path, its resource filter and the files it lists, its include and exclude filters, its custom features and its platform's options, and answers under changed what each held before and holds now, and under unchanged what already held the value given, with saved false when that is all of it, since the file is then not written; nothing is written when any of it is refused. The option names are the exporter's own, as the Export dialog's Options tab shows them by their paths, such as binary_format/embed_pck, and a name the platform does not have is refused with the nearest it has, or all of them when none is near. An option the dialog shows only while another is on, such as codesign/identity behind codesign/enable, is taken when the preset has that one on or the same call turns it on, and otherwise refused naming what shows it. A secret option, such as a signing password, is written to .godot/export_credentials.cfg, where the editor keeps secrets out of the committed file, and its value is never answered. A file an option names that is not there is written and listed under missing_files, or for a secret its option under secretsNamingNoFile. remove_preset takes a preset out, and when it was its platform's runnable preset the next of that platform becomes it, under runnableNow, which is null when the platform has no other; a secret it held is taken out with it. It answers where this engine's export templates belong and whether the preset's platform has them, since an export needs them; list says the same for every preset. An editor open on the project does not see a preset added this way until it restarts. run first imports whatever changed on disk since it was imported, named under importedFirst, so the build carries each file as it is now. It answers bytes, the size of the output it wrote, and names, as alsoWritten, what else the export wrote beside its output, such as the .pck a Windows or Linux build cannot start without. Its entries are the errors and warnings the export printed, the newest two hundred distinct ones, one printed more than once carrying times, and errors and warnings count them; exported is true only when this run wrote the output and printed no error.",
|
|
17909
18194
|
parameters: {
|
|
17910
18195
|
projectPath: PROJECT_PATH,
|
|
17911
18196
|
preset: {
|
|
@@ -18093,7 +18378,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
18093
18378
|
name: "scene_node",
|
|
18094
18379
|
title: "Scene nodes",
|
|
18095
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}`,
|
|
18096
|
-
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,
|
|
18097
18382
|
parameters: {
|
|
18098
18383
|
projectPath: PROJECT_PATH,
|
|
18099
18384
|
scenePath: SCENE_PATH,
|
|
@@ -19780,7 +20065,7 @@ var init_tool_reference = __esm(() => {
|
|
|
19780
20065
|
});
|
|
19781
20066
|
|
|
19782
20067
|
// src/suite-plan.ts
|
|
19783
|
-
import { existsSync as
|
|
20068
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync9, readFileSync as readFileSync24 } from "node:fs";
|
|
19784
20069
|
import { dirname as dirname11, join as join26, posix as posix3 } from "node:path";
|
|
19785
20070
|
function within(path, folder) {
|
|
19786
20071
|
return path === folder || path.startsWith(`${folder}/`);
|
|
@@ -19797,7 +20082,7 @@ class ProjectScripts {
|
|
|
19797
20082
|
this.projectPath = projectPath;
|
|
19798
20083
|
let settings = {};
|
|
19799
20084
|
try {
|
|
19800
|
-
settings = parseProjectGodot(
|
|
20085
|
+
settings = parseProjectGodot(readFileSync24(join26(projectPath, "project.godot"), "utf8"))["gdharness"] ?? {};
|
|
19801
20086
|
} catch {}
|
|
19802
20087
|
const [section, key] = [NOT_SEARCHED_SETTING, GUESS_WINDOW_SETTING].map((setting) => setting.slice("gdharness/".length));
|
|
19803
20088
|
const listed = settings[section ?? ""];
|
|
@@ -19912,7 +20197,7 @@ class ProjectScripts {
|
|
|
19912
20197
|
}
|
|
19913
20198
|
function readTimes(file) {
|
|
19914
20199
|
try {
|
|
19915
|
-
const parsed = JSON.parse(
|
|
20200
|
+
const parsed = JSON.parse(readFileSync24(file, "utf8"));
|
|
19916
20201
|
return typeof parsed === "object" && parsed !== null ? parsed : {};
|
|
19917
20202
|
} catch {
|
|
19918
20203
|
return {};
|
|
@@ -20192,25 +20477,25 @@ function windowNeedsOf(scripts, paths) {
|
|
|
20192
20477
|
}
|
|
20193
20478
|
function capsFrames(projectPath) {
|
|
20194
20479
|
const file = `${projectPath}/project.godot`;
|
|
20195
|
-
if (!
|
|
20480
|
+
if (!existsSync22(file)) {
|
|
20196
20481
|
return false;
|
|
20197
20482
|
}
|
|
20198
|
-
const cap = parseProjectGodot(
|
|
20483
|
+
const cap = parseProjectGodot(readFileSync24(file, "utf8"))["application"]?.["run/max_fps"];
|
|
20199
20484
|
return typeof cap === "number" && cap > 0;
|
|
20200
20485
|
}
|
|
20201
20486
|
function gdUnitFailsOnPushErrors(projectPath) {
|
|
20202
20487
|
const file = `${projectPath}/project.godot`;
|
|
20203
|
-
if (!
|
|
20488
|
+
if (!existsSync22(file)) {
|
|
20204
20489
|
return false;
|
|
20205
20490
|
}
|
|
20206
|
-
return parseProjectGodot(
|
|
20491
|
+
return parseProjectGodot(readFileSync24(file, "utf8"))["gdunit4"]?.["report/godot/push_error"] === true;
|
|
20207
20492
|
}
|
|
20208
20493
|
function viewportOf(projectPath) {
|
|
20209
20494
|
const file = `${projectPath}/project.godot`;
|
|
20210
|
-
if (!
|
|
20495
|
+
if (!existsSync22(file)) {
|
|
20211
20496
|
return null;
|
|
20212
20497
|
}
|
|
20213
|
-
const text =
|
|
20498
|
+
const text = readFileSync24(file, "utf8");
|
|
20214
20499
|
const width = /^window\/size\/viewport_width\s*=\s*(\d+)/m.exec(text)?.[1];
|
|
20215
20500
|
const height = /^window\/size\/viewport_height\s*=\s*(\d+)/m.exec(text)?.[1];
|
|
20216
20501
|
return width === undefined || height === undefined ? null : { width: Number(width), height: Number(height) };
|
|
@@ -41829,13 +42114,13 @@ var init_stdio = __esm(() => {
|
|
|
41829
42114
|
});
|
|
41830
42115
|
|
|
41831
42116
|
// src/autoload-failure.ts
|
|
41832
|
-
import { existsSync as
|
|
42117
|
+
import { existsSync as existsSync24, readFileSync as readFileSync27 } from "node:fs";
|
|
41833
42118
|
import { join as join29 } from "node:path";
|
|
41834
42119
|
function scriptsAutoloaded(projectPath) {
|
|
41835
42120
|
const scripts = new Map;
|
|
41836
42121
|
let settings;
|
|
41837
42122
|
try {
|
|
41838
|
-
settings = parseProjectGodot(
|
|
42123
|
+
settings = parseProjectGodot(readFileSync27(join29(projectPath, "project.godot"), "utf8"));
|
|
41839
42124
|
} catch {
|
|
41840
42125
|
return scripts;
|
|
41841
42126
|
}
|
|
@@ -41845,11 +42130,11 @@ function scriptsAutoloaded(projectPath) {
|
|
|
41845
42130
|
continue;
|
|
41846
42131
|
}
|
|
41847
42132
|
const scene = join29(projectPath, path);
|
|
41848
|
-
if (!
|
|
42133
|
+
if (!existsSync24(scene)) {
|
|
41849
42134
|
continue;
|
|
41850
42135
|
}
|
|
41851
42136
|
try {
|
|
41852
|
-
for (const named of
|
|
42137
|
+
for (const named of readFileSync27(scene, "utf8").matchAll(/^\[ext_resource\b[^\]]*\btype="Script"[^\]]*\bpath="(res:\/\/[^"]+)"/gm)) {
|
|
41853
42138
|
scripts.set(named[1] ?? "", name);
|
|
41854
42139
|
}
|
|
41855
42140
|
} catch {}
|
|
@@ -41868,11 +42153,11 @@ var init_autoload_failure = __esm(() => {
|
|
|
41868
42153
|
});
|
|
41869
42154
|
|
|
41870
42155
|
// src/runtime-client.ts
|
|
41871
|
-
import { existsSync as
|
|
42156
|
+
import { existsSync as existsSync25, readdirSync as readdirSync16, readFileSync as readFileSync28, statSync as statSync15, unlinkSync as unlinkSync3 } from "node:fs";
|
|
41872
42157
|
import { createConnection as createConnection2 } from "node:net";
|
|
41873
42158
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
41874
42159
|
import { dirname as dirname14, join as join30, resolve as resolve12 } from "node:path";
|
|
41875
|
-
import { setTimeout as
|
|
42160
|
+
import { setTimeout as delay6 } from "node:timers/promises";
|
|
41876
42161
|
function runtimeDirectory(variables = process.env) {
|
|
41877
42162
|
const explicit = envValue("GDHARNESS_RUNTIME_DIR", variables);
|
|
41878
42163
|
if (explicit) {
|
|
@@ -41892,7 +42177,7 @@ function runtimeDirectories(variables = process.env) {
|
|
|
41892
42177
|
function errorReportOf(pid, directories = runtimeDirectories()) {
|
|
41893
42178
|
for (const directory of directories) {
|
|
41894
42179
|
const path = join30(directory, `runtime-${pid}.log`);
|
|
41895
|
-
if (
|
|
42180
|
+
if (existsSync25(path)) {
|
|
41896
42181
|
return path;
|
|
41897
42182
|
}
|
|
41898
42183
|
}
|
|
@@ -41923,7 +42208,7 @@ function reportAlreadyInTranscript(transcript, report) {
|
|
|
41923
42208
|
function parseAnnouncement(file, pid) {
|
|
41924
42209
|
let fields;
|
|
41925
42210
|
try {
|
|
41926
|
-
fields = asParams(JSON.parse(
|
|
42211
|
+
fields = asParams(JSON.parse(readFileSync28(file, "utf8")));
|
|
41927
42212
|
} catch {
|
|
41928
42213
|
return { kind: "rubbish" };
|
|
41929
42214
|
}
|
|
@@ -41995,7 +42280,7 @@ function discoverRuntimes(directories = runtimeDirectories()) {
|
|
|
41995
42280
|
function wentAway(file, pid) {
|
|
41996
42281
|
let project = "";
|
|
41997
42282
|
try {
|
|
41998
|
-
const fields = asParams(JSON.parse(
|
|
42283
|
+
const fields = asParams(JSON.parse(readFileSync28(file, "utf8")));
|
|
41999
42284
|
project = readString(readParams(fields, "project") ?? {}, "path") ?? "";
|
|
42000
42285
|
} catch {
|
|
42001
42286
|
return;
|
|
@@ -42038,7 +42323,7 @@ function strangersAmong(candidates, now, startTimes = startTimesOf) {
|
|
|
42038
42323
|
}).map((one) => one.file));
|
|
42039
42324
|
}
|
|
42040
42325
|
function announcedIn(directory) {
|
|
42041
|
-
if (!
|
|
42326
|
+
if (!existsSync25(directory)) {
|
|
42042
42327
|
return [];
|
|
42043
42328
|
}
|
|
42044
42329
|
const found = [];
|
|
@@ -42091,7 +42376,7 @@ function announcedIn(directory) {
|
|
|
42091
42376
|
return found;
|
|
42092
42377
|
}
|
|
42093
42378
|
async function announcementEnded(pid, directories = runtimeDirectories()) {
|
|
42094
|
-
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));
|
|
42095
42380
|
const first = files[0];
|
|
42096
42381
|
if (first === undefined) {
|
|
42097
42382
|
return;
|
|
@@ -42102,7 +42387,7 @@ async function announcementEnded(pid, directories = runtimeDirectories()) {
|
|
|
42102
42387
|
if (left <= 0) {
|
|
42103
42388
|
return;
|
|
42104
42389
|
}
|
|
42105
|
-
await
|
|
42390
|
+
await delay6(Math.min(LOOK_EVERY_MS, left));
|
|
42106
42391
|
}
|
|
42107
42392
|
wentAway(first, pid);
|
|
42108
42393
|
for (const file of files) {
|
|
@@ -42134,7 +42419,7 @@ async function announcedSince(projectPath, before, waiting = {}) {
|
|
|
42134
42419
|
if (left <= 0 || waiting.giveUp?.() === true) {
|
|
42135
42420
|
return [];
|
|
42136
42421
|
}
|
|
42137
|
-
await
|
|
42422
|
+
await delay6(Math.min(LOOK_EVERY_MS, left));
|
|
42138
42423
|
}
|
|
42139
42424
|
}
|
|
42140
42425
|
function describe2(endpoint) {
|
|
@@ -42510,14 +42795,14 @@ var init_runtime_client = __esm(() => {
|
|
|
42510
42795
|
});
|
|
42511
42796
|
|
|
42512
42797
|
// src/boot-note.ts
|
|
42513
|
-
import { mkdirSync as mkdirSync11, readFileSync as
|
|
42798
|
+
import { mkdirSync as mkdirSync11, readFileSync as readFileSync29, writeFileSync as writeFileSync14 } from "node:fs";
|
|
42514
42799
|
import { dirname as dirname15, join as join31 } from "node:path";
|
|
42515
42800
|
function bootNotePath(projectPath) {
|
|
42516
42801
|
return join31(projectPath, ".godot", "gdharness-boot.json");
|
|
42517
42802
|
}
|
|
42518
42803
|
function readScenes(projectPath) {
|
|
42519
42804
|
try {
|
|
42520
|
-
return asParams(asParams(JSON.parse(
|
|
42805
|
+
return asParams(asParams(JSON.parse(readFileSync29(bootNotePath(projectPath), "utf8")))["scenes"]);
|
|
42521
42806
|
} catch {
|
|
42522
42807
|
return {};
|
|
42523
42808
|
}
|
|
@@ -42559,7 +42844,7 @@ var init_boot_note = __esm(() => {
|
|
|
42559
42844
|
});
|
|
42560
42845
|
|
|
42561
42846
|
// src/breakpoint-note.ts
|
|
42562
|
-
import { mkdirSync as mkdirSync12, readFileSync as
|
|
42847
|
+
import { mkdirSync as mkdirSync12, readFileSync as readFileSync30, rmSync as rmSync14, writeFileSync as writeFileSync15 } from "node:fs";
|
|
42563
42848
|
import { dirname as dirname16, isAbsolute as isAbsolute7, join as join32, relative as relative6 } from "node:path";
|
|
42564
42849
|
function breakpointNotePath(projectPath) {
|
|
42565
42850
|
return join32(projectPath, ".godot", "gdharness-breakpoints.json");
|
|
@@ -42588,7 +42873,7 @@ function writeBreakpointNote(projectPath, held) {
|
|
|
42588
42873
|
}
|
|
42589
42874
|
function readBreakpointNote(projectPath) {
|
|
42590
42875
|
try {
|
|
42591
|
-
const parsed = JSON.parse(
|
|
42876
|
+
const parsed = JSON.parse(readFileSync30(breakpointNotePath(projectPath), "utf8"));
|
|
42592
42877
|
if (typeof parsed !== "object" || parsed === null || !Array.isArray(parsed.breakpoints)) {
|
|
42593
42878
|
return [];
|
|
42594
42879
|
}
|
|
@@ -42621,14 +42906,14 @@ var init_breakpoint_note = __esm(() => {
|
|
|
42621
42906
|
});
|
|
42622
42907
|
|
|
42623
42908
|
// src/class-note.ts
|
|
42624
|
-
import { mkdirSync as mkdirSync13, readFileSync as
|
|
42909
|
+
import { mkdirSync as mkdirSync13, readFileSync as readFileSync31 } from "node:fs";
|
|
42625
42910
|
import { dirname as dirname17, join as join33 } from "node:path";
|
|
42626
42911
|
function classNotePath(projectPath) {
|
|
42627
42912
|
return join33(projectPath, ".godot", "gdharness-classes.json");
|
|
42628
42913
|
}
|
|
42629
42914
|
function readClassNote(projectPath) {
|
|
42630
42915
|
try {
|
|
42631
|
-
const fields = asParams(JSON.parse(
|
|
42916
|
+
const fields = asParams(JSON.parse(readFileSync31(classNotePath(projectPath), "utf8")));
|
|
42632
42917
|
const rebuiltWith = readArray(fields, "rebuiltWith");
|
|
42633
42918
|
if (rebuiltWith === undefined || !rebuiltWith.every((name) => typeof name === "string")) {
|
|
42634
42919
|
return null;
|
|
@@ -42670,16 +42955,16 @@ var init_class_note = __esm(() => {
|
|
|
42670
42955
|
});
|
|
42671
42956
|
|
|
42672
42957
|
// src/config-pin.ts
|
|
42673
|
-
import { existsSync as
|
|
42958
|
+
import { existsSync as existsSync26, readFileSync as readFileSync32 } from "node:fs";
|
|
42674
42959
|
import { join as join34 } from "node:path";
|
|
42675
42960
|
function versionsNamedInConfig(projectPath) {
|
|
42676
42961
|
const config = join34(projectPath, ".mcp.json");
|
|
42677
|
-
if (!
|
|
42962
|
+
if (!existsSync26(config)) {
|
|
42678
42963
|
return [];
|
|
42679
42964
|
}
|
|
42680
42965
|
let text;
|
|
42681
42966
|
try {
|
|
42682
|
-
text =
|
|
42967
|
+
text = readFileSync32(config, "utf8");
|
|
42683
42968
|
JSON.parse(text);
|
|
42684
42969
|
} catch {
|
|
42685
42970
|
return [];
|
|
@@ -42700,7 +42985,7 @@ var init_config_pin = __esm(() => {
|
|
|
42700
42985
|
});
|
|
42701
42986
|
|
|
42702
42987
|
// src/cut-test-run.ts
|
|
42703
|
-
import { existsSync as
|
|
42988
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync14, readFileSync as readFileSync33, rmSync as rmSync15, writeFileSync as writeFileSync16 } from "node:fs";
|
|
42704
42989
|
import { dirname as dirname18, join as join35 } from "node:path";
|
|
42705
42990
|
function keptAt(projectPath) {
|
|
42706
42991
|
return join35(projectPath, ".godot", "gdharness-reports", "cut-run.json");
|
|
@@ -42715,11 +43000,11 @@ function keepCutTestRun(projectPath, run) {
|
|
|
42715
43000
|
}
|
|
42716
43001
|
function takeCutTestRun(projectPath) {
|
|
42717
43002
|
const path = keptAt(projectPath);
|
|
42718
|
-
if (!
|
|
43003
|
+
if (!existsSync27(path)) {
|
|
42719
43004
|
return null;
|
|
42720
43005
|
}
|
|
42721
43006
|
try {
|
|
42722
|
-
const run = JSON.parse(
|
|
43007
|
+
const run = JSON.parse(readFileSync33(path, "utf8"));
|
|
42723
43008
|
rmSync15(path, { force: true });
|
|
42724
43009
|
return typeof run.cutAt === "string" && Array.isArray(run.paths) && run.paths.every((path) => typeof path === "string") ? run : null;
|
|
42725
43010
|
} catch {
|
|
@@ -42761,7 +43046,7 @@ var init_game_debugger = __esm(() => {
|
|
|
42761
43046
|
|
|
42762
43047
|
// src/dap_client.ts
|
|
42763
43048
|
import { createConnection as createConnection3 } from "node:net";
|
|
42764
|
-
import { setTimeout as
|
|
43049
|
+
import { setTimeout as delay7 } from "node:timers/promises";
|
|
42765
43050
|
function fileKey(path) {
|
|
42766
43051
|
return process.platform === "win32" ? path.replaceAll("\\", "/").toLowerCase() : path;
|
|
42767
43052
|
}
|
|
@@ -43241,7 +43526,7 @@ class GodotDAPClient {
|
|
|
43241
43526
|
await this.sendRequest(command, { threadId: resolvedThreadId });
|
|
43242
43527
|
const deadline = Date.now() + this.stepPatienceMs;
|
|
43243
43528
|
while (this.stops === before && this.connected && Date.now() < deadline) {
|
|
43244
|
-
await
|
|
43529
|
+
await delay7(50);
|
|
43245
43530
|
}
|
|
43246
43531
|
return this.stops !== before;
|
|
43247
43532
|
}
|
|
@@ -43267,7 +43552,7 @@ class GodotDAPClient {
|
|
|
43267
43552
|
return answered;
|
|
43268
43553
|
}
|
|
43269
43554
|
} catch {}
|
|
43270
|
-
await
|
|
43555
|
+
await delay7(200);
|
|
43271
43556
|
}
|
|
43272
43557
|
return null;
|
|
43273
43558
|
}
|
|
@@ -43288,7 +43573,7 @@ class GodotDAPClient {
|
|
|
43288
43573
|
break;
|
|
43289
43574
|
}
|
|
43290
43575
|
} catch {}
|
|
43291
|
-
await
|
|
43576
|
+
await delay7(200);
|
|
43292
43577
|
}
|
|
43293
43578
|
if (scopes.length === 0) {
|
|
43294
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`);
|
|
@@ -43321,7 +43606,7 @@ class GodotDAPClient {
|
|
|
43321
43606
|
return { frame, value, ...typeof type === "string" ? { type } : {} };
|
|
43322
43607
|
}
|
|
43323
43608
|
} catch {}
|
|
43324
|
-
await
|
|
43609
|
+
await delay7(200);
|
|
43325
43610
|
}
|
|
43326
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`);
|
|
43327
43612
|
}
|
|
@@ -43483,10 +43768,10 @@ var init_dap_client = __esm(() => {
|
|
|
43483
43768
|
// src/editor-log.ts
|
|
43484
43769
|
import {
|
|
43485
43770
|
closeSync as closeSync5,
|
|
43486
|
-
existsSync as
|
|
43771
|
+
existsSync as existsSync28,
|
|
43487
43772
|
mkdirSync as mkdirSync15,
|
|
43488
43773
|
openSync as openSync5,
|
|
43489
|
-
readFileSync as
|
|
43774
|
+
readFileSync as readFileSync34,
|
|
43490
43775
|
readSync as readSync3,
|
|
43491
43776
|
rmSync as rmSync16,
|
|
43492
43777
|
statSync as statSync16,
|
|
@@ -43501,7 +43786,7 @@ function editorLogNotePath(projectPath) {
|
|
|
43501
43786
|
}
|
|
43502
43787
|
function readEditorLogNote(projectPath) {
|
|
43503
43788
|
try {
|
|
43504
|
-
const fields = asParams(JSON.parse(
|
|
43789
|
+
const fields = asParams(JSON.parse(readFileSync34(editorLogNotePath(projectPath), "utf8")));
|
|
43505
43790
|
const pid = readNumber(fields, "pid");
|
|
43506
43791
|
const startedAt = readString(fields, "startedAt");
|
|
43507
43792
|
const processStartedAt = readNumber(fields, "processStartedAt");
|
|
@@ -43547,7 +43832,7 @@ function editorConsole(projectPath, editorPid, openedByAServer) {
|
|
|
43547
43832
|
return { kind: "another editor", notedPid: noted?.pid ?? null };
|
|
43548
43833
|
}
|
|
43549
43834
|
const path = editorLogPath(projectPath);
|
|
43550
|
-
if (!
|
|
43835
|
+
if (!existsSync28(path)) {
|
|
43551
43836
|
return { kind: "not written" };
|
|
43552
43837
|
}
|
|
43553
43838
|
const log = new GameLog;
|
|
@@ -43605,7 +43890,7 @@ function foldProgress(text) {
|
|
|
43605
43890
|
function theFirstOf(path) {
|
|
43606
43891
|
const whole = statSync16(path).size;
|
|
43607
43892
|
if (whole <= MOST_CONSOLE_BYTES) {
|
|
43608
|
-
return { text:
|
|
43893
|
+
return { text: readFileSync34(path, "utf8") };
|
|
43609
43894
|
}
|
|
43610
43895
|
const handle = openSync5(path, "r");
|
|
43611
43896
|
try {
|
|
@@ -43766,7 +44051,7 @@ var init_editor_log = __esm(() => {
|
|
|
43766
44051
|
});
|
|
43767
44052
|
|
|
43768
44053
|
// src/rename.ts
|
|
43769
|
-
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";
|
|
43770
44055
|
import { dirname as dirname20, posix as posix4 } from "node:path";
|
|
43771
44056
|
|
|
43772
44057
|
class Script {
|
|
@@ -44487,11 +44772,11 @@ function rewritesOf(plan, texts, move) {
|
|
|
44487
44772
|
}
|
|
44488
44773
|
function applyRewrites(rewrites) {
|
|
44489
44774
|
for (const rewrite of rewrites) {
|
|
44490
|
-
const now =
|
|
44775
|
+
const now = readFileSync35(rewrite.absolute, "utf8");
|
|
44491
44776
|
if (now !== rewrite.before) {
|
|
44492
44777
|
throw new Error(`${rewrite.path} changed on disk while the rename was being worked out; nothing was written`);
|
|
44493
44778
|
}
|
|
44494
|
-
if (rewrite.writeTo !== rewrite.absolute &&
|
|
44779
|
+
if (rewrite.writeTo !== rewrite.absolute && existsSync29(rewrite.writeTo)) {
|
|
44495
44780
|
throw new Error(`${rewrite.writeTo} already exists; nothing was written`);
|
|
44496
44781
|
}
|
|
44497
44782
|
}
|
|
@@ -44505,7 +44790,7 @@ function applyRewrites(rewrites) {
|
|
|
44505
44790
|
let movedUid = false;
|
|
44506
44791
|
if (rewrite.writeTo !== rewrite.absolute) {
|
|
44507
44792
|
unlinkSync4(rewrite.absolute);
|
|
44508
|
-
if (
|
|
44793
|
+
if (existsSync29(`${rewrite.absolute}.uid`)) {
|
|
44509
44794
|
renameSync4(`${rewrite.absolute}.uid`, `${rewrite.writeTo}.uid`);
|
|
44510
44795
|
movedUid = true;
|
|
44511
44796
|
}
|
|
@@ -44551,7 +44836,7 @@ var init_rename = __esm(() => {
|
|
|
44551
44836
|
});
|
|
44552
44837
|
|
|
44553
44838
|
// src/rename-symbol.ts
|
|
44554
|
-
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";
|
|
44555
44840
|
import { basename as basename10, dirname as dirname21, join as join37, relative as relative7, resolve as resolve13 } from "node:path";
|
|
44556
44841
|
function resourcePathOf(projectPath, absolute) {
|
|
44557
44842
|
const inside = relative7(onDiskSpelling(projectPath), onDiskSpelling(absolute));
|
|
@@ -44619,7 +44904,7 @@ async function renameSymbol(request, services) {
|
|
|
44619
44904
|
reason: `newScriptPath must be a .gd path inside the project, and ${request.newScriptPath} is not.`
|
|
44620
44905
|
};
|
|
44621
44906
|
}
|
|
44622
|
-
if (
|
|
44907
|
+
if (existsSync30(request.newScriptPath)) {
|
|
44623
44908
|
return { ok: false, reason: `${moveTo} already exists, so the script cannot be moved there.` };
|
|
44624
44909
|
}
|
|
44625
44910
|
}
|
|
@@ -44796,7 +45081,7 @@ async function renameSymbol(request, services) {
|
|
|
44796
45081
|
scripts,
|
|
44797
45082
|
moves: new Map([[declaringPath, moveTo]]),
|
|
44798
45083
|
named: [declaringPath],
|
|
44799
|
-
exists: (path) =>
|
|
45084
|
+
exists: (path) => existsSync30(`${projectPath}/${path.slice("res://".length)}`)
|
|
44800
45085
|
}, plan);
|
|
44801
45086
|
}
|
|
44802
45087
|
plan = mentionIgnored(plan, ignoredTexts(projectPath), symbol, moveTo === null ? [] : [declaringPath]);
|
|
@@ -45071,10 +45356,10 @@ var init_rename_symbol = __esm(() => {
|
|
|
45071
45356
|
|
|
45072
45357
|
// src/file-move.ts
|
|
45073
45358
|
import {
|
|
45074
|
-
existsSync as
|
|
45359
|
+
existsSync as existsSync31,
|
|
45075
45360
|
mkdirSync as mkdirSync18,
|
|
45076
45361
|
readdirSync as readdirSync18,
|
|
45077
|
-
readFileSync as
|
|
45362
|
+
readFileSync as readFileSync36,
|
|
45078
45363
|
renameSync as renameSync5,
|
|
45079
45364
|
statSync as statSync17,
|
|
45080
45365
|
writeFileSync as writeFileSync20
|
|
@@ -45104,7 +45389,7 @@ function unseenByTheEngine(projectPath, path) {
|
|
|
45104
45389
|
}
|
|
45105
45390
|
if (at < steps.length - 1) {
|
|
45106
45391
|
directory = join38(directory, step);
|
|
45107
|
-
if (
|
|
45392
|
+
if (existsSync31(join38(directory, ".gdignore"))) {
|
|
45108
45393
|
return `${path} is under a directory holding a .gdignore, which the engine does not load`;
|
|
45109
45394
|
}
|
|
45110
45395
|
}
|
|
@@ -45116,12 +45401,12 @@ function installedAddonOf(projectPath, path) {
|
|
|
45116
45401
|
if (steps[0] !== "addons" || steps[1] === undefined) {
|
|
45117
45402
|
return null;
|
|
45118
45403
|
}
|
|
45119
|
-
return
|
|
45404
|
+
return existsSync31(join38(projectPath, "addons", steps[1], VERSION_MARKER)) ? `res://addons/${steps[1]}` : null;
|
|
45120
45405
|
}
|
|
45121
45406
|
function binaryResources(projectPath) {
|
|
45122
45407
|
const found = [];
|
|
45123
45408
|
const visit = (directory, prefix) => {
|
|
45124
|
-
if (
|
|
45409
|
+
if (existsSync31(join38(directory, ".gdignore"))) {
|
|
45125
45410
|
return;
|
|
45126
45411
|
}
|
|
45127
45412
|
for (const entry of readdirSync18(directory, { withFileTypes: true })) {
|
|
@@ -45158,7 +45443,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
45158
45443
|
if (to === null) {
|
|
45159
45444
|
return { ok: false, reason: `newPath must be a path inside the project, and ${absoluteTo} is not.` };
|
|
45160
45445
|
}
|
|
45161
|
-
if (!
|
|
45446
|
+
if (!existsSync31(absoluteFrom)) {
|
|
45162
45447
|
return { ok: false, reason: `There is nothing at ${from} to move.` };
|
|
45163
45448
|
}
|
|
45164
45449
|
if (from === to) {
|
|
@@ -45187,7 +45472,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
45187
45472
|
if (isDirectory && to.startsWith(`${from}/`)) {
|
|
45188
45473
|
return { ok: false, reason: `${from} cannot be moved into itself.` };
|
|
45189
45474
|
}
|
|
45190
|
-
if (
|
|
45475
|
+
if (existsSync31(absoluteTo) && !sameFile(absoluteFrom, absoluteTo)) {
|
|
45191
45476
|
return { ok: false, reason: `${to} already exists, so nothing was moved there.` };
|
|
45192
45477
|
}
|
|
45193
45478
|
const unseen = unseenByTheEngine(projectPath, to);
|
|
@@ -45195,7 +45480,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
45195
45480
|
return { ok: false, reason: `${unseen}, so nothing there could load what was moved.` };
|
|
45196
45481
|
}
|
|
45197
45482
|
if (!isDirectory) {
|
|
45198
|
-
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))));
|
|
45199
45484
|
if (owner !== undefined && owner !== null) {
|
|
45200
45485
|
return { ok: false, reason: `${from} belongs to ${owner} and moves with it: move ${owner} instead.` };
|
|
45201
45486
|
}
|
|
@@ -45217,7 +45502,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
45217
45502
|
} else {
|
|
45218
45503
|
moves.set(from, to);
|
|
45219
45504
|
for (const sidecar of SIDECARS) {
|
|
45220
|
-
if (
|
|
45505
|
+
if (existsSync31(`${absoluteFrom}${sidecar}`)) {
|
|
45221
45506
|
moves.set(`${from}${sidecar}`, `${to}${sidecar}`);
|
|
45222
45507
|
}
|
|
45223
45508
|
}
|
|
@@ -45229,12 +45514,12 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
45229
45514
|
scripts,
|
|
45230
45515
|
moves,
|
|
45231
45516
|
named: [from],
|
|
45232
|
-
exists: (path) =>
|
|
45517
|
+
exists: (path) => existsSync31(join38(projectPath, path.slice("res://".length)))
|
|
45233
45518
|
}, { edits: [], mentions: [] });
|
|
45234
45519
|
plan = mentionIgnored(plan, ignoredTexts(projectPath), null, [from]);
|
|
45235
45520
|
const binaries = [];
|
|
45236
45521
|
for (const path of binaryResources(projectPath)) {
|
|
45237
|
-
const bytes =
|
|
45522
|
+
const bytes = readFileSync36(join38(projectPath, path.slice("res://".length)));
|
|
45238
45523
|
const names = [...moves.keys()].find((moving) => bytes.includes(moving));
|
|
45239
45524
|
if (names !== undefined) {
|
|
45240
45525
|
binaries.push({
|
|
@@ -45295,18 +45580,18 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
45295
45580
|
}
|
|
45296
45581
|
function applyFileMove(outcome) {
|
|
45297
45582
|
for (const rewrite of outcome.inPlace) {
|
|
45298
|
-
if (
|
|
45583
|
+
if (readFileSync36(rewrite.absolute, "utf8") !== rewrite.before) {
|
|
45299
45584
|
throw new Error(`${rewrite.path} changed on disk while the move was being worked out; nothing was written`);
|
|
45300
45585
|
}
|
|
45301
45586
|
}
|
|
45302
45587
|
for (const file of outcome.moved) {
|
|
45303
|
-
if (!
|
|
45588
|
+
if (!existsSync31(file.absoluteFrom)) {
|
|
45304
45589
|
throw new Error(`${file.from} is gone from disk; nothing was written`);
|
|
45305
45590
|
}
|
|
45306
|
-
if (file.text !== null &&
|
|
45591
|
+
if (file.text !== null && readFileSync36(file.absoluteFrom, "utf8") !== file.text.before) {
|
|
45307
45592
|
throw new Error(`${file.from} changed on disk while the move was being worked out; nothing was written`);
|
|
45308
45593
|
}
|
|
45309
|
-
if (
|
|
45594
|
+
if (existsSync31(file.absoluteTo) && !sameFile(file.absoluteFrom, file.absoluteTo)) {
|
|
45310
45595
|
throw new Error(`${file.to} already exists; nothing was written`);
|
|
45311
45596
|
}
|
|
45312
45597
|
}
|
|
@@ -49218,44 +49503,6 @@ function notListeningNote(servers, greetedAgoMs) {
|
|
|
49218
49503
|
var STARTING_MS = 20000;
|
|
49219
49504
|
var init_port_probe = () => {};
|
|
49220
49505
|
|
|
49221
|
-
// src/process-time.ts
|
|
49222
|
-
async function cpuSecondsOf(pid) {
|
|
49223
|
-
try {
|
|
49224
|
-
return process.platform === "win32" ? await secondsOnWindows(pid) : await askPosix2(pid);
|
|
49225
|
-
} catch {
|
|
49226
|
-
return;
|
|
49227
|
-
}
|
|
49228
|
-
}
|
|
49229
|
-
async function secondsOnWindows(pid) {
|
|
49230
|
-
const said = (await askProcessTable(`ProcessorSeconds(${pid})`, ASK_TIMEOUT_MS2)).trim();
|
|
49231
|
-
const seconds = Number(said);
|
|
49232
|
-
return said !== "" && Number.isFinite(seconds) ? seconds : undefined;
|
|
49233
|
-
}
|
|
49234
|
-
async function askPosix2(pid) {
|
|
49235
|
-
const { stdout } = await runHidden("ps", ["-o", "time=", "-p", String(pid)], { timeout: ASK_TIMEOUT_MS2 });
|
|
49236
|
-
return secondsFromClock(stdout.trim());
|
|
49237
|
-
}
|
|
49238
|
-
function secondsFromClock(printed) {
|
|
49239
|
-
if (printed === "") {
|
|
49240
|
-
return;
|
|
49241
|
-
}
|
|
49242
|
-
const dashed = printed.includes("-");
|
|
49243
|
-
const days = dashed ? printed.slice(0, printed.indexOf("-")) : null;
|
|
49244
|
-
const clock = dashed ? printed.slice(printed.indexOf("-") + 1) : printed;
|
|
49245
|
-
const parts = clock.split(":").map((part) => Number(part));
|
|
49246
|
-
if (parts.length === 0 || parts.some((part) => !Number.isFinite(part))) {
|
|
49247
|
-
return;
|
|
49248
|
-
}
|
|
49249
|
-
const seconds = parts.reduce((total, part) => total * 60 + part, 0);
|
|
49250
|
-
const extra = days === null ? 0 : Number(days) * 86400;
|
|
49251
|
-
return Number.isFinite(extra) ? seconds + extra : undefined;
|
|
49252
|
-
}
|
|
49253
|
-
var ASK_TIMEOUT_MS2 = 6000;
|
|
49254
|
-
var init_process_time = __esm(() => {
|
|
49255
|
-
init_process_table();
|
|
49256
|
-
init_spawn();
|
|
49257
|
-
});
|
|
49258
|
-
|
|
49259
49506
|
// src/prompts.ts
|
|
49260
49507
|
function listedPrompts() {
|
|
49261
49508
|
return PROMPT_SPECS.map((spec) => ({
|
|
@@ -49393,7 +49640,7 @@ var init_prompts = __esm(() => {
|
|
|
49393
49640
|
});
|
|
49394
49641
|
|
|
49395
49642
|
// src/restart-note.ts
|
|
49396
|
-
import { mkdirSync as mkdirSync20, readFileSync as
|
|
49643
|
+
import { mkdirSync as mkdirSync20, readFileSync as readFileSync37, rmSync as rmSync18, writeFileSync as writeFileSync21 } from "node:fs";
|
|
49397
49644
|
import { dirname as dirname24, join as join40 } from "node:path";
|
|
49398
49645
|
function restartNotePath(projectPath) {
|
|
49399
49646
|
return join40(projectPath, ".godot", "gdharness-restart.json");
|
|
@@ -49410,7 +49657,7 @@ function noteRestartBegun(note) {
|
|
|
49410
49657
|
}
|
|
49411
49658
|
function restartOwed(projectPath) {
|
|
49412
49659
|
try {
|
|
49413
|
-
const parsed = JSON.parse(
|
|
49660
|
+
const parsed = JSON.parse(readFileSync37(restartNotePath(projectPath), "utf8"));
|
|
49414
49661
|
if (typeof parsed !== "object" || parsed === null) {
|
|
49415
49662
|
return null;
|
|
49416
49663
|
}
|
|
@@ -49436,7 +49683,7 @@ var init_restart_note = __esm(() => {
|
|
|
49436
49683
|
|
|
49437
49684
|
// src/run-record.ts
|
|
49438
49685
|
import { createHash as createHash7 } from "node:crypto";
|
|
49439
|
-
import { mkdirSync as mkdirSync21, openSync as openSync6, readdirSync as readdirSync19, readFileSync as
|
|
49686
|
+
import { mkdirSync as mkdirSync21, openSync as openSync6, readdirSync as readdirSync19, readFileSync as readFileSync38, rmSync as rmSync19, statSync as statSync19 } from "node:fs";
|
|
49440
49687
|
import { basename as basename12, join as join41, resolve as resolve14 } from "node:path";
|
|
49441
49688
|
function runsDirectory() {
|
|
49442
49689
|
return join41(runtimeDirectory(), "runs");
|
|
@@ -49460,7 +49707,7 @@ function writeLatestRun(servedBy, latest) {
|
|
|
49460
49707
|
}
|
|
49461
49708
|
function readLatestRun(servedBy, directory = runtimeDirectory()) {
|
|
49462
49709
|
try {
|
|
49463
|
-
const fields = JSON.parse(
|
|
49710
|
+
const fields = JSON.parse(readFileSync38(latestRunPath(servedBy, directory), "utf8"));
|
|
49464
49711
|
if (typeof fields !== "object" || fields === null) {
|
|
49465
49712
|
return null;
|
|
49466
49713
|
}
|
|
@@ -49509,7 +49756,7 @@ function readEditorRunNote(projectPath) {
|
|
|
49509
49756
|
function editorNoteAt(path) {
|
|
49510
49757
|
let parsed;
|
|
49511
49758
|
try {
|
|
49512
|
-
parsed = JSON.parse(
|
|
49759
|
+
parsed = JSON.parse(readFileSync38(path, "utf8"));
|
|
49513
49760
|
} catch {
|
|
49514
49761
|
return null;
|
|
49515
49762
|
}
|
|
@@ -49559,7 +49806,7 @@ function everyRunRecord() {
|
|
|
49559
49806
|
function recordAt(path) {
|
|
49560
49807
|
let parsed;
|
|
49561
49808
|
try {
|
|
49562
|
-
parsed = JSON.parse(
|
|
49809
|
+
parsed = JSON.parse(readFileSync38(path, "utf8"));
|
|
49563
49810
|
} catch {
|
|
49564
49811
|
return null;
|
|
49565
49812
|
}
|
|
@@ -49640,7 +49887,7 @@ async function runningAs(pid) {
|
|
|
49640
49887
|
const began = await startedAt(pid, null);
|
|
49641
49888
|
const when = began === null ? {} : { startedAt: began };
|
|
49642
49889
|
if (process.platform === "linux") {
|
|
49643
|
-
const raw =
|
|
49890
|
+
const raw = readFileSync38(`/proc/${pid}/cmdline`, "utf8").replaceAll("\x00", " ").trim();
|
|
49644
49891
|
return raw === "" ? null : { kind: "commandLine", text: raw, ...when };
|
|
49645
49892
|
}
|
|
49646
49893
|
const args = (await runHidden("ps", ["-p", String(pid), "-o", "args="], { timeout: 15000 })).stdout.trim();
|
|
@@ -49836,10 +50083,10 @@ var init_run_record = __esm(() => {
|
|
|
49836
50083
|
});
|
|
49837
50084
|
|
|
49838
50085
|
// src/script-profile.ts
|
|
49839
|
-
import { readFileSync as
|
|
50086
|
+
import { readFileSync as readFileSync39 } from "node:fs";
|
|
49840
50087
|
function readProfileFile(path) {
|
|
49841
50088
|
try {
|
|
49842
|
-
const parsed = JSON.parse(
|
|
50089
|
+
const parsed = JSON.parse(readFileSync39(path, "utf8"));
|
|
49843
50090
|
return typeof parsed === "object" && typeof parsed.connected === "boolean" ? parsed : null;
|
|
49844
50091
|
} catch {
|
|
49845
50092
|
return null;
|
|
@@ -49897,7 +50144,7 @@ function writeProfileMark(path, mark) {
|
|
|
49897
50144
|
}
|
|
49898
50145
|
function readProfileMark(path) {
|
|
49899
50146
|
try {
|
|
49900
|
-
const parsed = JSON.parse(
|
|
50147
|
+
const parsed = JSON.parse(readFileSync39(path, "utf8"));
|
|
49901
50148
|
return typeof parsed === "object" && typeof parsed.totals === "object" ? parsed : null;
|
|
49902
50149
|
} catch {
|
|
49903
50150
|
return null;
|
|
@@ -50070,10 +50317,10 @@ var init_server_instructions = __esm(() => {
|
|
|
50070
50317
|
});
|
|
50071
50318
|
|
|
50072
50319
|
// src/suites-scene.ts
|
|
50073
|
-
import { existsSync as
|
|
50320
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync22, writeFileSync as writeFileSync22 } from "node:fs";
|
|
50074
50321
|
import { join as join42, relative as relative9, sep as sep5 } from "node:path";
|
|
50075
50322
|
function hasSuitesScene(projectPath) {
|
|
50076
|
-
return
|
|
50323
|
+
return existsSync32(join42(projectPath, SUITES_SCENE));
|
|
50077
50324
|
}
|
|
50078
50325
|
function suitesSceneArgs(projectPath, suites) {
|
|
50079
50326
|
const runs = join42(projectPath, ".godot", "gdharness", "suite-scenes");
|
|
@@ -50108,7 +50355,7 @@ var init_suites_scene = __esm(() => {
|
|
|
50108
50355
|
});
|
|
50109
50356
|
|
|
50110
50357
|
// src/test-selection.ts
|
|
50111
|
-
import { existsSync as
|
|
50358
|
+
import { existsSync as existsSync33 } from "node:fs";
|
|
50112
50359
|
import { basename as basename13, join as join43 } from "node:path";
|
|
50113
50360
|
function casesOutOfPath(projectPath, given, tests) {
|
|
50114
50361
|
const entries = Array.isArray(given) ? given : [given];
|
|
@@ -50153,12 +50400,12 @@ function casesIn(scripts, suite) {
|
|
|
50153
50400
|
}
|
|
50154
50401
|
function scriptsWithoutCases(projectPath, asked) {
|
|
50155
50402
|
const scripts = new ProjectScripts(projectPath);
|
|
50156
|
-
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);
|
|
50157
50404
|
}
|
|
50158
50405
|
function suitesUnder(projectPath, asked) {
|
|
50159
50406
|
const scripts = projectFiles(projectPath, [".gd"]).map((path) => `res://${path}`);
|
|
50160
50407
|
return [
|
|
50161
|
-
...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}/`))))
|
|
50162
50409
|
];
|
|
50163
50410
|
}
|
|
50164
50411
|
function selectTests(projectPath, asked, given) {
|
|
@@ -50224,12 +50471,12 @@ import {
|
|
|
50224
50471
|
closeSync as closeSync6,
|
|
50225
50472
|
constants,
|
|
50226
50473
|
copyFileSync as copyFileSync2,
|
|
50227
|
-
existsSync as
|
|
50474
|
+
existsSync as existsSync34,
|
|
50228
50475
|
fstatSync as fstatSync3,
|
|
50229
50476
|
mkdirSync as mkdirSync23,
|
|
50230
50477
|
openSync as openSync7,
|
|
50231
50478
|
readdirSync as readdirSync20,
|
|
50232
|
-
readFileSync as
|
|
50479
|
+
readFileSync as readFileSync40,
|
|
50233
50480
|
readSync as readSync4,
|
|
50234
50481
|
realpathSync as realpathSync6,
|
|
50235
50482
|
rmdirSync as rmdirSync2,
|
|
@@ -50237,7 +50484,7 @@ import {
|
|
|
50237
50484
|
writeFileSync as writeFileSync23
|
|
50238
50485
|
} from "node:fs";
|
|
50239
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";
|
|
50240
|
-
import { setTimeout as
|
|
50487
|
+
import { setTimeout as delay8 } from "node:timers/promises";
|
|
50241
50488
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
50242
50489
|
function editorRestartTimeoutMs() {
|
|
50243
50490
|
return waitFromEnv("GDHARNESS_EDITOR_RESTART_TIMEOUT_MS", 90000);
|
|
@@ -50250,9 +50497,9 @@ function greetingWaitMs() {
|
|
|
50250
50497
|
return waitFromEnv("GDHARNESS_GREETING_WAIT_MS", 1e4);
|
|
50251
50498
|
}
|
|
50252
50499
|
function pictureToSend(pngPath, jpegPath) {
|
|
50253
|
-
const png =
|
|
50500
|
+
const png = readFileSync40(pngPath);
|
|
50254
50501
|
const beside = pngPath.replace(/\.png$/, ".jpg");
|
|
50255
|
-
const jpeg = jpegPath !== undefined && normalize2(jpegPath) === normalize2(beside) &&
|
|
50502
|
+
const jpeg = jpegPath !== undefined && normalize2(jpegPath) === normalize2(beside) && existsSync34(beside) ? readFileSync40(beside) : null;
|
|
50256
50503
|
const sent = jpeg !== null && jpeg.length < png.length ? jpeg : png;
|
|
50257
50504
|
return {
|
|
50258
50505
|
data: sent.toString("base64"),
|
|
@@ -50292,7 +50539,7 @@ function writtenFileRefusal(path, rule) {
|
|
|
50292
50539
|
return `${named} ${path} does not end in ${rule.extensions.join(" or ")}, which is what ${what} is.`;
|
|
50293
50540
|
}
|
|
50294
50541
|
const directory = realAsFarAsItExists(dirname25(path));
|
|
50295
|
-
if (!
|
|
50542
|
+
if (!existsSync34(directory)) {
|
|
50296
50543
|
return `${named}'s directory ${dirname25(path)} does not exist; ${what} creates no directories.`;
|
|
50297
50544
|
}
|
|
50298
50545
|
const where = join44(directory, basename14(path));
|
|
@@ -50300,7 +50547,7 @@ function writtenFileRefusal(path, rule) {
|
|
|
50300
50547
|
if (inside !== undefined) {
|
|
50301
50548
|
return `${named} ${path} is inside the project at ${inside}; ${what} is saved outside it, so it never becomes part of the game.`;
|
|
50302
50549
|
}
|
|
50303
|
-
const taken = rule.writes(where).find((file) =>
|
|
50550
|
+
const taken = rule.writes(where).find((file) => existsSync34(file));
|
|
50304
50551
|
if (taken !== undefined) {
|
|
50305
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.`;
|
|
50306
50553
|
}
|
|
@@ -50524,7 +50771,7 @@ async function untilGone(pids, withinMs = stopWaitMs()) {
|
|
|
50524
50771
|
const gone = () => pids.every((pid) => !alive(pid));
|
|
50525
50772
|
const deadline = Date.now() + withinMs;
|
|
50526
50773
|
while (!gone() && Date.now() < deadline) {
|
|
50527
|
-
await
|
|
50774
|
+
await delay8(50);
|
|
50528
50775
|
}
|
|
50529
50776
|
return gone();
|
|
50530
50777
|
}
|
|
@@ -50728,7 +50975,7 @@ function endedToStartThis(ended) {
|
|
|
50728
50975
|
return ` ${which} was ended to start this one; its output is no longer what editor_output answers about.`;
|
|
50729
50976
|
}
|
|
50730
50977
|
function lineNothingStopsOn(absolutePath, relativePath, line) {
|
|
50731
|
-
const text =
|
|
50978
|
+
const text = readFileSync40(absolutePath, "utf8");
|
|
50732
50979
|
const lines = text === "" ? 0 : text.split(`
|
|
50733
50980
|
`).length - (text.endsWith(`
|
|
50734
50981
|
`) ? 1 : 0);
|
|
@@ -50939,7 +51186,7 @@ function notRunNote(notRun, failFast) {
|
|
|
50939
51186
|
function presetsIn(projectPath) {
|
|
50940
51187
|
let text;
|
|
50941
51188
|
try {
|
|
50942
|
-
text =
|
|
51189
|
+
text = readFileSync40(join44(projectPath, "export_presets.cfg"), "utf8");
|
|
50943
51190
|
} catch {
|
|
50944
51191
|
return null;
|
|
50945
51192
|
}
|
|
@@ -50983,7 +51230,7 @@ function exportPresetRefusal(projectPath, preset) {
|
|
|
50983
51230
|
}
|
|
50984
51231
|
return names.length === 0 ? `export_presets.cfg names no preset, so there is no '${preset}' to export with. project_export add_preset adds one.` : `This project has no export preset named '${preset}'. Its presets are ${names.map((name) => `'${name}'`).join(", ")}.`;
|
|
50985
51232
|
}
|
|
50986
|
-
function exportAnswer(ending, asked, before, after, beside = [], docCacheNote = null, bytes = null) {
|
|
51233
|
+
function exportAnswer(ending, asked, before, after, beside = [], docCacheNote = null, bytes = null, imports = {}) {
|
|
50987
51234
|
const { log } = ending;
|
|
50988
51235
|
const written = after !== null && after !== before;
|
|
50989
51236
|
const notCopied = librariesNotCopied(log.all);
|
|
@@ -50997,6 +51244,7 @@ function exportAnswer(ending, asked, before, after, beside = [], docCacheNote =
|
|
|
50997
51244
|
warnings: log.count("warning"),
|
|
50998
51245
|
...written && bytes !== null ? { bytes } : {},
|
|
50999
51246
|
...beside.length === 0 ? {} : { alsoWritten: beside },
|
|
51247
|
+
...imports,
|
|
51000
51248
|
...notCopied.length === 0 ? {} : {
|
|
51001
51249
|
librariesNotLoaded: notCopied,
|
|
51002
51250
|
extensionNote: `The export could not load ${notCopied.join(" and ")}: on Windows an engine running as the editor, which an export is, loads a GDExtension from a ~ copy beside the library, and another engine on this project held that copy: it could not be moved aside before the export, or another engine made a new one in between. Export again once that engine has loaded or exited.`
|
|
@@ -51085,7 +51333,7 @@ function unsavedInEditorNote(scripts) {
|
|
|
51085
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.`;
|
|
51086
51334
|
}
|
|
51087
51335
|
function editorAddonMissing(projectPath) {
|
|
51088
|
-
if (!
|
|
51336
|
+
if (!existsSync34(join44(projectPath, "project.godot"))) {
|
|
51089
51337
|
return null;
|
|
51090
51338
|
}
|
|
51091
51339
|
const report = inspectProject(projectPath);
|
|
@@ -51114,7 +51362,7 @@ function rewriteBusNamed(projectPath, from, to) {
|
|
|
51114
51362
|
const rewritten = [];
|
|
51115
51363
|
for (const file of projectFiles(projectPath, [".tscn", ".tres"])) {
|
|
51116
51364
|
const absolute = join44(projectPath, file);
|
|
51117
|
-
const lines =
|
|
51365
|
+
const lines = readFileSync40(absolute, "utf8").split(`
|
|
51118
51366
|
`);
|
|
51119
51367
|
const at = [];
|
|
51120
51368
|
const after = lines.map((line, index) => {
|
|
@@ -51133,7 +51381,7 @@ function rewriteBusNamed(projectPath, from, to) {
|
|
|
51133
51381
|
}
|
|
51134
51382
|
const namedInScripts = [];
|
|
51135
51383
|
for (const file of projectFiles(projectPath, [".gd"])) {
|
|
51136
|
-
|
|
51384
|
+
readFileSync40(join44(projectPath, file), "utf8").split(`
|
|
51137
51385
|
`).forEach((line, index) => {
|
|
51138
51386
|
if (line.includes(`"${from}"`)) {
|
|
51139
51387
|
namedInScripts.push({ file: `res://${file}`, line: index + 1, text: line.trim() });
|
|
@@ -51418,7 +51666,7 @@ function profileFrameFunctions(projectPath) {
|
|
|
51418
51666
|
let projectGodot = null;
|
|
51419
51667
|
if (projectPath !== null) {
|
|
51420
51668
|
try {
|
|
51421
|
-
projectGodot =
|
|
51669
|
+
projectGodot = readFileSync40(join44(projectPath, "project.godot"), "utf8");
|
|
51422
51670
|
} catch {}
|
|
51423
51671
|
}
|
|
51424
51672
|
return frameFunctionsFor(queuedMessagesOf(projectGodot));
|
|
@@ -51442,7 +51690,7 @@ function projectSourceOf(projectPath) {
|
|
|
51442
51690
|
let source = null;
|
|
51443
51691
|
if (inside.ok) {
|
|
51444
51692
|
try {
|
|
51445
|
-
source =
|
|
51693
|
+
source = readFileSync40(inside.absolutePath, "utf8");
|
|
51446
51694
|
} catch {}
|
|
51447
51695
|
}
|
|
51448
51696
|
read.set(script, source);
|
|
@@ -51614,7 +51862,7 @@ function foldedEntriesAnswer(log, floor = "warning") {
|
|
|
51614
51862
|
}
|
|
51615
51863
|
function gdUnitFailsOnScriptErrors(projectPath) {
|
|
51616
51864
|
try {
|
|
51617
|
-
return settingKeys(
|
|
51865
|
+
return settingKeys(readFileSync40(join44(projectPath, "project.godot"), "utf8")).get("gdunit4/report/godot/script_error") !== false;
|
|
51618
51866
|
} catch {
|
|
51619
51867
|
return true;
|
|
51620
51868
|
}
|
|
@@ -51629,7 +51877,7 @@ function uncaughtNote(uncaught) {
|
|
|
51629
51877
|
}
|
|
51630
51878
|
function elsewhereIn(projectPath, asked) {
|
|
51631
51879
|
const wanted = asked.replace(/^res:\/\//, "").replace(/\/+$/, "");
|
|
51632
|
-
if (wanted === "" ||
|
|
51880
|
+
if (wanted === "" || existsSync34(join44(projectPath, wanted))) {
|
|
51633
51881
|
return "";
|
|
51634
51882
|
}
|
|
51635
51883
|
const root = (wanted.split("/")[0] ?? "").toLowerCase();
|
|
@@ -51652,7 +51900,7 @@ function windowNoteFor(needing, sharing) {
|
|
|
51652
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}`;
|
|
51653
51901
|
}
|
|
51654
51902
|
function testPathsIn(projectPath, given, named = "path") {
|
|
51655
|
-
const defaults = TEST_DIRECTORIES.filter((directory) =>
|
|
51903
|
+
const defaults = TEST_DIRECTORIES.filter((directory) => existsSync34(join44(projectPath, directory)));
|
|
51656
51904
|
const entries = given === undefined || given === null || given === "" ? defaults.length > 0 ? defaults : TEST_DIRECTORIES : given;
|
|
51657
51905
|
const listed = Array.isArray(entries) ? entries : [entries];
|
|
51658
51906
|
if (listed.length === 0) {
|
|
@@ -51761,11 +52009,11 @@ function isDirectory(path) {
|
|
|
51761
52009
|
}
|
|
51762
52010
|
}
|
|
51763
52011
|
function mainSceneOf(projectFile) {
|
|
51764
|
-
const scene = parseProjectGodot(
|
|
52012
|
+
const scene = parseProjectGodot(readFileSync40(projectFile, "utf8"))["application"]?.["run/main_scene"];
|
|
51765
52013
|
return typeof scene === "string" && scene !== "" ? scene : null;
|
|
51766
52014
|
}
|
|
51767
52015
|
function editorPlaysHeadless(projectFile) {
|
|
51768
|
-
const runArgs = parseProjectGodot(
|
|
52016
|
+
const runArgs = parseProjectGodot(readFileSync40(projectFile, "utf8"))["editor"]?.["run/main_run_args"];
|
|
51769
52017
|
return typeof runArgs === "string" && /(?:^|\s)--headless(?:\s|$)/.test(runArgs);
|
|
51770
52018
|
}
|
|
51771
52019
|
function ownArguments(params) {
|
|
@@ -51939,7 +52187,7 @@ class GodotServer {
|
|
|
51939
52187
|
taken = true;
|
|
51940
52188
|
this.logDebug(`Took port ${wanted} over from pid ${announced.pid}`);
|
|
51941
52189
|
} catch {
|
|
51942
|
-
await
|
|
52190
|
+
await delay8(HANDOVER_POLL_MS);
|
|
51943
52191
|
}
|
|
51944
52192
|
}
|
|
51945
52193
|
this.notHandedOverBy = taken ? null : announced.pid;
|
|
@@ -52077,7 +52325,7 @@ class GodotServer {
|
|
|
52077
52325
|
argv: process.argv.slice(1),
|
|
52078
52326
|
cwd,
|
|
52079
52327
|
project: this.ownProject,
|
|
52080
|
-
mcpJson:
|
|
52328
|
+
mcpJson: existsSync34(mcpJson) ? mcpJson : null
|
|
52081
52329
|
});
|
|
52082
52330
|
if (predecessor !== null) {
|
|
52083
52331
|
writeLifecycle("replaced", { project: this.ownProject, predecessor });
|
|
@@ -52219,7 +52467,7 @@ class GodotServer {
|
|
|
52219
52467
|
return checked.response;
|
|
52220
52468
|
}
|
|
52221
52469
|
const named = args["projectPath"];
|
|
52222
|
-
if (typeof named === "string" &&
|
|
52470
|
+
if (typeof named === "string" && existsSync34(join44(named, "project.godot"))) {
|
|
52223
52471
|
this.lastProjectPath = named;
|
|
52224
52472
|
}
|
|
52225
52473
|
this.updates.refresh();
|
|
@@ -52855,7 +53103,7 @@ class GodotServer {
|
|
|
52855
53103
|
return this.createErrorResponse("line is required: the one-based line to stop on.");
|
|
52856
53104
|
}
|
|
52857
53105
|
if (op === "set") {
|
|
52858
|
-
if (!
|
|
53106
|
+
if (!existsSync34(located.absolutePath)) {
|
|
52859
53107
|
return this.missingScript(project.value.path, located.relativePath);
|
|
52860
53108
|
}
|
|
52861
53109
|
const nothing = lineNothingStopsOn(located.absolutePath, located.relativePath, line);
|
|
@@ -52960,7 +53208,7 @@ class GodotServer {
|
|
|
52960
53208
|
return { ok: false, response: this.createErrorResponse("projectPath is required.") };
|
|
52961
53209
|
}
|
|
52962
53210
|
const file = join44(path, "project.godot");
|
|
52963
|
-
if (!
|
|
53211
|
+
if (!existsSync34(file)) {
|
|
52964
53212
|
return {
|
|
52965
53213
|
ok: false,
|
|
52966
53214
|
response: this.createErrorResponse(`Not a Godot project: ${path}`, [
|
|
@@ -53707,7 +53955,7 @@ class GodotServer {
|
|
|
53707
53955
|
if (!engine.ok) {
|
|
53708
53956
|
return engine.response;
|
|
53709
53957
|
}
|
|
53710
|
-
const application = parseProjectGodot(
|
|
53958
|
+
const application = parseProjectGodot(readFileSync40(project.value.file, "utf8"))["application"] ?? {};
|
|
53711
53959
|
const name = application["config/name"];
|
|
53712
53960
|
const mainScene = application["run/main_scene"];
|
|
53713
53961
|
const info = {
|
|
@@ -53786,7 +54034,7 @@ class GodotServer {
|
|
|
53786
54034
|
if (place !== null && !place.ok) {
|
|
53787
54035
|
return this.createErrorResponse(place.reason);
|
|
53788
54036
|
}
|
|
53789
|
-
if (place !== null && !
|
|
54037
|
+
if (place !== null && !existsSync34(place.absolutePath)) {
|
|
53790
54038
|
const folders = readdirSync20(project.value.path, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name).sort();
|
|
53791
54039
|
return this.createErrorResponse(`There is nothing at res://${place.relativePath} to search.${folders.length === 0 ? "" : ` The project's folders are ${folders.join(", ")}.`}`);
|
|
53792
54040
|
}
|
|
@@ -53964,6 +54212,7 @@ ${platform}`;
|
|
|
53964
54212
|
if (pack && extension !== ".pck" && extension !== ".zip") {
|
|
53965
54213
|
return this.createErrorResponse(`A pack is written as a .pck or a .zip, and ${output.relativePath} is neither: the exporter picks the format by the extension.`, ["Give outputPath ending in .pck, or .zip for a zip of the resources"]);
|
|
53966
54214
|
}
|
|
54215
|
+
const imported = await this.importWhatChanged(project.value.path);
|
|
53967
54216
|
const exportLogs = scratchDirectory("export");
|
|
53968
54217
|
const exportArgs = [
|
|
53969
54218
|
"--headless",
|
|
@@ -53976,7 +54225,7 @@ ${platform}`;
|
|
|
53976
54225
|
output.absolutePath
|
|
53977
54226
|
];
|
|
53978
54227
|
this.logDebug(`Exporting: ${engine.value} ${exportArgs.join(" ")}`);
|
|
53979
|
-
const writtenAt = () =>
|
|
54228
|
+
const writtenAt = () => existsSync34(output.absolutePath) ? statSync20(output.absolutePath).mtimeMs : null;
|
|
53980
54229
|
const caches = editorCacheDirectory(engine.value);
|
|
53981
54230
|
const exportOnce = async () => {
|
|
53982
54231
|
const before = writtenAt();
|
|
@@ -54006,7 +54255,7 @@ ${platform}`;
|
|
|
54006
54255
|
return this.createErrorResponse(`Export could not be run: ${ending.failure ?? "the engine gave no exit status"}`);
|
|
54007
54256
|
}
|
|
54008
54257
|
const beside = writtenBeside(listedBefore, filesIn(folder), basename14(output.absolutePath), dirname25(output.relativePath).replaceAll("\\", "/"));
|
|
54009
|
-
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));
|
|
54010
54259
|
}
|
|
54011
54260
|
reportTestProgress(log) {
|
|
54012
54261
|
const progress = callProgress();
|
|
@@ -54067,7 +54316,7 @@ ${platform}`;
|
|
|
54067
54316
|
if (movie !== null) {
|
|
54068
54317
|
return this.createErrorResponse(movie);
|
|
54069
54318
|
}
|
|
54070
|
-
const missing = paths.value.filter((path) => !
|
|
54319
|
+
const missing = paths.value.filter((path) => !existsSync34(join44(project.value.path, path.slice("res://".length))));
|
|
54071
54320
|
const projectScripts = new ProjectScripts(project.value.path);
|
|
54072
54321
|
const present = paths.value.filter((path) => !missing.includes(path));
|
|
54073
54322
|
const asked = projectScripts.searchedAsTold(present);
|
|
@@ -54259,7 +54508,7 @@ ${platform}`;
|
|
|
54259
54508
|
await untilGone([run.process.pid]);
|
|
54260
54509
|
}
|
|
54261
54510
|
await run.settled;
|
|
54262
|
-
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;
|
|
54263
54512
|
if (helperFailed !== null) {
|
|
54264
54513
|
discard(join44(project.value.path, ".godot", ...ours.split("/")), userData);
|
|
54265
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}`);
|
|
@@ -54275,13 +54524,13 @@ ${platform}`;
|
|
|
54275
54524
|
const reportsDir = join44(project.value.path, ".godot", ...ours.split("/"));
|
|
54276
54525
|
let report = null;
|
|
54277
54526
|
let reportProblem = null;
|
|
54278
|
-
const casePrinted = withNestedErrors(readRun(
|
|
54527
|
+
const casePrinted = withNestedErrors(readRun(existsSync34(engineLog) ? readFileSync40(engineLog, "utf8") : ""), run.log.all);
|
|
54279
54528
|
const declaredErrors = readExpected(expectedFile);
|
|
54280
54529
|
try {
|
|
54281
|
-
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))) : [];
|
|
54282
54531
|
const newest = written.at(-1);
|
|
54283
54532
|
if (newest !== undefined) {
|
|
54284
|
-
report = parseJUnit(
|
|
54533
|
+
report = parseJUnit(readFileSync40(join44(reportsDir, newest, "results.xml"), "utf8"));
|
|
54285
54534
|
}
|
|
54286
54535
|
} catch (error) {
|
|
54287
54536
|
reportProblem = errorMessage(error);
|
|
@@ -54605,7 +54854,7 @@ ${error.text}`;
|
|
|
54605
54854
|
if (!location.ok) {
|
|
54606
54855
|
return this.createErrorResponse(location.reason, PATH_SOLUTIONS);
|
|
54607
54856
|
}
|
|
54608
|
-
if (!
|
|
54857
|
+
if (!existsSync34(location.absolutePath)) {
|
|
54609
54858
|
return this.missingScript(project.value.path, location.relativePath);
|
|
54610
54859
|
}
|
|
54611
54860
|
ignored = scriptsUnderGdignore(project.value.path, [location.relativePath]);
|
|
@@ -54695,7 +54944,7 @@ ${error.text}`;
|
|
|
54695
54944
|
const wanted = `res://${relativePath}`;
|
|
54696
54945
|
const folder = dirname25(relativePath.replaceAll("\\", "/"));
|
|
54697
54946
|
const inFolder = join44(projectPath, folder);
|
|
54698
|
-
const beside =
|
|
54947
|
+
const beside = existsSync34(inFolder) ? readdirSync20(inFolder, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => `res://${folder === "." ? "" : `${folder}/`}${entry.name}`) : [];
|
|
54699
54948
|
return this.createErrorResponse(withNearestFiles(`Script file does not exist: ${wanted}`, wanted, scripts, beside));
|
|
54700
54949
|
}
|
|
54701
54950
|
async compileScripts(projectPath, paths) {
|
|
@@ -54823,11 +55072,11 @@ ${error.text}`;
|
|
|
54823
55072
|
const cached = cachedClasses(projectPath);
|
|
54824
55073
|
const sourceOf = (resourcePath) => {
|
|
54825
55074
|
const contained = resolveWithinProject(projectPath, resourcePath);
|
|
54826
|
-
if (!contained.ok || !
|
|
55075
|
+
if (!contained.ok || !existsSync34(contained.absolutePath)) {
|
|
54827
55076
|
return null;
|
|
54828
55077
|
}
|
|
54829
55078
|
try {
|
|
54830
|
-
return
|
|
55079
|
+
return readFileSync40(contained.absolutePath, "utf8");
|
|
54831
55080
|
} catch {
|
|
54832
55081
|
return null;
|
|
54833
55082
|
}
|
|
@@ -54917,11 +55166,11 @@ ${error.text}`;
|
|
|
54917
55166
|
}
|
|
54918
55167
|
sourceOfClass(projectPath, resourcePath) {
|
|
54919
55168
|
const contained = resolveWithinProject(projectPath, resourcePath);
|
|
54920
|
-
if (!contained.ok || !
|
|
55169
|
+
if (!contained.ok || !existsSync34(contained.absolutePath)) {
|
|
54921
55170
|
return null;
|
|
54922
55171
|
}
|
|
54923
55172
|
try {
|
|
54924
|
-
return
|
|
55173
|
+
return readFileSync40(contained.absolutePath, "utf8");
|
|
54925
55174
|
} catch {
|
|
54926
55175
|
return null;
|
|
54927
55176
|
}
|
|
@@ -55219,7 +55468,7 @@ ${error.text}`;
|
|
|
55219
55468
|
try {
|
|
55220
55469
|
const askedAt = Date.now();
|
|
55221
55470
|
const asked = this.godotBridge.invokeTool("playing_status", {}, { counted: false });
|
|
55222
|
-
const answer = await Promise.race([asked,
|
|
55471
|
+
const answer = await Promise.race([asked, delay8(PLAYING_STATUS_MS).then(() => null)]);
|
|
55223
55472
|
if (answer === null) {
|
|
55224
55473
|
this.logDebug(`playing_status did not answer within ${PLAYING_STATUS_MS}ms`);
|
|
55225
55474
|
asked.then(() => {
|
|
@@ -55244,7 +55493,7 @@ ${error.text}`;
|
|
|
55244
55493
|
try {
|
|
55245
55494
|
const answer = await Promise.race([
|
|
55246
55495
|
this.godotBridge.invokeTool("scan_status", {}, { counted: false }),
|
|
55247
|
-
|
|
55496
|
+
delay8(PLAYING_STATUS_MS).then(() => null)
|
|
55248
55497
|
]);
|
|
55249
55498
|
if (answer === null) {
|
|
55250
55499
|
return null;
|
|
@@ -55386,7 +55635,7 @@ ${error.text}`;
|
|
|
55386
55635
|
if (answer.serversNote === undefined || adapterFailed || Date.now() >= deadline) {
|
|
55387
55636
|
return answer;
|
|
55388
55637
|
}
|
|
55389
|
-
await
|
|
55638
|
+
await delay8(500);
|
|
55390
55639
|
}
|
|
55391
55640
|
}
|
|
55392
55641
|
async rebindTheDebugAdapter(servers) {
|
|
@@ -55440,7 +55689,7 @@ ${error.text}`;
|
|
|
55440
55689
|
return null;
|
|
55441
55690
|
}
|
|
55442
55691
|
try {
|
|
55443
|
-
return settingKeys(
|
|
55692
|
+
return settingKeys(readFileSync40(join44(projectPath, "project.godot"), "utf8"));
|
|
55444
55693
|
} catch {
|
|
55445
55694
|
return null;
|
|
55446
55695
|
}
|
|
@@ -55647,7 +55896,7 @@ ${error.text}`;
|
|
|
55647
55896
|
if (Date.now() >= deadline) {
|
|
55648
55897
|
return false;
|
|
55649
55898
|
}
|
|
55650
|
-
await
|
|
55899
|
+
await delay8(250);
|
|
55651
55900
|
}
|
|
55652
55901
|
}
|
|
55653
55902
|
async handleLaunchEditor(args) {
|
|
@@ -55785,7 +56034,7 @@ ${error.text}`;
|
|
|
55785
56034
|
if (!paths.ok) {
|
|
55786
56035
|
return refused(paths.reason, PATH_SOLUTIONS);
|
|
55787
56036
|
}
|
|
55788
|
-
const missing = paths.value.filter((path) => !
|
|
56037
|
+
const missing = paths.value.filter((path) => !existsSync34(join44(projectPath, path.slice("res://".length))));
|
|
55789
56038
|
if (missing.length > 0) {
|
|
55790
56039
|
return refused(`Nothing at ${missing.join(" and ")} in the project at ${projectPath}.`, PATH_SOLUTIONS);
|
|
55791
56040
|
}
|
|
@@ -55830,7 +56079,7 @@ ${error.text}`;
|
|
|
55830
56079
|
return this.createErrorResponse(sceneToRun.reason, PATH_SOLUTIONS);
|
|
55831
56080
|
}
|
|
55832
56081
|
const build = readNonEmptyString(args, "executable");
|
|
55833
|
-
if (build === undefined && sceneToRun?.ok && !
|
|
56082
|
+
if (build === undefined && sceneToRun?.ok && !existsSync34(sceneToRun.absolutePath)) {
|
|
55834
56083
|
return this.createErrorResponse(`No scene at res://${sceneToRun.relativePath} in the project at ${project.value.path}.`, PATH_SOLUTIONS);
|
|
55835
56084
|
}
|
|
55836
56085
|
const exported = build === undefined ? null : exportedBuild(project.value.path, build);
|
|
@@ -55958,7 +56207,7 @@ ${error.text}`;
|
|
|
55958
56207
|
}
|
|
55959
56208
|
async runtimeUp(projectPath, before, budget, withArgs) {
|
|
55960
56209
|
const budgetMs = budget.ms;
|
|
55961
|
-
if (!
|
|
56210
|
+
if (!existsSync34(join44(projectPath, RUNTIME_SCRIPT))) {
|
|
55962
56211
|
return runtimeVerdict(null, {
|
|
55963
56212
|
addon: false,
|
|
55964
56213
|
budgetMs,
|
|
@@ -56096,7 +56345,7 @@ ${error.text}`;
|
|
|
56096
56345
|
const sendingFrom = Date.now();
|
|
56097
56346
|
const breakpoints = await this.dapHoldingBreakpointsOf(projectPath).reapplyBreakpoints();
|
|
56098
56347
|
this.logDebug(`Breakpoints were sent again after ${Date.now() - sendingFrom}ms`);
|
|
56099
|
-
const slot = await slotForCall();
|
|
56348
|
+
const slot = await slotForCall(true);
|
|
56100
56349
|
if (profiled) {
|
|
56101
56350
|
const armed = await this.handleViaBridge("profile_start", {
|
|
56102
56351
|
arm: true,
|
|
@@ -56276,7 +56525,7 @@ ${error.text}`;
|
|
|
56276
56525
|
return 0;
|
|
56277
56526
|
}
|
|
56278
56527
|
try {
|
|
56279
|
-
return reportAlreadyInTranscript(
|
|
56528
|
+
return reportAlreadyInTranscript(readFileSync40(game.transcript), readFileSync40(report));
|
|
56280
56529
|
} catch (error) {
|
|
56281
56530
|
this.logDebug(`Could not compare a picked-up run's report with its transcript: ${errorMessage(error)}`);
|
|
56282
56531
|
return 0;
|
|
@@ -56299,7 +56548,7 @@ ${error.text}`;
|
|
|
56299
56548
|
if (Date.now() >= deadline) {
|
|
56300
56549
|
return false;
|
|
56301
56550
|
}
|
|
56302
|
-
await
|
|
56551
|
+
await delay8(100);
|
|
56303
56552
|
}
|
|
56304
56553
|
}
|
|
56305
56554
|
async endActiveGame(reason, going, graceful) {
|
|
@@ -56559,11 +56808,11 @@ ${error.text}`;
|
|
|
56559
56808
|
return Object.assign(started, { settled, stop });
|
|
56560
56809
|
}
|
|
56561
56810
|
async launchKeptGame(godotPath, cmdArgs, projectPath, env, desktop, profiled = false, debugged = true) {
|
|
56811
|
+
const slot = await slotForCall(true);
|
|
56562
56812
|
const startedAt = Date.now();
|
|
56563
56813
|
const transcript = openTranscript(startedAt);
|
|
56564
56814
|
closeSync6(transcript.fd);
|
|
56565
56815
|
const profile = profiled ? profilePath(startedAt) : undefined;
|
|
56566
|
-
const slot = await slotForCall();
|
|
56567
56816
|
const gameEnv = onTheSlot(profiled ? { ...env ?? process.env, [PROFILE_FROM_START]: "1" } : env ?? process.env, slot.lock);
|
|
56568
56817
|
let launched;
|
|
56569
56818
|
try {
|
|
@@ -57033,7 +57282,7 @@ ${error.text}`;
|
|
|
57033
57282
|
};
|
|
57034
57283
|
const going = await this.runStillGoing(run);
|
|
57035
57284
|
const projectPath = run.projectPath;
|
|
57036
|
-
const projectGone = projectPath !== null && !
|
|
57285
|
+
const projectGone = projectPath !== null && !existsSync34(join44(projectPath, "project.godot"));
|
|
57037
57286
|
if (projectGone && callersName !== undefined) {
|
|
57038
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"]);
|
|
57039
57288
|
}
|
|
@@ -57191,7 +57440,7 @@ ${error.text}`;
|
|
|
57191
57440
|
return true;
|
|
57192
57441
|
}
|
|
57193
57442
|
}
|
|
57194
|
-
await
|
|
57443
|
+
await delay8(100);
|
|
57195
57444
|
}
|
|
57196
57445
|
return false;
|
|
57197
57446
|
}
|
|
@@ -57211,7 +57460,7 @@ ${error.text}`;
|
|
|
57211
57460
|
while (cancelled?.aborted !== true && await this.runStillGoing(run) && Date.now() < until) {
|
|
57212
57461
|
this.drainEditorOutput(run);
|
|
57213
57462
|
this.drainTranscript(run);
|
|
57214
|
-
await
|
|
57463
|
+
await delay8(RUN_POLL_MS);
|
|
57215
57464
|
}
|
|
57216
57465
|
return await this.handleGetDebugOutput(args, await this.runStillGoing(run) ? budgetMs : undefined);
|
|
57217
57466
|
}
|
|
@@ -57264,7 +57513,7 @@ ${error.text}`;
|
|
|
57264
57513
|
if (Date.now() >= until) {
|
|
57265
57514
|
return false;
|
|
57266
57515
|
}
|
|
57267
|
-
await
|
|
57516
|
+
await delay8(50);
|
|
57268
57517
|
}
|
|
57269
57518
|
}
|
|
57270
57519
|
async handleEditorConsole(args) {
|
|
@@ -57418,7 +57667,7 @@ ${error.text}`;
|
|
|
57418
57667
|
notes.push(endedWithoutACode({
|
|
57419
57668
|
throughEditor: run.throughEditor,
|
|
57420
57669
|
announced: announced !== undefined || run.announcedPid !== undefined,
|
|
57421
|
-
couldAnnounce: run.projectPath !== null &&
|
|
57670
|
+
couldAnnounce: run.projectPath !== null && existsSync34(join44(run.projectPath, RUNTIME_SCRIPT)),
|
|
57422
57671
|
endedHere: typeof run.endedHere === "string",
|
|
57423
57672
|
pickedUp: run.pickedUp === true
|
|
57424
57673
|
}));
|
|
@@ -58300,7 +58549,7 @@ ${error.text}`;
|
|
|
58300
58549
|
if (!scriptPath.ok) {
|
|
58301
58550
|
return this.createErrorResponse(scriptPath.reason);
|
|
58302
58551
|
}
|
|
58303
|
-
if (!
|
|
58552
|
+
if (!existsSync34(scriptPath.absolutePath)) {
|
|
58304
58553
|
return this.missingScript(projectPath, scriptPath.relativePath);
|
|
58305
58554
|
}
|
|
58306
58555
|
const asked = readNonEmptyString(args, "newScriptPath");
|
|
@@ -58747,7 +58996,7 @@ ${error.text}`;
|
|
|
58747
58996
|
}
|
|
58748
58997
|
const escaped = symbol.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
58749
58998
|
const declared = new RegExp(`^\\s*(?:@\\w+(?:\\([^)]*\\))?\\s+)*class_name\\s+${escaped}\\b`, "m");
|
|
58750
|
-
if (declared.test(
|
|
58999
|
+
if (declared.test(readFileSync40(scriptPath, "utf8"))) {
|
|
58751
59000
|
return null;
|
|
58752
59001
|
}
|
|
58753
59002
|
const checked = await this.classesTheEditorCannotSee(args);
|
|
@@ -58944,7 +59193,7 @@ ${error.text}`;
|
|
|
58944
59193
|
async ownRunOnItsWay(projectPath, budgetMs) {
|
|
58945
59194
|
const run = await this.currentRun();
|
|
58946
59195
|
const project = projectPath ?? run?.projectPath ?? null;
|
|
58947
|
-
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)) {
|
|
58948
59197
|
return null;
|
|
58949
59198
|
}
|
|
58950
59199
|
const already = runtimesAnnounced().running;
|
|
@@ -59397,7 +59646,7 @@ var init_server = __esm(() => {
|
|
|
59397
59646
|
init_bridge_announce();
|
|
59398
59647
|
init_engine_launch();
|
|
59399
59648
|
init_engine_slots();
|
|
59400
|
-
import { existsSync as
|
|
59649
|
+
import { existsSync as existsSync35 } from "node:fs";
|
|
59401
59650
|
import { dirname as dirname26, join as join45, resolve as resolve15 } from "node:path";
|
|
59402
59651
|
|
|
59403
59652
|
// src/error-mode.ts
|
|
@@ -59436,7 +59685,7 @@ init_alive();
|
|
|
59436
59685
|
init_engine_launch();
|
|
59437
59686
|
init_lsp_client();
|
|
59438
59687
|
init_process_children();
|
|
59439
|
-
import { existsSync as
|
|
59688
|
+
import { existsSync as existsSync17, readdirSync as readdirSync11, readFileSync as readFileSync19, unlinkSync as unlinkSync2 } from "node:fs";
|
|
59440
59689
|
import { connect as connect2 } from "node:net";
|
|
59441
59690
|
import { join as join21, resolve as resolve8 } from "node:path";
|
|
59442
59691
|
var EDITOR_RECORD_PROTOCOL = 1;
|
|
@@ -59455,7 +59704,7 @@ function editorRecordsIn(projectPath) {
|
|
|
59455
59704
|
for (const name of names) {
|
|
59456
59705
|
const file = join21(directory, name);
|
|
59457
59706
|
try {
|
|
59458
|
-
const said = JSON.parse(
|
|
59707
|
+
const said = JSON.parse(readFileSync19(file, "utf8"));
|
|
59459
59708
|
const { protocol, pid, lsp_port: lspPort, written_at_ms: writtenAtMs } = said;
|
|
59460
59709
|
if (protocol === EDITOR_RECORD_PROTOCOL && typeof pid === "number" && typeof lspPort === "number" && lspPort > 0 && typeof writtenAtMs === "number") {
|
|
59461
59710
|
records.push({ file, pid, lspPort, writtenAtMs });
|
|
@@ -59548,7 +59797,7 @@ function lspOptionsOf(args, cwd) {
|
|
|
59548
59797
|
}
|
|
59549
59798
|
}
|
|
59550
59799
|
const projectPath = resolve8(cwd, named ?? ".");
|
|
59551
|
-
if (!
|
|
59800
|
+
if (!existsSync17(join21(projectPath, "project.godot"))) {
|
|
59552
59801
|
throw new EngineUsageError(`Not a Godot project: ${projectPath} holds no project.godot.`);
|
|
59553
59802
|
}
|
|
59554
59803
|
return { projectPath, port, waitSeconds };
|
|
@@ -59655,7 +59904,7 @@ init_setup();
|
|
|
59655
59904
|
init_setup();
|
|
59656
59905
|
init_tool_definitions();
|
|
59657
59906
|
init_tool_reference();
|
|
59658
|
-
import { existsSync as
|
|
59907
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync7, readdirSync as readdirSync13, rmSync as rmSync11, writeFileSync as writeFileSync12 } from "node:fs";
|
|
59659
59908
|
import { basename as basename9, dirname as dirname10, join as join23 } from "node:path";
|
|
59660
59909
|
var SKILL_NAME = "gdharness";
|
|
59661
59910
|
var SHARED_SKILLS = join23(".agents", "skills");
|
|
@@ -59927,7 +60176,7 @@ function everySkillDirectory(projectPath, harnesses) {
|
|
|
59927
60176
|
function removeSkill(directories, projectPath) {
|
|
59928
60177
|
const removed = [];
|
|
59929
60178
|
for (const directory of directories) {
|
|
59930
|
-
if (
|
|
60179
|
+
if (existsSync19(directory)) {
|
|
59931
60180
|
rmSync11(directory, { recursive: true, force: true });
|
|
59932
60181
|
pruneEmpty(dirname10(directory), projectPath);
|
|
59933
60182
|
removed.push(directory);
|
|
@@ -59949,7 +60198,7 @@ function pruneEmpty(directory, projectPath) {
|
|
|
59949
60198
|
function writeSkill(directories, version) {
|
|
59950
60199
|
const files = skillFiles(version);
|
|
59951
60200
|
return directories.map((directory) => {
|
|
59952
|
-
const replaced =
|
|
60201
|
+
const replaced = existsSync19(directory);
|
|
59953
60202
|
rmSync11(directory, { recursive: true, force: true });
|
|
59954
60203
|
for (const [name, contents] of files) {
|
|
59955
60204
|
const path = join23(directory, name);
|
|
@@ -59966,8 +60215,8 @@ init_engine_slots();
|
|
|
59966
60215
|
init_log_read();
|
|
59967
60216
|
init_setup();
|
|
59968
60217
|
init_suite_judge();
|
|
59969
|
-
import { existsSync as
|
|
59970
|
-
import { availableParallelism as
|
|
60218
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync8, readFileSync as readFileSync22, rmSync as rmSync12 } from "node:fs";
|
|
60219
|
+
import { availableParallelism as availableParallelism4 } from "node:os";
|
|
59971
60220
|
import { join as join24, resolve as resolve10 } from "node:path";
|
|
59972
60221
|
import process13 from "node:process";
|
|
59973
60222
|
var SHARE = "--gdh-share=";
|
|
@@ -60008,9 +60257,9 @@ function spreadOptionsOf(args, cwd) {
|
|
|
60008
60257
|
}
|
|
60009
60258
|
const first = positional[0];
|
|
60010
60259
|
const named = first === undefined ? null : resolve10(cwd, first);
|
|
60011
|
-
const projectNamed = named !== null &&
|
|
60260
|
+
const projectNamed = named !== null && existsSync20(join24(named, "project.godot"));
|
|
60012
60261
|
const projectPath = projectNamed ? named : resolve10(cwd);
|
|
60013
|
-
if (!
|
|
60262
|
+
if (!existsSync20(join24(projectPath, "project.godot"))) {
|
|
60014
60263
|
throw new EngineUsageError(`Not a Godot project: ${projectPath} holds no project.godot.`);
|
|
60015
60264
|
}
|
|
60016
60265
|
const scenes = positional.slice(projectNamed ? 1 : 0);
|
|
@@ -60018,7 +60267,7 @@ function spreadOptionsOf(args, cwd) {
|
|
|
60018
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(", ")}.`);
|
|
60019
60268
|
}
|
|
60020
60269
|
const scene = resPathOf(scenes[0] ?? "", projectPath, cwd);
|
|
60021
|
-
if (!
|
|
60270
|
+
if (!existsSync20(join24(projectPath, scene.slice("res://".length)))) {
|
|
60022
60271
|
throw new EngineUsageError(`Nothing at ${scene} in the project at ${projectPath}.`);
|
|
60023
60272
|
}
|
|
60024
60273
|
const benchArguments = dashes === -1 ? [] : args.slice(dashes + 1);
|
|
@@ -60089,7 +60338,7 @@ function shareFaults(played) {
|
|
|
60089
60338
|
return faults;
|
|
60090
60339
|
}
|
|
60091
60340
|
async function runSpreadCommand(options, godotPath) {
|
|
60092
|
-
if (!
|
|
60341
|
+
if (!existsSync20(join24(options.projectPath, SHARE_SCRIPT))) {
|
|
60093
60342
|
throw new EngineUsageError(`res://${SHARE_SCRIPT} is not in the project, so its bench cannot ask GdhShare for outcomes. Run gdharness setup.`);
|
|
60094
60343
|
}
|
|
60095
60344
|
const startedAt = Date.now();
|
|
@@ -60123,7 +60372,7 @@ async function runSpreadCommand(options, godotPath) {
|
|
|
60123
60372
|
let workers = options.workers;
|
|
60124
60373
|
if (workers === null) {
|
|
60125
60374
|
const memory = await memoryAvailable();
|
|
60126
|
-
const processors = options.cores ??
|
|
60375
|
+
const processors = options.cores ?? availableParallelism4();
|
|
60127
60376
|
const room = roomFor(slotCount, processors, memory.bytes, memory.said);
|
|
60128
60377
|
workers = room.engines;
|
|
60129
60378
|
console.log(`${options.scene} over ${plural(workers, "worker")}${room.held === undefined ? "" : `, since ${room.held}`}.`);
|
|
@@ -60154,7 +60403,7 @@ async function runSpreadCommand(options, godotPath) {
|
|
|
60154
60403
|
const faults = left.flatMap((worker) => engineFaults(worker, options.godotVersion));
|
|
60155
60404
|
const arms = left.map((_, index) => {
|
|
60156
60405
|
const file = join24(shareDirectory, `worker-${String(index)}.arms`);
|
|
60157
|
-
return
|
|
60406
|
+
return existsSync20(file) ? armsPlayed(readFileSync22(file, "utf8")) : [];
|
|
60158
60407
|
});
|
|
60159
60408
|
faults.push(...shareFaults(arms));
|
|
60160
60409
|
if (faults.length > 0) {
|
|
@@ -60164,7 +60413,7 @@ async function runSpreadCommand(options, godotPath) {
|
|
|
60164
60413
|
console.log(readLog(gather.log).replace(CONTROL_SEQUENCE, "").trimEnd());
|
|
60165
60414
|
const gatherFaults = engineFaults(gather, options.godotVersion);
|
|
60166
60415
|
const gatheredFile = join24(shareDirectory, "gathered.arms");
|
|
60167
|
-
const gathered = new Set((
|
|
60416
|
+
const gathered = new Set((existsSync20(gatheredFile) ? armsPlayed(readFileSync22(gatheredFile, "utf8")) ?? [] : []).map((arm) => arm.arm));
|
|
60168
60417
|
const ungathered = (arms[0] ?? []).filter((arm) => !gathered.has(arm.arm)).map((arm) => arm.arm);
|
|
60169
60418
|
if (ungathered.length > 0) {
|
|
60170
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`);
|
|
@@ -60215,7 +60464,7 @@ function engineFaults(engine, godotVersion) {
|
|
|
60215
60464
|
const said = code === null ? "without an exit code" : code >>> 0 >= WINDOWS_EXCEPTION2 ? exitNamed(code) : String(code);
|
|
60216
60465
|
faults.push(`${engine.name}: the engine exited ${said}`);
|
|
60217
60466
|
}
|
|
60218
|
-
if (!
|
|
60467
|
+
if (!existsSync20(engine.log)) {
|
|
60219
60468
|
return faults;
|
|
60220
60469
|
}
|
|
60221
60470
|
const printed = readRun(readLog(engine.log));
|
|
@@ -60231,7 +60480,7 @@ function engineFaults(engine, godotVersion) {
|
|
|
60231
60480
|
}
|
|
60232
60481
|
function progressOf(logs) {
|
|
60233
60482
|
const each = logs.map((log, index) => {
|
|
60234
|
-
const text =
|
|
60483
|
+
const text = existsSync20(log) ? readLog(log) : "";
|
|
60235
60484
|
const last = [...text.matchAll(PROGRESS)].at(-1);
|
|
60236
60485
|
return last === undefined ? `worker ${String(index)} has played no arm yet` : `worker ${String(index)} at ${last[1] ?? ""} ${last[2] ?? ""} of ${last[3] ?? ""}`;
|
|
60237
60486
|
});
|
|
@@ -60263,23 +60512,24 @@ init_reimport();
|
|
|
60263
60512
|
init_setup();
|
|
60264
60513
|
import {
|
|
60265
60514
|
copyFileSync,
|
|
60266
|
-
existsSync as
|
|
60515
|
+
existsSync as existsSync23,
|
|
60267
60516
|
mkdirSync as mkdirSync10,
|
|
60268
60517
|
readdirSync as readdirSync15,
|
|
60269
|
-
readFileSync as
|
|
60518
|
+
readFileSync as readFileSync26,
|
|
60270
60519
|
rmSync as rmSync13,
|
|
60271
60520
|
statSync as statSync14,
|
|
60272
60521
|
writeFileSync as writeFileSync13
|
|
60273
60522
|
} from "node:fs";
|
|
60274
|
-
import { availableParallelism as
|
|
60523
|
+
import { availableParallelism as availableParallelism5 } from "node:os";
|
|
60275
60524
|
import { dirname as dirname13, join as join28, relative as relative5, resolve as resolve11, sep as sep4 } from "node:path";
|
|
60276
60525
|
import process14 from "node:process";
|
|
60526
|
+
import { setTimeout as delay5 } from "node:timers/promises";
|
|
60277
60527
|
|
|
60278
60528
|
// src/suite-inputs.ts
|
|
60279
60529
|
init_class_cache();
|
|
60280
60530
|
init_gdscript_source();
|
|
60281
60531
|
import { createHash as createHash6 } from "node:crypto";
|
|
60282
|
-
import { existsSync as
|
|
60532
|
+
import { existsSync as existsSync21, readdirSync as readdirSync14, readFileSync as readFileSync23, statSync as statSync13 } from "node:fs";
|
|
60283
60533
|
import { join as join25, posix as posix2 } from "node:path";
|
|
60284
60534
|
var EVERY_FILE = "res://";
|
|
60285
60535
|
var CACHE_HELD = "cache:";
|
|
@@ -60297,13 +60547,13 @@ var ADDON = /^res:\/\/addons\/[^/]+\//;
|
|
|
60297
60547
|
var TEXT_RESOURCE = /\.(?:tscn|tres|gdextension)$/;
|
|
60298
60548
|
function reachedBySuite(file) {
|
|
60299
60549
|
const bySuite = new Map;
|
|
60300
|
-
if (!
|
|
60550
|
+
if (!existsSync21(file)) {
|
|
60301
60551
|
return bySuite;
|
|
60302
60552
|
}
|
|
60303
60553
|
const paths = (value) => Array.isArray(value) ? value.filter((path) => typeof path === "string") : [];
|
|
60304
60554
|
let autoloads = [];
|
|
60305
60555
|
const resident = new Map;
|
|
60306
|
-
for (const line of
|
|
60556
|
+
for (const line of readFileSync23(file, "utf8").split(`
|
|
60307
60557
|
`)) {
|
|
60308
60558
|
if (line.trim() === "") {
|
|
60309
60559
|
continue;
|
|
@@ -60398,7 +60648,7 @@ ${this.read(path).digest}
|
|
|
60398
60648
|
let modified = 0;
|
|
60399
60649
|
walkSeen(this.scripts.projectPath, (file, under, stat) => {
|
|
60400
60650
|
hash.update(`${under}
|
|
60401
|
-
`).update(
|
|
60651
|
+
`).update(readFileSync23(file));
|
|
60402
60652
|
modified = Math.max(modified, stat.mtimeMs);
|
|
60403
60653
|
});
|
|
60404
60654
|
return { digest: hash.digest("hex"), follows: [], also: [], modified };
|
|
@@ -60407,10 +60657,10 @@ ${this.read(path).digest}
|
|
|
60407
60657
|
const hash = createHash6("sha256");
|
|
60408
60658
|
let modified = 0;
|
|
60409
60659
|
const directory = join25(this.scripts.projectPath, root.slice("res://".length));
|
|
60410
|
-
if (
|
|
60660
|
+
if (existsSync21(directory)) {
|
|
60411
60661
|
walkSeen(directory, (file, under, stat) => {
|
|
60412
60662
|
hash.update(`${under}
|
|
60413
|
-
`).update(
|
|
60663
|
+
`).update(readFileSync23(file));
|
|
60414
60664
|
modified = Math.max(modified, stat.mtimeMs);
|
|
60415
60665
|
});
|
|
60416
60666
|
}
|
|
@@ -60418,7 +60668,7 @@ ${this.read(path).digest}
|
|
|
60418
60668
|
}
|
|
60419
60669
|
readAnew(path) {
|
|
60420
60670
|
const file = join25(this.scripts.projectPath, path.slice("res://".length));
|
|
60421
|
-
if (!
|
|
60671
|
+
if (!existsSync21(file)) {
|
|
60422
60672
|
return { digest: "missing", follows: [], also: [], modified: 0 };
|
|
60423
60673
|
}
|
|
60424
60674
|
const stat = statSync13(file);
|
|
@@ -60427,14 +60677,14 @@ ${this.read(path).digest}
|
|
|
60427
60677
|
return { digest: inside.join(`
|
|
60428
60678
|
`), follows: [], also: [], modified: stat.mtimeMs };
|
|
60429
60679
|
}
|
|
60430
|
-
const bytes =
|
|
60680
|
+
const bytes = readFileSync23(file);
|
|
60431
60681
|
const digest = createHash6("sha256").update(bytes).digest("hex");
|
|
60432
|
-
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))));
|
|
60433
60683
|
const follows = [];
|
|
60434
60684
|
if (TEXT_RESOURCE.test(path)) {
|
|
60435
60685
|
for (const [named] of bytes.toString("latin1").matchAll(RES_LITERAL)) {
|
|
60436
60686
|
const target = join25(this.scripts.projectPath, named.slice("res://".length));
|
|
60437
|
-
(
|
|
60687
|
+
(existsSync21(target) && statSync13(target).isDirectory() ? also : follows).push(named);
|
|
60438
60688
|
}
|
|
60439
60689
|
} else if (path.endsWith(".gd")) {
|
|
60440
60690
|
const reaches = this.scriptReaches(path);
|
|
@@ -60621,7 +60871,7 @@ function joinedString(expression, named) {
|
|
|
60621
60871
|
}
|
|
60622
60872
|
function walkSeen(root, seen) {
|
|
60623
60873
|
const walk = (directory, under) => {
|
|
60624
|
-
if (
|
|
60874
|
+
if (existsSync21(join25(directory, ".gdignore"))) {
|
|
60625
60875
|
return;
|
|
60626
60876
|
}
|
|
60627
60877
|
for (const entry of readdirSync14(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
@@ -60639,7 +60889,7 @@ function walkSeen(root, seen) {
|
|
|
60639
60889
|
}
|
|
60640
60890
|
function extensionsOf(projectPath) {
|
|
60641
60891
|
const list = join25(projectPath, ".godot", "extension_list.cfg");
|
|
60642
|
-
return
|
|
60892
|
+
return existsSync21(list) ? readFileSync23(list, "utf8").split(`
|
|
60643
60893
|
`).map((line) => line.trim()).filter((line) => line.startsWith("res://")) : [];
|
|
60644
60894
|
}
|
|
60645
60895
|
|
|
@@ -60648,7 +60898,7 @@ init_suite_judge();
|
|
|
60648
60898
|
init_suite_plan();
|
|
60649
60899
|
|
|
60650
60900
|
// src/version.ts
|
|
60651
|
-
import { readFileSync as
|
|
60901
|
+
import { readFileSync as readFileSync25 } from "node:fs";
|
|
60652
60902
|
import { dirname as dirname12, join as join27 } from "node:path";
|
|
60653
60903
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
60654
60904
|
function getLocalVersion() {
|
|
@@ -60659,7 +60909,7 @@ function getLocalVersion() {
|
|
|
60659
60909
|
];
|
|
60660
60910
|
for (const packagePath of packageCandidates) {
|
|
60661
60911
|
try {
|
|
60662
|
-
const value = JSON.parse(
|
|
60912
|
+
const value = JSON.parse(readFileSync25(packagePath, "utf-8"));
|
|
60663
60913
|
if (typeof value === "object" && value !== null && "name" in value && value.name === "gdharness" && "version" in value && typeof value.version === "string") {
|
|
60664
60914
|
return value.version;
|
|
60665
60915
|
}
|
|
@@ -60670,6 +60920,7 @@ function getLocalVersion() {
|
|
|
60670
60920
|
|
|
60671
60921
|
// src/suite-run.ts
|
|
60672
60922
|
var LAST_RUN_FILE = "last-run.json";
|
|
60923
|
+
var COMPILED_FILE = "compiled-together.json";
|
|
60673
60924
|
var SLOWEST_NAMED = 5;
|
|
60674
60925
|
var SILENCE_TIMES_TAKEN = 4;
|
|
60675
60926
|
function silenceWhile(running, times, floorSeconds) {
|
|
@@ -60727,9 +60978,9 @@ function testOptionsOf(args, cwd) {
|
|
|
60727
60978
|
}
|
|
60728
60979
|
const first = positional[0];
|
|
60729
60980
|
const named = first === undefined ? null : resolve11(cwd, first);
|
|
60730
|
-
const projectNamed = named !== null &&
|
|
60981
|
+
const projectNamed = named !== null && existsSync23(join28(named, "project.godot"));
|
|
60731
60982
|
const projectPath = projectNamed ? named : resolve11(cwd);
|
|
60732
|
-
if (!
|
|
60983
|
+
if (!existsSync23(join28(projectPath, "project.godot"))) {
|
|
60733
60984
|
throw new EngineUsageError(`Not a Godot project: ${projectPath} holds no project.godot.`);
|
|
60734
60985
|
}
|
|
60735
60986
|
const last = (flag) => valued.get(flag)?.at(-1);
|
|
@@ -60764,12 +61015,12 @@ function seedOf(value) {
|
|
|
60764
61015
|
return seed;
|
|
60765
61016
|
}
|
|
60766
61017
|
function rootsOf(options) {
|
|
60767
|
-
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}`);
|
|
60768
61019
|
}
|
|
60769
61020
|
function searchedRoots(options) {
|
|
60770
61021
|
return options.selected.length === 0 ? rootsOf(options) : options.selected.filter((entry) => {
|
|
60771
61022
|
const directory = join28(options.projectPath, entry.slice("res://".length));
|
|
60772
|
-
return
|
|
61023
|
+
return existsSync23(directory) && statSync14(directory).isDirectory();
|
|
60773
61024
|
});
|
|
60774
61025
|
}
|
|
60775
61026
|
function selectedSuites(scripts, options) {
|
|
@@ -60786,9 +61037,9 @@ function selectedSuites(scripts, options) {
|
|
|
60786
61037
|
const caseAt = /^(res:\/\/.*\.gd):(\w+)$/.exec(entry);
|
|
60787
61038
|
const path = caseAt?.[1] ?? entry;
|
|
60788
61039
|
const directory = join28(options.projectPath, path.slice(6));
|
|
60789
|
-
const suites =
|
|
61040
|
+
const suites = existsSync23(directory) && statSync14(directory).isDirectory() ? scripts.suitesUnder([path.replace(/\/$/, "")]) : [scripts.suite(path)].filter((suite) => suite !== null);
|
|
60790
61041
|
if (suites.length === 0) {
|
|
60791
|
-
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}.`);
|
|
60792
61043
|
}
|
|
60793
61044
|
for (const suite of suites) {
|
|
60794
61045
|
const picked = chosen.get(suite.path) ?? { suite, cases: new Set };
|
|
@@ -60912,11 +61163,11 @@ async function runTestCommand(options, godotPath) {
|
|
|
60912
61163
|
failsOnPushErrors: gdUnitFailsOnPushErrors(options.projectPath)
|
|
60913
61164
|
};
|
|
60914
61165
|
try {
|
|
60915
|
-
const
|
|
60916
|
-
if (
|
|
60917
|
-
console.log(
|
|
61166
|
+
const needed = options.importFirst ? null : importNeeded(options.projectPath);
|
|
61167
|
+
if (needed !== null) {
|
|
61168
|
+
console.log(needed);
|
|
60918
61169
|
}
|
|
60919
|
-
if (options.importFirst ||
|
|
61170
|
+
if (options.importFirst || needed !== null) {
|
|
60920
61171
|
const imported = await importProject(launch);
|
|
60921
61172
|
if (imported !== null) {
|
|
60922
61173
|
logs.keep();
|
|
@@ -60928,12 +61179,13 @@ async function runTestCommand(options, godotPath) {
|
|
|
60928
61179
|
const suitesBegan = Date.now();
|
|
60929
61180
|
const always = [
|
|
60930
61181
|
getLocalVersion(),
|
|
60931
|
-
|
|
61182
|
+
readFileSync26(shippedListedRunner(), "utf8"),
|
|
60932
61183
|
engineSaid(godotPath),
|
|
60933
61184
|
...options.reachAlso.map((path) => `${path}
|
|
60934
|
-
${
|
|
61185
|
+
${existsSync23(path) ? readFileSync26(path, "latin1") : "missing"}`)
|
|
60935
61186
|
];
|
|
60936
61187
|
const everySuite = suites;
|
|
61188
|
+
const compileKept = options.changedOnly ? { file: join28(state, COMPILED_FILE), scripts, always } : null;
|
|
60937
61189
|
if (options.changedOnly) {
|
|
60938
61190
|
const inputs = new SuiteInputs(scripts, always);
|
|
60939
61191
|
const passedBefore = readPassed(passedFile);
|
|
@@ -60947,7 +61199,7 @@ ${existsSync24(path) ? readFileSync24(path, "latin1") : "missing"}`)
|
|
|
60947
61199
|
}
|
|
60948
61200
|
if (suites.length === 0) {
|
|
60949
61201
|
console.log("Nothing has changed since every suite last passed.");
|
|
60950
|
-
const compiled = await
|
|
61202
|
+
const compiled = await compileUnlessUnchanged(launch, everySuite, compileKept);
|
|
60951
61203
|
const problems = [...compiled.faults.map((fault) => `${COMPILE_CHECK}: ${fault}`), ...uncollected];
|
|
60952
61204
|
if (problems.length === 0) {
|
|
60953
61205
|
rmSync13(runDirectory, { recursive: true, force: true });
|
|
@@ -60970,12 +61222,18 @@ ${existsSync24(path) ? readFileSync24(path, "latin1") : "missing"}`)
|
|
|
60970
61222
|
if (memory.unread !== undefined) {
|
|
60971
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.`);
|
|
60972
61224
|
}
|
|
60973
|
-
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;
|
|
60974
61232
|
if (options.cores !== null && process14.platform === "darwin") {
|
|
60975
61233
|
console.log("macOS offers no way to hold a process to some processors, so --cores holds only the number of engines here.");
|
|
60976
61234
|
}
|
|
60977
61235
|
const splitPast = splitPastFor(suites, times, room.engines);
|
|
60978
|
-
const units = unitsOf(suites, times, splitPast);
|
|
61236
|
+
const units = memoryHeld ? unheldUnits : unitsOf(suites, times, splitPast);
|
|
60979
61237
|
const past = splitPast > SPLIT_PAST_SECONDS ? `an engine's share of this run (${String(Math.round(splitPast))} s)` : `${String(SPLIT_PAST_SECONDS)} s`;
|
|
60980
61238
|
const plans = options.order === null ? dealt(units, declared, room.engines) : [inOneEngine(ordered(units, options.order), declared)];
|
|
60981
61239
|
const functions = suites.reduce((sum, suite) => sum + suite.cases.length, 0);
|
|
@@ -61008,24 +61266,28 @@ ${existsSync24(path) ? readFileSync24(path, "latin1") : "missing"}`)
|
|
|
61008
61266
|
say(`Kept whole in one engine, since ${one ? "it declares" : "each declares"} GDHARNESS_TOGETHER: ${named(keptWhole)}.`);
|
|
61009
61267
|
}
|
|
61010
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;
|
|
61011
61270
|
const taken = [];
|
|
61012
|
-
while (taken.length <
|
|
61271
|
+
while (taken.length < startable) {
|
|
61013
61272
|
const lock = await slots.takeFree();
|
|
61014
61273
|
if (lock === null) {
|
|
61015
61274
|
break;
|
|
61016
61275
|
}
|
|
61017
61276
|
taken.push(lock);
|
|
61018
61277
|
}
|
|
61019
|
-
|
|
61020
|
-
|
|
61021
|
-
|
|
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));
|
|
61022
61284
|
}
|
|
61023
61285
|
const handed = new HandedSlot;
|
|
61024
|
-
const compiling =
|
|
61286
|
+
const compiling = compileUnlessUnchanged(launch, everySuite, compileKept, handed);
|
|
61025
61287
|
compiling.catch(() => {
|
|
61026
61288
|
return;
|
|
61027
61289
|
});
|
|
61028
|
-
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);
|
|
61029
61291
|
if (ran.some((engine) => engine.verdict.starved) && ran.some((engine) => !engine.verdict.passed)) {
|
|
61030
61292
|
say("An engine ran out of memory, so every engine that failed runs again, one at a time.");
|
|
61031
61293
|
const again = [];
|
|
@@ -61052,6 +61314,55 @@ ${existsSync24(path) ? readFileSync24(path, "latin1") : "missing"}`)
|
|
|
61052
61314
|
function sharesSaid(free, lanes) {
|
|
61053
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.`;
|
|
61054
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
|
+
}
|
|
61055
61366
|
function roomSaid(engines, lanes, unheld, held, asked) {
|
|
61056
61367
|
if (held === undefined || lanes >= unheld) {
|
|
61057
61368
|
return "";
|
|
@@ -61061,7 +61372,7 @@ function roomSaid(engines, lanes, unheld, held, asked) {
|
|
|
61061
61372
|
function readPassed(file) {
|
|
61062
61373
|
let parsed;
|
|
61063
61374
|
try {
|
|
61064
|
-
parsed = JSON.parse(
|
|
61375
|
+
parsed = JSON.parse(readFileSync26(file, "utf8"));
|
|
61065
61376
|
} catch {
|
|
61066
61377
|
return {};
|
|
61067
61378
|
}
|
|
@@ -61077,7 +61388,7 @@ function readPassed(file) {
|
|
|
61077
61388
|
function recordPassed(file, projectPath, ran, failedAcross, inputs, began) {
|
|
61078
61389
|
const passed = readPassed(file);
|
|
61079
61390
|
for (const path of Object.keys(passed)) {
|
|
61080
|
-
if (!
|
|
61391
|
+
if (!existsSync23(join28(projectPath, path.slice("res://".length)))) {
|
|
61081
61392
|
delete passed[path];
|
|
61082
61393
|
}
|
|
61083
61394
|
}
|
|
@@ -61126,6 +61437,9 @@ class HandedSlot {
|
|
|
61126
61437
|
lock = new Promise((resolve) => {
|
|
61127
61438
|
this.handOver = resolve;
|
|
61128
61439
|
});
|
|
61440
|
+
decline() {
|
|
61441
|
+
this.wanted = false;
|
|
61442
|
+
}
|
|
61129
61443
|
give(lock) {
|
|
61130
61444
|
if (!this.wanted) {
|
|
61131
61445
|
return false;
|
|
@@ -61177,7 +61491,42 @@ async function compileCheck(launch, suites, handed) {
|
|
|
61177
61491
|
} finally {
|
|
61178
61492
|
launch.slots.release(lock);
|
|
61179
61493
|
}
|
|
61180
|
-
return { faults: judgeCompile(readRun(
|
|
61494
|
+
return { faults: judgeCompile(readRun(readFileSync26(log, "utf8")), end), log };
|
|
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
|
+
}
|
|
61181
61530
|
}
|
|
61182
61531
|
function printCompiled(compiled, logs) {
|
|
61183
61532
|
if (compiled.faults.length === 0) {
|
|
@@ -61203,6 +61552,21 @@ function importFault(printed) {
|
|
|
61203
61552
|
].join(" and ");
|
|
61204
61553
|
return `it printed ${counted}, the first ${first.warning ? "warning" : "error"} ${JSON.stringify(first.text)}`;
|
|
61205
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
|
+
}
|
|
61206
61570
|
async function importProject(launch) {
|
|
61207
61571
|
const seeded = seedExtensionList(launch.projectPath);
|
|
61208
61572
|
if (seeded !== null && seeded.length > 0) {
|
|
@@ -61250,35 +61614,48 @@ async function runLane(launch, lane, times, taken, handed) {
|
|
|
61250
61614
|
doneWith(launch, lock, handed);
|
|
61251
61615
|
}
|
|
61252
61616
|
}
|
|
61253
|
-
async function runShares(launch, units, declared, lanes, taken, times, handed) {
|
|
61617
|
+
async function runShares(launch, units, declared, lanes, taken, times, handed, memory) {
|
|
61254
61618
|
const shares = new Shares(units, declared, lanes);
|
|
61255
61619
|
const handedOut = new AbortController;
|
|
61256
61620
|
let engines = 0;
|
|
61621
|
+
const empty = () => shares.empty;
|
|
61257
61622
|
const lane = async (at) => {
|
|
61258
61623
|
let lock = taken[at] ?? null;
|
|
61259
|
-
|
|
61260
|
-
try {
|
|
61261
|
-
lock = await launch.slots.take(handedOut.signal);
|
|
61262
|
-
} catch (error) {
|
|
61263
|
-
if (handedOut.signal.aborted) {
|
|
61264
|
-
return [];
|
|
61265
|
-
}
|
|
61266
|
-
throw error;
|
|
61267
|
-
}
|
|
61268
|
-
}
|
|
61624
|
+
const ran = [];
|
|
61269
61625
|
try {
|
|
61270
|
-
|
|
61271
|
-
|
|
61272
|
-
|
|
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()) {
|
|
61273
61644
|
handedOut.abort();
|
|
61274
61645
|
}
|
|
61275
61646
|
const index = engines;
|
|
61276
61647
|
engines += 1;
|
|
61277
|
-
|
|
61648
|
+
try {
|
|
61649
|
+
ran.push(await runEngine2(launch, plan, index, times, "", lock));
|
|
61650
|
+
} finally {
|
|
61651
|
+
ended?.();
|
|
61652
|
+
}
|
|
61278
61653
|
}
|
|
61279
61654
|
return ran;
|
|
61280
61655
|
} finally {
|
|
61281
|
-
|
|
61656
|
+
if (lock !== null) {
|
|
61657
|
+
doneWith(launch, lock, handed);
|
|
61658
|
+
}
|
|
61282
61659
|
}
|
|
61283
61660
|
};
|
|
61284
61661
|
return (await Promise.all(Array.from({ length: lanes }, (_, at) => lane(at)))).flat().sort((a, b) => a.index - b.index);
|
|
@@ -61373,7 +61750,7 @@ async function runEngine2(launch, plan, index, times, again = "", slot = null) {
|
|
|
61373
61750
|
}
|
|
61374
61751
|
var REPORT_FILES_NAMED = 3;
|
|
61375
61752
|
function reportsFault(reports) {
|
|
61376
|
-
const files =
|
|
61753
|
+
const files = existsSync23(reports) ? readdirSync15(reports, { recursive: true, encoding: "utf8" }).filter((file) => statSync14(join28(reports, file)).isFile()).sort() : [];
|
|
61377
61754
|
if (files.length === 0) {
|
|
61378
61755
|
return null;
|
|
61379
61756
|
}
|
|
@@ -61386,7 +61763,7 @@ function report(ran, compiled, across, uncollected, startedAt, logs, printOutput
|
|
|
61386
61763
|
for (const engine of ran) {
|
|
61387
61764
|
console.log("");
|
|
61388
61765
|
console.log(`--- what engine ${String(engine.index)} printed, running ${named(engine.plan.suites.map((suite) => suite.path))}:`);
|
|
61389
|
-
console.log(
|
|
61766
|
+
console.log(existsSync23(engine.log) ? readLog(engine.log).replace(CONTROL_SEQUENCE, "").trimEnd() : "(no log was written)");
|
|
61390
61767
|
}
|
|
61391
61768
|
}
|
|
61392
61769
|
const failed = ran.filter((engine) => !engine.verdict.passed);
|
|
@@ -61397,7 +61774,7 @@ function report(ran, compiled, across, uncollected, startedAt, logs, printOutput
|
|
|
61397
61774
|
for (const fault of engine.verdict.faults) {
|
|
61398
61775
|
console.log(` ${fault}`);
|
|
61399
61776
|
}
|
|
61400
|
-
if (
|
|
61777
|
+
if (existsSync23(engine.log)) {
|
|
61401
61778
|
const verdict = [
|
|
61402
61779
|
`gdharness: ${heading.slice(4)}`,
|
|
61403
61780
|
...engine.verdict.faults.map((fault) => ` ${fault}`)
|
|
@@ -61492,6 +61869,9 @@ function report(ran, compiled, across, uncollected, startedAt, logs, printOutput
|
|
|
61492
61869
|
const problems = failed.reduce((sum, engine) => sum + engine.verdict.faults.length, compiled.faults.length + across.length + uncollected.length);
|
|
61493
61870
|
console.log(`Failed: ${plural(problems, "problem")}, listed above. Ran ${totals}`);
|
|
61494
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
|
+
}
|
|
61495
61875
|
return 1;
|
|
61496
61876
|
}
|
|
61497
61877
|
function writeEarlyResult(targets, startedAt, problems, logs) {
|
|
@@ -61533,7 +61913,7 @@ class UsageError extends Refusal {
|
|
|
61533
61913
|
function projectArgument(at) {
|
|
61534
61914
|
const named = args.slice(at).find((value) => !value.startsWith("--"));
|
|
61535
61915
|
const projectPath = resolve15(named ?? ".");
|
|
61536
|
-
if (!
|
|
61916
|
+
if (!existsSync35(join45(projectPath, "project.godot"))) {
|
|
61537
61917
|
throw new UsageError(`Not a Godot project: ${projectPath} holds no project.godot.`);
|
|
61538
61918
|
}
|
|
61539
61919
|
return projectPath;
|
|
@@ -61597,7 +61977,7 @@ async function registerRuntime(godot, projectPath) {
|
|
|
61597
61977
|
}
|
|
61598
61978
|
const path = (named ?? "").replace(/^res:\/\//, "");
|
|
61599
61979
|
console.log(`${RUNTIME_AUTOLOAD.name} autoload left at ${named}, which this project registers itself`);
|
|
61600
|
-
if (!
|
|
61980
|
+
if (!existsSync35(join45(projectPath, path))) {
|
|
61601
61981
|
console.log(" that file is not in this project, so it boots with a missing script");
|
|
61602
61982
|
}
|
|
61603
61983
|
console.log(` ${useTheShippedLoader(RUNTIME_AUTOLOAD.name, path)}`);
|
|
@@ -61730,7 +62110,7 @@ async function setup() {
|
|
|
61730
62110
|
console.log("no harness configured; name one yourself, and gdharness harnesses lists them all");
|
|
61731
62111
|
}
|
|
61732
62112
|
if (!args.includes("--no-skill")) {
|
|
61733
|
-
const directories = skillDirectories(chosen.harnesses, projectPath,
|
|
62113
|
+
const directories = skillDirectories(chosen.harnesses, projectPath, existsSync35);
|
|
61734
62114
|
for (const written of writeSkill(directories, getLocalVersion())) {
|
|
61735
62115
|
console.log(`skill: ${written.replaced ? "replaced" : "written"} ${written.path}`);
|
|
61736
62116
|
}
|
|
@@ -61850,7 +62230,7 @@ async function upgrade() {
|
|
|
61850
62230
|
moved.push(took.from);
|
|
61851
62231
|
}
|
|
61852
62232
|
}
|
|
61853
|
-
for (const written of writeSkill(skillDirectories(already, projectPath,
|
|
62233
|
+
for (const written of writeSkill(skillDirectories(already, projectPath, existsSync35), version)) {
|
|
61854
62234
|
console.log(`skill: ${written.replaced ? "replaced" : "written"} ${written.path}`);
|
|
61855
62235
|
}
|
|
61856
62236
|
console.log(`
|