author Jonathan Hao <>
Thu, 12 Jan 2017 14:58:04 +0800
changeset 462919 24c57a372151b229c5b5fcd976a86e999cc768e4
parent 449910 801e9e6efb1742fd3e086685cec6698c8d05a995
child 484822 868a4dc22d7a40d78a620c2939be59392b7822be
permissions -rw-r--r--
Bug 1115712 - make DataStorage for HPKP and HSTS enumerable via xpcom. r=keeler,Cykesiopka MozReview-Commit-ID: GEOtuTAiPIX

# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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

import json
import os
import signal
import subprocess

import which
from mozprocess import ProcessHandler

from mozlint import result

here = os.path.abspath(os.path.dirname(__file__))
FLAKE8_REQUIREMENTS_PATH = os.path.join(here, 'flake8', 'flake8_requirements.txt')

Could not find flake8! Install flake8 and try again.

    $ pip install -U --require-hashes -r {}

Unable to install correct version of flake8
Try to install it manually with:
    $ pip install -U --require-hashes -r {}

    # continuation line under-indented for hanging indent
    'E121': (-1, 2),
    # continuation line missing indentation or outdented
    'E122': (-1, 2),
    # continuation line over-indented for hanging indent
    'E126': (-1, 2),
    # continuation line over-indented for visual indent
    'E127': (-1, 2),
    # continuation line under-indented for visual indent
    'E128': (-1, 2),
    # continuation line unaligned for hanging indend
    'E131': (-1, 2),
    # expected 1 blank line, found 0
    'E301': (-1, 2),
    # expected 2 blank lines, found 1
    'E302': (-2, 3),
"""Maps a flake8 error to a lineoffset tuple.

The offset is of the form (lineno_offset, num_lines) and is passed
to the lineoffset property of `ResultContainer`.

EXTENSIONS = ['.py', '.lint']
results = []

def process_line(line):
    # Escape slashes otherwise JSON conversion will not work
    line = line.replace('\\', '\\\\')
        res = json.loads(line)
    except ValueError:
        print('Non JSON output from linter, will not be processed: {}'.format(line))

    if 'code' in res:
        if res['code'].startswith('W'):
            res['level'] = 'warning'

        if res['code'] in LINE_OFFSETS:
            res['lineoffset'] = LINE_OFFSETS[res['code']]

    results.append(result.from_linter(LINTER, **res))

def run_process(cmdargs):
    # flake8 seems to handle SIGINT poorly. Handle it here instead
    # so we can kill the process without a cryptic traceback.
    orig = signal.signal(signal.SIGINT, signal.SIG_IGN)
    proc = ProcessHandler(cmdargs, env=os.environ,
    signal.signal(signal.SIGINT, orig)

    except KeyboardInterrupt:

def get_flake8_binary():
    Returns the path of the first flake8 binary available
    if not found returns None
    binary = os.environ.get('FLAKE8')
    if binary:
        return binary

        return which.which('flake8')
    except which.WhichError:
        return None

def _run_pip(*args):
    Helper function that runs pip with subprocess
        subprocess.check_output(['pip'] + list(args),
        return True
    except subprocess.CalledProcessError as e:
        return False

def reinstall_flake8():
    Try to install flake8 at the target version, returns True on success
    otherwise prints the otuput of the pip command and returns False
    if _run_pip('install', '-U',
                '--require-hashes', '-r',
        return True

    return False

def lint(files, **lintargs):

    if not reinstall_flake8():
        return 1

    binary = get_flake8_binary()

    cmdargs = [
        '--format', '{"path":"%(path)s","lineno":%(row)s,'

    # Run any paths with a .flake8 file in the directory separately so
    # it gets picked up. This means only .flake8 files that live in
    # directories that are explicitly included will be considered.
    # See bug 1277851
    no_config = []
    for f in files:
        if not os.path.isfile(os.path.join(f, '.flake8')):

    # XXX For some reason passing in --exclude results in flake8 not using
    # the local .flake8 file. So for now only pass in --exclude if there
    # is no local config.
    exclude = lintargs.get('exclude')
    if exclude:
        cmdargs += ['--exclude', ','.join(lintargs['exclude'])]

    if no_config:

    return results

    'name': "flake8",
    'description': "Python linter",
    'include': [
    'exclude': ["testing/mozbase/mozdevice/mozdevice/",
    'extensions': EXTENSIONS,
    'type': 'external',
    'payload': lint,