Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ env/
# Locale stats file
src/backend/InvenTree/InvenTree/locale_stats.json
src/backend/InvenTree/InvenTree/licenses.txt
src/backend/InvenTree/InvenTree/locale_stats.json
src/backend/InvenTree/InvenTree/constraint.txt

# Logs
src/backend/InvenTree/logs.json
Expand Down
28 changes: 28 additions & 0 deletions src/backend/InvenTree/InvenTree/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,34 @@ def get_backup_dir(create=True, error=True):
return bd


def get_constraint_file(force_write: bool = False) -> Path:
"""Returns the path to the constraints file.

Args:
force_write (bool): If True, the constraints file will be created if it does not exist.

Returns:
Path or str: The path to the constraints file.
"""
from .version import INVENTREE_SW_NXT_MAJOR, INVENTREE_SW_VERSION

const_file = get_base_dir().joinpath('InvenTree', 'constraint.txt')
if force_write or (not const_file.exists()):
if not force_write:
logger.warning(
'Constraint file does not exist - creating default file at %s',
const_file,
)
ensure_dir(const_file.parent)
vers = INVENTREE_SW_VERSION.replace(
' ', ''
) # ensure that the uv resolver parses the condition correctly
const_file.write_text(
f'# InvenTree constraints file\ninventree-server~={vers},<{INVENTREE_SW_NXT_MAJOR}\n'
)
return const_file


def get_plugin_file() -> Path:
"""Returns the path of the InvenTree plugins specification file.

Expand Down
1 change: 1 addition & 0 deletions src/backend/InvenTree/InvenTree/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

# InvenTree software version
INVENTREE_SW_VERSION = '1.2.0 dev'
INVENTREE_SW_NXT_MAJOR = '2.0' # the next breaking major version


logger = logging.getLogger('inventree')
Expand Down
20 changes: 18 additions & 2 deletions src/backend/InvenTree/plugin/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import plugin.models
import plugin.staticfiles
from InvenTree.config import get_constraint_file
from InvenTree.exceptions import log_error

logger = structlog.get_logger('inventree')
Expand Down Expand Up @@ -134,7 +135,15 @@ def install_plugins_file():
logger.warning('Plugin file %s does not exist', str(pf))
return

cmd = ['install', '--disable-pip-version-check', '-U', '-r', str(pf)]
cmd = [
'install',
'--disable-pip-version-check',
'-U',
'-r',
str(pf),
'-c',
str(get_constraint_file()),
]

try:
pip_command(*cmd)
Expand Down Expand Up @@ -245,7 +254,13 @@ def install_plugin(url=None, packagename=None, user=None, version=None):
logger.info('install_plugin: %s, %s', url, packagename)

# build up the command
install_name = ['install', '-U', '--disable-pip-version-check']
install_name = [
'install',
'-U',
'--disable-pip-version-check',
'-c',
str(get_constraint_file()),
]

full_pkg = ''

Expand Down Expand Up @@ -291,6 +306,7 @@ def install_plugin(url=None, packagename=None, user=None, version=None):
log_error('install_plugin', scope='plugins')

if version := ret.get('version'):
# TODO do not pin version
# Save plugin to plugins file
update_plugins_file(packagename, full_package=full_pkg, version=version)

Expand Down
27 changes: 23 additions & 4 deletions tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,34 +457,52 @@ def check_file_existence(filename: Path, overwrite: bool = False):

# Install tasks
# region tasks
@task
@state_logger('TASK13')
def update_constraint(c):
"""Update the constraints file for plugin installations."""
from src.backend.InvenTree.InvenTree.config import get_constraint_file

info('Generating constraint file for plugin installations...')
info('New constraint file written to: ', get_constraint_file(force_write=True))


@task(help={'uv': 'Use UV (experimental package manager)'})
@state_logger('TASK01')
def plugins(c, uv=False):
"""Installs all plugins as specified in 'plugins.txt'."""
from src.backend.InvenTree.InvenTree.config import ( # type: ignore[import]
get_constraint_file,
get_plugin_file,
)

plugin_file = get_plugin_file()
constraint = get_constraint_file()

info(f"Installing plugin packages from '{plugin_file}'")
info(
f"Installing plugin packages from '{plugin_file}' with constraints '{constraint}'"
)

# Install the plugins
if not uv:
run(c, f"pip3 install --disable-pip-version-check -U -r '{plugin_file}'")
run(
c,
f"pip3 install --disable-pip-version-check -U -r '{plugin_file}' -c '{constraint}'",
)
else:
run(c, 'pip3 install --no-cache-dir --disable-pip-version-check uv')
run(c, f"uv pip install -r '{plugin_file}'")
run(c, f"uv pip install -r '{plugin_file}' -c '{constraint}'")

# Collect plugin static files
manage(c, 'collectplugins')


@task(
pre=[update_constraint],
help={
'uv': 'Use UV package manager (experimental)',
'skip_plugins': 'Skip plugin installation',
}
},
)
@state_logger('TASK02')
def install(c, uv=False, skip_plugins=False):
Expand Down Expand Up @@ -845,6 +863,7 @@ def update(
info('Updating InvenTree installation...')

# Ensure required components are installed
update_constraint(c)
install(c, uv=uv)

if not skip_backup:
Expand Down
Loading