| 
									
										
										
										
											2024-07-08 20:30:49 +08:00
										 |  |  | #!/bin/bash
 | 
					
						
							|  |  |  | # Copyright 2020-2024 The OpenSSL Project Authors. All Rights Reserved. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Licensed under the Apache License 2.0 (the "License"). | 
					
						
							|  |  |  | # You may not use this file except in compliance with the License. | 
					
						
							|  |  |  | # You can obtain a copy in the file LICENSE in the source distribution | 
					
						
							|  |  |  | # or at https://www.openssl.org/source/license.html | 
					
						
							|  |  |  | # | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  | # This script is a wrapper around check-format.pl. | 
					
						
							|  |  |  | # It accepts the same commit revision range as 'git diff' as arguments, | 
					
						
							|  |  |  | # or just a single commit id, and uses it to identify the files and line ranges | 
					
						
							|  |  |  | # that were changed in that commit range, filtering check-format.pl output | 
					
						
							| 
									
										
										
										
											2024-07-11 18:40:29 +08:00
										 |  |  | # only to lines that fall into the change ranges of the changed files. | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  | # examples: | 
					
						
							|  |  |  | # check-format-commit.sh       # check unstaged changes | 
					
						
							|  |  |  | # check-format-commit.sh HEAD | 
					
						
							|  |  |  | # check-format-commit.sh @~3.. | 
					
						
							|  |  |  | # check-format-commit.sh f5981c9629667a5a5d6 | 
					
						
							|  |  |  | # check-format-commit.sh f5981c9629667a5a5d6..ee0bf38e8709bf71888 | 
					
						
							| 
									
										
										
										
											2024-07-08 20:30:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-12 19:25:20 +08:00
										 |  |  | # Allowlist of files to scan | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  | # Currently this is any .c or .h file (with an optional .in suffix) | 
					
						
							|  |  |  | FILE_NAME_END_ALLOWLIST=("\.[ch]\(.in\)\?") | 
					
						
							| 
									
										
										
										
											2024-07-08 20:30:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | # Global vars | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # TEMPDIR is used to hold any files this script creates | 
					
						
							|  |  |  | # And is cleaned on EXIT with a trap function | 
					
						
							|  |  |  | TEMPDIR=$(mktemp -d /tmp/checkformat.XXXXXX) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # TOPDIR always points to the root of the git tree we are working in | 
					
						
							|  |  |  | # used to locate the check-format.pl script | 
					
						
							|  |  |  | TOPDIR=$(git rev-parse --show-toplevel) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # cleanup handler function, returns us to the root of the git tree | 
					
						
							|  |  |  | # and erases our temp directory | 
					
						
							|  |  |  | cleanup() { | 
					
						
							|  |  |  |     rm -rf $TEMPDIR | 
					
						
							|  |  |  |     cd $TOPDIR | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | trap cleanup EXIT | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  | # Get the list of ids of the commits we are checking, | 
					
						
							|  |  |  | # or empty for unstaged changes. | 
					
						
							| 
									
										
										
										
											2024-07-08 20:30:49 +08:00
										 |  |  | # This lets us pass in symbolic ref names like master/etc and  | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  | # resolve them to commit ids easily | 
					
						
							| 
									
										
										
										
											2024-07-11 18:40:29 +08:00
										 |  |  | COMMIT_RANGE="$@" | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  | [ -n $COMMIT_RANGE ] && COMMIT_LAST=$(git rev-parse $COMMIT_RANGE) | 
					
						
							| 
									
										
										
										
											2024-07-08 20:30:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  | # Fail gracefully if git rev-parse doesn't produce a valid commit | 
					
						
							| 
									
										
										
										
											2024-07-08 20:30:49 +08:00
										 |  |  | if [ $? -ne 0 ] | 
					
						
							|  |  |  | then | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  |     echo "$1 is not a valid commit range or commit id" | 
					
						
							| 
									
										
										
										
											2024-07-08 20:30:49 +08:00
										 |  |  |     exit 1 | 
					
						
							|  |  |  | fi | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  | # If the commit range is exactly one revision, | 
					
						
							|  |  |  | # git rev-parse will output just the commit id of that one alone. | 
					
						
							|  |  |  | # In that case, we must manipulate a little to get a desirable result, | 
					
						
							|  |  |  | # as 'git diff' has a slightly different interpretation of a single commit id: | 
					
						
							|  |  |  | # it takes that to mean all commits up to HEAD, plus any unstaged changes. | 
					
						
							|  |  |  | if [ $(echo -n "$COMMIT_LAST" | wc -w) -ne 1 ]; then | 
					
						
							| 
									
										
										
										
											2024-07-11 18:40:29 +08:00
										 |  |  |     COMMIT_LAST=$(echo "$COMMIT_LAST" | head -1) | 
					
						
							|  |  |  | else | 
					
						
							|  |  |  |     # $COMMIT_RANGE is just one commit, make it an actual range | 
					
						
							|  |  |  |     COMMIT_RANGE=$COMMIT_RANGE^..$COMMIT_RANGE | 
					
						
							|  |  |  | fi | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:32:06 +08:00
										 |  |  | # Create an iterable list of files to check formatting on, | 
					
						
							| 
									
										
										
										
											2024-07-11 18:40:29 +08:00
										 |  |  | # including the line ranges that are changed by the commits | 
					
						
							|  |  |  | # It produces output of this format: | 
					
						
							|  |  |  | # <file name> <change start line>, <change line count> | 
					
						
							|  |  |  | git diff -U0 $COMMIT_RANGE | awk ' | 
					
						
							| 
									
										
										
										
											2024-07-08 20:30:49 +08:00
										 |  |  |     BEGIN {myfile=""}  | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  |     /^\+\+\+/ { sub(/^b./,"",$2); file=$2 } | 
					
						
							|  |  |  |     /^@@/     { sub(/^\+/,"",$3); range=$3; printf file " " range "\n" } | 
					
						
							|  |  |  |     ' > $TEMPDIR/ranges.txt | 
					
						
							| 
									
										
										
										
											2024-07-08 20:30:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-12 19:25:20 +08:00
										 |  |  | # filter in anything that matches on a filter regex | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  | for i in ${FILE_NAME_END_ALLOWLIST[@]} | 
					
						
							| 
									
										
										
										
											2024-07-08 20:30:49 +08:00
										 |  |  | do | 
					
						
							| 
									
										
										
										
											2024-07-12 19:25:20 +08:00
										 |  |  |     # Note the space after the $i below.  This is done because we want | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  |     # to match on file name suffixes, but the input file is of the form | 
					
						
							|  |  |  |     # <commit> <file path> <range start>, <range length> | 
					
						
							| 
									
										
										
										
											2024-07-12 19:25:20 +08:00
										 |  |  |     # So we can't just match on end of line.  The additional space | 
					
						
							|  |  |  |     # here lets us match on suffixes followed by the expected space | 
					
						
							|  |  |  |     # in the input file | 
					
						
							|  |  |  |     grep "$i " $TEMPDIR/ranges.txt >> $TEMPDIR/ranges.filter || true | 
					
						
							| 
									
										
										
										
											2024-07-08 20:30:49 +08:00
										 |  |  | done | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-17 23:34:14 +08:00
										 |  |  | REMAINING_FILES=$(wc -l <$TEMPDIR/ranges.filter) | 
					
						
							| 
									
										
										
										
											2024-07-12 19:25:20 +08:00
										 |  |  | if [ $REMAINING_FILES -eq 0 ] | 
					
						
							|  |  |  | then | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  |     echo "The given commit range has no C source file changes that require checking" | 
					
						
							| 
									
										
										
										
											2024-07-12 19:25:20 +08:00
										 |  |  |     exit 0 | 
					
						
							|  |  |  | fi | 
					
						
							| 
									
										
										
										
											2024-07-08 20:30:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  | # unless checking the format of unstaged changes, | 
					
						
							|  |  |  | # check out the files from the commit range. | 
					
						
							|  |  |  | if [ -n "$COMMIT_RANGE" ] | 
					
						
							|  |  |  | then | 
					
						
							|  |  |  |     # For each file name in ranges, we show that file at the commit range | 
					
						
							|  |  |  |     # we are checking, and redirect it to the same path, | 
					
						
							|  |  |  |     # relative to $TEMPDIR/check-format. | 
					
						
							|  |  |  |     # This give us the full file path to run check-format.pl on | 
					
						
							|  |  |  |     # with line numbers matching the ranges in the $TEMPDIR/ranges.filter file | 
					
						
							|  |  |  |     for j in $(awk '{print $1}' $TEMPDIR/ranges.filter | sort -u) | 
					
						
							|  |  |  |     do | 
					
						
							|  |  |  |         FDIR=$(dirname $j) | 
					
						
							|  |  |  |         mkdir -p $TEMPDIR/check-format/$FDIR | 
					
						
							|  |  |  |         git show $COMMIT_LAST:$j > $TEMPDIR/check-format/$j | 
					
						
							|  |  |  |     done | 
					
						
							|  |  |  | fi | 
					
						
							| 
									
										
										
										
											2024-07-08 20:30:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  | # Now for each file in $TEMPDIR/ranges.filter, run check-format.pl | 
					
						
							|  |  |  | for j in $(awk '{print $1}' $TEMPDIR/ranges.filter | sort -u) | 
					
						
							| 
									
										
										
										
											2024-07-08 20:30:49 +08:00
										 |  |  | do | 
					
						
							|  |  |  |     range_start=() | 
					
						
							|  |  |  |     range_end=() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Get the ranges for this file. Create 2 arrays.  range_start contains | 
					
						
							|  |  |  |     # the start lines for valid ranges from the commit.  the range_end array | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  |     # contains the corresponding end line.  Note, since diff output gives us | 
					
						
							| 
									
										
										
										
											2024-07-08 20:30:49 +08:00
										 |  |  |     # a line count for a change, the range_end[k] entry is actually | 
					
						
							|  |  |  |     # range_start[k]+line count | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  |     for k in $(grep ^$j $TEMPDIR/ranges.filter | awk '{print $2}') | 
					
						
							| 
									
										
										
										
											2024-07-08 20:30:49 +08:00
										 |  |  |     do | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  |         RSTART=$(echo $k | awk -F',' '{print $1}') | 
					
						
							|  |  |  |         RLEN=$(echo $k | awk -F',' '{print $2}') | 
					
						
							| 
									
										
										
										
											2024-07-16 11:28:30 +08:00
										 |  |  |         # when the hunk is just one line, its length is implied | 
					
						
							|  |  |  |         if [ -z "$RLEN" ]; then RLEN=1; fi | 
					
						
							| 
									
										
										
										
											2024-07-08 20:30:49 +08:00
										 |  |  |         let REND=$RSTART+$RLEN | 
					
						
							|  |  |  |         range_start+=($RSTART) | 
					
						
							|  |  |  |         range_end+=($REND) | 
					
						
							|  |  |  |     done | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  |     # Go to our checked out tree, unless checking unstaged changes | 
					
						
							|  |  |  |     [ -n "$COMMIT_RANGE" ] && cd $TEMPDIR/check-format | 
					
						
							| 
									
										
										
										
											2024-07-08 20:30:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Actually run check-format.pl on the file, capturing the output | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  |     # in a temporary file.  Note the format of check-format.pl output is | 
					
						
							|  |  |  |     # <file path>:<line number>:<error text>:<offending line contents> | 
					
						
							|  |  |  |     $TOPDIR/util/check-format.pl $j > $TEMPDIR/results.txt | 
					
						
							| 
									
										
										
										
											2024-07-08 20:30:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Now we filter the check-format.pl output based on the changed lines | 
					
						
							|  |  |  |     # captured in the range_start/end arrays | 
					
						
							|  |  |  |     let maxidx=${#range_start[@]}-1 | 
					
						
							|  |  |  |     for k in $(seq 0 1 $maxidx) | 
					
						
							|  |  |  |     do | 
					
						
							|  |  |  |         RSTART=${range_start[$k]} | 
					
						
							|  |  |  |         REND=${range_end[$k]} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # field 2 of check-format.pl output is the offending line number | 
					
						
							|  |  |  |         # Check here if any line in that output falls between any of the  | 
					
						
							|  |  |  |         # start/end ranges defined in the range_start/range_end array. | 
					
						
							|  |  |  |         # If it does fall in that range, print the entire line to stdout | 
					
						
							|  |  |  |         awk -v rstart=$RSTART -v rend=$REND -F':' ' | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  |                 /:/ { if (rstart <= $2 && $2 <= rend) print $0 } | 
					
						
							|  |  |  |             ' $TEMPDIR/results.txt >>$TEMPDIR/results-filtered.txt | 
					
						
							| 
									
										
										
										
											2024-07-08 20:30:49 +08:00
										 |  |  |     done | 
					
						
							|  |  |  | done | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  | cat $TEMPDIR/results-filtered.txt | 
					
						
							| 
									
										
										
										
											2024-07-08 20:30:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  | # If any findings were in range, exit with a different error code | 
					
						
							| 
									
										
										
										
											2024-10-27 18:15:21 +08:00
										 |  |  | if [ -s $TEMPDIR/results-filtered.txt ] | 
					
						
							| 
									
										
										
										
											2024-10-11 14:12:38 +08:00
										 |  |  | then | 
					
						
							|  |  |  |     exit 2 | 
					
						
							|  |  |  | fi |