moin-2.0 / contrib / pep8 / coding_std.py

#!/usr/bin/env python
# Copyright: 2012 by MoinMoin:RogerHaase
# License: GNU GPL v2 (or any later version), see LICENSE.txt for details.

"""
Detect and correct violations of the moin2 coding standards:
    - no trailing blanks
    - exactly one linefeed at file end, see PEP8
    - DOS line endings on .bat and .cmd files, unix line endings everywhere else

Execute this script from the root directory of the moin2 repository or
from anywhere within the contrib path.
"""

import sys
import os
import warnings
warnings.simplefilter("once")

# file types to be processed
SELECTED_SUFFIXES = set("py bat cmd html css js styl".split())

# stuff considered DOS/WIN
WIN_SUFFIXES = set("bat cmd".split())


def directories_to_ignore(starting_dir):
    """Return a list of directories that will not be processed."""
    # list format: [(fully qualified directory name, sub-directory name), ... ]
    ignore_dirs = []
    level2_dirs = ".hg contrib dlc docs env moin.egg-info wiki".split()
    for dir in level2_dirs:
        ignore_dirs.append((starting_dir, dir))
    ignore_dirs.append((starting_dir + os.sep + "MoinMoin", "translations"))
    return ignore_dirs


def check_files(filename, suffix):
    """Delete trailing blanks,
        force a single linefeed at file end,
        force line ending to be \r\n for bat files and \n for all others."""
    suffix = suffix.lower()
    if suffix in WIN_SUFFIXES:
        line_end = "\r\n"
    else:
        line_end = "\n"

    with open(filename, "rb") as f:
        lines = f.readlines()

    # now look at file end and get rid of all whitespace-only lines there:
    while lines:
        if not lines[-1].strip():
            del lines[-1]
            warnings.warn(u"%s was changed to remove empty lines at eof" % filename)
        else:
            break

    with open(filename, "wb") as f:
        for line in lines:
            pep8_line = line.rstrip() + line_end
            f.write(pep8_line)
            # if line was changed, issue warning once for each type of change
            if suffix in WIN_SUFFIXES and not line.endswith("\r\n"):
                warnings.warn(u"%s was changed to DOS line endings" % filename)
            elif suffix not in WIN_SUFFIXES and line.endswith("\r\n"):
                warnings.warn(u"%s was changed to Unix line endings" % filename)
            elif pep8_line != line:
                warnings.warn(u"%s was changed to remove trailing blanks" % filename)


def file_picker(starting_dir):
    """Select target files and pass each to file checker."""
    ignore_dirs = directories_to_ignore(starting_dir)

    for root, dirs, files in os.walk(starting_dir):
        # delete directories in ignore list
        for mama_dir, baby_dir in ignore_dirs:
            if mama_dir == root and baby_dir in dirs:
                dirs.remove(baby_dir)
        # check files with selected suffixes
        for file in files:
            suffix = file.split(".")[-1]
            if suffix in SELECTED_SUFFIXES:
                filename = os.path.join(root, file)
                check_files(filename, suffix)


if __name__ == "__main__":
    if len(sys.argv) > 1:
        starting_dir = os.path.abspath(sys.argv[1])
    else:
        starting_dir = os.path.abspath(os.path.dirname(__file__))
        starting_dir = starting_dir.split(os.sep + 'contrib')[0]
    warnings.warn(u"%s is starting directory" % starting_dir)
    file_picker(starting_dir)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.