#!/usr/bin/env python

# Runs style checker using Google's cpplint.
# http://google-styleguide.googlecode.com/svn/trunk/cpplint/cpplint.py

import os
import re
import subprocess
import sys

# Build active rules from list:
#
# build/class
# build/deprecated
# build/endif_comment
# build/explicit_make_pair
# build/forward_decl
# build/header_guard
# build/include
# build/include_alpha
# build/include_order
# build/include_what_you_use
# build/namespaces
# build/printf_format
# build/storage_class
# legal/copyright
# readability/alt_tokens
# readability/braces
# readability/casting
# readability/check
# readability/constructors
# readability/fn_size
# readability/function
# readability/multiline_comment
# readability/multiline_string
# readability/namespace
# readability/nolint
# readability/streams
# readability/todo
# readability/utf8
# runtime/arrays
# runtime/casting
# runtime/explicit
# runtime/int
# runtime/init
# runtime/invalid_increment
# runtime/member_string_references
# runtime/memset
# runtime/operator
# runtime/printf
# runtime/printf_format
# runtime/references
# runtime/rtti
# runtime/sizeof
# runtime/string
# runtime/threadsafe_fn
# whitespace/blank_line
# whitespace/braces
# whitespace/comma
# whitespace/comments
# whitespace/empty_loop_body
# whitespace/end_of_line
# whitespace/ending_newline
# whitespace/forcolon
# whitespace/indent
# whitespace/labels
# whitespace/line_length
# whitespace/newline
# whitespace/operators
# whitespace/parens
# whitespace/semicolon
# whitespace/tab
# whitespace/todo

# Currently, only tabs are checked.
active_rules = '--filter=-,+whitespace/tab'

# Root source paths (will be traversed recursively).
source_dirs = ['src',
               'include',
               os.path.join('3rdparty', 'libprocess')]

# Add file paths and patterns which should not be checked
# This should include 3rdparty libraries, includes and machine generated
# source.
exclude_files = '(protobuf\-2\.4\.1|gmock\-1\.6\.0|glog\-0\.3\.3|boost\-1\.53\.0|libev\-4\.15|java/jni|\.pb\.cc|\.pb\.h)'

source_files = '\.(cpp|hpp|cc|h)$'

def find_candidates(root_dir):
    exclude_file_regex = re.compile(exclude_files)
    source_criteria_regex = re.compile(source_files)
    for root, dirs, 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_lint(source_paths):
    print 'Checking ' + str(len(source_paths)) + ' files...'
    p = subprocess.Popen(
        ['python', 'support/cpplint.py', active_rules] + source_paths,
        stderr=subprocess.PIPE,
        close_fds=True)

    # Lines are stored and filtered, only showing found errors instead
    # of 'Done processing XXX.' which tends to be dominant output.
    lint_out_regex = re.compile(':')
    for line in p.stderr:
        if lint_out_regex.search(line) is not None:
            sys.stdout.write(line)


if __name__ == '__main__':
    # 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 source_dirs:
        if not os.path.exists(source_dir):
            print 'Could not find "' + 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 source_dirs:
        for candidate in find_candidates(source_dir):
            candidates.append(candidate)

    run_lint(candidates)