15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Copyright (C) 2009 Google Inc. All rights reserved.
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Copyright (C) 2010 ProFUSION embedded systems
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Redistribution and use in source and binary forms, with or without
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# modification, are permitted provided that the following conditions are
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# met:
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#     * Redistributions of source code must retain the above copyright
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# notice, this list of conditions and the following disclaimer.
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#     * Redistributions in binary form must reproduce the above
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# copyright notice, this list of conditions and the following disclaimer
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# in the documentation and/or other materials provided with the
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# distribution.
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#     * Neither the name of Google Inc. nor the names of its
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# contributors may be used to endorse or promote products derived from
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# this software without specific prior written permission.
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)"""Front end of some style-checker modules."""
325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import logging
345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import os.path
355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import re
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import sys
375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from checkers.common import categories as CommonCategories
395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from checkers.common import CarriageReturnChecker
405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from checkers.cpp import CppChecker
415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from checkers.jsonchecker import JSONChecker
425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from checkers.png import PNGChecker
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from checkers.python import PythonChecker
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from checkers.test_expectations import TestExpectationsChecker
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from checkers.text import TextChecker
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from checkers.xcodeproj import XcodeProjectFileChecker
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from checkers.xml import XMLChecker
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from error_handlers import DefaultStyleErrorHandler
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from filter import FilterConfiguration
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from optparser import ArgumentParser
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from optparser import DefaultCommandOptionValues
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from webkitpy.common.system.logutils import configure_logging as _configure_logging
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_log = logging.getLogger(__name__)
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# These are default option values for the command-line option parser.
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_DEFAULT_MIN_CONFIDENCE = 1
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_DEFAULT_OUTPUT_FORMAT = 'emacs'
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# FIXME: For style categories we will never want to have, remove them.
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#        For categories for which we want to have similar functionality,
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#        modify the implementation and enable them.
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Throughout this module, we use "filter rule" rather than "filter"
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# for an individual boolean filter flag like "+foo".  This allows us to
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# reserve "filter" for what one gets by collectively applying all of
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# the filter rules.
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# The base filter rules are the filter rules that begin the list of
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# filter rules used to check style.  For example, these rules precede
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# any user-specified filter rules.  Since by default all categories are
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# checked, this list should normally include only rules that begin
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# with a "-" sign.
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_BASE_FILTER_RULES = [
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    '-build/endif_comment',
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    '-build/include_what_you_use',  # <string> for std::string
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    '-build/storage_class',  # const static
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    '-legal/copyright',
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    '-readability/multiline_comment',
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    '-readability/braces',  # int foo() {};
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    '-readability/fn_size',
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    '-readability/casting',
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    '-readability/function',
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    '-runtime/arrays',  # variable length array
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    '-runtime/casting',
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    '-runtime/sizeof',
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    '-runtime/explicit',  # explicit
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    '-runtime/virtual',  # virtual dtor
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    '-runtime/printf',
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    '-runtime/threadsafe_fn',
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    '-runtime/rtti',
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    '-whitespace/blank_line',
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    '-whitespace/end_of_line',
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # List Python pep8 categories last.
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    #
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # Because much of WebKit's Python code base does not abide by the
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # PEP8 79 character limit, we ignore the 79-character-limit category
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # pep8/E501 for now.
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    #
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # FIXME: Consider bringing WebKit's Python code base into conformance
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    #        with the 79 character limit, or some higher limit that is
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    #        agreeable to the WebKit project.
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    '-pep8/E501',
107926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
108926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    # FIXME: Move the pylint rules from the pylintrc to here. This will
109926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    # also require us to re-work lint-webkitpy to produce the equivalent output.
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ]
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# The path-specific filter rules.
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# This list is order sensitive.  Only the first path substring match
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# is used.  See the FilterConfiguration documentation in filter.py
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# for more information on this list.
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Each string appearing in this nested list should have at least
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# one associated unit test assertion.  These assertions are located,
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# for example, in the test_path_rules_specifier() unit test method of
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# checker_unittest.py.
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_PATH_RULES_SPECIFIER = [
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # Files in these directories are consumers of the WebKit
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # API and therefore do not follow the same header including
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # discipline as WebCore.
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ([# There is no clean way to avoid "yy_*" names used by flex.
129e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)      "Source/core/css/CSSParser-in.cpp"],
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     ["-readability/naming"]),
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # For third-party Python code, keep only the following checks--
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    #
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    #   No tabs: to avoid having to set the SVN allow-tabs property.
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    #   No trailing white space: since this is easy to correct.
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    #   No carriage-return line endings: since this is easy to correct.
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    #
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    (["webkitpy/thirdparty/"],
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     ["-",
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      "+pep8/W191",  # Tabs
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      "+pep8/W291",  # Trailing white space
1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      "+whitespace/carriage_return"]),
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14423e46e0f045bc1935a09565578b448d36cfc5b8cBen Murdoch    ([# Jinja templates: files have .cpp or .h extensions, but contain
14523e46e0f045bc1935a09565578b448d36cfc5b8cBen Murdoch      # template code, which can't be handled, so disable tests.
14623e46e0f045bc1935a09565578b448d36cfc5b8cBen Murdoch      "Source/bindings/templates",
1471e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)      "Source/build/scripts/templates"],
14823e46e0f045bc1935a09565578b448d36cfc5b8cBen Murdoch     ["-"]),
149c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles)
150c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles)    ([# IDL compiler reference output
151c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles)      # Conforming to style significantly increases the complexity of the code
152c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles)      # generator and decreases *its* readability, which is of more concern
153c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles)      # than style of the machine-generated code itself.
154c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles)      "Source/bindings/tests/results"],
155c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles)     ["-"]),
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)]
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_CPP_FILE_EXTENSIONS = [
1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'c',
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'cpp',
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'h',
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ]
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_JSON_FILE_EXTENSION = 'json'
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_PYTHON_FILE_EXTENSION = 'py'
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_TEXT_FILE_EXTENSIONS = [
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'cc',
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'cgi',
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'css',
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'gyp',
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'gypi',
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'html',
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'idl',
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'in',
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'js',
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'mm',
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'php',
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'pl',
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'pm',
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'rb',
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'sh',
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'txt',
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'xhtml',
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'y',
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ]
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_XCODEPROJ_FILE_EXTENSION = 'pbxproj'
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_XML_FILE_EXTENSIONS = [
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'vcproj',
1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'vsprops',
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ]
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_PNG_FILE_EXTENSION = 'png'
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Files to skip that are less obvious.
2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Some files should be skipped when checking style. For example,
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# WebKit maintains some files in Mozilla style on purpose to ease
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# future merges.
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_SKIPPED_FILES_WITH_WARNING = [
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    "Source/WebKit/gtk/tests/",
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # All WebKit*.h files in Source/WebKit2/UIProcess/API/gtk,
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # except those ending in ...Private.h are GTK+ API headers,
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # which differ greatly from WebKit coding style.
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    re.compile(r'Source/WebKit2/UIProcess/API/gtk/WebKit(?!.*Private\.h).*\.h$'),
210926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    re.compile(r'Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKit(?!.*Private\.h).*\.h$'),
211926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    'Source/WebKit2/UIProcess/API/gtk/webkit2.h',
212926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    'Source/WebKit2/WebProcess/InjectedBundle/API/gtk/webkit-web-extension.h']
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Files to skip that are more common or obvious.
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# This list should be in addition to files with FileType.NONE.  Files
2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# with FileType.NONE are automatically skipped without warning.
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_SKIPPED_FILES_WITHOUT_WARNING = [
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    "LayoutTests" + os.path.sep,
220926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    "Source/ThirdParty/leveldb" + os.path.sep,
221926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    # Prevents this being recognized as a text file.
222926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    "Source/WebCore/GNUmakefile.features.am.in",
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ]
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Extensions of files which are allowed to contain carriage returns.
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_CARRIAGE_RETURN_ALLOWED_FILE_EXTENSIONS = [
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'png',
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'vcproj',
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'vsprops',
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ]
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# The maximum number of errors to report per file, per category.
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# If a category is not a key, then it has no maximum.
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_MAX_REPORTS_PER_CATEGORY = {
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    "whitespace/carriage_return": 1
2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def _all_categories():
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """Return the set of all categories used by check-webkit-style."""
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # Take the union across all checkers.
2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    categories = CommonCategories.union(CppChecker.categories)
2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    categories = categories.union(JSONChecker.categories)
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    categories = categories.union(TestExpectationsChecker.categories)
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    categories = categories.union(PNGChecker.categories)
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # FIXME: Consider adding all of the pep8 categories.  Since they
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    #        are not too meaningful for documentation purposes, for
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    #        now we add only the categories needed for the unit tests
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    #        (which validate the consistency of the configuration
2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    #        settings against the known categories, etc).
2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    categories = categories.union(["pep8/W191", "pep8/W291", "pep8/E501"])
2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return categories
2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def _check_webkit_style_defaults():
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """Return the default command-line options for check-webkit-style."""
2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return DefaultCommandOptionValues(min_confidence=_DEFAULT_MIN_CONFIDENCE,
2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                      output_format=_DEFAULT_OUTPUT_FORMAT)
2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# This function assists in optparser not having to import from checker.
2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def check_webkit_style_parser():
2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    all_categories = _all_categories()
2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    default_options = _check_webkit_style_defaults()
2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return ArgumentParser(all_categories=all_categories,
2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                          base_filter_rules=_BASE_FILTER_RULES,
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                          default_options=default_options)
2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def check_webkit_style_configuration(options):
2735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """Return a StyleProcessorConfiguration instance for check-webkit-style.
2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Args:
2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      options: A CommandOptionValues instance.
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    filter_configuration = FilterConfiguration(
2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                               base_rules=_BASE_FILTER_RULES,
2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                               path_specific=_PATH_RULES_SPECIFIER,
2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                               user_rules=options.filter_rules)
2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return StyleProcessorConfiguration(filter_configuration=filter_configuration,
2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)               max_reports_per_category=_MAX_REPORTS_PER_CATEGORY,
2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)               min_confidence=options.min_confidence,
2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)               output_format=options.output_format,
2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)               stderr_write=sys.stderr.write)
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def _create_log_handlers(stream):
2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """Create and return a default list of logging.Handler instances.
2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Format WARNING messages and above to display the logging level, and
2955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    messages strictly below WARNING not to display it.
2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Args:
2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      stream: See the configure_logging() docstring.
2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """
3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # Handles logging.WARNING and above.
3025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    error_handler = logging.StreamHandler(stream)
3035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    error_handler.setLevel(logging.WARNING)
3045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    formatter = logging.Formatter("%(levelname)s: %(message)s")
3055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    error_handler.setFormatter(formatter)
3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # Create a logging.Filter instance that only accepts messages
3085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # below WARNING (i.e. filters out anything WARNING or above).
3095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    non_error_filter = logging.Filter()
3105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # The filter method accepts a logging.LogRecord instance.
3115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    non_error_filter.filter = lambda record: record.levelno < logging.WARNING
3125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    non_error_handler = logging.StreamHandler(stream)
3145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    non_error_handler.addFilter(non_error_filter)
3155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    formatter = logging.Formatter("%(message)s")
3165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    non_error_handler.setFormatter(formatter)
3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return [error_handler, non_error_handler]
3195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def _create_debug_log_handlers(stream):
3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """Create and return a list of logging.Handler instances for debugging.
3235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Args:
3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      stream: See the configure_logging() docstring.
3265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """
3285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    handler = logging.StreamHandler(stream)
3295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    formatter = logging.Formatter("%(name)s: %(levelname)-8s %(message)s")
3305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    handler.setFormatter(formatter)
3315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return [handler]
3335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def configure_logging(stream, logger=None, is_verbose=False):
3365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """Configure logging, and return the list of handlers added.
3375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Returns:
3395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      A list of references to the logging handlers added to the root
3405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      logger.  This allows the caller to later remove the handlers
3415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      using logger.removeHandler.  This is useful primarily during unit
3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      testing where the caller may want to configure logging temporarily
3435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      and then undo the configuring.
3445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Args:
3465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      stream: A file-like object to which to log.  The stream must
3475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)              define an "encoding" data attribute, or else logging
3485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)              raises an error.
3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      logger: A logging.logger instance to configure.  This parameter
3505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)              should be used only in unit tests.  Defaults to the
3515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)              root logger.
3525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      is_verbose: A boolean value of whether logging should be verbose.
3535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """
3555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # If the stream does not define an "encoding" data attribute, the
3565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # logging module can throw an error like the following:
3575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    #
3585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # Traceback (most recent call last):
3595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    #   File "/System/Library/Frameworks/Python.framework/Versions/2.6/...
3605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    #         lib/python2.6/logging/__init__.py", line 761, in emit
3615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    #     self.stream.write(fs % msg.encode(self.stream.encoding))
3625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # LookupError: unknown encoding: unknown
3635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if logger is None:
3645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        logger = logging.getLogger()
3655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if is_verbose:
3675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        logging_level = logging.DEBUG
3685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        handlers = _create_debug_log_handlers(stream)
3695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    else:
3705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        logging_level = logging.INFO
3715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        handlers = _create_log_handlers(stream)
3725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    handlers = _configure_logging(logging_level=logging_level, logger=logger,
3745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                  handlers=handlers)
3755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return handlers
3775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Enum-like idiom
3805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class FileType:
3815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    NONE = 0  # FileType.NONE evaluates to False.
3835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # Alphabetize remaining types
384591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    # CHANGELOG = 1
3855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    CPP = 2
3865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    JSON = 3
3875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    PNG = 4
3885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    PYTHON = 5
3895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    TEXT = 6
390591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    # WATCHLIST = 7
3915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    XML = 8
3925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    XCODEPROJ = 9
3935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class CheckerDispatcher(object):
3965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """Supports determining whether and how to check style, based on path."""
3985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def _file_extension(self, file_path):
4005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Return the file extension without the leading dot."""
4015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return os.path.splitext(file_path)[1].lstrip(".")
4025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def _should_skip_file_path(self, file_path, skip_array_entry):
4045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        match = re.search("\s*png$", file_path)
4055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if match:
4065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return False
4075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if isinstance(skip_array_entry, str):
4085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if file_path.find(skip_array_entry) >= 0:
4095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return True
4105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif skip_array_entry.match(file_path):
4115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return True
4125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return False
4135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def should_skip_with_warning(self, file_path):
4155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Return whether the given file should be skipped with a warning."""
4165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for skipped_file in _SKIPPED_FILES_WITH_WARNING:
4175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if self._should_skip_file_path(file_path, skipped_file):
4185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return True
4195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return False
4205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def should_skip_without_warning(self, file_path):
4225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Return whether the given file should be skipped without a warning."""
4235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if not self._file_type(file_path):  # FileType.NONE.
4245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return True
4255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # Since "LayoutTests" is in _SKIPPED_FILES_WITHOUT_WARNING, make
426591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch        # an exception to prevent files like 'TestExpectations' from being skipped.
4275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        #
4285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # FIXME: Figure out a good way to avoid having to add special logic
4295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        #        for this special case.
4305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        basename = os.path.basename(file_path)
431591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch        if basename == 'TestExpectations':
4325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return False
4335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for skipped_file in _SKIPPED_FILES_WITHOUT_WARNING:
4345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if self._should_skip_file_path(file_path, skipped_file):
4355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return True
4365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return False
4375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def should_check_and_strip_carriage_returns(self, file_path):
4395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._file_extension(file_path) not in _CARRIAGE_RETURN_ALLOWED_FILE_EXTENSIONS
4405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def _file_type(self, file_path):
4425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Return the file type corresponding to the given file."""
4435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        file_extension = self._file_extension(file_path)
4445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (file_extension in _CPP_FILE_EXTENSIONS) or (file_path == '-'):
4465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # FIXME: Do something about the comment below and the issue it
4475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            #        raises since cpp_style already relies on the extension.
4485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            #
4495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # Treat stdin as C++. Since the extension is unknown when
4505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # reading from stdin, cpp_style tests should not rely on
4515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # the extension.
4525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return FileType.CPP
4535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif file_extension == _JSON_FILE_EXTENSION:
4545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return FileType.JSON
4555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif file_extension == _PYTHON_FILE_EXTENSION:
4565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return FileType.PYTHON
4575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif file_extension in _XML_FILE_EXTENSIONS:
4585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return FileType.XML
4595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif file_extension == _XCODEPROJ_FILE_EXTENSION:
4605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return FileType.XCODEPROJ
4615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif file_extension == _PNG_FILE_EXTENSION:
4625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return FileType.PNG
4635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif ((not file_extension and os.path.join("Tools", "Scripts") in file_path) or
4645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)              file_extension in _TEXT_FILE_EXTENSIONS or os.path.basename(file_path) == 'TestExpectations'):
4655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return FileType.TEXT
4665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else:
4675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return FileType.NONE
4685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def _create_checker(self, file_type, file_path, handle_style_error,
4705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                        min_confidence):
4715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Instantiate and return a style checker based on file type."""
4725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if file_type == FileType.NONE:
4735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            checker = None
4745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif file_type == FileType.CPP:
4755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            file_extension = self._file_extension(file_path)
4765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            checker = CppChecker(file_path, file_extension,
4775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                 handle_style_error, min_confidence)
4785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif file_type == FileType.JSON:
4795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            checker = JSONChecker(file_path, handle_style_error)
4805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif file_type == FileType.PYTHON:
4815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            checker = PythonChecker(file_path, handle_style_error)
4825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif file_type == FileType.XML:
4835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            checker = XMLChecker(file_path, handle_style_error)
4845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif file_type == FileType.XCODEPROJ:
4855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            checker = XcodeProjectFileChecker(file_path, handle_style_error)
4865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif file_type == FileType.PNG:
4875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            checker = PNGChecker(file_path, handle_style_error)
4885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif file_type == FileType.TEXT:
4895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            basename = os.path.basename(file_path)
4905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if basename == 'TestExpectations':
4915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                checker = TestExpectationsChecker(file_path, handle_style_error)
4925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            else:
4935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                checker = TextChecker(file_path, handle_style_error)
4945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else:
4955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            raise ValueError('Invalid file type "%(file_type)s": the only valid file types '
4965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                             "are %(NONE)s, %(CPP)s, and %(TEXT)s."
4975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                             % {"file_type": file_type,
4985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                "NONE": FileType.NONE,
4995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                "CPP": FileType.CPP,
5005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                "TEXT": FileType.TEXT})
5015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return checker
5035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def dispatch(self, file_path, handle_style_error, min_confidence):
5055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Instantiate and return a style checker based on file path."""
5065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        file_type = self._file_type(file_path)
5075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        checker = self._create_checker(file_type,
5095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                       file_path,
5105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                       handle_style_error,
5115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                       min_confidence)
5125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return checker
5135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# FIXME: Remove the stderr_write attribute from this class and replace
5165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#        its use with calls to a logging module logger.
5175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class StyleProcessorConfiguration(object):
5185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """Stores configuration values for the StyleProcessor class.
5205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Attributes:
5225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      min_confidence: An integer between 1 and 5 inclusive that is the
5235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      minimum confidence level of style errors to report.
5245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      max_reports_per_category: The maximum number of errors to report
5265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                per category, per file.
5275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      stderr_write: A function that takes a string as a parameter and
5295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    serves as stderr.write.
5305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """
5325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __init__(self,
5345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                 filter_configuration,
5355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                 max_reports_per_category,
5365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                 min_confidence,
5375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                 output_format,
5385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                 stderr_write):
5395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Create a StyleProcessorConfiguration instance.
5405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Args:
5425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          filter_configuration: A FilterConfiguration instance.  The default
5435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                is the "empty" filter configuration, which
5445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                means that all errors should be checked.
5455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          max_reports_per_category: The maximum number of errors to report
5475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                    per category, per file.
5485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          min_confidence: An integer between 1 and 5 inclusive that is the
5505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                          minimum confidence level of style errors to report.
5515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                          The default is 1, which reports all style errors.
5525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          output_format: A string that is the output format.  The supported
5545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                         output formats are "emacs" which emacs can parse
5555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                         and "vs7" which Microsoft Visual Studio 7 can parse.
5565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          stderr_write: A function that takes a string as a parameter and
5585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                        serves as stderr.write.
5595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """
5615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._filter_configuration = filter_configuration
5625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._output_format = output_format
5635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.max_reports_per_category = max_reports_per_category
5655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.min_confidence = min_confidence
5665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.stderr_write = stderr_write
5675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def is_reportable(self, category, confidence_in_error, file_path):
5695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Return whether an error is reportable.
5705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        An error is reportable if both the confidence in the error is
5725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        at least the minimum confidence level and the current filter
5735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        says the category should be checked for the given path.
5745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Args:
5765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          category: A string that is a style category.
5775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          confidence_in_error: An integer between 1 and 5 inclusive that is
5785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                               the application's confidence in the error.
5795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                               A higher number means greater confidence.
5805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          file_path: The path of the file being checked
5815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """
5835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if confidence_in_error < self.min_confidence:
5845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return False
5855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._filter_configuration.should_check(category, file_path)
5875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def write_style_error(self,
5895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                          category,
5905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                          confidence_in_error,
5915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                          file_path,
5925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                          line_number,
5935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                          message):
5945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Write a style error to the configured stderr."""
5955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if self._output_format == 'vs7':
5965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            format_string = "%s(%s):  %s  [%s] [%d]\n"
5975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else:
5985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            format_string = "%s:%s:  %s  [%s] [%d]\n"
5995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.stderr_write(format_string % (file_path,
6015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                           line_number,
6025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                           message,
6035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                           category,
6045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                           confidence_in_error))
6055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class ProcessorBase(object):
6085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """The base class for processors of lists of lines."""
6105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def should_process(self, file_path):
6125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Return whether the file at file_path should be processed.
6135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        The TextFileReader class calls this method prior to reading in
6155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        the lines of a file.  Use this method, for example, to prevent
6165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        the style checker from reading binary files into memory.
6175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """
6195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        raise NotImplementedError('Subclasses should implement.')
6205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def process(self, lines, file_path, **kwargs):
6225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Process lines of text read from a file.
6235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Args:
6255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          lines: A list of lines of text to process.
6265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          file_path: The path from which the lines were read.
6275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          **kwargs: This argument signifies that the process() method of
6285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    subclasses of ProcessorBase may support additional
6295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    keyword arguments.
6305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                        For example, a style checker's check() method
6315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    may support a "reportable_lines" parameter that represents
6325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    the line numbers of the lines for which style errors
6335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    should be reported.
6345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """
6365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        raise NotImplementedError('Subclasses should implement.')
6375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class StyleProcessor(ProcessorBase):
6405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """A ProcessorBase for checking style.
6425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Attributes:
6445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      error_count: An integer that is the total number of reported
6455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                   errors for the lifetime of this instance.
6465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """
6485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __init__(self, configuration, mock_dispatcher=None,
6505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                 mock_increment_error_count=None,
6515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                 mock_carriage_checker_class=None):
6525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Create an instance.
6535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Args:
6555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          configuration: A StyleProcessorConfiguration instance.
6565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          mock_dispatcher: A mock CheckerDispatcher instance.  This
6575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                           parameter is for unit testing.  Defaults to a
6585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                           CheckerDispatcher instance.
6595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          mock_increment_error_count: A mock error-count incrementer.
6605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          mock_carriage_checker_class: A mock class for checking and
6615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                       transforming carriage returns.
6625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                       This parameter is for unit testing.
6635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                       Defaults to CarriageReturnChecker.
6645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """
6665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if mock_dispatcher is None:
6675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            dispatcher = CheckerDispatcher()
6685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else:
6695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            dispatcher = mock_dispatcher
6705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if mock_increment_error_count is None:
6725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # The following blank line is present to avoid flagging by pep8.py.
6735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            def increment_error_count():
6755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                """Increment the total count of reported errors."""
6765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self.error_count += 1
6775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else:
6785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            increment_error_count = mock_increment_error_count
6795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if mock_carriage_checker_class is None:
6815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # This needs to be a class rather than an instance since the
6825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # process() method instantiates one using parameters.
6835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            carriage_checker_class = CarriageReturnChecker
6845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else:
6855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            carriage_checker_class = mock_carriage_checker_class
6865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.error_count = 0
6885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._carriage_checker_class = carriage_checker_class
6905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._configuration = configuration
6915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._dispatcher = dispatcher
6925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._increment_error_count = increment_error_count
6935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def should_process(self, file_path):
6955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Return whether the file should be checked for style."""
6965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if self._dispatcher.should_skip_without_warning(file_path):
6975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return False
6985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if self._dispatcher.should_skip_with_warning(file_path):
6995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            _log.warn('File exempt from style guide. Skipping: "%s"'
7005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                      % file_path)
7015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return False
7025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return True
7035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def process(self, lines, file_path, line_numbers=None):
7055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Check the given lines for style.
7065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Arguments:
7085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          lines: A list of all lines in the file to check.
7095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          file_path: The path of the file to process.  If possible, the path
7105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                     should be relative to the source root.  Otherwise,
7115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                     path-specific logic may not behave as expected.
7125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          line_numbers: A list of line numbers of the lines for which
7135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                        style errors should be reported, or None if errors
7145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                        for all lines should be reported.  When not None, this
7155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                        list normally contains the line numbers corresponding
7165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                        to the modified lines of a patch.
7175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """
7195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        _log.debug("Checking style: " + file_path)
7205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        style_error_handler = DefaultStyleErrorHandler(
7225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            configuration=self._configuration,
7235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            file_path=file_path,
7245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            increment_error_count=self._increment_error_count,
7255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            line_numbers=line_numbers)
7265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        carriage_checker = self._carriage_checker_class(style_error_handler)
7285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # Check for and remove trailing carriage returns ("\r").
7305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if self._dispatcher.should_check_and_strip_carriage_returns(file_path):
7315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            lines = carriage_checker.check(lines)
7325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        min_confidence = self._configuration.min_confidence
7345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        checker = self._dispatcher.dispatch(file_path,
7355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                            style_error_handler,
7365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                            min_confidence)
7375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if checker is None:
7395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            raise AssertionError("File should not be checked: '%s'" % file_path)
7405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        _log.debug("Using class: " + checker.__class__.__name__)
7425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        checker.check(lines)
744