mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-09-27 05:54:08 -03:00
fix: address review — injective mirror roots, root relocation, full preview coverage, EXDEV-safe rollback
Codex review on #1124: - P1: mirror layout root component is now <basename>-<roothash> (sha256 of the normalized root path), so two roots sharing a basename no longer map to the same mirror directory and overwrite each other's sidecars - P1: changing sidecar_storage_path while centralized no longer strands assets in the old root — new relocate_root migration direction moves the whole mirror tree, rewrites preview_url prefixes inside sidecars, reconciles scanner caches, and prunes the emptied old tree; the settings UI detects the path change and offers the relocation - P2: migration enumerates the same preview candidates as find_preview_file — case-insensitive variants (model.WEBP) and the legacy .example.0.jpeg suffix — instead of exact lowercase PREVIEW_EXTENSIONS only - P2: _rollback_model_staging restores staged files with the EXDEV-tolerant mover, so a failed undoable-delete staging no longer strands a cross-filesystem centralized sidecar copy Tests: same-basename root injectivity, mixed-case/example preview migration, relocate_root happy path + guards + route 400, frontend relocation prompt flow. Verified end-to-end in a sandboxed standalone server: uppercase/legacy previews migrate, root relocation moves the tree and the list API serves the new locations immediately without a rescan.
This commit is contained in:
@@ -2565,8 +2565,8 @@ class DummySidecarMigrationUseCase:
|
||||
self.result = result
|
||||
self.calls = []
|
||||
|
||||
async def execute_with_error_handling(self, *, direction, progress_cb=None, force=False):
|
||||
self.calls.append({"direction": direction, "force": force})
|
||||
async def execute_with_error_handling(self, *, direction, progress_cb=None, force=False, old_root=None):
|
||||
self.calls.append({"direction": direction, "force": force, "old_root": old_root})
|
||||
return self.result
|
||||
|
||||
|
||||
@@ -2592,7 +2592,7 @@ async def test_sidecar_migration_handler_runs_to_centralized():
|
||||
assert response.status == 200
|
||||
assert payload["success"] is True
|
||||
assert payload["moved"] == 3
|
||||
assert use_case.calls == [{"direction": "to_centralized", "force": True}]
|
||||
assert use_case.calls == [{"direction": "to_centralized", "force": True, "old_root": ""}]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -2624,7 +2624,7 @@ async def test_sidecar_migration_handler_accepts_get_query_params():
|
||||
|
||||
assert response.status == 200
|
||||
assert payload["success"] is True
|
||||
assert use_case.calls == [{"direction": "to_alongside", "force": True}]
|
||||
assert use_case.calls == [{"direction": "to_alongside", "force": True, "old_root": ""}]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -2640,4 +2640,41 @@ async def test_sidecar_migration_handler_guard_refusal_is_400():
|
||||
assert response.status == 400
|
||||
assert payload["success"] is False
|
||||
assert "already centralized" in payload["error"]
|
||||
assert use_case.calls == [{"direction": "to_centralized", "force": False}]
|
||||
assert use_case.calls == [{"direction": "to_centralized", "force": False, "old_root": ""}]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sidecar_migration_handler_relocate_root_passes_old_root():
|
||||
result = {"success": True, "direction": "relocate_root", "moved": 5}
|
||||
handler, use_case = _sidecar_migration_handler(result)
|
||||
|
||||
response = await handler.migrate_sidecars(
|
||||
FakeRequest( # pyright: ignore[reportArgumentType]
|
||||
json_data={
|
||||
"direction": "relocate_root",
|
||||
"old_root": "/old/sidecars",
|
||||
"force": True,
|
||||
}
|
||||
)
|
||||
)
|
||||
payload = _json_payload(response)
|
||||
|
||||
assert response.status == 200
|
||||
assert payload["success"] is True
|
||||
assert use_case.calls == [
|
||||
{"direction": "relocate_root", "force": True, "old_root": "/old/sidecars"}
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sidecar_migration_handler_relocate_root_requires_old_root():
|
||||
handler, use_case = _sidecar_migration_handler({"success": True})
|
||||
|
||||
response = await handler.migrate_sidecars(
|
||||
FakeRequest(json_data={"direction": "relocate_root"}) # pyright: ignore[reportArgumentType]
|
||||
)
|
||||
payload = _json_payload(response)
|
||||
|
||||
assert response.status == 400
|
||||
assert "old_root" in payload["error"]
|
||||
assert use_case.calls == []
|
||||
|
||||
Reference in New Issue
Block a user