Repair Assistent SQLite natives after extension build completes.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+104
-25
@@ -229,15 +229,27 @@ print(__import__("json").dumps(found))
|
||||
_ASSISTENT_SQLITE_BIN_PY = r"""
|
||||
from pathlib import Path
|
||||
import json
|
||||
skip = {"obj", "node_modules"}
|
||||
|
||||
def assistent_dlls(root: Path):
|
||||
out = []
|
||||
if not root.is_dir():
|
||||
return out
|
||||
for dll in root.rglob("*.dll"):
|
||||
if any(p in skip for p in dll.parts):
|
||||
continue
|
||||
name = dll.name.lower()
|
||||
if name == "swarmassistentextension.dll" or (
|
||||
name.startswith("swarmextensionswarm-assistent") and name.endswith(".dll")
|
||||
):
|
||||
out.append(dll)
|
||||
return out
|
||||
|
||||
roots = [Path("/mnt/swarm_data"), Path("/opt/swarmui")]
|
||||
seen = set()
|
||||
found = []
|
||||
for root in roots:
|
||||
if not root.is_dir():
|
||||
continue
|
||||
for dll in root.rglob("SwarmAssistentExtension.dll"):
|
||||
if any(p in {"obj", "node_modules"} for p in dll.parts):
|
||||
continue
|
||||
for dll in assistent_dlls(root):
|
||||
key = str(dll)
|
||||
if key in seen:
|
||||
continue
|
||||
@@ -247,6 +259,7 @@ for root in roots:
|
||||
pcl = list(dll_dir.glob("SQLitePCLRaw*.dll"))
|
||||
bundle = dll_dir / "SQLitePCLRaw.bundle_e_sqlite3.dll"
|
||||
native = list(dll_dir.glob("runtimes/**/e_sqlite3.*")) + list(dll_dir.glob("runtimes/**/libe_sqlite3.*"))
|
||||
native_flat = list(dll_dir.glob("e_sqlite3.*")) + list(dll_dir.glob("libe_sqlite3.*"))
|
||||
found.append({
|
||||
"path": str(dll.parent.parent) if dll.parent.name.startswith("net") else str(dll_dir),
|
||||
"name": "swarm-assistent",
|
||||
@@ -256,51 +269,84 @@ for root in roots:
|
||||
"sqlitepcl": bool(pcl),
|
||||
"sqlite_bundle": bundle.is_file(),
|
||||
"sqlite_native": bool(native),
|
||||
"sqlite_native_flat": bool(native_flat),
|
||||
})
|
||||
print(json.dumps(found))
|
||||
"""
|
||||
|
||||
_ASSISTENT_SQLITE_REPAIR_PY = r"""
|
||||
from pathlib import Path
|
||||
import json, shutil
|
||||
import json, os, shutil
|
||||
skip = {"obj", "node_modules"}
|
||||
dlls = []
|
||||
for root in (Path("/mnt/swarm_data"), Path("/opt/swarmui")):
|
||||
|
||||
def assistent_dlls(root: Path):
|
||||
out = []
|
||||
if not root.is_dir():
|
||||
continue
|
||||
for dll in root.rglob("SwarmAssistentExtension.dll"):
|
||||
return out
|
||||
for dll in root.rglob("*.dll"):
|
||||
if any(p in skip for p in dll.parts):
|
||||
continue
|
||||
dlls.append(dll)
|
||||
name = dll.name.lower()
|
||||
if name == "swarmassistentextension.dll" or (
|
||||
name.startswith("swarmextensionswarm-assistent") and name.endswith(".dll")
|
||||
):
|
||||
out.append(dll)
|
||||
return out
|
||||
|
||||
def find_native(d: Path):
|
||||
for rel in (
|
||||
Path("runtimes/linux-x64/native/libe_sqlite3.so"),
|
||||
Path("runtimes/linux-x64/native/e_sqlite3.so"),
|
||||
):
|
||||
p = d / rel
|
||||
if p.is_file():
|
||||
return p
|
||||
for p in d.glob("runtimes/**/libe_sqlite3.so"):
|
||||
return p
|
||||
for p in d.glob("runtimes/**/e_sqlite3.so"):
|
||||
return p
|
||||
return None
|
||||
|
||||
def link_native(dest_dir: Path, src: Path):
|
||||
for name in ("libe_sqlite3.so", "e_sqlite3.so"):
|
||||
out = dest_dir / name
|
||||
if out.exists() or out.is_symlink():
|
||||
continue
|
||||
try:
|
||||
os.symlink(src, out)
|
||||
except OSError:
|
||||
shutil.copy2(src, out)
|
||||
|
||||
dlls = []
|
||||
for root in (Path("/mnt/swarm_data"), Path("/opt/swarmui")):
|
||||
dlls.extend(assistent_dlls(root))
|
||||
|
||||
def has_sqlite(d):
|
||||
if not (d / "Microsoft.Data.Sqlite.dll").is_file():
|
||||
return False
|
||||
if not list(d.glob("SQLitePCLRaw*.dll")):
|
||||
return False
|
||||
return (d / "SQLitePCLRaw.bundle_e_sqlite3.dll").is_file() or list(
|
||||
d.glob("runtimes/**/e_sqlite3.*")
|
||||
) or list(d.glob("runtimes/**/libe_sqlite3.*"))
|
||||
if (d / "libe_sqlite3.so").is_file() or (d / "e_sqlite3.so").is_file():
|
||||
return True
|
||||
return bool(list(d.glob("runtimes/**/libe_sqlite3.*")) or list(d.glob("runtimes/**/e_sqlite3.*")))
|
||||
|
||||
donors = [d.parent for d in dlls if has_sqlite(d.parent)]
|
||||
if not donors:
|
||||
nuget = Path.home() / ".nuget" / "packages"
|
||||
extra = []
|
||||
if nuget.is_dir():
|
||||
extra.extend(nuget.rglob("Microsoft.Data.Sqlite.dll"))
|
||||
extra.extend(nuget.rglob("SQLitePCLRaw.core.dll"))
|
||||
# last resort: any copy on the disk under swarm
|
||||
for root in (Path("/opt/swarmui"), Path("/root/.nuget")):
|
||||
if root.is_dir():
|
||||
extra.extend(root.rglob("Microsoft.Data.Sqlite.dll"))
|
||||
for f in extra:
|
||||
for f in nuget.rglob("Microsoft.Data.Sqlite.dll"):
|
||||
if f.parent not in donors:
|
||||
donors.append(f.parent)
|
||||
|
||||
copied = []
|
||||
linked = []
|
||||
missing = []
|
||||
for dll in dlls:
|
||||
dest = dll.parent
|
||||
native = find_native(dest)
|
||||
if native is not None:
|
||||
link_native(dest, native)
|
||||
linked.append({"dll_dir": str(dest), "native": str(native)})
|
||||
if has_sqlite(dest):
|
||||
continue
|
||||
src = next((d for d in donors if d != dest and has_sqlite(d)), None)
|
||||
@@ -311,7 +357,6 @@ for dll in dlls:
|
||||
continue
|
||||
names = ["Microsoft.Data.Sqlite.dll"]
|
||||
names += [p.name for p in src.glob("SQLitePCLRaw*.dll")]
|
||||
names += [p.name for p in src.glob("e_sqlite3.*")]
|
||||
for name in names:
|
||||
fp = src / name
|
||||
if fp.is_file():
|
||||
@@ -326,7 +371,11 @@ for dll in dlls:
|
||||
out.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copy2(fp, out)
|
||||
copied.append({"dll_dir": str(dest), "from": str(src)})
|
||||
print(json.dumps({"copied": copied, "missing": missing, "dlls": [str(d) for d in dlls]}))
|
||||
n2 = find_native(dest)
|
||||
if n2 is not None:
|
||||
link_native(dest, n2)
|
||||
linked.append({"dll_dir": str(dest), "native": str(n2)})
|
||||
print(json.dumps({"copied": copied, "linked": linked, "missing": missing, "dlls": [str(d) for d in dlls]}))
|
||||
"""
|
||||
|
||||
|
||||
@@ -394,10 +443,14 @@ def repair_assistent_sqlite_bins(cfg: Config, host: str, log: Log) -> bool:
|
||||
return False
|
||||
for row in copied:
|
||||
log(f"Assistent Sqlite: скопировал рядом с {row.get('dll_dir')}")
|
||||
for row in data.get("linked") or []:
|
||||
log(f"Assistent Sqlite: symlink native → {row.get('dll_dir')}")
|
||||
for path in missing:
|
||||
log(f"⚠ Assistent Sqlite: нет donor DLL для {path}")
|
||||
if copied:
|
||||
return True
|
||||
if data.get("linked"):
|
||||
return True
|
||||
if not missing:
|
||||
log("Assistent Sqlite: private deps уже рядом с DLL")
|
||||
return True
|
||||
@@ -435,7 +488,7 @@ def verify_assistent_sqlite_bins(cfg: Config, host: str, log: Log) -> bool:
|
||||
)
|
||||
continue
|
||||
if row.get("sqlite_dll") and row.get("sqlitepcl") and (
|
||||
row.get("sqlite_bundle") or row.get("sqlite_native")
|
||||
row.get("sqlite_bundle") or row.get("sqlite_native") or row.get("sqlite_native_flat")
|
||||
):
|
||||
log(f"Assistent {name}: Microsoft.Data.Sqlite + SQLitePCLRaw (+ native) рядом с DLL")
|
||||
ok_any = True
|
||||
@@ -1387,13 +1440,39 @@ def ensure_swarmui_running(cfg: Config, host: str, log: Log, restart: bool) -> N
|
||||
if restart and active == "active":
|
||||
log("systemctl restart swarmui (новые extensions/autocomplete)")
|
||||
run_ssh(cfg, host, "sudo -n systemctl restart swarmui", timeout=120)
|
||||
_wait_swarmui_extension_build(cfg, host, log)
|
||||
return
|
||||
if active != "active":
|
||||
log("systemctl start swarmui")
|
||||
run_ssh(cfg, host, "sudo -n systemctl start swarmui", timeout=120)
|
||||
_wait_swarmui_extension_build(cfg, host, log)
|
||||
run_ssh(cfg, host, "sudo -n systemctl enable swarmui", check=False)
|
||||
|
||||
|
||||
def _wait_swarmui_extension_build(cfg: Config, host: str, log: Log, timeout_sec: int = 120) -> None:
|
||||
"""Wait until SwarmUI compiles extensions (Assistent DLL appears in bin/extensions)."""
|
||||
import time
|
||||
|
||||
deadline = time.monotonic() + timeout_sec
|
||||
while time.monotonic() < deadline:
|
||||
try:
|
||||
raw = run_ssh(
|
||||
cfg,
|
||||
host,
|
||||
"python3 - <<'PY'\n" + _ASSISTENT_SQLITE_BIN_PY + "\nPY",
|
||||
check=False,
|
||||
timeout=25,
|
||||
).strip()
|
||||
rows = json.loads(raw.splitlines()[-1]) if raw else []
|
||||
if isinstance(rows, list) and rows and any(r.get("dll") for r in rows):
|
||||
log("SwarmUI: extension DLL готов")
|
||||
return
|
||||
except Exception:
|
||||
pass
|
||||
time.sleep(5)
|
||||
log("⚠ SwarmUI: extension DLL не появился за 2 мин — repair Sqlite может не сработать")
|
||||
|
||||
|
||||
_OLLAMA_TAGS_PY = r"""
|
||||
import json, urllib.request
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user