gdharness 1.3.42 → 1.3.44
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 +383 -243
- package/build/godot/addons/auto_reload/auto_reload.gd +18 -19
- package/build/godot/addons/gdharness_editor/animation_reads.gd +55 -33
- package/build/godot/addons/gdharness_editor/bridge_client.gd +53 -58
- package/build/godot/addons/gdharness_editor/declared_values.gd +68 -32
- package/build/godot/addons/gdharness_editor/file_reads.gd +83 -42
- package/build/godot/addons/gdharness_editor/file_walk.gd +12 -5
- package/build/godot/addons/gdharness_editor/headless_check.gd +68 -44
- package/build/godot/addons/gdharness_editor/plugin.gd +2 -3
- package/build/godot/addons/gdharness_editor/property_paths.gd +22 -12
- package/build/godot/addons/gdharness_editor/property_values.gd +143 -78
- package/build/godot/addons/gdharness_editor/reading.gd +51 -17
- package/build/godot/addons/gdharness_editor/same_values.gd +4 -4
- package/build/godot/addons/gdharness_editor/scene_file.gd +127 -80
- package/build/godot/addons/gdharness_editor/scene_uids.gd +12 -6
- package/build/godot/addons/gdharness_editor/serialisation.gd +75 -51
- package/build/godot/addons/gdharness_editor/setting_reads.gd +7 -6
- package/build/godot/addons/gdharness_editor/tool_executor.gd +3 -6
- package/build/godot/addons/gdharness_editor/tools/animation_states.gd +37 -27
- package/build/godot/addons/gdharness_editor/tools/animation_tools.gd +79 -49
- package/build/godot/addons/gdharness_editor/tools/animation_tracks.gd +70 -40
- package/build/godot/addons/gdharness_editor/tools/class_tools.gd +65 -42
- package/build/godot/addons/gdharness_editor/tools/filesystem_tools.gd +24 -22
- package/build/godot/addons/gdharness_editor/tools/navigation_bake.gd +49 -29
- package/build/godot/addons/gdharness_editor/tools/play_tools.gd +26 -21
- package/build/godot/addons/gdharness_editor/tools/profile_tools.gd +40 -40
- package/build/godot/addons/gdharness_editor/tools/resource_tools.gd +166 -107
- package/build/godot/addons/gdharness_editor/tools/scene_groups.gd +16 -9
- package/build/godot/addons/gdharness_editor/tools/scene_kin.gd +68 -41
- package/build/godot/addons/gdharness_editor/tools/scene_paths.gd +35 -20
- package/build/godot/addons/gdharness_editor/tools/scene_placing.gd +28 -13
- package/build/godot/addons/gdharness_editor/tools/scene_sharing.gd +12 -5
- package/build/godot/addons/gdharness_editor/tools/scene_tools.gd +113 -67
- package/build/godot/addons/gdharness_editor/tools/script_paths.gd +20 -8
- package/build/godot/addons/gdharness_editor/tools/settings_tools.gd +11 -8
- package/build/godot/addons/gdharness_editor/tools/signal_tools.gd +47 -34
- package/build/godot/addons/gdharness_editor/tools/tileset_tools.gd +77 -50
- package/build/godot/addons/gdharness_editor/value_shapes.gd +5 -6
- package/build/godot/addons/gdharness_runtime/call_errors.gd +1 -2
- package/build/godot/addons/gdharness_runtime/declared_values.gd +68 -32
- package/build/godot/addons/gdharness_runtime/error_report.gd +1 -2
- package/build/godot/addons/gdharness_runtime/reading.gd +51 -17
- package/build/godot/addons/gdharness_runtime/runtime_accessibility.gd +84 -63
- package/build/godot/addons/gdharness_runtime/runtime_autoload.gd +149 -147
- package/build/godot/addons/gdharness_runtime/runtime_capture.gd +64 -42
- package/build/godot/addons/gdharness_runtime/runtime_changes.gd +184 -122
- package/build/godot/addons/gdharness_runtime/runtime_frames.gd +2 -2
- package/build/godot/addons/gdharness_runtime/runtime_hover.gd +24 -20
- package/build/godot/addons/gdharness_runtime/runtime_input.gd +134 -92
- package/build/godot/addons/gdharness_runtime/runtime_items.gd +29 -13
- package/build/godot/addons/gdharness_runtime/runtime_menus.gd +0 -1
- package/build/godot/addons/gdharness_runtime/runtime_mouse.gd +34 -17
- package/build/godot/addons/gdharness_runtime/runtime_pad.gd +17 -13
- package/build/godot/addons/gdharness_runtime/runtime_paths.gd +84 -46
- package/build/godot/addons/gdharness_runtime/runtime_queries.gd +117 -79
- package/build/godot/addons/gdharness_runtime/runtime_says.gd +14 -17
- package/build/godot/addons/gdharness_runtime/runtime_screen.gd +23 -16
- package/build/godot/addons/gdharness_runtime/runtime_targets.gd +117 -66
- package/build/godot/addons/gdharness_runtime/runtime_touch.gd +15 -15
- package/build/godot/addons/gdharness_runtime/runtime_typing.gd +44 -27
- package/build/godot/addons/gdharness_runtime/runtime_values.gd +108 -73
- package/build/godot/addons/gdharness_runtime/runtime_waits.gd +111 -84
- package/build/godot/addons/gdharness_runtime/runtime_words.gd +10 -7
- package/build/godot/addons/gdharness_runtime/serialisation.gd +75 -51
- package/build/godot/addons/gdharness_runtime/value_shapes.gd +5 -6
- package/build/godot/addons/gdharness_tests/bench.gd +4 -5
- package/build/godot/addons/gdharness_tests/event.gd +10 -5
- package/build/godot/addons/gdharness_tests/share.gd +38 -18
- package/build/godot/addons/gdharness_tests/suites.gd +3 -3
- package/build/godot/addons/gdharness_tests/wait.gd +3 -2
- package/build/godot/loader/loader.gd +9 -9
- package/build/godot/operations/animation_reads.gd +55 -33
- package/build/godot/operations/audio_buses.gd +48 -19
- package/build/godot/operations/class_cache.gd +16 -11
- package/build/godot/operations/classdb_queries.gd +89 -44
- package/build/godot/operations/declared_values.gd +68 -32
- package/build/godot/operations/dependencies.gd +190 -109
- package/build/godot/operations/editor_tools.gd +10 -10
- package/build/godot/operations/export_presets.gd +100 -54
- package/build/godot/operations/file_reads.gd +83 -42
- package/build/godot/operations/file_walk.gd +12 -5
- package/build/godot/operations/gdscript_analysis.gd +86 -65
- package/build/godot/operations/gdscript_authoring.gd +83 -36
- package/build/godot/operations/godot_operations.gd +17 -11
- package/build/godot/operations/import_pipeline.gd +110 -59
- package/build/godot/operations/input_actions.gd +62 -39
- package/build/godot/operations/patterns.gd +3 -1
- package/build/godot/operations/plugins.gd +36 -16
- package/build/godot/operations/project_config.gd +61 -32
- package/build/godot/operations/project_diagnostics.gd +24 -11
- package/build/godot/operations/project_file.gd +16 -16
- package/build/godot/operations/project_validation.gd +71 -44
- package/build/godot/operations/property_paths.gd +22 -12
- package/build/godot/operations/property_values.gd +143 -78
- package/build/godot/operations/reading.gd +51 -17
- package/build/godot/operations/rename_checks.gd +2 -2
- package/build/godot/operations/resource_files.gd +11 -9
- package/build/godot/operations/same_values.gd +4 -4
- package/build/godot/operations/scene_connections.gd +27 -13
- package/build/godot/operations/script_check.gd +52 -49
- package/build/godot/operations/serialisation.gd +75 -51
- package/build/godot/operations/setting_reads.gd +7 -6
- package/build/godot/operations/value_shapes.gd +5 -6
- package/build/godot/tests/listed.gd +321 -268
- package/build/keeper.js +43 -43
- package/package.json +1 -1
package/build/cli.js
CHANGED
|
@@ -9723,8 +9723,71 @@ var init_gdscript_source = __esm(() => {
|
|
|
9723
9723
|
]);
|
|
9724
9724
|
});
|
|
9725
9725
|
|
|
9726
|
+
// src/whole-file.ts
|
|
9727
|
+
import { readFileSync as readFileSync5, renameSync, rmSync as rmSync4, writeFileSync as writeFileSync4 } from "node:fs";
|
|
9728
|
+
function readWhole(path) {
|
|
9729
|
+
const until = Date.now() + HELD_FILE_MS;
|
|
9730
|
+
for (;; ) {
|
|
9731
|
+
try {
|
|
9732
|
+
return readFileSync5(path, "utf8");
|
|
9733
|
+
} catch (error) {
|
|
9734
|
+
const code = error.code ?? "";
|
|
9735
|
+
if (code === "ENOENT") {
|
|
9736
|
+
return null;
|
|
9737
|
+
}
|
|
9738
|
+
if (!HELD_BY_A_READER.has(code) || Date.now() >= until) {
|
|
9739
|
+
throw error;
|
|
9740
|
+
}
|
|
9741
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, HELD_FILE_RETRY_MS);
|
|
9742
|
+
}
|
|
9743
|
+
}
|
|
9744
|
+
}
|
|
9745
|
+
function writeWhole(path, text) {
|
|
9746
|
+
const partial = `${path}.${process.pid}.partial`;
|
|
9747
|
+
try {
|
|
9748
|
+
writeFileSync4(partial, text, "utf8");
|
|
9749
|
+
} catch {
|
|
9750
|
+
return false;
|
|
9751
|
+
}
|
|
9752
|
+
const until = Date.now() + HELD_FILE_MS;
|
|
9753
|
+
for (;; ) {
|
|
9754
|
+
try {
|
|
9755
|
+
renameSync(partial, path);
|
|
9756
|
+
return true;
|
|
9757
|
+
} catch (error) {
|
|
9758
|
+
const code = error.code ?? "";
|
|
9759
|
+
if (!HELD_BY_A_READER.has(code) || Date.now() >= until) {
|
|
9760
|
+
try {
|
|
9761
|
+
rmSync4(partial, { force: true });
|
|
9762
|
+
} catch {}
|
|
9763
|
+
return false;
|
|
9764
|
+
}
|
|
9765
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, HELD_FILE_RETRY_MS);
|
|
9766
|
+
}
|
|
9767
|
+
}
|
|
9768
|
+
}
|
|
9769
|
+
function removeWhole(path) {
|
|
9770
|
+
const until = Date.now() + HELD_FILE_MS;
|
|
9771
|
+
for (;; ) {
|
|
9772
|
+
try {
|
|
9773
|
+
rmSync4(path, { force: true });
|
|
9774
|
+
return true;
|
|
9775
|
+
} catch (error) {
|
|
9776
|
+
const code = error.code ?? "";
|
|
9777
|
+
if (!HELD_BY_A_READER.has(code) || Date.now() >= until) {
|
|
9778
|
+
return false;
|
|
9779
|
+
}
|
|
9780
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, HELD_FILE_RETRY_MS);
|
|
9781
|
+
}
|
|
9782
|
+
}
|
|
9783
|
+
}
|
|
9784
|
+
var HELD_FILE_MS = 1000, HELD_FILE_RETRY_MS = 10, HELD_BY_A_READER;
|
|
9785
|
+
var init_whole_file = __esm(() => {
|
|
9786
|
+
HELD_BY_A_READER = new Set(["EPERM", "EACCES", "EBUSY"]);
|
|
9787
|
+
});
|
|
9788
|
+
|
|
9726
9789
|
// src/class-cache.ts
|
|
9727
|
-
import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as
|
|
9790
|
+
import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync6, statSync as statSync4 } from "node:fs";
|
|
9728
9791
|
import { join as join6, posix } from "node:path";
|
|
9729
9792
|
function isToolScript(source) {
|
|
9730
9793
|
return TOOL.test(codeOf(source));
|
|
@@ -9799,7 +9862,7 @@ function eachScript(projectPath, each) {
|
|
|
9799
9862
|
if (entry.isDirectory()) {
|
|
9800
9863
|
visit(path, `${prefix}${entry.name}/`);
|
|
9801
9864
|
} else if (entry.isFile() && entry.name.endsWith(".gd")) {
|
|
9802
|
-
each(`res://${prefix}${entry.name}`,
|
|
9865
|
+
each(`res://${prefix}${entry.name}`, readFileSync6(path, "utf8"));
|
|
9803
9866
|
}
|
|
9804
9867
|
}
|
|
9805
9868
|
};
|
|
@@ -9832,12 +9895,11 @@ function scriptsDeclaring(projectPath, classes) {
|
|
|
9832
9895
|
return declaring.sort((a, b) => a.script.localeCompare(b.script));
|
|
9833
9896
|
}
|
|
9834
9897
|
function cachedClasses(projectPath) {
|
|
9835
|
-
const
|
|
9836
|
-
if (
|
|
9898
|
+
const text = readWhole(join6(projectPath, ".godot", "global_script_class_cache.cfg"));
|
|
9899
|
+
if (text === null) {
|
|
9837
9900
|
return null;
|
|
9838
9901
|
}
|
|
9839
9902
|
const listed = new Map;
|
|
9840
|
-
const text = readFileSync5(cache, "utf8");
|
|
9841
9903
|
for (const entry of text.matchAll(/"class":\s*&"([^"]+)"[\s\S]*?"path":\s*"([^"]+)"/g)) {
|
|
9842
9904
|
listed.set(entry[1] ?? "", entry[2] ?? "");
|
|
9843
9905
|
}
|
|
@@ -10126,7 +10188,8 @@ function failedReloadNote(failed) {
|
|
|
10126
10188
|
} else {
|
|
10127
10189
|
copy = `The copy the editor holds was compiled again from the text it was built from and changed even so${lost.length === 0 ? "" : `, and has lost ${lost.join(", ")}`}: anything diagnosed against it now is answered from what is left, and reloading it once it compiles rebuilds it.`;
|
|
10128
10190
|
}
|
|
10129
|
-
const
|
|
10191
|
+
const advice = failed.names.length === 0 ? "" : ` If they deny a member of ${failed.names.join(" or ")} that its file declares, the editor's copy of that class is behind: reload that class first with reloadScript and then this script, the order that cleared it in the one project that has met this.`;
|
|
10192
|
+
const order = failed.builtOn === undefined ? advice : ` ${failed.builtOn}${failed.builtOnUnchecked === true ? advice : ""}`;
|
|
10130
10193
|
return `${failed.script} did not compile: Godot answered ${answered}. ${copy} ` + `script_diagnostics on it gives the errors.${order}`;
|
|
10131
10194
|
}
|
|
10132
10195
|
function uncachedClassNote(types) {
|
|
@@ -10188,6 +10251,7 @@ function unseenByEditor(projectPath, editorHolds) {
|
|
|
10188
10251
|
var DECLARATION, TOOL, ABSTRACT_HEADER, UNKNOWN_CLASS;
|
|
10189
10252
|
var init_class_cache = __esm(() => {
|
|
10190
10253
|
init_gdscript_source();
|
|
10254
|
+
init_whole_file();
|
|
10191
10255
|
DECLARATION = /^(?:@[a-z_]+(?:\([^)\n]*\))?\s+)*class_name\s+([A-Za-z_][A-Za-z0-9_]*)/m;
|
|
10192
10256
|
TOOL = /^[ \t]*(?:@[a-z_]+(?:\([^)\n]*\))?[ \t]+)*@tool\b/m;
|
|
10193
10257
|
ABSTRACT_HEADER = /^((?:@[\p{L}_][\p{L}\p{N}_]*(?:\([^)]*\))?\s+)*)(?:class_name|extends)\s/mu;
|
|
@@ -10894,7 +10958,7 @@ var init_junit = __esm(() => {
|
|
|
10894
10958
|
});
|
|
10895
10959
|
|
|
10896
10960
|
// src/suite-judge.ts
|
|
10897
|
-
import { readFileSync as
|
|
10961
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
10898
10962
|
import { stripVTControlCharacters } from "node:util";
|
|
10899
10963
|
function secondsOf(time) {
|
|
10900
10964
|
let ms = 0;
|
|
@@ -10914,6 +10978,36 @@ function rowOf(name) {
|
|
|
10914
10978
|
function rowRuns(share, row) {
|
|
10915
10979
|
return "only" in share ? row !== null && share.only.includes(row) : row === null || !share.besides.includes(row);
|
|
10916
10980
|
}
|
|
10981
|
+
function mismatchedRowsIn(printed) {
|
|
10982
|
+
const lines = printed.flatMap((text) => stripVTControlCharacters(text).split(/\r?\n/));
|
|
10983
|
+
const found = [];
|
|
10984
|
+
let suite = null;
|
|
10985
|
+
let lastCase = null;
|
|
10986
|
+
for (let at = 0;at < lines.length; at += 1) {
|
|
10987
|
+
const line = lines[at] ?? "";
|
|
10988
|
+
const opened = SUITE_OPENED.exec(line)?.[1];
|
|
10989
|
+
if (opened !== undefined) {
|
|
10990
|
+
suite = opened;
|
|
10991
|
+
lastCase = null;
|
|
10992
|
+
continue;
|
|
10993
|
+
}
|
|
10994
|
+
const caseLine = CASE_LINE.exec(line);
|
|
10995
|
+
if (caseLine !== null) {
|
|
10996
|
+
lastCase = caseLine[3] === "STARTED" ? lastCase : caseLine[2] ?? null;
|
|
10997
|
+
continue;
|
|
10998
|
+
}
|
|
10999
|
+
if (suite === null || lastCase === null || !MISMATCHED_ROW.test(line)) {
|
|
11000
|
+
continue;
|
|
11001
|
+
}
|
|
11002
|
+
const parts = [line.trim()];
|
|
11003
|
+
while (at + 1 < lines.length && !["", "'"].includes((lines[at + 1] ?? "").trim())) {
|
|
11004
|
+
at += 1;
|
|
11005
|
+
parts.push((lines[at] ?? "").trim());
|
|
11006
|
+
}
|
|
11007
|
+
found.push({ suite, name: lastCase, reason: parts.join(" ").replaceAll(/\[\/?color[^\]]*\]/g, "") });
|
|
11008
|
+
}
|
|
11009
|
+
return found;
|
|
11010
|
+
}
|
|
10917
11011
|
function readRun(printed) {
|
|
10918
11012
|
const lines = stripVTControlCharacters(printed).replaceAll(`\r
|
|
10919
11013
|
`, `
|
|
@@ -11045,7 +11139,8 @@ function readRun(printed) {
|
|
|
11045
11139
|
running: last === null ? null : { suite: last.path, during },
|
|
11046
11140
|
leftOut,
|
|
11047
11141
|
engineVersion,
|
|
11048
|
-
orphansLeft
|
|
11142
|
+
orphansLeft,
|
|
11143
|
+
mismatched: mismatchedRowsIn(lines)
|
|
11049
11144
|
};
|
|
11050
11145
|
}
|
|
11051
11146
|
function withNestedErrors(printed, piped) {
|
|
@@ -11064,7 +11159,7 @@ function versionFault(said, wanted) {
|
|
|
11064
11159
|
function readExpected(file) {
|
|
11065
11160
|
const declared = (value) => typeof value === "object" && value !== null ? value : {};
|
|
11066
11161
|
try {
|
|
11067
|
-
const parsed = JSON.parse(
|
|
11162
|
+
const parsed = JSON.parse(readFileSync7(file, "utf8"));
|
|
11068
11163
|
const read = typeof parsed === "object" && parsed !== null ? parsed : {};
|
|
11069
11164
|
return { errors: declared(read["errors"]), warnings: declared(read["warnings"]) };
|
|
11070
11165
|
} catch {
|
|
@@ -11170,6 +11265,10 @@ function judgeEngine(printed, handed, end) {
|
|
|
11170
11265
|
if (printed.executed === null || printed.executed === 0) {
|
|
11171
11266
|
faults.push(printed.executed === null ? "the run never printed its summary" : "the run executed no test case at all, whatever it exited with");
|
|
11172
11267
|
}
|
|
11268
|
+
for (const row of printed.mismatched) {
|
|
11269
|
+
faults.push(`${row.suite} > ${row.name} never ran: gdUnit4 skipped it, saying "${row.reason}"`);
|
|
11270
|
+
failing.add(row.suite);
|
|
11271
|
+
}
|
|
11173
11272
|
for (const { path, cases, rows = {} } of handed.suites) {
|
|
11174
11273
|
const suite = printed.suites.get(path);
|
|
11175
11274
|
if (suite === undefined) {
|
|
@@ -11333,7 +11432,7 @@ ${String(error.warning)}`);
|
|
|
11333
11432
|
const neverPrinted = [...owed.values()].flatMap((debt) => debt.texts.map((text) => ({ suite: debt.suite, during: debt.during, text, warning: debt.warning })));
|
|
11334
11433
|
return { printed: unexpected, neverPrinted };
|
|
11335
11434
|
}
|
|
11336
|
-
var SUITE_OPENED, TIME, CASE_LINE, STATISTICS, ERROR_LINE, WARNING_LINE, EXECUTED, BANNER, LEFT_OUT, DRIVER_FALLBACK, MACHINE_WARNED, ORPHANS_REPORTED, STARVED, 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, TAIL = 60, MOST_NAMED = 8;
|
|
11435
|
+
var SUITE_OPENED, TIME, CASE_LINE, STATISTICS, ERROR_LINE, WARNING_LINE, EXECUTED, MISMATCHED_ROW, BANNER, LEFT_OUT, DRIVER_FALLBACK, MACHINE_WARNED, ORPHANS_REPORTED, STARVED, 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, TAIL = 60, MOST_NAMED = 8;
|
|
11337
11436
|
var init_suite_judge = __esm(() => {
|
|
11338
11437
|
init_engine_leaks();
|
|
11339
11438
|
init_junit();
|
|
@@ -11344,6 +11443,7 @@ var init_suite_judge = __esm(() => {
|
|
|
11344
11443
|
ERROR_LINE = /^\s*(?:SCRIPT |USER )?ERROR: (.*?)\s*$/;
|
|
11345
11444
|
WARNING_LINE = /^\s*(?:SCRIPT |USER )?WARNING: (.*?)\s*$/;
|
|
11346
11445
|
EXECUTED = /^Executed test cases\s*:\s*\((\d+)\//;
|
|
11446
|
+
MISMATCHED_ROW = /^\s*The test data set at index \(\d+\) does not match the expected test parameters/;
|
|
11347
11447
|
BANNER = /^\s*Godot Engine v(\S+?)(?:\s+-\s+\S+)?\s*$/;
|
|
11348
11448
|
LEFT_OUT = /^gdharness left out (res:\/\/.+?\.gd) > ([^:\s]+):(-?\d+)\s*$/;
|
|
11349
11449
|
DRIVER_FALLBACK = /^\s*WARNING: Your video card drivers .*, switching to /;
|
|
@@ -11381,9 +11481,9 @@ import {
|
|
|
11381
11481
|
openSync as openSync2,
|
|
11382
11482
|
readdirSync as readdirSync3,
|
|
11383
11483
|
readSync,
|
|
11384
|
-
rmSync as
|
|
11484
|
+
rmSync as rmSync5,
|
|
11385
11485
|
statSync as statSync5,
|
|
11386
|
-
writeFileSync as
|
|
11486
|
+
writeFileSync as writeFileSync5,
|
|
11387
11487
|
writeSync as writeSync2
|
|
11388
11488
|
} from "node:fs";
|
|
11389
11489
|
import { availableParallelism, freemem, totalmem } from "node:os";
|
|
@@ -11459,14 +11559,14 @@ function sweepRunDirectories(runs, kept = KEPT_RUN_DIRECTORIES) {
|
|
|
11459
11559
|
const named = /^(\d+)-(\d+)$/.exec(entry);
|
|
11460
11560
|
const pid = Number(named?.[2]);
|
|
11461
11561
|
if (!Number.isInteger(pid)) {
|
|
11462
|
-
|
|
11562
|
+
rmSync5(join7(runs, entry), { recursive: true, force: true });
|
|
11463
11563
|
} else if (!alive(pid)) {
|
|
11464
11564
|
ended.push({ entry, started: Number(named?.[1]) });
|
|
11465
11565
|
}
|
|
11466
11566
|
}
|
|
11467
11567
|
ended.sort((a, b) => b.started - a.started);
|
|
11468
11568
|
for (const { entry } of ended.slice(kept)) {
|
|
11469
|
-
|
|
11569
|
+
rmSync5(join7(runs, entry), { recursive: true, force: true });
|
|
11470
11570
|
}
|
|
11471
11571
|
}
|
|
11472
11572
|
function roomFor(most, processors, available, said = "of memory free", processorsSaid = `the machine has ${plural(processors, "processor")}`) {
|
|
@@ -11571,7 +11671,7 @@ async function watchedEngine(launch, args, directory, log, silenceSeconds, silen
|
|
|
11571
11671
|
piped = [helped.stdout, helped.stderr];
|
|
11572
11672
|
child = helped;
|
|
11573
11673
|
stop = () => {
|
|
11574
|
-
|
|
11674
|
+
writeFileSync5(stopFile, "");
|
|
11575
11675
|
};
|
|
11576
11676
|
} else {
|
|
11577
11677
|
const held = heldToCores(launch.cores, launch.godotPath, args);
|
|
@@ -11725,9 +11825,9 @@ function stillGoingSaid(tool, op, elapsedMs) {
|
|
|
11725
11825
|
const took = seconds < 60 ? `${seconds}s` : `${Math.floor(seconds / 60)}m ${seconds % 60}s`;
|
|
11726
11826
|
return `${op === null || op === "" ? tool : `${tool} ${op}`} is still going; ${took} in.`;
|
|
11727
11827
|
}
|
|
11728
|
-
async function withCallSignal(signal, answer, progress, still) {
|
|
11828
|
+
async function withCallSignal(signal, answer, progress, still, slotWaits) {
|
|
11729
11829
|
if (progress === undefined) {
|
|
11730
|
-
return signal === undefined ? answer() : current.run({ signal, progress: undefined }, answer);
|
|
11830
|
+
return signal === undefined && slotWaits === undefined ? answer() : current.run({ signal, progress: undefined, slotWaits }, answer);
|
|
11731
11831
|
}
|
|
11732
11832
|
const began = Date.now();
|
|
11733
11833
|
const rising = risingOnly(progress);
|
|
@@ -11751,7 +11851,7 @@ async function withCallSignal(signal, answer, progress, still) {
|
|
|
11751
11851
|
};
|
|
11752
11852
|
rearm();
|
|
11753
11853
|
try {
|
|
11754
|
-
return await current.run({ signal, progress: told }, answer);
|
|
11854
|
+
return await current.run({ signal, progress: told, slotWaits }, answer);
|
|
11755
11855
|
} finally {
|
|
11756
11856
|
going = undefined;
|
|
11757
11857
|
clearTimeout(quiet);
|
|
@@ -11770,63 +11870,20 @@ function callSignal() {
|
|
|
11770
11870
|
function callProgress() {
|
|
11771
11871
|
return current.getStore()?.progress;
|
|
11772
11872
|
}
|
|
11873
|
+
function callSlotWaits() {
|
|
11874
|
+
return current.getStore()?.slotWaits;
|
|
11875
|
+
}
|
|
11773
11876
|
var current, CALL_HEARTBEAT_MS = 20000;
|
|
11774
11877
|
var init_call_signal = __esm(() => {
|
|
11775
11878
|
current = new AsyncLocalStorage;
|
|
11776
11879
|
});
|
|
11777
11880
|
|
|
11778
|
-
// src/whole-file.ts
|
|
11779
|
-
import { renameSync, rmSync as rmSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
11780
|
-
function writeWhole(path, text) {
|
|
11781
|
-
const partial = `${path}.${process.pid}.partial`;
|
|
11782
|
-
try {
|
|
11783
|
-
writeFileSync5(partial, text, "utf8");
|
|
11784
|
-
} catch {
|
|
11785
|
-
return false;
|
|
11786
|
-
}
|
|
11787
|
-
const until = Date.now() + HELD_FILE_MS;
|
|
11788
|
-
for (;; ) {
|
|
11789
|
-
try {
|
|
11790
|
-
renameSync(partial, path);
|
|
11791
|
-
return true;
|
|
11792
|
-
} catch (error) {
|
|
11793
|
-
const code = error.code ?? "";
|
|
11794
|
-
if (!HELD_BY_A_READER.has(code) || Date.now() >= until) {
|
|
11795
|
-
try {
|
|
11796
|
-
rmSync5(partial, { force: true });
|
|
11797
|
-
} catch {}
|
|
11798
|
-
return false;
|
|
11799
|
-
}
|
|
11800
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, HELD_FILE_RETRY_MS);
|
|
11801
|
-
}
|
|
11802
|
-
}
|
|
11803
|
-
}
|
|
11804
|
-
function removeWhole(path) {
|
|
11805
|
-
const until = Date.now() + HELD_FILE_MS;
|
|
11806
|
-
for (;; ) {
|
|
11807
|
-
try {
|
|
11808
|
-
rmSync5(path, { force: true });
|
|
11809
|
-
return true;
|
|
11810
|
-
} catch (error) {
|
|
11811
|
-
const code = error.code ?? "";
|
|
11812
|
-
if (!HELD_BY_A_READER.has(code) || Date.now() >= until) {
|
|
11813
|
-
return false;
|
|
11814
|
-
}
|
|
11815
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, HELD_FILE_RETRY_MS);
|
|
11816
|
-
}
|
|
11817
|
-
}
|
|
11818
|
-
}
|
|
11819
|
-
var HELD_FILE_MS = 1000, HELD_FILE_RETRY_MS = 10, HELD_BY_A_READER;
|
|
11820
|
-
var init_whole_file = __esm(() => {
|
|
11821
|
-
HELD_BY_A_READER = new Set(["EPERM", "EACCES", "EBUSY"]);
|
|
11822
|
-
});
|
|
11823
|
-
|
|
11824
11881
|
// src/engine-slots.ts
|
|
11825
11882
|
import {
|
|
11826
11883
|
closeSync as closeSync3,
|
|
11827
11884
|
mkdirSync as mkdirSync3,
|
|
11828
11885
|
openSync as openSync3,
|
|
11829
|
-
readFileSync as
|
|
11886
|
+
readFileSync as readFileSync8,
|
|
11830
11887
|
rmSync as rmSync6,
|
|
11831
11888
|
statSync as statSync6,
|
|
11832
11889
|
watch,
|
|
@@ -11956,7 +12013,7 @@ class EngineSlots {
|
|
|
11956
12013
|
this.holder = holder;
|
|
11957
12014
|
this.say = say;
|
|
11958
12015
|
}
|
|
11959
|
-
async take(signal, waiting) {
|
|
12016
|
+
async take(signal, waiting, blocked) {
|
|
11960
12017
|
mkdirSync3(this.directory, { recursive: true });
|
|
11961
12018
|
const began = Date.now();
|
|
11962
12019
|
let said = Number.NEGATIVE_INFINITY;
|
|
@@ -11969,7 +12026,10 @@ class EngineSlots {
|
|
|
11969
12026
|
if (lock !== null) {
|
|
11970
12027
|
return lock;
|
|
11971
12028
|
}
|
|
11972
|
-
mark
|
|
12029
|
+
if (mark === undefined) {
|
|
12030
|
+
mark = this.waitMarked();
|
|
12031
|
+
blocked?.();
|
|
12032
|
+
}
|
|
11973
12033
|
const now = Date.now();
|
|
11974
12034
|
if (waiting !== undefined) {
|
|
11975
12035
|
if (now - said >= WAIT_SAID_MS) {
|
|
@@ -12023,7 +12083,7 @@ class EngineSlots {
|
|
|
12023
12083
|
const found = [];
|
|
12024
12084
|
for (let slot = 0;slot < this.count; slot += 1) {
|
|
12025
12085
|
try {
|
|
12026
|
-
const holder = holderOf(
|
|
12086
|
+
const holder = holderOf(readFileSync8(join8(this.directory, `${String(slot)}.lock`), "utf8"));
|
|
12027
12087
|
if (holder !== null) {
|
|
12028
12088
|
found.push(holder);
|
|
12029
12089
|
}
|
|
@@ -12043,7 +12103,7 @@ class EngineSlots {
|
|
|
12043
12103
|
release(lock) {
|
|
12044
12104
|
this.held.delete(lock);
|
|
12045
12105
|
try {
|
|
12046
|
-
if (holderOf(
|
|
12106
|
+
if (holderOf(readFileSync8(lock, "utf8"))?.pid === this.holder.pid) {
|
|
12047
12107
|
removeWhole(lock);
|
|
12048
12108
|
}
|
|
12049
12109
|
} catch {}
|
|
@@ -12093,7 +12153,7 @@ class EngineSlots {
|
|
|
12093
12153
|
let content;
|
|
12094
12154
|
let writtenAt;
|
|
12095
12155
|
try {
|
|
12096
|
-
content =
|
|
12156
|
+
content = readFileSync8(lock, "utf8");
|
|
12097
12157
|
writtenAt = statSync6(lock).mtimeMs;
|
|
12098
12158
|
} catch {
|
|
12099
12159
|
return false;
|
|
@@ -12131,31 +12191,55 @@ function nameSlotTaker(by) {
|
|
|
12131
12191
|
}
|
|
12132
12192
|
function slotWaitSaid(waitedMs, count, directory, holders = []) {
|
|
12133
12193
|
const slots = count === 1 ? `the one engine slot on this machine (${directory}) is in use` : `all ${String(count)} engine slots on this machine (${directory}) are in use`;
|
|
12194
|
+
const named = holdersNamed(count, holders);
|
|
12195
|
+
const waiting = `Waiting${waitedMs >= 1000 ? ` ${String(Math.round(waitedMs / 1000))} s so far` : ""} for an engine: ${slots}`;
|
|
12196
|
+
if (named.length === 0) {
|
|
12197
|
+
return `${waiting}, by a gate or another tool, and the engine starts when one is given back.`;
|
|
12198
|
+
}
|
|
12199
|
+
if (count === 1) {
|
|
12200
|
+
return `${waiting}, by ${named.join(", ")}, and the engine starts when it is given back.`;
|
|
12201
|
+
}
|
|
12202
|
+
return `${waiting}: ${listed(named)}. The engine starts when one is given back.`;
|
|
12203
|
+
}
|
|
12204
|
+
function slotWaitedSaid(waitedMs, count, directory, holders) {
|
|
12205
|
+
const waited = `This call waited ${String(Math.round(waitedMs / 1000))} s for an engine slot in all.`;
|
|
12206
|
+
const slots = count === 1 ? `the one engine slot on this machine (${directory}) was in use` : `all ${String(count)} engine slots on this machine (${directory}) were in use`;
|
|
12207
|
+
const named = holdersNamed(count, holders);
|
|
12208
|
+
if (named.length === 0) {
|
|
12209
|
+
return `${waited} When it first waited, ${slots}, by a gate or another tool.`;
|
|
12210
|
+
}
|
|
12211
|
+
return count === 1 ? `${waited} When it first waited, ${slots}, by ${named.join(", ")}.` : `${waited} When it first waited, ${slots}: ${listed(named)}.`;
|
|
12212
|
+
}
|
|
12213
|
+
function holdersNamed(count, holders) {
|
|
12134
12214
|
const held = new Map;
|
|
12135
12215
|
for (const holder of holders) {
|
|
12136
12216
|
const known = held.get(holder.pid);
|
|
12137
12217
|
held.set(holder.pid, { by: known?.by ?? holder.by, slots: (known?.slots ?? 0) + 1 });
|
|
12138
12218
|
}
|
|
12139
|
-
|
|
12219
|
+
return [...held].map(([pid, { by, slots: taken }]) => {
|
|
12140
12220
|
const who = pid === process7.pid ? `this process (pid ${String(pid)})` : by === undefined ? `pid ${String(pid)}` : `${by} (pid ${String(pid)})`;
|
|
12141
12221
|
return count === 1 ? who : `${String(taken)} by ${who}`;
|
|
12142
12222
|
});
|
|
12143
|
-
|
|
12144
|
-
|
|
12145
|
-
|
|
12146
|
-
}
|
|
12147
|
-
if (count === 1) {
|
|
12148
|
-
return `${waiting}, by ${named.join(", ")}, and the engine starts when it is given back.`;
|
|
12149
|
-
}
|
|
12150
|
-
const list = named.length === 1 ? named.join("") : `${named.slice(0, -1).join(", ")} and ${named.at(-1) ?? ""}`;
|
|
12151
|
-
return `${waiting}: ${list}. The engine starts when one is given back.`;
|
|
12223
|
+
}
|
|
12224
|
+
function listed(named) {
|
|
12225
|
+
return named.length === 1 ? named.join("") : `${named.slice(0, -1).join(", ")} and ${named.at(-1) ?? ""}`;
|
|
12152
12226
|
}
|
|
12153
12227
|
async function slotForCall() {
|
|
12154
12228
|
const slots = await processSlots();
|
|
12155
12229
|
const progress = callProgress();
|
|
12230
|
+
const waits = callSlotWaits();
|
|
12231
|
+
const began = Date.now();
|
|
12232
|
+
let blockedBy;
|
|
12156
12233
|
const lock = await slots.take(callSignal(), progress === undefined ? undefined : (waitedMs) => {
|
|
12157
12234
|
progress(waitedMs / 1000, slotWaitSaid(waitedMs, slots.count, slots.directory, slots.holders()));
|
|
12235
|
+
}, () => {
|
|
12236
|
+
blockedBy = slots.holders();
|
|
12158
12237
|
});
|
|
12238
|
+
if (waits !== undefined && blockedBy !== undefined) {
|
|
12239
|
+
waits.ms += Date.now() - began;
|
|
12240
|
+
const heldBy = blockedBy;
|
|
12241
|
+
waits.said ??= (waitedMs) => slotWaitedSaid(waitedMs, slots.count, slots.directory, heldBy);
|
|
12242
|
+
}
|
|
12159
12243
|
return {
|
|
12160
12244
|
release: () => {
|
|
12161
12245
|
slots.release(lock);
|
|
@@ -12925,7 +13009,7 @@ var init_doc_cache = __esm(() => {
|
|
|
12925
13009
|
});
|
|
12926
13010
|
|
|
12927
13011
|
// src/project-scan.ts
|
|
12928
|
-
import { existsSync as existsSync9, readdirSync as readdirSync6, readFileSync as
|
|
13012
|
+
import { existsSync as existsSync9, readdirSync as readdirSync6, readFileSync as readFileSync9, statSync as statSync9 } from "node:fs";
|
|
12929
13013
|
import { basename as basename5, extname, join as join11, relative as relative4, sep as sep3 } from "node:path";
|
|
12930
13014
|
function skipped(name) {
|
|
12931
13015
|
return name.startsWith(".") || SKIPPED.has(name);
|
|
@@ -13061,7 +13145,7 @@ function scriptsWithoutUid(projectPath) {
|
|
|
13061
13145
|
function pathsInUidCache(projectPath) {
|
|
13062
13146
|
let data;
|
|
13063
13147
|
try {
|
|
13064
|
-
data =
|
|
13148
|
+
data = readFileSync9(join11(projectPath, ".godot", "uid_cache.bin"));
|
|
13065
13149
|
} catch {
|
|
13066
13150
|
return null;
|
|
13067
13151
|
}
|
|
@@ -13123,7 +13207,7 @@ function projectTexts(projectPath) {
|
|
|
13123
13207
|
if (!entry.isFile() || BINARY_EXTENSIONS.has(extension)) {
|
|
13124
13208
|
continue;
|
|
13125
13209
|
}
|
|
13126
|
-
const bytes =
|
|
13210
|
+
const bytes = readFileSync9(absolute);
|
|
13127
13211
|
if (!isBinary(bytes)) {
|
|
13128
13212
|
found.push({ path: `res://${spelled}`, absolute, text: bytes.toString("utf8") });
|
|
13129
13213
|
}
|
|
@@ -13153,7 +13237,7 @@ function ignoredTexts(projectPath) {
|
|
|
13153
13237
|
if (!under || !entry.isFile() || BINARY_EXTENSIONS.has(extension) || entry.name === ".gdignore") {
|
|
13154
13238
|
continue;
|
|
13155
13239
|
}
|
|
13156
|
-
const bytes =
|
|
13240
|
+
const bytes = readFileSync9(absolute);
|
|
13157
13241
|
if (!isBinary(bytes)) {
|
|
13158
13242
|
found.push({ path: `res://${spelled}`, absolute, text: bytes.toString("utf8") });
|
|
13159
13243
|
}
|
|
@@ -13190,7 +13274,7 @@ function searchProject(projectPath, options) {
|
|
|
13190
13274
|
};
|
|
13191
13275
|
const regex = options.regex ? compiledQuery(options.query, options.caseSensitive) : null;
|
|
13192
13276
|
const needle = options.caseSensitive ? options.query : options.query.toLowerCase();
|
|
13193
|
-
|
|
13277
|
+
let shown = 0;
|
|
13194
13278
|
const notSearched = [];
|
|
13195
13279
|
const met = new Set;
|
|
13196
13280
|
const searchFile = (entryPath, name) => {
|
|
@@ -13201,28 +13285,33 @@ function searchProject(projectPath, options) {
|
|
|
13201
13285
|
if (extensions !== null && !extensions.has(extension)) {
|
|
13202
13286
|
return;
|
|
13203
13287
|
}
|
|
13204
|
-
const bytes =
|
|
13288
|
+
const bytes = readFileSync9(entryPath);
|
|
13205
13289
|
if (extensions === null && isBinary(bytes)) {
|
|
13206
13290
|
return;
|
|
13207
13291
|
}
|
|
13208
13292
|
result.summary.files_searched += 1;
|
|
13209
13293
|
const matches = [];
|
|
13294
|
+
let matched = false;
|
|
13210
13295
|
for (const [index, line] of bytes.toString("utf8").split(/\r?\n/).entries()) {
|
|
13211
13296
|
const found = regex ? regex.exec(line) : plainMatch(line, needle, options.caseSensitive);
|
|
13212
13297
|
if (found === null) {
|
|
13213
13298
|
continue;
|
|
13214
13299
|
}
|
|
13215
|
-
|
|
13300
|
+
matched = true;
|
|
13301
|
+
result.summary.total_matches += 1;
|
|
13302
|
+
if (shown >= options.maxResults) {
|
|
13216
13303
|
result.summary.truncated = true;
|
|
13217
|
-
|
|
13304
|
+
continue;
|
|
13218
13305
|
}
|
|
13306
|
+
shown += 1;
|
|
13219
13307
|
matches.push({ line: index + 1, content: line.trim(), match: found[0] });
|
|
13220
|
-
|
|
13308
|
+
}
|
|
13309
|
+
if (matched) {
|
|
13310
|
+
result.summary.files_with_matches += 1;
|
|
13221
13311
|
}
|
|
13222
13312
|
if (matches.length > 0) {
|
|
13223
13313
|
const relativePath = entryPath.slice(projectPath.length + 1).replace(/\\/g, "/");
|
|
13224
13314
|
result.results.push({ file: `res://${relativePath}`, matches });
|
|
13225
|
-
result.summary.files_with_matches += 1;
|
|
13226
13315
|
}
|
|
13227
13316
|
};
|
|
13228
13317
|
const visit = (directory, named = false) => {
|
|
@@ -13233,9 +13322,6 @@ function searchProject(projectPath, options) {
|
|
|
13233
13322
|
return;
|
|
13234
13323
|
}
|
|
13235
13324
|
for (const entry of readdirSync6(directory, { withFileTypes: true })) {
|
|
13236
|
-
if (full()) {
|
|
13237
|
-
return;
|
|
13238
|
-
}
|
|
13239
13325
|
if (skipped(entry.name)) {
|
|
13240
13326
|
continue;
|
|
13241
13327
|
}
|
|
@@ -13315,7 +13401,7 @@ var init_project_scan = __esm(() => {
|
|
|
13315
13401
|
|
|
13316
13402
|
// src/import-freshness.ts
|
|
13317
13403
|
import { createHash as createHash2 } from "node:crypto";
|
|
13318
|
-
import { existsSync as existsSync10, readdirSync as readdirSync7, readFileSync as
|
|
13404
|
+
import { existsSync as existsSync10, readdirSync as readdirSync7, readFileSync as readFileSync10, statSync as statSync10 } from "node:fs";
|
|
13319
13405
|
import { join as join12 } from "node:path";
|
|
13320
13406
|
function md5Of(file) {
|
|
13321
13407
|
let stats;
|
|
@@ -13330,7 +13416,7 @@ function md5Of(file) {
|
|
|
13330
13416
|
}
|
|
13331
13417
|
let md5;
|
|
13332
13418
|
try {
|
|
13333
|
-
md5 = createHash2("md5").update(
|
|
13419
|
+
md5 = createHash2("md5").update(readFileSync10(file)).digest("hex");
|
|
13334
13420
|
} catch {
|
|
13335
13421
|
return null;
|
|
13336
13422
|
}
|
|
@@ -13356,7 +13442,7 @@ function sectionOf(text, section) {
|
|
|
13356
13442
|
function unquoted(value) {
|
|
13357
13443
|
return value === undefined ? "" : value.replace(/^"(.*)"$/, "$1");
|
|
13358
13444
|
}
|
|
13359
|
-
function
|
|
13445
|
+
function listed2(value) {
|
|
13360
13446
|
return [...(value ?? "").matchAll(/"((?:[^"\\]|\\.)*)"/g)].map((match) => match[1] ?? "");
|
|
13361
13447
|
}
|
|
13362
13448
|
function importedIntoTheProject(projectPath, resPaths) {
|
|
@@ -13364,11 +13450,11 @@ function importedIntoTheProject(projectPath, resPaths) {
|
|
|
13364
13450
|
for (const resPath of resPaths) {
|
|
13365
13451
|
let sidecar;
|
|
13366
13452
|
try {
|
|
13367
|
-
sidecar =
|
|
13453
|
+
sidecar = readFileSync10(`${onDisk(projectPath, resPath)}.import`, "utf8");
|
|
13368
13454
|
} catch {
|
|
13369
13455
|
continue;
|
|
13370
13456
|
}
|
|
13371
|
-
const outputs =
|
|
13457
|
+
const outputs = listed2(sectionOf(sidecar, "deps").get("dest_files")).filter((output) => output.startsWith("res://") && !output.startsWith("res://.godot/"));
|
|
13372
13458
|
if (outputs.length > 0) {
|
|
13373
13459
|
wrote[resPath] = outputs;
|
|
13374
13460
|
}
|
|
@@ -13384,7 +13470,7 @@ function behind(projectPath, resPath, sidecar) {
|
|
|
13384
13470
|
if (importer === "keep" || importer === "skip") {
|
|
13385
13471
|
return null;
|
|
13386
13472
|
}
|
|
13387
|
-
const outputs =
|
|
13473
|
+
const outputs = listed2(sectionOf(sidecar, "deps").get("dest_files"));
|
|
13388
13474
|
if (outputs.some((output) => !existsSync10(onDisk(projectPath, output)))) {
|
|
13389
13475
|
return "its imported output is not on disk";
|
|
13390
13476
|
}
|
|
@@ -13392,7 +13478,7 @@ function behind(projectPath, resPath, sidecar) {
|
|
|
13392
13478
|
const record = join12(projectPath, ".godot", "imported", `${name}-${createHash2("md5").update(resPath, "utf8").digest("hex")}.md5`);
|
|
13393
13479
|
let recorded = "";
|
|
13394
13480
|
try {
|
|
13395
|
-
recorded = /^source_md5="([0-9a-f]*)"/m.exec(
|
|
13481
|
+
recorded = /^source_md5="([0-9a-f]*)"/m.exec(readFileSync10(record, "utf8"))?.[1] ?? "";
|
|
13396
13482
|
} catch {
|
|
13397
13483
|
recorded = "";
|
|
13398
13484
|
}
|
|
@@ -13434,7 +13520,7 @@ function staleImports(projectPath) {
|
|
|
13434
13520
|
}
|
|
13435
13521
|
let sidecar;
|
|
13436
13522
|
try {
|
|
13437
|
-
sidecar =
|
|
13523
|
+
sidecar = readFileSync10(join12(directory, entry.name), "utf8");
|
|
13438
13524
|
} catch {
|
|
13439
13525
|
continue;
|
|
13440
13526
|
}
|
|
@@ -13498,7 +13584,7 @@ import {
|
|
|
13498
13584
|
existsSync as existsSync11,
|
|
13499
13585
|
mkdirSync as mkdirSync4,
|
|
13500
13586
|
readdirSync as readdirSync8,
|
|
13501
|
-
readFileSync as
|
|
13587
|
+
readFileSync as readFileSync11,
|
|
13502
13588
|
renameSync as renameSync2,
|
|
13503
13589
|
unlinkSync,
|
|
13504
13590
|
writeFileSync as writeFileSync6
|
|
@@ -13614,7 +13700,7 @@ function resolveResource(projectPath, relativeTo, path) {
|
|
|
13614
13700
|
}
|
|
13615
13701
|
function readOrNull(path) {
|
|
13616
13702
|
try {
|
|
13617
|
-
return
|
|
13703
|
+
return readFileSync11(path, "utf8");
|
|
13618
13704
|
} catch {
|
|
13619
13705
|
return null;
|
|
13620
13706
|
}
|
|
@@ -13623,7 +13709,7 @@ var init_library_copies = () => {};
|
|
|
13623
13709
|
|
|
13624
13710
|
// src/reimport.ts
|
|
13625
13711
|
import { createHash as createHash3 } from "node:crypto";
|
|
13626
|
-
import { existsSync as existsSync12, readFileSync as
|
|
13712
|
+
import { existsSync as existsSync12, readFileSync as readFileSync12, rmSync as rmSync7, statSync as statSync11, utimesSync, writeFileSync as writeFileSync7 } from "node:fs";
|
|
13627
13713
|
import { basename as basename7, join as join14 } from "node:path";
|
|
13628
13714
|
function forceNextImport(projectPath, resourcePath) {
|
|
13629
13715
|
const relative = resourcePath.replace(/^res:\/\//, "");
|
|
@@ -13632,7 +13718,7 @@ function forceNextImport(projectPath, resourcePath) {
|
|
|
13632
13718
|
return;
|
|
13633
13719
|
}
|
|
13634
13720
|
const { atime, mtimeMs } = statSync11(sidecar);
|
|
13635
|
-
writeFileSync7(sidecar,
|
|
13721
|
+
writeFileSync7(sidecar, readFileSync12(sidecar, "utf8").replace(/^valid=false\r?\n/m, ""));
|
|
13636
13722
|
utimesSync(sidecar, atime, new Date(mtimeMs + 2000));
|
|
13637
13723
|
rmSync7(importRecord(projectPath, resourcePath), { force: true });
|
|
13638
13724
|
}
|
|
@@ -13858,7 +13944,7 @@ var init_script_origins = __esm(() => {
|
|
|
13858
13944
|
});
|
|
13859
13945
|
|
|
13860
13946
|
// src/headless.ts
|
|
13861
|
-
import { existsSync as existsSync14, readFileSync as
|
|
13947
|
+
import { existsSync as existsSync14, readFileSync as readFileSync13, writeFileSync as writeFileSync8 } from "node:fs";
|
|
13862
13948
|
import { dirname as dirname7, join as join17 } from "node:path";
|
|
13863
13949
|
function snakeCased(params) {
|
|
13864
13950
|
const result = emptyRecord();
|
|
@@ -14149,7 +14235,7 @@ function answerIn(file) {
|
|
|
14149
14235
|
if (!existsSync14(file)) {
|
|
14150
14236
|
return { kind: "none" };
|
|
14151
14237
|
}
|
|
14152
|
-
const text =
|
|
14238
|
+
const text = readFileSync13(file, "utf8");
|
|
14153
14239
|
try {
|
|
14154
14240
|
const parsed = JSON.parse(text);
|
|
14155
14241
|
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)}` };
|
|
@@ -14174,7 +14260,7 @@ var init_headless = __esm(() => {
|
|
|
14174
14260
|
});
|
|
14175
14261
|
|
|
14176
14262
|
// src/update-check.ts
|
|
14177
|
-
import { existsSync as existsSync15, mkdirSync as mkdirSync5, readFileSync as
|
|
14263
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync5, readFileSync as readFileSync14, writeFileSync as writeFileSync9 } from "node:fs";
|
|
14178
14264
|
import { homedir as homedir5, tmpdir as tmpdir4 } from "node:os";
|
|
14179
14265
|
import { join as join18 } from "node:path";
|
|
14180
14266
|
function packageUrl(root) {
|
|
@@ -14219,7 +14305,7 @@ function readCache(path) {
|
|
|
14219
14305
|
if (!existsSync15(path)) {
|
|
14220
14306
|
return null;
|
|
14221
14307
|
}
|
|
14222
|
-
const parsed = JSON.parse(
|
|
14308
|
+
const parsed = JSON.parse(readFileSync14(path, "utf8"));
|
|
14223
14309
|
if (typeof parsed !== "object" || parsed === null) {
|
|
14224
14310
|
return null;
|
|
14225
14311
|
}
|
|
@@ -14367,7 +14453,7 @@ var init_update_check = __esm(() => {
|
|
|
14367
14453
|
});
|
|
14368
14454
|
|
|
14369
14455
|
// src/server-version.ts
|
|
14370
|
-
import { readFileSync as
|
|
14456
|
+
import { readFileSync as readFileSync15 } from "node:fs";
|
|
14371
14457
|
function staleAddon(addonDigest, shippedDigest) {
|
|
14372
14458
|
return addonDigest !== shippedDigest;
|
|
14373
14459
|
}
|
|
@@ -14426,7 +14512,7 @@ var init_server_version = __esm(() => {
|
|
|
14426
14512
|
DEBUG_MODE = process.env["GDHARNESS_DEBUG"] === "1";
|
|
14427
14513
|
SERVER_VERSION = (() => {
|
|
14428
14514
|
try {
|
|
14429
|
-
const pkg = JSON.parse(
|
|
14515
|
+
const pkg = JSON.parse(readFileSync15(new URL("../package.json", import.meta.url), "utf8"));
|
|
14430
14516
|
return typeof pkg.version === "string" ? pkg.version : "0.0.0";
|
|
14431
14517
|
} catch {
|
|
14432
14518
|
return "0.0.0";
|
|
@@ -15537,7 +15623,7 @@ var init_lsp_client = __esm(() => {
|
|
|
15537
15623
|
});
|
|
15538
15624
|
|
|
15539
15625
|
// src/resources.ts
|
|
15540
|
-
import { readFileSync as
|
|
15626
|
+
import { readFileSync as readFileSync17, realpathSync as realpathSync3 } from "node:fs";
|
|
15541
15627
|
import { extname as extname2, resolve as resolve8 } from "node:path";
|
|
15542
15628
|
function ensureProjectPath(getProjectPath) {
|
|
15543
15629
|
const projectPath = getProjectPath();
|
|
@@ -15733,7 +15819,7 @@ function readResourceText(uri, getProjectPath) {
|
|
|
15733
15819
|
const parsedUri = parseGodotUri(uri);
|
|
15734
15820
|
if (parsedUri.kind === "project-info") {
|
|
15735
15821
|
const projectFilePath = resolveProjectFile(projectPath, "project.godot");
|
|
15736
|
-
const rawProject =
|
|
15822
|
+
const rawProject = readFileSync17(projectFilePath, "utf-8");
|
|
15737
15823
|
const parsedProject = parseProjectGodot(rawProject);
|
|
15738
15824
|
return {
|
|
15739
15825
|
mimeType: "application/json",
|
|
@@ -15742,7 +15828,7 @@ function readResourceText(uri, getProjectPath) {
|
|
|
15742
15828
|
}
|
|
15743
15829
|
const filePath = resolveProjectFile(projectPath, parsedUri.resourcePath);
|
|
15744
15830
|
ensureAllowedExtension(parsedUri.kind, filePath);
|
|
15745
|
-
const text =
|
|
15831
|
+
const text = readFileSync17(filePath, "utf-8");
|
|
15746
15832
|
return {
|
|
15747
15833
|
mimeType: parsedUri.kind === "script" ? "text/x-gdscript" : "text/plain",
|
|
15748
15834
|
text
|
|
@@ -15889,7 +15975,7 @@ import {
|
|
|
15889
15975
|
existsSync as existsSync18,
|
|
15890
15976
|
mkdirSync as mkdirSync6,
|
|
15891
15977
|
readdirSync as readdirSync11,
|
|
15892
|
-
readFileSync as
|
|
15978
|
+
readFileSync as readFileSync18,
|
|
15893
15979
|
rmdirSync,
|
|
15894
15980
|
rmSync as rmSync9,
|
|
15895
15981
|
statSync as statSync12,
|
|
@@ -15923,7 +16009,7 @@ function addonsDigest(names, from) {
|
|
|
15923
16009
|
} else {
|
|
15924
16010
|
hash.update(`${inside}
|
|
15925
16011
|
`);
|
|
15926
|
-
hash.update(
|
|
16012
|
+
hash.update(readFileSync18(path));
|
|
15927
16013
|
hash.update(`
|
|
15928
16014
|
`);
|
|
15929
16015
|
}
|
|
@@ -15953,7 +16039,7 @@ function digestMarker(projectPath, addon) {
|
|
|
15953
16039
|
if (!existsSync18(marker)) {
|
|
15954
16040
|
return null;
|
|
15955
16041
|
}
|
|
15956
|
-
const said =
|
|
16042
|
+
const said = readFileSync18(marker, "utf8").trim();
|
|
15957
16043
|
return said === "" ? null : said;
|
|
15958
16044
|
}
|
|
15959
16045
|
function shippedAddonsDirectory() {
|
|
@@ -15970,7 +16056,7 @@ function loaderState(projectPath) {
|
|
|
15970
16056
|
if (!existsSync18(copy)) {
|
|
15971
16057
|
return "missing";
|
|
15972
16058
|
}
|
|
15973
|
-
const lines = (path) =>
|
|
16059
|
+
const lines = (path) => readFileSync18(path, "utf8").replaceAll(`\r
|
|
15974
16060
|
`, `
|
|
15975
16061
|
`);
|
|
15976
16062
|
return lines(copy) === lines(shippedLoader()) ? "current" : "differs";
|
|
@@ -15981,7 +16067,7 @@ function writeLoader(projectPath) {
|
|
|
15981
16067
|
}
|
|
15982
16068
|
const copy = join21(projectPath, ...RUNTIME_AUTOLOAD.path.split("/"));
|
|
15983
16069
|
mkdirSync6(dirname9(copy), { recursive: true });
|
|
15984
|
-
writeFileSync10(copy,
|
|
16070
|
+
writeFileSync10(copy, readFileSync18(shippedLoader()));
|
|
15985
16071
|
return true;
|
|
15986
16072
|
}
|
|
15987
16073
|
function removeLoader(projectPath) {
|
|
@@ -16040,7 +16126,7 @@ function installedAddonVersion(projectPath) {
|
|
|
16040
16126
|
if (!existsSync18(marker)) {
|
|
16041
16127
|
return null;
|
|
16042
16128
|
}
|
|
16043
|
-
const said =
|
|
16129
|
+
const said = readFileSync18(marker, "utf8").trim();
|
|
16044
16130
|
return said === "" ? null : said;
|
|
16045
16131
|
}
|
|
16046
16132
|
function removeAddons(projectPath) {
|
|
@@ -16095,7 +16181,7 @@ function loaderAmong(projectPath, named) {
|
|
|
16095
16181
|
}
|
|
16096
16182
|
let source = null;
|
|
16097
16183
|
try {
|
|
16098
|
-
source =
|
|
16184
|
+
source = readFileSync18(join21(projectPath, path), "utf8");
|
|
16099
16185
|
} catch {}
|
|
16100
16186
|
if (source?.includes(RUNTIME_SCRIPT)) {
|
|
16101
16187
|
return { name: entry, path, exists: true };
|
|
@@ -16154,7 +16240,7 @@ function inspectProject(projectPath) {
|
|
|
16154
16240
|
const directory = join21(projectPath, "addons", name);
|
|
16155
16241
|
const marker = join21(directory, VERSION_MARKER);
|
|
16156
16242
|
const installed = existsSync18(directory);
|
|
16157
|
-
const version = existsSync18(marker) ?
|
|
16243
|
+
const version = existsSync18(marker) ? readFileSync18(marker, "utf8").trim() : null;
|
|
16158
16244
|
const current = version === SERVER_VERSION;
|
|
16159
16245
|
if (!installed) {
|
|
16160
16246
|
problems.push(`addons/${name} is not installed; run gdharness setup`);
|
|
@@ -16163,7 +16249,7 @@ function inspectProject(projectPath) {
|
|
|
16163
16249
|
}
|
|
16164
16250
|
return { name, installed, version, current };
|
|
16165
16251
|
});
|
|
16166
|
-
const settings = parseProjectGodot(
|
|
16252
|
+
const settings = parseProjectGodot(readFileSync18(join21(projectPath, "project.godot"), "utf8"));
|
|
16167
16253
|
const pluginsEnabled = enabledPlugins(settings);
|
|
16168
16254
|
for (const name of EDITOR_PLUGINS) {
|
|
16169
16255
|
if (!pluginsEnabled.includes(name)) {
|
|
@@ -16472,7 +16558,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
16472
16558
|
position: {
|
|
16473
16559
|
type: "string",
|
|
16474
16560
|
enum: ["end", "after_ready", "after_init"],
|
|
16475
|
-
description: "Functions: where to insert. end, the default, is the end of the file; after_ready and after_init are after _ready or _init, above the comments and annotation lines that open the function after it, and the end when nothing follows. A function goes in with two blank lines on each side, as gdformat
|
|
16561
|
+
description: "Functions: where to insert. end, the default, is the end of the file; after_ready and after_init are after _ready or _init, above the comments and annotation lines that open the function after it, and the end when nothing follows. A function goes in with two blank lines on each side, as gdstyle and gdformat write them."
|
|
16476
16562
|
}
|
|
16477
16563
|
},
|
|
16478
16564
|
required: ["type", "name"],
|
|
@@ -16594,7 +16680,11 @@ var init_tool_definitions = __esm(() => {
|
|
|
16594
16680
|
ops: ["set"],
|
|
16595
16681
|
description: 'The value to write, fitted to the type the setting is registered as, the way scene_node set fits a property. Engine types may be written as their fields, {"x": 1, "y": 2}, or tagged, {"_type": "Vector2", "x": 1, "y": 2}, and infinity as {"_type": "float", "value": "inf"}, the form a read answers with; one carrying a field its type has not is refused naming it, and a colour may also be its html code, "#ff8000". "" writes an empty string. A setting the engine does not declare is written as given, a whole number as an int and a plain list as an Array, so a packed array is tagged with its type, {"_type": "PackedStringArray", "value": ["res://a/"]}; a tag that cannot be read as its type is refused rather than written as a dictionary. When a setting in its section is named like an undeclared one, note names the nearest, as it may be a misspelt one. Every line of project.godot for another setting stays as it was, one holding a default value included.'
|
|
16596
16682
|
},
|
|
16597
|
-
name: {
|
|
16683
|
+
name: {
|
|
16684
|
+
type: "string",
|
|
16685
|
+
ops: ["add_autoload", "remove_autoload"],
|
|
16686
|
+
description: "Autoload name. add_autoload on a name already registered replaces its entry, as the editor's Add does, and answers action updated with old_path, the path it held, which no longer loads."
|
|
16687
|
+
},
|
|
16598
16688
|
path: {
|
|
16599
16689
|
type: "string",
|
|
16600
16690
|
ops: ["add_autoload"],
|
|
@@ -16748,7 +16838,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
16748
16838
|
maxResults: {
|
|
16749
16839
|
type: "integer",
|
|
16750
16840
|
minimum: 1,
|
|
16751
|
-
description: "How many matching lines to answer. Default 100."
|
|
16841
|
+
description: "How many matching lines to answer. Default 100. Past it truncated is true, and the summary still counts the whole search."
|
|
16752
16842
|
}
|
|
16753
16843
|
},
|
|
16754
16844
|
requires: ["projectPath", "query"]
|
|
@@ -16787,7 +16877,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
16787
16877
|
name: "project_import",
|
|
16788
16878
|
title: "Asset imports",
|
|
16789
16879
|
description: "The import pipeline: what needs importing, how a resource is imported, reimports, UIDs, and the global class list the editor and the engine read.",
|
|
16790
|
-
answer: "reimport is answered from a second status read: reimported lists what is current now, notReimported what is not, one entry per status and reason with the paths sharing them, and via says which of the two did the work. importedByTheScan names what the editor's scan imported first, and alsoImported, on a reimport of one resourcePath, the others it imported. wroteInProject names, by source, what an import wrote into the project itself rather than under .godot, such as the .translation a CSV gives each language, which version control sees and internationalization/locale/translations names. The import gives every script without a .uid sidecar one, as the editor's scan does, and uidsWritten names those scripts, counted per addon under uidsWrittenInAddons for the ones inside an addon. When nothing needed reimporting, the two lists are empty, a note says so, and there is no via. A whole-project reimport also answers missingSource, the .import files whose source is not beside them, empty when there are none, even when nothing needed reimporting; one resourcePath leaves it out. stillImporting is an editor that had not finished within timeoutMs.",
|
|
16880
|
+
answer: "options answers remap, deps and params as the .import file holds them, so an enum option such as compress/mode is its number: the engine gives scripts no list of a built-in importer's options or of what the numbers mean, so Godot's documentation of that importer is where a number is looked up. reimport is answered from a second status read: reimported lists what is current now, notReimported what is not, one entry per status and reason with the paths sharing them, and via says which of the two did the work. importedByTheScan names what the editor's scan imported first, and alsoImported, on a reimport of one resourcePath, the others it imported. wroteInProject names, by source, what an import wrote into the project itself rather than under .godot, such as the .translation a CSV gives each language, which version control sees and internationalization/locale/translations names. The import gives every script without a .uid sidecar one, as the editor's scan does, and uidsWritten names those scripts, counted per addon under uidsWrittenInAddons for the ones inside an addon. When nothing needed reimporting, the two lists are empty, a note says so, and there is no via. A whole-project reimport also answers missingSource, the .import files whose source is not beside them, empty when there are none, even when nothing needed reimporting; one resourcePath leaves it out. stillImporting is an editor that had not finished within timeoutMs.",
|
|
16791
16881
|
parameters: {
|
|
16792
16882
|
projectPath: PROJECT_PATH,
|
|
16793
16883
|
resourcePath: { ...RESOURCE_PATH, ops: ["status", "options", "set_options", "uid", "reimport"] },
|
|
@@ -16849,7 +16939,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
16849
16939
|
},
|
|
16850
16940
|
refresh_classes: {
|
|
16851
16941
|
effect: "destructive",
|
|
16852
|
-
summary: 'rewrite .godot/global_script_class_cache.cfg from the class_name declarations on disk. That misses the list a running editor loaded, so "added: []" means the file was already right, not that nothing is wrong: unseenByEditor names a class the editor open on this project cannot resolve, and heldBehindInEditor one it holds compiled from an older text of its file. lostSinceLastRebuild names a class the cache held after the last rebuild and lost before this one: the editor wrote the file without it, on a save or a scan, and will again until restarted. staleInThisEngine names a class the rebuild added, unknown to the autoloads its own engine compiles afterwards, and autoloadsOnTheRebuiltList what a second engine on that list reports of them',
|
|
16942
|
+
summary: 'rewrite .godot/global_script_class_cache.cfg from the class_name declarations on disk. That misses the list a running editor loaded, so "added: []" means the file was already right, not that nothing is wrong: unseenByEditor names a class the editor open on this project cannot resolve, and heldBehindInEditor one it holds compiled from an older text of its file, with heldBehindUnchecked saying why when the editor did not say. lostSinceLastRebuild names a class the cache held after the last rebuild and lost before this one: the editor wrote the file without it, on a save or a scan, and will again until restarted. staleInThisEngine names a class the rebuild added, unknown to the autoloads its own engine compiles afterwards, and autoloadsOnTheRebuiltList what a second engine on that list reports of them',
|
|
16853
16943
|
requires: []
|
|
16854
16944
|
}
|
|
16855
16945
|
}
|
|
@@ -16857,7 +16947,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
16857
16947
|
{
|
|
16858
16948
|
name: "project_export",
|
|
16859
16949
|
title: "Export",
|
|
16860
|
-
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; 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 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.",
|
|
16950
|
+
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 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.",
|
|
16861
16951
|
parameters: {
|
|
16862
16952
|
projectPath: PROJECT_PATH,
|
|
16863
16953
|
preset: {
|
|
@@ -16941,13 +17031,13 @@ var init_tool_definitions = __esm(() => {
|
|
|
16941
17031
|
title: "Run tests",
|
|
16942
17032
|
effect: "additive",
|
|
16943
17033
|
description: "Runs the project's gdUnit4 tests and answers with every case that did not pass: where it is, and what the assertion said. Each entry under failed carries its first report as message and detail, and, when it has more than one, its reports under reports in the order the case met them: gdUnit4 goes on past a failed assertion, and a case can fail several and then stop on a runtime error, which makes its status error. Identical reports fold into one with times, at most twenty different ones are kept (reportsLeftOut counts the rest), and past about a megabyte the largest cases keep only their first message (failedWithoutDetail). failures counts the cases that failed an assertion and errors the cases that hit an error, so such a case counts in both. Suites where everything passed are counted, not listed, and an engine message keeps the frames above gdUnit4, not the twenty inside it; identical engine messages come back once under engineEntries, with times saying how often they were printed, and with script, line and function for the project script one points at, as editor_output's entries have. The class list is rebuilt first, so a suite written a moment ago is found, and the rebuild's answer is under classes. What changed on disk since it was imported is then imported before any suite runs, and named under importedFirst. A suite it ran with no .uid beside it is named under uidsMissing, with uidsNote. On Windows and Linux the run gets a user:// of its own, away from a player's saves; on macOS the engine reads user:// off HOME, so it writes where the player keeps theirs, and savesNote says so. The run is headless unless a suite in it needs a window as gdharness test reads it, and then has one, on a desktop of its own on Windows. A run that found nothing to run is never called a pass, and names the path it looked in. A script that does not load stops gdUnit4 before any suite runs: its errors come back in full under scriptErrors, and the scripts that failed only because one they depend on did are listed by path under failedThroughDependency. When they failed on a class whose own script has a parser error, which gdUnit4 never names, that script is checked by the engine and its error comes first under scriptErrors, with the class it declares under declares, and the errors a script has only because that class did not resolve, which the engine reads as Variant, are kept apart under followFromUnresolved. An autoload that does not compile stops the run at once, its errors listed the same way. A client sending a progress token is told as each suite finishes, and at least every twenty seconds. A run that ends without a report, at its timeout or otherwise, names the suites it finished under suitesFinished, the failing ones with their failed cases under suitesFailing, and the one it was in under suiteRunning. When a client cuts a run off, that is kept in the project and the next project_test there carries it under previousRunCut. A run where nothing failed but orphan nodes were left comes back under warnings, with the count per suite: gdUnit4 decides its verdict on those and keeps them out of its report, so they are read off what it printed. A run whose every case passed is still not called passed when it printed a script error that no case failed on: gdUnit4 fails a case on the script errors its logger sees, and it cannot see a stack overflow, so the cases pass on whatever the faulted calls returned. Those errors come back under uncaughtScriptErrors, and under engineEntries by index with detailUnder rather than with their backtrace a second time; a backtrace that repeats, as a recursion's does, has each repeated frame or cycle of frames written once with the frames it covers and how many times. One raised inside assert_error(...).is_runtime_error is the test's own and is not listed there, and none are when the project turns off gdUnit4's report/godot/script_error setting; a suite declares them all the same. Needs gdUnit4 under addons/gdUnit4.",
|
|
16944
|
-
answer: "passed is the verdict to read. exitCode is the engine's own exit, gdUnit4's code for what it saw (100 a case failed, 101 only warnings, 105 script errors it detected), and is 0 beside passed false when the run is failed for something gdUnit4 does not judge, such as an engine error no suite declared. time is gdUnit4's own sum of the seconds its cases took, from its report. tookMs is the whole call in milliseconds, from the class rebuild to the engine's exit, which is what a caller waits for, and tookMsBy splits it into the class rebuild (classes), the import after it (import) and the engine running the suites (engine), each with any wait for an engine slot or the editor's scan in it. The run is judged as gdharness test judges it: undeclaredErrors names each engine error that no suite declared in its GDHARNESS_EXPECTED_ERRORS constant, and each engine warning a suite printed and did not declare in its GDHARNESS_EXPECTED_WARNINGS, marked warning true, with the suite and the case that printed it, and declaredNotPrinted each declared error or warning its case did not print. gdUnit4 does not fail a case on push_error or push_warning, so a case that printed one undeclared is in neither failed nor errors: it is named here, and the run is failed for it. A declared text must be the whole line after ERROR: or WARNING: and its space, so a longer one its case printed holding the text is named under printedInstead. Either fails the run, and each suite holding one is listed with its count. leakedAtExit holds the engine's lines saying it exited still holding objects, resources, memory pages or a server's RIDs, which fail the run too, and the note names any script of the project Godot itself never frees and, on a run with engineArgs [\"--verbose\"], what the engine held. engineErrors counts every engine error the run printed but those a suite declared. orphans totals the orphan nodes gdUnit4 counted, and each suite that left some has its count, and a warning saying how to free them, under warnings, with left naming each case that left some (before or after for one of the suite's hooks, or the one value \"before or after\" where no case began and the two cannot be told apart) and the nodes, by class, name and script. suites lists only the suites with something to say (a case that failed, erred or was skipped, a hook that failed, orphans, or an error undeclared or declared and not printed), and suitesPassed counts the rest. A before() or after() that failed comes back under hookFailures with its suite, line and whole message; failures and errors count cases and leave it out, so the verdict names it as failed hooks, and the cases after a failed before() still run and are counted. Under classes, the classes each addon declares are counted under addedInAddons and changedInAddons rather than named, and a class the rebuild puts back that the cache had after the last rebuild is named under classes.lostSinceLastRebuild, which is the editor writing its shorter list over the file on every save until restarted. A suite needs a window when it declares const GDHARNESS_NEEDS_WINDOW: bool = true, or calls scene_runner and declares nothing; a run holding one has a window, at the size project.godot gives its viewport and with no sound, and windowed is true and windowNote names those suites and any saying it runs headless that shared the window. On a machine with no display such a run is headless, windowed is false, and windowNote says so. " + IMPORTED_FIRST,
|
|
17034
|
+
answer: "passed is the verdict to read. exitCode is the engine's own exit, gdUnit4's code for what it saw (100 a case failed, 101 only warnings, 105 script errors it detected), and is 0 beside passed false when the run is failed for something gdUnit4 does not judge, such as an engine error no suite declared. time is gdUnit4's own sum of the seconds its cases took, from its report. tookMs is the whole call in milliseconds, from the class rebuild to the engine's exit, which is what a caller waits for, and tookMsBy splits it into the class rebuild (classes), the import after it (import) and the engine running the suites (engine), each with any wait for an engine slot or the editor's scan in it; a call that waited a second or more for slots in all is answered with an engine_slot_wait block giving waitedMs and who held them. The run is judged as gdharness test judges it: undeclaredErrors names each engine error that no suite declared in its GDHARNESS_EXPECTED_ERRORS constant, and each engine warning a suite printed and did not declare in its GDHARNESS_EXPECTED_WARNINGS, marked warning true, with the suite and the case that printed it, and declaredNotPrinted each declared error or warning its case did not print. gdUnit4 does not fail a case on push_error or push_warning, so a case that printed one undeclared is in neither failed nor errors: it is named here, and the run is failed for it. A declared text must be the whole line after ERROR: or WARNING: and its space, so a longer one its case printed holding the text is named under printedInstead. Either fails the run, and each suite holding one is listed with its count. leakedAtExit holds the engine's lines saying it exited still holding objects, resources, memory pages or a server's RIDs, which fail the run too, and the note names any script of the project Godot itself never frees and, on a run with engineArgs [\"--verbose\"], what the engine held. engineErrors counts every engine error the run printed but those a suite declared. orphans totals the orphan nodes gdUnit4 counted, and each suite that left some has its count, and a warning saying how to free them, under warnings, with left naming each case that left some (before or after for one of the suite's hooks, or the one value \"before or after\" where no case began and the two cannot be told apart) and the nodes, by class, name and script. suites lists only the suites with something to say (a case that failed, erred or was skipped, a hook that failed, orphans, or an error undeclared or declared and not printed), and suitesPassed counts the rest. A before() or after() that failed comes back under hookFailures with its suite, line and whole message; failures and errors count cases and leave it out, so the verdict names it as failed hooks, and the cases after a failed before() still run and are counted. Under classes, the classes each addon declares are counted under addedInAddons and changedInAddons rather than named, and a class the rebuild puts back that the cache had after the last rebuild is named under classes.lostSinceLastRebuild, which is the editor writing its shorter list over the file on every save until restarted. A suite needs a window when it declares const GDHARNESS_NEEDS_WINDOW: bool = true, or calls scene_runner and declares nothing; a run holding one has a window, at the size project.godot gives its viewport and with no sound, and windowed is true and windowNote names those suites and any saying it runs headless that shared the window. On a machine with no display such a run is headless, windowed is false, and windowNote says so. " + IMPORTED_FIRST,
|
|
16945
17035
|
parameters: {
|
|
16946
17036
|
projectPath: PROJECT_PATH,
|
|
16947
17037
|
path: {
|
|
16948
17038
|
type: ["string", "array"],
|
|
16949
17039
|
items: { type: "string" },
|
|
16950
|
-
description: 'A test directory or suite file inside the project, or a list of them, all run on one engine: a named set of suites boots once rather than once per suite. An entry given twice, or a suite inside a directory also listed, runs once. An entry "suite.gd:test_name" runs that case alone, as gdharness test reads it and as tests runs it, so it cannot share the list with a whole suite or a directory. An entry that is not there is left out and named under missing, the rest run, and such a run is never called passed; when no entry is there the run is refused before the engine starts, naming each one. A script named that declares no test_ function at the top level is refused the same way, and so is a directory holding no suite. A script that declares test_ functions and does not extend GdUnitTestSuite, which gdUnit4 never runs and never mentions, is refused when named, and under a directory run whole it is named under notSuites and the run is not called passed. Default tests and test, those the project has, which is where gdharness test looks.'
|
|
17040
|
+
description: 'A test directory or suite file inside the project, or a list of them, all run on one engine: a named set of suites boots once rather than once per suite. An entry given twice, or a suite inside a directory also listed, runs once. An entry "suite.gd:test_name" runs that case alone, as gdharness test reads it and as tests runs it, so it cannot share the list with a whole suite or a directory. An entry that is not there is left out and named under missing, the rest run, and such a run is never called passed; when no entry is there the run is refused before the engine starts, naming each one. A script named that declares no test_ function at the top level is refused the same way, and so is a directory holding no suite. A script that declares test_ functions and does not extend GdUnitTestSuite, which gdUnit4 never runs and never mentions, is refused when named, and under a directory run whole it is named under notSuites and the run is not called passed. A case declared there that gdUnit4 never ran, in a suite that passed, comes back under testsNotRun, and a row it skipped for data that does not fit the case under rowsMismatched with the reason gdUnit4 gave; neither run is called passed. Default tests and test, those the project has, which is where gdharness test looks.'
|
|
16951
17041
|
},
|
|
16952
17042
|
ignore: {
|
|
16953
17043
|
type: "array",
|
|
@@ -17476,7 +17566,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
17476
17566
|
name: "script_diagnostics",
|
|
17477
17567
|
title: "Script diagnostics",
|
|
17478
17568
|
effect: "read",
|
|
17479
|
-
description: "Errors and warnings for a script, or for several, from the editor's language server, and whether each is clean. With no editor of this project open, so no language server of it to ask, a short headless engine compiles the scripts instead and the answer says checkedBy: engine rather than language server: every error that stops a script compiling, up to its first syntax error, with its line and no column (a
|
|
17569
|
+
description: "Errors and warnings for a script, or for several, from the editor's language server, and whether each is clean. With no editor of this project open, so no language server of it to ask, a short headless engine compiles the scripts instead and the answer says checkedBy: engine rather than language server: every error that stops a script compiling, up to its first syntax error, with its line and no column (a method or property another class lacks is not one, since GDScript checks a method only on self and a property only named bare: the object may be a subclass that has it, so it fails at run time instead), dependenciesWithErrors naming the other scripts that failed while it loaded, typesMissingFromTheClassCache naming a class the project declares that the engine could not resolve because the class cache lacks it, with staleAnalysis saying what rewrites the cache, and the warnings at the levels the project sets, which a second engine reports by raising each warning set to warn as an error for that run only, each at its line with no column, warnings being null when that engine could not answer; a script with a syntax error is checked for no warnings until it parses. Of several scripts, a language server that stops answering partway leaves the rest to the engine, and checkedBy then says language server, then engine, with checkedByLanguageServer counting the scripts it answered. Each diagnostic carries its severity (error or warning), its message, and where it is as the editor shows it: line and column counted from 1, and endLine and endColumn just past its end. Diagnostics are checked against the project's own files, and the two that the files disprove are named rather than passed on: a member the class cache's file declares, or a project class it extends does, a method, property, constant, static function or enum member, comes back under contradictedByTheFile with the script declaring it, and so does one a diagnostic names alone as an external class member, read against the class it is looked up on in the line it is on; and a class this project declares that the diagnostic could not resolve comes back under typesTheEditorHasNotLoaded, with inTheClassCache saying whether a launched game would resolve it. staleAnalysis then says what to do, and for both states it is editor_rescan first: it asks the editor already running, starts nothing, and has cleared each in every reproduction measured. Two exceptions are named when they apply. For an enum member, constant or static function of a global class the reload comes first: in the one project that has reproduced a stale enum member, editor_rescan with reloadScript on the declaring script cleared it and a plain rescan did not. And an editor whose last scan wrote the class cache shorter than the file holds a list behind the files and writes it on every scan, so on that editor the rescan loads nothing and staleAnalysis says editor_launch restart instead. What follows differs: for a stale analysed type, editor_rescan with reloadScript recompiles the held copy and editor_launch restart is the last resort that costs a window; for a class missing from the cache, project_import refresh_classes rewrites the cache from disk at the cost of a short headless engine, which matters beside a running bench.",
|
|
17480
17570
|
parameters: {
|
|
17481
17571
|
projectPath: PROJECT_PATH,
|
|
17482
17572
|
scriptPath: {
|
|
@@ -17863,7 +17953,8 @@ var init_tool_definitions = __esm(() => {
|
|
|
17863
17953
|
name: "editor_rescan",
|
|
17864
17954
|
title: "Rescan the project",
|
|
17865
17955
|
effect: "additive",
|
|
17866
|
-
description: "Makes the running editor scan the project filesystem, so files written outside it are picked up. A scan or an import the editor is already running is waited out first rather than scanned over, which would start a second import over it.
|
|
17956
|
+
description: "Makes the running editor scan the project filesystem, so files written outside it are picked up. A scan or an import the editor is already running is waited out first rather than scanned over, which would start a second import over it. The scan is a change-detecting walk rather than an unconditional reparse, so a file another engine has already imported reads as settled and the walk does not look inside it: its class_name then stays out of the list the editor resolves against, however many times you scan. Any class in that state is named under unseenByEditor, which is what no check on disk can see, since the declaration and the cache are both correct there and only the editor disagrees. The cure is this call on its own, with no change to the declaring script, measured against a real editor on three platforms. editor_launch restart also does it and costs a window, and project_import refresh_classes does not: it rewrites the cache and does not touch what the editor is holding. The walk also passes over a file whose .uid alone changed, so the editor keeps the old UID and every engine reading its cache warns of a duplicate; before scanning, each file whose .uid names a UID the editor does not hold for it is read again and named under uidsReread, and files on disk naming one UID between them are named under uidsDuplicatedOnDisk, which reading again cannot settle. A class the scan brings in is named under broughtIn, and every script naming it is reloaded in the editor and named under dependentsReloaded: what the editor compiled from them while it could not see the class stays compiled that way after the scan, and a script extending a new base class went on reporting \"Could not find base class\" until reloaded. One that would not reload is named under dependentsNotReloaded and the call is not ok, as it is not when the script named in reloadScript was not reloaded. A script that fails to compile is tried again once the scripts it is compiled against that the editor holds behind their files are reloaded, which are named under reloadedFirst. An editor importing answers nothing until the import is over, and a hidden one imports on the thread that answers, so a large addon install can leave the rescan itself unanswered: that is waited for as any busy editor is, within timeoutMs, and when the wait runs out first the answer is stillWorking. The classes the editor could not see before that scan are then noted in the project, and the next editor_rescan of the same editor, from any server, names them under broughtIn and reloads what names them, which it could not otherwise know to do, since by then the editor sees them. A scan writes .godot/global_script_class_cache.cfg from the list the editor is holding, so a class the editor cannot resolve goes out of that file with it. That is not a reason to refuse the scan, because on a class the editor has merely not walked yet the scan is the cure; what the answer does instead is name the loss under cacheLost and rebuild the cache from the files, naming what came back under cacheRestored, so no fresh engine, CI run or clone inherits the short file. An editor that lost classes is still holding the short list, so the note says to restart it before scanning again. The other direction is guarded the same way: a class the editor still holds for a script that was renamed or deleted comes back into the cache at a path that is not there, and the next engine to read it fails on \"Could not parse global class\" in whichever correct script shares the bare name, so the cache is rebuilt without it and the answer names it under cacheDropped; the editor goes on holding it until it is restarted, and every scan until then ends in that rebuild. A script or shader written outside the editor has no .uid sidecar until something imports it, and the scan writes one beside it, which a project that commits sidecars needs before the commit. Needs the editor connected.",
|
|
17957
|
+
answer: "waitedMs is the whole call, and waitedForEditorScanMs, given only when a scan or an import was already running, the part spent waiting it out. waitedForEditorAnswerMs, given when an idle editor took a second or more to say so, is how long that took: such an editor is busy on the thread that answers with an earlier request rather than scanning, so the time is added to timeoutMs rather than taken from it, and the note says so. stillWorking is true when a scan was still running at the end of the wait; the scan the call started is looked at once even when the wait has run out, so stillWorking is never said of a scan nothing looked at.",
|
|
17867
17958
|
parameters: {
|
|
17868
17959
|
projectPath: PROJECT_PATH,
|
|
17869
17960
|
timeoutMs: {
|
|
@@ -18521,7 +18612,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
18521
18612
|
{
|
|
18522
18613
|
name: "debug_state",
|
|
18523
18614
|
title: "Debugger state",
|
|
18524
|
-
description: "Where the debugged game is stopped: the stack trace, what is in scope at a frame with the values, or the debugger's console output so far, its last thousand lines, with any earlier ones counted under notShown. For a game this server started the output is what the game printed; the errors and warnings it reported, with where each happened, are in editor_output. For a game this server started, its keeper's debugger answers: each frame names its script as the project spells it under script and on this machine under path, and held says which thread stopped and why. For a game the editor plays, the editor's debug adapter answers. A stop is reported by the editor's adapter only to the sessions connected when it happened, so a server that connected afterwards, which is every server after a reconnect, is shown a thread and no frames about a game still sitting at its breakpoint. That server asks the runtime instead: a held game accepts a connection and never answers, and the refusal then says held rather than running, and that the stack cannot be read from here. debug_control continue lets it go, and the next stop is one this session is told about, with its stack. A function that awaited is resumed with no caller below it, since the call that started it returned at the await, so its frame is the only one. The variables give an object as its class and instance id only, and evaluate reads into it: an expression worked out by the game at a frame, with the frame's locals, the globals and every global class in scope and the frame's instance as self, such as wave.spawned or wave.spawned.size(). The game runs what the expression calls, so a call that changes something changes the game. A frame with no instance, a static function's called on its class, is refused, since the engine lets the game go on rather than evaluate there; the frame below it has one. The compiler's own locals, named with @ such as a for loop's @counter_pos, are left out.",
|
|
18615
|
+
description: "Where the debugged game is stopped: the stack trace, what is in scope at a frame with the values, or the debugger's console output so far, its last thousand lines, with any earlier ones counted under notShown. For a game this server started the output is what the game printed; the errors and warnings it reported, with where each happened, are in editor_output, which also has what it printed once it has ended, as its debugger ends with it. For a game this server started, its keeper's debugger answers: each frame names its script as the project spells it under script and on this machine under path, and held says which thread stopped and why. For a game the editor plays, the editor's debug adapter answers. A stop is reported by the editor's adapter only to the sessions connected when it happened, so a server that connected afterwards, which is every server after a reconnect, is shown a thread and no frames about a game still sitting at its breakpoint. That server asks the runtime instead: a held game accepts a connection and never answers, and the refusal then says held rather than running, and that the stack cannot be read from here. debug_control continue lets it go, and the next stop is one this session is told about, with its stack. A function that awaited is resumed with no caller below it, since the call that started it returned at the await, so its frame is the only one. The variables give an object as its class and instance id only, and evaluate reads into it: an expression worked out by the game at a frame, with the frame's locals, the globals and every global class in scope and the frame's instance as self, such as wave.spawned or wave.spawned.size(). The game runs what the expression calls, so a call that changes something changes the game. A frame with no instance, a static function's called on its class, is refused, since the engine lets the game go on rather than evaluate there; the frame below it has one. The compiler's own locals, named with @ such as a for loop's @counter_pos, are left out.",
|
|
18525
18616
|
parameters: {
|
|
18526
18617
|
frameId: {
|
|
18527
18618
|
type: "number",
|
|
@@ -18662,9 +18753,9 @@ function whatItCanChange(tool) {
|
|
|
18662
18753
|
if (destroying.length === 0) {
|
|
18663
18754
|
return "Adds or starts things, and overwrites and removes nothing itself.";
|
|
18664
18755
|
}
|
|
18665
|
-
return `Can overwrite, remove or end what is there, through ${
|
|
18756
|
+
return `Can overwrite, remove or end what is there, through ${listed3(destroying)}.`;
|
|
18666
18757
|
}
|
|
18667
|
-
function
|
|
18758
|
+
function listed3(items) {
|
|
18668
18759
|
const last = items.at(-1) ?? "";
|
|
18669
18760
|
return items.length === 1 ? last : `${items.slice(0, -1).join(", ")} and ${last}`;
|
|
18670
18761
|
}
|
|
@@ -18722,7 +18813,7 @@ var init_tool_reference = __esm(() => {
|
|
|
18722
18813
|
});
|
|
18723
18814
|
|
|
18724
18815
|
// src/suite-plan.ts
|
|
18725
|
-
import { existsSync as existsSync22, mkdirSync as mkdirSync9, readFileSync as
|
|
18816
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync9, readFileSync as readFileSync21 } from "node:fs";
|
|
18726
18817
|
import { dirname as dirname11, join as join25, posix as posix3 } from "node:path";
|
|
18727
18818
|
function within(path, folder) {
|
|
18728
18819
|
return path === folder || path.startsWith(`${folder}/`);
|
|
@@ -18739,7 +18830,7 @@ class ProjectScripts {
|
|
|
18739
18830
|
this.projectPath = projectPath;
|
|
18740
18831
|
let settings = {};
|
|
18741
18832
|
try {
|
|
18742
|
-
settings = parseProjectGodot(
|
|
18833
|
+
settings = parseProjectGodot(readFileSync21(join25(projectPath, "project.godot"), "utf8"))["gdharness"] ?? {};
|
|
18743
18834
|
} catch {}
|
|
18744
18835
|
const [section, key] = [NOT_SEARCHED_SETTING, GUESS_WINDOW_SETTING].map((setting) => setting.slice("gdharness/".length));
|
|
18745
18836
|
const listed = settings[section ?? ""];
|
|
@@ -18854,7 +18945,7 @@ class ProjectScripts {
|
|
|
18854
18945
|
}
|
|
18855
18946
|
function readTimes(file) {
|
|
18856
18947
|
try {
|
|
18857
|
-
const parsed = JSON.parse(
|
|
18948
|
+
const parsed = JSON.parse(readFileSync21(file, "utf8"));
|
|
18858
18949
|
return typeof parsed === "object" && parsed !== null ? parsed : {};
|
|
18859
18950
|
} catch {
|
|
18860
18951
|
return {};
|
|
@@ -19137,7 +19228,7 @@ function viewportOf(projectPath) {
|
|
|
19137
19228
|
if (!existsSync22(file)) {
|
|
19138
19229
|
return null;
|
|
19139
19230
|
}
|
|
19140
|
-
const text =
|
|
19231
|
+
const text = readFileSync21(file, "utf8");
|
|
19141
19232
|
const width = /^window\/size\/viewport_width\s*=\s*(\d+)/m.exec(text)?.[1];
|
|
19142
19233
|
const height = /^window\/size\/viewport_height\s*=\s*(\d+)/m.exec(text)?.[1];
|
|
19143
19234
|
return width === undefined || height === undefined ? null : { width: Number(width), height: Number(height) };
|
|
@@ -40756,13 +40847,13 @@ var init_stdio = __esm(() => {
|
|
|
40756
40847
|
});
|
|
40757
40848
|
|
|
40758
40849
|
// src/autoload-failure.ts
|
|
40759
|
-
import { existsSync as existsSync24, readFileSync as
|
|
40850
|
+
import { existsSync as existsSync24, readFileSync as readFileSync24 } from "node:fs";
|
|
40760
40851
|
import { join as join28 } from "node:path";
|
|
40761
40852
|
function scriptsAutoloaded(projectPath) {
|
|
40762
40853
|
const scripts = new Map;
|
|
40763
40854
|
let settings;
|
|
40764
40855
|
try {
|
|
40765
|
-
settings = parseProjectGodot(
|
|
40856
|
+
settings = parseProjectGodot(readFileSync24(join28(projectPath, "project.godot"), "utf8"));
|
|
40766
40857
|
} catch {
|
|
40767
40858
|
return scripts;
|
|
40768
40859
|
}
|
|
@@ -40776,7 +40867,7 @@ function scriptsAutoloaded(projectPath) {
|
|
|
40776
40867
|
continue;
|
|
40777
40868
|
}
|
|
40778
40869
|
try {
|
|
40779
|
-
for (const named of
|
|
40870
|
+
for (const named of readFileSync24(scene, "utf8").matchAll(/^\[ext_resource\b[^\]]*\btype="Script"[^\]]*\bpath="(res:\/\/[^"]+)"/gm)) {
|
|
40780
40871
|
scripts.set(named[1] ?? "", name);
|
|
40781
40872
|
}
|
|
40782
40873
|
} catch {}
|
|
@@ -40795,7 +40886,7 @@ var init_autoload_failure = __esm(() => {
|
|
|
40795
40886
|
});
|
|
40796
40887
|
|
|
40797
40888
|
// src/runtime-client.ts
|
|
40798
|
-
import { existsSync as existsSync25, readdirSync as readdirSync15, readFileSync as
|
|
40889
|
+
import { existsSync as existsSync25, readdirSync as readdirSync15, readFileSync as readFileSync25, statSync as statSync15, unlinkSync as unlinkSync3 } from "node:fs";
|
|
40799
40890
|
import { createConnection as createConnection2 } from "node:net";
|
|
40800
40891
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
40801
40892
|
import { dirname as dirname14, join as join29, resolve as resolve11 } from "node:path";
|
|
@@ -40850,7 +40941,7 @@ function reportAlreadyInTranscript(transcript, report) {
|
|
|
40850
40941
|
function parseAnnouncement(file, pid) {
|
|
40851
40942
|
let fields;
|
|
40852
40943
|
try {
|
|
40853
|
-
fields = asParams(JSON.parse(
|
|
40944
|
+
fields = asParams(JSON.parse(readFileSync25(file, "utf8")));
|
|
40854
40945
|
} catch {
|
|
40855
40946
|
return { kind: "rubbish" };
|
|
40856
40947
|
}
|
|
@@ -40922,7 +41013,7 @@ function discoverRuntimes(directories = runtimeDirectories()) {
|
|
|
40922
41013
|
function wentAway(file, pid) {
|
|
40923
41014
|
let project = "";
|
|
40924
41015
|
try {
|
|
40925
|
-
const fields = asParams(JSON.parse(
|
|
41016
|
+
const fields = asParams(JSON.parse(readFileSync25(file, "utf8")));
|
|
40926
41017
|
project = readString(readParams(fields, "project") ?? {}, "path") ?? "";
|
|
40927
41018
|
} catch {
|
|
40928
41019
|
return;
|
|
@@ -41437,14 +41528,14 @@ var init_runtime_client = __esm(() => {
|
|
|
41437
41528
|
});
|
|
41438
41529
|
|
|
41439
41530
|
// src/boot-note.ts
|
|
41440
|
-
import { mkdirSync as mkdirSync11, readFileSync as
|
|
41531
|
+
import { mkdirSync as mkdirSync11, readFileSync as readFileSync26, writeFileSync as writeFileSync13 } from "node:fs";
|
|
41441
41532
|
import { dirname as dirname15, join as join30 } from "node:path";
|
|
41442
41533
|
function bootNotePath(projectPath) {
|
|
41443
41534
|
return join30(projectPath, ".godot", "gdharness-boot.json");
|
|
41444
41535
|
}
|
|
41445
41536
|
function readScenes(projectPath) {
|
|
41446
41537
|
try {
|
|
41447
|
-
return asParams(asParams(JSON.parse(
|
|
41538
|
+
return asParams(asParams(JSON.parse(readFileSync26(bootNotePath(projectPath), "utf8")))["scenes"]);
|
|
41448
41539
|
} catch {
|
|
41449
41540
|
return {};
|
|
41450
41541
|
}
|
|
@@ -41486,7 +41577,7 @@ var init_boot_note = __esm(() => {
|
|
|
41486
41577
|
});
|
|
41487
41578
|
|
|
41488
41579
|
// src/breakpoint-note.ts
|
|
41489
|
-
import { mkdirSync as mkdirSync12, readFileSync as
|
|
41580
|
+
import { mkdirSync as mkdirSync12, readFileSync as readFileSync27, rmSync as rmSync13, writeFileSync as writeFileSync14 } from "node:fs";
|
|
41490
41581
|
import { dirname as dirname16, isAbsolute as isAbsolute7, join as join31, relative as relative6 } from "node:path";
|
|
41491
41582
|
function breakpointNotePath(projectPath) {
|
|
41492
41583
|
return join31(projectPath, ".godot", "gdharness-breakpoints.json");
|
|
@@ -41515,7 +41606,7 @@ function writeBreakpointNote(projectPath, held) {
|
|
|
41515
41606
|
}
|
|
41516
41607
|
function readBreakpointNote(projectPath) {
|
|
41517
41608
|
try {
|
|
41518
|
-
const parsed = JSON.parse(
|
|
41609
|
+
const parsed = JSON.parse(readFileSync27(breakpointNotePath(projectPath), "utf8"));
|
|
41519
41610
|
if (typeof parsed !== "object" || parsed === null || !Array.isArray(parsed.breakpoints)) {
|
|
41520
41611
|
return [];
|
|
41521
41612
|
}
|
|
@@ -41548,14 +41639,14 @@ var init_breakpoint_note = __esm(() => {
|
|
|
41548
41639
|
});
|
|
41549
41640
|
|
|
41550
41641
|
// src/class-note.ts
|
|
41551
|
-
import { mkdirSync as mkdirSync13, readFileSync as
|
|
41642
|
+
import { mkdirSync as mkdirSync13, readFileSync as readFileSync28 } from "node:fs";
|
|
41552
41643
|
import { dirname as dirname17, join as join32 } from "node:path";
|
|
41553
41644
|
function classNotePath(projectPath) {
|
|
41554
41645
|
return join32(projectPath, ".godot", "gdharness-classes.json");
|
|
41555
41646
|
}
|
|
41556
41647
|
function readClassNote(projectPath) {
|
|
41557
41648
|
try {
|
|
41558
|
-
const fields = asParams(JSON.parse(
|
|
41649
|
+
const fields = asParams(JSON.parse(readFileSync28(classNotePath(projectPath), "utf8")));
|
|
41559
41650
|
const rebuiltWith = readArray(fields, "rebuiltWith");
|
|
41560
41651
|
if (rebuiltWith === undefined || !rebuiltWith.every((name) => typeof name === "string")) {
|
|
41561
41652
|
return null;
|
|
@@ -41597,7 +41688,7 @@ var init_class_note = __esm(() => {
|
|
|
41597
41688
|
});
|
|
41598
41689
|
|
|
41599
41690
|
// src/config-pin.ts
|
|
41600
|
-
import { existsSync as existsSync26, readFileSync as
|
|
41691
|
+
import { existsSync as existsSync26, readFileSync as readFileSync29 } from "node:fs";
|
|
41601
41692
|
import { join as join33 } from "node:path";
|
|
41602
41693
|
function versionsNamedInConfig(projectPath) {
|
|
41603
41694
|
const config = join33(projectPath, ".mcp.json");
|
|
@@ -41606,7 +41697,7 @@ function versionsNamedInConfig(projectPath) {
|
|
|
41606
41697
|
}
|
|
41607
41698
|
let text;
|
|
41608
41699
|
try {
|
|
41609
|
-
text =
|
|
41700
|
+
text = readFileSync29(config, "utf8");
|
|
41610
41701
|
JSON.parse(text);
|
|
41611
41702
|
} catch {
|
|
41612
41703
|
return [];
|
|
@@ -41627,7 +41718,7 @@ var init_config_pin = __esm(() => {
|
|
|
41627
41718
|
});
|
|
41628
41719
|
|
|
41629
41720
|
// src/cut-test-run.ts
|
|
41630
|
-
import { existsSync as existsSync27, mkdirSync as mkdirSync14, readFileSync as
|
|
41721
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync14, readFileSync as readFileSync30, rmSync as rmSync14, writeFileSync as writeFileSync15 } from "node:fs";
|
|
41631
41722
|
import { dirname as dirname18, join as join34 } from "node:path";
|
|
41632
41723
|
function keptAt(projectPath) {
|
|
41633
41724
|
return join34(projectPath, ".godot", "gdharness-reports", "cut-run.json");
|
|
@@ -41646,7 +41737,7 @@ function takeCutTestRun(projectPath) {
|
|
|
41646
41737
|
return null;
|
|
41647
41738
|
}
|
|
41648
41739
|
try {
|
|
41649
|
-
const run = JSON.parse(
|
|
41740
|
+
const run = JSON.parse(readFileSync30(path, "utf8"));
|
|
41650
41741
|
rmSync14(path, { force: true });
|
|
41651
41742
|
return typeof run.cutAt === "string" && Array.isArray(run.paths) && run.paths.every((path) => typeof path === "string") ? run : null;
|
|
41652
41743
|
} catch {
|
|
@@ -42382,7 +42473,7 @@ import {
|
|
|
42382
42473
|
existsSync as existsSync28,
|
|
42383
42474
|
mkdirSync as mkdirSync15,
|
|
42384
42475
|
openSync as openSync4,
|
|
42385
|
-
readFileSync as
|
|
42476
|
+
readFileSync as readFileSync31,
|
|
42386
42477
|
readSync as readSync2,
|
|
42387
42478
|
rmSync as rmSync15,
|
|
42388
42479
|
statSync as statSync16,
|
|
@@ -42397,7 +42488,7 @@ function editorLogNotePath(projectPath) {
|
|
|
42397
42488
|
}
|
|
42398
42489
|
function readEditorLogNote(projectPath) {
|
|
42399
42490
|
try {
|
|
42400
|
-
const fields = asParams(JSON.parse(
|
|
42491
|
+
const fields = asParams(JSON.parse(readFileSync31(editorLogNotePath(projectPath), "utf8")));
|
|
42401
42492
|
const pid = readNumber(fields, "pid");
|
|
42402
42493
|
const startedAt = readString(fields, "startedAt");
|
|
42403
42494
|
const processStartedAt = readNumber(fields, "processStartedAt");
|
|
@@ -42501,7 +42592,7 @@ function foldProgress(text) {
|
|
|
42501
42592
|
function theFirstOf(path) {
|
|
42502
42593
|
const whole = statSync16(path).size;
|
|
42503
42594
|
if (whole <= MOST_CONSOLE_BYTES) {
|
|
42504
|
-
return { text:
|
|
42595
|
+
return { text: readFileSync31(path, "utf8") };
|
|
42505
42596
|
}
|
|
42506
42597
|
const handle = openSync4(path, "r");
|
|
42507
42598
|
try {
|
|
@@ -42662,7 +42753,7 @@ var init_editor_log = __esm(() => {
|
|
|
42662
42753
|
});
|
|
42663
42754
|
|
|
42664
42755
|
// src/rename.ts
|
|
42665
|
-
import { existsSync as existsSync29, mkdirSync as mkdirSync16, readFileSync as
|
|
42756
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync16, readFileSync as readFileSync32, renameSync as renameSync3, unlinkSync as unlinkSync4, writeFileSync as writeFileSync17 } from "node:fs";
|
|
42666
42757
|
import { dirname as dirname20, posix as posix4 } from "node:path";
|
|
42667
42758
|
|
|
42668
42759
|
class Script {
|
|
@@ -43367,7 +43458,7 @@ function rewritesOf(plan, texts, move) {
|
|
|
43367
43458
|
}
|
|
43368
43459
|
function applyRewrites(rewrites) {
|
|
43369
43460
|
for (const rewrite of rewrites) {
|
|
43370
|
-
const now =
|
|
43461
|
+
const now = readFileSync32(rewrite.absolute, "utf8");
|
|
43371
43462
|
if (now !== rewrite.before) {
|
|
43372
43463
|
throw new Error(`${rewrite.path} changed on disk while the rename was being worked out; nothing was written`);
|
|
43373
43464
|
}
|
|
@@ -43457,18 +43548,18 @@ function onDiskSpelling(path) {
|
|
|
43457
43548
|
}
|
|
43458
43549
|
}
|
|
43459
43550
|
function usedAsIdentifier(scripts, name, most) {
|
|
43460
|
-
const found =
|
|
43551
|
+
const found = new Set;
|
|
43461
43552
|
for (const script of scripts.values()) {
|
|
43462
43553
|
for (const occurrence of script.occurrences(name)) {
|
|
43463
43554
|
if (occurrence.kind === "code" && !occurrence.afterDot) {
|
|
43464
|
-
found.
|
|
43465
|
-
if (found.
|
|
43466
|
-
return found;
|
|
43555
|
+
found.add(`${script.path}:${script.lines.positionOf(occurrence.offset).line + 1}`);
|
|
43556
|
+
if (found.size >= most) {
|
|
43557
|
+
return [...found];
|
|
43467
43558
|
}
|
|
43468
43559
|
}
|
|
43469
43560
|
}
|
|
43470
43561
|
}
|
|
43471
|
-
return found;
|
|
43562
|
+
return [...found];
|
|
43472
43563
|
}
|
|
43473
43564
|
function autoloadNames(texts) {
|
|
43474
43565
|
const settings = texts.find((file) => file.path === "res://project.godot");
|
|
@@ -43532,7 +43623,7 @@ async function renameSymbol(request, services) {
|
|
|
43532
43623
|
conflicts.push(`${newName} is already an autoload in project.godot`);
|
|
43533
43624
|
}
|
|
43534
43625
|
for (const place of usedAsIdentifier(scripts, newName, 10)) {
|
|
43535
|
-
conflicts.push(`${newName} is already
|
|
43626
|
+
conflicts.push(`${newName} is already used in code at ${place}`);
|
|
43536
43627
|
}
|
|
43537
43628
|
const taken = (await services.namesTaken([newName], null))[newName];
|
|
43538
43629
|
if (taken !== undefined && taken.as.length > 0) {
|
|
@@ -43935,7 +44026,7 @@ import {
|
|
|
43935
44026
|
existsSync as existsSync31,
|
|
43936
44027
|
mkdirSync as mkdirSync18,
|
|
43937
44028
|
readdirSync as readdirSync17,
|
|
43938
|
-
readFileSync as
|
|
44029
|
+
readFileSync as readFileSync33,
|
|
43939
44030
|
renameSync as renameSync4,
|
|
43940
44031
|
statSync as statSync17,
|
|
43941
44032
|
writeFileSync as writeFileSync19
|
|
@@ -44095,7 +44186,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
44095
44186
|
plan = mentionIgnored(plan, ignoredTexts(projectPath), null, [from]);
|
|
44096
44187
|
const binaries = [];
|
|
44097
44188
|
for (const path of binaryResources(projectPath)) {
|
|
44098
|
-
const bytes =
|
|
44189
|
+
const bytes = readFileSync33(join37(projectPath, path.slice("res://".length)));
|
|
44099
44190
|
const names = [...moves.keys()].find((moving) => bytes.includes(moving));
|
|
44100
44191
|
if (names !== undefined) {
|
|
44101
44192
|
binaries.push({
|
|
@@ -44156,7 +44247,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
44156
44247
|
}
|
|
44157
44248
|
function applyFileMove(outcome) {
|
|
44158
44249
|
for (const rewrite of outcome.inPlace) {
|
|
44159
|
-
if (
|
|
44250
|
+
if (readFileSync33(rewrite.absolute, "utf8") !== rewrite.before) {
|
|
44160
44251
|
throw new Error(`${rewrite.path} changed on disk while the move was being worked out; nothing was written`);
|
|
44161
44252
|
}
|
|
44162
44253
|
}
|
|
@@ -44164,7 +44255,7 @@ function applyFileMove(outcome) {
|
|
|
44164
44255
|
if (!existsSync31(file.absoluteFrom)) {
|
|
44165
44256
|
throw new Error(`${file.from} is gone from disk; nothing was written`);
|
|
44166
44257
|
}
|
|
44167
|
-
if (file.text !== null &&
|
|
44258
|
+
if (file.text !== null && readFileSync33(file.absoluteFrom, "utf8") !== file.text.before) {
|
|
44168
44259
|
throw new Error(`${file.from} changed on disk while the move was being worked out; nothing was written`);
|
|
44169
44260
|
}
|
|
44170
44261
|
if (existsSync31(file.absoluteTo) && !sameFile(file.absoluteFrom, file.absoluteTo)) {
|
|
@@ -48278,7 +48369,7 @@ var init_prompts = __esm(() => {
|
|
|
48278
48369
|
});
|
|
48279
48370
|
|
|
48280
48371
|
// src/restart-note.ts
|
|
48281
|
-
import { mkdirSync as mkdirSync20, readFileSync as
|
|
48372
|
+
import { mkdirSync as mkdirSync20, readFileSync as readFileSync34, rmSync as rmSync17, writeFileSync as writeFileSync20 } from "node:fs";
|
|
48282
48373
|
import { dirname as dirname24, join as join39 } from "node:path";
|
|
48283
48374
|
function restartNotePath(projectPath) {
|
|
48284
48375
|
return join39(projectPath, ".godot", "gdharness-restart.json");
|
|
@@ -48295,7 +48386,7 @@ function noteRestartBegun(note) {
|
|
|
48295
48386
|
}
|
|
48296
48387
|
function restartOwed(projectPath) {
|
|
48297
48388
|
try {
|
|
48298
|
-
const parsed = JSON.parse(
|
|
48389
|
+
const parsed = JSON.parse(readFileSync34(restartNotePath(projectPath), "utf8"));
|
|
48299
48390
|
if (typeof parsed !== "object" || parsed === null) {
|
|
48300
48391
|
return null;
|
|
48301
48392
|
}
|
|
@@ -48321,7 +48412,7 @@ var init_restart_note = __esm(() => {
|
|
|
48321
48412
|
|
|
48322
48413
|
// src/run-record.ts
|
|
48323
48414
|
import { createHash as createHash7 } from "node:crypto";
|
|
48324
|
-
import { mkdirSync as mkdirSync21, openSync as openSync5, readdirSync as readdirSync18, readFileSync as
|
|
48415
|
+
import { mkdirSync as mkdirSync21, openSync as openSync5, readdirSync as readdirSync18, readFileSync as readFileSync35, rmSync as rmSync18, statSync as statSync19 } from "node:fs";
|
|
48325
48416
|
import { basename as basename11, join as join40, resolve as resolve13 } from "node:path";
|
|
48326
48417
|
function runsDirectory() {
|
|
48327
48418
|
return join40(runtimeDirectory(), "runs");
|
|
@@ -48345,7 +48436,7 @@ function writeLatestRun(servedBy, latest) {
|
|
|
48345
48436
|
}
|
|
48346
48437
|
function readLatestRun(servedBy, directory = runtimeDirectory()) {
|
|
48347
48438
|
try {
|
|
48348
|
-
const fields = JSON.parse(
|
|
48439
|
+
const fields = JSON.parse(readFileSync35(latestRunPath(servedBy, directory), "utf8"));
|
|
48349
48440
|
if (typeof fields !== "object" || fields === null) {
|
|
48350
48441
|
return null;
|
|
48351
48442
|
}
|
|
@@ -48394,7 +48485,7 @@ function readEditorRunNote(projectPath) {
|
|
|
48394
48485
|
function editorNoteAt(path) {
|
|
48395
48486
|
let parsed;
|
|
48396
48487
|
try {
|
|
48397
|
-
parsed = JSON.parse(
|
|
48488
|
+
parsed = JSON.parse(readFileSync35(path, "utf8"));
|
|
48398
48489
|
} catch {
|
|
48399
48490
|
return null;
|
|
48400
48491
|
}
|
|
@@ -48444,7 +48535,7 @@ function everyRunRecord() {
|
|
|
48444
48535
|
function recordAt(path) {
|
|
48445
48536
|
let parsed;
|
|
48446
48537
|
try {
|
|
48447
|
-
parsed = JSON.parse(
|
|
48538
|
+
parsed = JSON.parse(readFileSync35(path, "utf8"));
|
|
48448
48539
|
} catch {
|
|
48449
48540
|
return null;
|
|
48450
48541
|
}
|
|
@@ -48525,7 +48616,7 @@ async function runningAs(pid) {
|
|
|
48525
48616
|
const began = await startedAt(pid, null);
|
|
48526
48617
|
const when = began === null ? {} : { startedAt: began };
|
|
48527
48618
|
if (process.platform === "linux") {
|
|
48528
|
-
const raw =
|
|
48619
|
+
const raw = readFileSync35(`/proc/${pid}/cmdline`, "utf8").replaceAll("\x00", " ").trim();
|
|
48529
48620
|
return raw === "" ? null : { kind: "commandLine", text: raw, ...when };
|
|
48530
48621
|
}
|
|
48531
48622
|
const args = (await runHidden("ps", ["-p", String(pid), "-o", "args="], { timeout: 15000 })).stdout.trim();
|
|
@@ -48721,10 +48812,10 @@ var init_run_record = __esm(() => {
|
|
|
48721
48812
|
});
|
|
48722
48813
|
|
|
48723
48814
|
// src/script-profile.ts
|
|
48724
|
-
import { readFileSync as
|
|
48815
|
+
import { readFileSync as readFileSync36 } from "node:fs";
|
|
48725
48816
|
function readProfileFile(path) {
|
|
48726
48817
|
try {
|
|
48727
|
-
const parsed = JSON.parse(
|
|
48818
|
+
const parsed = JSON.parse(readFileSync36(path, "utf8"));
|
|
48728
48819
|
return typeof parsed === "object" && typeof parsed.connected === "boolean" ? parsed : null;
|
|
48729
48820
|
} catch {
|
|
48730
48821
|
return null;
|
|
@@ -48782,7 +48873,7 @@ function writeProfileMark(path, mark) {
|
|
|
48782
48873
|
}
|
|
48783
48874
|
function readProfileMark(path) {
|
|
48784
48875
|
try {
|
|
48785
|
-
const parsed = JSON.parse(
|
|
48876
|
+
const parsed = JSON.parse(readFileSync36(path, "utf8"));
|
|
48786
48877
|
return typeof parsed === "object" && typeof parsed.totals === "object" ? parsed : null;
|
|
48787
48878
|
} catch {
|
|
48788
48879
|
return null;
|
|
@@ -49114,7 +49205,7 @@ import {
|
|
|
49114
49205
|
mkdirSync as mkdirSync23,
|
|
49115
49206
|
openSync as openSync6,
|
|
49116
49207
|
readdirSync as readdirSync19,
|
|
49117
|
-
readFileSync as
|
|
49208
|
+
readFileSync as readFileSync37,
|
|
49118
49209
|
readSync as readSync3,
|
|
49119
49210
|
realpathSync as realpathSync5,
|
|
49120
49211
|
rmdirSync as rmdirSync2,
|
|
@@ -49135,9 +49226,9 @@ function greetingWaitMs() {
|
|
|
49135
49226
|
return waitFromEnv("GDHARNESS_GREETING_WAIT_MS", 1e4);
|
|
49136
49227
|
}
|
|
49137
49228
|
function pictureToSend(pngPath, jpegPath) {
|
|
49138
|
-
const png =
|
|
49229
|
+
const png = readFileSync37(pngPath);
|
|
49139
49230
|
const beside = pngPath.replace(/\.png$/, ".jpg");
|
|
49140
|
-
const jpeg = jpegPath !== undefined && normalize2(jpegPath) === normalize2(beside) && existsSync34(beside) ?
|
|
49231
|
+
const jpeg = jpegPath !== undefined && normalize2(jpegPath) === normalize2(beside) && existsSync34(beside) ? readFileSync37(beside) : null;
|
|
49141
49232
|
const sent = jpeg !== null && jpeg.length < png.length ? jpeg : png;
|
|
49142
49233
|
return {
|
|
49143
49234
|
data: sent.toString("base64"),
|
|
@@ -49616,7 +49707,7 @@ function endedToStartThis(ended) {
|
|
|
49616
49707
|
return ` ${which} was ended to start this one; its output is no longer what editor_output answers about.`;
|
|
49617
49708
|
}
|
|
49618
49709
|
function lineNothingStopsOn(absolutePath, relativePath, line) {
|
|
49619
|
-
const text =
|
|
49710
|
+
const text = readFileSync37(absolutePath, "utf8");
|
|
49620
49711
|
const lines = text === "" ? 0 : text.split(`
|
|
49621
49712
|
`).length - (text.endsWith(`
|
|
49622
49713
|
`) ? 1 : 0);
|
|
@@ -49827,7 +49918,7 @@ function notRunNote(notRun, failFast) {
|
|
|
49827
49918
|
function presetsIn(projectPath) {
|
|
49828
49919
|
let text;
|
|
49829
49920
|
try {
|
|
49830
|
-
text =
|
|
49921
|
+
text = readFileSync37(join43(projectPath, "export_presets.cfg"), "utf8");
|
|
49831
49922
|
} catch {
|
|
49832
49923
|
return null;
|
|
49833
49924
|
}
|
|
@@ -49977,7 +50068,7 @@ function rewriteBusNamed(projectPath, from, to) {
|
|
|
49977
50068
|
const rewritten = [];
|
|
49978
50069
|
for (const file of projectFiles(projectPath, [".tscn", ".tres"])) {
|
|
49979
50070
|
const absolute = join43(projectPath, file);
|
|
49980
|
-
const lines =
|
|
50071
|
+
const lines = readFileSync37(absolute, "utf8").split(`
|
|
49981
50072
|
`);
|
|
49982
50073
|
const at = [];
|
|
49983
50074
|
const after = lines.map((line, index) => {
|
|
@@ -49996,7 +50087,7 @@ function rewriteBusNamed(projectPath, from, to) {
|
|
|
49996
50087
|
}
|
|
49997
50088
|
const namedInScripts = [];
|
|
49998
50089
|
for (const file of projectFiles(projectPath, [".gd"])) {
|
|
49999
|
-
|
|
50090
|
+
readFileSync37(join43(projectPath, file), "utf8").split(`
|
|
50000
50091
|
`).forEach((line, index) => {
|
|
50001
50092
|
if (line.includes(`"${from}"`)) {
|
|
50002
50093
|
namedInScripts.push({ file: `res://${file}`, line: index + 1, text: line.trim() });
|
|
@@ -50281,7 +50372,7 @@ function profileFrameFunctions(projectPath) {
|
|
|
50281
50372
|
let projectGodot = null;
|
|
50282
50373
|
if (projectPath !== null) {
|
|
50283
50374
|
try {
|
|
50284
|
-
projectGodot =
|
|
50375
|
+
projectGodot = readFileSync37(join43(projectPath, "project.godot"), "utf8");
|
|
50285
50376
|
} catch {}
|
|
50286
50377
|
}
|
|
50287
50378
|
return frameFunctionsFor(queuedMessagesOf(projectGodot));
|
|
@@ -50305,7 +50396,7 @@ function projectSourceOf(projectPath) {
|
|
|
50305
50396
|
let source = null;
|
|
50306
50397
|
if (inside.ok) {
|
|
50307
50398
|
try {
|
|
50308
|
-
source =
|
|
50399
|
+
source = readFileSync37(inside.absolutePath, "utf8");
|
|
50309
50400
|
} catch {}
|
|
50310
50401
|
}
|
|
50311
50402
|
read.set(script, source);
|
|
@@ -50477,7 +50568,7 @@ function foldedEntriesAnswer(log, floor = "warning") {
|
|
|
50477
50568
|
}
|
|
50478
50569
|
function gdUnitFailsOnScriptErrors(projectPath) {
|
|
50479
50570
|
try {
|
|
50480
|
-
return settingKeys(
|
|
50571
|
+
return settingKeys(readFileSync37(join43(projectPath, "project.godot"), "utf8")).get("gdunit4/report/godot/script_error") !== false;
|
|
50481
50572
|
} catch {
|
|
50482
50573
|
return true;
|
|
50483
50574
|
}
|
|
@@ -50609,7 +50700,7 @@ function engineChecked(why) {
|
|
|
50609
50700
|
return {
|
|
50610
50701
|
checkedBy: "engine",
|
|
50611
50702
|
languageServer: why,
|
|
50612
|
-
note: "No editor of this project is open to ask, so a headless engine compiled the scripts the way loading them does. It reports every error that stops a script compiling, at its line and without a column, but stops reading a script at its first syntax error, so an error after one shows once it is fixed. A second engine reports the warnings, at the levels the project sets, by raising each warning set to warn as an error for that run only, since the engine tells a warning as one only to an editor; each comes at its line without a column, and warnings is null when that engine could not answer. editor_launch with hidden: true opens this project's editor without a window, and its language server reports both with their columns."
|
|
50703
|
+
note: "No editor of this project is open to ask, so a headless engine compiled the scripts the way loading them does. It reports every error that stops a script compiling, at its line and without a column, but stops reading a script at its first syntax error, so an error after one shows once it is fixed, and so do its warnings, since a script that does not parse is not checked for any. A second engine reports the warnings, at the levels the project sets, by raising each warning set to warn as an error for that run only, since the engine tells a warning as one only to an editor; each comes at its line without a column, and warnings is null when that engine could not answer. editor_launch with hidden: true opens this project's editor without a window, and its language server reports both with their columns."
|
|
50613
50704
|
};
|
|
50614
50705
|
}
|
|
50615
50706
|
function asWarning(raised) {
|
|
@@ -50624,11 +50715,11 @@ function isDirectory(path) {
|
|
|
50624
50715
|
}
|
|
50625
50716
|
}
|
|
50626
50717
|
function mainSceneOf(projectFile) {
|
|
50627
|
-
const scene = parseProjectGodot(
|
|
50718
|
+
const scene = parseProjectGodot(readFileSync37(projectFile, "utf8"))["application"]?.["run/main_scene"];
|
|
50628
50719
|
return typeof scene === "string" && scene !== "" ? scene : null;
|
|
50629
50720
|
}
|
|
50630
50721
|
function editorPlaysHeadless(projectFile) {
|
|
50631
|
-
const runArgs = parseProjectGodot(
|
|
50722
|
+
const runArgs = parseProjectGodot(readFileSync37(projectFile, "utf8"))["editor"]?.["run/main_run_args"];
|
|
50632
50723
|
return typeof runArgs === "string" && /(?:^|\s)--headless(?:\s|$)/.test(runArgs);
|
|
50633
50724
|
}
|
|
50634
50725
|
function ownArguments(params) {
|
|
@@ -51081,12 +51172,16 @@ class GodotServer {
|
|
|
51081
51172
|
};
|
|
51082
51173
|
const call = this.callsTaken++;
|
|
51083
51174
|
this.inFlight.set(call, { tool: spec.name, op: checked.op ?? "", startedAt: Date.now() });
|
|
51175
|
+
const slotWaits = { ms: 0, said: undefined };
|
|
51084
51176
|
try {
|
|
51085
51177
|
const answer = await withCallSignal(ctx.mcpReq.signal, () => this.answered(spec.name, checked.op ?? "", args), progress, {
|
|
51086
51178
|
everyMs: CALL_HEARTBEAT_MS,
|
|
51087
51179
|
said: (elapsedMs) => stillGoingSaid(spec.name, checked.op, elapsedMs)
|
|
51180
|
+
}, slotWaits);
|
|
51181
|
+
const waited = slotWaits.said === undefined || slotWaits.ms < 1000 ? answer : this.saying(answer, {
|
|
51182
|
+
engine_slot_wait: { waitedMs: slotWaits.ms, note: slotWaits.said(slotWaits.ms) }
|
|
51088
51183
|
});
|
|
51089
|
-
return this.withinTheClientsLimit(spec.name, this.withFeedbackNotice(this.withUpdateNotice(
|
|
51184
|
+
return this.withinTheClientsLimit(spec.name, this.withFeedbackNotice(this.withUpdateNotice(waited)));
|
|
51090
51185
|
} finally {
|
|
51091
51186
|
this.inFlight.delete(call);
|
|
51092
51187
|
}
|
|
@@ -51765,6 +51860,10 @@ class GodotServer {
|
|
|
51765
51860
|
if (kept !== null) {
|
|
51766
51861
|
return await this.askTheKeptGame(kept.keeper, keptGameRequest(tool, op, args), kept.projectPath ?? "");
|
|
51767
51862
|
}
|
|
51863
|
+
const last = this.activeProcess;
|
|
51864
|
+
if (tool === "debug_state" && op === "output" && last !== null && !last.throughEditor && last.keeper !== undefined) {
|
|
51865
|
+
return this.createErrorResponse("The game this server started has ended, and its debugger, which held its console output, ended with it.", ["editor_output reads what the game printed, with the errors and warnings it reported"]);
|
|
51866
|
+
}
|
|
51768
51867
|
if (tool === "debug_state" && op === "output") {
|
|
51769
51868
|
return await this.handleDAP("dap_get_output", args);
|
|
51770
51869
|
}
|
|
@@ -52543,7 +52642,7 @@ class GodotServer {
|
|
|
52543
52642
|
if (!engine.ok) {
|
|
52544
52643
|
return engine.response;
|
|
52545
52644
|
}
|
|
52546
|
-
const application = parseProjectGodot(
|
|
52645
|
+
const application = parseProjectGodot(readFileSync37(project.value.file, "utf8"))["application"] ?? {};
|
|
52547
52646
|
const name = application["config/name"];
|
|
52548
52647
|
const mainScene = application["run/main_scene"];
|
|
52549
52648
|
const info = {
|
|
@@ -53094,13 +53193,13 @@ ${platform}`;
|
|
|
53094
53193
|
const reportsDir = join43(project.value.path, ".godot", ...ours.split("/"));
|
|
53095
53194
|
let report = null;
|
|
53096
53195
|
let reportProblem = null;
|
|
53097
|
-
const casePrinted = withNestedErrors(readRun(existsSync34(engineLog) ?
|
|
53196
|
+
const casePrinted = withNestedErrors(readRun(existsSync34(engineLog) ? readFileSync37(engineLog, "utf8") : ""), run.log.all);
|
|
53098
53197
|
const declaredErrors = readExpected(expectedFile);
|
|
53099
53198
|
try {
|
|
53100
53199
|
const written = existsSync34(reportsDir) && notCompiled === null ? readdirSync19(reportsDir).filter((name) => name.startsWith("report_")).sort((a, b) => Number(a.slice("report_".length)) - Number(b.slice("report_".length))) : [];
|
|
53101
53200
|
const newest = written.at(-1);
|
|
53102
53201
|
if (newest !== undefined) {
|
|
53103
|
-
report = parseJUnit(
|
|
53202
|
+
report = parseJUnit(readFileSync37(join43(reportsDir, newest, "results.xml"), "utf8"));
|
|
53104
53203
|
}
|
|
53105
53204
|
} catch (error) {
|
|
53106
53205
|
reportProblem = errorMessage(error);
|
|
@@ -53287,10 +53386,23 @@ ${error.text}`;
|
|
|
53287
53386
|
const testsNotRun = [
|
|
53288
53387
|
...new Set((selection.value?.selected ?? []).filter((one) => !report.suites.some((suite) => (suite.path === one.suite || suite.name === basename13(one.suite, ".gd")) && suite.cases.some((ran) => ran.name === one.test || new RegExp(`^${one.test}\\W`).test(ran.name)))).map((one) => `${basename13(one.suite, ".gd")}:${one.test}`))
|
|
53289
53388
|
];
|
|
53389
|
+
const casesNotRun = selection.value === null ? asked.flatMap((path) => path.endsWith(".gd") ? projectScripts.suite(path) ?? [] : projectScripts.suitesUnder([path])).flatMap((suite) => {
|
|
53390
|
+
const ran = casePrinted.suites.get(suite.path);
|
|
53391
|
+
if (ran?.closed?.verdict !== "PASSED") {
|
|
53392
|
+
return [];
|
|
53393
|
+
}
|
|
53394
|
+
return suite.cases.filter((func) => !ran.cases.some((one) => one.func === func)).map((func) => `${basename13(suite.path, ".gd")}:${func}`).filter((one) => !ignoreRead.leftOut.includes(one));
|
|
53395
|
+
}) : [];
|
|
53396
|
+
const firstUndeclared = undeclaredErrors[0];
|
|
53397
|
+
const declaredAs = firstUndeclared?.case === undefined ? "" : ` A suite declaring none yet does it as const ${firstUndeclared.warning === true ? "GDHARNESS_EXPECTED_WARNINGS" : "GDHARNESS_EXPECTED_ERRORS"}: Dictionary = ${JSON.stringify({ [funcOf(firstUndeclared.case)]: [firstUndeclared.text] })}, keyed by case function, or by before and after for the suite's own hooks.`;
|
|
53398
|
+
const rowsMismatched = casePrinted.mismatched.map((row) => ({
|
|
53399
|
+
test: `${row.suite} > ${row.name}`,
|
|
53400
|
+
reason: row.reason
|
|
53401
|
+
}));
|
|
53290
53402
|
return this.jsonTextResponse({
|
|
53291
|
-
passed: !timedOut && exitCode === 0 && nothingRan === null && report.tests > 0 && report.failures === 0 && report.errors === 0 && hookFailures.length === 0 && uncaught.length === 0 && undeclaredPrinted.length === 0 && declaredNotPrinted.length === 0 && countedLeaks.length === 0 && missing.length === 0 && testsNotRun.length === 0 && notSuites.length === 0,
|
|
53403
|
+
passed: !timedOut && exitCode === 0 && nothingRan === null && report.tests > 0 && report.failures === 0 && report.errors === 0 && hookFailures.length === 0 && uncaught.length === 0 && undeclaredPrinted.length === 0 && declaredNotPrinted.length === 0 && countedLeaks.length === 0 && missing.length === 0 && testsNotRun.length === 0 && casesNotRun.length === 0 && rowsMismatched.length === 0 && notSuites.length === 0,
|
|
53292
53404
|
verdict: [
|
|
53293
|
-
verdict === "passed" && undeclaredPrinted.length + declaredNotPrinted.length + countedLeaks.length + testsNotRun.length + notSuites.length > 0 ? undefined : verdict,
|
|
53405
|
+
verdict === "passed" && undeclaredPrinted.length + declaredNotPrinted.length + countedLeaks.length + testsNotRun.length + casesNotRun.length + rowsMismatched.length + notSuites.length > 0 ? undefined : verdict,
|
|
53294
53406
|
...[false, true].map((warning) => {
|
|
53295
53407
|
const count = undeclaredPrinted.filter((error) => error.warning === warning).length;
|
|
53296
53408
|
const word = warning ? "warning" : "error";
|
|
@@ -53302,12 +53414,14 @@ ${error.text}`;
|
|
|
53302
53414
|
return count > 0 ? `${count === 1 ? `one declared ${word}` : `${String(count)} declared ${word}s`} never printed` : undefined;
|
|
53303
53415
|
}),
|
|
53304
53416
|
countedLeaks.length > 0 ? "the engine exited holding what it should have freed" : undefined,
|
|
53305
|
-
testsNotRun.length > 0 ? `not run: ${testsNotRun.join(", ")}` : undefined,
|
|
53417
|
+
testsNotRun.length + casesNotRun.length > 0 ? `not run: ${[...testsNotRun, ...casesNotRun].join(", ")}` : undefined,
|
|
53418
|
+
rowsMismatched.length > 0 ? `${rowsMismatched.length === 1 ? "one row" : `${String(rowsMismatched.length)} rows`} skipped for data that does not fit the case` : undefined,
|
|
53306
53419
|
notSuites.length > 0 ? `${notSuites.length === 1 ? "one script declares" : `${String(notSuites.length)} scripts declare`} cases gdUnit4 never runs` : undefined
|
|
53307
53420
|
].filter((part) => part !== undefined).join("; "),
|
|
53308
53421
|
...missing.length > 0 ? { missing } : {},
|
|
53309
53422
|
...notSuites.length > 0 ? { notSuites } : {},
|
|
53310
|
-
...testsNotRun.length > 0 ? { testsNotRun } : {},
|
|
53423
|
+
...testsNotRun.length + casesNotRun.length > 0 ? { testsNotRun: [...testsNotRun, ...casesNotRun] } : {},
|
|
53424
|
+
...rowsMismatched.length > 0 ? { rowsMismatched } : {},
|
|
53311
53425
|
...timedOut ? { timedOut, hung, silentForMs } : {},
|
|
53312
53426
|
exitCode,
|
|
53313
53427
|
exitSignal: run.exitSignal ?? undefined,
|
|
@@ -53339,12 +53453,14 @@ ${error.text}`;
|
|
|
53339
53453
|
note: [
|
|
53340
53454
|
missingNote,
|
|
53341
53455
|
testsNotRun.length > 0 ? `${testsNotRun.join(", ")} ${testsNotRun.length === 1 ? "was" : "were"} asked for and not run, so the run is not called passed: gdUnit4 runs a test_ function only in a script that extends GdUnitTestSuite, and leaves out a suite whose script does not load.` : undefined,
|
|
53456
|
+
casesNotRun.length > 0 ? `${casesNotRun.join(", ")} ${casesNotRun.length === 1 ? "is a case" : "are cases"} of a suite that ran and passed, and gdUnit4 never ran ${casesNotRun.length === 1 ? "it" : "them"} and said nothing of it, so the run is not called passed, as gdharness test judges it.` : undefined,
|
|
53457
|
+
rowsMismatched.length > 0 ? `gdUnit4 skipped what rowsMismatched names because the row's data does not fit the case's parameters, though it printed ${rowsMismatched.length === 1 ? "the row" : "each row"} passed first; each entry carries gdUnit4's reason. The run is not called passed, as gdharness test judges it.` : undefined,
|
|
53342
53458
|
notSuites.length > 0 ? "What notSuites names declares cases gdUnit4 never runs, so the run is not called passed, as gdharness test judges it." : undefined,
|
|
53343
53459
|
briefed > 0 ? `${briefed} of the ${failed.length} failing cases, those with the largest reports, are named with their first message only, since their reports would have made the answer too large to deliver; pass one case's suite path to see its reports.` : undefined,
|
|
53344
53460
|
notApplied.length > 0 ? "An ignore entry named a case that ran all the same: gdUnit4 leaves a case out only as suite_name:test_name, and reads an entry with no colon as a suite name or a piece of a suite path. ignoreNotApplied gives the form for each case that ran." : undefined,
|
|
53345
53461
|
unmatched.length > 0 ? `${unmatched.join(", ")} ${unmatched.length === 1 ? "names" : "name"} no suite, case or row under the paths run, so ${unmatched.length === 1 ? "it" : "they"} left nothing out.` : undefined,
|
|
53346
53462
|
uncaughtNote(uncaught),
|
|
53347
|
-
undeclaredErrors.length > 0 ? `An engine error or warning a suite does not declare fails the run, as gdharness test judges it; ${declaringAdvice(undeclaredErrors[0]?.case ?? "test_name", undeclaredErrors[0]?.warning === true)}, once for each time it prints it${undeclaredErrors.some((error) => error.warning !== undeclaredErrors[0]?.warning) ? undeclaredErrors[0]?.warning === true ? ", and an error in its GDHARNESS_EXPECTED_ERRORS" : ", and a warning in its GDHARNESS_EXPECTED_WARNINGS" : ""}
|
|
53463
|
+
undeclaredErrors.length > 0 ? `An engine error or warning a suite does not declare fails the run, as gdharness test judges it; ${declaringAdvice(undeclaredErrors[0]?.case ?? "test_name", undeclaredErrors[0]?.warning === true)}, once for each time it prints it${undeclaredErrors.some((error) => error.warning !== undeclaredErrors[0]?.warning) ? undeclaredErrors[0]?.warning === true ? ", and an error in its GDHARNESS_EXPECTED_ERRORS" : ", and a warning in its GDHARNESS_EXPECTED_WARNINGS" : ""}.${declaredAs}` : undefined,
|
|
53348
53464
|
declaredNotPrinted.length > 0 ? "A declared error or warning the case did not print fails the run too, since the case no longer reaches what it was written to test." : undefined,
|
|
53349
53465
|
walkStopped ? WALK_STOPPED_SENTENCE : undefined,
|
|
53350
53466
|
countedLeaks.length > 0 ? [
|
|
@@ -53621,7 +53737,7 @@ ${error.text}`;
|
|
|
53621
53737
|
return null;
|
|
53622
53738
|
}
|
|
53623
53739
|
try {
|
|
53624
|
-
return
|
|
53740
|
+
return readFileSync37(contained.absolutePath, "utf8");
|
|
53625
53741
|
} catch {
|
|
53626
53742
|
return null;
|
|
53627
53743
|
}
|
|
@@ -53715,7 +53831,7 @@ ${error.text}`;
|
|
|
53715
53831
|
return null;
|
|
53716
53832
|
}
|
|
53717
53833
|
try {
|
|
53718
|
-
return
|
|
53834
|
+
return readFileSync37(contained.absolutePath, "utf8");
|
|
53719
53835
|
} catch {
|
|
53720
53836
|
return null;
|
|
53721
53837
|
}
|
|
@@ -54234,7 +54350,7 @@ ${error.text}`;
|
|
|
54234
54350
|
return null;
|
|
54235
54351
|
}
|
|
54236
54352
|
try {
|
|
54237
|
-
return settingKeys(
|
|
54353
|
+
return settingKeys(readFileSync37(join43(projectPath, "project.godot"), "utf8"));
|
|
54238
54354
|
} catch {
|
|
54239
54355
|
return null;
|
|
54240
54356
|
}
|
|
@@ -55059,7 +55175,7 @@ ${error.text}`;
|
|
|
55059
55175
|
return 0;
|
|
55060
55176
|
}
|
|
55061
55177
|
try {
|
|
55062
|
-
return reportAlreadyInTranscript(
|
|
55178
|
+
return reportAlreadyInTranscript(readFileSync37(game.transcript), readFileSync37(report));
|
|
55063
55179
|
} catch (error) {
|
|
55064
55180
|
this.logDebug(`Could not compare a picked-up run's report with its transcript: ${errorMessage(error)}`);
|
|
55065
55181
|
return 0;
|
|
@@ -56443,6 +56559,8 @@ ${error.text}`;
|
|
|
56443
56559
|
let writtenBefore = null;
|
|
56444
56560
|
let blind = { unseen: [] };
|
|
56445
56561
|
let waitedForEditorMs = 0;
|
|
56562
|
+
let answerStalledMs = 0;
|
|
56563
|
+
const deadline = () => started + timeoutMs + answerStalledMs;
|
|
56446
56564
|
let startUnanswered = false;
|
|
56447
56565
|
let completedBefore;
|
|
56448
56566
|
let uidsReread = [];
|
|
@@ -56450,7 +56568,15 @@ ${error.text}`;
|
|
|
56450
56568
|
for (;; ) {
|
|
56451
56569
|
const busySince = Date.now();
|
|
56452
56570
|
let wasBusy = false;
|
|
56453
|
-
while (Date.now()
|
|
56571
|
+
while (Date.now() < deadline()) {
|
|
56572
|
+
const asked = Date.now();
|
|
56573
|
+
if (!await this.editorIsScanningOrImporting()) {
|
|
56574
|
+
const took = Date.now() - asked;
|
|
56575
|
+
if (took >= SLOW_ANSWER_MS) {
|
|
56576
|
+
answerStalledMs += took;
|
|
56577
|
+
}
|
|
56578
|
+
break;
|
|
56579
|
+
}
|
|
56454
56580
|
wasBusy = true;
|
|
56455
56581
|
await new Promise((settle) => setTimeout(settle, 100));
|
|
56456
56582
|
}
|
|
@@ -56475,7 +56601,7 @@ ${error.text}`;
|
|
|
56475
56601
|
if (duplicated !== undefined) {
|
|
56476
56602
|
uidsDuplicatedOnDisk = duplicated.map((group) => Array.isArray(group) ? group.map(String) : []);
|
|
56477
56603
|
}
|
|
56478
|
-
if (firstAnswer["started"] !== false || Date.now()
|
|
56604
|
+
if (firstAnswer["started"] !== false || Date.now() >= deadline()) {
|
|
56479
56605
|
break;
|
|
56480
56606
|
}
|
|
56481
56607
|
await new Promise((settle) => setTimeout(settle, 100));
|
|
@@ -56485,7 +56611,9 @@ ${error.text}`;
|
|
|
56485
56611
|
const ghosts = blind.stillHeld ?? [];
|
|
56486
56612
|
let busy = true;
|
|
56487
56613
|
let idleSince = null;
|
|
56488
|
-
|
|
56614
|
+
let looked = false;
|
|
56615
|
+
while (!looked || Date.now() < deadline()) {
|
|
56616
|
+
looked = true;
|
|
56489
56617
|
await new Promise((settle) => setTimeout(settle, 100));
|
|
56490
56618
|
let status;
|
|
56491
56619
|
try {
|
|
@@ -56531,6 +56659,7 @@ ${error.text}`;
|
|
|
56531
56659
|
let reloaded = {};
|
|
56532
56660
|
const reloadedFirst = [];
|
|
56533
56661
|
let builtOn;
|
|
56662
|
+
let builtOnUnchecked = false;
|
|
56534
56663
|
const reloadingSource = reloading === undefined || projectPath === "" ? null : this.sourceOfClass(projectPath, reloading);
|
|
56535
56664
|
if (reloading !== undefined && reloadingSource !== null && isToolScript(reloadingSource)) {
|
|
56536
56665
|
reloaded = {
|
|
@@ -56548,6 +56677,7 @@ ${error.text}`;
|
|
|
56548
56677
|
answer = await reloadAsked();
|
|
56549
56678
|
}
|
|
56550
56679
|
builtOn = first.said;
|
|
56680
|
+
builtOnUnchecked = first.unchecked === true;
|
|
56551
56681
|
}
|
|
56552
56682
|
const methods = readArray(answer, "methods");
|
|
56553
56683
|
const listed = (field) => {
|
|
@@ -56574,7 +56704,8 @@ ${error.text}`;
|
|
|
56574
56704
|
names: projectPath === "" ? [] : this.classesAScriptNames(projectPath, script),
|
|
56575
56705
|
restored: answer["restored"] === true,
|
|
56576
56706
|
restoredAs: readString(answer, "restoredAs") ?? "",
|
|
56577
|
-
...builtOn === undefined ? {} : { builtOn }
|
|
56707
|
+
...builtOn === undefined ? {} : { builtOn },
|
|
56708
|
+
...builtOnUnchecked ? { builtOnUnchecked } : {}
|
|
56578
56709
|
})
|
|
56579
56710
|
};
|
|
56580
56711
|
} else {
|
|
@@ -56602,6 +56733,9 @@ ${error.text}`;
|
|
|
56602
56733
|
const dependents = busy || projectPath === "" || broughtIn.length === 0 ? null : await this.reloadDependents(projectPath, broughtIn);
|
|
56603
56734
|
const stillGone = lost.filter((name) => !restored.includes(name));
|
|
56604
56735
|
const notes = [];
|
|
56736
|
+
if (answerStalledMs > 0) {
|
|
56737
|
+
notes.push(`The editor took ${(answerStalledMs / 1000).toFixed(1)} seconds to say it was idle, busy on the thread that answers with an earlier request, and that time was added to the wait rather than taken from it.`);
|
|
56738
|
+
}
|
|
56605
56739
|
if (busy) {
|
|
56606
56740
|
notes.push(startUnanswered ? "The editor took the rescan in and did not answer it before the wait ran out, which is an editor importing: a hidden editor imports on the thread that answers, and answers nothing until it is done. It carries the scan out once it is free, so new files may not be visible yet." : "The editor was still scanning or importing when the wait ran out, so new files may not be visible yet.");
|
|
56607
56741
|
if (unseenBefore.length > 0) {
|
|
@@ -56630,6 +56764,7 @@ ${error.text}`;
|
|
|
56630
56764
|
stillWorking: busy,
|
|
56631
56765
|
waitedMs: Date.now() - started,
|
|
56632
56766
|
waitedForEditorScanMs: waitedForEditorMs > 0 ? waitedForEditorMs : undefined,
|
|
56767
|
+
waitedForEditorAnswerMs: answerStalledMs > 0 ? answerStalledMs : undefined,
|
|
56633
56768
|
reloadedAs: reloaded.as,
|
|
56634
56769
|
...reloadDifference(reloaded),
|
|
56635
56770
|
...args["listMembers"] === true ? {
|
|
@@ -56747,17 +56882,20 @@ ${error.text}`;
|
|
|
56747
56882
|
try {
|
|
56748
56883
|
const answer = asParams(await this.godotBridge.invokeTool("scripts_behind", { scriptPaths }));
|
|
56749
56884
|
const behind = readArray(answer, "behind");
|
|
56750
|
-
return behind === undefined ?
|
|
56885
|
+
return behind === undefined ? { unchecked: "the editor answered without a list of them" } : { behind: behind.map(String), unsaved: (readArray(answer, "unsavedInEditor") ?? []).map(String) };
|
|
56751
56886
|
} catch (error) {
|
|
56752
|
-
|
|
56753
|
-
return null;
|
|
56887
|
+
return { unchecked: `the editor would not say: ${errorMessage(error)}` };
|
|
56754
56888
|
}
|
|
56755
56889
|
}
|
|
56756
56890
|
async reloadWhatItIsBuiltOn(projectPath, scriptPath) {
|
|
56757
56891
|
const against = this.scriptsCompiledAgainst(projectPath, scriptPath);
|
|
56758
56892
|
const held = await this.scriptsHeldBehind(against);
|
|
56759
|
-
if (
|
|
56760
|
-
return {
|
|
56893
|
+
if ("unchecked" in held) {
|
|
56894
|
+
return {
|
|
56895
|
+
reloaded: [],
|
|
56896
|
+
said: `Whether the editor holds the scripts it is compiled against behind their files could not be checked: ${held.unchecked}.`,
|
|
56897
|
+
unchecked: true
|
|
56898
|
+
};
|
|
56761
56899
|
}
|
|
56762
56900
|
const reloadedFor = scriptPath.startsWith("res://") ? scriptPath : `res://${scriptPath.replace(/^\/+/, "")}`;
|
|
56763
56901
|
const reloaded = [];
|
|
@@ -57407,10 +57545,11 @@ ${error.text}`;
|
|
|
57407
57545
|
const checked = await this.classesTheEditorCannotSee(args);
|
|
57408
57546
|
const stillHeld = checked.stillHeld ?? [];
|
|
57409
57547
|
const projectPath = typeof args["projectPath"] === "string" ? args["projectPath"] : "";
|
|
57410
|
-
const listed = projectPath === "" ? null : cachedClasses(projectPath);
|
|
57548
|
+
const listed = projectPath === "" || checked.unchecked !== undefined ? null : cachedClasses(projectPath);
|
|
57411
57549
|
const held = listed === null ? null : await this.scriptsHeldBehind([...new Set(listed.values())]);
|
|
57412
|
-
const
|
|
57413
|
-
|
|
57550
|
+
const behindUnchecked = held !== null && "unchecked" in held ? held.unchecked : undefined;
|
|
57551
|
+
const behind = listed === null || held === null || "unchecked" in held ? [] : [...listed].filter(([, path]) => held.behind.includes(path)).map(([className, scriptPath]) => ({ className, scriptPath }));
|
|
57552
|
+
if (checked.unseen.length === 0 && stillHeld.length === 0 && checked.unchecked === undefined && behindUnchecked === undefined && behind.length === 0) {
|
|
57414
57553
|
return answered;
|
|
57415
57554
|
}
|
|
57416
57555
|
const payload = asParams(JSON.parse(first.text));
|
|
@@ -57433,6 +57572,7 @@ ${error.text}`;
|
|
|
57433
57572
|
stillHeldByEditor: stillHeld.length > 0 ? stillHeld : undefined,
|
|
57434
57573
|
heldBehindInEditor: behind.length > 0 ? behind : undefined,
|
|
57435
57574
|
classesUnchecked: checked.unchecked,
|
|
57575
|
+
heldBehindUnchecked: behindUnchecked,
|
|
57436
57576
|
note: notes.length > 0 ? notes.join(" ") : undefined
|
|
57437
57577
|
});
|
|
57438
57578
|
}
|
|
@@ -57442,7 +57582,7 @@ ${error.text}`;
|
|
|
57442
57582
|
}
|
|
57443
57583
|
const escaped = symbol.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
57444
57584
|
const declared = new RegExp(`^\\s*(?:@\\w+(?:\\([^)]*\\))?\\s+)*class_name\\s+${escaped}\\b`, "m");
|
|
57445
|
-
if (declared.test(
|
|
57585
|
+
if (declared.test(readFileSync37(scriptPath, "utf8"))) {
|
|
57446
57586
|
return null;
|
|
57447
57587
|
}
|
|
57448
57588
|
const checked = await this.classesTheEditorCannotSee(args);
|
|
@@ -57953,7 +58093,7 @@ async function runGodotServer() {
|
|
|
57953
58093
|
const server = new GodotServer;
|
|
57954
58094
|
await server.run();
|
|
57955
58095
|
}
|
|
57956
|
-
var UPDATE_NOTICE_EVERY = 500, FEEDBACK_NOTICE_EVERY = 250, FAILED_BUDGET = 1e6, ANSWER_BUDGET = 4000000, __dirname2, PARENT_ASKED_AFTER_MS = 5000, EDITOR_SERVERS_START_MS = 20000, HOLD_PING_MS = 2000, SLOWEST_FRAME_RATE = 20, ALONGSIDE_NOTE = "Another call on this game was running while this one was: calls sent together run together and are answered as each finishes, so this answer is not from after the other. Send a call meant to come after another once that one has answered.", OWN_DEBUGGER = " Its debugger is the keeper holding it rather than the editor, so the debug_* tools answer for it all the same: breakpoints stop it, and debug_control pause breaks into it wherever it is, which the editor offers no way to do.", PLAY_STARTS_WITHIN_MS = 30000, KEEPER_ANSWER_MS = 15000, KEEPER_DEBUG_MS, EXIT_REPORTED_WITHIN_MS = 2000, SUCCESSOR_SOUGHT_WITHIN_MS = 20000, CLOSE_ASK_MS = 3000, CONSOLE_WRAPPER, LONGEST_BOOT_NOTED_MS, PROFILE_SEND_MS = 5000, MOST_GROUPS = 20, RUNTIME_LISTENING_LINE = "[gdharness] runtime listening on ", VALUE_NAMES, BRIDGE_RETRY_MS = 2000, SUCCESSOR_CHECK_MS = 1e4, CONSOLE_WATCH_MS = 250, BOUNDARY_WAIT_MS = 2000, HANDOVER_MS, HANDOVER_POLL_MS = 250, CACHE_WRITE_MS = 2000, STREAMS_GRACE_MS = 2000, PLAYING_STATUS_MS = 1000, SCAN_SETTLED_MS = 500, REIMPORT_TIMEOUT_MS = 300000, OPS_ELSEWHERE, AUDIO_BUS_OPS, STALLED_AFTER_MS = 30000, TEST_TIMEOUT_MS = 600000, TEST_HEARTBEAT_MS = 20000, DEPENDED_FAILED = "Failed to compile depended scripts", LOOPING_AFTER = 100, WAIT_FOR_RUN_MS = 600000, RUN_POLL_MS = 250, PATH_SOLUTIONS, DESTINATION_ARGUMENTS, OUTPUT_PATH_SOLUTIONS, PROJECT_FILE_ARGUMENTS, DEBUG_STATE_CALLS, PROJECT_INFO_SECTIONS2, RUNNER_DIRECTORY = "addons/gdUnit4/", PROFILE_FUNCTIONS = 30, PROFILER_ON_MS = 3000, PROPERTY_PLACES = "It is a property, so each place says whether it writes it (access write), which runs its set block, or reads it (access read), which runs its get block: withinCalls on a read says nothing of the set block, nor on a write of the get block unless the write is a compound one such as +=. Inside the property's own blocks its name is the value stored, which the engine reads and writes without running them, so those lines are not listed.", CALLERS_FOUND_BY_NAME = "Found by name in the project's scripts, since the engine's profiler counts calls and time per function and records nothing about who made them: a method of the same name on another class is listed too, unless one class was asked about and it is called through another class by name or through a variable declared as one. Each place carries the profile's numbers for the function it is written in.", MOST_ENGINE_ENTRIES = 200, MOST_PRINTED_LINES = 50, MOST_UNDECLARED_ERRORS = 20, ERROR_ASSERT = "GdUnitGodotErrorAssertImpl.gd", RAISED_WARNING = " (Warning treated as error.)", PARSE_ERROR2 = "Parse Error: ", EXTERNAL_MEMBER = 'Could not resolve external class member "', STATIC_LIST_HINT;
|
|
58096
|
+
var UPDATE_NOTICE_EVERY = 500, FEEDBACK_NOTICE_EVERY = 250, FAILED_BUDGET = 1e6, ANSWER_BUDGET = 4000000, __dirname2, PARENT_ASKED_AFTER_MS = 5000, EDITOR_SERVERS_START_MS = 20000, HOLD_PING_MS = 2000, SLOWEST_FRAME_RATE = 20, ALONGSIDE_NOTE = "Another call on this game was running while this one was: calls sent together run together and are answered as each finishes, so this answer is not from after the other. Send a call meant to come after another once that one has answered.", OWN_DEBUGGER = " Its debugger is the keeper holding it rather than the editor, so the debug_* tools answer for it all the same: breakpoints stop it, and debug_control pause breaks into it wherever it is, which the editor offers no way to do.", PLAY_STARTS_WITHIN_MS = 30000, KEEPER_ANSWER_MS = 15000, KEEPER_DEBUG_MS, EXIT_REPORTED_WITHIN_MS = 2000, SUCCESSOR_SOUGHT_WITHIN_MS = 20000, CLOSE_ASK_MS = 3000, CONSOLE_WRAPPER, LONGEST_BOOT_NOTED_MS, PROFILE_SEND_MS = 5000, MOST_GROUPS = 20, RUNTIME_LISTENING_LINE = "[gdharness] runtime listening on ", VALUE_NAMES, BRIDGE_RETRY_MS = 2000, SUCCESSOR_CHECK_MS = 1e4, CONSOLE_WATCH_MS = 250, BOUNDARY_WAIT_MS = 2000, HANDOVER_MS, HANDOVER_POLL_MS = 250, CACHE_WRITE_MS = 2000, STREAMS_GRACE_MS = 2000, PLAYING_STATUS_MS = 1000, SCAN_SETTLED_MS = 500, SLOW_ANSWER_MS = 1000, REIMPORT_TIMEOUT_MS = 300000, OPS_ELSEWHERE, AUDIO_BUS_OPS, STALLED_AFTER_MS = 30000, TEST_TIMEOUT_MS = 600000, TEST_HEARTBEAT_MS = 20000, DEPENDED_FAILED = "Failed to compile depended scripts", LOOPING_AFTER = 100, WAIT_FOR_RUN_MS = 600000, RUN_POLL_MS = 250, PATH_SOLUTIONS, DESTINATION_ARGUMENTS, OUTPUT_PATH_SOLUTIONS, PROJECT_FILE_ARGUMENTS, DEBUG_STATE_CALLS, PROJECT_INFO_SECTIONS2, RUNNER_DIRECTORY = "addons/gdUnit4/", PROFILE_FUNCTIONS = 30, PROFILER_ON_MS = 3000, PROPERTY_PLACES = "It is a property, so each place says whether it writes it (access write), which runs its set block, or reads it (access read), which runs its get block: withinCalls on a read says nothing of the set block, nor on a write of the get block unless the write is a compound one such as +=. Inside the property's own blocks its name is the value stored, which the engine reads and writes without running them, so those lines are not listed.", CALLERS_FOUND_BY_NAME = "Found by name in the project's scripts, since the engine's profiler counts calls and time per function and records nothing about who made them: a method of the same name on another class is listed too, unless one class was asked about and it is called through another class by name or through a variable declared as one. Each place carries the profile's numbers for the function it is written in.", MOST_ENGINE_ENTRIES = 200, MOST_PRINTED_LINES = 50, MOST_UNDECLARED_ERRORS = 20, ERROR_ASSERT = "GdUnitGodotErrorAssertImpl.gd", RAISED_WARNING = " (Warning treated as error.)", PARSE_ERROR2 = "Parse Error: ", EXTERNAL_MEMBER = 'Could not resolve external class member "', STATIC_LIST_HINT;
|
|
57957
58097
|
var init_server = __esm(() => {
|
|
57958
58098
|
init_dist2();
|
|
57959
58099
|
init_stdio();
|
|
@@ -58126,7 +58266,7 @@ init_alive();
|
|
|
58126
58266
|
init_engine_launch();
|
|
58127
58267
|
init_lsp_client();
|
|
58128
58268
|
init_process_children();
|
|
58129
|
-
import { existsSync as existsSync17, readdirSync as readdirSync10, readFileSync as
|
|
58269
|
+
import { existsSync as existsSync17, readdirSync as readdirSync10, readFileSync as readFileSync16, unlinkSync as unlinkSync2 } from "node:fs";
|
|
58130
58270
|
import { connect as connect2 } from "node:net";
|
|
58131
58271
|
import { join as join20, resolve as resolve7 } from "node:path";
|
|
58132
58272
|
var EDITOR_RECORD_PROTOCOL = 1;
|
|
@@ -58145,7 +58285,7 @@ function editorRecordsIn(projectPath) {
|
|
|
58145
58285
|
for (const name of names) {
|
|
58146
58286
|
const file = join20(directory, name);
|
|
58147
58287
|
try {
|
|
58148
|
-
const said = JSON.parse(
|
|
58288
|
+
const said = JSON.parse(readFileSync16(file, "utf8"));
|
|
58149
58289
|
const { protocol, pid, lsp_port: lspPort, written_at_ms: writtenAtMs } = said;
|
|
58150
58290
|
if (protocol === EDITOR_RECORD_PROTOCOL && typeof pid === "number" && typeof lspPort === "number" && lspPort > 0 && typeof writtenAtMs === "number") {
|
|
58151
58291
|
records.push({ file, pid, lspPort, writtenAtMs });
|
|
@@ -58654,7 +58794,7 @@ init_engine_launch();
|
|
|
58654
58794
|
init_engine_slots();
|
|
58655
58795
|
init_setup();
|
|
58656
58796
|
init_suite_judge();
|
|
58657
|
-
import { existsSync as existsSync20, mkdirSync as mkdirSync8, readFileSync as
|
|
58797
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync8, readFileSync as readFileSync19, rmSync as rmSync11 } from "node:fs";
|
|
58658
58798
|
import { availableParallelism as availableParallelism3 } from "node:os";
|
|
58659
58799
|
import { join as join23, resolve as resolve9 } from "node:path";
|
|
58660
58800
|
import process13 from "node:process";
|
|
@@ -58842,17 +58982,17 @@ async function runSpreadCommand(options, godotPath) {
|
|
|
58842
58982
|
const faults = left.flatMap((worker) => engineFaults(worker, options.godotVersion));
|
|
58843
58983
|
const arms = left.map((_, index) => {
|
|
58844
58984
|
const file = join23(shareDirectory, `worker-${String(index)}.arms`);
|
|
58845
|
-
return existsSync20(file) ? armsPlayed(
|
|
58985
|
+
return existsSync20(file) ? armsPlayed(readFileSync19(file, "utf8")) : [];
|
|
58846
58986
|
});
|
|
58847
58987
|
faults.push(...shareFaults(arms));
|
|
58848
58988
|
if (faults.length > 0) {
|
|
58849
58989
|
return failed(faults, left, runDirectory, "so nothing was gathered");
|
|
58850
58990
|
}
|
|
58851
58991
|
const gather = await engine("gather", `${GATHER}${String(workers)}`);
|
|
58852
|
-
console.log(
|
|
58992
|
+
console.log(readFileSync19(gather.log, "utf8").replace(CONTROL_SEQUENCE, "").trimEnd());
|
|
58853
58993
|
const gatherFaults = engineFaults(gather, options.godotVersion);
|
|
58854
58994
|
const gatheredFile = join23(shareDirectory, "gathered.arms");
|
|
58855
|
-
const gathered = new Set((existsSync20(gatheredFile) ? armsPlayed(
|
|
58995
|
+
const gathered = new Set((existsSync20(gatheredFile) ? armsPlayed(readFileSync19(gatheredFile, "utf8")) ?? [] : []).map((arm) => arm.arm));
|
|
58856
58996
|
const ungathered = (arms[0] ?? []).filter((arm) => !gathered.has(arm.arm)).map((arm) => arm.arm);
|
|
58857
58997
|
if (ungathered.length > 0) {
|
|
58858
58998
|
gatherFaults.push(`the gathering run never asked for ${ungathered.join(", ")}, which the workers played: it went another way through the arms than they did`);
|
|
@@ -58906,7 +59046,7 @@ function engineFaults(engine, godotVersion) {
|
|
|
58906
59046
|
if (!existsSync20(engine.log)) {
|
|
58907
59047
|
return faults;
|
|
58908
59048
|
}
|
|
58909
|
-
const printed = readRun(
|
|
59049
|
+
const printed = readRun(readFileSync19(engine.log, "utf8"));
|
|
58910
59050
|
const wrongEngine = godotVersion === null ? null : versionFault(printed.engineVersion, godotVersion);
|
|
58911
59051
|
if (wrongEngine !== null) {
|
|
58912
59052
|
faults.push(`${engine.name}: ${wrongEngine}`);
|
|
@@ -58919,7 +59059,7 @@ function engineFaults(engine, godotVersion) {
|
|
|
58919
59059
|
}
|
|
58920
59060
|
function progressOf(logs) {
|
|
58921
59061
|
const each = logs.map((log, index) => {
|
|
58922
|
-
const text = existsSync20(log) ?
|
|
59062
|
+
const text = existsSync20(log) ? readFileSync19(log, "utf8") : "";
|
|
58923
59063
|
const last = [...text.matchAll(PROGRESS)].at(-1);
|
|
58924
59064
|
return last === undefined ? `worker ${String(index)} has played no arm yet` : `worker ${String(index)} at ${last[1] ?? ""} ${last[2] ?? ""} of ${last[3] ?? ""}`;
|
|
58925
59065
|
});
|
|
@@ -58951,7 +59091,7 @@ import {
|
|
|
58951
59091
|
existsSync as existsSync23,
|
|
58952
59092
|
mkdirSync as mkdirSync10,
|
|
58953
59093
|
readdirSync as readdirSync14,
|
|
58954
|
-
readFileSync as
|
|
59094
|
+
readFileSync as readFileSync23,
|
|
58955
59095
|
rmSync as rmSync12,
|
|
58956
59096
|
statSync as statSync14,
|
|
58957
59097
|
writeFileSync as writeFileSync12
|
|
@@ -58963,7 +59103,7 @@ import process14 from "node:process";
|
|
|
58963
59103
|
// src/suite-fingerprint.ts
|
|
58964
59104
|
init_class_cache();
|
|
58965
59105
|
import { createHash as createHash6 } from "node:crypto";
|
|
58966
|
-
import { existsSync as existsSync21, readdirSync as readdirSync13, readFileSync as
|
|
59106
|
+
import { existsSync as existsSync21, readdirSync as readdirSync13, readFileSync as readFileSync20, statSync as statSync13 } from "node:fs";
|
|
58967
59107
|
import { join as join24, posix as posix2 } from "node:path";
|
|
58968
59108
|
var RES_LITERAL = /res:\/\/[^"'\s)\]<>]*/g;
|
|
58969
59109
|
var RELATIVE_LOAD = /\b(?:pre)?load\(\s*["']((?!res:\/\/|uid:\/\/)[^"']+)["']/g;
|
|
@@ -59028,7 +59168,7 @@ ${this.read(path).digest}
|
|
|
59028
59168
|
walk(file, `${under}${entry.name}/`);
|
|
59029
59169
|
} else if (entry.isFile()) {
|
|
59030
59170
|
hash.update(`${under}${entry.name}
|
|
59031
|
-
`).update(
|
|
59171
|
+
`).update(readFileSync20(file));
|
|
59032
59172
|
}
|
|
59033
59173
|
}
|
|
59034
59174
|
};
|
|
@@ -59054,7 +59194,7 @@ ${this.read(path).digest}
|
|
|
59054
59194
|
if (BINARY_RESOURCE.test(path)) {
|
|
59055
59195
|
return { digest: "", reaches: [], unreadable: `${path} is a binary resource` };
|
|
59056
59196
|
}
|
|
59057
|
-
const bytes =
|
|
59197
|
+
const bytes = readFileSync20(file);
|
|
59058
59198
|
const digest = createHash6("sha256").update(bytes).digest("hex");
|
|
59059
59199
|
const text = bytes.toString("latin1");
|
|
59060
59200
|
const reaches = new Set;
|
|
@@ -59092,7 +59232,7 @@ ${this.read(path).digest}
|
|
|
59092
59232
|
}
|
|
59093
59233
|
function extensionsOf(projectPath) {
|
|
59094
59234
|
const list = join24(projectPath, ".godot", "extension_list.cfg");
|
|
59095
|
-
return existsSync21(list) ?
|
|
59235
|
+
return existsSync21(list) ? readFileSync20(list, "utf8").split(`
|
|
59096
59236
|
`).map((line) => line.trim()).filter((line) => line.startsWith("res://")) : [];
|
|
59097
59237
|
}
|
|
59098
59238
|
|
|
@@ -59101,7 +59241,7 @@ init_suite_judge();
|
|
|
59101
59241
|
init_suite_plan();
|
|
59102
59242
|
|
|
59103
59243
|
// src/version.ts
|
|
59104
|
-
import { readFileSync as
|
|
59244
|
+
import { readFileSync as readFileSync22 } from "node:fs";
|
|
59105
59245
|
import { dirname as dirname12, join as join26 } from "node:path";
|
|
59106
59246
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
59107
59247
|
function getLocalVersion() {
|
|
@@ -59112,7 +59252,7 @@ function getLocalVersion() {
|
|
|
59112
59252
|
];
|
|
59113
59253
|
for (const packagePath of packageCandidates) {
|
|
59114
59254
|
try {
|
|
59115
|
-
const value = JSON.parse(
|
|
59255
|
+
const value = JSON.parse(readFileSync22(packagePath, "utf-8"));
|
|
59116
59256
|
if (typeof value === "object" && value !== null && "name" in value && value.name === "gdharness" && "version" in value && typeof value.version === "string") {
|
|
59117
59257
|
return value.version;
|
|
59118
59258
|
}
|
|
@@ -59373,9 +59513,9 @@ async function runTestCommand(options, godotPath) {
|
|
|
59373
59513
|
}
|
|
59374
59514
|
const fingerprints = new SuiteFingerprints(scripts, [
|
|
59375
59515
|
getLocalVersion(),
|
|
59376
|
-
|
|
59516
|
+
readFileSync23(shippedListedRunner(), "utf8"),
|
|
59377
59517
|
...options.reachAlso.map((path) => `${path}
|
|
59378
|
-
${existsSync23(path) ?
|
|
59518
|
+
${existsSync23(path) ? readFileSync23(path, "latin1") : "missing"}`)
|
|
59379
59519
|
]);
|
|
59380
59520
|
const printsOf = new Map(suites.map((suite) => [suite.path, fingerprints.of(suite)]));
|
|
59381
59521
|
if (options.changedOnly) {
|
|
@@ -59491,7 +59631,7 @@ function roomSaid(engines, lanes, unheld, held, asked) {
|
|
|
59491
59631
|
}
|
|
59492
59632
|
function readRecord(file) {
|
|
59493
59633
|
try {
|
|
59494
|
-
const parsed = JSON.parse(
|
|
59634
|
+
const parsed = JSON.parse(readFileSync23(file, "utf8"));
|
|
59495
59635
|
return typeof parsed === "object" && parsed !== null ? parsed : {};
|
|
59496
59636
|
} catch {
|
|
59497
59637
|
return {};
|
|
@@ -59550,7 +59690,7 @@ async function importProject(launch) {
|
|
|
59550
59690
|
if (ended.ended !== null || ended.code !== 0) {
|
|
59551
59691
|
return `${ended.ended ?? `the engine exited ${exitNamed(ended.code ?? 0)}`}; everything it printed is in ${launch.logs.named(log)}`;
|
|
59552
59692
|
}
|
|
59553
|
-
const printed = readRun(
|
|
59693
|
+
const printed = readRun(readFileSync23(log, "utf8"));
|
|
59554
59694
|
const wrongEngine = launch.godotVersion === null ? null : versionFault(printed.engineVersion, launch.godotVersion);
|
|
59555
59695
|
if (wrongEngine !== null) {
|
|
59556
59696
|
return `${wrongEngine}; everything it printed is in ${launch.logs.named(log)}`;
|
|
@@ -59666,7 +59806,7 @@ async function runEngine2(launch, plan, index, times, again = "", slot = null) {
|
|
|
59666
59806
|
launch.slots.release(lock);
|
|
59667
59807
|
}
|
|
59668
59808
|
}
|
|
59669
|
-
const printed = readRun(
|
|
59809
|
+
const printed = readRun(readFileSync23(log, "utf8"));
|
|
59670
59810
|
const assignment = {
|
|
59671
59811
|
suites: plan.suites,
|
|
59672
59812
|
expected: readExpected(expectedFile),
|
|
@@ -59701,7 +59841,7 @@ function report(ran, across, uncollected, startedAt, logs, printOutput, targets)
|
|
|
59701
59841
|
for (const engine of ran) {
|
|
59702
59842
|
console.log("");
|
|
59703
59843
|
console.log(`--- what engine ${String(engine.index)} printed, running ${named(engine.plan.suites.map((suite) => suite.path))}:`);
|
|
59704
|
-
console.log(existsSync23(engine.log) ?
|
|
59844
|
+
console.log(existsSync23(engine.log) ? readFileSync23(engine.log, "utf8").replace(CONTROL_SEQUENCE, "").trimEnd() : "(no log was written)");
|
|
59705
59845
|
}
|
|
59706
59846
|
}
|
|
59707
59847
|
const failed = ran.filter((engine) => !engine.verdict.passed);
|
|
@@ -59720,7 +59860,7 @@ function report(ran, across, uncollected, startedAt, logs, printOutput, targets)
|
|
|
59720
59860
|
writeFileSync12(engine.log, `${verdict.join(`
|
|
59721
59861
|
`)}
|
|
59722
59862
|
---
|
|
59723
|
-
${
|
|
59863
|
+
${readFileSync23(engine.log, "utf8")}`);
|
|
59724
59864
|
}
|
|
59725
59865
|
if (engine.verdict.shown.length > 0) {
|
|
59726
59866
|
console.log("");
|