| 1 | ================ |
|---|
| 2 | Plugins system |
|---|
| 3 | ================ |
|---|
| 4 | |
|---|
| 5 | Goals |
|---|
| 6 | ===== |
|---|
| 7 | |
|---|
| 8 | The plugin system (``pkgcore.plugin``) is used to pick up extra code |
|---|
| 9 | (potentially distributed separately from pkgcore itself) at a place |
|---|
| 10 | where using the config system is not a good idea for some reason. This |
|---|
| 11 | means that for a lot of things that most people would call "plugins" |
|---|
| 12 | you should not actually use ``pkgcore.plugin``, you should use the |
|---|
| 13 | config system. Things like extra repository types should simply be |
|---|
| 14 | used as "class" value in the configuration. The plugin system is |
|---|
| 15 | currently mainly used in places where handing in a ``ConfigManager`` |
|---|
| 16 | is too inconvenient. |
|---|
| 17 | |
|---|
| 18 | Using plugins |
|---|
| 19 | ============= |
|---|
| 20 | |
|---|
| 21 | Plugins are looked up based on a string "key". You can always look up |
|---|
| 22 | all available plugins matching this key with |
|---|
| 23 | ``pkgcore.plugin.get_plugins(key)``. For some kinds of plugin (the |
|---|
| 24 | ones defining a "priority" attribute) you can also get the "best" |
|---|
| 25 | plugin with ``pkgcore.plugin.get_plugin(key)``. This does not make |
|---|
| 26 | sense for all kinds of plugin, so not all of them define this. |
|---|
| 27 | |
|---|
| 28 | The plugin system does not care about what kind of object plugins are, |
|---|
| 29 | this depends entirely on the key. |
|---|
| 30 | |
|---|
| 31 | Adding plugins |
|---|
| 32 | ============== |
|---|
| 33 | |
|---|
| 34 | Basics, caching |
|---|
| 35 | --------------- |
|---|
| 36 | |
|---|
| 37 | Plugins for pkgcore are loaded from modules inside the |
|---|
| 38 | ``pkgcore.plugins`` package. This package has some magic to make |
|---|
| 39 | plugins in any subdirectory ``pkgcore/plugins`` under a directory on |
|---|
| 40 | ``sys.path`` work. So if pkgcore itself is installed in site-packages |
|---|
| 41 | you can still add plugins to ``/home/you/pythonlib/pkgcore/plugins`` |
|---|
| 42 | if ``/home/you/pythonlib`` is in ``PYTHONPATH``. You should not put an |
|---|
| 43 | ``__init__.py`` in this extra plugin directory. |
|---|
| 44 | |
|---|
| 45 | Plugin modules should contain a ``pkgcore_plugins`` directory that |
|---|
| 46 | maps the "key" strings to a sequence of plugins. This dictionary has |
|---|
| 47 | to be constant, since pkgcore keeps track of what plugin module |
|---|
| 48 | provides plugins for what keys in a cache file to avoid unnecessary |
|---|
| 49 | imports. So this is invalid:: |
|---|
| 50 | |
|---|
| 51 | try: |
|---|
| 52 | import spork_package |
|---|
| 53 | except ImportError: |
|---|
| 54 | pkgcore_plugins = {} |
|---|
| 55 | else: |
|---|
| 56 | pkgcore_plugins = {'myplug': [spork_package.ThePlugin]} |
|---|
| 57 | |
|---|
| 58 | since if the plugin cache is generated while the package is not |
|---|
| 59 | available pkgcore will cache the module as not providing any |
|---|
| 60 | ``myplug`` plugins, and the cache will not be updated if the package |
|---|
| 61 | becomes available (only changes to the mtime of actual plugin modules |
|---|
| 62 | invalidate the cache). Instead you should do something like this:: |
|---|
| 63 | |
|---|
| 64 | try: |
|---|
| 65 | from spork_package import ThePlugin |
|---|
| 66 | except ImportError: |
|---|
| 67 | class ThePlugin(object): |
|---|
| 68 | disabled = True |
|---|
| 69 | |
|---|
| 70 | pkgcore_plugins = {'myplug': [ThePlugin]} |
|---|
| 71 | |
|---|
| 72 | If a plugin has a "disabled" attribute the plugin system will never |
|---|
| 73 | return it from ``get_plugin`` or ``get_plugins``. |
|---|
| 74 | |
|---|
| 75 | Priority |
|---|
| 76 | -------- |
|---|
| 77 | |
|---|
| 78 | If you want your plugin to support ``get_plugin`` it should have a |
|---|
| 79 | ``priority`` attribute: an integer indicating how "preferred" this |
|---|
| 80 | plugin is. The plugin with the highest priority (that is not disabled) |
|---|
| 81 | is returned from ``get_plugin``. |
|---|
| 82 | |
|---|
| 83 | Some types of plugins need more information to determine a priority |
|---|
| 84 | value. Those should not have a priority attribute. They should use |
|---|
| 85 | ``get_plugins`` instead and have a method that gets passed the extra |
|---|
| 86 | data and returns the priority. |
|---|
| 87 | |
|---|
| 88 | Import behaviour |
|---|
| 89 | ---------------- |
|---|
| 90 | |
|---|
| 91 | Assuming the cache is working correctly (it was generated after |
|---|
| 92 | installing a plugin as root) pkgcore will import all plugin modules |
|---|
| 93 | containing plugins for a requested key. No more, no less. The priority |
|---|
| 94 | and disabled values are not cached (intentionally, since they may |
|---|
| 95 | change without a cache invalidation), so it has to check all plugins |
|---|
| 96 | for the key even if only one of them is requested (``get_plugin``, and |
|---|
| 97 | the same will usually be true for ``get_plugins``). |
|---|
| 98 | |
|---|
| 99 | This means it makes sense to have only one kind of plugin per plugin |
|---|
| 100 | module (unless the required imports overlap). |
|---|
| 101 | |
|---|
| 102 | The disabled and priority values are not cached by the plugin system |
|---|
| 103 | after the plugin module is imported. This means they should be simple |
|---|
| 104 | attributes (either completely constant or set at import time) or |
|---|
| 105 | properties that do their own caching. |
|---|
| 106 | |
|---|
| 107 | Adding a plugin package |
|---|
| 108 | ======================= |
|---|
| 109 | |
|---|
| 110 | Both ``get_plugin`` and ``get_plugins`` take a plugin package as |
|---|
| 111 | second argument. This means you can use the plugin system for external |
|---|
| 112 | pkgcore-related tools without cluttering up the main pkgcore plugin |
|---|
| 113 | directory. If you do this you will probably want to copy the |
|---|
| 114 | ``__path__`` trick from ``pkgcore/plugin/__init__.py`` to support |
|---|
| 115 | plugins elsewhere on ``sys.path``. |
|---|