You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by bb...@apache.org on 2019/09/18 10:52:43 UTC

[mesos] 06/09: Removed old mesos-style and references.

This is an automated email from the ASF dual-hosted git repository.

bbannier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git

commit 37d76fff124d28a0281b9231058bb1b92fc65abe
Author: Benjamin Bannier <bb...@apache.org>
AuthorDate: Wed Sep 18 11:37:15 2019 +0200

    Removed old mesos-style and references.
    
    This patch removes references to `support/mesos-style.py` which was
    replaced with a pre-commit setup in a previous commit. We also remove
    the tool itself.
    
    Review: https://reviews.apache.org/r/71206/
---
 docs/c++-style-guide.md    |   2 +-
 support/build-virtualenv   |  72 ------
 support/hooks/commit-msg   |  46 ----
 support/hooks/post-rewrite |  40 ----
 support/hooks/pre-commit   |  41 ----
 support/mesos-split.py     |   2 -
 support/mesos-style.py     | 557 ++-------------------------------------------
 7 files changed, 17 insertions(+), 743 deletions(-)

diff --git a/docs/c++-style-guide.md b/docs/c++-style-guide.md
index 8a48afe..8df99c8 100644
--- a/docs/c++-style-guide.md
+++ b/docs/c++-style-guide.md
@@ -7,7 +7,7 @@ layout: documentation
 
 The Mesos codebase follows the [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) with some notable differences, as described below.
 
-Note that the [clang-format](clang-format.md) tool can be helpful to ensure that some of the mechanical style rules are obeyed. Commits should be checked with the script `support/mesos-style.py` for high-level conformance, or with `support/mesos-tidy.sh` for conformance to low-level expectations.
+Note that the [clang-format](clang-format.md) tool can be helpful to ensure that some of the mechanical style rules are obeyed. Commits should be checked with the command `pre-commit run cpplint` for high-level conformance, or with `support/mesos-tidy.sh` for conformance to low-level expectations.
 
 ## Scoping
 
diff --git a/support/build-virtualenv b/support/build-virtualenv
deleted file mode 100755
index 7dc03b0..0000000
--- a/support/build-virtualenv
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/usr/bin/env bash
-
-# This script sets up a Python virtualenv for the Web UI. This creates
-# a new virtualenv and installs nodeenv inside the virtualenv.
-
-set -e
-trap "exit 1" INT
-
-CURRDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-
-: ${VIRTUALENV_NAME:="linters"}
-: ${VIRTUALENV_DIRECTORY:="${CURRDIR}/.virtualenv"}
-
-: ${PYTHON:="$(which python)"}
-: ${VIRTUALENV:="$(which virtualenv)"}
-
-OLD_PYTHONPATH="${PYTHONPATH}"
-PYTHONPATH=""
-
-# If we already have a virtual environment activated,
-# bail out and advise the user to deactivate.
-OLD_VIRTUAL_ENV="${VIRTUAL_ENV}"
-if [ "${OLD_VIRTUAL_ENV}" != "" ]; then
-  echo "Please deactivate your current virtual environment in order to continue."
-  echo "source deactivate"
-  exit 1
-fi
-
-# Verify that python is installed.
-if [ "${PYTHON}" = "" ]; then
-  echo "You must have python installed in order to continue."
-  exit 1
-fi
-
-# Old versions of virtualenv do not remove the bin directory in the
-# virtual environment even when using `--clear`. We thus remove the
-# entire directory in case the virtual environment already exists.
-# See https://github.com/pypa/virtualenv/issues/2 for more info.
-rm -rf ${VIRTUALENV_DIRECTORY}
-
-PYTHON_MAJOR=$(${PYTHON} -c 'import sys; print(sys.version_info[0])')
-PYTHON_MINOR=$(${PYTHON} -c 'import sys; print(sys.version_info[1])')
-
-if [ "${PYTHON_MAJOR}" = "3" ]; then
-  if [ "${PYTHON_MINOR}" -lt "6" ]; then
-    echo "You must be running python 3.6 or newer in order to continue."
-    echo "Consider running as 'PYTHON=python3 ${0}' or similar."
-    exit 1
-  else
-    # Set up a virtual environment for the linters.
-    ${PYTHON} -m venv --prompt="${VIRTUALENV_NAME}" ${VIRTUALENV_DIRECTORY}
-  fi
-else
-  echo "You must be running python 3.6 or newer in order to continue."
-  echo "Consider running as 'PYTHON=python3 ${0}' or similar."
-  exit 1
-fi
-
-source ${VIRTUALENV_DIRECTORY}/bin/activate
-pip install --upgrade pip
-pip install -r ${CURRDIR}/pip-requirements.txt
-
-# Add Node.js virtual environment to the existing virtual environment.
-nodeenv -p
-
-# Restart the virtual environment to then have npm available.
-deactivate
-source ${VIRTUALENV_DIRECTORY}/bin/activate
-
-# Install the JavaScript linter in the virtual environment.
-npm install -g eslint@5.1.0
-deactivate
diff --git a/support/hooks/commit-msg b/support/hooks/commit-msg
deleted file mode 100755
index a0c218d..0000000
--- a/support/hooks/commit-msg
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env bash
-#
-# A hook script to verify commit message format. Called by "git commit"
-# with one argument, the name of the file that has the commit message.
-# The hook exits with non-zero status after issuing an appropriate
-# message if it wants to stop the commit. The hook is allowed to edit the
-# commit message file.
-#
-# To enable this hook, run `bootstrap` or do this from the root of the repo:
-#
-# $ ln -s ../../support/hooks/commit-msg .git/hooks/commit-msg
-
-COMMIT_MESSAGE=$(cat "$1")
-FIRST_LINE=$(head -n 1 "$1")
-LAST_CHAR=$(echo -n "$FIRST_LINE" | tail -c 1)
-FIRST_CHAR=$(echo -n "$FIRST_LINE" | head -c 1)
-
-if [[ "$FIRST_LINE" =~ ^(fixup|squash)\! ]]; then
-    # If the commit starts with fixup! or squash! we ignore everything.
-    # The message will be checked when the final commit is made.
-    exit 0
-fi
-
-while read -r LINE
-do
-    # In verbose mode, the diff of the commit is included in the commit message.
-    # Since git looks for the following line and skips everything after it,
-    # we also skip everything once this line is observed.
-    if [ "$LINE" = "# ------------------------ >8 ------------------------" ]; then break; fi
-    if [ "$(echo -n "$LINE" | head -c 1)" = "#" ]; then continue; fi
-    LENGTH=$(echo -n "$LINE" | wc -c)
-    if [ "$LENGTH" -gt "72" ]; then
-        echo >&2 "Error: No line in the commit message summary may exceed 72 characters."
-        exit 1
-    fi
-done <<< "$COMMIT_MESSAGE"
-
-if [[ ! "$FIRST_CHAR" =~ [A-Z] ]]; then
-    echo >&2 "Error: Commit message summary (the first line) must start with a capital letter."
-    exit 1
-fi
-
-if [ "$LAST_CHAR" != "." ]; then
-    echo >&2 "Error: Commit message summary (the first line) must end in a period."
-    exit 1
-fi
diff --git a/support/hooks/post-rewrite b/support/hooks/post-rewrite
deleted file mode 100755
index 1ab14ab..0000000
--- a/support/hooks/post-rewrite
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/sh
-#
-# A hook script to verify what is about to be committed.
-# Called by "git commit --amend" or "git rebase". The hook exits with
-# non-zero status and warning messages if the files being rewritten do
-# not conform to the Mesos style.
-#
-# To enable this hook, do this from the root of the repo:
-#
-# $ ln -s ../../support/hooks/post_rewrite .git/hooks/post_rewrite
-
-# Redirect output to stderr.
-exec 1>&2
-
-# If there are whitespace errors, print the offending file names.
-## In git, '@~' represent previous commit. We check the whitespace between
-## current head and previous commit after a commit is rewritten.
-git diff-index --check @~ -- || exit 1
-
-# Check Mesos style.
-## In git, '@' represent current head, '@~' represent previous commit. We check
-## the style of changes between current head and previous commit after a commit
-## is rewritten.
-ADDED_OR_MODIFIED=$(git diff --name-only --diff-filter=AM @~..@)
-if [ "$ADDED_OR_MODIFIED" ]; then
-    # NOTE: We choose to implement this as a conditional rather than a call to
-    # `xargs` on purpose. Some implementations of `xargs` will call your script
-    # even if the arguments you pass in are empty. In our case, this would
-    # cause us to erroneously lint every file in the repository. Additionally,
-    # many implementations do not support the `-r` flag, (which instructs
-    # `xargs` to not run the script if the arguments are empty), so we also
-    # cannot use that.
-    ./support/mesos-style.py $ADDED_OR_MODIFIED || exit 1
-fi
-
-# Check that the commits are properly split between mesos, libprocess and stout.
-## In git, '@' represent current head, '@~' represent previous commit. We check
-## the style of changes between current head and previous commit after a commit
-## is rewritten.
-git diff --name-only --diff-filter=AMD @~..@ | xargs ./support/mesos-split.py || exit 1
diff --git a/support/hooks/pre-commit b/support/hooks/pre-commit
deleted file mode 100755
index 519567b..0000000
--- a/support/hooks/pre-commit
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/bin/sh
-#
-# A hook script to verify what is about to be committed.
-# Called by "git commit" with no arguments.  The hook exits with
-# non-zero status if the files being committed do not conform to
-# the Mesos style.
-#
-# To enable this hook, do this from the root of the repo:
-#
-# $ ln -s ../../support/hooks/pre-commit .git/hooks/pre-commit
-
-if git rev-parse --verify HEAD >/dev/null 2>&1
-then
-	against=HEAD
-else
-	# Initial commit: diff against an empty tree object
-	against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
-fi
-
-# Redirect output to stderr.
-exec 1>&2
-
-# If there are whitespace errors, print the offending file names and fail.
-git diff-index --check --cached $against -- || exit 1
-
-# Check Mesos style.
-ADDED_OR_MODIFIED=$(git diff --cached --name-only --diff-filter=AM)
-if [ -n "$ADDED_OR_MODIFIED" ]; then
-    # NOTE: We choose to implement this as a conditional rather than a call to
-    # `xargs` on purpose. Some implementations of `xargs` will call your script
-    # even if the arguments you pass in are empty. In our case, this would
-    # cause us to erroneously lint every file in the repository. Additionally,
-    # many implementations do not support the `-r` flag, (which instructs
-    # `xargs` to not run the script if the arguments are empty), so we also
-    # cannot use that.
-    ./support/mesos-style.py $ADDED_OR_MODIFIED || exit 1
-fi
-
-# Check that the commits are properly split between mesos, libprocess and stout.
-# TODO(ArmandGrillet): Remove the if to really switch to Python 3.
-git diff --cached --name-only --diff-filter=AMD | xargs ./support/mesos-split.py || exit 1
diff --git a/support/mesos-split.py b/support/mesos-split.py
index 0a77c25..aecad3f 100755
--- a/support/mesos-split.py
+++ b/support/mesos-split.py
@@ -58,8 +58,6 @@ def find_project(filename):
 def main():
     """
     Expects a list of filenames on the command line.
-
-    See `support/hooks/pre-commit` for the canonical usage of this method.
     """
     touched_projects = defaultdict(list)
     for filename in sys.argv[1:]:
diff --git a/support/mesos-style.py b/support/mesos-style.py
index b3e20fd..4d9d3b4 100755
--- a/support/mesos-style.py
+++ b/support/mesos-style.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-#
+
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -15,551 +15,26 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
+"""This is a dummy script to ease the transition from mesos-style to pre-commit
+hooks. This script can be removed after we have given contributors enough time
+to adjust their checkouts."""
 
-"""Runs checks for mesos style."""
-
-import os
-import platform
-import re
-import string
-import subprocess
 import sys
 
-from pathlib import PurePath
-
-
-class LinterBase():
-    """
-    This is an abstract class that provides the base functionality for
-    linting files in the mesos project. Its 'main()' function
-    walks through the set of files passed to it and runs some
-    standard linting over them. This includes checking for license headers
-    and checking for non-supported characters. From there it calls a
-    'run_lint()' function that can be overridden to provide
-    customizable style checks for a specific class of files (e.g. C++,
-    Python, etc.).
-
-    Any class that extends from 'LinterBase' should override the
-    following class variables / functions:
-
-    linter_type
-    source_dirs
-    exclude_files
-    source_files
-    comment_prefix
-
-    run_lint()
-
-    Please see the comments below for details on how to override each
-    variable.
-    """
-    # The name of the linter to help with printing which linter files
-    # are currently being processed by.
-    linter_type = ''
-
-    # Root source paths (will be traversed recursively).
-    source_dirs = []
-
-    # Add file paths and patterns which should not be checked
-    # This should include 3rdparty libraries, includes and machine generated
-    # source.
-    exclude_files = ''
-
-    # A regex of possible matches for your source files.
-    source_files = ''
-
-    # A prefix at the beginning of the line to demark comments (e.g. '//')
-    comment_prefix = ''
-
-    def check_encoding(self, source_paths):
-        """
-        Checks for encoding errors in the given files. Source
-        code files must contain only printable ascii characters.
-        This excludes the extended ascii characters 128-255.
-        http://www.asciitable.com/
-        """
-        error_count = 0
-        for path in source_paths:
-            with open(path) as source_file:
-                for line_number, line in enumerate(source_file):
-                    # If we find an error, add 1 to both the character and
-                    # the line offset to give them 1-based indexing
-                    # instead of 0 (as is common in most editors).
-                    char_errors = [offset for offset, char in enumerate(line)
-                                   if char not in string.printable]
-                    if char_errors:
-                        sys.stderr.write(
-                            "{path}:{line_number}:  Non-printable characters"
-                            " found at [{offsets}]: \"{line}\"\n".format(
-                                path=path,
-                                line_number=line_number + 1,
-                                offsets=', '.join([str(offset + 1) for offset
-                                                   in char_errors]),
-                                line=line.rstrip()))
-                        error_count += 1
-
-        return error_count
-
-    def check_license_header(self, source_paths):
-        """Checks the license headers of the given files."""
-        error_count = 0
-        for path in source_paths:
-            with open(path) as source_file:
-                # We read the three first lines of the file as the
-                # first line could be a shebang and the second line empty.
-                head = "".join([next(source_file) for _ in range(3)])
-
-                # TODO(bbannier) We allow `Copyright` for
-                # currently deviating files. This should be
-                # removed one we have a uniform license format.
-                regex = r'^{comment_prefix} [Licensed|Copyright]'.format(
-                    comment_prefix=self.comment_prefix)
-                # pylint: disable=no-member
-                regex = re.compile(regex, re.MULTILINE)
-
-                if not regex.search(head):
-                    sys.stderr.write(
-                        "{path}:1: A license header should appear's on one of"
-                        " the first line of the file starting with"
-                        " '{comment_prefix} Licensed'.: {head}".format(
-                            path=path,
-                            head=head,
-                            comment_prefix=self.comment_prefix))
-                    error_count += 1
-
-        return error_count
-
-    def find_candidates(self, root_dir):
-        """
-        Search through the all files rooted at 'root_dir' and compare
-        them against 'self.exclude_files' and 'self.source_files' to
-        come up with a set of candidate files to lint.
-        """
-        exclude_file_regex = re.compile(self.exclude_files)
-        source_criteria_regex = re.compile(self.source_files)
-        for root, _, files in os.walk(root_dir):
-            for name in files:
-                path = os.path.join(root, name)
-                if exclude_file_regex.search(path) is not None:
-                    continue
-
-                if source_criteria_regex.search(name) is not None:
-                    yield path
-
-    def run_command_in_virtualenv(self, command):
-        """
-        Activate the virtual environment, run the
-        given command and return its output.
-        """
-        virtualenv = os.path.join('support', '.virtualenv')
-
-        if platform.system() == 'Windows':
-            command = r'{virtualenv_path}\Scripts\activate.bat & {cmd}'.format(
-                virtualenv_path=virtualenv, cmd=command)
-        else:
-            command = '. {virtualenv_path}/bin/activate; {cmd}'.format(
-                virtualenv_path=virtualenv, cmd=command)
-
-        return subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
-
-    # pylint: disable=unused-argument
-    def run_lint(self, source_paths):
-        """
-        A custom function to provide linting for 'linter_type'.
-        It takes a list of source files to lint and returns the number
-        of errors found during the linting process.
-
-        It should print any errors as it encounters them to provide
-        feedback to the caller.
-        """
-        return 0
-
-    def main(self, modified_files):
-        """
-        This function takes a list of files and lints them for the
-        class of files defined by 'linter_type'.
-        """
-
-        # Verify that source roots are accessible from current
-        # working directory. A common error could be to call
-        # the style checker from other (possibly nested) paths.
-        for source_dir in self.source_dirs:
-            if not os.path.exists(source_dir):
-                print("Could not find '{dir}'".format(dir=source_dir))
-                print('Please run from the root of the mesos source directory')
-                exit(1)
-
-        # Add all source file candidates to candidates list.
-        candidates = []
-        for source_dir in self.source_dirs:
-            for candidate in self.find_candidates(source_dir):
-                candidates.append(candidate)
-
-        # Normalize paths of any files given.
-        modified_files = [os.fspath(PurePath(f)) for f in modified_files]
-
-        # If file paths are specified, check all file paths that are
-        # candidates; else check all candidates.
-        file_paths = modified_files if modified_files else candidates
-
-        # Compute the set intersect of the input file paths and candidates.
-        # This represents the reduced set of candidates to run lint on.
-        candidates_set = set(candidates)
-        clean_file_paths_set = set(path.rstrip() for path in file_paths)
-        filtered_candidates_set = clean_file_paths_set.intersection(
-            candidates_set)
-
-        if filtered_candidates_set:
-            plural = '' if len(filtered_candidates_set) == 1 else 's'
-            print('Checking {num_files} {linter} file{plural}'.format(
-                num_files=len(filtered_candidates_set),
-                linter=self.linter_type,
-                plural=plural))
-
-            license_errors = self.check_license_header(filtered_candidates_set)
-            encoding_errors = self.check_encoding(list(filtered_candidates_set))
-            lint_errors = self.run_lint(list(filtered_candidates_set))
-            total_errors = license_errors + encoding_errors + lint_errors
-
-            if total_errors > 0:
-                sys.stderr.write('Total errors found: {num_errors}\n'.format(
-                    num_errors=total_errors))
-
-            return total_errors
-
-        return 0
-
-
-class CppLinter(LinterBase):
-    """The linter for C++ files, uses cpplint."""
-    linter_type = 'C++'
-
-    source_dirs = ['src',
-                   'include',
-                   os.path.join('3rdparty', 'libprocess'),
-                   os.path.join('3rdparty', 'stout')]
-
-    exclude_files = '(' \
-                    r'elfio\-3\.2|' \
-                    r'protobuf\-2\.4\.1|' \
-                    r'googletest\-release\-1\.8\.0|' \
-                    r'glog\-0\.3\.3|' \
-                    r'boost\-1\.53\.0|' \
-                    r'libev\-4\.15|' \
-                    r'\.pb\.cc|\.pb\.h|\.md|\.virtualenv' \
-                    ')'
-
-    source_files = r'\.(cpp|hpp|cc|h)$'
-
-    comment_prefix = r'\/\/'
-
-    def run_lint(self, source_paths):
-        """
-        Runs cpplint over given files.
-
-        http://google-styleguide.googlecode.com/svn/trunk/cpplint/cpplint.py
-        """
-        # We do not use a version of cpplint available through pip as
-        # we use a custom version (see cpplint.path) to lint C++ files.
-        process = subprocess.Popen(
-            [sys.executable, 'support/cpplint.py', '--extensions=hpp,cpp'] +
-            source_paths,
-            stderr=subprocess.PIPE,
-            close_fds=True)
-
-        # Lines are stored and filtered, only showing found errors instead
-        # of e.g., 'Done processing XXX.' which tends to be dominant output.
-        for line in process.stderr:
-            line = line.decode(sys.stdout.encoding)
-            if re.match('^(Done processing |Total errors found: )', line):
-                continue
-            sys.stderr.write(line)
-
-        process.wait()
-        return process.returncode
-
-
-class JsLinter(LinterBase):
-    """The linter for JavaScript files, uses eslint."""
-    linter_type = 'JavaScript'
-
-    source_dirs = [os.path.join('src', 'webui')]
-
-    exclude_files = '(' \
-                    r'angular\-1\.2\.32|' \
-                    r'angular\-route\-1\.2\.32|' \
-                    r'bootstrap\-table\-1\.11\.1|' \
-                    r'clipboard\-1\.5\.16|' \
-                    r'jquery\-3\.2\.1|' \
-                    r'relative\-date|' \
-                    r'ui\-bootstrap\-tpls\-0\.9\.0|' \
-                    r'angular\-route\-1\.2\.32|' \
-                    r'underscore\-1\.4\.3' \
-                    ')'
-
-    source_files = r'\.(js)$'
-
-    comment_prefix = '//'
-
-    def run_lint(self, source_paths):
-        """
-        Runs eslint over given files.
-
-        https://eslint.org/docs/user-guide/configuring
-        """
-
-        num_errors = 0
-
-        source_files = ' '.join(source_paths)
-        config_path = os.path.join('support', '.eslintrc.js')
-
-        process = self.run_command_in_virtualenv(
-            'eslint {files} -c {config} -f compact'.format(
-                files=source_files,
-                config=config_path
-            )
-        )
-
-        for line in process.stdout:
-            line = line.decode(sys.stdout.encoding)
-            if "Error -" in line or "Warning -" in line:
-                sys.stderr.write(line)
-                if "Error -" in line:
-                    num_errors += 1
-
-        return num_errors
-
-
-class PyLinter(LinterBase):
-    """The linter for Python files, uses pylint."""
-    linter_type = 'Python'
-
-    cli_dir = os.path.join('src', 'python', 'cli_new')
-    lib_dir = os.path.join('src', 'python', 'lib')
-    support_dir = os.path.join('support')
-    source_dirs_to_lint_with_venv = [support_dir]
-    source_dirs_to_lint_with_tox = [cli_dir, lib_dir]
-    source_dirs = source_dirs_to_lint_with_tox + source_dirs_to_lint_with_venv
-
-    exclude_files = '(' \
-                    r'protobuf\-2\.4\.1|' \
-                    r'googletest\-release\-1\.8\.0|' \
-                    r'glog\-0\.3\.3|' \
-                    r'boost\-1\.53\.0|' \
-                    r'libev\-4\.15|' \
-                    r'\.virtualenv|' \
-                    r'\.tox' \
-                    ')'
-
-    source_files = r'\.(py)$'
-
-    comment_prefix = '#'
-
-    pylint_config = os.path.abspath(os.path.join('support', 'pylint.config'))
-
-    def run_tox(self, configfile, args, tox_env=None, recreate=False):
-        """
-        Runs tox with given configfile and args. Optionally set tox env
-        and/or recreate the tox-managed virtualenv.
-        """
-        support_dir = os.path.dirname(__file__)
-        bin_dir = 'Script' if platform.system() == 'Windows' else 'bin'
-
-        cmd = [os.path.join(support_dir, '.virtualenv', bin_dir, 'tox')]
-        cmd += ['-qq']
-        cmd += ['-c', configfile]
-        if tox_env is not None:
-            cmd += ['-e', tox_env]
-        if recreate:
-            cmd += ['--recreate']
-        cmd += ['--']
-        cmd += args
-
-        # We do not use `run_command_in_virtualenv()` here, as we
-        # directly call `tox` from inside the virtual environment bin
-        # directory without activating the virtualenv.
-        return subprocess.Popen(cmd, stdout=subprocess.PIPE)
-
-    def filter_source_files(self, source_dir, source_files):
-        """
-        Filters out files starting with source_dir.
-        """
-        return [f for f in source_files if f.startswith(source_dir)]
-
-    def lint_source_files_under_source_dir(self, source_dir, source_files):
-        """
-        Runs pylint directly or indirectly throgh tox on source_files which
-        are under source_dir. If tox is to be used, it must be configured
-        in source_dir, i.e. a tox.ini must be present.
-        """
-        filtered_source_files = self.filter_source_files(
-            source_dir, source_files)
-
-        if not filtered_source_files:
-            return 0
-
-        if source_dir in self.source_dirs_to_lint_with_tox:
-            process = self.run_tox(
-                configfile=os.path.join(source_dir, 'tox.ini'),
-                args=['--rcfile='+self.pylint_config] + filtered_source_files,
-                tox_env='py3-lint')
-        else:
-            process = self.run_command_in_virtualenv(
-                'pylint --score=n --rcfile={rcfile} {files}'.format(
-                    rcfile=self.pylint_config,
-                    files=' '.join(filtered_source_files)))
-
-        num_errors = 0
-        for line in process.stdout:
-            line = line.decode(sys.stdout.encoding)
-            if re.search(r'[RCWEF][0-9]{4}:', line):
-                num_errors += 1
-            sys.stderr.write(line)
-
-        return num_errors
-
-    def run_lint(self, source_paths):
-        """
-        Runs pylint over given files.
-
-        https://google.github.io/styleguide/pyguide.html
-        """
-        num_errors = 0
-
-        for source_dir in self.source_dirs:
-            num_errors += self.lint_source_files_under_source_dir(
-                source_dir, source_paths)
-
-        return num_errors
-
-
-def should_build_virtualenv(modified_files):
-    """
-    Check if we should build the virtual environment required.
-    This is the case if the requirements of the environment
-    have changed or if the support script is run with no
-    arguments (meaning that the entire codebase should be linted).
-    """
-    # NOTE: If the file list is empty, we are linting the entire test
-    # codebase. We should always rebuild the virtualenv in this case.
-    if not modified_files:
-        return True
-
-    support_dir = os.path.dirname(__file__)
-    bin_dir = 'Script' if platform.system() == 'Windows' else 'bin'
-
-    interpreter = os.path.basename(sys.executable)
-    interpreter = os.path.join(support_dir, '.virtualenv', bin_dir, interpreter)
-    if not os.path.isfile(interpreter):
-        return True
-
-    basenames = [os.path.basename(path) for path in modified_files]
-
-    if 'pip-requirements.txt' in basenames:
-        print('The "pip-requirements.txt" file has changed.')
-        return True
-
-    if 'build-virtualenv' in basenames:
-        print('The "build-virtualenv" file has changed.')
-        return True
-
-    # The JS and Python linters require a virtual environment.
-    # If all the files modified are not JS or Python files,
-    # we do not need to build the virtual environment.
-    # TODO(ArmandGrillet): There should be no duplicated logic to know
-    # which linters to instantiate depending on the files to analyze.
-    if not os.path.isdir(os.path.join('support', '.virtualenv')):
-        js_and_python_files = [JsLinter().source_files, PyLinter().source_files]
-        js_and_python_files_regex = re.compile('|'.join(js_and_python_files))
-
-        for basename in basenames:
-            if js_and_python_files_regex.search(basename) is not None:
-                print('Virtualenv not detected and required... building')
-                return True
-
-    return False
-
-
-def build_virtualenv():
-    """
-    Rebuild the virtualenv by running a bootstrap script.
-    This will exit the program if there is a failure.
-    """
-    print('Rebuilding virtualenv...')
-
-    python3_env = os.environ.copy()
-    python3_env["PYTHON"] = sys.executable
-
-    build_virtualenv_file = [os.path.join('support', 'build-virtualenv')]
-
-    if platform.system() == 'Windows':
-        # TODO(andschwa): Port more of the `build-virtualenv` Bash script.
-        python_dir = os.path.dirname(sys.executable)
-        virtualenv = os.path.join(python_dir, 'Scripts', 'virtualenv.exe')
-        build_virtualenv_file = [virtualenv,
-                                 '--no-site-packages',
-                                 'support/.virtualenv']
-
-    process = subprocess.Popen(
-        build_virtualenv_file,
-        env=python3_env,
-        stdout=subprocess.PIPE)
-
-    output = ''
-    for line in process.stdout:
-        output += line.decode(sys.stdout.encoding)
-
-    process.wait()
-
-    if process.returncode != 0:
-        sys.stderr.write(output)
-        sys.exit(1)
-
-    # TODO(andschwa): Move this into a script like above.
-    if platform.system() == 'Windows':
-        def run_command_in_virtualenv(command):
-            """
-            Stolen from `PyLinter`, runs command in virtualenv.
-            """
-            virtualenv = os.path.join('support',
-                                      '.virtualenv',
-                                      'Scripts',
-                                      'activate.bat')
-            command = '{virtualenv_path} & {cmd}'.format(
-                virtualenv_path=virtualenv, cmd=command)
-
-            return subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
-
-        pip_install_pip = 'python.exe -m pip install --upgrade pip'
-        process = run_command_in_virtualenv(pip_install_pip)
-        for line in process.stdout:
-            output += line.decode(sys.stdout.encoding)
-        process.wait()
+error = """\
+'mesos-style.py' was removed in favor of hooks managed by pre-commit.
 
-        if process.returncode != 0:
-            sys.stderr.write(output)
-            sys.exit(1)
+Linting requires an installation of pre-commit, see
+https://pre-commit.com/#install, e.g.,
 
-        pip_reqs = 'python.exe -m pip install -r support/pip-requirements.txt'
-        process = run_command_in_virtualenv(pip_reqs)
-        for line in process.stdout:
-            output += line.decode(sys.stdout.encoding)
-        process.wait()
+    $ pip3 install pre-commit
 
-        if process.returncode != 0:
-            sys.stderr.write(output)
-            sys.exit(1)
+After installing pre-commit, remove existing hooks in '.git/hooks'
+and reinstall hooks with './support/setup-dev.sh'.
 
-if __name__ == '__main__':
-    if should_build_virtualenv(sys.argv[1:]):
-        build_virtualenv()
+    $ rm -rfv .git/hooks/*
+    $ ./support/setup-dev.sh
+"""
 
-    # TODO(ArmandGrillet): We should only instantiate the linters
-    # required to lint the files to analyze. See MESOS-8351.
-    CPP_LINTER = CppLinter()
-    CPP_ERRORS = CPP_LINTER.main(sys.argv[1:])
-    JS_LINTER = JsLinter()
-    JS_ERRORS = JS_LINTER.main(sys.argv[1:])
-    PY_LINTER = PyLinter()
-    PY_ERRORS = PY_LINTER.main(sys.argv[1:])
-    sys.exit(CPP_ERRORS + JS_ERRORS + PY_ERRORS)
+print(error, file=sys.stderr)
+sys.exit(1)