Bug 1433410 - Add codespell support for mach lint r=ahal
☠☠ backed out by 01e0ee57f2f9 ☠ ☠
authorSylvestre Ledru <sledru@mozilla.com>
Fri, 26 Jan 2018 23:58:29 +0100
changeset 401025 e414096f1c3b8fe55c1da6344c87c2df26e28b8c
parent 401024 4f1a5068af92d329781d4805519a0904c45d0e67
child 401026 7a14e9cff76d248f7cde31e5725cc3940a131992
push id58720
push usersledru@mozilla.com
push dateFri, 26 Jan 2018 23:01:16 +0000
treeherderautoland@e414096f1c3b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersahal
bugs1433410
milestone60.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 1433410 - Add codespell support for mach lint r=ahal MozReview-Commit-ID: Ii6QjPMN0Ks
taskcluster/docker/lint/system-setup.sh
tools/lint/codespell.yml
tools/lint/spell/__init__.py
--- a/taskcluster/docker/lint/system-setup.sh
+++ b/taskcluster/docker/lint/system-setup.sh
@@ -5,16 +5,17 @@ export DEBIAN_FRONTEND=noninteractive
 set -ve
 
 test "$(whoami)" == 'root'
 
 mkdir -p /setup
 cd /setup
 
 apt_packages=()
+apt_packages+=('codespell')
 apt_packages+=('curl')
 apt_packages+=('locales')
 apt_packages+=('git')
 apt_packages+=('python')
 apt_packages+=('python-pip')
 apt_packages+=('python3')
 apt_packages+=('python3-pip')
 apt_packages+=('shellcheck')
new file mode 100644
--- /dev/null
+++ b/tools/lint/codespell.yml
@@ -0,0 +1,14 @@
+---
+codespell:
+    description: Check code for common misspellings
+    include: ['.']
+    exclude:
+        - third_party
+    # List of extensions coming from:
+    # tools/lint/{flake8,eslint}.yml
+    # tools/mach_commands.py (clang-format)
+    # + documentation
+    # + localization files
+    extensions: ['js', 'jsm', 'jsx', 'xml', 'html', 'xhtml', 'cpp', 'c', 'h', 'configure', 'py', 'properties', 'rst']
+    type: external
+    payload: spell:lint
new file mode 100644
--- /dev/null
+++ b/tools/lint/spell/__init__.py
@@ -0,0 +1,117 @@
+# 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
+
+import os
+import signal
+import which
+import re
+
+# Py3/Py2 compatibility.
+try:
+    from json.decoder import JSONDecodeError
+except ImportError:
+    JSONDecodeError = ValueError
+
+from mozlint import result
+from mozprocess import ProcessHandlerMixin
+
+
+CODESPELL_NOT_FOUND = """
+Unable to locate codespell, please ensure it is installed and in
+your PATH or set the CODESPELL environment variable.
+
+https://github.com/lucasdemarchi/codespell or your system's package manager.
+""".strip()
+
+results = []
+
+CODESPELL_FORMAT_REGEX = re.compile(r'(.*):(.*): (.*) ==> (.*)$')
+
+
+class CodespellProcess(ProcessHandlerMixin):
+    def __init__(self, config, *args, **kwargs):
+        self.config = config
+        kwargs['processOutputLine'] = [self.process_line]
+        ProcessHandlerMixin.__init__(self, *args, **kwargs)
+
+    def process_line(self, line):
+        try:
+            match = CODESPELL_FORMAT_REGEX.match(line)
+            abspath, line, typo, correct = match.groups()
+        except AttributeError:
+            print('Unable to match regex against output: {}'.format(line))
+            return
+
+        # Ignore false positive like aParent (which would be fixed to apparent)
+        # See https://github.com/lucasdemarchi/codespell/issues/314
+        m = re.match(r'^[a-z][A-Z][a-z]*', typo)
+        if m:
+            return
+        res = {'path': os.path.relpath(abspath, self.config['root']),
+               'message': typo + " ==> " + correct,
+               'level': "warning",
+               'lineno': line,
+               }
+        results.append(result.from_config(self.config, **res))
+
+    def run(self, *args, **kwargs):
+        orig = signal.signal(signal.SIGINT, signal.SIG_IGN)
+        ProcessHandlerMixin.run(self, *args, **kwargs)
+        signal.signal(signal.SIGINT, orig)
+
+
+def run_process(config, cmd):
+    proc = CodespellProcess(config, cmd)
+    proc.run()
+    try:
+        proc.wait()
+    except KeyboardInterrupt:
+        proc.kill()
+
+
+def get_codespell_binary():
+    """
+    Returns the path of the first codespell binary available
+    if not found returns None
+    """
+    binary = os.environ.get('CODESPELL')
+    if binary:
+        return binary
+
+    try:
+        return which.which('codespell')
+    except which.WhichError:
+        return None
+
+
+def lint(paths, config, fix=None, **lintargs):
+
+    binary = get_codespell_binary()
+
+    if not binary:
+        print(CODESPELL_NOT_FOUND)
+        if 'MOZ_AUTOMATION' in os.environ:
+            return 1
+        return []
+
+    config['root'] = lintargs['root']
+    cmd_args = [binary,
+                '--disable-colors',
+                # Silence some warnings:
+                # 1: disable warnings about wrong encoding
+                # 2: disable warnings about binary file
+                '--quiet-level=3',
+                ]
+
+# Disabled for now because of
+# https://github.com/lucasdemarchi/codespell/issues/314
+#    if fix:
+#        cmd_args.append('--write-changes')
+
+    base_command = cmd_args + paths
+
+    run_process(config, base_command)
+    return results