2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-30 18:50:53 +00:00

Allow plugin loading from external directory (#3364)

* Load custom plugin directories

* Allow plugins to be loaded from an external directory

* Handle exception when path is not relative to base path

* Fix typo

* Use pathlib

* Move plugin directory code into registry.py

- Allows us to reload plugins without having to reload the server itself

Co-authored-by: Matthias Mair <code@mjmair.com>
This commit is contained in:
Oliver
2022-07-26 14:35:01 +10:00
committed by GitHub
parent 805accb479
commit b98ae25583
4 changed files with 77 additions and 18 deletions

View File

@ -187,6 +187,53 @@ class PluginsRegistry:
logger.info('Finished reloading plugins')
def plugin_dirs(self):
"""Construct a list of directories from where plugins can be loaded"""
dirs = ['plugin.builtin', ]
if settings.TESTING or settings.DEBUG:
# If in TEST or DEBUG mode, load plugins from the 'samples' directory
dirs.append('plugin.samples')
if settings.TESTING:
custom_dirs = os.getenv('INVENTREE_PLUGIN_TEST_DIR', None)
else:
custom_dirs = os.getenv('INVENTREE_PLUGIN_DIR', None)
# Load from user specified directories (unless in testing mode)
dirs.append('plugins')
if custom_dirs is not None:
# Allow multiple plugin directories to be specified
for pd_text in custom_dirs.split(','):
pd = pathlib.Path(pd_text.strip()).absolute()
# Attempt to create the directory if it does not already exist
if not pd.exists():
try:
pd.mkdir(exist_ok=True)
except Exception:
logger.error(f"Could not create plugin directory '{pd}'")
continue
# Ensure the directory has an __init__.py file
init_filename = pd.joinpath('__init__.py')
if not init_filename.exists():
try:
init_filename.write_text("# InvenTree plugin directory\n")
except Exception:
logger.error(f"Could not create file '{init_filename}'")
continue
if pd.exists() and pd.is_dir():
# By this point, we have confirmed that the directory at least exists
logger.info(f"Added plugin directory: '{pd}'")
dirs.append(pd)
return dirs
def collect_plugins(self):
"""Collect plugins from all possible ways of loading."""
if not settings.PLUGINS_ENABLED:
@ -196,8 +243,21 @@ class PluginsRegistry:
self.plugin_modules = [] # clear
# Collect plugins from paths
for plugin in settings.PLUGIN_DIRS:
modules = get_plugins(importlib.import_module(plugin), InvenTreePlugin)
for plugin in self.plugin_dirs():
print(f"Loading plugins from directory '{plugin}'")
parent_path = None
parent_obj = pathlib.Path(plugin)
# If a "path" is provided, some special handling is required
if parent_obj.name is not plugin and len(parent_obj.parts) > 1:
print("loading from a qualified path:", plugin)
parent_path = parent_obj.parent
plugin = parent_obj.name
modules = get_plugins(importlib.import_module(plugin), InvenTreePlugin, path=parent_path)
if modules:
[self.plugin_modules.append(item) for item in modules]