mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-05-30 23:53:32 +00:00
fix(plugin-loader): detect new deps via requirements.txt hash instead of empty marker
The .dependencies_installed marker was an empty file, so adding a new package to requirements.txt (e.g. astral in ledmatrix-weather v2.3.0) never triggered a pip re-install on existing installs — the file existed so the check returned early. The marker now stores a SHA-256 hash of requirements.txt. On every plugin load, the loader compares the current hash to the stored one; a mismatch (or missing marker) triggers pip install and writes the new hash. store_manager._install_dependencies() also writes the hash marker after a store install/update so the loader skips a redundant pip run on next boot. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@ Handles plugin module imports, dependency installation, and class instantiation.
|
|||||||
Extracted from PluginManager to improve separation of concerns.
|
Extracted from PluginManager to improve separation of concerns.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import importlib
|
import importlib
|
||||||
import importlib.util
|
import importlib.util
|
||||||
@@ -164,11 +165,15 @@ class PluginLoader:
|
|||||||
if not requirements_file.exists():
|
if not requirements_file.exists():
|
||||||
return True # No dependencies needed
|
return True # No dependencies needed
|
||||||
marker_path = plugin_dir_resolved / ".dependencies_installed"
|
marker_path = plugin_dir_resolved / ".dependencies_installed"
|
||||||
|
current_hash = hashlib.sha256(requirements_file.read_bytes()).hexdigest()
|
||||||
|
|
||||||
# Check if already installed
|
# Skip if requirements.txt hasn't changed since last install
|
||||||
if marker_path.exists():
|
if marker_path.exists():
|
||||||
self.logger.debug("Dependencies already installed for %s", plugin_id)
|
stored_hash = marker_path.read_text(encoding='utf-8').strip()
|
||||||
|
if stored_hash == current_hash:
|
||||||
|
self.logger.debug("Dependencies already installed for %s (requirements unchanged)", plugin_id)
|
||||||
return True
|
return True
|
||||||
|
self.logger.info("Requirements changed for %s, reinstalling dependencies", plugin_id)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.logger.info("Installing dependencies for plugin %s...", plugin_id)
|
self.logger.info("Installing dependencies for plugin %s...", plugin_id)
|
||||||
@@ -181,9 +186,7 @@ class PluginLoader:
|
|||||||
)
|
)
|
||||||
|
|
||||||
if result.returncode == 0:
|
if result.returncode == 0:
|
||||||
# Mark as installed
|
marker_path.write_text(current_hash, encoding='utf-8')
|
||||||
marker_path.touch()
|
|
||||||
# Set proper file permissions after creating marker
|
|
||||||
ensure_file_permissions(marker_path, get_plugin_file_mode())
|
ensure_file_permissions(marker_path, get_plugin_file_mode())
|
||||||
self.logger.info("Dependencies installed successfully for %s", plugin_id)
|
self.logger.info("Dependencies installed successfully for %s", plugin_id)
|
||||||
return True
|
return True
|
||||||
@@ -199,7 +202,7 @@ class PluginLoader:
|
|||||||
"Assuming they are satisfied: %s",
|
"Assuming they are satisfied: %s",
|
||||||
plugin_id, stderr.strip()
|
plugin_id, stderr.strip()
|
||||||
)
|
)
|
||||||
marker_path.touch()
|
marker_path.write_text(current_hash, encoding='utf-8')
|
||||||
ensure_file_permissions(marker_path, get_plugin_file_mode())
|
ensure_file_permissions(marker_path, get_plugin_file_mode())
|
||||||
return True
|
return True
|
||||||
self.logger.warning(
|
self.logger.warning(
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ Handles plugin discovery, installation, updates, and uninstallation
|
|||||||
from both the official registry and custom GitHub repositories.
|
from both the official registry and custom GitHub repositories.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import hashlib
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import stat
|
import stat
|
||||||
@@ -1755,6 +1756,12 @@ class PluginStoreManager:
|
|||||||
timeout=300
|
timeout=300
|
||||||
)
|
)
|
||||||
self.logger.info(f"Dependencies installed successfully for {plugin_path.name}")
|
self.logger.info(f"Dependencies installed successfully for {plugin_path.name}")
|
||||||
|
# Write hash marker so plugin_loader skips redundant pip run on next startup
|
||||||
|
try:
|
||||||
|
current_hash = hashlib.sha256(requirements_file.read_bytes()).hexdigest()
|
||||||
|
(plugin_path / ".dependencies_installed").write_text(current_hash, encoding='utf-8')
|
||||||
|
except OSError as marker_err:
|
||||||
|
self.logger.debug("Could not write dependency marker for %s: %s", plugin_path.name, marker_err)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
|
|||||||
Reference in New Issue
Block a user