Przeglądaj źródła

fix: bug when reinstall plugin

lanvent 3 lat temu
rodzic
commit
8b73a74609

+ 1 - 1
channel/wechatmp/wechatmp_channel.py

@@ -41,7 +41,7 @@ class WechatMPChannel(ChatChannel):
         urls = (
             '/wx', 'SubsribeAccountQuery',
         )
-        app = web.application(urls, globals())
+        app = web.application(urls, globals(), autoreload=False)
         port = conf().get('wechatmp_port', 8080)
         web.httpserver.runsimple(app.wsgifunc(), ('0.0.0.0', port))
 

+ 15 - 3
common/package_manager.py

@@ -1,3 +1,4 @@
+import time
 import pip
 
 def install(package):
@@ -7,9 +8,20 @@ def install_requirements(file):
     pip.main(['install', '-r', file, "--upgrade"])
 
 def check_dulwich():
+    needwait = False
+    for i in range(2):
+        if needwait:
+            time.sleep(3)
+            needwait = False
+        try:
+            import dulwich
+            return
+        except ImportError:
+            try:
+                install('dulwich')
+            except:
+                needwait = True
     try:
         import dulwich
-        return
     except ImportError:
-        install('dulwich')
-    raise ImportError("Unable to import dulwich")
+        raise ImportError("Unable to import dulwich")

+ 1 - 5
plugins/godcmd/godcmd.py

@@ -310,11 +310,7 @@ class Godcmd(Plugin):
                             if len(args) != 1:
                                 ok, result = False, "请提供插件名"
                             else:
-                                ok = PluginManager().enable_plugin(args[0])
-                                if ok:
-                                    result = "插件已启用"
-                                else:
-                                    result = "插件不存在"
+                                ok, result = PluginManager().enable_plugin(args[0])
                         elif cmd == "disablep":
                             if len(args) != 1:
                                 ok, result = False, "请提供插件名"

+ 39 - 15
plugins/plugin_manager.py

@@ -1,8 +1,10 @@
 # encoding:utf-8
 
 import importlib
+import importlib.util
 import json
 import os
+import sys
 from common.singleton import singleton
 from common.sorted_dict import SortedDict
 from .event import *
@@ -18,6 +20,7 @@ class PluginManager:
         self.instances = {}
         self.pconf = {}
         self.current_plugin_path = None
+        self.loaded = {}
 
     def register(self, name: str, desire_priority: int = 0, **kwargs):
         def wrapper(plugincls):
@@ -30,9 +33,10 @@ class PluginManager:
             plugincls.namecn = kwargs.get('namecn') if kwargs.get('namecn') != None else name
             plugincls.hidden = kwargs.get('hidden') if kwargs.get('hidden') != None else False
             plugincls.enabled = True
+            if self.current_plugin_path == None:
+                raise Exception("Plugin path not set")
             self.plugins[name.upper()] = plugincls
             logger.info("Plugin %s_v%s registered, path=%s" % (name, plugincls.version, plugincls.path))
-            return plugincls
         return wrapper
 
     def save_config(self):
@@ -58,6 +62,7 @@ class PluginManager:
     def scan_plugins(self):
         logger.info("Scaning plugins ...")
         plugins_dir = "./plugins"
+        raws = [self.plugins[name] for name in self.plugins]
         for plugin_name in os.listdir(plugins_dir):
             plugin_path = os.path.join(plugins_dir, plugin_name)
             if os.path.isdir(plugin_path):
@@ -68,17 +73,27 @@ class PluginManager:
                     import_path = "plugins.{}".format(plugin_name)
                     try:
                         self.current_plugin_path = plugin_path
-                        main_module = importlib.import_module(import_path)
+                        if plugin_path in self.loaded:
+                            if self.loaded[plugin_path] == None:
+                                logger.info("reload module %s" % plugin_name)
+                                self.loaded[plugin_path] = importlib.reload(sys.modules[import_path])
+                                dependent_module_names = [name for name in sys.modules.keys() if name.startswith( import_path+ '.')]
+                                for name in dependent_module_names:
+                                    logger.info("reload module %s" % name)
+                                    importlib.reload(sys.modules[name])
+                        else:
+                            self.loaded[plugin_path] = importlib.import_module(import_path)
+                        self.current_plugin_path = None
                     except Exception as e:
-                        logger.warn("Failed to import plugin %s: %s" % (plugin_name, e))
+                        logger.exception("Failed to import plugin %s: %s" % (plugin_name, e))
                         continue
         pconf = self.pconf
-        new_plugins = []
+        news = [self.plugins[name] for name in self.plugins]
+        new_plugins = list(set(news) - set(raws))
         modified = False
         for name, plugincls in self.plugins.items():
             rawname = plugincls.name
             if rawname not in pconf["plugins"]:
-                new_plugins.append(plugincls)
                 modified = True
                 logger.info("Plugin %s not found in pconfig, adding to pconfig..." % name)
                 pconf["plugins"][rawname] = {"enabled": plugincls.enabled, "priority": plugincls.priority}
@@ -95,14 +110,16 @@ class PluginManager:
             self.listening_plugins[event].sort(key=lambda name: self.plugins[name].priority, reverse=True)
 
     def activate_plugins(self): # 生成新开启的插件实例
+        failed_plugins = []
         for name, plugincls in self.plugins.items():
             if plugincls.enabled:
                 if name not in self.instances:
                     try:
                         instance = plugincls()
                     except Exception as e:
-                        logger.warn("Failed to create init %s, diabled. %s" % (name, e))
+                        logger.warn("Failed to init %s, diabled. %s" % (name, e))
                         self.disable_plugin(name)
+                        failed_plugins.append(name)
                         continue
                     self.instances[name] = instance
                     for event in instance.handlers:
@@ -110,6 +127,7 @@ class PluginManager:
                             self.listening_plugins[event] = []
                         self.listening_plugins[event].append(name)
         self.refresh_order()
+        return failed_plugins
 
     def reload_plugin(self, name:str):
         name = name.upper()
@@ -159,15 +177,17 @@ class PluginManager:
     def enable_plugin(self, name:str):
         name = name.upper()
         if name not in self.plugins:
-            return False
+            return False, "插件不存在"
         if not self.plugins[name].enabled :
             self.plugins[name].enabled = True
             rawname = self.plugins[name].name
             self.pconf["plugins"][rawname]["enabled"] = True
             self.save_config()
-            self.activate_plugins()
-            return True
-        return True
+            failed_plugins = self.activate_plugins()
+            if name in failed_plugins:
+                return False, "插件开启失败"
+            return True, "插件已开启"
+        return True, "插件已开启"
     
     def disable_plugin(self, name:str):
         name = name.upper()
@@ -206,12 +226,12 @@ class PluginManager:
                     repo = source["repo"][repo]["url"]
                     match = re.match(r"^(https?:\/\/|git@)([^\/:]+)[\/:]([^\/:]+)\/(.+).git$", repo)
                     if not match:
-                        return False, "source中的仓库地址不合法"
+                        return False, "安装插件失败,source中的仓库地址不合法"
                 else:
-                    return False, "仓库地址不合法"
+                    return False, "安装插件失败,仓库地址不合法"
             except Exception as e:
                 logger.error("Failed to install plugin, {}".format(e))
-                return False, "安装插件失败"
+                return False, "安装插件失败,请检查仓库地址是否正确"
         dirname = os.path.join("./plugins",match.group(4))
         try:
             repo = porcelain.clone(repo, dirname, checkout=True)
@@ -221,7 +241,7 @@ class PluginManager:
             return True, "安装插件成功,请扫描插件或重启程序"
         except Exception as e:
             logger.error("Failed to install plugin, {}".format(e))
-            return False, "安装插件失败"
+            return False, "安装插件失败"+str(e)
         
     def uninstall_plugin(self, name:str):
         name = name.upper()
@@ -233,8 +253,12 @@ class PluginManager:
         try:
             import shutil
             shutil.rmtree(dirname)
+            rawname = self.plugins[name].name
             del self.plugins[name]
+            del self.pconf["plugins"][rawname]
+            self.loaded[dirname] = None
+            self.save_config()
             return True, "卸载插件成功"
         except Exception as e:
             logger.error("Failed to uninstall plugin, {}".format(e))
-            return False, "卸载插件失败"
+            return False, "卸载插件失败,请手动删除文件夹完成卸载,"+str(e)