refactor(identity): derive identity strings from one slug; tidy legacy import

Every lowercase identity constant is now derived from a single _SLUG, so
a rename is one edit. The values are unchanged (checked against
origin/main for all 33 constants and the user agent).

legacy_import: drop the unused subdirectory field from the payload
tuples, merge the four near-identical directory helpers, and use the
identity constants directly instead of aliases.

Docstrings: the retained package is vocalinux, not voculinux; the
one-time import is described as a legacy Vocalinux install.
This commit is contained in:
2026-11-06 18:25:17 +05:30
parent e6fdb3be9b
commit bf8a6b7b56
3 changed files with 48 additions and 50 deletions
+31 -26
View File
@@ -2,45 +2,50 @@
Ticket #18 rename: every user-visible identity string that is hardcoded in
more than one place is driven from this single module. The fork takes its
own name everywhere a user can see it; the internal ``voculinux`` Python
package name is retained (see :data:`RETAINED_SURFACES`) and unrelated to
these values.
own name everywhere a user can see it. The Python import package name
``vocalinux`` is retained internally (see :data:`RETAINED_SURFACES`) and is
unrelated to these values.
One-time legacy import of a previous Voculinux install lives in
:mod:`vocalinux.legacy_import` and keys off :data:`LEGACY_APP_DIR_NAME`.
"""
#: The one place the lowercase fork slug is spelled. Every lowercase identity
#: below is derived from it, so a rename is one edit here plus the surfaces
#: listed in RENAME_SURFACES.
_SLUG: str = "voculinux"
APP_NAME: str = "Voculinux"
APP_ID: str = "voculinux"
APP_DIR_NAME: str = "voculinux"
CLI_PROG: str = "voculinux"
APP_ID: str = _SLUG
APP_DIR_NAME: str = _SLUG
CLI_PROG: str = _SLUG
BUS_NAME: str = "com.voculinux.Voculinux"
OBJECT_PATH: str = "/com/voculinux/Voculinux"
INTERFACE_NAME: str = "com.voculinux.Voculinux"
BUS_NAME: str = f"com.{_SLUG}.Voculinux"
OBJECT_PATH: str = f"/com/{_SLUG}/Voculinux"
INTERFACE_NAME: str = f"com.{_SLUG}.Voculinux"
DESKTOP_FILENAME: str = "voculinux.desktop"
DESKTOP_ICON_NAME: str = "voculinux"
DESKTOP_FILENAME: str = f"{_SLUG}.desktop"
DESKTOP_ICON_NAME: str = _SLUG
TRAY_TITLE: str = APP_NAME
ICON_DEFAULT: str = "voculinux-microphone-off"
ICON_ACTIVE: str = "voculinux-microphone"
ICON_PROCESSING: str = "voculinux-microphone-process"
ICON_DEFAULT: str = f"{_SLUG}-microphone-off"
ICON_ACTIVE: str = f"{_SLUG}-microphone"
ICON_PROCESSING: str = f"{_SLUG}-microphone-process"
ICON_BASE_NAMES: tuple[str, ...] = (
"voculinux",
_SLUG,
ICON_ACTIVE,
ICON_DEFAULT,
ICON_PROCESSING,
)
ENGINE_NAME: str = "voculinux"
ENGINE_LONGNAME: str = "Voculinux"
ENGINE_DESCRIPTION: str = "Voculinux voice dictation (use as default input method)"
COMPONENT_NAME: str = "org.freedesktop.IBus.Voculinux"
IBUS_DIR_NAME: str = "voculinux-ibus"
IBUS_TEXTDOMAIN: str = "voculinux"
ENGINE_NAME: str = _SLUG
ENGINE_LONGNAME: str = APP_NAME
ENGINE_DESCRIPTION: str = f"{APP_NAME} voice dictation (use as default input method)"
COMPONENT_NAME: str = f"org.freedesktop.IBus.{APP_NAME}"
IBUS_DIR_NAME: str = f"{_SLUG}-ibus"
IBUS_TEXTDOMAIN: str = _SLUG
UPDATE_CHECKER_USER_AGENT: str = "Voculinux-UpdateChecker"
UPDATE_CHECKER_USER_AGENT: str = f"{APP_NAME}-UpdateChecker"
def user_agent(version: str) -> str:
@@ -48,11 +53,11 @@ def user_agent(version: str) -> str:
return f"{APP_ID}/{version}"
RESOURCE_DIR_NAME: str = "voculinux"
RESOURCE_DIR_NAME: str = _SLUG
VERIFICATION_STAMP_NAME: str = ".voculinux_verified"
LOG_FILE_PREFIX: str = "voculinux_logs_"
PORTAL_TOKEN_PREFIX: str = "voculinux_"
VERIFICATION_STAMP_NAME: str = f".{_SLUG}_verified"
LOG_FILE_PREFIX: str = f"{_SLUG}_logs_"
PORTAL_TOKEN_PREFIX: str = f"{_SLUG}_"
ENV_FORCE_BACKEND: str = "VOCULINUX_FORCE_BACKEND"
ENV_INJECT_MODIFIER_WAIT: str = "VOCULINUX_INJECT_MODIFIER_WAIT"
+16 -23
View File
@@ -18,50 +18,43 @@ from .app_identity import APP_DIR_NAME, LEGACY_APP_DIR_NAME
logger = logging.getLogger(__name__)
#: Directory basenames, deliberately literal: the legacy name must keep
#: resolving to the old install even after the rename.
LEGACY_CONFIG_DIRNAME: str = LEGACY_APP_DIR_NAME
NEW_CONFIG_DIRNAME: str = APP_DIR_NAME
CONFIG_FILENAME: str = "config.json"
TERMS_FILENAME: str = "dictionary.txt"
CORRECTIONS_FILENAME: str = "custom-dictionary-corrections.json"
RESTORE_TOKEN_FILENAME: str = "remote_desktop_restore_token"
#: ``(subdirectory, filename)`` pairs copied ``config -> config`` or
#: ``data -> data``. Models are deliberately absent: they re-resolve through
#: the pinned-checksum download path instead of being migrated.
CONFIG_PAYLOAD: tuple[tuple[str, str], ...] = (
("", CONFIG_FILENAME),
("", TERMS_FILENAME),
("", CORRECTIONS_FILENAME),
)
DATA_PAYLOAD: tuple[tuple[str, str], ...] = (("", RESTORE_TOKEN_FILENAME),)
#: Files copied from the legacy configuration directory. Models are
#: deliberately absent: they re-resolve through the pinned-checksum download
#: path instead of being migrated.
CONFIG_PAYLOAD: tuple[str, ...] = (CONFIG_FILENAME, TERMS_FILENAME, CORRECTIONS_FILENAME)
#: Files copied from the legacy data directory.
DATA_PAYLOAD: tuple[str, ...] = (RESTORE_TOKEN_FILENAME,)
def _xdg_dir(env_var: str, fallback: str) -> str:
"""Return an XDG base directory (empty values treated as unset)."""
return os.environ.get(env_var) or os.path.expanduser(fallback)
def _app_dir(xdg_env_var: str, xdg_fallback: str, app_dir_name: str) -> str:
"""Return an application directory under an XDG base (empty values unset)."""
base = os.environ.get(xdg_env_var) or os.path.expanduser(xdg_fallback)
return os.path.join(base, app_dir_name)
def legacy_config_dir() -> str:
"""Return the previous Vocalinux configuration directory."""
return os.path.join(_xdg_dir("XDG_CONFIG_HOME", "~/.config"), LEGACY_CONFIG_DIRNAME)
return _app_dir("XDG_CONFIG_HOME", "~/.config", LEGACY_APP_DIR_NAME)
def new_config_dir() -> str:
"""Return the Voculinux configuration directory."""
return os.path.join(_xdg_dir("XDG_CONFIG_HOME", "~/.config"), NEW_CONFIG_DIRNAME)
return _app_dir("XDG_CONFIG_HOME", "~/.config", APP_DIR_NAME)
def legacy_data_dir() -> str:
"""Return the previous Vocalinux data directory."""
return os.path.join(_xdg_dir("XDG_DATA_HOME", "~/.local/share"), LEGACY_CONFIG_DIRNAME)
return _app_dir("XDG_DATA_HOME", "~/.local/share", LEGACY_APP_DIR_NAME)
def new_data_dir() -> str:
"""Return the Voculinux data directory."""
return os.path.join(_xdg_dir("XDG_DATA_HOME", "~/.local/share"), NEW_CONFIG_DIRNAME)
return _app_dir("XDG_DATA_HOME", "~/.local/share", APP_DIR_NAME)
def _copy_once(src: str, dst: str) -> bool:
@@ -103,14 +96,14 @@ def import_legacy_once() -> list[str]:
return []
imported: list[str] = []
for _subdir, filename in CONFIG_PAYLOAD:
for filename in CONFIG_PAYLOAD:
src = os.path.join(legacy_config, filename)
dst = os.path.join(new_config_dir(), filename)
if _copy_once(src, dst):
imported.append(dst)
legacy_data = legacy_data_dir()
if os.path.isdir(legacy_data):
for _subdir, filename in DATA_PAYLOAD:
for filename in DATA_PAYLOAD:
src = os.path.join(legacy_data, filename)
dst = os.path.join(new_data_dir(), filename)
if _copy_once(src, dst):
+1 -1
View File
@@ -394,7 +394,7 @@ def main():
# Register cleanup to release lock on exit
atexit.register(single_instance.release_lock)
# One-time legacy Voculinux import (ticket #18): copies a previous
# One-time legacy Vocalinux import (ticket #18): copies a previous
# install's config, dictionary, and portal token into the new locations
# before anything reads them. No-op on every later run.
try: