--- a/.eslintignore
+++ b/.eslintignore
@@ -35,18 +35,18 @@ netwerk/**
nsprpub/**
other-licenses/**
parser/**
probes/**
python/**
rdf/**
startupcache/**
testing/**
-!testing/eslint-plugin-mozilla/
-testing/eslint-plugin-mozilla/node_modules/**
+!tools/lint/eslint/eslint-plugin-mozilla/
+tools/lint/eslint/eslint-plugin-mozilla/node_modules/**
tools/**
uriloader/**
view/**
widget/**
xpcom/**
xpfe/**
xulrunner/**
--- a/.gitignore
+++ b/.gitignore
@@ -96,17 +96,17 @@ embedding/ios/GeckoEmbed/GeckoEmbed.xcod
# Ignore mozharness execution files
testing/mozharness/.tox/
testing/mozharness/build/
testing/mozharness/logs/
testing/mozharness/.coverage
testing/mozharness/nosetests.xml
# Ignore node_modules
-testing/eslint/node_modules/
+tools/lint/eslint/node_modules/
# Ignore talos virtualenv and tp5n files.
# The tp5n set is supposed to be decompressed at
# testing/talos/talos/page_load_test/tp5n in order to run tests like tps
# locally. Similarly, running talos requires a Python package virtual
# environment. Both the virtual environment and tp5n files end up littering
# the status command, so we ignore them.
testing/talos/.Python
--- a/.hgignore
+++ b/.hgignore
@@ -113,17 +113,17 @@ GPATH
^testing/mozharness/logs/
^testing/mozharness/.coverage
^testing/mozharness/nosetests.xml
# Ignore tox generated dir
.tox/
# Ignore node_modules
-^testing/eslint/node_modules/
+^tools/lint/eslint/node_modules/
# Ignore talos virtualenv and tp5n files.
# The tp5n set is supposed to be decompressed at
# testing/talos/talos/page_load_test/tp5n in order to run tests like tps
# locally. Similarly, running talos requires a Python package virtual
# environment. Both the virtual environment and tp5n files end up littering
# the status command, so we ignore them.
^testing/talos/.Python
--- a/python/mach_commands.py
+++ b/python/mach_commands.py
@@ -1,68 +1,30 @@
# 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/.
from __future__ import absolute_import, print_function, unicode_literals
import __main__
import argparse
-import json
import logging
import mozpack.path as mozpath
import os
-import platform
-import subprocess
-import sys
-import which
-from distutils.version import LooseVersion
from mozbuild.base import (
MachCommandBase,
)
from mach.decorators import (
CommandArgument,
CommandProvider,
Command,
)
-ESLINT_PACKAGES = [
- "eslint@2.9.0",
- "eslint-plugin-html@1.4.0",
- "eslint-plugin-mozilla@0.0.3",
- "eslint-plugin-react@4.2.3"
-]
-
-ESLINT_NOT_FOUND_MESSAGE = '''
-Could not find eslint! We looked at the --binary option, at the ESLINT
-environment variable, and then at your local node_modules path. Please Install
-eslint and needed plugins with:
-
-mach eslint --setup
-
-and try again.
-'''.strip()
-
-NODE_NOT_FOUND_MESSAGE = '''
-nodejs v4.2.3 is either not installed or is installed to a non-standard path.
-Please install nodejs from https://nodejs.org and try again.
-
-Valid installation paths:
-'''.strip()
-
-NPM_NOT_FOUND_MESSAGE = '''
-Node Package Manager (npm) is either not installed or installed to a
-non-standard path. Please install npm from https://nodejs.org (it comes as an
-option in the node installation) and try again.
-
-Valid installation paths:
-'''.strip()
-
@CommandProvider
class MachCommands(MachCommandBase):
@Command('python', category='devenv',
description='Run Python.')
@CommandArgument('args', nargs=argparse.REMAINDER)
def python(self, args):
# Avoid logging the command
@@ -194,277 +156,8 @@ class MachCommands(MachCommandBase):
message = 'TEST-UNEXPECTED-FAIL | No tests collected'
if not path_only:
message += ' (Not in PYTHON_UNIT_TESTS? Try --path-only?)'
self.log(logging.WARN, 'python-test', {}, message)
return 1
return 0 if return_code == 0 else 1
- @Command('eslint', category='devenv',
- description='Run eslint or help configure eslint for optimal development.')
- @CommandArgument('-s', '--setup', default=False, action='store_true',
- help='configure eslint for optimal development.')
- @CommandArgument('-e', '--ext', default='[.js,.jsm,.jsx,.xml,.html]',
- help='Filename extensions to lint, default: "[.js,.jsm,.jsx,.xml,.html]".')
- @CommandArgument('-b', '--binary', default=None,
- help='Path to eslint binary.')
- @CommandArgument('args', nargs=argparse.REMAINDER) # Passed through to eslint.
- def eslint(self, setup, ext=None, binary=None, args=None):
- '''Run eslint.'''
-
- module_path = self.get_eslint_module_path()
-
- # eslint requires at least node 4.2.3
- nodePath = self.getNodeOrNpmPath("node", LooseVersion("4.2.3"))
- if not nodePath:
- return 1
-
- if setup:
- return self.eslint_setup()
-
- npmPath = self.getNodeOrNpmPath("npm")
- if not npmPath:
- return 1
-
- if self.eslintModuleHasIssues():
- install = self._prompt_yn("\nContinuing will automatically fix "
- "these issues. Would you like to "
- "continue")
- if install:
- self.eslint_setup()
- else:
- return 1
-
- # Valid binaries are:
- # - Any provided by the binary argument.
- # - Any pointed at by the ESLINT environmental variable.
- # - Those provided by mach eslint --setup.
- #
- # eslint --setup installs some mozilla specific plugins and installs
- # all node modules locally. This is the preferred method of
- # installation.
-
- if not binary:
- binary = os.environ.get('ESLINT', None)
-
- if not binary:
- binary = os.path.join(module_path, "node_modules", ".bin", "eslint")
- if not os.path.isfile(binary):
- binary = None
-
- if not binary:
- print(ESLINT_NOT_FOUND_MESSAGE)
- return 1
-
- self.log(logging.INFO, 'eslint', {'binary': binary, 'args': args},
- 'Running {binary}')
-
- args = args or ['.']
-
- cmd_args = [binary,
- # Enable the HTML plugin.
- # We can't currently enable this in the global config file
- # because it has bad interactions with the SublimeText
- # ESLint plugin (bug 1229874).
- '--plugin', 'html',
- '--ext', ext, # This keeps ext as a single argument.
- ] + args
-
- success = self.run_process(cmd_args,
- pass_thru=True, # Allow user to run eslint interactively.
- ensure_exit_code=False, # Don't throw on non-zero exit code.
- require_unix_environment=True # eslint is not a valid Win32 binary.
- )
-
- self.log(logging.INFO, 'eslint', {'msg': ('No errors' if success == 0 else 'Errors')},
- 'Finished eslint. {msg} encountered.')
- return success
-
- def eslint_setup(self, update_only=False):
- """Ensure eslint is optimally configured.
-
- This command will inspect your eslint configuration and
- guide you through an interactive wizard helping you configure
- eslint for optimal use on Mozilla projects.
- """
- orig_cwd = os.getcwd()
- sys.path.append(os.path.dirname(__file__))
-
- module_path = self.get_eslint_module_path()
-
- # npm sometimes fails to respect cwd when it is run using check_call so
- # we manually switch folders here instead.
- os.chdir(module_path)
-
- npmPath = self.getNodeOrNpmPath("npm")
- if not npmPath:
- return 1
-
- # Install eslint and necessary plugins.
- for pkg in ESLINT_PACKAGES:
- name, version = pkg.split("@")
- success = False
-
- if self.node_package_installed(pkg, cwd=module_path):
- success = True
- else:
- if pkg.startswith("eslint-plugin-mozilla"):
- cmd = [npmPath, "install",
- os.path.join(module_path, "eslint-plugin-mozilla")]
- else:
- cmd = [npmPath, "install", pkg]
-
- print("Installing %s v%s using \"%s\"..."
- % (name, version, " ".join(cmd)))
- success = self.callProcess(pkg, cmd)
-
- if not success:
- return 1
-
- eslint_path = os.path.join(module_path, "node_modules", ".bin", "eslint")
-
- print("\nESLint and approved plugins installed successfully!")
- print("\nNOTE: Your local eslint binary is at %s\n" % eslint_path)
-
- os.chdir(orig_cwd)
-
- def callProcess(self, name, cmd, cwd=None):
- try:
- with open(os.devnull, "w") as fnull:
- subprocess.check_call(cmd, cwd=cwd, stdout=fnull)
- except subprocess.CalledProcessError:
- if cwd:
- print("\nError installing %s in the %s folder, aborting." % (name, cwd))
- else:
- print("\nError installing %s, aborting." % name)
-
- return False
-
- return True
-
- def eslintModuleHasIssues(self):
- has_issues = False
- node_module_path = os.path.join(self.get_eslint_module_path(), "node_modules")
-
- for pkg in ESLINT_PACKAGES:
- name, req_version = pkg.split("@")
- path = os.path.join(node_module_path, name, "package.json")
-
- if not os.path.exists(path):
- print("%s v%s needs to be installed locally." % (name, req_version))
- has_issues = True
- continue
-
- data = json.load(open(path))
-
- if data["version"] != req_version:
- print("%s v%s should be v%s." % (name, version, req_version))
- has_issues = True
-
- return has_issues
-
- def node_package_installed(self, package_name="", globalInstall=False, cwd=None):
- try:
- npmPath = self.getNodeOrNpmPath("npm")
-
- cmd = [npmPath, "ls", "--parseable", package_name]
-
- if globalInstall:
- cmd.append("-g")
-
- with open(os.devnull, "w") as fnull:
- subprocess.check_call(cmd, stdout=fnull, stderr=fnull, cwd=cwd)
-
- return True
- except subprocess.CalledProcessError:
- return False
-
- def getPossibleNodePathsWin(self):
- """
- Return possible nodejs paths on Windows.
- """
- if platform.system() != "Windows":
- return []
-
- return list({
- "%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")
- })
-
- def getNodeOrNpmPath(self, filename, minversion=None):
- """
- Return the nodejs or npm path.
- """
- if platform.system() == "Windows":
- for ext in [".cmd", ".exe", ""]:
- try:
- nodeOrNpmPath = which.which(filename + ext,
- path=self.getPossibleNodePathsWin())
- if self.is_valid(nodeOrNpmPath, minversion):
- return nodeOrNpmPath
- except which.WhichError:
- pass
- else:
- try:
- nodeOrNpmPath = which.which(filename)
- if self.is_valid(nodeOrNpmPath, minversion):
- return nodeOrNpmPath
- except which.WhichError:
- pass
-
- if filename == "node":
- print(NODE_NOT_FOUND_MESSAGE)
- elif filename == "npm":
- print(NPM_NOT_FOUND_MESSAGE)
-
- if platform.system() == "Windows":
- appPaths = self.getPossibleNodePathsWin()
-
- for p in appPaths:
- print(" - %s" % p)
- elif platform.system() == "Darwin":
- print(" - /usr/local/bin/node")
- elif platform.system() == "Linux":
- print(" - /usr/bin/nodejs")
-
- return None
-
- def is_valid(self, path, minversion = None):
- try:
- version_str = subprocess.check_output([path, "--version"],
- stderr=subprocess.STDOUT)
- if minversion:
- # nodejs prefixes its version strings with "v"
- version = LooseVersion(version_str.lstrip('v'))
- return version >= minversion
- return True
- except (subprocess.CalledProcessError, OSError):
- return False
-
- def get_project_root(self):
- fullpath = os.path.abspath(sys.modules['__main__'].__file__)
- return os.path.dirname(fullpath)
-
- def get_eslint_module_path(self):
- return os.path.join(self.get_project_root(), "testing", "eslint")
-
- def _prompt_yn(self, msg):
- if not sys.stdin.isatty():
- return False
-
- print('%s? [Y/n]' % msg)
-
- while True:
- choice = raw_input().lower().strip()
-
- if not choice:
- return True
-
- if choice in ('y', 'yes'):
- return True
-
- if choice in ('n', 'no'):
- return False
-
- print('Must reply with one of {yes, no, y, n}.')
--- a/testing/taskcluster/tasks/branches/base_jobs.yml
+++ b/testing/taskcluster/tasks/branches/base_jobs.yml
@@ -517,17 +517,17 @@ tasks:
- '**/*.jsm'
- '**/*.jsx'
- '**/*.html'
- '**/*.xml'
# Run when eslint policies change.
- '**/.eslintignore'
- '**/*eslintrc*'
# The plugin implementing custom checks.
- - 'testing/eslint/eslint-plugin-mozilla/**'
+ - 'tools/lint/eslint/eslint-plugin-mozilla/**'
# Other misc lint related files.
- 'tools/lint/**'
- 'testing/docker/lint/**'
android-api-15-gradle-dependencies:
task: tasks/builds/android_api_15_gradle_dependencies.yml
root: true
when:
file_patterns:
--- a/testing/taskcluster/tasks/tests/eslint-gecko.yml
+++ b/testing/taskcluster/tasks/tests/eslint-gecko.yml
@@ -17,22 +17,22 @@ task:
path: 'public/image.tar'
taskId: '{{#task_id_for_image}}lint{{/task_id_for_image}}'
command:
- bash
- -cx
- >
tc-vcs checkout ./gecko {{base_repository}} {{head_repository}} {{head_rev}} {{head_ref}} &&
- cd gecko/testing/eslint &&
+ cd gecko/tools/lint/eslint &&
/build/tooltool.py fetch -m manifest.tt &&
tar xvfz eslint.tar.gz &&
rm eslint.tar.gz &&
- cd ../.. &&
- testing/eslint/node_modules/.bin/eslint --quiet --plugin html --ext [.js,.jsm,.jsx,.xml,.html] -f tools/lint/eslint-formatter .
+ cd ../../.. &&
+ tools/lint/eslint/node_modules/.bin/eslint --quiet --plugin html --ext [.js,.jsm,.jsx,.xml,.html] -f tools/lint/eslint-formatter .
extra:
locations:
build: null
tests: null
treeherder:
machine:
platform: lint
rename from testing/eslint/eslint-plugin-mozilla/LICENSE
rename to tools/lint/eslint/eslint-plugin-mozilla/LICENSE
rename from testing/eslint/eslint-plugin-mozilla/docs/balanced-listeners.rst
rename to tools/lint/eslint/eslint-plugin-mozilla/docs/balanced-listeners.rst
rename from testing/eslint/eslint-plugin-mozilla/docs/import-browserjs-globals.rst
rename to tools/lint/eslint/eslint-plugin-mozilla/docs/import-browserjs-globals.rst
rename from testing/eslint/eslint-plugin-mozilla/docs/import-globals.rst
rename to tools/lint/eslint/eslint-plugin-mozilla/docs/import-globals.rst
rename from testing/eslint/eslint-plugin-mozilla/docs/import-headjs-globals.rst
rename to tools/lint/eslint/eslint-plugin-mozilla/docs/import-headjs-globals.rst
rename from testing/eslint/eslint-plugin-mozilla/docs/index.rst
rename to tools/lint/eslint/eslint-plugin-mozilla/docs/index.rst
rename from testing/eslint/eslint-plugin-mozilla/docs/mark-test-function-used.rst
rename to tools/lint/eslint/eslint-plugin-mozilla/docs/mark-test-function-used.rst
rename from testing/eslint/eslint-plugin-mozilla/docs/no-aArgs.rst
rename to tools/lint/eslint/eslint-plugin-mozilla/docs/no-aArgs.rst
rename from testing/eslint/eslint-plugin-mozilla/docs/no-cpows-in-tests.rst
rename to tools/lint/eslint/eslint-plugin-mozilla/docs/no-cpows-in-tests.rst
rename from testing/eslint/eslint-plugin-mozilla/docs/reject-importGlobalProperties.rst
rename to tools/lint/eslint/eslint-plugin-mozilla/docs/reject-importGlobalProperties.rst
rename from testing/eslint/eslint-plugin-mozilla/docs/var-only-at-top-level.rst
rename to tools/lint/eslint/eslint-plugin-mozilla/docs/var-only-at-top-level.rst
rename from testing/eslint/eslint-plugin-mozilla/lib/globals.js
rename to tools/lint/eslint/eslint-plugin-mozilla/lib/globals.js
rename from testing/eslint/eslint-plugin-mozilla/lib/helpers.js
rename to tools/lint/eslint/eslint-plugin-mozilla/lib/helpers.js
rename from testing/eslint/eslint-plugin-mozilla/lib/index.js
rename to tools/lint/eslint/eslint-plugin-mozilla/lib/index.js
rename from testing/eslint/eslint-plugin-mozilla/lib/processors/xbl-bindings.js
rename to tools/lint/eslint/eslint-plugin-mozilla/lib/processors/xbl-bindings.js
rename from testing/eslint/eslint-plugin-mozilla/lib/rules/.eslintrc
rename to tools/lint/eslint/eslint-plugin-mozilla/lib/rules/.eslintrc
rename from testing/eslint/eslint-plugin-mozilla/lib/rules/balanced-listeners.js
rename to tools/lint/eslint/eslint-plugin-mozilla/lib/rules/balanced-listeners.js
rename from testing/eslint/eslint-plugin-mozilla/lib/rules/import-browserjs-globals.js
rename to tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-browserjs-globals.js
rename from testing/eslint/eslint-plugin-mozilla/lib/rules/import-globals.js
rename to tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-globals.js
rename from testing/eslint/eslint-plugin-mozilla/lib/rules/import-headjs-globals.js
rename to tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-headjs-globals.js
rename from testing/eslint/eslint-plugin-mozilla/lib/rules/mark-test-function-used.js
rename to tools/lint/eslint/eslint-plugin-mozilla/lib/rules/mark-test-function-used.js
rename from testing/eslint/eslint-plugin-mozilla/lib/rules/no-aArgs.js
rename to tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-aArgs.js
rename from testing/eslint/eslint-plugin-mozilla/lib/rules/no-cpows-in-tests.js
rename to tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-cpows-in-tests.js
rename from testing/eslint/eslint-plugin-mozilla/lib/rules/reject-importGlobalProperties.js
rename to tools/lint/eslint/eslint-plugin-mozilla/lib/rules/reject-importGlobalProperties.js
rename from testing/eslint/eslint-plugin-mozilla/lib/rules/var-only-at-top-level.js
rename to tools/lint/eslint/eslint-plugin-mozilla/lib/rules/var-only-at-top-level.js
rename from testing/eslint/eslint-plugin-mozilla/moz.build
rename to tools/lint/eslint/eslint-plugin-mozilla/moz.build
rename from testing/eslint/eslint-plugin-mozilla/package.json
rename to tools/lint/eslint/eslint-plugin-mozilla/package.json
rename from testing/eslint/manifest.tt
rename to tools/lint/eslint/manifest.tt
rename from testing/eslint/npm-shrinkwrap.json
rename to tools/lint/eslint/npm-shrinkwrap.json
rename from testing/eslint/package.json
rename to tools/lint/eslint/package.json
rename from testing/eslint/update
rename to tools/lint/eslint/update
--- a/testing/eslint/update
+++ b/tools/lint/eslint/update
@@ -1,10 +1,10 @@
#!/bin/sh
-# Force the scripts working directory to be projdir/testing/eslint.
+# Force the scripts working directory to be projdir/tools/lint/eslint.
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $DIR
echo "To complete this script you will need the following tokens from https://api.pub.build.mozilla.org/tokenauth/"
echo " - tooltool.upload.public"
echo " - tooltool.download.public"
echo ""
read -p "Are these tokens visible at the above URL (y/n)?" choice
@@ -50,16 +50,16 @@ echo "Downloading tooltool..."
wget https://raw.githubusercontent.com/mozilla/build-tooltool/master/tooltool.py
chmod +x tooltool.py
echo "Adding eslint.tar.gz to tooltool..."
rm manifest.tt
./tooltool.py add --visibility public eslint.tar.gz
echo "Uploading eslint.tar.gz to tooltool..."
-./tooltool.py upload --authentication-file=~/.tooltool-token --message "node_modules folder update for testing/eslint"
+./tooltool.py upload --authentication-file=~/.tooltool-token --message "node_modules folder update for tools/lint/eslint"
echo "Cleaning up..."
rm eslint.tar.gz
rm tooltool.py
echo ""
echo "Update complete, please commit and check in your changes."
--- a/tools/lint/mach_commands.py
+++ b/tools/lint/mach_commands.py
@@ -1,15 +1,23 @@
# 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/.
from __future__ import absolute_import, print_function, unicode_literals
+import argparse
+import json
+import logging
import os
+import platform
+import subprocess
+import sys
+import which
+from distutils.version import LooseVersion
from mozbuild.base import (
MachCommandBase,
)
from mach.decorators import (
CommandArgument,
@@ -17,16 +25,49 @@ from mach.decorators import (
Command,
SubCommand,
)
here = os.path.abspath(os.path.dirname(__file__))
+ESLINT_PACKAGES = [
+ "eslint@2.9.0",
+ "eslint-plugin-html@1.4.0",
+ "eslint-plugin-mozilla@0.0.3",
+ "eslint-plugin-react@4.2.3"
+]
+
+ESLINT_NOT_FOUND_MESSAGE = '''
+Could not find eslint! We looked at the --binary option, at the ESLINT
+environment variable, and then at your local node_modules path. Please Install
+eslint and needed plugins with:
+
+mach eslint --setup
+
+and try again.
+'''.strip()
+
+NODE_NOT_FOUND_MESSAGE = '''
+nodejs v4.2.3 is either not installed or is installed to a non-standard path.
+Please install nodejs from https://nodejs.org and try again.
+
+Valid installation paths:
+'''.strip()
+
+NPM_NOT_FOUND_MESSAGE = '''
+Node Package Manager (npm) is either not installed or installed to a
+non-standard path. Please install npm from https://nodejs.org (it comes as an
+option in the node installation) and try again.
+
+Valid installation paths:
+'''.strip()
+
+
@CommandProvider
class MachCommands(MachCommandBase):
@Command(
'lint', category='devenv',
description='Run linters.')
@CommandArgument(
'paths', nargs='*', default=None,
@@ -83,8 +124,279 @@ class MachCommands(MachCommandBase):
if ext != '.lint':
continue
if linters and name not in linters:
continue
lints.append(os.path.join(here, f))
return lints
+
+ @Command('eslint', category='devenv',
+ description='Run eslint or help configure eslint for optimal development.')
+ @CommandArgument('-s', '--setup', default=False, action='store_true',
+ help='configure eslint for optimal development.')
+ @CommandArgument('-e', '--ext', default='[.js,.jsm,.jsx,.xml,.html]',
+ help='Filename extensions to lint, default: "[.js,.jsm,.jsx,.xml,.html]".')
+ @CommandArgument('-b', '--binary', default=None,
+ help='Path to eslint binary.')
+ @CommandArgument('args', nargs=argparse.REMAINDER) # Passed through to eslint.
+ def eslint(self, setup, ext=None, binary=None, args=None):
+ '''Run eslint.'''
+
+ module_path = self.get_eslint_module_path()
+
+ # eslint requires at least node 4.2.3
+ nodePath = self.getNodeOrNpmPath("node", LooseVersion("4.2.3"))
+ if not nodePath:
+ return 1
+
+ if setup:
+ return self.eslint_setup()
+
+ npmPath = self.getNodeOrNpmPath("npm")
+ if not npmPath:
+ return 1
+
+ if self.eslintModuleHasIssues():
+ install = self._prompt_yn("\nContinuing will automatically fix "
+ "these issues. Would you like to "
+ "continue")
+ if install:
+ self.eslint_setup()
+ else:
+ return 1
+
+ # Valid binaries are:
+ # - Any provided by the binary argument.
+ # - Any pointed at by the ESLINT environmental variable.
+ # - Those provided by mach eslint --setup.
+ #
+ # eslint --setup installs some mozilla specific plugins and installs
+ # all node modules locally. This is the preferred method of
+ # installation.
+
+ if not binary:
+ binary = os.environ.get('ESLINT', None)
+
+ if not binary:
+ binary = os.path.join(module_path, "node_modules", ".bin", "eslint")
+ if not os.path.isfile(binary):
+ binary = None
+
+ if not binary:
+ print(ESLINT_NOT_FOUND_MESSAGE)
+ return 1
+
+ self.log(logging.INFO, 'eslint', {'binary': binary, 'args': args},
+ 'Running {binary}')
+
+ args = args or ['.']
+
+ cmd_args = [binary,
+ # Enable the HTML plugin.
+ # We can't currently enable this in the global config file
+ # because it has bad interactions with the SublimeText
+ # ESLint plugin (bug 1229874).
+ '--plugin', 'html',
+ '--ext', ext, # This keeps ext as a single argument.
+ ] + args
+
+ success = self.run_process(
+ cmd_args,
+ pass_thru=True, # Allow user to run eslint interactively.
+ ensure_exit_code=False, # Don't throw on non-zero exit code.
+ require_unix_environment=True # eslint is not a valid Win32 binary.
+ )
+
+ self.log(logging.INFO, 'eslint', {'msg': ('No errors' if success == 0 else 'Errors')},
+ 'Finished eslint. {msg} encountered.')
+ return success
+
+ def eslint_setup(self, update_only=False):
+ """Ensure eslint is optimally configured.
+
+ This command will inspect your eslint configuration and
+ guide you through an interactive wizard helping you configure
+ eslint for optimal use on Mozilla projects.
+ """
+ orig_cwd = os.getcwd()
+ sys.path.append(os.path.dirname(__file__))
+
+ module_path = self.get_eslint_module_path()
+
+ # npm sometimes fails to respect cwd when it is run using check_call so
+ # we manually switch folders here instead.
+ os.chdir(module_path)
+
+ npmPath = self.getNodeOrNpmPath("npm")
+ if not npmPath:
+ return 1
+
+ # Install eslint and necessary plugins.
+ for pkg in ESLINT_PACKAGES:
+ name, version = pkg.split("@")
+ success = False
+
+ if self.node_package_installed(pkg, cwd=module_path):
+ success = True
+ else:
+ if pkg.startswith("eslint-plugin-mozilla"):
+ cmd = [npmPath, "install",
+ os.path.join(module_path, "eslint-plugin-mozilla")]
+ else:
+ cmd = [npmPath, "install", pkg]
+
+ print("Installing %s v%s using \"%s\"..."
+ % (name, version, " ".join(cmd)))
+ success = self.callProcess(pkg, cmd)
+
+ if not success:
+ return 1
+
+ eslint_path = os.path.join(module_path, "node_modules", ".bin", "eslint")
+
+ print("\nESLint and approved plugins installed successfully!")
+ print("\nNOTE: Your local eslint binary is at %s\n" % eslint_path)
+
+ os.chdir(orig_cwd)
+
+ def callProcess(self, name, cmd, cwd=None):
+ try:
+ with open(os.devnull, "w") as fnull:
+ subprocess.check_call(cmd, cwd=cwd, stdout=fnull)
+ except subprocess.CalledProcessError:
+ if cwd:
+ print("\nError installing %s in the %s folder, aborting." % (name, cwd))
+ else:
+ print("\nError installing %s, aborting." % name)
+
+ return False
+
+ return True
+
+ def eslintModuleHasIssues(self):
+ has_issues = False
+ node_module_path = os.path.join(self.get_eslint_module_path(), "node_modules")
+
+ for pkg in ESLINT_PACKAGES:
+ name, req_version = pkg.split("@")
+ path = os.path.join(node_module_path, name, "package.json")
+
+ if not os.path.exists(path):
+ print("%s v%s needs to be installed locally." % (name, req_version))
+ has_issues = True
+ continue
+
+ data = json.load(open(path))
+
+ if data["version"] != req_version:
+ print("%s v%s should be v%s." % (name, data["version"], req_version))
+ has_issues = True
+
+ return has_issues
+
+ def node_package_installed(self, package_name="", globalInstall=False, cwd=None):
+ try:
+ npmPath = self.getNodeOrNpmPath("npm")
+
+ cmd = [npmPath, "ls", "--parseable", package_name]
+
+ if globalInstall:
+ cmd.append("-g")
+
+ with open(os.devnull, "w") as fnull:
+ subprocess.check_call(cmd, stdout=fnull, stderr=fnull, cwd=cwd)
+
+ return True
+ except subprocess.CalledProcessError:
+ return False
+
+ def getPossibleNodePathsWin(self):
+ """
+ Return possible nodejs paths on Windows.
+ """
+ if platform.system() != "Windows":
+ return []
+
+ return list({
+ "%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")
+ })
+
+ def getNodeOrNpmPath(self, filename, minversion=None):
+ """
+ Return the nodejs or npm path.
+ """
+ if platform.system() == "Windows":
+ for ext in [".cmd", ".exe", ""]:
+ try:
+ nodeOrNpmPath = which.which(filename + ext,
+ path=self.getPossibleNodePathsWin())
+ if self.is_valid(nodeOrNpmPath, minversion):
+ return nodeOrNpmPath
+ except which.WhichError:
+ pass
+ else:
+ try:
+ nodeOrNpmPath = which.which(filename)
+ if self.is_valid(nodeOrNpmPath, minversion):
+ return nodeOrNpmPath
+ except which.WhichError:
+ pass
+
+ if filename == "node":
+ print(NODE_NOT_FOUND_MESSAGE)
+ elif filename == "npm":
+ print(NPM_NOT_FOUND_MESSAGE)
+
+ if platform.system() == "Windows":
+ appPaths = self.getPossibleNodePathsWin()
+
+ for p in appPaths:
+ print(" - %s" % p)
+ elif platform.system() == "Darwin":
+ print(" - /usr/local/bin/node")
+ elif platform.system() == "Linux":
+ print(" - /usr/bin/nodejs")
+
+ return None
+
+ def is_valid(self, path, minversion=None):
+ try:
+ version_str = subprocess.check_output([path, "--version"],
+ stderr=subprocess.STDOUT)
+ if minversion:
+ # nodejs prefixes its version strings with "v"
+ version = LooseVersion(version_str.lstrip('v'))
+ return version >= minversion
+ return True
+ except (subprocess.CalledProcessError, OSError):
+ return False
+
+ def get_project_root(self):
+ fullpath = os.path.abspath(sys.modules['__main__'].__file__)
+ return os.path.dirname(fullpath)
+
+ def get_eslint_module_path(self):
+ return os.path.join(self.get_project_root(), "testing", "eslint")
+
+ def _prompt_yn(self, msg):
+ if not sys.stdin.isatty():
+ return False
+
+ print('%s? [Y/n]' % msg)
+
+ while True:
+ choice = raw_input().lower().strip()
+
+ if not choice:
+ return True
+
+ if choice in ('y', 'yes'):
+ return True
+
+ if choice in ('n', 'no'):
+ return False
+
+ print('Must reply with one of {yes, no, y, n}.')