added env variable and file to be able to install python packages on start
a better approach for installing packages.
This commit is contained in:
parent
f4668aab60
commit
531ffc7eb6
4 changed files with 73 additions and 0 deletions
|
|
@ -92,6 +92,8 @@ Certain values can be set via environment variables, using the `-e` parameter on
|
||||||
* __YTP_DB_FILE__: The path to the SQLite database file. Defaults to `{config_path}/ytptube.db`.
|
* __YTP_DB_FILE__: The path to the SQLite database file. Defaults to `{config_path}/ytptube.db`.
|
||||||
* __YTP_MANUAL_ARCHIVE__: The path to the manual archive file. Defaults to `{config_path}/manual_archive.log`.
|
* __YTP_MANUAL_ARCHIVE__: The path to the manual archive file. Defaults to `{config_path}/manual_archive.log`.
|
||||||
* __YTP_UI_UPDATE_TITLE__: Whether to update the title of the page with the current stats. Defaults to `true`.
|
* __YTP_UI_UPDATE_TITLE__: Whether to update the title of the page with the current stats. Defaults to `true`.
|
||||||
|
* __YTP_PIP_PACKAGES__: a space separated list of pip packages to install. Defaults to `""`, you can also use `{config_path}/pip.txt` to install the packages.
|
||||||
|
* __YTP_PIP_IGNORE_UPDATES__: Do not update the custom pip packages. Defaults to `false`.
|
||||||
|
|
||||||
## Running behind a reverse proxy
|
## Running behind a reverse proxy
|
||||||
|
|
||||||
|
|
|
||||||
60
app/library/PackageInstaller.py
Normal file
60
app/library/PackageInstaller.py
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import importlib
|
||||||
|
from library.config import Config
|
||||||
|
|
||||||
|
LOG = logging.getLogger("package_installer")
|
||||||
|
|
||||||
|
|
||||||
|
class PackageInstaller:
|
||||||
|
"""
|
||||||
|
This class is responsible for installing and upgrading pip packages.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, config: Config):
|
||||||
|
self.config: Config = config
|
||||||
|
|
||||||
|
def from_env(self):
|
||||||
|
return self.config.pip_packages.split() if self.config.pip_packages else []
|
||||||
|
|
||||||
|
def from_file(self, file_path):
|
||||||
|
if not os.path.exists(file_path):
|
||||||
|
return []
|
||||||
|
|
||||||
|
if os.access(file_path, os.R_OK):
|
||||||
|
with open(file_path, "r") as f:
|
||||||
|
return [pkg.strip() for pkg in f.readlines() if pkg.strip()]
|
||||||
|
else:
|
||||||
|
LOG.error(f"Could not read pip packages from '{file_path}'.")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def action(self, pkg: str):
|
||||||
|
try:
|
||||||
|
importlib.import_module(pkg)
|
||||||
|
if self.config.pip_ignore_updates:
|
||||||
|
LOG.info(f"'{pkg}' is already installed. Skipping upgrades. as requested.")
|
||||||
|
return
|
||||||
|
LOG.info(f"'{pkg}' is already installed. Checking for upgrades...")
|
||||||
|
subprocess.run([sys.executable, "-m", "pip", "install", "--upgrade", pkg], check=True)
|
||||||
|
except ImportError:
|
||||||
|
LOG.info(f"'{pkg}' is not installed. Installing...")
|
||||||
|
subprocess.run([sys.executable, "-m", "pip", "install", pkg], check=True)
|
||||||
|
|
||||||
|
def check(self):
|
||||||
|
"""
|
||||||
|
Checks for user supplied pip packages and installs them if they are not already installed.
|
||||||
|
"""
|
||||||
|
pip_file = os.path.join(self.config.config_path, "pip.txt")
|
||||||
|
packages = list(set(self.from_env() + self.from_file(pip_file)))
|
||||||
|
|
||||||
|
if not packages:
|
||||||
|
return
|
||||||
|
|
||||||
|
for package in packages:
|
||||||
|
try:
|
||||||
|
self.action(package)
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error(f"Failed to install or upgrade package '{package}'. Error message: {str(e)}")
|
||||||
|
LOG.exception(e)
|
||||||
|
|
@ -56,6 +56,8 @@ class Config:
|
||||||
db_file: str = "{config_path}/ytptube.db"
|
db_file: str = "{config_path}/ytptube.db"
|
||||||
manual_archive: str = "{config_path}/archive.manual.log"
|
manual_archive: str = "{config_path}/archive.manual.log"
|
||||||
ui_update_title: bool = True
|
ui_update_title: bool = True
|
||||||
|
pip_packages: str = ""
|
||||||
|
pip_ignore_updates: bool = False
|
||||||
|
|
||||||
# immutable config vars.
|
# immutable config vars.
|
||||||
version: str = APP_VERSION
|
version: str = APP_VERSION
|
||||||
|
|
@ -146,6 +148,7 @@ class Config:
|
||||||
"remove_files",
|
"remove_files",
|
||||||
"ignore_ui",
|
"ignore_ui",
|
||||||
"ui_update_title",
|
"ui_update_title",
|
||||||
|
"pip_ignore_updates",
|
||||||
)
|
)
|
||||||
|
|
||||||
_frontend_vars: tuple = (
|
_frontend_vars: tuple = (
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ from library.encoder import Encoder
|
||||||
from library.HttpAPI import HttpAPI, LOG as http_logger
|
from library.HttpAPI import HttpAPI, LOG as http_logger
|
||||||
from library.HttpSocket import HttpSocket
|
from library.HttpSocket import HttpSocket
|
||||||
from library.Webhooks import Webhooks
|
from library.Webhooks import Webhooks
|
||||||
|
from library.PackageInstaller import PackageInstaller
|
||||||
|
|
||||||
LOG = logging.getLogger("app")
|
LOG = logging.getLogger("app")
|
||||||
MIME = magic.Magic(mime=True)
|
MIME = magic.Magic(mime=True)
|
||||||
|
|
@ -37,6 +38,13 @@ class Main:
|
||||||
self.encoder = Encoder()
|
self.encoder = Encoder()
|
||||||
|
|
||||||
self.checkFolders()
|
self.checkFolders()
|
||||||
|
|
||||||
|
try:
|
||||||
|
PackageInstaller(self.config).check()
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error(f"Failed to check for packages. Error message '{str(e)}'.")
|
||||||
|
LOG.exception(e)
|
||||||
|
|
||||||
caribou.upgrade(self.config.db_file, os.path.join(self.rootPath, "migrations"))
|
caribou.upgrade(self.config.db_file, os.path.join(self.rootPath, "migrations"))
|
||||||
|
|
||||||
connection = sqlite3.connect(database=self.config.db_file, isolation_level=None)
|
connection = sqlite3.connect(database=self.config.db_file, isolation_level=None)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue