gdharness 1.3.53 → 1.3.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/cli.js
CHANGED
|
@@ -14312,16 +14312,76 @@ function importedIntoTheProject(projectPath, resPaths) {
|
|
|
14312
14312
|
function onDisk(projectPath, resPath) {
|
|
14313
14313
|
return join13(projectPath, resPath.slice("res://".length));
|
|
14314
14314
|
}
|
|
14315
|
-
function
|
|
14315
|
+
function importedSidecarMd5s(projectPath) {
|
|
14316
|
+
const found = new Map;
|
|
14317
|
+
const editor = join13(projectPath, ".godot", "editor");
|
|
14318
|
+
let newest = -1;
|
|
14319
|
+
try {
|
|
14320
|
+
for (const name of readdirSync8(editor)) {
|
|
14321
|
+
const version = /^filesystem_cache(\d+)$/.exec(name)?.[1];
|
|
14322
|
+
if (version !== undefined) {
|
|
14323
|
+
newest = Math.max(newest, Number(version));
|
|
14324
|
+
}
|
|
14325
|
+
}
|
|
14326
|
+
} catch {
|
|
14327
|
+
return found;
|
|
14328
|
+
}
|
|
14329
|
+
if (newest < 0) {
|
|
14330
|
+
return found;
|
|
14331
|
+
}
|
|
14332
|
+
let text;
|
|
14333
|
+
try {
|
|
14334
|
+
text = readFileSync11(join13(editor, `filesystem_cache${newest}`), "utf8");
|
|
14335
|
+
} catch {
|
|
14336
|
+
return found;
|
|
14337
|
+
}
|
|
14338
|
+
let directory = "res://";
|
|
14339
|
+
for (const line of text.split(/\r?\n/).slice(1).map((one) => one.trim())) {
|
|
14340
|
+
if (line === "") {
|
|
14341
|
+
continue;
|
|
14342
|
+
}
|
|
14343
|
+
const fields = line.split("::");
|
|
14344
|
+
if (line.startsWith("::")) {
|
|
14345
|
+
if (fields.length === 3) {
|
|
14346
|
+
directory = fields[1] ?? directory;
|
|
14347
|
+
}
|
|
14348
|
+
continue;
|
|
14349
|
+
}
|
|
14350
|
+
const slices = fields.length < 9 ? [] : (fields[7] ?? "").split("<>");
|
|
14351
|
+
const md5 = slices[5];
|
|
14352
|
+
if (slices.length >= 7 && md5 !== undefined && md5 !== "") {
|
|
14353
|
+
found.set(`${directory}${directory.endsWith("/") ? "" : "/"}${fields[0]}`, md5);
|
|
14354
|
+
}
|
|
14355
|
+
}
|
|
14356
|
+
return found;
|
|
14357
|
+
}
|
|
14358
|
+
function behind(projectPath, resPath, sidecarFile, sidecar, importedFrom) {
|
|
14359
|
+
const imported = importedFrom.get(resPath);
|
|
14360
|
+
if (imported !== undefined && md5Of(sidecarFile) !== imported) {
|
|
14361
|
+
return "its import file changed after it was imported, as setting an option does";
|
|
14362
|
+
}
|
|
14316
14363
|
const remap = sectionOf(sidecar, "remap");
|
|
14317
14364
|
const importer = unquoted(remap.get("importer"));
|
|
14318
14365
|
if (importer === "keep" || importer === "skip") {
|
|
14319
14366
|
return null;
|
|
14320
14367
|
}
|
|
14321
|
-
const
|
|
14368
|
+
const deps = sectionOf(sidecar, "deps");
|
|
14369
|
+
const outputs = listed2(deps.get("dest_files"));
|
|
14370
|
+
if (remap.get("valid") !== "false") {
|
|
14371
|
+
if (!remap.has("uid")) {
|
|
14372
|
+
return "its import file has no uid, which the import writes";
|
|
14373
|
+
}
|
|
14374
|
+
if (outputs.length === 0 && ![...remap.keys()].some((key) => key.startsWith("path"))) {
|
|
14375
|
+
return "its import file names no imported output, as one written before the engine imports from it does";
|
|
14376
|
+
}
|
|
14377
|
+
}
|
|
14322
14378
|
if (outputs.some((output) => !existsSync11(onDisk(projectPath, output)))) {
|
|
14323
14379
|
return "its imported output is not on disk";
|
|
14324
14380
|
}
|
|
14381
|
+
const source = unquoted(deps.get("source_file"));
|
|
14382
|
+
if (source !== "" && source !== resPath) {
|
|
14383
|
+
return `its import file was written for ${source}`;
|
|
14384
|
+
}
|
|
14325
14385
|
const name = resPath.slice(resPath.lastIndexOf("/") + 1);
|
|
14326
14386
|
const record = join13(projectPath, ".godot", "imported", `${name}-${createHash2("md5").update(resPath, "utf8").digest("hex")}.md5`);
|
|
14327
14387
|
let recorded = "";
|
|
@@ -14338,6 +14398,7 @@ function behind(projectPath, resPath, sidecar) {
|
|
|
14338
14398
|
}
|
|
14339
14399
|
function staleImports(projectPath) {
|
|
14340
14400
|
const stale = [];
|
|
14401
|
+
const importedFrom = importedSidecarMd5s(projectPath);
|
|
14341
14402
|
const visit = (directory, resDirectory) => {
|
|
14342
14403
|
if (existsSync11(join13(directory, ".gdignore")) || existsSync11(join13(directory, VERSION_MARKER))) {
|
|
14343
14404
|
return;
|
|
@@ -14366,13 +14427,14 @@ function staleImports(projectPath) {
|
|
|
14366
14427
|
if (!names.has(entry.name.slice(0, -".import".length))) {
|
|
14367
14428
|
continue;
|
|
14368
14429
|
}
|
|
14430
|
+
const sidecarFile = join13(directory, entry.name);
|
|
14369
14431
|
let sidecar;
|
|
14370
14432
|
try {
|
|
14371
|
-
sidecar = readFileSync11(
|
|
14433
|
+
sidecar = readFileSync11(sidecarFile, "utf8");
|
|
14372
14434
|
} catch {
|
|
14373
14435
|
continue;
|
|
14374
14436
|
}
|
|
14375
|
-
const reason = behind(projectPath, source, sidecar);
|
|
14437
|
+
const reason = behind(projectPath, source, sidecarFile, sidecar, importedFrom);
|
|
14376
14438
|
if (reason !== null) {
|
|
14377
14439
|
stale.push({ path: source, reason });
|
|
14378
14440
|
}
|
|
@@ -60197,6 +60259,7 @@ init_import_freshness();
|
|
|
60197
60259
|
init_launch();
|
|
60198
60260
|
init_library_copies();
|
|
60199
60261
|
init_log_read();
|
|
60262
|
+
init_reimport();
|
|
60200
60263
|
init_setup();
|
|
60201
60264
|
import {
|
|
60202
60265
|
copyFileSync,
|
|
@@ -61146,7 +61209,8 @@ async function importProject(launch) {
|
|
|
61146
61209
|
console.log(`Wrote .godot/extension_list.cfg naming ${named(seeded)}, so the import loads them.`);
|
|
61147
61210
|
}
|
|
61148
61211
|
const cached = cachedClasses(launch.projectPath);
|
|
61149
|
-
|
|
61212
|
+
const stale = staleImports(launch.projectPath);
|
|
61213
|
+
if ((seeded === null || seeded.length === 0) && cached !== null && staleAgainst(cached, launch.projectPath).length === 0 && stale.length === 0) {
|
|
61150
61214
|
console.log("The import was skipped: every imported file and the class cache are current.");
|
|
61151
61215
|
return null;
|
|
61152
61216
|
}
|
|
@@ -61156,6 +61220,9 @@ async function importProject(launch) {
|
|
|
61156
61220
|
const lock = await launch.slots.take();
|
|
61157
61221
|
try {
|
|
61158
61222
|
freeLibraryCopies(launch.projectPath);
|
|
61223
|
+
for (const one of stale) {
|
|
61224
|
+
forceNextImport(launch.projectPath, one.path);
|
|
61225
|
+
}
|
|
61159
61226
|
const ended = await watchedEngine(launch, lock, ["--headless", "--audio-driver", "Dummy", "--path", launch.projectPath, "--import"], directory, log, launch.silenceFloorSeconds);
|
|
61160
61227
|
if (ended.ended !== null || ended.code !== 0) {
|
|
61161
61228
|
return `${ended.ended ?? `the engine exited ${exitNamed(ended.code ?? 0)}`}; everything it printed is in ${launch.logs.named(log)}`;
|
|
@@ -574,10 +574,21 @@ static func _import_staleness(resource_path: String, sidecar: ConfigFile) -> Dic
|
|
|
574
574
|
if not sidecar.has_section_key("remap", "uid"):
|
|
575
575
|
return _stale("its import file has no uid, which the import writes")
|
|
576
576
|
|
|
577
|
+
# A tool that writes a sidecar for the engine to import from leaves out what the import writes,
|
|
578
|
+
# and every load of the resource then fails. The engine's scan without its cache takes such a
|
|
579
|
+
# sidecar as imported while the record of the last import still matches the source.
|
|
580
|
+
var outputs: Array[String] = _outputs_of(sidecar)
|
|
581
|
+
if outputs.is_empty() and not _names_a_path(sidecar):
|
|
582
|
+
return _stale(
|
|
583
|
+
(
|
|
584
|
+
"its import file names no imported output, as one written before the engine "
|
|
585
|
+
+ "imports from it does"
|
|
586
|
+
)
|
|
587
|
+
)
|
|
588
|
+
|
|
577
589
|
# The sidecar alone does not say the import is there: deleting the outputs under
|
|
578
590
|
# .godot/imported is the ordinary way to force one, and a resource whose output is gone was
|
|
579
591
|
# answered as current, which is what a reimport is then skipped on.
|
|
580
|
-
var outputs: Array[String] = _outputs_of(sidecar)
|
|
581
592
|
var missing: Array[String] = []
|
|
582
593
|
for output: String in outputs:
|
|
583
594
|
if not FileAccess.file_exists(output):
|
|
@@ -786,6 +797,17 @@ static func _outputs_of(sidecar: ConfigFile) -> Array[String]:
|
|
|
786
797
|
return outputs
|
|
787
798
|
|
|
788
799
|
|
|
800
|
+
## Whether [param sidecar]'s remap names where a load finds the import, as [code]path[/code] or a
|
|
801
|
+
## [code]path.<feature>[/code] key.
|
|
802
|
+
static func _names_a_path(sidecar: ConfigFile) -> bool:
|
|
803
|
+
if not sidecar.has_section("remap"):
|
|
804
|
+
return false
|
|
805
|
+
for key: String in sidecar.get_section_keys("remap"):
|
|
806
|
+
if key.begins_with("path"):
|
|
807
|
+
return true
|
|
808
|
+
return false
|
|
809
|
+
|
|
810
|
+
|
|
789
811
|
## The image files a glTF scene refers to by path, resolved against the scene's own directory.
|
|
790
812
|
## Embedded images and every other scene format answer nothing.
|
|
791
813
|
static func _images_of(scene_path: String) -> Array[String]:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gdharness",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.54",
|
|
4
4
|
"mcpName": "io.github.Aureliolo/gdharness",
|
|
5
5
|
"description": "A harness for driving a Godot 4 project from an agent: editor addons, a runtime bridge into the running game, an MCP server in front of them, and a CLI that installs and diagnoses the Godot side.",
|
|
6
6
|
"type": "module",
|