Bug 1509387 - When setting up ESLint, call npm via node so that node doesn't need to be in the path. r=ahal
authorMark Banner <standard8@mozilla.com>
Tue, 27 Nov 2018 14:46:53 +0000
changeset 504742 a177ba2ca668fabfb9e86610775e57dc3278e12d
parent 504741 a3d441ca4bb9e93d2cd9352e305f52de4460476d
child 504743 c8141cbb7ede93f9111de7dec9e0bf9a7e984bd2
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersahal
bugs1509387
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1509387 - When setting up ESLint, call npm via node so that node doesn't need to be in the path. r=ahal Differential Revision: https://phabricator.services.mozilla.com/D12742
python/mozbuild/mozbuild/nodeutil.py
tools/lint/eslint/setup_helper.py
--- a/python/mozbuild/mozbuild/nodeutil.py
+++ b/python/mozbuild/mozbuild/nodeutil.py
@@ -42,22 +42,32 @@ def find_node_paths():
             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):
+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 = subprocess.check_output([exe, "--version"]).lstrip('v').rstrip()
+    out = None
+    # npm may be a script, so we must call it with node.
+    if wrap_call_with_node:
+        binary, _ = find_node_executable()
+        if binary:
+            out = subprocess.check_output([binary, exe, "--version"]).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"]).lstrip('v').rstrip()
     return StrictVersion(out)
 
 
 def simple_which(filename, path=None):
     # Note: On windows, npm uses ".cmd"
     exts = [".cmd", ".exe", ""] if platform.system() == "Windows" else [""]
 
     for ext in exts:
@@ -97,20 +107,20 @@ def find_node_executable(nodejs_exe=os.e
 
 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)
+    return find_executable(["npm"], min_version, True)
 
 
-def find_executable(names, min_version):
+def find_executable(names, min_version, use_node_for_version_check=False):
     paths = find_node_paths()
 
     found_exe = None
     for name in names:
         try:
             exe = simple_which(name, paths)
         except which.WhichError:
             continue
@@ -119,16 +129,16 @@ def find_executable(names, min_version):
             continue
 
         if not found_exe:
             found_exe = exe
 
         # We always verify we can invoke the executable and its version is
         # sane.
         try:
-            version = check_executable_version(exe)
+            version = check_executable_version(exe, use_node_for_version_check)
         except (subprocess.CalledProcessError, ValueError):
             continue
 
         if version >= min_version:
             return exe, version.version
 
     return found_exe, None
--- a/tools/lint/eslint/setup_helper.py
+++ b/tools/lint/eslint/setup_helper.py
@@ -87,30 +87,34 @@ def eslint_setup(should_clobber=False):
             process.wait()
         else:
             mozfileremove(node_modules_path)
 
     npm_path, version = find_npm_executable()
     if not npm_path:
         return 1
 
+    node_path, _ = find_node_executable()
+    if not node_path:
+        return 1
+
     extra_parameters = ["--loglevel=error"]
 
     package_lock_json_path = os.path.join(get_project_root(), "package-lock.json")
     package_lock_json_tmp_path = os.path.join(tempfile.gettempdir(), "package-lock.json.tmp")
 
     # If we have an npm version newer than 5.8.0, just use 'ci', as that's much
     # simpler and does exactly what we want.
     npm_is_older_version = version < StrictVersion("5.8.0").version
 
     if npm_is_older_version:
-        cmd = [npm_path, "install"]
+        cmd = [node_path, npm_path, "install"]
         shutil.copy2(package_lock_json_path, package_lock_json_tmp_path)
     else:
-        cmd = [npm_path, "ci"]
+        cmd = [node_path, npm_path, "ci"]
 
     cmd.extend(extra_parameters)
     print("Installing eslint for mach using \"%s\"..." % (" ".join(cmd)))
     result = call_process("eslint", cmd)
 
     if npm_is_older_version:
         shutil.move(package_lock_json_tmp_path, package_lock_json_path)