1#!/usr/bin/env python3 2# 3# Script to check if any GNOME games Vala coding guidelines are violated. 4# 5# Copyright (C) 2015 Sahil Sareen (ssareen [ AT ] gnome [ DOT ] org) 6# 7# Permission is hereby granted, free of charge, to any person obtaining a copy 8# of this software and associated documentation files (the "Software"), to deal 9# in the Software without restriction, including without limitation the rights 10# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11# copies of the Software, and to permit persons to whom the Software is 12# furnished to do so, subject to the following conditions: 13# 14# The above copyright notice and this permission notice shall be included in 15# all copies or substantial portions of the Software. 16# 17# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23# THE SOFTWARE. 24 25# ======================= 26# Sample usage 27# ======================= 28# 29# To use it as a pre-commit hook, Update autogen.sh to symlink to this file 30# 31# if [ -d $srcdir/.git ]; then 32# for HOOK in pre-commit pre-applypatch 33# do 34# if [ ! -L $srcdir/.git/hooks/$HOOK ]; then 35# ln -s ../../../libgnome-games-support/style-checker \ 36# $srcdir/.git/hooks/$HOOK && echo "Enabled $HOOK style checker." 37# fi 38# done 39# fi 40# 41# Note: This can be used as the following hooks: 42# Client side 43# - pre-commit 44# - pre-applypatch 45# - pre-push 46# Server side 47# - pre-receive 48 49import sys 50import re 51import os 52 53 54def find(s, ch): 55 return [i for i, ltr in enumerate(s) if ltr == ch] 56 57 58def main(): 59 print("Validating the diff ...") 60 61 p = os.popen('git diff --cached --unified=0', "r") 62 63 # Read the diff 64 lines = [] 65 lineNum = 0 66 fileName = '' 67 nIssues = 0 68 69 while True: 70 line = p.readline() 71 if not line: 72 break 73 if line.startswith('@@'): 74 lineNumSearch = re.search(r'.* .* \+(\d+).*', line) 75 lineNum = int(lineNumSearch.groups()[0]) 76 elif line.startswith('+'): 77 if line.startswith('+++'): 78 pos = line.rfind('/') 79 fileName = line[pos + 1: -1] 80 elif fileName.endswith('vala'): 81 lines += [(fileName, lineNum, line[1:])] 82 lineNum += 1 83 84 def getLineFileName(line): 85 return line[0] 86 87 def getLineNum(line): 88 return line[1] 89 90 def getLineData(line, pos=-1): 91 if pos == -1: 92 return line[2] 93 else: 94 return line[2][pos] 95 96 def getLineWidth(line): 97 return len(getLineData(line)) 98 99 def printIssue(line, msg): 100 print("%s => Line %d %s" 101 % (getLineFileName(line), getLineNum(line), msg)) 102 103 for lineNum in range(0, len(lines)): 104 currLine = lines[lineNum] 105 106 # Line Width 107 if getLineWidth(currLine) > 120: 108 printIssue(currLine, "is greater than 120 characters") 109 nIssues += 1 110 111 # Lines with trailing white-space or tabspace 112 if getLineData(currLine).endswith(' \n'): 113 printIssue(currLine, "has trailing whitespace") 114 nIssues += 1 115 116 if getLineData(currLine).endswith('\t\n'): 117 printIssue(currLine, "has trailing tabspace") 118 nIssues += 1 119 120 # Lines with tabspace 121 if '\t' in getLineData(currLine): 122 printIssue(currLine, "has tabspace") 123 nIssues += 1 124 125 # Single whitespace before "{" 126 indexes = find(getLineData(currLine), '{') 127 for index in indexes: 128 if index > 1: 129 if getLineData(currLine, index - 1) not in [' ', '_']: 130 printIssue(currLine, "missing whitespace before {") 131 nIssues += 1 132 elif getLineData(currLine, index - 2) == ' ' \ 133 and getLineData(currLine, index - 1) != '_' \ 134 and not (re.findall("\s*{", 135 getLineData(currLine)) != [] and 136 getLineData(currLine, 0) in ['\t', ' ']): 137 printIssue(currLine, "multiple whitespace before {") 138 nIssues += 1 139 140 # Single whitespace before "(" 141 indexes = find(getLineData(currLine), '(') 142 for index in indexes: 143 if index > 1: 144 if getLineData(currLine, index - 1) != ' ' \ 145 and getLineData(currLine, index - 1) \ 146 not in ['_', '(', '&', '*', '-', '$', '!', '\t', '"']: 147 printIssue(currLine, "missing whitespace before (") 148 nIssues += 1 149 elif getLineData(currLine, index - 2) == ' ' \ 150 and getLineData(currLine, index - 1) not in ['_', '('] \ 151 and not (getLineData(currLine).startswith(" *") or 152 getLineData(currLine).startswith("#") or 153 (re.findall("\s*\(", 154 getLineData(currLine)) != [] and 155 getLineData(currLine, 0) in ['\t', ' '])): 156 printIssue(currLine, "multiple whitespace before (") 157 nIssues += 1 158 159 # No whitespace between round brackets "(xyz)" 160 indexes = find(getLineData(currLine), '(') 161 for index in indexes: 162 if index > 1: 163 if getLineData(currLine, index + 1) == ' ': 164 printIssue(currLine, "has whitespace after (") 165 nIssues += 1 166 167 indexes = find(getLineData(currLine), ')') 168 for index in indexes: 169 if index > 1: 170 if getLineData(currLine, index - 1) == ' ': 171 printIssue(currLine, "has whitespace before )") 172 nIssues += 1 173 174 if nIssues != 0: 175 if nIssues == 1: 176 print("Guideline checker found one issue.") 177 else: 178 print("Guideline checker found " + str(nIssues) + " issues.") 179 180 if os.path.basename(__file__) == 'pre-commit': 181 print("To ignore use `git commit --no-verify`") 182 return -1 183 elif os.path.basename(__file__) == 'pre-push': 184 print("To ignore use `git push --no-verify`") 185 return -1 186 elif os.path.basename(__file__) == 'pre-receive': 187 print("Your push has been rejected.") 188 return -1 189 elif os.path.basename(__file__) == 'pre-applypatch': 190 print("We strongly recommend you to fix these.") 191 print("Continuing anyway....") 192 else: 193 print("Guideline checker found no issues.") 194 195 return 0 196 197if __name__ == "__main__": 198 sys.exit(main()) 199