#!/bin/bash
set -e

#   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.

################################################ ABOUT JDIFF #######################################################
#
#   What is JDiff? JDiff is a tool for comparing the public APIs of two separate Java codebases. Like diff, it will
#   give additions, changes, and removals. It will output an HTML report with the information.
#   To learn more, visit http://javadiff.sourceforge.net/.
#   JDiff is licensed under LGPL.

############################################# QUICK-START EXAMPLE ##################################################
#
#   Suppose we wanted to see the API diffs between HBase 0.92 and HBase 0.94. We could use this tool like so:
#   > ./jdiffHBasePublicAPI.sh https://github.com/apache/hbase.git 0.92 https://github.com/apache/hbase.git 0.94
#
#   This would generate a report in the local folder /tmp/jdiff/hbase_jdiff_report-p-0.92-c-0.94/
#   To view the report, simply examine /tmp/jdiff/hbase_jdiff_report-p-0.92-c-0.94/changes.html in your choice of
#   browser.
#
#   Note that this works because 0.92 and 0.94 have the source directory structure that is specified in the
#   hbase_jdiff_template.xml file. To compare 0.95 to 0.96, which have the post-singularity structure,  two other
#   template files (included) are used. The formats are autoated and is all taken care of automatically by the script.
#
#   On a local machine, JDiff reports have taken ~20-30 minutes to run. On Jenkins, it has taken over 35 minutes
#   in some cases. Your mileage may vary. Trunk and 0.95 take more time than 0.92 and 0.94.
#
#
############################################ SPECIFYING A LOCAL REPO ###############################################
#
#   The JDiff tool also works with local code. Instead of specifying a repo and a branch, you can specifying the
#   absolute path of the ./hbase folder and a name for code (e.g. experimental_94).
#
#   A local repo can be specified for none, one, or both of the sources.
#
############################################### EXAMPLE USE CASES ##################################################
#
#   Example 1: Generate a report to check if potential change doesn't break API compatibility with Apache HBase 0.94
#
#   In this case, you could compare the version you are using against a repo branch where your changes are.
#   >  ./jdiffHBasePublicAPI.sh https://github.com/apache/hbase.git 0.94 https://github.com/MY_REPO/hbase.git 0.94
#
#   Example 2: Generate a report to check if two branches of the same repo have any public API incompatibilities
#   >  ./jdiffHBasePublicAPI.sh https://github.com/MY_REPO/hbase.git $BRANCH_1  \
#   >   https://github.com/MY_REPO/hbase.git $BRANCH_2
#
#   Example 3: Have Example 1 done in a special directory in the user's home folder
#
#   >  export JDIFF_WORKING_DIRECTORY=~/jdiff_reports
#   >  ./jdiffHBasePublicAPI.sh https://github.com/apache/hbase.git 0.94 https://github.com/MY_REPO/hbase.git 0.94
#
#   Example 4: Check the API diff of a local change against an existing repo branch.
#   >  ./jdiffHBasePublicAPI.sh https://github.com/apache/hbase.git 0.95 /home/aleks/exp_hbase/hbase experiment_95
#
#   Example 5: Compare two local repos for public API changes
#   >  ./jdiffHBasePublicAPI.sh /home/aleks/stable_hbase/hbase stable_95 /home/aleks/exp_hbase/hbase experiment_95
#
#
################################################## NOTE ON USAGE ###################################################
#
#   1. When using this tool, please specify the initial version first and the current version second. The semantics
#      do not make sense otherwise. For example: jdiff 94 95 is good. jdiff 95 94 is bad
#
############################################# READING A JDIFF REPORT ###############################################
#
#   The purpose of the JDiff report is show things that have changed between two versions of the public API. A user
#   would use this report to determine if committing a change would cause existing API clients to break. To do so,
#   there are specific things that one should look for in the report.
#
#   1. Identify the classes that constitute the public API. An example in 0.94 might be all classes in
#      org.apache.hadoop.hbase.client.*
#   2. After identifying those classes, go through each one and look for offending changes.
#      Those may include, but are not limited to:
#      1. Removed methods
#      2. Changed methods (including changes in return type and exception types)
#      3. Methods added to interfaces
#      4. Changed class inheritence information (may in innocuous but definitely worth validating)
#      5. Removed or renamed public static member variables and constants
#      6. Removed or renamed packages
#      7. Class moved to a different package

########################################### SETTING THE JDIFF WORKING DIRECTORY ####################################
#
#   By default, the working environment of jdiff is /tmp/jdiff. However, sometimes it is nice to have it place reports
#   and temp files elsewhere. In that case, please export JDIFF_WORKING_DIRECTORY into the bash environment and this
#   script will pick that up and use it.
#

scriptDirectory=$(dirname ${BASH_SOURCE[0]})
x=`echo $scriptDirectory | sed "s{\.{{g"`
DEV_SUPPORT_HOME="`pwd`$x"
. $scriptDirectory/jdiffHBasePublicAPI_common.sh

EXPECTED_ARGS=4

if [[ "$#" -ne "$EXPECTED_ARGS" ]]; then
  echo "This tool expects $EXPECTED_ARGS arguments, but received $#. Please check your command and try again.";
  echo "Usage: $0 <repoUrl or local source directory 1> <branch or source name 1> <repoUrl or local source directory 2> <branch or source name 2>"
  exit 1;
fi

echo "JDiff evaluation beginning:";
isGitRepo $1
FIRST_SOURCE_TYPE=$INPUT_FORMAT;
isGitRepo $3
SECOND_SOURCE_TYPE=$INPUT_FORMAT;

PREVIOUS_BRANCH=$2  ## We will still call it a branch even if it's not from a git repo.
CURRENT_BRANCH=$4

echo "We are going to compare source 1 which is a $FIRST_SOURCE_TYPE and source 2, which is a $SECOND_SOURCE_TYPE"


# Check that if either source is from a git repo, that the name is reasonable.
if [[ "$FIRST_SOURCE_TYPE" = "git_repo" ]]; then

  git check-ref-format --branch $2
fi

if [[ "$SECOND_SOURCE_TYPE" = "git_repo" ]]; then

  git check-ref-format --branch $4
fi

#If the JDIFF_WORKING_DIRECTORY is set, then we will output the report there. Otherwise, to the default location
if [[ "$JDIFF_WORKING_DIRECTORY" = "" ]]; then

  JDIFF_WORKING_DIRECTORY=/tmp/jdiff
  echo "JDIFF_WORKING_DIRECTORY not set. That's not an issue. We will default it to $JDIFF_WORKING_DIRECTORY."
else
  echo "JDIFF_WORKING_DIRECTORY set to $JDIFF_WORKING_DIRECTORY";
fi
mkdir -p $JDIFF_WORKING_DIRECTORY

# We will need this to reference the template we want to use
cd $JDIFF_WORKING_DIRECTORY
scenario_template_name=hbase_jdiff_p-$PREVIOUS_BRANCH-c-$CURRENT_BRANCH.xml


# Pull down JDiff tool and unpack it
if [ ! -d jdiff-1.1.1-with-incompatible-option ]; then
  curl -O http://cloud.github.com/downloads/tomwhite/jdiff/jdiff-1.1.1-with-incompatible-option.zip
  unzip jdiff-1.1.1-with-incompatible-option.zip
fi

JDIFF_HOME=`pwd`/jdiff-1.1.1-with-incompatible-option
cd $JDIFF_WORKING_DIRECTORY

# Pull down sources if necessary. Note that references to previous change are prefaced with p- in order to avoid collission of branch names
if [[ "$FIRST_SOURCE_TYPE" = "git_repo" ]]; then

  PREVIOUS_REPO=$1
  rm -rf p-$PREVIOUS_BRANCH
  mkdir -p p-$PREVIOUS_BRANCH
  cd p-$PREVIOUS_BRANCH
  git clone --depth 1 $PREVIOUS_REPO && cd hbase && git checkout origin/$PREVIOUS_BRANCH
  cd $JDIFF_WORKING_DIRECTORY
  HBASE_1_HOME=`pwd`/p-$PREVIOUS_BRANCH/hbase
else
  HBASE_1_HOME=$1
fi

echo "HBASE_1_HOME set to $HBASE_1_HOME"
echo "In HBASE_1_HOME, we have"
ls -la $HBASE_1_HOME

if [[ "$SECOND_SOURCE_TYPE" = "git_repo" ]]; then
  CURRENT_REPO=$3
  rm -rf $JDIFF_WORKING_DIRECTORY/c-$CURRENT_BRANCH
  mkdir -p $JDIFF_WORKING_DIRECTORY/c-$CURRENT_BRANCH
  cd $JDIFF_WORKING_DIRECTORY/c-$CURRENT_BRANCH
  git clone --depth 1 $CURRENT_REPO && cd hbase && git checkout origin/$CURRENT_BRANCH
  cd $JDIFF_WORKING_DIRECTORY
  HBASE_2_HOME=`pwd`/c-$CURRENT_BRANCH/hbase
else
  HBASE_2_HOME=$3
fi

echo "HBASE_2_HOME set to $HBASE_2_HOME"
echo "In HBASE_2_HOME, we have"
ls -la $HBASE_2_HOME

# Next step is to pull down the proper template based on the directory structure
isNewFormat $HBASE_1_HOME
export P_FORMAT=$BRANCH_FORMAT

isNewFormat $HBASE_2_HOME
export C_FORMAT=$BRANCH_FORMAT

if  [[ "$C_FORMAT" = "new" ]]; then

  if [[ "$P_FORMAT" = "new" ]]; then
    templateFile=$DEV_SUPPORT_HOME/hbase_jdiff_afterSingularityTemplate.xml
    echo "Previous format is of the new style. We'll be using template $templateFile";
  else
    templateFile=$DEV_SUPPORT_HOME/hbase_jdiff_acrossSingularityTemplate.xml
    echo "Previous format is of the old style. We'll be using template $templateFile";
  fi

else

  if [[ "P_FORMAT" != "old" ]]; then
    echo "When using this tool, please specify the initial version first and the current version second. They should be in ascending chronological order.
          The semantics do not make sense otherwise. For example: jdiff 94 95 is good. jdiff 95 94 is bad."
    echo "Exiting the script."
    exit 5;
  fi
  templateFile=$DEV_SUPPORT_HOME/hbase_jdiff_template.xml
  echo "Both formats are using the 94 and earlier style directory format. We'll be using template $templateFile"
fi

cp $templateFile $JDIFF_WORKING_DIRECTORY/$scenario_template_name

### Configure the jdiff script

### Note that PREVIOUS_BRANCH and CURRENT_BRANCH will be the absolute locations of the source.
echo "Configuring the jdiff script"
sed -i "s]hbase_jdiff_report]hbase_jdiff_report-p-$PREVIOUS_BRANCH-c-$CURRENT_BRANCH]g" $JDIFF_WORKING_DIRECTORY/$scenario_template_name
sed -i "s]JDIFF_HOME_NAME]$JDIFF_HOME]g" $JDIFF_WORKING_DIRECTORY/$scenario_template_name
sed -i "s]OLD_BRANCH_NAME]$HBASE_1_HOME]g" $JDIFF_WORKING_DIRECTORY/$scenario_template_name
sed -i "s]NEW_BRANCH_NAME]$HBASE_2_HOME]g" $JDIFF_WORKING_DIRECTORY/$scenario_template_name

sed -i "s]V1]$PREVIOUS_BRANCH]g" $JDIFF_WORKING_DIRECTORY/$scenario_template_name
sed -i "s]V2]$CURRENT_BRANCH]g" $JDIFF_WORKING_DIRECTORY/$scenario_template_name

sed -i "s]JDIFF_FOLDER]$JDIFF_WORKING_DIRECTORY]g" $JDIFF_WORKING_DIRECTORY/$scenario_template_name

echo "Running jdiff";
ls -la $JDIFF_WORKING_DIRECTORY;
ant -f $JDIFF_WORKING_DIRECTORY/$scenario_template_name;

echo "jdiff operation complete. Report placed into $JDIFF_WORKING_DIRECTORY/hbase_jdiff_report-p-$PREVIOUS_BRANCH-c-$CURRENT_BRANCH/changes.html";

