97 lines
3.3 KiB
Python
97 lines
3.3 KiB
Python
import subprocess
|
|
import tempfile
|
|
from optional_django import six
|
|
from .exceptions import ErrorInterrogatingEnvironment, MalformedVersionInput, MissingDependency, OutdatedDependency
|
|
from .conf import settings
|
|
|
|
|
|
def run_command(cmd_to_run):
|
|
"""
|
|
Wrapper around subprocess that pipes the stderr and stdout from `cmd_to_run`
|
|
to temporary files. Using the temporary files gets around subprocess.PIPE's
|
|
issues with handling large buffers.
|
|
|
|
Note: this command will block the python process until `cmd_to_run` has completed.
|
|
|
|
Returns a tuple, containing the stderr and stdout as strings.
|
|
"""
|
|
with tempfile.TemporaryFile() as stdout_file, tempfile.TemporaryFile() as stderr_file:
|
|
|
|
# Run the command
|
|
popen = subprocess.Popen(cmd_to_run, stdout=stdout_file, stderr=stderr_file)
|
|
popen.wait()
|
|
|
|
stderr_file.seek(0)
|
|
stdout_file.seek(0)
|
|
|
|
stderr = stderr_file.read()
|
|
stdout = stdout_file.read()
|
|
|
|
if six.PY3:
|
|
stderr = stderr.decode()
|
|
stdout = stdout.decode()
|
|
|
|
return stderr, stdout
|
|
|
|
|
|
try:
|
|
_stderr, _stdout = run_command((settings.PATH, settings.VERSION_COMMAND,))
|
|
if _stderr:
|
|
raise ErrorInterrogatingEnvironment(_stderr)
|
|
npm_installed = True
|
|
npm_version_raw = _stdout.strip()
|
|
except OSError:
|
|
npm_installed = False
|
|
npm_version_raw = None
|
|
npm_version = None
|
|
if npm_version_raw:
|
|
npm_version = settings.VERSION_FILTER(npm_version_raw)
|
|
|
|
|
|
def _check_if_version_is_outdated(current_version, required_version):
|
|
if not isinstance(required_version, tuple):
|
|
raise MalformedVersionInput(
|
|
'Versions must be tuples. Received {0}'.format(required_version)
|
|
)
|
|
if len(required_version) < 3:
|
|
raise MalformedVersionInput(
|
|
'Versions must have three numbers defined. Received {0}'.format(required_version)
|
|
)
|
|
for number in required_version:
|
|
if not isinstance(number, six.integer_types):
|
|
raise MalformedVersionInput(
|
|
'Versions can only contain number. Received {0}'.format(required_version)
|
|
)
|
|
for i, number_required in enumerate(required_version):
|
|
if number_required > current_version[i]:
|
|
return True
|
|
elif number_required < current_version[i]:
|
|
return False
|
|
return current_version != required_version
|
|
|
|
|
|
def _format_version(version):
|
|
return '.'.join(map(six.text_type, version))
|
|
|
|
|
|
def raise_if_npm_missing(required_version=None):
|
|
if not npm_installed:
|
|
error = 'npm is not installed or cannot be found at path "{path}"'.format(path=settings.PATH)
|
|
if required_version:
|
|
error += '. Version {required_version} or greater is required.'.format(
|
|
required_version=_format_version(required_version)
|
|
)
|
|
raise MissingDependency(error)
|
|
|
|
|
|
def raise_if_npm_version_less_than(required_version):
|
|
if _check_if_version_is_outdated(npm_version, required_version):
|
|
raise OutdatedDependency(
|
|
(
|
|
'The installed npm version is outdated. Version {current_version} is installed, but version '
|
|
'{required_version} is required. Please update npm.'
|
|
).format(
|
|
current_version=_format_version(npm_version),
|
|
required_version=_format_version(required_version),
|
|
)
|
|
) |