From 5c2121b1a115dc83050412f3d5306d4e0c11e0af Mon Sep 17 00:00:00 2001
From: Oliver <oliver.henry.walters@gmail.com>
Date: Thu, 6 Jan 2022 12:25:07 +1100
Subject: [PATCH] Add invoke target to install plugins from file

---
 .gitignore                      |  1 +
 InvenTree/InvenTree/settings.py | 22 +++++++++++++++-------
 tasks.py                        | 23 +++++++++++++++++++++++
 3 files changed, 39 insertions(+), 7 deletions(-)

diff --git a/.gitignore b/.gitignore
index 4bc0bb1389..6532442dc7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -49,6 +49,7 @@ static_i18n
 
 # Local config file
 config.yaml
+plugins.txt
 
 # Default data file
 data.json
diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py
index e811028ccc..894332b189 100644
--- a/InvenTree/InvenTree/settings.py
+++ b/InvenTree/InvenTree/settings.py
@@ -89,13 +89,6 @@ with open(cfg_filename, 'r') as cfg:
 # We will place any config files in the same directory as the config file
 config_dir = os.path.dirname(cfg_filename)
 
-# 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
-    PLUGIN_FILE = os.path.join(config_dir, 'plugins.txt')
-
 # Default action is to run the system in Debug mode
 # SECURITY WARNING: don't run with debug turned on in production!
 DEBUG = _is_true(get_setting(
@@ -150,6 +143,21 @@ LOGGING = {
 # Get a logger instance for this setup file
 logger = logging.getLogger("inventree")
 
+# 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
+    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")
+
 """
 Specify a secret key to be used by django.
 
diff --git a/tasks.py b/tasks.py
index 4d5d7ff6c8..9eaaa261d9 100644
--- a/tasks.py
+++ b/tasks.py
@@ -78,10 +78,33 @@ def install(c):
     Installs required python packages
     """
 
+    print("Installing required python packages from 'requirements.txt'")
+
     # Install required Python packages with PIP
     c.run('pip3 install -U -r requirements.txt')
 
 
+@task
+def plugins(c):
+    """
+    Installs all plugins as specified in 'plugins.txt'
+    """
+
+    try:
+        from InvenTree.InvenTree.settings import PLUGIN_FILE
+    except:
+        print("Error: Could not import PLUGIN_FILE from settings.py")
+        return
+    
+    if not os.path.exists(PLUGIN_FILE):
+        # Create an empty plugin 
+        print(f"Plugins file '{PLUGIN_FILE}' does not exist")
+
+    print(f"Installing plugin packages from '{PLUGIN_FILE}'")
+
+    # Install the plugins
+    c.run(f"pip3 install -U -r '{PLUGIN_FILE}'")
+
 @task
 def shell(c):
     """