mirror of
https://github.com/thunderheronight/splat-workshop.git
synced 2026-10-17 12:01:30 +02:00
Folder names without a trailing dot (NTFS refuses them)
Found moving the runs to an NTFS disk: the tour "Rundgang 12.10." (folder Rundgang-12.10.) was not copied. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3cf0e81aef
commit
fccaf4afc6
4 files changed
+30
-7
No files matched your search
@@ -2,6 +2,12 @@
|
||||
|
||||
All notable changes to Splat Workshop. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), versions follow [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Folder names without a dot at the end**: a name like "Tour 12.10." gave the folder `Tour-12.10.`, which Windows file systems (NTFS, e.g. a second disk the runs are moved to) refuse – the copy silently lacked that tour. Now it is `Tour-12.10`. Existing folders keep their names.
|
||||
|
||||
## [0.3.0] – 2026-10-15
|
||||
|
||||
### Added
|
||||
|
||||
@@ -76,7 +76,8 @@ class Config:
|
||||
|
||||
|
||||
def slugify(name: str) -> str:
|
||||
"""Folder/file name from a display name: ä→ae etc., accents dropped, only [A-Za-z0-9._-]."""
|
||||
"""Folder/file name from a display name: ä→ae etc., accents dropped, only [A-Za-z0-9._-]; no dot or
|
||||
dash at the ends ("Tour 12.10." → Tour-12.10: Windows file systems such as NTFS refuse a trailing dot)."""
|
||||
for a, b in (("ä", "ae"), ("ö", "oe"), ("ü", "ue"), ("Ä", "Ae"), ("Ö", "Oe"), ("Ü", "Ue"), ("ß", "ss")):
|
||||
name = name.replace(a, b)
|
||||
name = unicodedata.normalize("NFKD", name).encode("ascii", "ignore").decode()
|
||||
@@ -88,7 +89,7 @@ def slugify(name: str) -> str:
|
||||
elif not dash:
|
||||
out.append("-")
|
||||
dash = True
|
||||
return "".join(out).strip("-")
|
||||
return "".join(out).strip("-.")
|
||||
|
||||
|
||||
def _merge(base: dict, over: dict) -> dict:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"""Groups of scenes: one group per scene, suggestions, renaming, cleaning up together."""
|
||||
import json
|
||||
import pytest
|
||||
|
||||
from conftest import RUNS, server
|
||||
import synth
|
||||
@@ -78,3 +79,18 @@ def test_dissolving_a_group_keeps_its_scenes(api):
|
||||
assert api.post("/api/delete", {"slug": "Home"})[0] == 200
|
||||
assert api.get("/api/groups")[1]["groups"] == []
|
||||
assert {"Kitchen", "Hallway", "Statue"} <= {s["slug"] for s in server.scenes()}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name,slug", [("Rundgang 12.10.", "Rundgang-12.10"), ("Küche", "Kueche"),
|
||||
("...", ""), (".hidden", "hidden"), ("Flur 2", "Flur-2")])
|
||||
def test_folder_names_suit_every_file_system(name, slug):
|
||||
"""No dot at the end: NTFS (e.g. runs on a Windows disk) refuses it, and the copy loses the tour."""
|
||||
from splat_workshop import config
|
||||
assert config.slugify(name) == slug
|
||||
|
||||
|
||||
def test_a_tour_named_with_a_date_gets_a_folder_ntfs_accepts(api):
|
||||
synth.make_room(RUNS, "Kitchen", "A", name="Kitchen")
|
||||
synth.make_room(RUNS, "Hall", "B", name="Hall")
|
||||
status, r = api.post("/api/group", {"name": "Tour 12.10.", "members": "Kitchen,Hall"})
|
||||
assert status == 200 and r["slug"] == "Tour-12.10"
|
||||
@@ -23,13 +23,13 @@ def test_renaming_moves_folder_files_and_log(api):
|
||||
(run / "aufnahme-12.10.-16-40.gallery.png").write_bytes(b"x")
|
||||
status, r = api.post("/api/rename", {"slug": "Aufnahme-12.10.-16-40", "new": "Büro 12.10."})
|
||||
assert status == 200, r
|
||||
new = RUNS / "Buero-12.10."
|
||||
new = RUNS / "Buero-12.10"
|
||||
assert new.is_dir() and not run.exists()
|
||||
assert (new / "buero-12.10..sog").exists() and (new / "buero-12.10..gallery.png").exists()
|
||||
assert (RUNS / "Buero-12.10..log").exists() and not (RUNS / "Aufnahme-12.10.-16-40.log").exists()
|
||||
meta = json.loads((RUNS / "Buero-12.10..ui.json").read_text())
|
||||
assert (new / "buero-12.10.sog").exists() and (new / "buero-12.10.gallery.png").exists()
|
||||
assert (RUNS / "Buero-12.10.log").exists() and not (RUNS / "Aufnahme-12.10.-16-40.log").exists()
|
||||
meta = json.loads((RUNS / "Buero-12.10.ui.json").read_text())
|
||||
assert meta["name"] == "Büro 12.10." and meta["folder_renamed"] is True
|
||||
assert server.no_resume("Buero-12.10.") == "renamed" # the pipeline remembers the old path
|
||||
assert server.no_resume("Buero-12.10") == "renamed" # the pipeline remembers the old path
|
||||
|
||||
|
||||
def test_renaming_to_a_taken_name_is_refused(api):
|
||||
|
||||
Reference in new issue
Block a user