1 | #!/bin/bash
|
---|
2 | # Copyright 2020-2024 The OpenSSL Project Authors. All Rights Reserved.
|
---|
3 | #
|
---|
4 | # Licensed under the Apache License 2.0 (the "License").
|
---|
5 | # You may not use this file except in compliance with the License.
|
---|
6 | # You can obtain a copy in the file LICENSE in the source distribution
|
---|
7 | # or at https://www.openssl.org/source/license.html
|
---|
8 | #
|
---|
9 | # This script is a wrapper around check-format.pl. It accepts a commit sha
|
---|
10 | # value as input, and uses it to identify the files and ranges that were
|
---|
11 | # changed in that commit, filtering check-format.pl output only to lines that
|
---|
12 | # fall into the commits change ranges.
|
---|
13 | #
|
---|
14 |
|
---|
15 |
|
---|
16 | # List of Regexes to use when running check-format.pl.
|
---|
17 | # Style checks don't apply to any of these
|
---|
18 | EXCLUDED_FILE_REGEX=("\.pod" \
|
---|
19 | "\.pl" \
|
---|
20 | "\.pm" \
|
---|
21 | "\.t" \
|
---|
22 | "\.yml" \
|
---|
23 | "\.sh")
|
---|
24 |
|
---|
25 | # Exit code for the script
|
---|
26 | EXIT_CODE=0
|
---|
27 |
|
---|
28 | # Global vars
|
---|
29 |
|
---|
30 | # TEMPDIR is used to hold any files this script creates
|
---|
31 | # And is cleaned on EXIT with a trap function
|
---|
32 | TEMPDIR=$(mktemp -d /tmp/checkformat.XXXXXX)
|
---|
33 |
|
---|
34 | # TOPDIR always points to the root of the git tree we are working in
|
---|
35 | # used to locate the check-format.pl script
|
---|
36 | TOPDIR=$(git rev-parse --show-toplevel)
|
---|
37 |
|
---|
38 |
|
---|
39 | # cleanup handler function, returns us to the root of the git tree
|
---|
40 | # and erases our temp directory
|
---|
41 | cleanup() {
|
---|
42 | rm -rf $TEMPDIR
|
---|
43 | cd $TOPDIR
|
---|
44 | }
|
---|
45 |
|
---|
46 | trap cleanup EXIT
|
---|
47 |
|
---|
48 | # Get the canonical sha256 sum for the commit we are checking
|
---|
49 | # This lets us pass in symbolic ref names like master/etc and
|
---|
50 | # resolve them to sha256 sums easily
|
---|
51 | COMMIT=$(git rev-parse $1)
|
---|
52 |
|
---|
53 | # Fail gracefully if git rev-parse doesn't produce a valid
|
---|
54 | # commit
|
---|
55 | if [ $? -ne 0 ]
|
---|
56 | then
|
---|
57 | echo "$1 is not a valid revision"
|
---|
58 | exit 1
|
---|
59 | fi
|
---|
60 |
|
---|
61 | # Create a iteratable list of files to check for a
|
---|
62 | # given commit. It produces output of the format
|
---|
63 | # <commit id> <file name> <change start line>, <change line count>
|
---|
64 | touch $TEMPDIR/ranges.txt
|
---|
65 | git show $COMMIT | awk -v mycmt=$COMMIT '
|
---|
66 | BEGIN {myfile=""}
|
---|
67 | /+{3}/ {
|
---|
68 | gsub(/b\//,"",$2);
|
---|
69 | myfile=$2
|
---|
70 | }
|
---|
71 | /@@/ {
|
---|
72 | gsub(/+/,"",$3);
|
---|
73 | printf mycmt " " myfile " " $3 "\n"
|
---|
74 | }' >> $TEMPDIR/ranges.txt || true
|
---|
75 |
|
---|
76 | # filter out anything that matches on a filter regex
|
---|
77 | for i in ${EXCLUDED_FILE_REGEX[@]}
|
---|
78 | do
|
---|
79 | touch $TEMPDIR/ranges.filter
|
---|
80 | grep -v "$i" $TEMPDIR/ranges.txt >> $TEMPDIR/ranges.filter || true
|
---|
81 | REMAINING_FILES=$(wc -l $TEMPDIR/ranges.filter | awk '{print $1}')
|
---|
82 | if [ $REMAINING_FILES -eq 0 ]
|
---|
83 | then
|
---|
84 | echo "This commit has no files that require checking"
|
---|
85 | exit 0
|
---|
86 | fi
|
---|
87 | mv $TEMPDIR/ranges.filter $TEMPDIR/ranges.txt
|
---|
88 | done
|
---|
89 |
|
---|
90 | # check out the files from the commit level.
|
---|
91 | # For each file name in ranges, we show that file at the commit
|
---|
92 | # level we are checking, and redirect it to the same path, relative
|
---|
93 | # to $TEMPDIR/check-format. This give us the full file to run
|
---|
94 | # check-format.pl on with line numbers matching the ranges in the
|
---|
95 | # $TEMPDIR/ranges.txt file
|
---|
96 | for j in $(grep $COMMIT $TEMPDIR/ranges.txt | awk '{print $2}')
|
---|
97 | do
|
---|
98 | FDIR=$(dirname $j)
|
---|
99 | mkdir -p $TEMPDIR/check-format/$FDIR
|
---|
100 | git show $COMMIT:$j > $TEMPDIR/check-format/$j
|
---|
101 | done
|
---|
102 |
|
---|
103 | # Now for each file in $TEMPDIR/check-format run check-format.pl
|
---|
104 | # Note that we use the %P formatter in the find utilty. This strips
|
---|
105 | # off the $TEMPDIR/check-format path prefix, leaving $j with the
|
---|
106 | # path to the file relative to the root of the source dir, so that
|
---|
107 | # output from check-format.pl looks correct, relative to the root
|
---|
108 | # of the git tree.
|
---|
109 | for j in $(find $TEMPDIR/check-format -type f -printf "%P\n")
|
---|
110 | do
|
---|
111 | range_start=()
|
---|
112 | range_end=()
|
---|
113 |
|
---|
114 | # Get the ranges for this file. Create 2 arrays. range_start contains
|
---|
115 | # the start lines for valid ranges from the commit. the range_end array
|
---|
116 | # contains the corresponding end line (note, since diff output gives us
|
---|
117 | # a line count for a change, the range_end[k] entry is actually
|
---|
118 | # range_start[k]+line count
|
---|
119 | for k in $(grep $COMMIT $TEMPDIR/ranges.txt | grep $j | awk '{print $3}')
|
---|
120 | do
|
---|
121 | RANGE=$k
|
---|
122 | RSTART=$(echo $RANGE | awk -F',' '{print $1}')
|
---|
123 | RLEN=$(echo $RANGE | awk -F',' '{print $2}')
|
---|
124 | let REND=$RSTART+$RLEN
|
---|
125 | range_start+=($RSTART)
|
---|
126 | range_end+=($REND)
|
---|
127 | done
|
---|
128 |
|
---|
129 | # Go to our checked out tree
|
---|
130 | cd $TEMPDIR/check-format
|
---|
131 |
|
---|
132 | # Actually run check-format.pl on the file, capturing the output
|
---|
133 | # in a temporary file. Note the format of check-patch.pl output is
|
---|
134 | # <file name>:<line number>:<error text>:<offending line contents>
|
---|
135 | $TOPDIR/util/check-format.pl $j > $TEMPDIR/format-results.txt
|
---|
136 |
|
---|
137 | # Now we filter the check-format.pl output based on the changed lines
|
---|
138 | # captured in the range_start/end arrays
|
---|
139 | let maxidx=${#range_start[@]}-1
|
---|
140 | for k in $(seq 0 1 $maxidx)
|
---|
141 | do
|
---|
142 | RSTART=${range_start[$k]}
|
---|
143 | REND=${range_end[$k]}
|
---|
144 |
|
---|
145 | # field 2 of check-format.pl output is the offending line number
|
---|
146 | # Check here if any line in that output falls between any of the
|
---|
147 | # start/end ranges defined in the range_start/range_end array.
|
---|
148 | # If it does fall in that range, print the entire line to stdout
|
---|
149 | # If anything is printed, have awk exit with a non-zero exit code
|
---|
150 | awk -v rstart=$RSTART -v rend=$REND -F':' '
|
---|
151 | BEGIN {rc=0}
|
---|
152 | /:/ {
|
---|
153 | if (($2 >= rstart) && ($2 <= rend)) {
|
---|
154 | print $0;
|
---|
155 | rc=1
|
---|
156 | }
|
---|
157 | }
|
---|
158 | END {exit rc;}
|
---|
159 | ' $TEMPDIR/format-results.txt
|
---|
160 |
|
---|
161 | # If awk exited with a non-zero code, this script will also exit
|
---|
162 | # with a non-zero code
|
---|
163 | if [ $? -ne 0 ]
|
---|
164 | then
|
---|
165 | EXIT_CODE=1
|
---|
166 | fi
|
---|
167 | done
|
---|
168 | done
|
---|
169 |
|
---|
170 | # Exit with the recorded exit code above
|
---|
171 | exit $EXIT_CODE
|
---|