Home | History | Annotate | Line # | Download | only in util
check-format-commit.sh revision 1.1.1.1
      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
    172