godot::publish-to-library action with import-setting passthrough

This commit is contained in:
BillyOutlast committed 2026-10-25 16:52:34 -09:00
1 parent 9ab3bb8afd
commit 660b3053dc
4 files changed
+164 -1

No files matched your search

+60
View File
@@ -0,0 +1,60 @@
"""Publish the selection to the self-hosted asset library."""
import json
import os
import subprocess
import sys
import anchorpoint
from assetmgr.godot import describe_for_library, find_godot_project_root
ctx = anchorpoint.get_context()
selection = [*(ctx.selected_files or []), *(ctx.selected_folders or [])]
if ctx.path and ctx.path not in selection:
selection.append(ctx.path)
files = [p for p in selection if p and os.path.isfile(p)]
root = None
if ctx.project_path:
root = find_godot_project_root(ctx.project_path)
if root is None and ctx.path:
root = find_godot_project_root(ctx.path)
if root is None:
anchorpoint.UI().show_error("Not a Godot project",
"No project.godot found above the selection.")
raise SystemExit(1)
if not files:
anchorpoint.UI().show_error("Publish failed", "No files selected.")
raise SystemExit(1)
server = str(ctx.inputs.get("server", "") or "")
token = str(ctx.inputs.get("token", "") or "")
cli = [sys.executable, "-m", "assetmgr.cli"]
published: list[int] = []
for path in files:
described = describe_for_library(path)
argv = cli + ["library-push", path, "--json"]
if server:
argv += ["--server", server]
if token:
argv += ["--token", token]
argv += ["--kind", described["kind"]]
if described["importer"]:
argv += ["--importer", str(described["importer"]),
"--params", json.dumps(described["params"])]
completed = subprocess.run(argv, capture_output=True, text=True)
if completed.returncode != 0:
anchorpoint.UI().show_error(
"Publish failed",
(completed.stderr or completed.stdout).strip()[-300:])
raise SystemExit(1)
try:
published.append(int(json.loads(completed.stdout)["id"]))
except (ValueError, KeyError):
anchorpoint.UI().show_error("Publish failed",
"library returned an unreadable reply")
raise SystemExit(1)
anchorpoint.UI().show_success(
"Published to library",
f"{len(published)} file(s), asset {published[0]}"
+ (f" (+{len(published) - 1} more)" if len(published) > 1 else ""))
+18
View File
@@ -0,0 +1,18 @@
version: "1.0"
action:
name: Publish to library
id: godot::publish-to-library
version: 1
author: Heretek-AI
category: godot
type: python
description: Uploads selected files to the self-hosted asset library (import settings travel with each file).
script: publish.py
inputs:
server: ""
token: ""
register:
file:
enable: true
folder:
enable: true
+32
View File
@@ -407,6 +407,38 @@ def known_importer_params(importer: str) -> frozenset[str] | None:
return IMPORTER_PARAMS.get(importer)
_SUFFIX_KINDS = {
".png": "texture", ".jpg": "texture", ".jpeg": "texture",
".svg": "texture", ".webp": "texture", ".exr": "texture",
".tga": "texture", ".bmp": "texture",
".wav": "audio", ".ogg": "audio", ".mp3": "audio",
".glb": "model", ".gltf": "model", ".obj": "model",
".fbx": "model", ".dae": "model",
".ttf": "font", ".otf": "font", ".woff2": "font",
".gd": "script", ".gdshader": "shader", ".tscn": "scene",
}
def describe_for_library(asset_path: str) -> dict[str, Any]:
"""Metadata for publishing *asset_path* to the library.
Prefers the ``*.import`` sidecar (importer + params travel with the
file); falls back to a suffix-based kind with no importer or params.
"""
sidecar = asset_path + ".import"
if os.path.isfile(sidecar):
summary = import_summary(read_import(sidecar))
importer = summary.get("importer")
return {
"kind": importer if isinstance(importer, str) else "raw",
"importer": importer,
"params": summary.get("params") or {},
}
suffix = os.path.splitext(asset_path)[1].lower()
return {"kind": _SUFFIX_KINDS.get(suffix, "raw"),
"importer": None, "params": {}}
def validate_import_params(importer: str, params: dict) -> list[str]:
"""Keys in *params* the importer does not declare.
+54 -1
View File
@@ -121,7 +121,8 @@ def test_godot_action_manifests_discovered():
assert not errors
ids = {m.manifest_id for m in found}
assert {"godot::import-asset", "godot::reimport",
"godot::open-project", "godot::set-preset"} <= ids
"godot::open-project", "godot::set-preset",
"godot::publish-to-library"} <= ids
def test_import_action_dispatch(tmp_path, capsys):
@@ -358,3 +359,55 @@ def test_live_set_preset_survives_reimport(tmp_path):
capture_output=True, text=True, timeout=300)
assert second.returncode == 0, second.stderr[-2000:]
assert read_import(import_path)["params"]["compress/lossy_quality"] == 0.25
def test_describe_for_library_with_import_sidecar(tmp_path):
from assetmgr.godot import describe_for_library
root = make_project(tmp_path)
asset = os.path.join(root, "hero.png")
with open(asset, "w") as handle:
handle.write("x")
with open(asset + ".import", "w", encoding="utf-8") as handle:
handle.write(REAL_TEXTURE_IMPORT)
described = describe_for_library(asset)
assert described["importer"] == "texture"
assert described["kind"] == "texture"
assert described["params"]["compress/mode"] == 0
def test_describe_for_library_suffix_fallback(tmp_path):
from assetmgr.godot import describe_for_library
root = make_project(tmp_path)
asset = os.path.join(root, "click.wav")
with open(asset, "w") as handle:
handle.write("x")
described = describe_for_library(asset)
assert described["kind"] == "audio"
assert described["importer"] is None
assert described["params"] == {}
def test_publish_action_dispatch(tmp_path, capsys, monkeypatch):
from test_library_server import TOKEN, start_server
_, base = start_server(tmp_path / "srv")
root = make_project(tmp_path)
asset = os.path.join(root, "hero.png")
with open(asset, "w") as handle:
handle.write("png-bytes")
with open(asset + ".import", "w", encoding="utf-8") as handle:
handle.write(REAL_TEXTURE_IMPORT)
found, _ = discover(GODOT_ACTIONS)
action = next(m for m in found
if m.manifest_id == "godot::publish-to-library")
monkeypatch.delenv("ASSETMGR_LIBRARY_URL", raising=False)
monkeypatch.delenv("ASSETMGR_LIBRARY_TOKEN", raising=False)
assert run_action(action, path=asset,
extra_inputs={"server": base, "token": TOKEN},
context_overrides={"project_path": root}) == 0
out = capsys.readouterr().out
assert "Published" in out and "asset 1" in out
from library.client import pull
dest = os.path.join(str(tmp_path), "fetched.png")
pull(base, TOKEN, 1, dest)
with open(dest, "rb") as handle:
assert handle.read() == b"png-bytes"