mirror of
https://github.com/Heretek-AI/Asset-Manager.git
synced 2026-11-07 10:45:57 -10:00
godot::publish-to-library action with import-setting passthrough
This commit is contained in:
1 parent
9ab3bb8afd
commit
660b3053dc
4 files changed
+164
-1
No files matched your search
@@ -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 ""))
|
||||
@@ -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
|
||||
@@ -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
@@ -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"
|
||||
Reference in new issue
Block a user