fix(plugins): a linked plugins/<name> slot reads "already installed", not a bad manifest
A memory provider's own installer (mnemosyne-hermes install, its README's manual `ln -s`) leaves ~/.hermes/plugins/<name> as a symlink into a venv. The catalog install of the same name then failed in _sanitize_plugin_name with "Invalid plugin name 'mnemosyne': resolves outside the plugins directory" and was recorded as failure_class=manifest_invalid, though the catalog manifest is valid (hermes plugins validate passes it). Name the link and its target, say how to free the slot, and record already_installed.
This commit is contained in:
@@ -385,6 +385,15 @@ def _install_plugin_core(
|
||||
manifest = _read_manifest_for_install(tmp_target)
|
||||
plugin_name = manifest.get("name") or (
|
||||
subdir.rstrip("/").rsplit("/", 1)[-1] if subdir else _pc()._repo_name_from_url(git_url))
|
||||
link = plugins_dir / str(plugin_name)
|
||||
from pm.filesystem import is_junction
|
||||
if "/" not in str(plugin_name) and (link.is_symlink() or is_junction(link)):
|
||||
# A provider's own installer (e.g. `mnemosyne-hermes install`) links its package here; the
|
||||
# name is fine, the slot is taken. Say so instead of blaming the manifest.
|
||||
raise _pc().PluginOperationError(
|
||||
f"Plugin '{plugin_name}' is already installed outside the catalog: {link} is a link to "
|
||||
f"{os.path.realpath(link)}. Delete that link to install the catalog version.",
|
||||
failure_class="already_installed")
|
||||
try:
|
||||
target = _pc()._sanitize_plugin_name(plugin_name, plugins_dir)
|
||||
except ValueError as e:
|
||||
|
||||
@@ -85,3 +85,21 @@ def test_manifest_version_above_shared_support_is_refused_cleanly(
|
||||
|
||||
assert not (home / "plugins" / "demo").exists()
|
||||
assert not (home / "plugins" / ".install-metadata.json").exists()
|
||||
|
||||
|
||||
def test_a_linked_plugin_slot_is_already_installed_not_a_bad_manifest(monkeypatch, tmp_path):
|
||||
"""A provider's own installer can leave ``plugins/<name>`` as a link into a venv (mnemosyne-hermes
|
||||
did). The catalog install must say the slot is taken, not record ``manifest_invalid``."""
|
||||
from hermes_cli import plugins_cmd
|
||||
|
||||
monkeypatch.setattr(plugins_cmd, "_scan_on_install_enabled", lambda: False)
|
||||
repo = _plugin_repo(tmp_path, {"name": "demo", "version": "1.0.0"})
|
||||
home = tmp_path / "home"
|
||||
monkeypatch.setenv("HERMES_HOME", str(home))
|
||||
(home / "plugins").mkdir(parents=True)
|
||||
(tmp_path / "elsewhere").mkdir()
|
||||
(home / "plugins" / "demo").symlink_to(tmp_path / "elsewhere", target_is_directory=True)
|
||||
|
||||
with pytest.raises(plugins_cmd.PluginOperationError, match="already installed outside the catalog") as exc:
|
||||
plugins_cmd._install_plugin_core(repo.as_uri(), force=False)
|
||||
assert exc.value.failure_class == "already_installed"
|
||||
|
||||
Reference in New Issue
Block a user