#!/bin/bash --norc
set -euo pipefail

DEFAULT_REFSPEC=origin/master

function usage() {
  cat <<EOF
Usage: $0 [ -h | --help | [<refspec>] ]
Options:
  -h, --help: Print help and usage information to stdout and exit.
Arguments:
  <refspec>:  A "commit-ish" passed to \`git rev-list\` to enumerate commits. If
              omitted, defaults to \`$DEFAULT_REFSPEC\`.
EOF
}

function help() {
  cat <<EOF
$0

Emit Identifiers for all historical ZRNs found in the Driving git repository
relative to an optional refspec. See \`//mapping/zrn/proto:identifier.proto\`
for the expected format.

Note: This tool uses your local git repository to search for changed files, so
be sure you are to date with your remotes before running (\`git fetch ...\`).
EOF
}

# Search for help flags before parsing input.
for arg in "$@"; do
  if [ "$arg" = "-h" ] || [ "$arg" = "--help" ]; then
    help
    echo
    usage
    exit
  fi
done

# Take and shift the refspec if specified. Use the default if it is absent.
if [ $# -gt 0 ]; then
  refspec="$1"
  shift
else
  refspec="$DEFAULT_REFSPEC"
fi

# Verify no other arguments were passed.
if [ $# -ne 0 ]; then
  usage >&2
  exit 1
fi

# Ensure we are executing within the workspace.
builtin cd "$(dirname "${BASH_SOURCE[0]}")"
builtin cd "$(git rev-parse --show-toplevel)"

function zrn_commits() {
  local refspec="$1"

  # Find all commits that touch files with one of the ZRN file extensions.
  # This includes added files, deleted files, and modified files.
  git rev-list --all -- '*.zrn' '*.zrn.pbtxt'
}

function zrn_names() {
  local commit="$1"

  # Recursive diff from the first-parent to the commit. This shows the diff
  # introduced by merge commits as well as regular commits.
  #
  # Filter to files with one of the ZRN file extensions.
  #
  # Strip off the file extension to produce the ZRN "name" relative to the top
  # of the workspace.
  #
  # Remove duplcate names.
  git diff-tree --name-only -r "$commit^1" "$commit" \
    | grep --extended-regexp --regexp='\.zrn$' --regexp='\.zrn\.pbtxt$' \
    | sed --expression 's#\.zrn$##;s#\.zrn.pbtxt$##' \
    | sort --unique
}

function zrn_commit_and_names() {
  local commit="$1"

  # Find all the ZRN names touched by the given commit.
  # Emit one line for every commit+name pair.
  zrn_names "$commit" \
    | while read file; do echo $commit $file; done
}

function make_named_revision_pbtxt() {
  local commit="$1"
  local name="$2"
  local repo=DRIVING_RAW

  # If a ZRN name starts with 'vehicle/zrn/' then we can "more correctly"
  # describe it with the 'DRIVING' repository type, which is relative to
  # 'vehicle/zrn/'.
  if [[ "$name" = "vehicle/zrn/"* ]]; then
    name="${name#"vehicle/zrn/"}"
    repo=DRIVING
  fi
  echo -n named_revision {name: \"$name\" revision {repository: $repo git_sha: \"$commit\"}} \
  | base64 -w 512
}

zrn_commits "$refspec" \
  | while read commit; do zrn_commit_and_names "$commit"; done \
  | while read line; do make_named_revision_pbtxt $line; done
