|
| 1 | +#!/bin/bash |
| 2 | + |
| 3 | +set -e |
| 4 | + |
| 5 | +if [[ "$#" -ne 2 ]] |
| 6 | +then |
| 7 | + echo "Script for running the CPP linter only on modified lines." |
| 8 | + echo "Requires two arguments the start and the end" |
| 9 | + echo "start - a git reference that marks the first commit whose changes to consider" |
| 10 | + echo "end - a git reference that marks the last commit whose changes to consider" |
| 11 | + |
| 12 | + exit 1 |
| 13 | +fi |
| 14 | + |
| 15 | +git_start=$1 |
| 16 | +git_end=$2 |
| 17 | + |
| 18 | +# Get the list of files that have changed |
| 19 | +diff_files=`git diff --name-only $git_start $git_end` |
| 20 | + |
| 21 | +# Build a filter that will filter the blame output |
| 22 | +# to only include lines that come from one of the relevant_commits |
| 23 | +# We do this by making the blame tool output the same hash for all |
| 24 | +# lines that are too old. |
| 25 | +blame_grep_filter=`git rev-parse "$git_start"` |
| 26 | + |
| 27 | +# Build a regex for finding the line number of a given line inside blame |
| 28 | +# First matches the 40 digit hash of the commi |
| 29 | +# Then match an arbitary length number that represents the line in the original file |
| 30 | +# Finally matches (and groups) another arbitary length digit which is the |
| 31 | +# line in the final file |
| 32 | +regex="[0-9a-f]{40} [0-9]+ ([0-9]+)" |
| 33 | + |
| 34 | +# We only split on lines or otherwise the git blame output is nonsense |
| 35 | +IFS=$'\n' |
| 36 | + |
| 37 | +are_errors=0 |
| 38 | + |
| 39 | +for file in $diff_files; do |
| 40 | + # We build another grep filter the output of the linting script |
| 41 | + lint_grep_filter="^(" |
| 42 | + |
| 43 | + # Include line 0 errors (e.g. copyright) |
| 44 | + lint_grep_filter+=$file |
| 45 | + lint_grep_filter+=":0" |
| 46 | + |
| 47 | + # We first filter only the lines that start with a commit hash |
| 48 | + # Then we filter out the ones that come from the start commit |
| 49 | + modified_lines=`git blame $git_start..$git_end --line-porcelain $file | grep -E "^[0-9a-f]{40}" | { grep -v "$blame_grep_filter" || true; }` |
| 50 | + |
| 51 | + # For each modified line we find the line number |
| 52 | + for line in $modified_lines; do |
| 53 | + |
| 54 | + # Use the above regex to match the line number |
| 55 | + if [[ $line =~ $regex ]] |
| 56 | + then |
| 57 | + # Some bash magic to get the first group from the regex (the line number) |
| 58 | + LINENUM="${BASH_REMATCH[1]}" |
| 59 | + |
| 60 | + # The format from the linting script is filepath:linenum: [error type] |
| 61 | + # So we build the first bit to filter out relevant lines |
| 62 | + LINE_FILTER=$file:$LINENUM |
| 63 | + |
| 64 | + # Add the line filter on to the grep expression as we want |
| 65 | + # lines that match any of the line filters |
| 66 | + lint_grep_filter+="|" |
| 67 | + lint_grep_filter+=$LINE_FILTER |
| 68 | + fi |
| 69 | + done |
| 70 | + |
| 71 | + # Add the closing bracket |
| 72 | + lint_grep_filter+=")" |
| 73 | + |
| 74 | + # Run the linting script and filter by the filter we've build |
| 75 | + # of all the modified lines |
| 76 | + # The errors from the linter go to STDERR so must be redirected to STDOUT |
| 77 | + result=`python scripts/cpplint.py $file 2>&1 | grep -E "$lint_grep_filter"` |
| 78 | + |
| 79 | + # Providing some errors were relevant we print them out |
| 80 | + if [ "$result" ] |
| 81 | + then |
| 82 | + are_errors=1 |
| 83 | + (>&2 echo "$result") |
| 84 | + fi |
| 85 | +done |
| 86 | + |
| 87 | +unset IFS |
| 88 | + |
| 89 | +# Return an error code if errors are found |
| 90 | +exit $are_errors |
0 commit comments