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),
)
)