#!/usr/bin/env bash
#
# Magento Continuous Integration Tools
#
# NOTICE OF LICENSE
#
# This source file is subject to the Open Software License (OSL 3.0)
# that is bundled with this package in the file LICENSE.txt.
# It is also available through the world-wide-web at this URL:
# http://opensource.org/licenses/osl-3.0.php
#
# @category   EcomDev
# @package    EcomDev/MageCI
# @copyright  Copyright (c) 2013 EcomDev BV (http://www.ecomdev.org)
# @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
# @author     Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>


script_bin=$(realpath $0 || readlink -f $0)
script=$(basename $script_bin)
script_dir=$(dirname $script_bin)
action=$1
shift;


MAGECIF=(
   $(tput sgr0) # Reset char
   $(tput setaf 2) # Success Message
   $(tput setaf 3) # Info Message
   $(tput setaf 5) # Error Message
   $(tput bold) # Important text
)
print_usage ()
{
echo "
Usage:
${MAGECIF[4]}$ mage-ci install <magento_directory> <version> <db_name> <OPTIONS> ${MAGECIF[0]}
    Installs a Magento version to a specified destination
      -c                  Create databases flag
      -t                  Create test database flag (only in combination with -c option)
      -d  <download_dir>  Directory where all downloads are stored
      -u  <db_user>       DB Username
      -p  <db_pass>       DB Password
      -b  <base_url>      If you'd like to have custom base url, just specify in this option
      -r  <sql_base_url>  SQL dumps repository url for a particular Magento version (<sql_base_url>/<version>.sql.gz)
      -f  <sql_dump_file> SQL dump file, if you'd like to preinstall some data and specfied -c option

${MAGECIF[4]}$ mage-ci install-module <magento_directory> <module_dir_or_vcs_url>${MAGECIF[0]}
    Installs a Magento module with modman definition

${MAGECIF[4]}$ mage-ci update-modules <magento_directory>${MAGECIF[0]}
    Updates all installed modman modules at specified Magento instance

${MAGECIF[4]}$ mage-ci uninstall <magento_directory> [<db_name>] <OPTIONS>${MAGECIF[0]}
    Performs uninstall of Magento instance
      -u  <db_user>       DB Username
      -p  <db_pass>       DB Password

${MAGECIF[4]}$ mage-ci uninstall-module <magento_directory> <module_dir_or_vcs_url>${MAGECIF[0]}
    Performs uninstall of Magento module from instance

${MAGECIF[4]}$ mage-ci install-multiple <directory> <prefix> <version1> ... <versionN> <OPTIONS>${MAGECIF[0]}
    Installs multiple version of magento at <directory> in subdirectories which name is a combined value of <prefix>-<version> 
      -d  <download_dir>  Directory where all downloads are stored
      -u  <db_user>       DB Username
      -p  <db_pass>       DB Password
      -t                  Create test db as well
      -r  <sql_base_url>  SQL dumps repository url for a particular Magento version (<sql_base_url>/<version>.sql.gz)

${MAGECIF[4]}$ mage-ci db-dump <directory> <prefix> <version1> ... <versionN> <OPTIONS>${MAGECIF[0]}
    Creates Magento database dump file at <directory> directory with name <file_prefix><version>.sql.gz, the data dunped database is <prefix>_<version>
      -u  <db_user>       DB Username
      -p  <db_pass>       DB Password
      -s  <file_prefix>   sql file prefix

${MAGECIF[4]}$ mage-ci phpunit <directory> <OPTIONS> ${MAGECIF[0]}
    Runs unit tests for all phpunit.xml or phpunit.dist.xml files in <directory> or its subdirectories. <OPTIONS> will be passed directly to phpunit.

${MAGECIF[4]}$ mage-ci shell <magento_directory> <script_name> <OPTIONS> ${MAGECIF[0]}
    Runs magento shell script with name <script_name> at <magento_directory>/shell directory with specified options.
"
}

show_usage () 
{
   print_usage
   exit 1;
}

run_shell ()
{
   local magento_dir=$1
   local current_dir=$(pwd)
   local script_name=$2
   shift 2;

   # Check that first parameter is directory
   if [ ! -d "$magento_dir/shell" ]
   then
      echo "${MAGECIF[3]}Magento shell directory is not found at $magento_dir/shell ${MAGECIF[0]}"
      exit 1
   fi

   cd $magento_dir/shell
   php -f $script_name -- ${@}
   check_error_exit
}

run_phpunit ()
{
   local test_dir=$1;
   local current_dir=$(pwd);
   local phpunit_bin="phpunit";

   if [ -e "$current_dir/vendor/bin/phpunit" ]
   then
      phpunit_bin="$current_dir/vendor/bin/phpunit"
   elif [ -e "$current_dir/bin/phpunit" ]
   then
      phpunit_bin="$current_dir/bin/phpunit"
   fi

   local phpunit_version=$($phpunit_bin --version)
   echo "${MAGECIF[2]}PHPUnit binary: $phpunit_bin"
   echo "Version $phpunit_version${MAGECIF[0]}"

   # Check existance of phpunit at the system
   if [ $? -ne 0 ]
   then
      echo "${MAGECIF[3]}PHPUnit is not installed on your system, please visit http://phpunit.de/ for installation"
      exit 1;
   fi

   # Check that first parameter is directory
   if [ ! -d "$test_dir" -a -d tests ]
   then 
      tests_dir="tests"
   elif [ ! -d "$test_dir" ]
   then
      echo "${MAGECIF[3]}PHPUnit tests directory doesn't exists: $test_dir${MAGECIF[0]}"
      exit 1
   else
      shift; # Correct test dir, so remove it from args list
   fi

   test_dir=$(realpath $test_dir || readlink -f $test_dir);
   cd $test_dir

   local exitCode=1

   if [ -f phpunit.xml -o -f phpunit.xml.dist ]
   then
       echo "${MAGECIF[2]}Running test in $test_dir...${MAGECIF[0]}"
      $phpunit_bin ${@}
      check_error_exit
      exitCode=0
   else
      for dir in $test_dir/*
      do
         if [  -f  "$dir/phpunit.xml" -o -f "$dir/phpunit.xml.dist"  ]
         then
            cd $dir;
            echo "${MAGECIF[2]}Running test in $dir...${MAGECIF[0]}"
            $phpunit_bin ${@}
            check_error_exit
            exitCode=0
         fi
      done
   fi

   if [ $exitCode -eq 1 ]
   then
      echo "${MAGECIF[2]}No tests were found${MAGECIF[0]}"
   else
      echo "${MAGECIF[1]}PHPUnit tests run completed${MAGECIF[0]}"
   fi

   exit $exitCode
}

dump_magento () 
{
   local dest_dir=$1; local prefix=$2; shift 2; 
   local db_name; local db_cred; local db_user="root"; local db_pass=""; 
   local version=""; local options=""; local file_prefix=""

   if [ ! -d "$dest_dir" ] 
   then 
      mkdir -p $dest_dir
   fi

   for arg
   do
     if [[ $arg =~ ^[0-9.]+$ ]]
     then
       version+=" $arg"
     else
       options+=" $arg"
     fi
   done
 
   while getopts :u:p:f: opt $options
   do
     case $opt in
       u) db_user=$OPTARG ;;
       p) db_pass=$OPTARG ;;
       f) file_prefix=$OPTARG ;;
       \?) echo "${MAGECIF[3]}Unkown option -$OPTARG${MAGECIF[0]}" >&2; print_usage; exit 1 ;;
       :) echo "${MAGECIF[3]}Option -$OPTARG requires an argument.${MAGECIF[0]}" >&2; print_usage; exit 1 ;;
     esac
   done 

   db_cred="-u ${db_user}"

   if [[ $db_pass != "" ]]
   then 
     db_cred+="-p${db_pass}"
   fi

   if [[ $prefix == "" ]] 
   then 
     echo "${MAGECIF[3]}<prefix> is required ${MAGECIF[0]}"
     print_usage; exit 1;
   fi

   for ver in $version
   do
      db_name="${prefix}_${ver//./_}"
      echo "${MAGECIF[2]}Dump magento database version $ver into $dest_dir/${file_prefix}${ver}.sql.gz file ${MAGECIF[0]}"
      mysqldump $db_cred $db_name > $dest_dir/${file_prefix}${ver}.sql
      if [ $? -ne 0 ]
      then
        echo "${MAGECIF[3]}Failed to dump $db_name... Skipping${MAGECIF[0]}"
      else
        gzip -f -9 $dest_dir/${file_prefix}${ver}.sql
        echo "${MAGECIF[1]}Dumped...${MAGECIF[0]}"
      fi
   done
}

install_multiple_magento ()
{
   local magento_dir=$1; local pass_options="-c"; local prefix=$2; shift 2
   local version=""; local options=""

   for arg
   do
     if [[ $arg =~ ^[0-9.]+$ ]]
     then
       version+=" $arg"
     else
       options+=" $arg"
     fi
   done

   while getopts :u:r:p:f:d:t opt $options
   do
     case $opt in
       u) pass_options="$pass_options -u $OPTARG" ;;
       p) pass_options="$pass_options -p $OPTARG" ;;
       r) pass_options="$pass_options -r $OPTARG" ;;
       t) pass_options="$pass_options -t"   ;;
       d) pass_options="$pass_options -d $OPTARG"  ;;
       \?) echo "${MAGECIF[3]}Unkown option -$OPTARG${MAGECIF[0]}" >&2; print_usage; exit 1 ;;
       :) echo "${MAGECIF[3]}Option -$OPTARG requires an argument.${MAGECIF[0]}" >&2; print_usage; exit 1 ;;
     esac
   done
   
   local db_name

   for ver in $version
   do 
      # Running as subprocess to not break all version installs
      db_name="${prefix}_${ver//./_}"
      echo "${MAGECIF[2]}Installing magento version $ver into $magento_dir/${prefix}-${ver} directory and $db_name mysql DB${MAGECIF[0]}"
      $script_bin install $magento_dir/${prefix}-${ver} $ver $db_name $pass_options > /dev/null 2>&1
      if [ $? -ne 0 ]
      then 
        echo "${MAGECIF[3]}Failed to install $magento_dir/$prefix-$ver... Skipping${MAGECIF[0]}"
      else
	echo "${MAGECIF[1]}Installed...${MAGECIF[0]}"
      fi
   done
}

install_magento ()
{
   local magento_dir=$1; local version=$2; local db_name=$3; shift 3
   local db_create; local db_user="root"; local db_pass=""; local sql_dump_file=""; local include_test_db
   local phpunit_local_xml; local opt; local sql_base_url; local db_cred
   local base_url="http://magento.local/"; local download_dir="$(dirname $script_dir)/.tmp";
   
   while getopts :u:r:p:f:b:d:ct opt
   do
     case $opt in
       u) db_user=$OPTARG       ;;
       p) db_pass=$OPTARG       ;;
       f) sql_dump_file=$OPTARG ;;
       c) db_create="1"         ;;
       t) include_test_db="1"   ;;
       d) download_dir=$OPTARG  ;;
       r) sql_base_url=$OPTARG  ;;
       b) base_url=$OPTARG      ;;
       \?) echo "${MAGECIF[3]}Unkown option -$OPTARG${MAGECIF[0]}" >&2; print_usage; exit 1 ;;
       :) echo "${MAGECIF[3]}Option -$OPTARG requires an argument.${MAGECIF[0]}" >&2; print_usage; exit 1 ;;
     esac
   done

   [[ $db_pass == "" ]] && db_cred="-u $db_user" || db_cred="-u $db_user -p$db_pass"

   if [[ $magento_dir == "" ]]
   then
      echo "${MAGECIF[3]}Magento directory should be specified${MAGECIF[0]}"
      print_usage;
      exit 1
   fi

   if [ ! -d "$magento_dir" ]
   then
      echo "${MAGECIF[2]}Creating Magento directory: $magento_dir ...${MAGECIF[0]}"
      mkdir -p "$magento_dir"
   fi
 
   if [[ ! $version =~ ^[0-9.]+$ ]]
   then 
      echo "${MAGECIF[3]}Version should be specified: $version${MAGECIF[0]}"
      exit 1
   fi 

   if [[ $db_name == "" ]]
   then 
      echo "${MAGECIF[3]}<db_name> is required${MAGECIF[0]}"
      exit 1
   fi

   if [ ! -d "$download_dir" ]
   then
     mkdir -p $magento_dir
     check_error_exit
   fi

   if [[ $db_create == "1" ]]
   then 
      echo "${MAGECIF[2]}Creating ${db_name} database...${MAGECIF[0]}"
      mysql $db_cred -e "DROP DATABASE IF EXISTS ${db_name};CREATE DATABASE ${db_name};"
      check_error_exit

      if [[ $include_test_db == "1" ]]
      then
        echo "${MAGECIF[2]}Create ${db_name}_test database...${MAGECIF[0]}"
        mysql $db_cred -e "DROP DATABASE IF EXISTS ${db_name}_test;CREATE DATABASE ${db_name}_test;"
        check_error_exit
      fi

      if [[ $sql_base_url =~ ^https?\:// ]]
      then
        echo "${MAGECIF[2]}Trying download SQL dump from url: $sql_base_url/$version.sql.gz"
        wget -q --no-clobber -P $download_dir $sql_base_url/$version.sql.gz
        if [ $? -eq 0 ]
        then
          echo "Dump is downloaded and will be used for installation${MAGECIF[0]}"
          sql_dump_file="$download_dir/$version.sql.gz"
        else
          echo "Dump is not available...${MAGECIF[0]}"
        fi
      fi


      if [ -f "${sql_dump_file}" ]
      then 
        if [[ $sql_dump_file =~ \.gz$ ]] 
	then 
           echo "${MAGECIF[2]}Uncompressing dump file...${MAGECIF[0]}"
           mkdir -p $download_dir/dump
           local dest_file=$(basename $sql_dump_file)
           cp $sql_dump_file $download_dir/dump/$dest_file
           gzip -f -d $download_dir/dump/$dest_file
           sql_dump_file="$download_dir/dump/${dest_file/.gz/}"
        fi
        
        echo "${MAGECIF[2]}Loading db dump into ${db_name} database...${MAGECIF[0]}"
        mysql -B $db_cred $db_name < $sql_dump_file
        check_error_exit
        if [[ $include_test_db == "1" ]]
          then
            echo "${MAGECIF[2]}Create ${db_name}_test database...${MAGECIF[0]}"
            mysql -B $db_cred ${db_name}_test < $sql_dump_file
            check_error_exit
          fi
      fi
   fi	

   uninstall_magento $magento_dir

   echo "${MAGECIF[2]}Downloading Magento from URL: http://www.magentocommerce.com/downloads/assets/$version/magento-$version.tar.gz${MAGECIF[0]}"
   wget -q --no-clobber -P $download_dir http://www.magentocommerce.com/downloads/assets/$version/magento-$version.tar.gz
   check_error_exit;
   echo "${MAGECIF[2]}Unpacking magento installment...${MAGECIF[0]}"
   tar -zxf $download_dir/magento-$version.tar.gz -C $download_dir
   mv $download_dir/magento/* $magento_dir
   mv $download_dir/magento/.ht* $magento_dir
   rm -rf $download_dir/magento
   # Special case for PHP5.4 with installation process
   echo "${MAGECIF[2]}Applying pdo_mysql check fix...${MAGECIF[0]}"
   config_file="${magento_dir}/app/code/core/Mage/Install/etc/config.xml"
   config_file_tmp="${config_file}.tmp"
   cp $config_file $config_file_tmp
   sed 's/<pdo_mysql\/>/<pdo_mysql>1<\/pdo_mysql>/' $config_file_tmp > $config_file


   echo "${MAGECIF[2]}Installing Magento...${MAGECIF[0]}"
   cd $magento_dir
   php -f install.php -- --license_agreement_accepted yes \
  	  --locale en_US --timezone "America/Los_Angeles" --default_currency USD \
          --db_host localhost --db_name "$db_name" --db_user "$db_user" --db_pass "$db_pass" \
          --url "$base_url" --use_rewrites yes \
          --use_secure no --secure_base_url "$base_url" --use_secure_admin no \
          --admin_lastname Owner --admin_firstname Store --admin_email "admin@example.com" \
          --admin_username admin --admin_password 123123test \
          --skip_url_validation yes --encryption_key "key"

   check_error_exit
   echo "${MAGECIF[1]}Installation sucesfully finished${MAGECIF[0]}"
   if [ -n $include_test_db ] 
   then 
     read -d '' phpunit_local_xml <<LOCALXML
<?xml version="1.0"?>
<config>
    <global>
        <resources>
            <default_setup>
                <connection>
                    <dbname><![CDATA[${db_name}_test]]></dbname>
                </connection>
            </default_setup>
        </resources>
    </global>
    <default>
        <web>
            <seo>
                <use_rewrites>1</use_rewrites>
            </seo>
            <secure>
                <base_url>${base_url}</base_url>
            </secure>
            <unsecure>
                <base_url>${base_url}</base_url>
            </unsecure>
            <url>
                <redirect_to_base>0</redirect_to_base>
            </url>
        </web>
    </default>
</config>
LOCALXML
     echo "${MAGECIF[2]}Adding local.xml.phpunit..."
     echo $phpunit_local_xml > "app/etc/local.xml.phpunit"
     check_error_exit
     echo "... to app/etc directory (finished)${MAGECIF[0]}"
   fi
   
   exit 0
}

install_module () {
   local magento_dir=$1
   local magento_module_source=$2
   local magento_module
   local modman="${script_dir}/modman"

   init_modman $magento_dir

   if [[ $magento_module_source =~ ^git@ ]]
   then
     magento_module=$(basename ${magento_module_source/.git//})
     check_error_exit
   elif [ -d "${magento_module_source}" ]
   then
     magento_module=$(basename ${magento_module_source})
   else
     echo "${MAGECIF[3]}Unkown source type${MAGECIF[0]}"
     print_usage;
     exit 1
   fi

   if [ ! -d ".modman/${magento_module}" ]
   then
     if [[ $magento_module_source =~ ^git@ ]]
        then
        echo "${MAGECIF[2]}Installing module from git repository: $magento_module_source${MAGECIF[0]}"
        $modman clone $magento_module_source
        check_error_exit
     elif [ -d "$magento_module_source" ]
     then
        echo "${MAGECIF[2]}Installing module from local directory: $magento_module_source${MAGECIF[0]}"
        $modman link $magento_module_source
        check_error_exit
     fi
   else
      $modman $magento_module update
      echo "${MAGECIF[2]}Updating module${MAGECIF[0]}"
   fi

   echo "${MAGECIF[1]}Module was sucessfully installed/updated${MAGECIF[0]}"

   exit 0
}

init_modman () {
   local magento_dir=$1
   local modman="${script_dir}/modman"

   if [ ! -f "$modman" ]
   then
     echo "${MAGECIF[2]}Installing modman...${MAGECIF[0]}"
     curl -s -o "$modman" https://raw.github.com/colinmollenhour/modman/master/modman
     check_error_exit
     chmod +x "$modman"
     check_error_exit
   fi

   cd $magento_dir
   check_error_exit

   if [ ! -d ".modman" ]
   then
     echo "${MAGECIF[2]}Initializing modman...${MAGECIF[0]}"
     $modman init
   fi
}

update_modules () {
   local magento_dir=$1
   local modman="${script_dir}/modman"

   init_modman $magento_dir
   $modman update-all
   $modman deploy-all
   echo "${MAGECIF[1]}Modules updated${MAGECIF[0]}"
}

uninstall_magento () {
   local magento_dir=$1; local db_name=$2; shift 2
   local db_user="root"; local db_pass=""; local opt;local db_cred

   while getopts :u:p: opt
   do
     case $opt in
       u) db_user=$OPTARG       ;;
       p) db_pass=$OPTARG       ;;
       \?) echo "${MAGECIF[3]}Unkown option -$OPTARG${MAGECIF[0]}" >&2; exit 1 ;;
       :) echo "${MAGECIF[3]}Option -$OPTARG requires an argument.${MAGECIF[0]}" >&2; exit 1 ;;
     esac
   done

   [[ $db_pass == "" ]] && db_cred="-u $db_user" || db_cred="-u $db_user -p$db_pass"

   echo "${MAGECIF[2]}Cleaning up Magento directory...${MAGECIF[0]}"
   rm -rf $magento_dir/* $magento_dir/.ht*

   if [[ $db_name != "" ]]
   then
        echo "${MAGECIF[2]}Uninstalling database...${MAGECIF[0]}"
        mysql $db_cred -e "DROP DATABASE IF EXISTS ${db_name};DROP DATABASE IF EXISTS ${db_name}_test;"
        check_error_exit
   fi;

   echo "${MAGECIF[1]}Magento was uninstalled at: $magento_dir"
}

uninstall_module () {
   local magento_dir=$1
   local magento_module_source=$2
   local magento_module
   local modman="${script_dir}/modman"

   init_modman $magento_dir

   if [[ $magento_module_source =~ ^git@ ]]
   then
     magento_module=$(basename ${magento_module_source/.git//})
     check_error_exit
   elif [ -d "${magento_module_source}" ]
   then
     magento_module=$(basename ${magento_module_source})
   elif [ -d ".modman/$magento_module_source" ]
   then
     magento_module=$magento_module_source
   else
     echo "${MAGECIF[3]}Unkown source type${MAGECIF[0]}"
     print_usage;
     exit 1
   fi

   if [ -d ".modman/$magento_module" ]
   then
      echo "${MAGECIF[2]}Removing $magento_module module${MAGECIF[0]}"
      $modman remove $magento_module
      echo "${MAGECIF[1]}$magento_module module was removed${MAGECIF[0]}"
   else
      echo "${MAGECIF[2]}$magento_module module is already removed${MAGECIF[0]}"
   fi
}

check_error_exit () {
  local errorCode=$?
  if [ $errorCode -ne 0 ]
  then
    echo "${MAGECIF[3]}Previous command returned an error exit code $errorCode${MAGECIF[0]}"
    exit $errorCode
  fi
}

case $action in
install) install_magento "$@" ;;
install-module)  install_module "$@" ;;
update-modules)  update_modules "$@" ;;
uninstall-module)  uninstall_module "$@" ;;
uninstall)  uninstall_magento "$@" ;;
install-multiple) install_multiple_magento "$@" ;;
db-dump) dump_magento "$@" ;;
phpunit) run_phpunit "$@" ;;
shell) run_shell "$@" ;;
*) show_usage ;;
esac
