* feat(platform): app declarations list every place an app may be installed An app block's location may now be one path or an ordered list. A list item is a path, where a `*` segment stands for a versioned folder and the highest version is tried first, or a mapping naming a location kind: command (PATH), uninstall_registry (InstallLocation plus a file, Windows), app_bundle (/Applications, ~/Applications), flatpak (app id) and snap. The directories behind each kind live in known_dirs. Each kind's OS, key, presence and locator are one LOCATION_KINDS entry in resolver/app.py. The declaration parser validates against that table, so a new kind is one entry instead of three coordinated edits in two modules. With requires.min_version, availability reads the version of every present copy and returns the first that qualifies, so an old copy found first does not hide a newer one; if none qualifies it reports the highest readable version. A Linux block may omit a version source (Linux has none) and is then gated on presence only; Windows and macOS blocks still need one, and a Linux-only declaration cannot set a minimum. Brought over from #129246. The Blender 0.2.0 catalog pin stays out: older clients reject a list location, so it follows a release that ships this. * fix(platform): bad app declarations and vanished registry entries no longer break app lookup (review) A location with a non-string kind raises DeclarationError instead of TypeError. A location's file and key value are checked after stripping, so a leading / or \ or a drive cannot escape the install folder. An uninstall registry entry that cannot be opened or read is skipped instead of ending the scan of its root.
57 lines
1.9 KiB
Python
57 lines
1.9 KiB
Python
"""Directories where tools install outside PATH, grouped by the ecosystem that owns them.
|
|
|
|
Every table in Hermes lives here. A directory literal outside this module fails the ratchet in
|
|
`tests/test_managed_runtime_resolution.py`. Each table is empty on an OS where the ecosystem
|
|
does not install there, so callers compose tables without OS branches.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
|
|
_POSIX = sys.platform != "win32"
|
|
_WIN = sys.platform == "win32"
|
|
|
|
|
|
def homebrew_dirs() -> tuple[str, ...]:
|
|
return ("/opt/homebrew/bin", "/usr/local/bin") if sys.platform == "darwin" else ()
|
|
|
|
|
|
def user_local_bin() -> tuple[str, ...]:
|
|
return ("~/.local/bin",) if _POSIX else ("%USERPROFILE%/.local/bin",)
|
|
|
|
|
|
def rust_tool_dirs() -> tuple[str, ...]:
|
|
return ("~/.cargo/bin",) if _POSIX else ("%USERPROFILE%/.cargo/bin",)
|
|
|
|
|
|
def node_tool_dirs() -> tuple[str, ...]:
|
|
return ("~/.npm-global/bin", "~/.bun/bin", "~/.volta/bin") if _POSIX else ("%APPDATA%/npm", "%USERPROFILE%/.bun/bin", "%LOCALAPPDATA%/Volta/bin")
|
|
|
|
|
|
def hermes_vendored_dirs() -> tuple[str, ...]:
|
|
return ("~/.hermes/bin",) if _POSIX else ("%USERPROFILE%/.hermes/bin",)
|
|
|
|
|
|
def windows_user_program_dirs() -> tuple[str, ...]:
|
|
if not _WIN:
|
|
return ()
|
|
return (
|
|
"%LOCALAPPDATA%/Programs",
|
|
"%USERPROFILE%/scoop/shims",
|
|
"%LOCALAPPDATA%/Microsoft/WinGet/Links",
|
|
)
|
|
|
|
|
|
def mac_application_dirs() -> tuple[str, ...]:
|
|
return ("/Applications", "~/Applications") if sys.platform == "darwin" else ()
|
|
|
|
|
|
def flatpak_export_dirs() -> tuple[str, ...]:
|
|
"""Where flatpak links each installed app's launcher, named by its app id (system, then per-user)."""
|
|
return ("/var/lib/flatpak/exports/bin", "~/.local/share/flatpak/exports/bin") if sys.platform.startswith("linux") else ()
|
|
|
|
|
|
def snap_bin_dirs() -> tuple[str, ...]:
|
|
return ("/snap/bin",) if sys.platform.startswith("linux") else ()
|