#!/bin/bash

####################################################################################################################################
# Usage examples:
# first you need to source this script, so that you can use it's methods:
# $ source releaseSilecs.sh
#
### release ####
# release a new version v1.0.0 using the default pathes. A git branch and tag will be created and pushed
# $ release_global 1.0.0 /home/bel/schwinn/lnx/git
#
# A local release will not create any branches and/or tags
# $ release_local 1.0.0 /home/bel/schwinn/lnx/git
# 
### patch ###
# patch two packages of an existing version 1.2.3, resulting of a installation of 1.2.4 using the default pathes. A git branch and tag will be created and pushed
# $ patch_global silecs-codegen 1.2.3 /home/bel/schwinn/lnx/git
# $ patch_global silecs-model 1.2.3 /home/bel/schwinn/lnx/git
#
# A local patch will not create any branches and/or tags
# $ patch_local silecs-model 1.2.3 /home/bel/schwinn/lnx/git
#

### release plugin ###
# release a new version of the silecs-eclipse plugin
# $ plugin_release /home/bel/schwinn/lnx/git-silecs-plugin /common/usr/cscofe/silecs
#
####################################################################################################################################


# List of silecs packages which can be released or patched
PACKAGES="silecs-codegen silecs-model silecs-communication-cpp silecs-diagnostic-cpp silecs-cli-client snap7"

# branch to release
RELEASE_BRANCH=gsi

# name of git remote repo
UPSTREAM=origin

# release locations
#GLOBAL_RELEASE_DIR=${HOME}/tmp/silecs-global
GLOBAL_RELEASE_DIR=/common/usr/cscofe/silecs
LOCAL_RELEASE_DIR=${HOME}/tmp/silecs



validateBranch()
{
    REQUIRED_BRANCH=$1
    CURRENT_BRANCH=`git symbolic-ref --short -q HEAD`
    if [ "$CURRENT_BRANCH" != "$REQUIRED_BRANCH" ]; then
        echo "Error: Release only can be done if branch '${REQUIRED_BRANCH}' is checked out."
        return 1
    fi
    
    git fetch
    REMOTE_SHA=`git rev-parse origin/${REQUIRED_BRANCH}`
    LOCAL_SHA=`git rev-parse HEAD`
    
    if [[ -z $(git status -s) ]]
    then
      echo "workspace is in sync with local repo"
    else
      echo "workspace is dirty, please commit changes before running this"
      return 1
    fi
    
    

    if [ $REMOTE_SHA != $LOCAL_SHA ]; then
        echo "Error: local repo differs from remote repo ! Please first push/pull to get a consistant state!"
        return 1
    fi
}

createAndPushBranch()
{
    BRANCH_NAME=$1
    
    git rev-parse --verify ${BRANCH_NAME}
    if [ "$?" = "0" ]; then
        echo "Error: The branch '${BRANCH_NAME}' already exists locally."
        echo "Creating branch cancelled."
        return 1
    fi
    
    # check if already exists
    EXISTS=`git ls-remote --heads ${UPSTREAM} ${BRANCH_NAME} | wc -l`
    if [ "$EXISTS" != "0" ]; then
        echo "Error: The branch '${BRANCH_NAME}' already exists on ${UPSTREAM}."
        echo "Creating branch cancelled."
        return 1
    fi
    
    # create new and push
    git checkout -b ${BRANCH_NAME}
    git push ${UPSTREAM} ${BRANCH_NAME}
}

createAndPushTag()
{
    TAG_NAME=$1
    if [ $(git tag -l "${TAG_NAME}") ]; then
        echo "Error: The tag '${TAG_NAME}' already exists locally."
        echo "Creating tag cancelled."
        return 1
    fi
    
    EXISTS=`git ls-remote ${UPSTREAM} refs/tags/${TAG_NAME} | wc -l`
    echo $EXISTS
    if [ "$EXISTS" != "0" ]; then
        echo "Error: The tag '${TAG_NAME}' already exists on ${UPSTREAM}."
        echo "Creating branch cancelled."
        return 1
    fi
    
    # create new and push
    git tag ${TAG_NAME}
    git push ${UPSTREAM} ${TAG_NAME}
}

# Check that folder exists, print proper error if not
checkFolderExists()
{
    FOLDER=$1
    if [ ! -d ${FOLDER} ]; then
        echo "Error: The folder '${FOLDER}' is needed in order to finish the installation."
        echo "Installation cancelled."
        return 1
    fi
}

# releases all silecs-packages to release-dir

release_local()
{
    release $1 $2 ${LOCAL_RELEASE_DIR}
}

release_global()
{
    release $1 $2 ${GLOBAL_RELEASE_DIR}
}

release()
{
    VERSION=$1
    WORKSPACE=$2
    RELEASE_DIR_BASE=$3
    
    checkFolderExists ${WORKSPACE}
    
    if [ $RELEASE_DIR_BASE = $GLOBAL_RELEASE_DIR ]; then
       validateBranch ${RELEASE_BRANCH}
       if [ "$?" -eq "1" ]; then
          echo "Installation cancelled."
          return 1
       fi
    fi
    
    for PACKAGE in $PACKAGES; do
        INSTALL_DIR=${RELEASE_DIR_BASE}/${PACKAGE}/${VERSION}
        if [ -d ${INSTALL_DIR} ]; then 
            echo "Error: Silecs version ${VERSION} is already installed in ${INSTALL_DIR}. Exiting now."
            return 1
        else
            checkFolderExists ${WORKSPACE}/${PACKAGE}
            echo "installing ${INSTALL_DIR} from ${WORKSPACE}/${PACKAGE}"
            ${WORKSPACE}/${PACKAGE}/install.sh ${INSTALL_DIR}
        fi
    done
    
    if [ $RELEASE_DIR_BASE = $GLOBAL_RELEASE_DIR ]; then
       RELEASE_BRANCH_VERSION=`replace_tiny_version_with_x ${VERSION}`
       RELEASE_BRANCH_NAME="gsi-$RELEASE_BRANCH_VERSION"
       createAndPushBranch ${RELEASE_BRANCH_NAME}
       if [ "$?" -eq "1" ]; then
          echo "Creation of branch cancelled."
          return 1
       fi
       RELEASE_TAG="gsi-$VERSION"
       createAndPushTag ${RELEASE_TAG}
    fi
    return 0
}

patch_local()
{
    patch $1 $2 $3 ${LOCAL_RELEASE_DIR}
}

patch_global()
{
    patch $1 $2 $3 ${GLOBAL_RELEASE_DIR}
}

plugin_release()
{
    (
        set -e
        WORKSPACE=$1
        RELEASE_DIR_BASE=$2

        PACKAGE=silecs-eclipse-plugin-update-site
        INSTALL_DIR=${RELEASE_DIR_BASE}/${PACKAGE}
        checkFolderExists ${WORKSPACE}/${PACKAGE}
        echo "installing ${INSTALL_DIR} from ${WORKSPACE}/${PACKAGE}"
        ${WORKSPACE}/${PACKAGE}/install.sh ${INSTALL_DIR}
        return 0
    )
}

increment_version ()
{
  declare -a part=( ${1//\./ } )
  declare    new
  declare -i carry=1

  for (( CNTR=${#part[@]}-1; CNTR>=0; CNTR-=1 )); do
    len=${#part[CNTR]}
    new=$((part[CNTR]+carry))
    [ ${#new} -gt $len ] && carry=1 || carry=0
    [ $CNTR -gt 0 ] && part[CNTR]=${new: -len} || part[CNTR]=${new}
  done
  new="${part[*]}"
  echo -e "${new// /.}"
}

replace_tiny_version_with_x ()
{
    echo -e "${1%.*}.x"
} 

patch_local()
{
    patch $1 $2 $3 ${LOCAL_RELEASE_DIR}
}

patch_global()
{
    patch $1 $2 $3 ${GLOBAL_RELEASE_DIR}
}

# releases a specific package to release-dir. For all other packages symlinks to the base-version are generated
patch()
{
    PACKAGE_TO_PATCH=$1
    BASE_VERSION=$2
    WORKSPACE=$3
    RELEASE_DIR_BASE=$4
    checkFolderExists ${WORKSPACE}
    
    NEW_VERSION=`increment_version $BASE_VERSION`
    echo "New version will be: '$NEW_VERSION'"
    
    BASE_BRANCH_VERSION=`replace_tiny_version_with_x $BASE_VERSION`
    BASE_BRANCH="gsi-$BASE_BRANCH_VERSION"
       
    if [ $RELEASE_DIR_BASE = $GLOBAL_RELEASE_DIR ]; then
       validateBranch ${BASE_BRANCH}
       if [ "$?" -eq "1" ]; then
          echo "Installation cancelled."
          return 1
       fi
    fi
    
    for PACKAGE in $PACKAGES; do
        INSTALL_DIR=${RELEASE_DIR_BASE}/${PACKAGE}/${NEW_VERSION}
        BASE_DIR=${RELEASE_DIR_BASE}/${PACKAGE}/${BASE_VERSION}
        checkFolderExists ${BASE_DIR}
        checkFolderExists ${INSTALL_DIR}
        if [ "$PACKAGE" == "$PACKAGE_TO_PATCH" ]; then
            if [ -d ${INSTALL_DIR} ]; then
               if [ -L ${INSTALL_DIR} ]; then
                  checkFolderExists ${WORKSPACE}/${PACKAGE}
                  # Replace Sym-Link with patch-version ... needed if more than one package is patched for the same version
                  unlink ${INSTALL_DIR}
                  checkFolderExists ${WORKSPACE}/${PACKAGE}
                  ${WORKSPACE}/${PACKAGE}/install.sh ${INSTALL_DIR}
               else
                  echo "Error: Silecs version ${NEW_VERSION} of package ${PACKAGE} is already installed in ${INSTALL_DIR}. Exiting now."
                  return 1
               fi
            else
               checkFolderExists ${WORKSPACE}/${PACKAGE}
               echo "installing ${INSTALL_DIR} from ${WORKSPACE}/${PACKAGE}"
               ${WORKSPACE}/${PACKAGE}/install.sh ${INSTALL_DIR}
            fi
        else
           if [ ! -d ${INSTALL_DIR} ]; then
                # no patched version for this package available --> link to base-version
                echo "Symbolic link to base version '${BASE_VERSION}' created for package '${PACKAGE}' of version '${NEW_VERSION}'"
                ln -s ${BASE_VERSION} ${INSTALL_DIR}
            fi
        fi
    done
    
    echo "All packages patched successfully"
     
    if [ $RELEASE_DIR_BASE = $GLOBAL_RELEASE_DIR ]; then
       echo "Attempt to create and push git tag"
       TAG_NAME="gsi-$NEW_VERSION"
       createAndPushTag ${TAG_NAME}
    fi
    
    return 0
}
