Add check_all.py and check_whitespace.py scripts.

Change-Id: I29ea94aa38ad1cb9e665836db6e4d48d3dbc041b
diff --git a/scripts/src_util/check_all.py b/scripts/src_util/check_all.py
new file mode 100644
index 0000000..f666a78
--- /dev/null
+++ b/scripts/src_util/check_all.py
@@ -0,0 +1,51 @@
+# -*- coding: utf-8 -*-
+
+#-------------------------------------------------------------------------
+# drawElements Quality Program utilities
+# --------------------------------------
+#
+# Copyright 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# 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.
+#
+#-------------------------------------------------------------------------
+
+import sys
+from argparse import ArgumentParser
+from common import getChangedFiles, getAllProjectFiles
+from check_include_guards import checkIncludeGuards
+from check_whitespace import checkWhitespace
+
+if __name__ == "__main__":
+    parser = ArgumentParser()
+    parser.add_argument("-e", "--only-errors",  action="store_true", dest="onlyErrors",   default=False, help="Print only on error")
+    parser.add_argument("-i", "--only-changed", action="store_true", dest="useGitIndex",  default=False, help="Check only modified files. Uses git.")
+
+    args = parser.parse_args()
+
+    if args.useGitIndex:
+        files = getChangedFiles()
+    else:
+        files = getAllProjectFiles()
+
+    error = not all([
+        checkWhitespace(files),
+        checkIncludeGuards(files),
+        #todo checkRedundantIncludeGuards(files),
+        ])
+
+    if error:
+        print "One or more checks failed"
+        sys.exit(1)
+    if not args.onlyErrors:
+        print "All checks passed"
diff --git a/scripts/src_util/check_include_guards.py b/scripts/src_util/check_include_guards.py
index 085ba0c..fa792e1 100644
--- a/scripts/src_util/check_include_guards.py
+++ b/scripts/src_util/check_include_guards.py
@@ -97,6 +97,15 @@
 					headers.append(os.path.join(root, file))
 	return headers
 
+def checkIncludeGuards (files):
+    error = False
+    for file in files:
+        if isHeader(file):
+            if not hasValidIncludeGuard(file):
+                error = True
+                print "File %s contains invalid include guards" % file
+    return not error
+
 if __name__ == "__main__":
 	parser = OptionParser()
 	parser.add_option("-x", "--fix", action="store_true", dest="fix", default=False, help="attempt to fix include guards (use with caution)")
diff --git a/scripts/src_util/check_whitespace.py b/scripts/src_util/check_whitespace.py
new file mode 100644
index 0000000..7d079bf
--- /dev/null
+++ b/scripts/src_util/check_whitespace.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+
+#-------------------------------------------------------------------------
+# drawElements Quality Program utilities
+# --------------------------------------
+#
+# Copyright 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# 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.
+#
+#-------------------------------------------------------------------------
+
+import sys
+from argparse import ArgumentParser
+from common import getChangedFiles, getAllProjectFiles, isTextFile
+
+def checkFileWhitespace (file):
+    f = open(file, 'rb')
+    error = False
+    for lineNum, line in enumerate(f):
+        if line.endswith(" \n") or line.endswith("\t\n"):
+            error = True
+            print "%s:%i trailing whitespace" % (file, lineNum+1)
+        if " \t" in line:
+            error = True
+            print "%s:%i merged <space><tab>" % (file, lineNum+1)
+    f.close()
+
+    return not error
+
+def checkWhitespace (files):
+    error = False
+    for file in files:
+        if isTextFile(file):
+            if not checkFileWhitespace(file):
+                error = True
+
+    return not error
+
+if __name__ == "__main__":
+    parser = ArgumentParser()
+    parser.add_argument("-e", "--only-errors",  action="store_true", dest="onlyErrors",   default=False, help="Print only on error")
+    parser.add_argument("-i", "--only-changed", action="store_true", dest="useGitIndex",  default=False, help="Check only modified files. Uses git.")
+
+    args = parser.parse_args()
+
+    if args.useGitIndex:
+        files = getChangedFiles()
+    else:
+        files = getAllProjectFiles()
+
+    error = not checkWhitespace(files)
+
+    if error:
+        print "One or more checks failed"
+        sys.exit(1)
+    if not args.onlyErrors:
+        print "All checks passed"
diff --git a/scripts/src_util/common.py b/scripts/src_util/common.py
new file mode 100644
index 0000000..536573b
--- /dev/null
+++ b/scripts/src_util/common.py
@@ -0,0 +1,109 @@
+# -*- coding: utf-8 -*-
+
+#-------------------------------------------------------------------------
+# drawElements Quality Program utilities
+# --------------------------------------
+#
+# Copyright 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# 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.
+#
+#-------------------------------------------------------------------------
+
+import os
+import subprocess
+
+TEXT_FILE_EXTENSION = [
+    ".bat",
+    ".c",
+    ".cfg",
+    ".cmake",
+    ".cpp",
+    ".css",
+    ".h",
+    ".hh",
+    ".hpp",
+    ".html",
+    ".inl",
+    ".java",
+    ".js",
+    ".m",
+    ".mk",
+    ".mm",
+    ".py",
+    ".rule",
+    ".sh",
+    ".test",
+    ".txt",
+    ".xml",
+    ".xsl",
+    ]
+
+BINARY_FILE_EXTENSION = [
+    ".png",
+    ".pkm",
+    ".xcf",
+    ]
+
+def isTextFile (filePath):
+    ext = os.path.splitext(filePath)[1]
+    if ext in TEXT_FILE_EXTENSION:
+        return True
+    if ext in BINARY_FILE_EXTENSION:
+        return False
+
+    # Analyze file contents, zero byte is the marker for a binary file
+    f = open(filePath, "rb")
+
+    TEST_LIMIT = 1024
+    nullFound = False
+    numBytesTested = 0
+
+    byte = f.read(1)
+    while byte and numBytesTested < TEST_LIMIT:
+        if byte == "\0":
+            nullFound = True
+            break
+
+        byte = f.read(1)
+        numBytesTested += 1
+
+    f.close()
+    return not nullFound
+
+def getProjectPath ():
+    # File system hierarchy is fixed
+    scriptDir = os.path.dirname(os.path.abspath(__file__))
+    projectDir = os.path.normpath(os.path.join(scriptDir, "../.."))
+    return projectDir
+
+def git (*args):
+    process = subprocess.Popen(['git'] + list(args), cwd=getProjectPath(), stdout=subprocess.PIPE)
+    output = process.communicate()[0]
+    if process.returncode != 0:
+        raise Exception("Failed to execute '%s', got %d" % (str(args), process.returncode))
+    return output
+
+def getAbsolutePathPathFromProjectRelativePath (projectRelativePath):
+    return os.path.normpath(os.path.join(getProjectPath(), projectRelativePath))
+
+def getChangedFiles ():
+    # Added, Copied, Moved, Renamed
+    output = git('diff', '--cached', '--name-only', '-z', '--diff-filter=ACMR')
+    relativePaths = output.split('\0')[:-1] # remove trailing ''
+    return [getAbsolutePathPathFromProjectRelativePath(path) for path in relativePaths]
+
+def getAllProjectFiles ():
+    output = git('ls-files', '--cached', '-z')
+    relativePaths = output.split('\0')[:-1] # remove trailing ''
+    return [getAbsolutePathPathFromProjectRelativePath(path) for path in relativePaths]