#!/bin/bash
#/**
# * Licensed to the Apache Software Foundation (ASF) under one
# * or more contributor license agreements.  See the NOTICE file
# * distributed with this work for additional information
# * regarding copyright ownership.  The ASF licenses this file
# * to you 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.
# */

# Make a patch for the current branch based on its tracking branch

# Process args
while getopts "ahd:b:" opt; do
    case "$opt" in
        a)  addendum='-addendum'
            ;;
        d)
            patch_dir=$OPTARG
            ;;
        b)
            tracking_branch=$OPTARG
            ;;
        *)
            echo -e "Usage: $0 [-h] [-a] [-d] <directory> \n\
        Must be run from within the git branch to make the patch against.\n\
        -h - display these instructions.\n\
        -a - Add an 'addendum' prefix to the patch name.\n\
        -b - Specify the base branch to diff from. (defaults to the tracking branch or origin master)\n\
        -d - specify a patch directory (defaults to ~/patches/)"
            exit 0
            ;;
    esac
done

# Find what branch we are on
branch=$(git branch |grep '*' |awk '{print $2}')
if [ ! "$branch" ]; then
    echo "Can't determine the git branch. Exiting." >&2
    exit 1
fi

# Exit if git status is dirty
git_dirty=$(git diff --shortstat 2> /dev/null | wc -l|awk {'print $1'})
echo "git_dirty is $git_dirty"
if [ "$git_dirty" -ne 0 ]; then
    echo "Git status is dirty. Commit locally first.">&2
    exit 1
fi

# Determine the tracking branch if needed.
# If it was passed in from the command line
# with -b then use dthat no matter what.
if [ ! "$tracking_branch" ]; then
  git log -n 1 origin/$branch > /dev/null 2>&1
  status=$?
  if [ "$status" -eq 128 ]; then
      # Status 128 means there is no remote branch
      tracking_branch='origin/master'
  elif [ "$status" -eq 0 ]; then
      # Status 0 means there is a remote branch
      tracking_branch="origin/$branch"
  else
      echo "Unknown error: $?" >&2
      exit 1
  fi
fi


# Deal with invalid or missing $patch_dir
if [ ! "$patch_dir" ]; then
    echo -e "Patch directory not specified. Falling back to ~/patches/."
    patch_dir=~/patches
fi

if [ ! -d "$patch_dir" ]; then
    echo "$patch_dir does not exist. Creating it."
    mkdir $patch_dir
fi

# Determine what to call the patch
# Check to see if any patch exists that includes the branch name
status=$(ls $patch_dir/*$branch* 2>/dev/null|grep -v addendum|wc -l|awk {'print $1'})
if [ "$status" -eq 0 ]; then
    # This is the first patch we are making for this release
    prefix=''
elif  [ "$status" -ge 1 ]; then
    # At least one patch already exists -- add a version prefix
    for i in {1..99}; do
        # Check to see the maximum version of patch that exists
        if [ ! -f "$patch_dir/$branch.v$i.patch" ]; then
            version=$i
            if [ -n "$addendum" ]; then
                # Don't increment the patch # if it is an addendum
                echo "Creating an addendum"
                if [ "$version" -eq 1 ]; then
                    # We are creating an addendum to the first version of the patch
                    prefix=''
                else
                    # We are making an addendum to a different version of the patch
                    let version=$version-1
                    prefix=".v$version"
                fi
            else
                prefix=".v$version"
            fi
            break
        fi
    done
fi
# If this is against a tracking branch other than master
# include it in the patch name
tracking_suffix=""
if [[ $tracking_branch != "origin/master" \
    &&  $tracking_branch != "master" ]]; then
    tracking_suffix=".${tracking_branch#origin/}"
fi

patch_name="$branch$prefix$addendum$tracking_suffix.patch"

# Do we need to make a diff?
git diff --quiet $tracking_branch
status=$?
if [ "$status" -eq 0 ]; then
    echo "There is no difference between $branch and $tracking_branch."
    echo "No patch created."
    exit 0
fi

# Check whether we need to squash or not
local_commits=$(git log $tracking_branch..$branch|grep 'Author:'|wc -l|awk {'print $1'})
if [ "$local_commits" -gt 1 ]; then
    read -p "$local_commits commits exist only in your local branch. Interactive rebase?" yn
    case $yn in
        [Yy]* )
            git rebase -i $tracking_branch
                ;;
        [Nn]* )
          echo "Creating $patch_dir/$patch_name using git diff."
          git diff $tracking_branch > $patch_dir/$patch_name
          exit 0
        ;;
    esac
fi

echo "Creating patch $patch_dir/$patch_name using git format-patch"
git format-patch --stdout $tracking_branch > $patch_dir/$patch_name
