mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-02-18 22:20:03 +00:00
This change solves the basename collision bug by using UNIQUE(file_path) on the unified asset_references table. Key changes: Database: - Migration 0005 merges asset_cache_states and asset_infos into asset_references - AssetReference now contains: cache state fields (file_path, mtime_ns, needs_verify, is_missing, enrichment_level) plus info fields (name, owner_id, preview_id, etc.) - AssetReferenceMeta replaces AssetInfoMeta - AssetReferenceTag replaces AssetInfoTag - UNIQUE constraint on file_path prevents duplicate entries for same file Code: - New unified query module: asset_reference.py (replaces asset_info.py, cache_state.py) - Updated scanner, seeder, and services to use AssetReference - Updated API routes to use reference_id instead of asset_info_id Tests: - All 175 unit tests updated and passing - Integration tests require server environment (not run here) Amp-Thread-ID: https://ampcode.com/threads/T-019c4fe8-9dcb-75ce-bea8-ea786343a581 Co-authored-by: Amp <amp@ampcode.com>
55 lines
1.6 KiB
Python
55 lines
1.6 KiB
Python
import os
|
|
from datetime import datetime, timezone
|
|
from typing import Literal, Sequence
|
|
|
|
|
|
def select_best_live_path(states: Sequence) -> str:
|
|
"""
|
|
Return the best on-disk path among cache states:
|
|
1) Prefer a path that exists with needs_verify == False (already verified).
|
|
2) Otherwise, pick the first path that exists.
|
|
3) Otherwise return empty string.
|
|
"""
|
|
alive = [
|
|
s
|
|
for s in states
|
|
if getattr(s, "file_path", None) and os.path.isfile(s.file_path)
|
|
]
|
|
if not alive:
|
|
return ""
|
|
for s in alive:
|
|
if not getattr(s, "needs_verify", False):
|
|
return s.file_path
|
|
return alive[0].file_path
|
|
|
|
|
|
ALLOWED_ROOTS: tuple[Literal["models", "input", "output"], ...] = (
|
|
"models",
|
|
"input",
|
|
"output",
|
|
)
|
|
|
|
|
|
def escape_sql_like_string(s: str, escape: str = "!") -> tuple[str, str]:
|
|
"""Escapes %, _ and the escape char in a LIKE prefix.
|
|
|
|
Returns (escaped_prefix, escape_char).
|
|
"""
|
|
s = s.replace(escape, escape + escape) # escape the escape char first
|
|
s = s.replace("%", escape + "%").replace("_", escape + "_") # escape LIKE wildcards
|
|
return s, escape
|
|
|
|
|
|
def get_utc_now() -> datetime:
|
|
"""Naive UTC timestamp (no tzinfo). We always treat DB datetimes as UTC."""
|
|
return datetime.now(timezone.utc).replace(tzinfo=None)
|
|
|
|
|
|
def normalize_tags(tags: list[str] | None) -> list[str]:
|
|
"""
|
|
Normalize a list of tags by:
|
|
- Stripping whitespace and converting to lowercase.
|
|
- Removing duplicates.
|
|
"""
|
|
return [t.strip().lower() for t in (tags or []) if (t or "").strip()]
|