DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (c68fe15a81fc)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
# 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 re
import subprocess

from mozlint import result
from mozlint.pathutils import expand_exclusions
from mozlint.util import pip
from mozfile import which

# Error Levels
# (0, 'debug')
# (1, 'info')
# (2, 'warning')
# (3, 'error')
# (4, 'severe')

abspath = os.path.abspath(os.path.dirname(__file__))
rstcheck_requirements_file = os.path.join(abspath, 'requirements.txt')

results = []

RSTCHECK_NOT_FOUND = """
Could not find rstcheck! Install rstcheck and try again.

    $ pip install -U --require-hashes -r {}
""".strip().format(rstcheck_requirements_file)

RSTCHECK_INSTALL_ERROR = """
Unable to install required version of rstcheck
Try to install it manually with:
    $ pip install -U --require-hashes -r {}
""".strip().format(rstcheck_requirements_file)

RSTCHECK_FORMAT_REGEX = re.compile(r'(.*):(.*): \(.*/([0-9]*)\) (.*)$')


def setup(root, **lintargs):
    if not pip.reinstall_program(rstcheck_requirements_file):
        print(RSTCHECK_INSTALL_ERROR)
        return 1


def get_rstcheck_binary():
    """
    Returns the path of the first rstcheck binary available
    if not found returns None
    """
    binary = os.environ.get('RSTCHECK')
    if binary:
        return binary

    return which('rstcheck')


def parse_with_split(errors):
    match = RSTCHECK_FORMAT_REGEX.match(errors)
    filename, lineno, level, message = match.groups()

    return filename, lineno, level, message


def lint(files, config, **lintargs):
    log = lintargs['log']
    config['root'] = lintargs['root']
    paths = expand_exclusions(files, config, config['root'])
    paths = list(paths)
    chunk_size = 50
    binary = get_rstcheck_binary()
    rstcheck_options = "--ignore-language=cpp,json"

    while paths:
        cmdargs = [
            which('python'),
            binary,
            rstcheck_options,
        ] + paths[:chunk_size]
        log.debug("Command: {}".format(' '.join(cmdargs)))

        proc = subprocess.Popen(
            cmdargs, stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            env=os.environ,
            universal_newlines=True,
        )
        all_errors = proc.communicate()[1]
        for errors in all_errors.split("\n"):
            if len(errors) > 1:
                filename, lineno, level, message = parse_with_split(errors)
                res = {
                    'path': filename,
                    'message': message,
                    'lineno': lineno,
                    'level': "error" if int(level) >= 2 else "warning",
                }
                results.append(result.from_config(config, **res))
        paths = paths[chunk_size:]

    return results