From bf8a6b7b5626c6eed6648c3d1b04d97ed47701c4 Mon Sep 17 00:00:00 2001 From: Xavier Karma Date: Fri, 6 Nov 2026 18:25:17 +0530 Subject: [PATCH] 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. --- src/vocalinux/app_identity.py | 57 ++++++++++++++++++---------------- src/vocalinux/legacy_import.py | 39 ++++++++++------------- src/vocalinux/main.py | 2 +- 3 files changed, 48 insertions(+), 50 deletions(-) diff --git a/src/vocalinux/app_identity.py b/src/vocalinux/app_identity.py index 4a97bc8..cbce773 100644 --- a/src/vocalinux/app_identity.py +++ b/src/vocalinux/app_identity.py @@ -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" diff --git a/src/vocalinux/legacy_import.py b/src/vocalinux/legacy_import.py index 8e1d1b8..760b71e 100644 --- a/src/vocalinux/legacy_import.py +++ b/src/vocalinux/legacy_import.py @@ -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): diff --git a/src/vocalinux/main.py b/src/vocalinux/main.py index 0cafaaa..f6e479e 100644 --- a/src/vocalinux/main.py +++ b/src/vocalinux/main.py @@ -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: