feat(identity): rename user-visible identity to voculinux with one-time legacy import

The fork takes its own name everywhere a user can see it: binaries
(voculinux, voculinux-gui), desktop entry, autostart, tray, D-Bus
namespace (com.voculinux.Voculinux, no alias for the old name),
config/data/cache dirs, single-instance lock, IBus engine identity,
tray icons, resource prefixes, VOCULINUX_* environment names, and the
update-checker user agent. The internal Python module stays vocalinux
and the distribution metadata keeps the upstream URLs as provenance.

On first run a previous Vocalinux install's config.json, custom
dictionary, and portal restore token are copied once into the new
locations (new config always wins, no merge, no write-back); models
re-resolve through the pinned-checksum download path. An offline
naming-sweep test proves no old-name strings remain on user-visible
surfaces outside the allowlist.

Refs #18
This commit is contained in:
soubarnak
2026-11-06 01:29:39 +05:30
parent c565e6d946
commit ea7be5f111
251 changed files with 2449 additions and 1991 deletions
+18 -18
View File
@@ -6,35 +6,35 @@ import yaml
REPO_ROOT = Path(__file__).resolve().parents[1]
SNAPCRAFT_YAML = REPO_ROOT / "snap" / "snapcraft.yaml"
DESKTOP_FILE = REPO_ROOT / "snap" / "gui" / "vocalinux.desktop"
SNAP_PNG = REPO_ROOT / "snap" / "gui" / "vocalinux.png"
DESKTOP_FILE = REPO_ROOT / "snap" / "gui" / "voculinux.desktop"
SNAP_PNG = REPO_ROOT / "snap" / "gui" / "voculinux.png"
def test_snapcraft_recipe_and_gui_assets() -> None:
assert SNAPCRAFT_YAML.is_file()
doc = yaml.safe_load(SNAPCRAFT_YAML.read_text(encoding="utf-8"))
assert doc["name"] == "vocalinux"
assert doc["name"] == "voculinux"
assert doc["base"] == "core24"
assert doc["summary"] == "Free offline voice dictation for Linux"
assert doc["license"] == "AGPL-3.0-only"
assert doc["icon"] == "snap/gui/vocalinux.png"
assert doc["website"] == "https://vocalinux.com"
assert doc["icon"] == "snap/gui/voculinux.png"
assert doc["website"] == "https://voculinux.com"
assert doc["confinement"] == "strict"
assert doc["grade"] == "stable"
plugs = set((doc.get("apps") or {}).get("vocalinux", {}).get("plugs") or [])
plugs = set((doc.get("apps") or {}).get("voculinux", {}).get("plugs") or [])
assert "raw-input" in plugs
assert "hardware-observe" in plugs
assert "audio-record" in plugs
# The Store denied the super-privileged uinput grant; the plug (and the
# uinput-only ydotool) must stay out or every revision is held in review.
assert "uinput" not in plugs
stage = doc["parts"]["vocalinux"].get("stage-packages") or []
stage = doc["parts"]["voculinux"].get("stage-packages") or []
assert "ydotool" not in stage
recipe_text = SNAPCRAFT_YAML.read_text(encoding="utf-8")
assert "sudo snap connect vocalinux:raw-input" in recipe_text
assert "sudo snap connect vocalinux:hardware-observe" in recipe_text
assert "sudo snap connect voculinux:raw-input" in recipe_text
assert "sudo snap connect voculinux:hardware-observe" in recipe_text
assert DESKTOP_FILE.is_file()
assert SNAP_PNG.is_file()
@@ -50,7 +50,7 @@ def test_snap_puts_gnome_platform_first_on_ld_library_path() -> None:
come first or About-page SVGs fail with "Image type svg is not supported".
"""
doc = yaml.safe_load(SNAPCRAFT_YAML.read_text(encoding="utf-8"))
env = (doc.get("apps") or {}).get("vocalinux", {}).get("environment") or {}
env = (doc.get("apps") or {}).get("voculinux", {}).get("environment") or {}
ld_path = env.get("LD_LIBRARY_PATH")
assert isinstance(ld_path, str)
assert ld_path.startswith("$SNAP/gnome-platform/usr/lib/$CRAFT_ARCH_TRIPLET:")
@@ -63,8 +63,8 @@ def test_snap_docs_tell_users_to_connect_hardware_observe() -> None:
install = (REPO_ROOT / "docs" / "INSTALL.md").read_text(encoding="utf-8")
snapcraft = SNAPCRAFT_YAML.read_text(encoding="utf-8")
for text in (readme, install, snapcraft):
assert "sudo snap connect vocalinux:raw-input" in text
assert "sudo snap connect vocalinux:hardware-observe" in text
assert "sudo snap connect voculinux:raw-input" in text
assert "sudo snap connect voculinux:hardware-observe" in text
def test_snap_docs_explain_typing_without_uinput_plug() -> None:
@@ -88,13 +88,13 @@ def test_snap_preserves_metadata_and_uses_gnome_gi() -> None:
"""GI comes from GNOME without rewriting project dependencies."""
text = SNAPCRAFT_YAML.read_text(encoding="utf-8")
doc = yaml.safe_load(text)
part = doc["parts"]["vocalinux"]
part = doc["parts"]["voculinux"]
assert part["plugin"] == "nil"
assert "python-packages" not in part
assert "sed -i" not in part["override-pull"]
assert "snap/local/build.py" in part["override-build"]
assert "craftctl default" not in part["override-build"]
stage = doc["parts"]["vocalinux"].get("stage-packages") or []
stage = doc["parts"]["voculinux"].get("stage-packages") or []
assert "python3-gi" not in stage
assert "python3-gi-cairo" not in stage
@@ -143,7 +143,7 @@ def test_release_notes_document_snap_sideload() -> None:
assert "snap install --dangerous" in body
assert "RemoteDesktop portal" in body
assert "no `uinput` plug" in body
assert "vocalinux_${{ steps.get_version.outputs.VERSION }}_amd64.snap" in body
assert "voculinux_${{ steps.get_version.outputs.VERSION }}_amd64.snap" in body
def test_snap_backfill_workflow_attests_only_the_snap() -> None:
@@ -179,11 +179,11 @@ def test_snap_promote_dispatch_gates_stable_on_candidate() -> None:
"""stable is the gated option of #783: a manual dispatch releasing the candidate revision."""
text = (REPO_ROOT / ".github" / "workflows" / "snap-promote.yml").read_text(encoding="utf-8")
assert "workflow_dispatch:" in text
assert 'snapcraft release vocalinux "$REVISION" latest/stable' in text
assert 'snapcraft release voculinux "$REVISION" latest/stable' in text
assert "SNAPCRAFT_STORE_CREDENTIALS is unset; cannot promote the snap" in text
assert "environment:" in text
# The promote must prove the candidate revision carries the tag's version.
assert "snapcraft status vocalinux" in text
assert "snapcraft status voculinux" in text
assert 'if [ "$seen_version" != "$VERSION" ]' in text
@@ -222,7 +222,7 @@ def test_snap_builds_pywhispercpp_at_the_portable_baseline() -> None:
alone leaves them all on."""
doc = yaml.safe_load(SNAPCRAFT_YAML.read_text(encoding="utf-8"))
env: dict = {}
for entry in doc["parts"]["vocalinux"].get("build-environment") or []:
for entry in doc["parts"]["voculinux"].get("build-environment") or []:
env.update(entry)
build = (REPO_ROOT / "snap/local/build.py").read_text()
assert '"--no-binary=pywhispercpp"' in build