Oops, I broke it. Hopefully cthulhu will actually run again.

This commit is contained in:
Storm Dragon 2025-04-03 21:14:20 -04:00
parent fd2e782b5b
commit 7ef8ea8ce3
2 changed files with 98 additions and 16 deletions

View File

@ -610,8 +610,19 @@ def loadUserSettings(script=None, inputEvent=None, skipReloadMessage=False):
_storeXmodmap(_cthulhuModifiers)
_createCthulhuXmodmap()
activePlugins = list(_settingsManager.getSetting('activePlugins'))
cthulhuApp.getPluginSystemManager().setActivePlugins(activePlugins)
# Safe plugin initialization
try:
debug.printMessage(debug.LEVEL_INFO, 'CTHULHU: Loading plugins', True)
pluginManager = cthulhuApp.getPluginSystemManager()
pluginManager.rescanPlugins() # First scan for available plugins
activePlugins = list(_settingsManager.getSetting('activePlugins'))
debug.printMessage(debug.LEVEL_INFO, f'CTHULHU: Setting active plugins: {activePlugins}', True)
pluginManager.setActivePlugins(activePlugins)
except Exception as e:
debug.printMessage(debug.LEVEL_WARNING, f'CTHULHU: Error loading plugins: {e}', True)
import traceback
debug.printMessage(debug.LEVEL_INFO, traceback.format_exc(), True)
_scriptManager.activate()
_eventManager.activate()
@ -1018,8 +1029,7 @@ class Cthulhu(GObject.Object):
self.APIHelper = APIHelper(self)
self.createCompatAPI()
self.pluginSystemManager = plugin_system_manager.PluginSystemManager(self)
# Scan for available plugins at startup
self.pluginSystemManager.rescanPlugins()
# DO NOT scan for plugins during initialization - will be done later in loadUserSettings
def getAPIHelper(self):
return self.APIHelper
def getPluginSystemManager(self):

View File

@ -222,7 +222,8 @@ class PluginSystemManager:
# Simple regex-like search for class definition that inherits from Plugin
import re
matches = re.findall(r'class\s+(\w+)\s*\([^)]*Plugin[^)]*\)', content)
# Simpler regex to reduce chance of regex hang
matches = re.findall(r'class\s+(\w+).*Plugin', content)
if matches:
return matches[0]
except Exception as e:
@ -271,11 +272,25 @@ class PluginSystemManager:
logger.info(f"Active plugins: {self._active_plugins}")
# Find missing plugins
missing_plugins = [p for p in self._active_plugins if p not in available_plugins]
missing_plugins = [p for p in self._active_plugins if p not in available_plugins and p.lower() not in [x.lower() for x in available_plugins]]
if missing_plugins:
logger.warning(f"Active plugins not found: {missing_plugins}")
self.syncAllPluginsActive()
# Start plugin activation in a background thread
import threading
def activate_plugins_thread():
try:
self.syncAllPluginsActive()
except Exception as e:
logger.error(f"Error activating plugins: {e}")
import traceback
logger.error(traceback.format_exc())
# Start a background thread for plugin activation
thread = threading.Thread(target=activate_plugins_thread)
thread.daemon = True
thread.start()
logger.info("Plugin activation started in background thread")
def setPluginActive(self, pluginInfo, active):
"""Set the active state of a plugin."""
@ -335,12 +350,20 @@ class PluginSystemManager:
logger.warning("Pluggy not available, skipping plugin sync")
return
# Don't do anything if there are no plugins
if not self.plugins:
logger.warning("No plugins found, skipping plugin sync")
return
# Log plugin status before syncing
if PLUGIN_DEBUG:
for pluginInfo in self.plugins:
is_active = self.isPluginActive(pluginInfo)
is_loaded = pluginInfo.loaded
logger.debug(f"Plugin {pluginInfo.get_module_name()}: active={is_active}, loaded={is_loaded}")
try:
is_active = self.isPluginActive(pluginInfo)
is_loaded = pluginInfo.loaded
logger.debug(f"Plugin {pluginInfo.get_module_name()}: active={is_active}, loaded={is_loaded}")
except Exception as e:
logger.error(f"Error checking plugin status: {e}")
try:
# First unload inactive plugins
@ -368,13 +391,52 @@ class PluginSystemManager:
def loadPlugin(self, pluginInfo):
"""Load a plugin."""
# Skip if pluggy is not available
if not PLUGGY_AVAILABLE:
logger.info(f"Skipping plugin {pluginInfo.get_name()}: pluggy not available")
return False
# Set a reasonable timeout for plugin loading - 10 seconds
import threading
import time
# Create an event to signal when loading is done
load_complete = threading.Event()
result = [False] # Use a list to store result from the thread
# Create a thread to load the plugin
def load_plugin_thread():
try:
# Skip if pluggy is not available
if not PLUGGY_AVAILABLE:
logger.info(f"Skipping plugin {pluginInfo.get_name()}: pluggy not available")
result[0] = False
load_complete.set()
return
module_name = pluginInfo.get_module_name()
logger.info(f"Attempting to load plugin: {module_name}")
# Actual loading logic will continue below
result[0] = self._load_plugin_impl(pluginInfo)
except Exception as e:
logger.error(f"Error in plugin loading thread: {e}")
import traceback
logger.error(traceback.format_exc())
result[0] = False
finally:
load_complete.set()
# Start the loading thread
thread = threading.Thread(target=load_plugin_thread)
thread.daemon = True
thread.start()
# Wait for loading to complete with a timeout
if not load_complete.wait(10): # 10 second timeout
logger.error(f"Plugin loading timeout for {pluginInfo.get_name()}")
return False
return result[0]
def _load_plugin_impl(self, pluginInfo):
"""Implementation of plugin loading that runs in a thread."""
module_name = pluginInfo.get_module_name()
logger.info(f"Attempting to load plugin: {module_name}")
try:
# Already loaded?
@ -400,11 +462,18 @@ class PluginSystemManager:
logger.error(f"Plugin file not found: {plugin_file}")
return False
# Add a delay to improve stability
import time
time.sleep(0.1)
logger.info(f"Loading plugin from: {plugin_file}")
spec = importlib.util.spec_from_file_location(module_name, plugin_file)
if spec is None:
logger.error(f"Failed to create spec for plugin: {module_name}")
return False
# Add another small delay
time.sleep(0.1)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
@ -450,6 +519,9 @@ class PluginSystemManager:
logger.info(f"Registering plugin with pluggy: {module_name}")
self.plugin_manager.register(plugin_instance)
# Add another small delay
time.sleep(0.1)
try:
logger.info(f"Activating plugin: {module_name}")
self.plugin_manager.hook.activate(plugin=plugin_instance)