1#!/usr/bin/env bash
2# Copyright 2021 Google LLC
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16# Find code files.
17CODE_FILES=()
18while IFS=  read -r -d $'\0'; do
19  CODE_FILES+=("$REPLY")
20done < <(find . -not \( -path '*/target' -prune \) -and -name '*.rs' -print0)
21
22# Find markdown files.
23MD_FILES=()
24while IFS=  read -r -d $'\0'; do
25  MD_FILES+=("$REPLY")
26done < <(find . -not \( -path '*/target' -prune \) -and -not \( -path '*/wycheproof' -prune \) -and -name '*.md' -print0)
27
28# Check that source files have the Apache License header.
29# Automatically skips generated files.
30check_license() {
31  local path="$1"
32
33  if head -1 "$path" | grep -iq -e 'generated' -e '::prost::message'; then
34    return 0
35  fi
36
37  if echo "$path" | grep -q "/proto/"; then
38    return 0
39  fi
40
41  # Look for "Apache License" on the file header
42  if ! head -10 "$path" | grep -q 'Apache License'; then
43    # Format: $path:$line:$message
44    echo "$path:1:license header not found"
45    return 1
46  fi
47  return 0
48}
49
50# Check that any TODO markers in files have associated issue numbers
51check_todo() {
52  local path="$1"
53  local result
54  result=$(grep --with-filename --line-number TODO "$path" | grep --invert-match --regexp='TODO(#[0-9][0-9]*)')
55  if [[ -n $result ]]; then
56    echo "TODO marker without issue number:"
57    echo "$result"
58    return 1
59  fi
60  return 0
61}
62
63# Check that any calls that might panic have a comment noting why they're safe
64check_panic() {
65  local path="$1"
66  if [[ $path =~ "test" || $path =~ "examples/" || $path =~ "rinkey/" || $path =~ "benches/" ]]; then
67    return 0
68  fi
69  for needle in "panic!(" "unwrap(" "expect(" "unwrap_err(" "expect_err(" "unwrap_none(" "expect_none(" "unreachable!"; do
70    local result
71    result=$(grep --with-filename --line-number "$needle" "$path" | grep --invert-match --regexp='safe:'| grep --invert-match --regexp=':[0-9]*://')
72    if [[ -n $result ]]; then
73      echo "Un-annotated panic code:"
74      echo "$result"
75      return 1
76    fi
77  done
78  return 0
79}
80
81errcount=0
82for f in "${CODE_FILES[@]}"; do
83  check_license "$f"
84  errcount=$((errcount + $?))
85  check_todo "$f"
86  errcount=$((errcount + $?))
87  check_panic "$f"
88  errcount=$((errcount + $?))
89done
90
91EMBEDMD="$(go env GOPATH)/bin/embedmd"
92if [[ ! -x "$EMBEDMD" ]]; then
93  go install github.com/campoy/embedmd@97c13d6
94fi
95for f in "${MD_FILES[@]}"; do
96  "$EMBEDMD" -d "$f"
97  errcount=$((errcount + $?))
98  check_todo "$f"
99  errcount=$((errcount + $?))
100  mdl "$f"
101  errcount=$((errcount + $?))
102done
103
104if [ $errcount -gt 0 ]; then
105  echo "$errcount errors detected"
106  exit 1
107fi
108