summaryrefslogtreecommitdiffstats
path: root/python/mozbuild/mozbuild/nodeutil.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/mozbuild/mozbuild/nodeutil.py')
-rw-r--r--python/mozbuild/mozbuild/nodeutil.py126
1 files changed, 126 insertions, 0 deletions
diff --git a/python/mozbuild/mozbuild/nodeutil.py b/python/mozbuild/mozbuild/nodeutil.py
new file mode 100644
index 0000000000..8ec724ab89
--- /dev/null
+++ b/python/mozbuild/mozbuild/nodeutil.py
@@ -0,0 +1,126 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import os
+import platform
+import subprocess
+from distutils.version import StrictVersion
+
+from mozboot.util import get_tools_dir
+from mozfile import which
+from six import PY3
+
+NODE_MIN_VERSION = StrictVersion("12.22.12")
+NPM_MIN_VERSION = StrictVersion("6.14.16")
+
+
+def find_node_paths():
+ """Determines the possible paths for node executables.
+
+ Returns a list of paths, which includes the build state directory.
+ """
+ mozbuild_tools_dir = get_tools_dir()
+
+ if platform.system() == "Windows":
+ mozbuild_node_path = os.path.join(mozbuild_tools_dir, "node")
+ else:
+ mozbuild_node_path = os.path.join(mozbuild_tools_dir, "node", "bin")
+
+ # We still fallback to the PATH, since on OSes that don't have toolchain
+ # artifacts available to download, Node may be coming from $PATH.
+ paths = [mozbuild_node_path] + os.environ.get("PATH").split(os.pathsep)
+
+ if platform.system() == "Windows":
+ paths += [
+ "%s\\nodejs" % os.environ.get("SystemDrive"),
+ os.path.join(os.environ.get("ProgramFiles"), "nodejs"),
+ os.path.join(os.environ.get("PROGRAMW6432"), "nodejs"),
+ os.path.join(os.environ.get("PROGRAMFILES"), "nodejs"),
+ ]
+
+ return paths
+
+
+def check_executable_version(exe, wrap_call_with_node=False):
+ """Determine the version of a Node executable by invoking it.
+
+ May raise ``subprocess.CalledProcessError`` or ``ValueError`` on failure.
+ """
+ out = None
+ # npm may be a script (Except on Windows), so we must call it with node.
+ if wrap_call_with_node and platform.system() != "Windows":
+ binary, _ = find_node_executable()
+ if binary:
+ out = (
+ subprocess.check_output(
+ [binary, exe, "--version"], universal_newlines=PY3
+ )
+ .lstrip("v")
+ .rstrip()
+ )
+
+ # If we can't find node, or we don't need to wrap it, fallback to calling
+ # direct.
+ if not out:
+ out = (
+ subprocess.check_output([exe, "--version"], universal_newlines=PY3)
+ .lstrip("v")
+ .rstrip()
+ )
+ return StrictVersion(out)
+
+
+def find_node_executable(
+ nodejs_exe=os.environ.get("NODEJS"), min_version=NODE_MIN_VERSION
+):
+ """Find a Node executable from the mozbuild directory.
+
+ Returns a tuple containing the the path to an executable binary and a
+ version tuple. Both tuple entries will be None if a Node executable
+ could not be resolved.
+ """
+ if nodejs_exe:
+ try:
+ version = check_executable_version(nodejs_exe)
+ except (subprocess.CalledProcessError, ValueError):
+ return None, None
+
+ if version >= min_version:
+ return nodejs_exe, version.version
+
+ return None, None
+
+ # "nodejs" is first in the tuple on the assumption that it's only likely to
+ # exist on systems (probably linux distros) where there is a program in the path
+ # called "node" that does something else.
+ return find_executable("node", min_version)
+
+
+def find_npm_executable(min_version=NPM_MIN_VERSION):
+ """Find a Node executable from the mozbuild directory.
+
+ Returns a tuple containing the the path to an executable binary and a
+ version tuple. Both tuple entries will be None if a Node executable
+ could not be resolved.
+ """
+ return find_executable("npm", min_version, True)
+
+
+def find_executable(name, min_version, use_node_for_version_check=False):
+ paths = find_node_paths()
+ exe = which(name, path=paths)
+
+ if not exe:
+ return None, None
+
+ # Verify we can invoke the executable and its version is acceptable.
+ try:
+ version = check_executable_version(exe, use_node_for_version_check)
+ except (subprocess.CalledProcessError, ValueError):
+ return None, None
+
+ if version < min_version:
+ return None, None
+
+ return exe, version.version