mirror of
https://github.com/inventree/InvenTree.git
synced 2025-06-16 20:15:44 +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).
|
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.
|
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)
|
### INVE-I (InvenTree Information)
|
||||||
Information — These are not errors but information messages. They might point out potential issues or just provide 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
|
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():
|
def is_docker_environment():
|
||||||
"""Check if the InvenTree environment is running in a Docker container."""
|
"""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'))
|
return is_true(os.environ.get('INVENTREE_DOCKER', 'False'))
|
||||||
|
|
||||||
|
|
||||||
def is_rtd_environment():
|
def is_rtd_environment():
|
||||||
"""Check if the InvenTree environment is running on ReadTheDocs."""
|
"""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'))
|
return is_true(os.environ.get('READTHEDOCS', 'False'))
|
||||||
|
|
||||||
|
|
||||||
def is_debug_environment():
|
def is_debug_environment():
|
||||||
"""Check if the InvenTree environment is running in a 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(
|
return is_true(os.environ.get('INVENTREE_DEBUG', 'False')) or is_true(
|
||||||
os.environ.get('RUNNER_DEBUG', 'False')
|
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
|
# region execution logging helpers
|
||||||
def task_exception_handler(t, v, tb):
|
def task_exception_handler(t, v, tb):
|
||||||
"""Handle exceptions raised by tasks.
|
"""Handle exceptions raised by tasks.
|
||||||
@ -121,9 +157,9 @@ def state_logger(fn=None, method_name=None):
|
|||||||
|
|
||||||
|
|
||||||
# region environment checks
|
# region environment checks
|
||||||
def check_invoke_version():
|
def envcheck_invoke_version():
|
||||||
"""Check that the installed invoke version meets minimum requirements."""
|
"""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('.')))
|
min_version = tuple(map(int, MIN_INVOKE_VERSION.split('.')))
|
||||||
invoke_version = tuple(map(int, invoke.__version__.split('.'))) # noqa: RUF048
|
invoke_version = tuple(map(int, invoke.__version__.split('.'))) # noqa: RUF048
|
||||||
@ -134,14 +170,14 @@ def check_invoke_version():
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def check_invoke_path():
|
def envcheck_invoke_path():
|
||||||
"""Check that the path of the used invoke is correct."""
|
"""Check that the path of the used invoke is correct."""
|
||||||
if is_docker_environment() or is_rtd_environment():
|
if is_docker_environment() or is_rtd_environment():
|
||||||
return
|
return
|
||||||
|
|
||||||
invoke_path = Path(invoke.__file__)
|
invoke_path: Path = Path(invoke.__file__)
|
||||||
env_path = Path(sys.prefix).resolve()
|
env_path: Path = Path(sys.prefix).resolve()
|
||||||
loc_path = Path(__file__).parent.resolve()
|
loc_path: Path = Path(__file__).parent.resolve()
|
||||||
if not invoke_path.is_relative_to(loc_path) and not invoke_path.is_relative_to(
|
if not invoke_path.is_relative_to(loc_path) and not invoke_path.is_relative_to(
|
||||||
env_path
|
env_path
|
||||||
):
|
):
|
||||||
@ -152,17 +188,17 @@ def check_invoke_path():
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def check_python_version():
|
def envcheck_python_version():
|
||||||
"""Check that the installed python version meets minimum requirements.
|
"""Check that the installed python version meets minimum requirements.
|
||||||
|
|
||||||
If the python version is not sufficient, exits with a non-zero exit code.
|
If the python version is not sufficient, exits with a non-zero exit code.
|
||||||
"""
|
"""
|
||||||
REQ_MAJOR = 3
|
REQ_MAJOR: int = 3
|
||||||
REQ_MINOR = 9
|
REQ_MINOR: int = 9
|
||||||
|
|
||||||
version = sys.version.split(' ')[0]
|
version = sys.version.split(' ')[0]
|
||||||
|
|
||||||
valid = True
|
valid: bool = True
|
||||||
|
|
||||||
if sys.version_info.major < REQ_MAJOR or (
|
if sys.version_info.major < REQ_MAJOR or (
|
||||||
sys.version_info.major == REQ_MAJOR and sys.version_info.minor < REQ_MINOR
|
sys.version_info.major == REQ_MAJOR and sys.version_info.minor < REQ_MINOR
|
||||||
@ -175,10 +211,35 @@ def check_python_version():
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
if __name__ in ['__main__', 'tasks']:
|
def envcheck_invoke_cmd():
|
||||||
check_invoke_version()
|
"""Checks if the rights invoke command for the current environment is used."""
|
||||||
check_invoke_path()
|
first_cmd = sys.argv[0].replace(sys.prefix, '')
|
||||||
check_python_version()
|
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
|
# endregion
|
||||||
|
|
||||||
|
|
||||||
@ -279,6 +340,9 @@ def manage_py_path():
|
|||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
|
|
||||||
|
if __name__ in ['__main__', 'tasks']:
|
||||||
|
main()
|
||||||
|
|
||||||
|
|
||||||
def run(c, cmd, path: Optional[Path] = None, pty=False, env=None):
|
def run(c, cmd, path: Optional[Path] = None, pty=False, env=None):
|
||||||
"""Runs a given command a given path.
|
"""Runs a given command a given path.
|
||||||
@ -1399,11 +1463,12 @@ Yarn {yarn if yarn else NA}
|
|||||||
Environment:
|
Environment:
|
||||||
Docker {is_docker_environment()}
|
Docker {is_docker_environment()}
|
||||||
RTD {is_rtd_environment()}
|
RTD {is_rtd_environment()}
|
||||||
|
PKG {is_pkg_installer()}
|
||||||
|
|
||||||
Commit hash: {InvenTreeVersion.inventreeCommitHash()}
|
Commit hash: {InvenTreeVersion.inventreeCommitHash()}
|
||||||
Commit date: {InvenTreeVersion.inventreeCommitDate()}"""
|
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(
|
print(
|
||||||
"""
|
"""
|
||||||
You are probably running the package installer / single-line installer. Please mention this in any bug reports!
|
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()
|
).strip()
|
||||||
except Exception:
|
except Exception:
|
||||||
# .deb Packages contain extra information in the VERSION file
|
# .deb Packages contain extra information in the VERSION file
|
||||||
version_file = local_dir().joinpath('VERSION')
|
content: dict = get_version_vals()
|
||||||
if not version_file.exists():
|
if is_pkg_installer(content):
|
||||||
return
|
|
||||||
from dotenv import dotenv_values
|
|
||||||
|
|
||||||
content = dotenv_values(version_file)
|
|
||||||
if (
|
|
||||||
'INVENTREE_PKG_INSTALLER' in content
|
|
||||||
and content['INVENTREE_PKG_INSTALLER'] == 'PKG'
|
|
||||||
):
|
|
||||||
ref = content.get('INVENTREE_COMMIT_SHA')
|
ref = content.get('INVENTREE_COMMIT_SHA')
|
||||||
info(
|
info(
|
||||||
f'[INFO] Running in package environment, got commit "{ref}" from VERSION file'
|
f'[INFO] Running in package environment, got commit "{ref}" from VERSION file'
|
||||||
|
Reference in New Issue
Block a user