mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge pull request #2504 from SchrodingersGat/plugin-docker-support
Plugin Installation Support
This commit is contained in:
commit
8597ae89b6
1
.gitignore
vendored
1
.gitignore
vendored
@ -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
|
||||||
|
90
InvenTree/InvenTree/config.py
Normal file
90
InvenTree/InvenTree/config.py
Normal 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
|
@ -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:
|
||||||
|
@ -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}
|
||||||
|
|
||||||
|
19
tasks.py
19
tasks.py
@ -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):
|
||||||
"""
|
"""
|
||||||
|
Loading…
Reference in New Issue
Block a user