Merge pull request #2504 from SchrodingersGat/plugin-docker-support

Plugin Installation Support
This commit is contained in:
Oliver 2022-01-06 14:48:00 +11:00 committed by GitHub
commit 8597ae89b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 122 additions and 46 deletions

1
.gitignore vendored
View File

@ -49,6 +49,7 @@ static_i18n
# Local config file # Local config file
config.yaml config.yaml
plugins.txt
# Default data file # Default data file
data.json data.json

View File

@ -0,0 +1,90 @@
"""
Helper functions for loading InvenTree configuration options
"""
import os
import shutil
import logging
logger = logging.getLogger('inventree')
def get_base_dir():
""" Returns the base (top-level) InvenTree directory """
return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
def get_config_file():
"""
Returns the path of the InvenTree configuration file.
Note: It will be created it if does not already exist!
"""
base_dir = get_base_dir()
cfg_filename = os.getenv('INVENTREE_CONFIG_FILE')
if cfg_filename:
cfg_filename = cfg_filename.strip()
cfg_filename = os.path.abspath(cfg_filename)
else:
# Config file is *not* specified - use the default
cfg_filename = os.path.join(base_dir, 'config.yaml')
if not os.path.exists(cfg_filename):
print("InvenTree configuration file 'config.yaml' not found - creating default file")
cfg_template = os.path.join(base_dir, "config_template.yaml")
shutil.copyfile(cfg_template, cfg_filename)
print(f"Created config file {cfg_filename}")
return cfg_filename
def get_plugin_file():
"""
Returns the path of the InvenTree plugins specification file.
Note: It will be created if it does not already exist!
"""
# Check if the plugin.txt file (specifying required plugins) is specified
PLUGIN_FILE = os.getenv('INVENTREE_PLUGIN_FILE')
if not PLUGIN_FILE:
# If not specified, look in the same directory as the configuration file
config_dir = os.path.dirname(get_config_file())
PLUGIN_FILE = os.path.join(config_dir, 'plugins.txt')
if not os.path.exists(PLUGIN_FILE):
logger.warning("Plugin configuration file does not exist")
logger.info(f"Creating plugin file at '{PLUGIN_FILE}'")
# If opening the file fails (no write permission, for example), then this will throw an error
with open(PLUGIN_FILE, 'w') as plugin_file:
plugin_file.write("# InvenTree Plugins (uses PIP framework to install)\n\n")
return PLUGIN_FILE
def get_setting(environment_var, backup_val, default_value=None):
"""
Helper function for retrieving a configuration setting value
- First preference is to look for the environment variable
- Second preference is to look for the value of the settings file
- Third preference is the default value
"""
val = os.getenv(environment_var)
if val is not None:
return val
if backup_val is not None:
return backup_val
return default_value

View File

@ -17,7 +17,6 @@ import os
import random import random
import socket import socket
import string import string
import shutil
import sys import sys
from datetime import datetime from datetime import datetime
@ -28,30 +27,12 @@ from django.utils.translation import gettext_lazy as _
from django.contrib.messages import constants as messages from django.contrib.messages import constants as messages
import django.conf.locale import django.conf.locale
from .config import get_base_dir, get_config_file, get_plugin_file, get_setting
def _is_true(x): def _is_true(x):
# Shortcut function to determine if a value "looks" like a boolean # Shortcut function to determine if a value "looks" like a boolean
return str(x).lower() in ['1', 'y', 'yes', 't', 'true'] return str(x).strip().lower() in ['1', 'y', 'yes', 't', 'true']
def get_setting(environment_var, backup_val, default_value=None):
"""
Helper function for retrieving a configuration setting value
- First preference is to look for the environment variable
- Second preference is to look for the value of the settings file
- Third preference is the default value
"""
val = os.getenv(environment_var)
if val is not None:
return val
if backup_val is not None:
return backup_val
return default_value
# Determine if we are running in "test" mode e.g. "manage.py test" # Determine if we are running in "test" mode e.g. "manage.py test"
@ -61,27 +42,9 @@ TESTING = 'test' in sys.argv
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = get_base_dir()
# Specify where the "config file" is located. cfg_filename = get_config_file()
# By default, this is 'config.yaml'
cfg_filename = os.getenv('INVENTREE_CONFIG_FILE')
if cfg_filename:
cfg_filename = cfg_filename.strip()
cfg_filename = os.path.abspath(cfg_filename)
else:
# Config file is *not* specified - use the default
cfg_filename = os.path.join(BASE_DIR, 'config.yaml')
if not os.path.exists(cfg_filename):
print("InvenTree configuration file 'config.yaml' not found - creating default file")
cfg_template = os.path.join(BASE_DIR, "config_template.yaml")
shutil.copyfile(cfg_template, cfg_filename)
print(f"Created config file {cfg_filename}")
with open(cfg_filename, 'r') as cfg: with open(cfg_filename, 'r') as cfg:
CONFIG = yaml.safe_load(cfg) CONFIG = yaml.safe_load(cfg)
@ -89,6 +52,8 @@ with open(cfg_filename, 'r') as cfg:
# We will place any config files in the same directory as the config file # We will place any config files in the same directory as the config file
config_dir = os.path.dirname(cfg_filename) config_dir = os.path.dirname(cfg_filename)
PLUGIN_FILE = get_plugin_file()
# Default action is to run the system in Debug mode # Default action is to run the system in Debug mode
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = _is_true(get_setting( DEBUG = _is_true(get_setting(
@ -908,8 +873,7 @@ MARKDOWNIFY_BLEACH = False
# Maintenance mode # Maintenance mode
MAINTENANCE_MODE_RETRY_AFTER = 60 MAINTENANCE_MODE_RETRY_AFTER = 60
# Plugin Directories (local plugins will be loaded from these directories)
# Plugins
PLUGIN_DIRS = ['plugin.builtin', ] PLUGIN_DIRS = ['plugin.builtin', ]
if not TESTING: if not TESTING:

View File

@ -30,9 +30,11 @@ ENV INVENTREE_MNG_DIR="${INVENTREE_HOME}/InvenTree"
ENV INVENTREE_DATA_DIR="${INVENTREE_HOME}/data" ENV INVENTREE_DATA_DIR="${INVENTREE_HOME}/data"
ENV INVENTREE_STATIC_ROOT="${INVENTREE_DATA_DIR}/static" ENV INVENTREE_STATIC_ROOT="${INVENTREE_DATA_DIR}/static"
ENV INVENTREE_MEDIA_ROOT="${INVENTREE_DATA_DIR}/media" ENV INVENTREE_MEDIA_ROOT="${INVENTREE_DATA_DIR}/media"
ENV INVENTREE_PLUGIN_DIR="${INVENTREE_DATA_DIR}/plugins"
ENV INVENTREE_CONFIG_FILE="${INVENTREE_DATA_DIR}/config.yaml" ENV INVENTREE_CONFIG_FILE="${INVENTREE_DATA_DIR}/config.yaml"
ENV INVENTREE_SECRET_KEY_FILE="${INVENTREE_DATA_DIR}/secret_key.txt" ENV INVENTREE_SECRET_KEY_FILE="${INVENTREE_DATA_DIR}/secret_key.txt"
ENV INVENTREE_PLUGIN_FILE="${INVENTREE_DATA_DIR}/plugins.txt"
# Worker configuration (can be altered by user) # Worker configuration (can be altered by user)
ENV INVENTREE_GUNICORN_WORKERS="4" ENV INVENTREE_GUNICORN_WORKERS="4"
@ -129,8 +131,12 @@ ENV INVENTREE_PY_ENV="${INVENTREE_DEV_DIR}/env"
# Override default path settings # Override default path settings
ENV INVENTREE_STATIC_ROOT="${INVENTREE_DEV_DIR}/static" ENV INVENTREE_STATIC_ROOT="${INVENTREE_DEV_DIR}/static"
ENV INVENTREE_MEDIA_ROOT="${INVENTREE_DEV_DIR}/media" ENV INVENTREE_MEDIA_ROOT="${INVENTREE_DEV_DIR}/media"
ENV INVENTREE_PLUGIN_DIR="${INVENTREE_DEV_DIR}/plugins"
ENV INVENTREE_CONFIG_FILE="${INVENTREE_DEV_DIR}/config.yaml" ENV INVENTREE_CONFIG_FILE="${INVENTREE_DEV_DIR}/config.yaml"
ENV INVENTREE_SECRET_KEY_FILE="${INVENTREE_DEV_DIR}/secret_key.txt" ENV INVENTREE_SECRET_KEY_FILE="${INVENTREE_DEV_DIR}/secret_key.txt"
ENV INVENTREE_PLUGIN_FILE="${INVENTREE_DEV_DIR}/plugins.txt"
WORKDIR ${INVENTREE_HOME} WORKDIR ${INVENTREE_HOME}

View File

@ -71,17 +71,32 @@ def manage(c, cmd, pty=False):
cmd=cmd cmd=cmd
), pty=pty) ), pty=pty)
@task @task
def plugins(c):
"""
Installs all plugins as specified in 'plugins.txt'
"""
from InvenTree.InvenTree.config import get_plugin_file
plugin_file = get_plugin_file()
print(f"Installing plugin packages from '{plugin_file}'")
# Install the plugins
c.run(f"pip3 install -U -r '{plugin_file}'")
@task(post=[plugins])
def install(c): def install(c):
""" """
Installs required python packages Installs required python packages
""" """
print("Installing required python packages from 'requirements.txt'")
# Install required Python packages with PIP # Install required Python packages with PIP
c.run('pip3 install -U -r requirements.txt') c.run('pip3 install -U -r requirements.txt')
@task @task
def shell(c): def shell(c):
""" """