mirror of
https://github.com/inventree/InvenTree.git
synced 2025-06-13 18:45:40 +00:00
feat(backend): Add check to cli tools to confirm the right commands for deployment method are used (#9687)
* refactor * rename functions * move checking for a package install out * [FR] Add check to cli tools to confirm the right commands for deployment method are used Fixes #9684 * also log pkg enviroment detection * vendor is_true * ensure content is loaded in pkg enviroment * fix tests and imporve error message * cleanup * simplify * ensure runs in misconfed enviroment
This commit is contained in:
@ -99,6 +99,13 @@ There are database migrations waiting to be applied. This might lead to integrit
|
||||
Some deployment methods support [auto applying of updates](../start/config.md#auto-update). See also [Perform Database Migrations](../start/install.md#perform-database-migrations).
|
||||
Steps very between deployment methods.
|
||||
|
||||
#### INVE-W9
|
||||
**Wrong Invoke Environment - Backend**
|
||||
|
||||
The command that was used to run invoke is not the one that is recommended. This might be caused by a wrong PATH variable or by thinking you are using a different deployment method.
|
||||
The warning text will show the recommended command for intended use.
|
||||
|
||||
|
||||
### INVE-I (InvenTree Information)
|
||||
Information — These are not errors but information messages. They might point out potential issues or just provide information.
|
||||
|
||||
|
119
tasks.py
119
tasks.py
@ -17,29 +17,65 @@ from invoke import Collection, task
|
||||
from invoke.exceptions import UnexpectedExit
|
||||
|
||||
|
||||
def is_true(x):
|
||||
"""Shortcut function to determine if a value "looks" like a boolean."""
|
||||
return str(x).strip().lower() in ['1', 'y', 'yes', 't', 'true', 'on']
|
||||
|
||||
|
||||
def is_docker_environment():
|
||||
"""Check if the InvenTree environment is running in a Docker container."""
|
||||
from src.backend.InvenTree.InvenTree.config import is_true
|
||||
|
||||
return is_true(os.environ.get('INVENTREE_DOCKER', 'False'))
|
||||
|
||||
|
||||
def is_rtd_environment():
|
||||
"""Check if the InvenTree environment is running on ReadTheDocs."""
|
||||
from src.backend.InvenTree.InvenTree.config import is_true
|
||||
|
||||
return is_true(os.environ.get('READTHEDOCS', 'False'))
|
||||
|
||||
|
||||
def is_debug_environment():
|
||||
"""Check if the InvenTree environment is running in a debug environment."""
|
||||
from src.backend.InvenTree.InvenTree.config import is_true
|
||||
|
||||
return is_true(os.environ.get('INVENTREE_DEBUG', 'False')) or is_true(
|
||||
os.environ.get('RUNNER_DEBUG', 'False')
|
||||
)
|
||||
|
||||
|
||||
def get_version_vals():
|
||||
"""Get values from the VERSION file."""
|
||||
version_file = local_dir().joinpath('VERSION')
|
||||
if not version_file.exists():
|
||||
return {}
|
||||
try:
|
||||
from dotenv import dotenv_values
|
||||
|
||||
return dotenv_values(version_file)
|
||||
except ImportError:
|
||||
error(
|
||||
'ERROR: dotenv package not installed. You might not be running in the right environment.'
|
||||
)
|
||||
return {}
|
||||
|
||||
|
||||
def is_pkg_installer(content: Optional[dict] = None, load_content: bool = False):
|
||||
"""Check if the current environment is a package installer by VERSION/environment."""
|
||||
if load_content:
|
||||
content = get_version_vals()
|
||||
return get_installer(content) == 'PKG'
|
||||
|
||||
|
||||
def is_pkg_installer_by_path():
|
||||
"""Check if the current environment is a package installer by checking the path."""
|
||||
return len(sys.argv) >= 1 and sys.argv[0].startswith(
|
||||
'/opt/inventree/env/bin/invoke'
|
||||
)
|
||||
|
||||
|
||||
def get_installer(content: Optional[dict] = None):
|
||||
"""Get the installer for the current environment or a content dict."""
|
||||
if content is None:
|
||||
content = os.environ
|
||||
return content.get('INVENTREE_PKG_INSTALLER', None)
|
||||
|
||||
|
||||
# region execution logging helpers
|
||||
def task_exception_handler(t, v, tb):
|
||||
"""Handle exceptions raised by tasks.
|
||||
@ -121,9 +157,9 @@ def state_logger(fn=None, method_name=None):
|
||||
|
||||
|
||||
# region environment checks
|
||||
def check_invoke_version():
|
||||
def envcheck_invoke_version():
|
||||
"""Check that the installed invoke version meets minimum requirements."""
|
||||
MIN_INVOKE_VERSION = '2.0.0'
|
||||
MIN_INVOKE_VERSION: str = '2.0.0'
|
||||
|
||||
min_version = tuple(map(int, MIN_INVOKE_VERSION.split('.')))
|
||||
invoke_version = tuple(map(int, invoke.__version__.split('.'))) # noqa: RUF048
|
||||
@ -134,14 +170,14 @@ def check_invoke_version():
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def check_invoke_path():
|
||||
def envcheck_invoke_path():
|
||||
"""Check that the path of the used invoke is correct."""
|
||||
if is_docker_environment() or is_rtd_environment():
|
||||
return
|
||||
|
||||
invoke_path = Path(invoke.__file__)
|
||||
env_path = Path(sys.prefix).resolve()
|
||||
loc_path = Path(__file__).parent.resolve()
|
||||
invoke_path: Path = Path(invoke.__file__)
|
||||
env_path: Path = Path(sys.prefix).resolve()
|
||||
loc_path: Path = Path(__file__).parent.resolve()
|
||||
if not invoke_path.is_relative_to(loc_path) and not invoke_path.is_relative_to(
|
||||
env_path
|
||||
):
|
||||
@ -152,17 +188,17 @@ def check_invoke_path():
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def check_python_version():
|
||||
def envcheck_python_version():
|
||||
"""Check that the installed python version meets minimum requirements.
|
||||
|
||||
If the python version is not sufficient, exits with a non-zero exit code.
|
||||
"""
|
||||
REQ_MAJOR = 3
|
||||
REQ_MINOR = 9
|
||||
REQ_MAJOR: int = 3
|
||||
REQ_MINOR: int = 9
|
||||
|
||||
version = sys.version.split(' ')[0]
|
||||
|
||||
valid = True
|
||||
valid: bool = True
|
||||
|
||||
if sys.version_info.major < REQ_MAJOR or (
|
||||
sys.version_info.major == REQ_MAJOR and sys.version_info.minor < REQ_MINOR
|
||||
@ -175,10 +211,35 @@ def check_python_version():
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ in ['__main__', 'tasks']:
|
||||
check_invoke_version()
|
||||
check_invoke_path()
|
||||
check_python_version()
|
||||
def envcheck_invoke_cmd():
|
||||
"""Checks if the rights invoke command for the current environment is used."""
|
||||
first_cmd = sys.argv[0].replace(sys.prefix, '')
|
||||
intendded = ['/bin/invoke', '/bin/inv']
|
||||
|
||||
correct_cmd: Optional[str] = None
|
||||
if is_rtd_environment() or is_docker_environment():
|
||||
pass
|
||||
elif is_pkg_installer(load_content=True) and not is_pkg_installer_by_path():
|
||||
correct_cmd = 'inventree run invoke'
|
||||
else:
|
||||
warning('Unknown environment, not checking used invoke command')
|
||||
|
||||
if first_cmd not in intendded:
|
||||
correct_cmd = correct_cmd if correct_cmd else 'invoke'
|
||||
error('INVE-W9 - Wrong Invoke Environment')
|
||||
error(
|
||||
f'The detected invoke command `{first_cmd}` is not the intended one for this environment, ensure you are using one of the following command(s) `{correct_cmd}`'
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function to check the execution environment."""
|
||||
envcheck_invoke_version()
|
||||
envcheck_python_version()
|
||||
envcheck_invoke_path()
|
||||
envcheck_invoke_cmd()
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
|
||||
@ -279,6 +340,9 @@ def manage_py_path():
|
||||
|
||||
# endregion
|
||||
|
||||
if __name__ in ['__main__', 'tasks']:
|
||||
main()
|
||||
|
||||
|
||||
def run(c, cmd, path: Optional[Path] = None, pty=False, env=None):
|
||||
"""Runs a given command a given path.
|
||||
@ -1399,11 +1463,12 @@ Yarn {yarn if yarn else NA}
|
||||
Environment:
|
||||
Docker {is_docker_environment()}
|
||||
RTD {is_rtd_environment()}
|
||||
PKG {is_pkg_installer()}
|
||||
|
||||
Commit hash: {InvenTreeVersion.inventreeCommitHash()}
|
||||
Commit date: {InvenTreeVersion.inventreeCommitDate()}"""
|
||||
)
|
||||
if len(sys.argv) == 1 and sys.argv[0].startswith('/opt/inventree/env/lib/python'):
|
||||
if is_pkg_installer_by_path():
|
||||
print(
|
||||
"""
|
||||
You are probably running the package installer / single-line installer. Please mention this in any bug reports!
|
||||
@ -1622,16 +1687,8 @@ def frontend_download(
|
||||
).strip()
|
||||
except Exception:
|
||||
# .deb Packages contain extra information in the VERSION file
|
||||
version_file = local_dir().joinpath('VERSION')
|
||||
if not version_file.exists():
|
||||
return
|
||||
from dotenv import dotenv_values
|
||||
|
||||
content = dotenv_values(version_file)
|
||||
if (
|
||||
'INVENTREE_PKG_INSTALLER' in content
|
||||
and content['INVENTREE_PKG_INSTALLER'] == 'PKG'
|
||||
):
|
||||
content: dict = get_version_vals()
|
||||
if is_pkg_installer(content):
|
||||
ref = content.get('INVENTREE_COMMIT_SHA')
|
||||
info(
|
||||
f'[INFO] Running in package environment, got commit "{ref}" from VERSION file'
|
||||
|
Reference in New Issue
Block a user