#!/usr/bin/env bash

# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -e 

help()
{
  cat <<EOF
lint - go linter supporting message suppression

synopsis: line [-csv] [-s] <package folder>  ...

options:
  -s standard message suppression. Dedicated messages
     are completely suppressed (like the 'this' error)
  -c assume undocumented sources, errors because of
     undocumented public language elements are suppressed
  -a suppress messages concerning lower case of dedicated
     abbreviations (for example Id)
  -v verbose mode, show analyzed packages

By adding the line
// golint: ignore
into the source file just before the line with a lint mesaage
this message will be suppressed. Alternatively add '// golint: ignore' at the end of the line
EOF
}

ignore=(
)

standard=(
   "receiver name should be a reflection of its identity; don't use generic names such as \"this\" or \"self\""
   "should not use basic type string as key in context.WithValue"
   "context.Context should be the first parameter of a function"
   "if block ends with a return statement, so drop this else and outdent its block"
   "should not use dot imports"
   "don't use ALL_CAPS in Go names; use CamelCase"
   "don't use underscores in Go names"
   "by other packages, and that stutters; consider calling this"
)

commented=(
   ": exported "
)

abbrev=(
   "Id should be .*ID"
)

join_by()
{
   local IFS="$1"
   shift
   echo "$*"
}

line()
{
  if [ $1 -eq 0 ]; then
    sed "1q;d" "$2"
  else
    sed "${1}q;d" "$2"
  fi
}

COMM='^comment on exported function SyncPointWait should be of the form.*$'
TAG='^// golint: ignore.*$'
TAG2='// golint: ignore$'

handle() {
   #grep -vE "$(join_by "|" "${ignore[@]}")" | sed "s/\(\(.*\.go\):\([^:]*\).*\)/\3 \2 \1/"
   grep -vE "$(join_by "|" "${ignore[@]}")" | 
   sed "s/\(.*\.go\):\([0-9]*\):\([0-9]*\): \(.*\)/\2 \3 \1 \4/" | {
   err=
   while read l a f m; do
      if [[ "$m" =~ $COMM ]]; then
        b="$(line $l "$f")"
        b2=''
      else
        b="$(line $(( l - 1 )) "$f")"
        b2="$(line $l "$f")"
      fi
      if [[ ! "$b" =~ $TAG  && ! "$b2" =~ $TAG2 ]]; then
         echo "$f:$l:$a: $m"
         err=1
      fi
   done
   return $err
   }
}


lint()
{
  for package; do
    if [ -n "$verbose" ]; then
      echo "$package:"
    fi
    if ! { golint $(find $package -maxdepth 1 -name "*.go" | grep -vE 'zz_generated|_test.go') | handle; }; then
      err=X
    fi
  done
  if [ -n "$err" ]; then
    echo "found lint errors - good bye"
    exit 1
  fi
}

while [ $# -gt 0 ]; do
  case "$1" in 
    --help)
        help
        exit 0;;
    -*) for o in $(fold -w1 <<<"${1:1}"); do
          case "$o" in 
            s) ignore=( "${ignore[@]}"  "${standard[@]}" );;
            c) ignore=( "${ignore[@]}"  "${commented[@]}" );;
            a) ignore=( "${ignore[@]}"  "${abbrev[@]}" );;
            v) verbose=X;;
            *) echo "invalid option $o" >&2
               exit 1;;
          esac
        done
        shift;;
    *)  break;;
  esac
done

lint "$@"
