more compact plugin framwork
authorJF Ding <jian-feng.ding@intel.com>
Tue, 30 Aug 2011 05:32:56 +0000 (13:32 +0800)
committerJF Ding <jian-feng.ding@intel.com>
Tue, 30 Aug 2011 05:32:56 +0000 (13:32 +0800)
15 files changed:
mic/chroot.py
mic/creator.py
mic/pluginbase.py [moved from mic/pluginbase/imager_plugin.py with 50% similarity]
mic/pluginbase/__init__.py [deleted file]
mic/pluginbase/backend_plugin.py [deleted file]
mic/pluginbase/hook_plugin.py [deleted file]
mic/pluginmgr.py
plugins/backend/yumpkgmgr.py
plugins/backend/zypppkgmgr.py
plugins/imager/fs_plugin.py
plugins/imager/livecd_plugin.py
plugins/imager/liveusb_plugin.py
plugins/imager/loop_plugin.py
plugins/imager/raw_plugin.py
setup.py

index 82153c4..026ea7e 100644 (file)
@@ -129,7 +129,7 @@ def setup_chrootenv(chrootdir, bindmounts = None):
                 continue
 
             if srcdst[0] in BIND_MOUNTS or srcdst[0] == '/':
-                pwarning("%s will be mounted by default." % srcdst[0])
+                msger.warning("%s will be mounted by default." % srcdst[0])
                 continue
 
             if srcdst[1] == "" or srcdst[1] == "none":
@@ -137,7 +137,7 @@ def setup_chrootenv(chrootdir, bindmounts = None):
             else:
                 srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
                 if os.path.isdir(chrootdir + "/" + srcdst[1]):
-                    pwarning("%s has existed in %s , skip it." % (srcdst[1], chrootdir))
+                    msger.warning("%s has existed in %s , skip it." % (srcdst[1], chrootdir))
                     continue
 
             chrootmounts.append(fs_related.BindChrootMount(srcdst[0], chrootdir, srcdst[1]))
index 58eb9d9..e47fa57 100644 (file)
@@ -44,14 +44,14 @@ class Creator(cmdln.Cmdln):
 
         # load pluginmgr
         self.pluginmgr = pluginmgr.PluginMgr()
-        self.pluginmgr.loadPlugins()
-        self.plugincmds = self.pluginmgr.getImagerPlugins()
+        self.plugincmds = self.pluginmgr.get_plugins('imager')
 
         # mix-in do_subcmd interface
-        for subcmd, klass in self.plugincmds:
+        for subcmd, klass in self.plugincmds.iteritems():
             if not hasattr(klass, 'do_create'):
                 msger.warning("Unsurpport subcmd: %s" % subcmd)
                 continue
+
             func = getattr(klass, 'do_create')
             setattr(self.__class__, "do_"+subcmd, func)
 
similarity index 50%
rename from mic/pluginbase/imager_plugin.py
rename to mic/pluginbase.py
index 35c111a..1fdf390 100644 (file)
 # with the express permission of Red Hat, Inc.
 #
 
-class ImagerPlugin(object):
-    plugin_type = "imager"
+from mic import msger
+
+class _Plugin(object):
+    class __metaclass__(type):
+        def __init__(cls, name, bases, attrs):
+            if not hasattr(cls, 'plugins'):
+                cls.plugins = {}
+
+            elif 'mic_plugin_type' in attrs:
+                    if attrs['mic_plugin_type'] not in cls.plugins:
+                        cls.plugins[attrs['mic_plugin_type']] = {}
+
+            elif hasattr(cls, 'mic_plugin_type') and 'name' in attrs:
+                    cls.plugins[cls.mic_plugin_type][attrs['name']] = cls
+
+        def show_plugins(cls):
+            for cls in cls.plugins[cls.mic_plugin_type]:
+                print cls
+
+        def get_plugins(cls):
+            return cls.plugins
+
+class ImagerPlugin(_Plugin):
+    mic_plugin_type = "imager"
 
     def do_create(self):
         pass
@@ -32,5 +54,17 @@ class ImagerPlugin(object):
     def do_unpack(self):
         pass
 
-# [a, b]: a is for subcmd name, b is for plugin class
-mic_plugin = ["", None]
+class BackendPlugin(_Plugin):
+    mic_plugin_type="backend"
+
+    def addRepository(self):
+        pass
+
+def get_plugins(typen):
+    ps = ImagerPlugin.get_plugins()
+    if typen in ps:
+        return ps[typen]
+    else:
+        return None
+
+__all__ = ['ImagerPlugin', 'BackendPlugin', 'get_plugins']
diff --git a/mic/pluginbase/__init__.py b/mic/pluginbase/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/mic/pluginbase/backend_plugin.py b/mic/pluginbase/backend_plugin.py
deleted file mode 100644 (file)
index c8131db..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/python -tt
-#
-# Copyright 2008, 2009, 2010 Intel, Inc.
-#
-# This copyrighted material is made available to anyone wishing to use, modify,
-# copy, or redistribute it subject to the terms and conditions of the GNU
-# General Public License v.2.  This program is distributed in the hope that it
-# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
-# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along with
-# this program; if not, write to the Free Software Foundation, Inc., 51
-# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  Any Red Hat
-# trademarks that are incorporated in the source code or documentation are not
-# subject to the GNU General Public License and may only be used or replicated
-# with the express permission of Red Hat, Inc.
-#
-
-class BackendPlugin(object):
-    plugin_type="backend"
-
-    def addRepository(self):
-        pass
-
-# [a, b]: a is for bachend name, b is for bachend class
-mic_plugin = ["", None]
diff --git a/mic/pluginbase/hook_plugin.py b/mic/pluginbase/hook_plugin.py
deleted file mode 100644 (file)
index 764062c..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#/usr/bin/python
-
-# TODO: implementation
index e1a1e49..3569387 100644 (file)
 
 import os, sys
 from mic import msger
+from mic import pluginbase
 
 DEFAULT_PLUGIN_LOCATION = "/usr/lib/mic/plugins"
 
-PLGUIN_TYPES = ["imager", "backend", "hook"]
-
-STRING_PLUGIN_MARK = "mic_plugin"
-STRING_PTYPE_MARK = "plugin_type"
+PLUGIN_TYPES = ["imager", "backend"] # TODO  "hook"
 
 class PluginMgr(object):
-    def __init__(self, plugin_dirs=[]):
-        self.plugin_locations = []
-        self.plugin_sets = {}
-        self.plugin_types = PLGUIN_TYPES
-
-        # initial plugin directory
-        self.addPluginDir(DEFAULT_PLUGIN_LOCATION)
-        for directory in plugin_dirs:
-            self.addPluginDir(os.path.expanduser(directory))
-
-        # intial plugin sets
-        for plugintype in self.plugin_types:
-            self.plugin_sets[plugintype] = []
-
-    def addPluginDir(self, plugin_dir):
-        if not os.path.isdir(plugin_dir):
-            msger.debug("Plugin dir is not a directory or does not exist: %s" % plugin_dir)
-            return
-
-        if plugin_dir not in self.plugin_locations:
-            self.plugin_locations.append(plugin_dir)
-
-    def pluginCheck(self, pymod):
-        if not hasattr(pymod, STRING_PLUGIN_MARK):
-            msger.debug("Not a valid plugin: %s" % pymod.__file__)
-            msger.debug("Please check whether %s given" % STRING_PLUGIN_MARK)
-            return False
-
-        plclass = getattr(pymod, STRING_PLUGIN_MARK)[1]
-        if not hasattr(plclass, STRING_PTYPE_MARK):
-            msger.debug("Not a valid plugin: %s" % pymod.__file__)
-            msger.debug("Please check whether %s given" % STRING_PTYPE_MARK)
-            return False
+    plugin_dirs = {}
 
-        pltype = getattr(plclass, STRING_PTYPE_MARK)
-        if not (pltype in self.plugin_types):
-            msger.debug("Unsupported plugin type in %s: %s" % (pymod.__file__, plugintype))
-            return False
+    # make the manager class as singleton
+    _instance = None
+    def __new__(cls, *args, **kwargs):
+        if not cls._instance:
+            cls._instance = super(PluginMgr, cls).__new__(cls, *args, **kwargs)
 
-        return True
+        return cls._instance
 
-    def importModule(self, dir_path, plugin_filename):
-        if plugin_filename.endswith(".pyc"):
-            return
-
-        if not plugin_filename.endswith(".py"):
-            msger.debug("Not a python file: %s" % os.path.join(dir_path, plugin_filename))
-            return
+    def __init__(self, plugin_dirs=[]):
 
-        if plugin_filename == ".py":
-            msger.debug("Empty module name: %s" % os.path.join(dir_path, plugin_filename))
-            return
+        # default plugin directory
+        for pt in PLUGIN_TYPES:
+            self._add_plugindir(os.path.join(DEFAULT_PLUGIN_LOCATION, pt))
 
-        if plugin_filename == "__init__.py":
-            msger.debug("Unsupported python file: %s" % os.path.join(dir_path, plugin_filename))
-            return
+        for dir in plugin_dirs:
+            self._add_plugindir(dir)
 
-        modname = os.path.splitext(plugin_filename)[0]
-        if sys.modules.has_key(modname):
-            pymod = sys.modules[modname]
-            msger.debug("Module %s already exists: %s" % (modname, pymod.__file__))
+        # load all the plugins
+        self._load_all()
 
-        else:
-            pymod = __import__(modname)
-            pymod.__file__ = os.path.join(dir_path, plugin_filename)
-            msger.debug("Plugin module %s:%s importing" % (modname, pymod.__file__))
+    def _add_plugindir(self, dir):
+        dir = os.path.abspath(os.path.expanduser(dir))
 
-        if not self.pluginCheck(pymod):
-            msger.warning("Failed to check plugin: %s" % os.path.join(dir_path, plugin_filename))
+        if not os.path.isdir(dir):
+            msger.warning("Plugin dir is not a directory or does not exist: %s" % dir)
             return
 
-        (pname, pcls) = pymod.__dict__[STRING_PLUGIN_MARK]
-        plugintype = getattr(pcls, STRING_PTYPE_MARK)
-        self.plugin_sets[plugintype].append((pname, pcls))
-
-    def loadPlugins(self):
-        for pdir in map(os.path.abspath, self.plugin_locations):
-            for pitem in os.walk(pdir):
-                sys.path.insert(0, pitem[0])
-                for pf in pitem[2]:
-                    self.importModule(pitem[0], pf)
-                del(sys.path[0])
-
-    def getPluginByCateg(self, categ = None):
-        if not (categ in self.plugin_types):
-            msger.warning("Failed to get plugin category: %s" % categ)
-            return None
-        else:
-            return self.plugin_sets[categ]
-
-    def getImagerPlugins(self):
-        return self.plugin_sets['imager']
-
-    def getBackendPlugins(self):
-        return self.plugin_sets['backend']
-
-    def getHookPlugins(self):
-        return self.plugin_sets['hook']
-
-    def listAllPlugins(self):
-        # just for debug
-        for key in self.plugin_sets.keys():
-            msger.debug("plugin type (%s) :::\n" % key)
-            for item in self.plugin_sets[key]:
-                msger.debug("%-6s: %s\n" % (item[0], item[1]))
-
-    def getPluginType(self, plugin_str):
-        pass
-
-if __name__ == "__main__":
-    msger.set_loglevel('debug')
-
-    pluginmgr = PluginMgr()
-    pluginmgr.loadPlugins()
-    pluginmgr.listAllPlugins()
+        if dir not in self.plugin_dirs:
+            self.plugin_dirs[dir] = False
+            # the value True/False means "loaded"
+
+    def _load_all(self):
+        for (pdir, loaded) in self.plugin_dirs.iteritems():
+            if loaded: continue
+
+            sys.path.insert(0, pdir)
+            for mod in [x[:-3] for x in os.listdir(pdir) if x.endswith(".py")]:
+                if mod and mod != '__init__':
+                    if mod in sys.modules:
+                        msger.debug("Module %s already exists, skip" % mod)
+                    else:
+                        pymod = __import__(mod)
+                        self.plugin_dirs[pdir] = True
+                        msger.debug("Plugin module %s:%s importing" % (mod, pymod.__file__))
+
+            del(sys.path[0])
+
+    def get_plugins(self, ptype):
+        """ the return value is dict of name:class pairs """
+        return pluginbase.get_plugins(ptype)
index 2c4656f..40118b1 100644 (file)
@@ -32,9 +32,10 @@ import subprocess
 
 from mic.utils.errors import *
 from mic.utils.fs_related import *
-from mic.pluginbase.backend_plugin import BackendPlugin
 from mic.imager.baseimager import BaseImageCreator as ImageCreator
+
 from mic import msger
+from mic.pluginbase import BackendPlugin
 
 def getRPMCallback():
     sys.path.append('/usr/share/yum-cli')
@@ -137,6 +138,8 @@ class MyYumRepository(yum.yumRepo.YumRepository):
         pass
 
 class Yum(BackendPlugin, yum.YumBase):
+    name = 'yum'
+
     def __init__(self, creator = None, recording_pkgs=None):
         if not isinstance(creator, ImageCreator):
             raise CreatorError("Invalid argument: creator")
@@ -534,5 +537,3 @@ class Yum(BackendPlugin, yum.YumBase):
 
     def getAllContent(self):
         return self.__pkgs_content
-
-mic_plugin = ["yum", Yum]
index 29af211..c93f665 100644 (file)
@@ -16,7 +16,8 @@ from mic.imager.baseimager import BaseImageCreator as ImageCreator
 from mic.utils.fs_related import *
 from mic.utils.misc import *
 from mic.utils.rpmmisc import *
-from mic.pluginbase.backend_plugin import BackendPlugin
+
+from mic.pluginbase import BackendPlugin
 
 class RepositoryStub:
     def __init__(self):
@@ -41,6 +42,8 @@ class RpmError(CreatorError):
     pass
 
 class Zypp(BackendPlugin):
+    name = 'zypp'
+
     def __init__(self, creator = None, recording_pkgs=None):
         if not isinstance(creator, ImageCreator):
             raise CreatorError("Invalid argument: creator")
@@ -753,5 +756,3 @@ class Zypp(BackendPlugin):
             repourl = repoinfo.baseUrls()[0].__str__()
             return get_proxy(repourl)
 
-mic_plugin = ["zypp", Zypp]
-
index 451b9b8..80cd985 100644 (file)
@@ -2,7 +2,6 @@
 import sys
 import subprocess
 
-from mic.pluginbase.imager_plugin import ImagerPlugin
 import mic.utils.cmdln as cmdln
 import mic.utils.errors as errors
 import mic.configmgr as configmgr
@@ -10,8 +9,11 @@ import mic.pluginmgr as pluginmgr
 import mic.imager.fs as fs
 import mic.chroot as chroot
 
+from mic.pluginbase import ImagerPlugin
 
 class FsPlugin(ImagerPlugin):
+    name = 'fs'
+
     @classmethod
     @cmdln.option("--include-src", dest="include_src", help="include source pakcage")
     def do_create(self, subcmd, opts, *args):
@@ -32,10 +34,10 @@ class FsPlugin(ImagerPlugin):
         cfgmgr.setProperty("ksconf", ksconf)
 
         plgmgr = pluginmgr.PluginMgr()
-        plgmgr.loadPlugins()
-        for (key, pcls) in plgmgr.getBackendPlugins():
+        for (key, pcls) in plgmgr.get_plugins('backend').iteritems():
             if key == createopts['pkgmgr']:
                 pkgmgr = pcls
+
         if not pkgmgr:
             raise CreatorError("Can't find backend plugin: %s" % createopts['pkgmgr'])
 
@@ -75,4 +77,3 @@ class FsPlugin(ImagerPlugin):
                 chroot.cleanup_after_chroot("dir", None, None, None)
                 return 1
 
-mic_plugin = ["fs", FsPlugin]
index 5f92283..a0bccca 100644 (file)
@@ -4,7 +4,6 @@ import subprocess
 import shutil
 import tempfile
 
-from mic.pluginbase.imager_plugin import ImagerPlugin
 import mic.chroot as chroot
 import mic.utils.misc as misc
 import mic.utils.fs_related as fs_related
@@ -14,7 +13,10 @@ import mic.pluginmgr as pluginmgr
 import mic.imager.livecd as livecd
 from mic.utils.errors import *
 
+from mic.pluginbase import ImagerPlugin
+
 class LiveCDPlugin(ImagerPlugin):
+    name = 'livecd'
 
     @classmethod
     def do_create(self, subcmd, opts, *args):
@@ -34,9 +36,8 @@ class LiveCDPlugin(ImagerPlugin):
         cfgmgr.setProperty("ksconf", ksconf)
         creatoropts = cfgmgr.create
         plgmgr = pluginmgr.PluginMgr()
-        plgmgr.loadPlugins()
 
-        for (key, pcls) in plgmgr.getBackendPlugins():
+        for (key, pcls) in plgmgr.get_plugins('backend').iteritems():
             if key == creatoropts['pkgmgr']:
                 pkgmgr = pcls
 
@@ -168,5 +169,3 @@ class LiveCDPlugin(ImagerPlugin):
             shutil.rmtree(imgmnt, ignore_errors = True)
 
         return rtimage
-
-mic_plugin = ["livecd", LiveCDPlugin]
index f6007af..e4dc98b 100644 (file)
@@ -5,7 +5,7 @@ import subprocess
 import shutil
 import tempfile
 
-from mic.pluginbase.imager_plugin import ImagerPlugin
+from mic.pluginbase import ImagerPlugin
 import mic.imager.liveusb as liveusb
 import mic.utils.misc as misc
 import mic.utils.fs_related as fs_related
@@ -17,6 +17,8 @@ from mic.utils.errors import *
 import mic.chroot as chroot
 
 class LiveUSBPlugin(ImagerPlugin):
+    name = 'liveusb'
+
     #@cmdln.option
     @classmethod
     def do_create(self, subcmd, opts, *args):
@@ -37,9 +39,8 @@ class LiveUSBPlugin(ImagerPlugin):
         creatoropts = cfgmgr.create
         cfgmgr.setProperty("ksconf", args[0])
         plgmgr = pluginmgr.PluginMgr()
-        plgmgr.loadPlugins()
 
-        for (key, pcls) in plgmgr.getBackendPlugins():
+        for (key, pcls) in plgmgr.get_plugins('backend').iteritems():
             if key == creatoropts['pkgmgr']:
                 pkgmgr = pcls
 
@@ -169,5 +170,3 @@ class LiveUSBPlugin(ImagerPlugin):
             shutil.rmtree(imgmnt, ignore_errors = True)
 
         return rtimage
-
-mic_plugin = ["liveusb", LiveUSBPlugin]
index 70dbab5..b002e1a 100644 (file)
@@ -6,7 +6,7 @@ import subprocess
 import shutil
 import tempfile
 
-from mic.pluginbase.imager_plugin import ImagerPlugin
+from mic.pluginbase import ImagerPlugin
 import mic.utils.misc as misc
 import mic.utils.cmdln as cmdln
 import mic.utils.fs_related as fs_related
@@ -17,6 +17,8 @@ import mic.imager.loop as loop
 import mic.chroot as chroot
 
 class LoopPlugin(ImagerPlugin):
+    name = 'loop'
+
     @classmethod
     def do_create(self, subcmd, opts, *args):
         """${cmd_name}: create loop image
@@ -36,9 +38,8 @@ class LoopPlugin(ImagerPlugin):
         cfgmgr.setProperty("ksconf", ksconf)
 
         plgmgr = pluginmgr.PluginMgr()
-        plgmgr.loadPlugins()
 
-        for (key, pcls) in plgmgr.getBackendPlugins():
+        for (key, pcls) in plgmgr.get_plugins('backend').iteritems():
             if key == creatoropts['pkgmgr']:
                 pkgmgr = pcls
 
@@ -92,6 +93,3 @@ class LoopPlugin(ImagerPlugin):
         print "Copying file system..."
         shutil.copyfile(srcimg, image)
         return image
-
-mic_plugin = ["loop", LoopPlugin]
-
index 99c6ccd..6a5659a 100644 (file)
@@ -6,7 +6,7 @@ import shutil
 import re
 import tempfile
 
-from mic.pluginbase.imager_plugin import ImagerPlugin
+from mic.pluginbase import ImagerPlugin
 import mic.utils.misc as misc
 import mic.utils.fs_related as fs_related
 import mic.utils.cmdln as cmdln
@@ -18,6 +18,7 @@ import mic.imager.raw as raw
 import mic.chroot as chroot
 
 class RawPlugin(ImagerPlugin):
+    name = 'raw'
 
     @classmethod
     def do_create(self, subcmd, opts, *args):
@@ -37,9 +38,8 @@ class RawPlugin(ImagerPlugin):
         creatoropts = cfgmgr.create
         cfgmgr.setProperty("ksconf", ksconf)
         plgmgr = pluginmgr.PluginMgr()
-        plgmgr.loadPlugins()
 
-        for (key, pcls) in plgmgr.getBackendPlugins():
+        for (key, pcls) in plgmgr.get_plugins('backend').iteritems():
             if key == creatoropts['pkgmgr']:
                 pkgmgr = pcls
 
@@ -177,6 +177,3 @@ class RawPlugin(ImagerPlugin):
         srcloop.cleanup()
         shutil.rmtree(srcmnt, ignore_errors = True)
         return image
-
-mic_plugin = ["raw", RawPlugin]
-
index a3bc3f1..475d719 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -33,7 +33,6 @@ except IOError:
 PACKAGES = [MOD_NAME,
             MOD_NAME + '/utils',
             MOD_NAME + '/imager',
-            MOD_NAME + '/pluginbase',
             MOD_NAME + '/urlgrabber',
             MOD_NAME + '/kickstart',
             MOD_NAME + '/kickstart/custom_commands',