diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index 279225355d..9688f90c12 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -900,3 +900,4 @@ if DEBUG or TESTING: PLUGIN_TESTING = get_setting('PLUGIN_TESTING', TESTING) # are plugins beeing tested? PLUGIN_TESTING_SETUP = get_setting('PLUGIN_TESTING_SETUP', False) # load plugins from setup hooks in testing? PLUGIN_RETRY = get_setting('PLUGIN_RETRY', 5) # how often should plugin loading be tried? +PLUGIN_FILE_CHECKED = False # Was the plugin file checked? diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index 56e41dd24b..1a9b6f37d4 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -1007,6 +1007,13 @@ class InvenTreeSetting(BaseInvenTreeSetting): 'validator': bool, }, + 'PLUGIN_ON_STARTUP': { + 'name': _('Check plugins on startup'), + 'description': _('Check that all plugins are installed on startup - enable in container enviroments'), + 'default': False, + 'validator': bool, + 'requires_restart': True, + }, # Settings for plugin mixin features 'ENABLE_PLUGINS_URL': { 'name': _('Enable URL integration'), diff --git a/InvenTree/plugin/apps.py b/InvenTree/plugin/apps.py index 75063c6b3c..c611f6f8c1 100644 --- a/InvenTree/plugin/apps.py +++ b/InvenTree/plugin/apps.py @@ -30,6 +30,15 @@ class PluginAppConfig(AppConfig): if not registry.is_loading: # this is the first startup + try: + from common.models import InvenTreeSetting + if InvenTreeSetting.get_setting('PLUGIN_ON_STARTUP', create=False): + # make sure all plugins are installed + registry.install_plugin_file() + except: + pass + + # get plugins and init them registry.collect_plugins() registry.load_plugins() diff --git a/InvenTree/plugin/registry.py b/InvenTree/plugin/registry.py index 928f238f58..2db1beb805 100644 --- a/InvenTree/plugin/registry.py +++ b/InvenTree/plugin/registry.py @@ -8,6 +8,8 @@ Registry for loading and managing multiple plugins at run-time import importlib import pathlib import logging +import os +import subprocess from typing import OrderedDict from importlib import reload @@ -211,6 +213,27 @@ class PluginsRegistry: # Log collected plugins logger.info(f'Collected {len(self.plugin_modules)} plugins!') logger.info(", ".join([a.__module__ for a in self.plugin_modules])) + + def install_plugin_file(self): + """ + Make sure all plugins are installed in the current enviroment + """ + + if settings.PLUGIN_FILE_CHECKED: + logger.info('Plugin file was already checked') + return + + try: + output = str(subprocess.check_output(['pip', 'install', '-U', '-r', settings.PLUGIN_FILE], cwd=os.path.dirname(settings.BASE_DIR)), 'utf-8') + except subprocess.CalledProcessError as error: # pragma: no cover + logger.error(f'Ran into error while trying to install plugins!\n{str(error)}') + return False + + logger.info(f'plugin requirements were run\n{output}') + + # do not run again + settings.PLUGIN_FILE_CHECKED = True + # endregion # region registry functions diff --git a/InvenTree/plugin/serializers.py b/InvenTree/plugin/serializers.py index 14c2c11ec6..6965f398f0 100644 --- a/InvenTree/plugin/serializers.py +++ b/InvenTree/plugin/serializers.py @@ -16,7 +16,6 @@ from django.utils import timezone from rest_framework import serializers from plugin.models import PluginConfig, PluginSetting -from InvenTree.config import get_plugin_file from common.serializers import SettingsSerializer @@ -123,7 +122,7 @@ class PluginConfigInstallSerializer(serializers.Serializer): # save plugin to plugin_file if installed successfull if success: - with open(get_plugin_file(), "a") as plugin_file: + with open(settings.PLUGIN_FILE, "a") as plugin_file: plugin_file.write(f'{" ".join(install_name)} # Installed {timezone.now()} by {str(self.context["request"].user)}\n') return ret