m2install.sh
#!/usr/bin/env bash
# Magento 2 Bash Install Script
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# @copyright Copyright (c) 2015-2019 by Yaroslav Voronoy (y.voronoy@gmail.com)
# @license http://www.gnu.org/licenses/
GLOBAL_ARGS="$@"
VERBOSE=1
CURRENT_DIR_NAME=$(basename "$(pwd)")
STEPS=
HTTP_HOST=http://mage2.dev/
BASE_PATH=${CURRENT_DIR_NAME}
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=
ELASTICSEARCH_HOST=
ELASTICSEARCH_PORT=
MAGENTO_VERSION=2.3.7
DB_NAME=
USE_SAMPLE_DATA=
EE_PATH=magento2ee
INSTALL_EE=
INSTALL_B2B=
CONFIG_NAME=.m2install.conf
USE_WIZARD=1
GIT_CE_REPO="git@github.com:magento/magento2.git"
GIT_CE_SD_REPO="git@github.com:magento/magento2-sample-data.git"
GIT_EE_REPO=
GIT_EE_SD_REPO=
GIT_B2B_REPO=
GIT_CE_SD_PATH=magento2-sample-data
GIT_EE_SD_PATH=magento2-sample-data-ee
GIT_B2B_PATH=magento2b2b
SOURCE=
FORCE=
MAGE_MODE=dev
BIN_PHP=${BIN_PHP:-"php"}
BIN_MAGE="-d memory_limit=4G bin/magento"
BIN_COMPOSER=$(command -v composer)
BIN_MYSQL="mysql"
BIN_GIT="git"
BACKEND_FRONTNAME="admin"
ADMIN_NAME="admin"
ADMIN_PASSWORD="123123q"
ADMIN_FIRSTNAME="Admin"
ADMIN_LASTNAME="Test"
ADMIN_EMAIL="admin@test.com"
TIMEZONE="America/Chicago"
LANGUAGE="en_US"
CURRENCY="USD"
REMOTE_DB=
REMOTE_DB_HOST=""
REMOTE_DB_PASSWORD=""
REMOTE_HOST=""
REMOTE_KEY=""
LOCAL_PORT=""
BUNDLED_EXTENSION=(
amzn/amazon-pay-and-login-magento-2-module
dotmailer/dotmailer-magento2-extension
klarna/module-core
klarna/module-kp
klarna/module-ordermanagement
temando/module-shipping-m2
vertex/module-tax
)
M2INSTALL_CSV_LOG=${M2INSTALL_CSV_LOG:-}
function printVersion()
{
printString "1.0.5"
}
function getScriptDirectory()
{
echo "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )";
return 0;
}
function getCsvLogFile()
{
local path="$(getScriptDir)/m2install.csv"
[[ "$M2INSTALL_CSV_LOG" ]] && path="$M2INSTALL_CSV_LOG"
touch "$csvFile" 2>/dev/null || csvFile=/tmp/m2install.csv
echo "$path"
return 0;
}
function getErrorLogFile()
{
local path="$(getScriptDir)/error.csv"
touch "$errorLogFile" 2>/dev/null || errorLogFile=/tmp/m2install.error.log
echo "$path"
return 0;
}
function writeCsvMetricRow()
{
local csvFile="$(getCsvLogFile)"
[ -s "$csvFile" ] || echo "datetime, mode, home_response_code, home_url, admin_response_code, admin_url, duration, user, dir, script, args" >> "$csvFile"
echo "$@" >> $csvFile
return 0
}
function writeCsvErrorRow()
{
local errorLogFile="$(getErrorLogFile)"
[ -s "$errorLogFile" ] || echo "datetime, error_code, user, dir, script, arguments" >> "$errorLogFile"
echo "$(date '+%Y-%m-%d %H:%M:%S'), $1, $(whoami), $(pwd), $BASH_SOURCE, \"$GLOBAL_ARGS\"" >> $errorLogFile
return 0
}
# Get Script Directory with resolving symlink
function getScriptDir()
{
local source=
local dir=
local source="${BASH_SOURCE[0]}"
while [ -h "$source" ]; do # resolve $SOURCE until the file is no longer a symlink
local dir="$( cd -P "$( dirname "$source" )" && pwd )"
source="$(readlink "$source")"
[[ $source != /* ]] && source="$dir/$source" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
dir="$( cd -P "$( dirname "$source" )" && pwd )"
echo "$dir";
return 0;
}
function checkDependencies()
{
DEPENDENCIES=(
php
composer
mysql
mysqladmin
git
cat
basename
tar
gunzip
sed
grep
mkdir
cp
mv
rm
find
chmod
date
)
for util in "${DEPENDENCIES[@]}"
do
hash "${util}" &>/dev/null || printError "'${util}' is not found on this system" || exit 1
done;
}
function askValue()
{
MESSAGE="$1"
READ_DEFAULT_VALUE="$2"
READVALUE=
if [ "${READ_DEFAULT_VALUE}" ]
then
MESSAGE="${MESSAGE} (default: ${READ_DEFAULT_VALUE})"
fi
MESSAGE="${MESSAGE}: "
read -r -p "$MESSAGE" READVALUE
if [[ $READVALUE = [Nn] ]]
then
READVALUE=''
return
fi
if [ -z "${READVALUE}" ] && [ "${READ_DEFAULT_VALUE}" ]
then
READVALUE=${READ_DEFAULT_VALUE}
fi
}
function askConfirmation() {
if [ "$FORCE" ]
then
return 0;
fi
read -r -p "${1:-Are you sure? [y/N]} " response
case $response in
[yY][eE][sS]|[yY])
retval=0
;;
*)
retval=1
;;
esac
return $retval
}
function printString()
{
if [[ "$VERBOSE" -eq 1 ]]
then
echo "$@";
fi
}
function printError()
{
>&2 echo "ERROR: $@";
return 1;
}
function printLine()
{
if [[ "$VERBOSE" -eq 1 ]]
then
echo "--------------------------------------------------"
fi
}
function setRequest()
{
local _key=$1
local _value=$2
local expression="REQUEST_${_key}=${_value}"
eval "${expression}";
}
function getRequest()
{
local _key=$1
local _variableName="REQUEST_${_key}";
if [[ "${!_variableName:-}" ]]
then
echo "${!_variableName}"
return 0;
fi
echo "";
return 1;
}
function runCommand()
{
local _prefixMessage=${1:-};
local _suffixMessage=${2:-}
if [[ "$VERBOSE" -eq 1 ]]
then
echo "${_prefixMessage}${CMD}${_suffixMessage}"
fi
# shellcheck disable=SC2086
eval ${CMD};
}
function extract()
{
if [ -f "$EXTRACT_FILENAME" ] ; then
case $EXTRACT_FILENAME in
*.tar.*|*.t*z*)
CMD="tar $(getStripComponentsValue ${EXTRACT_FILENAME}) -xf ${EXTRACT_FILENAME} $1"
;;
*.gz) CMD="gunzip $EXTRACT_FILENAME" ;;
*.zip) CMD="unzip -qu -x $EXTRACT_FILENAME" ;;
*) printError "'$EXTRACT_FILENAME' cannot be extracted"; exit 1; CMD='' ;;
esac
runCommand
else
printError "'$EXTRACT_FILENAME' is not a valid file"
fi
}
function getStripComponentsValue()
{
local stripComponents=
local slashCount=
slashCount=$(tar -tf "$1" | grep -v vendor | fgrep pub/index.php | sed 's/pub[/]index[.]php//' | sort | head -1 | tr -cd '/' | wc -m | tr -d ' ')
if [[ "$slashCount" -gt 0 ]]
then
stripComponents="--strip-components=$slashCount"
fi
echo "$stripComponents";
}
function mysqlQuery()
{
CMD="${BIN_MYSQL} -h${DB_HOST} -u${DB_USER} --password=\"${DB_PASSWORD}\" --execute=\"${SQLQUERY}\"";
runCommand
}
function generateDBName()
{
if [ -z "$DB_NAME" ]
then
prepareBasePath
DB_NAME=${DB_USER}_${CURRENT_DIR_NAME}
fi
DB_NAME=$(sed -e "s/\//_/g; s/-/_/g; s/[^a-zA-Z0-9_]//g" <(${BIN_PHP} -r "print strtolower('$DB_NAME');"));
}
function prepareBasePath()
{
BASE_PATH=$(echo "${BASE_PATH}" | sed "s/^\///g" | sed "s/\/$//g" );
}
function checkIfBasedOnDevelopBranch()
{
if [ "$SOURCE" == 'git' ] && [ "${MAGENTO_VERSION}" == '2.4-develop' ]
then
return 0
fi
if [ "$(ls -A ./)" ] && [ -d ".git" ]
then
${BIN_GIT} rev-parse --abbrev-ref HEAD | grep -q '2.4-develop'
if [ 0 = $? ]
then
return 0
fi
fi
return 1
}
function prepareBaseURL()
{
prepareBasePath
HTTP_HOST=$(echo ${HTTP_HOST}/ | sed "s/\/\/$/\//g" );
BASE_URL="${HTTP_HOST}${BASE_PATH}/"
BASE_URL=$(echo ${BASE_URL} | sed "s/\/\/$/\//g" )
if isPubRequired
then
BASE_URL="${BASE_URL}pub/"
fi
BASE_URL=$(echo "$BASE_URL" | sed "s/\/\/$/\//g" );
}
function isPubRequired()
{
if versionIsHigherThan "$(getMagentoVersion)" "2.4.2"
then
return 0
fi
if checkIfBasedOnDevelopBranch
then
return 0
fi
if versionIsHigherThan "$MAGENTO_VERSION" "2.4.2"
then
return 0
fi
if foundSupportBackupFiles
then
if ! tar -tf $(getCodeDumpFilename) | grep '^index.php'
then
return 0
fi
fi
#return false/failure
return 255
}
function initQuietMode()
{
if [[ "$VERBOSE" -eq 1 ]]
then
return;
fi
BIN_MAGE="${BIN_MAGE} --quiet"
BIN_COMPOSER="${BIN_COMPOSER} --quiet"
BIN_GIT="${BIN_GIT} --quiet"
FORCE=1
}
function getCodeDumpFilename()
{
local codeDumpFilename="";
if [[ -f "$(getRequest codedump)" ]]
then
codeDumpFilename="$(getRequest codedump)";
echo "$codeDumpFilename";
return 0;
fi
codeDumpFilename=$(find . -maxdepth 1 -name '*.tbz2' -o -name '*.tar.bz2' | head -n1)
if [ "${codeDumpFilename}" == "" ]
then
codeDumpFilename=$(find . -maxdepth 1 -name '*.tar.gz' | grep -v 'logs.tar.gz' | head -n1)
fi
if [ ! "$codeDumpFilename" ]
then
codeDumpFilename=$(find . -maxdepth 1 -name '*.tgz' | head -n1)
fi
if [ ! "$codeDumpFilename" ]
then
codeDumpFilename=$(find . -maxdepth 1 -name '*.zip' | head -n1)
fi
echo "$codeDumpFilename";
return 0;
}
function getDbDumpFilename()
{
local dbDumpFilename="";
if [[ -f "$(getRequest dbdump)" ]]
then
dbDumpFilename="$(getRequest dbdump)";
echo "$dbDumpFilename";
return 0;
fi
dbdumpFilename=$(find . -maxdepth 1 -name '*.sql.gz' | head -n1)
if [ ! "$dbdumpFilename" ]
then
dbdumpFilename=$(find . -maxdepth 1 -name '*_db.gz' | head -n1)
fi
if [ ! "$dbdumpFilename" ]
then
dbdumpFilename=$(find . -maxdepth 1 -name '*.sql' | head -n1)
fi
echo "$dbdumpFilename";
return 0;
}
function foundSupportBackupFiles()
{
if [ -z getCodeDumpFilename ]
then
return 1;
fi
if [[ "$REMOTE_DB" ]]
then
return 0;
fi
if [ -z getDbDumpFilename ]
then
return 1;
fi
if [ ! -f "$(getCodeDumpFilename)" ] || [ ! -f "$(getDbDumpFilename)" ]
then
return 1;
fi
validateDatabaseDumpArchive
return 0;
}
function validateDatabaseDumpArchive()
{
local minSizeLimit=2
local dbDumpFilenamePath="$(getDbDumpFilename)"
local codeDumpFilenamePath="$(getCodeDumpFilename)"
local dbDumpFileSize="$(wc -c ${dbDumpFilenamePath} | awk '{print $1}')"
local codeDumpFileSize="$(wc -c ${codeDumpFilenamePath} | awk '{print $1}')"
[ "$dbDumpFileSize" -lt "$minSizeLimit" ] && { printErrorAndExit 255 "MySQL DB Dump is corrupt. For on-prem, please request a new MySQL Dump from the merchant and ensure it is created using the mysqldump utility and not bin/magento support:db:backup. For Magento-Cloud, please regenerate a new MySQL Dump by using the ZD Dump Widget / cloud-teleport."; }
[ "$codeDumpFileSize" -lt "$minSizeLimit" ] && { printErrorAndExit 256 "Code Dump is corrupt. For on-prem, please request a new Code Dump from the merchant. For Magento-Cloud, please regenerate a new MySQL Dump by using the ZD Dump Widget / cloud-teleport."; }
}
function printErrorAndExit()
{
printError $2
writeCsvErrorRow "$1"
exit $1
}
function wizard()
{
askValue "Enter Server Name of Document Root" "${HTTP_HOST}"
HTTP_HOST=${READVALUE}
askValue "Enter Base Path" "${BASE_PATH}"
BASE_PATH=${READVALUE}
askValue "Enter DB Host" "${DB_HOST}"
DB_HOST=${READVALUE}
askValue "Enter DB User" "${DB_USER}"
DB_USER=${READVALUE}
askValue "Enter DB Password" "${DB_PASSWORD}"
DB_PASSWORD=${READVALUE}
generateDBName
askValue "Enter DB Name" "${DB_NAME}"
DB_NAME=${READVALUE}
if foundSupportBackupFiles
then
return;
fi
if askConfirmation "Do you want to install Sample Data (y/N)"
then
USE_SAMPLE_DATA=1
fi
}
function noSourceWizard()
{
if [[ "$SOURCE" ]]
then
return;
fi
if [[ ! "$SOURCE" ]] && askConfirmation "Do you want install Enterprise Edition (y/N)"
then
INSTALL_EE=1
fi
if [[ "$INSTALL_EE" ]] && askConfirmation "Do you want install B2B Extension (y/N)"
then
INSTALL_B2B=1
fi
}
function printConfirmation()
{
printComposerConfirmation
printGitConfirmation
prepareBaseURL
printString "BASE URL: ${BASE_URL}"
printString "BASE PATH: ${BASE_PATH}"
printString "DB PARAM: ${DB_USER}@${DB_HOST}"
printString "DB NAME: ${DB_NAME}"
printString "DB PASSWORD: ********"
printString "MAGE MODE: ${MAGE_MODE}"
printString "BACKEND FRONTNAME: ${BACKEND_FRONTNAME}"
printString "ADMIN NAME: ${ADMIN_NAME}"
printString "ADMIN PASSWORD: ${ADMIN_PASSWORD}"
printString "ADMIN FIRSTNAME: ${ADMIN_FIRSTNAME}"
printString "ADMIN LASTNAME: ${ADMIN_LASTNAME}"
printString "ADMIN EMAIL: ${ADMIN_EMAIL}"
printString "TIMEZONE: ${TIMEZONE}"
printString "LANGUAGE: ${LANGUAGE}"
printString "CURRENCY: ${CURRENCY}"
if [[ "$REMOTE_DB" ]]
then
printString "REMOTE DB HOST: ${REMOTE_DB_HOST}"
printString "REMOTE HOST: ${REMOTE_HOST}"
printString "REMOTE KEY: ${REMOTE_KEY}"
printString "LOCAL PORT: ${LOCAL_PORT}"
printString "REMOTE DB: ${REMOTE_DB}"
printString "REMOTE DB PASSWORD: ${REMOTE_DB_PASSWORD}"
fi
if foundSupportBackupFiles
then
return;
fi
if [ "${USE_SAMPLE_DATA}" ]
then
printString "Sample Data will be installed."
else
printString "Sample Data will NOT be installed."
fi
if [ "${INSTALL_EE}" ]
then
printString "Magento EE will be installed."
else
printString "Magento EE will NOT be installed."
fi
if [ "${INSTALL_B2B}" ]
then
printString "Magento B2B will be installed."
else
printString "Magento B2B will NOT be installed."
fi
}
function showWizard()
{
I=1;
while [ "$I" -eq 1 ]
do
if [ "$USE_WIZARD" -eq 1 ]
then
showComposerWizzard
showWizzardGit
noSourceWizard
wizard
fi
printLine
printConfirmation
if askConfirmation "Confirm That the Entered Data Is Correct? (y/N)"
then
I=0
else
USE_WIZARD=1
fi
done
}
function getConfigFiles()
{
local configPaths[0]="$HOME/$CONFIG_NAME"
configPaths[1]="$HOME/${CONFIG_NAME}.override"
local recursiveconfigs=$( (find "$(pwd)" -maxdepth 1 -name "${CONFIG_NAME}" ;\
x=$(pwd);\
while [ "$x" != "/" ] ;\
do x=$(dirname "$x");\
find "$x" -maxdepth 1 -name "${CONFIG_NAME}";\
done) | sed '1!G;h;$!d')
configPaths=("${configPaths[@]}" "${recursiveconfigs[@]}" "./$(basename ${CONFIG_NAME})" "$(getScriptDir)/master.conf");
echo "${configPaths[@]} "
return 0;
}
function loadConfigFile()
{
local filePath=
local configPaths=("$@");
for filePath in "${configPaths[@]}"
do
if [ -f "${filePath}" ]
then
source "$filePath"
USE_WIZARD=0
fi
done
generateDBName
}
function promptSaveConfig()
{
if [ "$FORCE" ]
then
return;
fi
_local=$(dirname "$BASE_PATH")
if [ "$_local" == "." ]
then
_local=
else
_local=$_local/
fi
if [ "$_local" != '/' ]
then
_local=${_local}\$CURRENT_DIR_NAME
fi
_configContent=$(cat << EOF
HTTP_HOST=$HTTP_HOST
BASE_PATH=$_local
DB_HOST=$DB_HOST
DB_NAME=$DB_NAME
DB_USER=$DB_USER
DB_PASSWORD=$DB_PASSWORD
MAGENTO_VERSION=$MAGENTO_VERSION
INSTALL_EE=$INSTALL_EE
INSTALL_B2B=$INSTALL_B2B
GIT_CE_REPO=$GIT_CE_REPO
GIT_EE_REPO=$GIT_EE_REPO
MAGE_MODE=$MAGE_MODE
BACKEND_FRONTNAME=$BACKEND_FRONTNAME
ADMIN_NAME=$ADMIN_NAME
ADMIN_PASSWORD=$ADMIN_PASSWORD
ADMIN_FIRSTNAME=$ADMIN_FIRSTNAME
ADMIN_LASTNAME=$ADMIN_LASTNAME
ADMIN_EMAIL=$ADMIN_EMAIL
TIMEZONE=$TIMEZONE
LANGUAGE=$LANGUAGE
CURRENCY=$CURRENCY
REMOTE_DB_HOST=$REMOTE_DB_HOST
REMOTE_HOST=$REMOTE_HOST
REMOTE_KEY=$REMOTE_KEY
LOCAL_PORT=$LOCAL_PORT
REMOTE_DB=$REMOTE_DB
REMOTE_DB_PASSWORD=$REMOTE_DB_PASSWORD
ELASTICSEARCH_HOST=$ELASTICSEARCH_HOST
ELASTICSEARCH_PORT=$ELASTICSEARCH_PORT
EOF
)
if [ "$(getConfigFiles)" ]
then
_currentConfigContent=$(cat "$HOME/$CONFIG_NAME")
if [ "$_configContent" == "$_currentConfigContent" ]
then
return;
fi
fi
configSavePath="$HOME/$CONFIG_NAME"
if [ -f "${configSavePath}" ]
then
configSavePath="./$CONFIG_NAME"
fi
if askConfirmation "Do you want save config to ${configSavePath} (y/N)"
then
cat << EOF > ${configSavePath}
$_configContent
EOF
printString "Config file has been created in ${configSavePath}";
fi
_local=
configSavePath=
}
function dropES()
{
# in general, the assumption is to take no care about if an index is deleted
# the goal here is only to request index deletion for any valid config we can find
local es_engine es_host es_port es_prefix elasticsuite version versions=("" "5" "6" "7")
for version in "${versions[@]}"
do
es_host=$(getConfig "catalog/search/elasticsearch${version}_server_hostname" "value");
es_port=$(getConfig "catalog/search/elasticsearch${version}_server_port" "value");
es_prefix=$(getConfig "catalog/search/elasticsearch${version}_index_prefix" "value");
dropEsIndex "$es_host" "$es_port" "$es_prefix"
done
es_host=$(getConfig "amasty_elastic/connection/server_hostname" "value");
es_port=$(getConfig "amasty_elastic/connection/server_port" "value");
es_prefix=$(getConfig "amasty_elastic/connection/index_prefix" "value");
dropEsIndex "$es_host" "$es_port" "$es_prefix"
elasticsuite=$(getConfig "smile_elasticsuite_core_base_settings/es_client/servers" "value");
es_host=${elasticsuite%%:*}
es_port=${elasticsuite/*:/}
es_prefix=$(getConfig "smile_elasticsuite_core_base_settings/indices_settings/alias" "value");
dropEsIndex "$es_host" "$es_port" "$es_prefix"
}
function dropEsIndex()
{
local host="$1" port="$2" index="$3"
if [[ -z "$host" ]] || [[ -z "$port" ]] || [[ -z "$index" ]]; then
return 0
fi
curl -S -s -o /dev/null -X DELETE "$host:$port/$index*"
return 0
}
function dropDB()
{
SQLQUERY="DROP DATABASE IF EXISTS ${DB_NAME}";
mysqlQuery
}
function createNewDB()
{
SQLQUERY="CREATE DATABASE IF NOT EXISTS ${DB_NAME}";
mysqlQuery
}
function restore_db()
{
dropDB
createNewDB
CMD="gunzip -cf \"$(getDbDumpFilename)\""
if which pv > /dev/null
then
CMD="pv \"$(getDbDumpFilename)\" | gunzip -cf";
fi
# Don't be confused by double gunzip in following command. Some poorly
# configured web servers can gzip everything including gzip files
CMD="${CMD} | gunzip -cf | sed -e 's/DEFINER[ ]*=[ ]*[^*]*\*/\*/'
| sed -e 's/TRIGGER[ ][\`][A-Za-z0-9_]*[\`][.]/TRIGGER /'
| sed -e 's/AFTER[ ]\(INSERT\)\{0,1\}\(UPDATE\)\{0,1\}\(DELETE\)\{0,1\}[ ]ON[ ][\`][A-Za-z0-9_]*[\`][.]/AFTER \1\2\3 ON /'
| grep -v 'mysqldump: Couldn.t find table' | grep -v 'mysqldump: Couldn.t execute' | grep -v 'Warning: Using a password'
| ${BIN_MYSQL} -h${DB_HOST} -u${DB_USER} --password=\"${DB_PASSWORD}\" --force $DB_NAME";
runCommand
validateDatabaseDumpDataExists
}
function validateDatabaseDumpDataExists()
{
local isError=
if [ -z "$(getAllTables \"$(getTablePrefix)store\")" ]
then
printError "The store table is not found"
isError="1"
fi
if [ -z "$(getAllStores)" ]
then
printError "The store table missing data"
isError="1"
fi
if [ -z "$(getAllWebsites)" ]
then
printError "The store_website table missing data"
isError="1"
fi
[[ "$isError" ]] && { printErrorAndExit 257 "MySQL DB Dump is corrupt. For on-prem, please request a new MySQL Dump from the merchant and ensure it is created using the mysqldump utility and not bin/magento support:db:backup. For Magento-Cloud, please regenerate a new MySQL Dump by using the ZD Dump Widget / cloud-teleport." "Missing data DB Dump"; }
}
function restore_code()
{
EXTRACT_FILENAME="$(getCodeDumpFilename)"
extract
CMD="mkdir -p var pub/media pub/static"
runCommand
}
function configure_files()
{
CMD="find -L ./pub -type l -delete"
runCommand
updateMagentoEnvFile
overwriteOriginalFiles
#CMD="find . -type d -exec chmod 775 {} \; && find . -type f -exec chmod 664 {} \;"
CMD="chmod -R 775 ."
runCommand
CMD="${BIN_PHP} ${BIN_COMPOSER} dump-autoload"
runCommand
patchDumps
}
function add_remote()
{
updateEnvFileRemote
patchRemote
}
function getRemoteDBUser()
{
local user=(${REMOTE_DB//_/ })
echo ${user[0]} ;
}
function updateEnvFileRemote()
{
local deployConfigurator=$(cat << EOF
<?php
\$dbName = '${REMOTE_DB}';
\$dbUser = '$(getRemoteDBUser)';
\$dbPassword = '${REMOTE_DB_PASSWORD}';
\$localPort = '${LOCAL_PORT}';
EOF
);
deployConfigurator+=$(cat << 'EOF'
function updateDbConnection($envConfig, $connectionDetails)
{
unset($envConfig['db']['slave_connection']);
foreach ($envConfig['db'] as $key => $connections) {
if ($key != 'connection') {
continue;
}
foreach ($connections as $connectionName => $connectionParams) {
$envConfig['db'][$key][$connectionName] = $connectionDetails;
}
}
return $envConfig;
}
$envConfig = require 'app/etc/env.php';
$envConfig = updateDbConnection($envConfig, array(
'host' => "127.0.0.1:$localPort",
'dbname' => $dbName,
'username' => $dbUser,
'password' => "$dbPassword",
'model' => 'mysql4',
'engine' => 'innodb',
'initStatements' => 'SET NAMES utf8;',
'active' => '1'
));
echo "<?php\nreturn " . var_export($envConfig, true) . "\n;";
EOF
);
echo "$deployConfigurator" | ${BIN_PHP} > app/etc/env.php.generated
mv app/etc/env.php.generated app/etc/env.php
}
function addToBootstrap()
{
echo "$1" >> app/bootstrap.php;
}
function patchRemote()
{
local sshKey=''
if [[ "$REMOTE_KEY" ]]
then
sshKey="-i ${REMOTE_KEY} "
fi
addToBootstrap "//patched by m2install."
local ssh_command="ssh ${sshKey}-o ConnectTimeout=10 -o StrictHostKeyChecking=no -4fN -L ${LOCAL_PORT}:${REMOTE_DB_HOST} ${REMOTE_HOST}"
if ! pgrep -f -x "${ssh_command}" > /dev/null
then
echo "Start tunnel"
eval $ssh_command >> /dev/null
fi
SQLQUERY="SELECT code FROM ${REMOTE_DB}.$(getTablePrefix)store WHERE code != 'admin';";
local stores=$(mysql -h127.0.0.1 -N -u$(getRemoteDBUser) -P${LOCAL_PORT} --execute="${SQLQUERY}")
echo "$stores" | while IFS= read -r line ;
do
addToBootstrap "\$_ENV['CONFIG__STORES__${line}__WEB__SECURE__BASE_URL'] = '${BASE_URL}';"
addToBootstrap "\$_ENV['CONFIG__STORES__${line}__WEB__UNSECURE__BASE_URL'] = '${BASE_URL}';"
done
addToBootstrap "\$_ENV['CONFIG__DEFAULT__WEB__UNSECURE__BASE_URL'] = '${BASE_URL}';"
addToBootstrap "\$_ENV['CONFIG__DEFAULT__WEB__SECURE__BASE_URL'] = '${BASE_URL}';"
addToBootstrap "\$command = '$ssh_command';"
addToBootstrap 'exec("ps aux | grep -v \" grep\" | grep \"$command\" | tr -s \" \" | cut -d \" \" -f 2", $pids);'
addToBootstrap 'if (count($pids) === 0) {'
addToBootstrap ' exec($command . " >> /dev/null", $output, $exitCode);';
addToBootstrap ' if ($exitCode > 0) {'
addToBootstrap ' throw new \Exception("Remote Host ${REMOTE_HOST} is unavailable, check your network settings or VPN connection");'
addToBootstrap ' }'
addToBootstrap ' exec("ps aux | grep -v \" grep\" | grep \"$command\" | tr -s \" \" | cut -d \" \" -f 2", $pids);'
addToBootstrap '}'
addToBootstrap 'file_put_contents("kill_tunnel.sh", PHP_EOL . "kill " . implode(" ", $pids));'
addToBootstrap ""
}
function patchDumps()
{
patch -p1 <<'EOF'
diff --git a/vendor/magento/module-backend/Block/Dashboard/Orders/Grid.php b/vendor/magento/module-backend/Block/Dashboard/Orders/Grid.php
index 5027978..9df3c24 100644
--- a/vendor/magento/module-backend/Block/Dashboard/Orders/Grid.php
+++ b/vendor/magento/module-backend/Block/Dashboard/Orders/Grid.php
@@ -92,6 +92,11 @@ class Grid extends \Magento\Backend\Block\Dashboard\Grid
protected function _afterLoadCollection()
{
foreach ($this->getCollection() as $item) {
+ // patched by m2install.
+ // To revert patch remove next lines from 95 to 99
+ if (is_null($item->getBillingAddress())) {
+ return $this;
+ }
$item->getCustomer() ?: $item->setCustomer($item->getBillingAddress()->getName());
}
return $this;
EOF
}
function appConfigImport()
{
if ${BIN_PHP} bin/magento | grep -q app:config:import
then
CMD="$BIN_PHP $BIN_MAGE app:config:import -n"
runCommand
fi
}
function validateDeploymentFromDumps()
{
local files=(
'composer.json'
'composer.lock'
'pub/index.php'
'pub/static.php'
);
if ! isPubRequired
then
files+=('index.php')
fi
local directories=("app" "bin" "dev" "lib" "pub/errors" "setup" "vendor");
missingDirectories=();
for dir in "${directories[@]}"
do
if [ ! -d "$dir" ]; then
missingDirectories+=("$dir");
fi
done
if [[ "${missingDirectories[@]-}" ]]
then
echo "The following directories are missing: ${missingDirectories[@]}";
fi
missingFiles=()
for file in "${files[@]}"
do
if [ ! -f "$file" ]; then
missingFiles+=("$file");
fi
done
if [[ "${missingFiles[@]-}" ]]
then
echo "The following files are missing: ${missingFiles[@]}";
fi
if [[ "${missingDirectories[@]-}" || "${missingFiles[@]-}" ]]
then
printError "Download missing files and directories from vanilla magento"
fi
}
function updateElasticSearchConfiguration()
{
local currentSearchEngine="$($BIN_PHP bin/magento config:show catalog/search/engine)"
[[ ! "$currentSearchEngine" ]] && currentSearchEngine=$(getRecommendedSearchEngineForVersion)
appConfigImport
printString "Updating ElasticSearch Configuration $(getESConfigHost $currentSearchEngine):$(getESConfigPort $currentSearchEngine)"
$BIN_PHP bin/magento config:set "catalog/search/${currentSearchEngine}_server_hostname" $(getESConfigHost $currentSearchEngine)
$BIN_PHP bin/magento config:set "catalog/search/${currentSearchEngine}_server_port" $(getESConfigPort $currentSearchEngine)
$BIN_PHP bin/magento config:set "catalog/search/${currentSearchEngine}_index_prefix" $DB_NAME
printString "To see products on storefront run: $BIN_PHP bin/magento indexer:reindex catalogsearch_fulltext"
return 0
}
function disableLiveSearch()
{
if $BIN_PHP $BIN_MAGE module:status Magento_LiveSearch | grep -q 'Module is enabled'
then
$BIN_PHP $BIN_MAGE module:status | grep Magento_LiveSearch | grep -v List | grep -v None | grep -v -e '^$' | xargs $BIN_PHP $BIN_MAGE module:disable
$BIN_PHP $BIN_MAGE module:status | grep -E 'Magento_Elasticsearch*|Magento_AdvancedSearch|Magento_InventoryElasticsearch' | grep -v List | grep -v None | grep -v -e '^$' | xargs $BIN_PHP $BIN_MAGE module:enable
$BIN_PHP $BIN_MAGE --quiet config:set 'catalog/search/engine' $(getRecommendedSearchEngineForVersion)
cat <<endmessage
${yellow}
####################################################################################
Warning: A Search Engine has been switched from LiveSearch to ElasticSearch
####################################################################################
${default}
endmessage
fi
}
function switchSearchEngineToDefaultEngine()
{
disableLiveSearch
isElasticSearchRequired && updateElasticSearchConfiguration && return 0;
local red=`tput setaf 1`
local green=`tput setaf 2`
local yellow=`tput setaf 3`
local default=`tput sgr0`
local engine=$(getConfig 'catalog/search/engine' "value");
local stepsToTake=
[[ "$engine" == "mysql" ]] && return 0
[[ ! "$engine" ]] && return 0
if [[ "$engine" ]]
then
setConfig 'catalog/search/engine' "mysql"
local stepsToTake=" - Run php bin/magento indexer:reindex catalogsearch_fulltext"
fi
cat <<endmessage
${yellow}
####################################################################################
Warning: A Search Engine has been switched from ${engine} to mysql
If you need to see products on frontend follow the steps below:
${stepsToTake}
####################################################################################
${default}
endmessage
}
function configure_db()
{
printString "Updating Database Configuration"
setConfig 'web/secure/base_url' "${BASE_URL}";
setConfig 'web/unsecure/base_url' "${BASE_URL}";
setConfig 'web/secure/offloader_header' 'X-Forwarded-Proto';
setConfig 'google/analytics/active' '0';
setConfig 'google/adwords/active' '0';
setConfig 'msp_securitysuite_twofactorauth/general/enabled' '0';
setConfig 'msp_securitysuite_recaptcha/backend/enabled' '0';
setConfig 'msp_securitysuite_recaptcha/frontend/enabled' '0';
setConfig 'admin/security/session_lifetime' '31536000';
setConfig 'admin/startup/menu_item_id' 'Magento_Backend::system_store';
deleteConfig 'web/unsecure/base_link_url';
deleteConfig 'web/secure/base_link_url';
deleteConfig 'web/unsecure/base_static_url';
deleteConfig 'web/unsecure/base_media_url';
deleteConfig 'web/secure/base_static_url';
deleteConfig 'web/secure/base_media_url';
deleteConfig "web/cookie/cookie_domain";
deleteConfig "web/secure/use_in_adminhtml";
deleteConfig "web/secure/use_in_frontend";
deleteConfig "admin/url/custom";
deleteConfig "admin/url/custom_path";
deleteConfig "admin/url/use_custom";
deleteConfig "admin/url/use_custom_path";
deleteConfig 'system/full_page_cache/fastly/fastly_api_key';
deleteConfig 'system/full_page_cache/caching_application';
deleteConfig 'catalog/placeholder/%' 'LIKE';
deleteConfig 'algoliasearch_credentials/credentials/application_id';
deleteConfig 'algoliasearch_credentials/credentials/search_only_api_key';
deleteConfig 'algoliasearch_credentials/credentials/api_key';
deleteConfig 'algoliasearch_credentials/credentials/enable_backend';
deleteConfig 'algoliasearch_credentials/credentials/enable_frontend';
deleteConfig 'services_connector/services_connector_integration/production_api_key';
deleteConfig 'services_connector/services_connector_integration/sandbox_api_key';
deleteConfig 'services_connector/services_id/project_name';
deleteConfig 'services_connector/services_id/environment_name';
deleteConfig 'services_connector/services_id/environment';
deleteConfig 'services_connector/services_id/project_id';
deleteConfig 'services_connector/services_id/environment_id';
processShippingConfig
processPaymentConfig
removeConfigByKeyword
resetAdminPassword
switchSearchEngineToDefaultEngine
}
function setConfig()
{
local path="${1}";
local value="${2}";
SQLQUERY="UPDATE ${DB_NAME}.$(getTablePrefix)core_config_data SET ${DB_NAME}.$(getTablePrefix)core_config_data.value = '${value}' WHERE path = '${path}'"
mysqlQuery
}
function getConfig()
{
local output=
local path="${1}";
local field="${2}";
SQLQUERY="SELECT ${field} FROM ${DB_NAME}.$(getTablePrefix)core_config_data WHERE path = '${path}'";
output=$(mysqlQuery)
echo "$output" | grep -v "$field"
}
function deleteConfig()
{
local path="${1}";
local where="=";
if [ ! -z $2 ]
then
where="${2}";
fi
SQLQUERY="DELETE FROM ${DB_NAME}.$(getTablePrefix)core_config_data WHERE path ${where} '${path}'";
mysqlQuery
}
function processShippingConfig()
{
setShippingConfigToInactive
deleteShippingConfig
}
function setShippingConfigToInactive()
{
setConfig 'carriers/fedex/active' '0';
setConfig 'carriers/ups/is_account_live' '0';
setConfig 'carriers/usps/active' '0';
}
function deleteShippingConfig()
{
deleteConfig 'carriers/fedex/key';
deleteConfig 'carriers/fedex/password';
deleteConfig 'carriers/fedex/meter_number';
deleteConfig 'carriers/fedex/account';
deleteConfig 'carriers/ups/password';
deleteConfig 'carriers/ups/access_license_number';
deleteConfig 'carriers/ups/username';
deleteConfig 'carriers/ups/shipper_number';
deleteConfig 'carriers/usps/gateway_secure_url';
deleteConfig 'carriers/usps/gateway_url';
deleteConfig 'carriers/usps/userid';
deleteConfig 'carriers/usps/password';
deleteConfig 'carriers/dhl/id';
deleteConfig 'carriers/dhl/password';
}
function processPaymentConfig()
{
setPaymentConfigToInactive
deletePaymentConfig
}
function setPaymentConfigToInactive()
{
setConfig 'payment/authorizenet_acceptjs/active' '0';
setConfig 'payment/cybersource/active' '0';
setConfig 'payment/amazon_payment/active' '0';
setConfig 'payment/amazonlogin/active' '0';
setConfig 'payment/braintree/active' '0';
setConfig 'payment/braintree_paypal/active' '0';
setConfig 'payment/eway/active' '0';
setConfig 'payment/worldpay/active' '0';
setConfig 'payment/klarna_kp/active' '0';
setConfig 'paypal/wpp/api_authentication' '0';
setConfig 'payment/paypal_express/active' '0';
setConfig 'payment/payflow_advanced/active' '0';
setConfig 'payment/payflowpro/active' '0';
setConfig 'payment/paypal_payment_pro/active' '0';
setConfig 'payment/payflow_link/active' '0';
}
function deletePaymentConfig()
{
deleteConfig 'payment/authorizenet_acceptjs/trans_signature_key';
deleteConfig 'payment/authnetcim/trans_key';
deleteConfig 'payment/authnetcim/client_key';
deleteConfig 'payment/authnetcim_ach/trans_key';
deleteConfig 'payment/authorizenet_acceptjs/public_client_key';
deleteConfig 'payment/authorizenet_acceptjs/trans_key';
deleteConfig 'payment/authorizenet_acceptjs/trans_md5';
deleteConfig 'payment/authorizenet_acceptjs/login';
deleteConfig 'payment/cybersource/transaction_key';
deleteConfig 'payment/cybersource/access_key';
deleteConfig 'payment/cybersource/secret_key';
deleteConfig 'payment/cybersource/merchant_id';
deleteConfig 'payment/cybersource/profile_id';
deleteConfig 'payment/amazon_payments/simplepath/privatekey';
deleteConfig 'payment/amazon_payments/simplepath/publickey';
deleteConfig 'payment/amazon_payment/credentials_json';
deleteConfig 'payment/amazon_payment/client_secret';
deleteConfig 'payment/amazon_payment/client_id';
deleteConfig 'payment/amazon_payment/secret_key';
deleteConfig 'payment/amazon_payment/access_key';
deleteConfig 'payment/amazon_payment/merchant_id';
deleteConfig 'payment/braintree/public_key';
deleteConfig 'payment/braintree/private_key';
deleteConfig 'payment/braintree/merchant_id';
deleteConfig 'payment/braintree/merchant_account_id';
deleteConfig 'payment/eway/live_api_key';
deleteConfig 'payment/eway/live_api_password';
deleteConfig 'payment/eway/live_encryption_key';
deleteConfig 'payment/eway/payment_action';
deleteConfig 'payment/eway/sandbox_api_key';
deleteConfig 'payment/eway/sandbox_api_password';
deleteConfig 'payment/eway/sandbox_encryption_key';
deleteConfig 'payment/worldpay/md5_secret';
deleteConfig 'payment/worldpay/auth_password';
deleteConfig 'payment/worldpay/response_password';
deleteConfig 'klarna/api/shared_secret';
deleteConfig 'klarna/api/merchant_id';
deleteConfig 'paypal/wpp/api_username';
deleteConfig 'paypal/wpp/api_password';
deleteConfig 'paypal/wpp/api_signature';
deleteConfig 'payment/payflow_advanced/pwd';
deleteConfig 'payment/payflowpro/pwd';
deleteConfig 'payment/payflow_link/pwd';
deleteConfig 'payment/payment_methods/sandbox_merchant_id';
deleteConfig 'payment/payment_methods/production_merchant_id';
deleteConfig 'payment/payment_methods/method';
}
function removeConfigByKeyword()
{
deleteConfig '%activation_key%' 'LIKE';
deleteConfig '%secret_key%' 'LIKE';
deleteConfig '%serial_key%' 'LIKE';
deleteConfig '%license_key%' 'LIKE';
deleteConfig '%encryption_key%' 'LIKE';
deleteConfig '%private_key%' 'LIKE';
deleteConfig '%public_key%' 'LIKE';
deleteConfig '%api_key%' 'LIKE';
deleteConfig '%client_key%' 'LIKE';
deleteConfig '%client_secret%' 'LIKE';
deleteConfig '%api_password%' 'LIKE';
deleteConfig '%api_signature%' 'LIKE';
deleteConfig '%secret%' 'LIKE';
deleteConfig '%application_key%' 'LIKE';
deleteConfig '%token%' 'LIKE';
}
function resetAdminPassword()
{
SQLQUERY="UPDATE ${DB_NAME}.$(getTablePrefix)admin_user SET ${DB_NAME}.$(getTablePrefix)admin_user.email = '${ADMIN_EMAIL}' WHERE ${DB_NAME}.$(getTablePrefix)admin_user.username = '${ADMIN_NAME}'"
mysqlQuery
CMD="${BIN_PHP} ${BIN_MAGE} admin:user:create
--admin-user='${ADMIN_NAME}'
--admin-password='${ADMIN_PASSWORD}'
--admin-email='${ADMIN_EMAIL}'
--admin-firstname='${ADMIN_FIRSTNAME}'
--admin-lastname='${ADMIN_LASTNAME}'"
runCommand
}
function overwriteOriginalFiles()
{
if [ -f app/etc/config.local.php ]
then
CMD="mv app/etc/config.local.php app/etc/config.local.php.merchant"
runCommand
fi
if [ ! -f pub/static.php ]
then
CMD="curl -s -o pub/static.php https://raw.githubusercontent.com/magento/magento2/${MAGENTO_VERSION}/pub/static.php"
runCommand
fi
if [ -f .htaccess ] && [ ! -f .htaccess.merchant ]
then
CMD="mv .htaccess .htaccess.merchant"
runCommand
fi
CMD="curl -s -o .htaccess https://raw.githubusercontent.com/magento/magento2/${MAGENTO_VERSION}/.htaccess"
runCommand
if [ -f pub/.htaccess ] && [ ! -f pub/.htaccess.merchant ]
then
CMD="mv pub/.htaccess pub/.htaccess.merchant"
runCommand
fi
CMD="curl -s -o pub/.htaccess https://raw.githubusercontent.com/magento/magento2/${MAGENTO_VERSION}/pub/.htaccess"
runCommand
if [ -f pub/static/.htaccess ] && [ ! -f pub/static/.htaccess.merchant ]
then
CMD="mv pub/static/.htaccess pub/static/.htaccess.merchant"
runCommand
fi
CMD="curl -s -o pub/static/.htaccess https://raw.githubusercontent.com/magento/magento2/${MAGENTO_VERSION}/pub/static/.htaccess"
runCommand
if [ -f pub/media/.htaccess ] && [ ! -f pub/media/.htaccess.merchant ]
then
CMD="mv pub/media/.htaccess pub/media/.htaccess.merchant"
runCommand
fi
CMD="curl -s -o pub/media/.htaccess https://raw.githubusercontent.com/magento/magento2/${MAGENTO_VERSION}/pub/media/.htaccess"
runCommand
if [ ! "$(getRequest skipPostOverwrite)" ]
then
postOverwriteOriginalFiles
fi
}
function postOverwriteOriginalFiles()
{
if [ -f app/etc/config.php ]
then
disableModuleInConfigFile 'smtp'
fi
}
function configurePWA()
{
if [ -f pwa_path.txt ]
then
CMD="curl -s -o .htaccess https://raw.githubusercontent.com/magento/magento2/2.4.3/.htaccess"
runCommand
local ABSOLUTE_PATH="$(pwd)"
echo "PWA setup"
PWA="$(cat pwa_path.txt)"
PWA_CONFIG="echo -e '
SetEnv MAGENTO_BACKEND_URL ${BASE_URL} \n
SetEnv NODE_ENV production \n
SetEnv CONFIG__DEFAULT__WEB__UPWARD__PATH ${ABSOLUTE_PATH}/${PWA}/upward.yml \n
'"
CMD="${PWA_CONFIG} >> .htaccess "
runCommand
CMD="${PWA_CONFIG} >> pub/.htaccess "
runCommand
$BIN_PHP bin/magento --quiet config:set "web/upward/path" ${ABSOLUTE_PATH}/${PWA}/upward.yml
CMD="echo -e \"
putenv('MAGENTO_BACKEND_URL=${BASE_URL}');\n
putenv('NODE_ENV=production');\n
\" >> app/bootstrap.php "
runCommand
ORIGIN_URL=$(grep -o 'data-media-backend=\"https\?://[^/]\+/' ${PWA}/index.html | grep -o 'https\?://[^/]\+/')
echo $ORIGIN_URL
#this is for Mac
CMD="sed -i '' 's=${ORIGIN_URL}=${BASE_URL}=g' ${PWA}/*"
runCommand
#this is for Linux
CMD="sed -i 's=${ORIGIN_URL}=${BASE_URL}=g' ${PWA}/*"
runCommand
fi
}
function getTablePrefix()
{
echo $(grep 'table_prefix' app/etc/env.php | head -n1 | sed "s/[a-z'_ ]*[=][>][ ]*[']//" | sed "s/['][,]*//")
return 0;
}
function updateMagentoEnvFile()
{
if [ -f app/etc/env.php ] && [ ! -f app/etc/env.php.merchant ]
then
CMD="cp app/etc/env.php app/etc/env.php.merchant"
runCommand
fi
if [ -f app/etc/env.support.backup ] && [ ! -f app/etc/env.php ]
then
CMD="cp app/etc/env.support.backup app/etc/env.php"
runCommand
fi
if [ ! -f app/etc/env.php ]
then
CMD="echo -e \"<?php\nreturn array('install'=>array('date'=>'$(date)'),'db'=>array('connection'=>array('default'=>array())));\n\" > app/etc/env.php"
runCommand
fi
local deployConfigurator=$(cat << EOF
<?php
\$dbHost = '${DB_HOST}';
\$dbName = '${DB_NAME}';
\$dbUser = '${DB_USER}';
\$dbPassword = '${DB_PASSWORD}';
\$frontName = '${BACKEND_FRONTNAME}';
EOF
);
deployConfigurator+=$(cat << 'EOF'
function updateMode($envConfig, $mode)
{
$envConfig['MAGE_MODE'] = $mode;
return $envConfig;
}
function updateBackendFrontName($envConfig, $frontName)
{
$envConfig['backend'] = array('frontName' => $frontName);
return $envConfig;
}
function updateDbConnection($envConfig, $connectionDetails)
{
unset($envConfig['db']['slave_connection']);
foreach ($envConfig['db'] as $key => $connections) {
if ($key != 'connection') {
continue;
}
foreach ($connections as $connectionName => $connectionParams) {
$envConfig['db'][$key][$connectionName] = $connectionDetails;
}
}
return $envConfig;
}
function updateSessionConfiguration($envConfig, $value)
{
$envConfig['session'] = array('save' => $value);
return $envConfig;
}
function removeNonDefaultConfiguration($envConfig)
{
$allowedConfigPaths = array(
'backend',
'crypt',
'db',
'resource',
'x-frame-options',
'MAGE_MODE',
'session',
'cache_types',
'install'
);
foreach ($envConfig as $path => $value) {
if (!in_array($path, $allowedConfigPaths)) {
unset($envConfig[$path]);
}
}
return $envConfig;
}
$envConfig = require 'app/etc/env.php';
$envConfig = removeNonDefaultConfiguration($envConfig);
$envConfig = updateSessionConfiguration($envConfig, 'files');
$envConfig = updateDbConnection($envConfig, array(
'host' => "$dbHost",
'dbname' => "$dbName",
'username' => "$dbUser",
'password' => "$dbPassword",
'model' => 'mysql4',
'engine' => 'innodb',
'initStatements' => 'SET NAMES utf8;',
'active' => '1'
));
$envConfig = updateBackendFrontName($envConfig, $frontName);
$envConfig = updateMode($envConfig, 'default');
echo "<?php\nreturn " . var_export($envConfig, true) . "\n;";
EOF
);
echo "$deployConfigurator" | ${BIN_PHP} > app/etc/env.php.generated
mv app/etc/env.php.generated app/etc/env.php
}
function deployStaticContent()
{
if [[ "$MAGE_MODE" == "dev" ]]
then
return;
fi
CMD="${BIN_PHP} ${BIN_MAGE} setup:static-content:deploy"
runCommand
}
function compileDi()
{
if [[ "$MAGE_MODE" == "dev" ]]
then
return;
fi
CMD="${BIN_PHP} ${BIN_MAGE} setup:di:compile"
runCommand
}
function installSampleData()
{
if ${BIN_PHP} bin/magento --version | grep -q beta
then
_installSampleDataForBeta;
elif [ "$SOURCE" == 'git' ]
then
_installGitSampleData;
else
_installSampleData;
fi
}
function _installSampleData()
{
if ! ${BIN_PHP} bin/magento | grep -q sampledata:deploy
then
printString "Your version does not support sample data"
return;
fi
if [ -f "${HOME}/.config/composer/auth.json" ]
then
if [ -d "var/composer_home" ]
then
CMD="cp ${HOME}/.config/composer/auth.json var/composer_home/"
runCommand
fi
fi
if [ -f "${HOME}/.composer/auth.json" ]
then
if [ -d "var/composer_home" ]
then
CMD="cp ${HOME}/.composer/auth.json var/composer_home/"
runCommand
fi
fi
if ! grep -q 'https://repo.magento.com' composer.json;
then
CMD="${BIN_PHP} ${BIN_COMPOSER} config repositories.magento composer https://repo.magento.com"
runCommand
fi
CMD="${BIN_PHP} ${BIN_MAGE} sampledata:deploy"
runCommand
CMD="${BIN_PHP} ${BIN_MAGE} setup:upgrade"
runCommand
if [ -f "var/composer_home/auth.json" ]
then
CMD="rm var/composer_home/auth.json"
runCommand
fi
}
function _installSampleDataForBeta()
{
CMD="${BIN_PHP} ${BIN_COMPOSER} config repositories.magento composer http://packages.magento.com"
runCommand
CMD="${BIN_PHP} ${BIN_COMPOSER} require magento/sample-data:~1.0.0-beta"
runCommand
CMD="${BIN_PHP} ${BIN_MAGE} setup:upgrade"
runCommand
CMD="${BIN_PHP} ${BIN_MAGE} sampledata:install admin"
runCommand
}
function _installGitSampleData()
{
CMD="${BIN_GIT} clone --branch $MAGENTO_VERSION --single-branch $GIT_CE_SD_REPO $GIT_CE_SD_PATH"
runCommand
CMD="${BIN_PHP} -f $GIT_CE_SD_PATH/dev/tools/build-sample-data.php -- --ce-source=."
runCommand
if [[ "$GIT_EE_SD_REPO" ]] && [[ "$INSTALL_EE" ]]
then
CMD="${BIN_GIT} clone --branch $MAGENTO_VERSION --single-branch $GIT_EE_SD_REPO $GIT_EE_SD_PATH"
runCommand
CMD="${BIN_PHP} -f $GIT_EE_SD_PATH/dev/tools/build-sample-data.php -- --ce-source=. --ee-source=$MAGENTO_EE_PATH"
runCommand
fi
CMD="${BIN_PHP} ${BIN_MAGE} setup:upgrade"
runCommand
}
function installLiveSearch()
{
if [ "${SOURCE}" == 'git' ] || checkIfBasedOnDevelopBranch
then
echo "Not supported at this moment"
return 0;
else
CMD="${BIN_PHP} ${BIN_COMPOSER} require magento/live-search"
runCommand
fi
$BIN_PHP $BIN_MAGE module:status | grep -E 'Magento_Elasticsearch*|Magento_AdvancedSearch|Magento_InventoryElasticsearch' | grep -v List | grep -v None | grep -v -e '^$' | xargs $BIN_PHP $BIN_MAGE module:disable
$BIN_PHP $BIN_MAGE module:status | grep Magento_LiveSearch | grep -v List | grep -v None | grep -v -e '^$' | xargs $BIN_PHP $BIN_MAGE module:enable
$BIN_PHP $BIN_MAGE --quiet config:set 'catalog/search/engine' NULL
$BIN_PHP $BIN_MAGE module:status | grep -E '.*ServicesId*|.*ServicesConnector*|.*DataExporter*|.*SaaS*|.*DataServices*'| xargs $BIN_PHP $BIN_MAGE module:enable
CMD="${BIN_PHP} ${BIN_MAGE} setup:upgrade"
runCommand
cat <<endmessage
${yellow}
####################################################################################
Warning: LiveSearch has been enabled.
Please proceed to the API keys configuration and Catalog data synchronization:
https://devdocs.magento.com/live-search/install.html#configure-api-keys
####################################################################################
${default}
endmessage
}
function installB2B()
{
if [ -z "$B2B_VERSION" ]
then
getB2Bversion
fi
if [ "${SOURCE}" == 'git' ] || checkIfBasedOnDevelopBranch
then
validateGitRepository "${GIT_B2B_REPO}" "${B2B_VERSION}"
CMD="[ ! -d "$B2B_VERSION" ] && ${BIN_GIT} clone --branch ${B2B_VERSION} --single-branch ${GIT_B2B_REPO} ${GIT_B2B_PATH}"
runCommand
CMD="${BIN_PHP} dev/tools/build-ee.php --ce-source $(pwd) --ee-source ${GIT_B2B_PATH}"
runCommand
CMD="rm -rf var/* generation/*"
runCommand
else
CMD="${BIN_PHP} ${BIN_COMPOSER} require magento/extension-b2b=${B2B_VERSION}"
runCommand
fi
CMD="${BIN_PHP} ${BIN_MAGE} setup:upgrade"
runCommand
}
function getB2Bversion()
{
checkIfBasedOnDevelopBranch && { B2B_VERSION="develop"; return 0; }
REAL_MAGENTO_VERSION=`${BIN_PHP} bin/magento --version`
MAGENTO_MAJOR_VERSION=`echo "${REAL_MAGENTO_VERSION}" | sed 's/.*2\.\([0-9]*\)\.\([0-9]*\).*/\1/'`
MAGENTO_MINOR_VERSION=`echo "${REAL_MAGENTO_VERSION}" | sed 's/.*2\.\([0-9]*\)\.\([0-9]*\).*/\2/'`
MAGENTO_PATCH_VERSION=`echo "${REAL_MAGENTO_VERSION}" | sed 's/.*2\.\([0-9]*\)\.\([0-9]*\).\([a-z0-9]*\)/\3/'`
if [ $MAGENTO_MAJOR_VERSION -ge 4 ] && [ $MAGENTO_MINOR_VERSION -ge 1 ]
then
B2B_VERSION_MAJOR=$(( `echo "${MAGENTO_MAJOR_VERSION}"` -1 ))
B2B_VERSION_MINOR=$(( `echo "${MAGENTO_MINOR_VERSION}"` -1 ))
else
B2B_VERSION_MAJOR=$(( `echo "${MAGENTO_MAJOR_VERSION}"` -2 ))
B2B_VERSION_MINOR=$MAGENTO_MINOR_VERSION
fi
if [ ! -z "$MAGENTO_PATCH_VERSION" ]
then
B2B_PATCH_VERSION="-${MAGENTO_PATCH_VERSION}"
fi
B2B_VERSION="1.${B2B_VERSION_MAJOR}.${B2B_VERSION_MINOR}${B2B_PATCH_VERSION}"
}
function linkEnterpriseEdition()
{
if [ "${SOURCE}" == 'composer' ]
then
return;
fi
if [ "${EE_PATH}" ] && [ "$INSTALL_EE" ]
then
if [ ! -d "$EE_PATH" ]
then
printError "There is no Enterprise Edition directory ${EE_PATH}"
printString "Use absolute or relative path to EE code base or [N] to skip it"
exit 1
fi
CMD="${BIN_PHP} ${EE_PATH}/dev/tools/build-ee.php --ce-source $(pwd) --ee-source ${EE_PATH}"
runCommand
CMD="cp ${EE_PATH}/composer.json $(pwd)/"
runCommand
CMD="cp ${EE_PATH}/composer.lock $(pwd)/"
runCommand
fi
}
function runComposerInstall()
{
CMD="${BIN_PHP} ${BIN_COMPOSER} install"
runCommand
}
function installMagento()
{
if [ "${SOURCE}" == 'git' ]
then
CMD="${BIN_PHP} ${BIN_COMPOSER} config repositories.magento composer https://repo.magento.com/"
runCommand
# Install Bundled Extensions for version 2.2.+
if [[ $MAGENTO_VERSION =~ ^2\.[^01]\..* ]]
then
for be in "${BUNDLED_EXTENSION[@]}"
do
CMD="composer require --quiet ${be}"
runCommand
done
fi
fi
CMD="rm -rf var/generation/*"
runCommand
CMD="${BIN_PHP} ${BIN_MAGE} --no-interaction setup:uninstall"
runCommand
dropDB
createNewDB
CMD="${BIN_PHP} ${BIN_MAGE} setup:install \
--base-url=${BASE_URL} \
--db-host=${DB_HOST} \
--db-name=${DB_NAME} \
--db-user=${DB_USER} \
--admin-firstname=${ADMIN_FIRSTNAME} \
--admin-lastname=${ADMIN_LASTNAME} \
--admin-email=${ADMIN_EMAIL} \
--admin-user=${ADMIN_NAME} \
--admin-password=${ADMIN_PASSWORD} \
--language=${LANGUAGE} \
--currency=${CURRENCY} \
--timezone=${TIMEZONE} \
--use-rewrites=1 \
--backend-frontname=${BACKEND_FRONTNAME}"
if [ "${DB_PASSWORD}" ]; then
CMD="${CMD} --db-password=${DB_PASSWORD}"
fi
if isElasticSearchRequired && isElasticSearchConfigIsAvailable
then
local searchEngine="$(getRecommendedSearchEngineForVersion)"
CMD="${CMD} --search-engine=$searchEngine --elasticsearch-host=$(getESConfigHost $searchEngine) --elasticsearch-port=$(getESConfigPort $searchEngine) --elasticsearch-index-prefix=${DB_NAME}"
fi
runCommand
}
function isElasticSearchRequired()
{
checkIfBasedOnDevelopBranch && return 0
versionIsHigherThan "$(getMagentoVersion)" "2.4" && return 0
return 255
}
function isElasticSearchConfigIsAvailable()
{
[[ "$ELASTICSEARCH_HOST" ]] && [[ "$ELASTICSEARCH_PORT" ]] && return 0
local searchEngine="$1"
if [[ ! "$searchEngine" ]]
then
searchEngine="$(getRecommendedSearchEngineForVersion)"
fi
local eshost=$(getESConfigHost "$searchEngine")
local esport=$(getESConfigPort "$searchEngine")
[[ "$eshost" ]] && [[ "$esport" ]] && return 0
return 255
}
function getRecommendedSearchEngineForVersion()
{
local searchEngine=
if [[ "$(getESConfigHost)" ]] && [[ "$(getESConfigPort)" ]]
then
searchEngine="$(parseElasticSearchVersion $(getESConfigHost) $(getESConfigPort))"
[[ "$searchEngine" ]] && { echo "$searchEngine"; return 0; }
fi
searchEngine=elasticsearch7
local currentMagentoVersion="$(getMagentoVersion)"
#https://devdocs.magento.com/guides/v2.4/install-gde/system-requirements.html
versionIsHigherThan "$(getMagentoVersion)" "2.3.0" && searchEngine="elasticsearch"
versionIsHigherThan "$(getMagentoVersion)" "2.3.1" && searchEngine="elasticsearch5"
versionIsHigherThan "$(getMagentoVersion)" "2.3.5" && searchEngine="elasticsearch7"
checkIfBasedOnDevelopBranch && searchEngine="elasticsearch7"
echo "$searchEngine"
return 0
}
function parseElasticSearchVersion()
{
local eshost=$1
local esport=$2
local elasticSearchVersion=$(curl -s -X GET "$eshost:$esport" | grep number | sed 's/[^0-9.]//g' | head -c 1)
[[ "$elasticSearchVersion" ]] && [[ "$elasticSearchVersion" -gt 1 ]] && { echo "elasticsearch${elasticSearchVersion}"; return 0; }
return 255
}
function getESConfigHost()
{
[[ "$ELASTICSEARCH_HOST" ]] && { echo "$ELASTICSEARCH_HOST"; return 0; }
case "$1" in
elasticsearch7)
echo "$SEARCH_ENGINE_ELASTICSEARCH7_HOST"
return 0
;;
elasticsearch6)
echo "$SEARCH_ENGINE_ELASTICSEARCH6_HOST"
return 0
;;
elasticsearch5)
echo "$SEARCH_ENGINE_ELASTICSEARCH5_HOST"
return 0
;;
elasticsearch)
echo "$SEARCH_ENGINE_ELASTICSEARCH2_HOST"
return 0
;;
esac
return 255
}
function getESConfigPort()
{
[[ "$ELASTICSEARCH_PORT" ]] && { echo "$ELASTICSEARCH_PORT"; return 0; }
case "$1" in
elasticsearch7)
echo "$SEARCH_ENGINE_ELASTICSEARCH7_PORT"
return 0
;;
elasticsearch6)
echo "$SEARCH_ENGINE_ELASTICSEARCH6_PORT"
return 0
;;
elasticsearch5)
echo "$SEARCH_ENGINE_ELASTICSEARCH5_PORT"
return 0
;;
elasticsearch)
echo "$SEARCH_ENGINE_ELASTICSEARCH2_PORT"
return 0
;;
esac
}
function getMagentoVersion()
{
local version=
[[ "$SOURCE" ]] && { version="$MAGENTO_VERSION"; echo "$version"; return 0; }
[[ -f bin/magento ]] && { echo "$(parseMagentoVersion)"; return 0; }
if [[ ! -f composer.lock ]] && foundSupportBackupFiles
then
EXTRACT_FILENAME="$(getCodeDumpFilename)"
extract "composer.lock" > /dev/null
fi
[[ -f composer.lock ]] && version=$(parseMagentoVersion "$(grep '\"name\": \"magento/product-community\|enterprise-edition\"' composer.lock -A1 | tail -n1)")
[[ "$version" ]] && { echo "$version"; return 0; }
echo "$MAGENTO_VERSION"
return 0
}
function downloadSourceCode()
{
if [ "$(ls -A ./)" ]; then
printError "Can't download source code from ${SOURCE} since current directory doesn't empty."
printString "You can remove all files from current directory using next command:"
printString "ls -A | xargs rm -rf"
exit 1;
fi
if [ "$SOURCE" == 'composer' ]
then
composerInstall
fi
if [ "$SOURCE" == 'git' ]
then
gitClone
fi
if [ "$SOURCE" == 'worktree' ]
then
gitWorktree
fi
}
function composerInstall()
{
if [ "$INSTALL_EE" ]
then
CMD="${BIN_PHP} ${BIN_COMPOSER} create-project --repository-url=https://repo.magento.com/ magento/project-enterprise-edition . ${MAGENTO_VERSION}"
runCommand
else
CMD="${BIN_PHP} ${BIN_COMPOSER} create-project --repository-url=https://repo.magento.com/ magento/project-community-edition . ${MAGENTO_VERSION}"
runCommand
fi
}
showComposerWizzard()
{
if [ "$SOURCE" != 'composer' ]
then
return;
fi
askValue "Composer Magento version" "${MAGENTO_VERSION}"
MAGENTO_VERSION=${READVALUE}
if askConfirmation "Do you want to install Enterprise Edition (y/N)"
then
INSTALL_EE=1
fi
if [[ "$INSTALL_EE" ]] && askConfirmation "Do you want install B2B Extension (y/N)"
then
INSTALL_B2B=1
fi
}
printComposerConfirmation()
{
if [ "$SOURCE" != 'composer' ]
then
return;
fi
printString "Magento code will be downloaded from composer";
printString "Composer version: $MAGENTO_VERSION";
}
function showWizzardGit()
{
if [ "$SOURCE" != 'git' ]
then
return
fi
askValue "Git CE repository" ${GIT_CE_REPO}
GIT_CE_REPO=${READVALUE}
askValue "Git EE repository" ${GIT_EE_REPO}
GIT_EE_REPO=${READVALUE}
askValue "Git branch" ${MAGENTO_VERSION}
MAGENTO_VERSION=${READVALUE}
if askConfirmation "Do you want to install Enterprise Edition (y/N)"
then
INSTALL_EE=1
fi
if [[ "$INSTALL_EE" ]] && askConfirmation "Do you want install B2B Extension (y/N)"
then
INSTALL_B2B=1
fi
}
function gitClone()
{
validateGitRepository "${GIT_CE_REPO}" "${MAGENTO_VERSION}"
validateGitRepository "${GIT_EE_REPO}" "${MAGENTO_VERSION}"
CMD="${BIN_GIT} clone --branch $MAGENTO_VERSION $GIT_CE_REPO ."
runCommand
if [[ "$GIT_EE_REPO" ]] && [[ "$INSTALL_EE" ]]
then
CMD="${BIN_GIT} clone --branch $MAGENTO_VERSION $GIT_EE_REPO $EE_PATH"
runCommand
fi
}
function gitWorktree()
{
local currentDir=$(pwd);
local worktreeCEPath="$(getWorktreePath CE)"
validateGitRepository "${worktreeCEPath}" "$MAGENTO_VERSION"
cd "$worktreeCEPath"
CMD="git worktree add $currentDir $MAGENTO_VERSION"
runCommand
if [[ "$INSTALL_EE" ]]
then
cd "$currentDir"
local worktreeEEPath="$(getWorktreePath EE)"
validateGitRepository "${worktreeEEPath}" "$MAGENTO_VERSION"
cd "$worktreeEEPath"
CMD="git worktree add ${currentDir}/${EE_PATH} $MAGENTO_VERSION"
runCommand
fi
cd "$currentDir"
}
function getWorktreePath()
{
local ee=${1:-CE}
local configName="CONFIG_GIT_WORKTREE_${ee}_PATH"
local defaultValue="../repo"
[ "$ee" == "EE" ] && defaultValue="../repo/magento2ee"
if [ -z ${!configName} ]
then
eval "read -p \"Git Worktree requires path to local GIT ${ee} repository (Default: ${defaultValue}): \" ${configName}"
fi
echo "${!configName:-${defaultValue}}";
}
function validateGitRepository()
{
local repoName=$1
local versionName=$2
local isBranchExists=$(${BIN_GIT} ls-remote ${repoName} | grep -F ${versionName})
if [ ! "$isBranchExists" ]
then
printError "Requested tag or branch ${versionName} does not exists in ${repoName}"
exit 1;
fi
}
function printGitConfirmation()
{
if [ "$SOURCE" != 'git' ]
then
return
fi
printString "Magento code will be downloaded from GIT";
printString "Git CE repository: ${GIT_CE_REPO}"
printString "Git EE repository: ${GIT_EE_REPO}"
printString "Git branch: ${MAGENTO_VERSION}"
if [[ ! -z $INSTALL_B2B ]]
then
printString "Git B2B repository: ${GIT_B2B_REPO}"
printString "Git B2B branch: ${B2B_VERSION}"
fi
}
function checkArgumentHasValue()
{
if [ ! "$2" ]
then
printError "$1 Argument is empty."
printLine
printUsage
exit
fi
}
function isInputNegative()
{
if [[ $1 = [Nn][oO] ]] || [[ $1 = [Nn] ]] || [[ $1 = [0] ]]
then
return 0;
else
return 1;
fi
}
function validateStep()
{
local _step=$1;
local _steps="restore_db restore_code configure_db configure_files configure installB2B installLiveSearch add_remote"
if echo "$_steps" | grep -q "$_step"
then
if type -t "$_step" &>/dev/null
then
return 0;
fi
fi
return 1;
}
function prepareSteps()
{
local _step;
local _steps;
_steps=(${STEPS[@]//,/ })
STEPS=
for _step in "${_steps[@]}"
do
if validateStep "$_step"
then
addStep "$_step"
fi
done
}
function addStep()
{
local _step=$1
STEPS+=($_step)
}
function setProductionMode()
{
CMD="${BIN_PHP} ${BIN_MAGE} deploy:mode:set production"
runCommand
}
function setFilesystemPermission()
{
CMD="chmod u+x ./bin/magento"
runCommand
local _writeableDirectories="./var ./pub/media ./pub/static ./app/etc"
if [ -d './generated' ]
then
_writeableDirectories="$_writeableDirectories ./generated"
fi
CMD="chmod -R 2777 ${_writeableDirectories}"
runCommand
}
function executePostDeployScript()
{
if [ ! "$(getRequest skipPostDeploy)" ] && [ -f "$1" ]
then
printString "==> Run the post deploy $1"
source "$1";
printString "==> Post deploy script has been finished"
fi
return 0;
}
function warmCache()
{
local home_url=${BASE_URL}
local home_response_code="$(curl --insecure --location --write-out '%{http_code}' --silent --output /dev/null $home_url)"
local admin_url="${BASE_URL}${BACKEND_FRONTNAME}"
local admin_response_code="$(curl --insecure --location --write-out '%{http_code}' --silent --output /dev/null $admin_url)"
local mode=install
local currentUser="$(whoami)"
local dir="$(pwd)"
local currentScript="$BASH_SOURCE"
if foundSupportBackupFiles
then
mode=restore
fi
END_TIME=$(date +%s)
SUMMARY_TIME=$((((END_TIME - START_TIME)) / 60));
printString "Cache warm up ${home_url}. Response code: $home_response_code"
printString "Cache warm up ${admin_url}. Response code: $admin_response_code"
printString "$(basename "$0") took $SUMMARY_TIME minutes to complete install/deploy process"
writeCsvMetricRow "$(date '+%Y-%m-%d %H:%M:%S'), $mode, $home_response_code, $home_url, $admin_response_code, $admin_url, $SUMMARY_TIME, $currentUser, $dir, $currentScript, \"$GLOBAL_ARGS\""
}
function afterInstall()
{
disableTwoFactorAuthModules
if [[ "$MAGE_MODE" == "production" ]]
then
setProductionMode
fi
executePostDeployScript "$(getScriptDirectory)/post-deploy"
executePostDeployScript "$HOME/post-deploy"
setFilesystemPermission
if [ -z "$REMOTE_DB" ]
then
appConfigImport
fi
if isPubRequired
then
CMD="sed -i '/RewriteRule\ .*\ \/pub\/\$0 \[L\]/d' .htaccess"
runCommand
CMD="cp pub/index.php index.php && sed -i 's/\/..\/app\/bootstrap.php/\/app\/bootstrap.php/g' index.php"
runCommand
fi
warmCache
}
function disableTwoFactorAuthModules()
{
disableModule 'Magento_TwoFactorAuth'
disableModule 'MarkShust_DisableTwoFactorAuth'
disableModule 'WolfSellers_EnableDisableTfa'
}
function disableModule()
{
local moduleName=$1
$BIN_PHP $BIN_MAGE module:status $moduleName | grep -q 'Module is enabled' && $BIN_PHP $BIN_MAGE module:disable $moduleName && echo "$moduleName is being disabled"
}
function disableModuleInConfigFile()
{
local modulePattern=$1
if [ -f app/etc/config.php ]
then
grep -iEo "['\"][a-z0-9]+_[a-z0-9]+['\"]\s*?=>\s*?1,?" app/etc/config.php | grep -iEo "['\"].*$modulePattern.*['\"]" | while read -r module ; do
echo "Module $module will be disabled in config.php"
CMD="sed -iE \"s/($module.*=>.*)[10]{1}/\\1 0/g\" app/etc/config.php"
runCommand
done
fi
}
function executeSteps()
{
local _steps=("$@")
for step in "${_steps[@]}"
do
if [ "${step}" ]
then
CMD="${step}"
runCommand "=> "
fi
done
}
function printUsage()
{
cat <<EOF
$(basename "$0") is designed to simplify the installation process of Magento 2
and deployment of client dumps created by Magento 2 Support Extension.
Usage: $(basename "$0") [options]
Options:
-h, --help Get this help.
-s, --source (git, composer) Get source code.
-f, --force Install/Restore without any confirmations.
--sample-data (yes, no) Install sample data.
--ee Install Enterprise Edition.
--b2b Install B2B Extension.
-v, --version Magento Version - it means: Composer version or GIT Branch
--mode (dev, prod) Magento Mode. Dev mode does not generate static & di content.
--quiet Quiet mode. Suppress output all commands
--skip-post-deploy Skip the post deploy script if it is exist
--skip-post-overwrite Skip the post orginal files overwrite actions
--step (restore_code,restore_db Specify step through comma without spaces.
configure_db,configure_files - Example: $(basename "$0") --step restore_db,configure_db
installB2B --b2b - Example: $(basename "$0") --step installB2B --b2b
installLiveSearch) - Example: $(basename "$0") --step installLiveSearch
--restore-table Restore only the specific table from DB dumps
--debug Enable debug mode
--php Specify path to PHP CLI (php71 or /usr/bin/php71)
--remote-db Remote database name
--es-host, --elasticsearch-host Set the Elasticsearch host
--es-port, --elasticsearch-port Set the Elasticsearch port
--uninstall Delete database and application from the current folder
_________________________________________________________________________________________________
--ee-path (/path/to/ee) (DEPRECATED use --ee flag) Path to Enterprise Edition.
EOF
}
function uninstallAction()
{
dropES
cleanupCurrentDirectory
dropDB
}
function processOptions()
{
while [[ $# -gt 0 ]]
do
case "$1" in
-s|--source)
checkArgumentHasValue "$1" "$2"
SOURCE="$2"
shift
;;
-d|--sample-data)
checkArgumentHasValue "$1" "$2"
if isInputNegative "$2"
then
USE_SAMPLE_DATA=
else
USE_SAMPLE_DATA="$2"
fi
shift
;;
-e|--ee-path)
# @DEPRECATED. Use --ee instead.
checkArgumentHasValue "$1" "$2"
EE_PATH="$2"
INSTALL_EE=1
shift
;;
--ee)
INSTALL_EE=1
;;
--b2b)
INSTALL_B2B=1
if [[ "$2" =~ ^- ]]
then
B2B_VERSION=
else
B2B_VERSION="$2"
shift
fi
;;
-b|--git-branch)
# @DEPRECATED. Use -v or --version instead
checkArgumentHasValue "$1" "$2"
MAGENTO_VERSION="$2"
shift
;;
-v|--version)
checkArgumentHasValue "$1" "$2"
MAGENTO_VERSION="$2"
shift
;;
--mode)
checkArgumentHasValue "$1" "$2"
MAGE_MODE=$2
shift
;;
-f|--force)
FORCE=1
USE_WIZARD=0
;;
--websites)
generateWebsites
exit 0;
;;
--quiet)
VERBOSE=0
;;
--skip-post-deploy)
setRequest skipPostDeploy 1
;;
--skip-post-overwrite)
setRequest skipPostOverwrite 1
;;
-h|--help)
printUsage
exit;
;;
--uninstall)
uninstallAction
exit;
;;
--code-dump)
checkArgumentHasValue "$1" "$2"
setRequest codedump "$2"
shift
;;
--db-dump)
checkArgumentHasValue "$1" "$2"
setRequest dbdump "$2"
shift
;;
--restore-table)
checkArgumentHasValue "$1" "$2"
setRequest restoreTableName "$2"
shift
;;
--step)
checkArgumentHasValue "$1" "$2"
STEPS=($2)
shift
;;
--debug)
set -o xtrace;
;;
--php)
checkArgumentHasValue "$1" "$2"
BIN_PHP=$2
shift
;;
--remote-db)
checkArgumentHasValue "$1" "$2"
REMOTE_DB=$2
shift
;;
--es-host|--elasticsearch-host)
checkArgumentHasValue "$1" "$2"
ELASTICSEARCH_HOST=$2
shift
;;
--es-port|--elasticsearch-port)
checkArgumentHasValue "$1" "$2"
ELASTICSEARCH_PORT=$2
shift
;;
esac
shift
done
}
function cleanupCurrentDirectory()
{
local currentDirectory="$(pwd)"
local homeDirectory="$(cd ~; pwd)"
if [[ "$currentDirectory" == "$homeDirectory" ]]
then
printError "Current Directory is home ($currentDirectory)"
exit 1;
fi
if [ "$(ls -A)" ] && askConfirmation "Current directory is not empty. Do you want to clean current Directory (y/N)"
then
CMD="ls -A | xargs rm -rf"
runCommand
fi
}
function versionIsHigherThan()
{
local defaultVersion="2.4"
local mageVersion="$MAGENTO_VERSION"
[[ "$1" ]] && mageVersion="$1"
[[ "$2" ]] && defaultVersion="$2"
local esRequired=$(php -r "echo (version_compare('$mageVersion', '$defaultVersion') >= 0) ? 'REQUIRED' : 'NO';")
[[ "$esRequired" == "REQUIRED" ]] && return 0;
return 1;
}
function validateElasticSearchIsAvailable()
{
[[ ! "$ELASTICSEARCH_HOST" ]] && ELASTICSEARCH_HOST="$(getESConfigHost $(getRecommendedSearchEngineForVersion))"
[[ ! "$ELASTICSEARCH_PORT" ]] && ELASTICSEARCH_PORT="$(getESConfigPort $(getRecommendedSearchEngineForVersion))"
[[ ! "$ELASTICSEARCH_HOST" ]] && ELASTICSEARCH_HOST="localhost"
[[ ! "$ELASTICSEARCH_PORT" ]] && ELASTICSEARCH_PORT="9200"
if curl -s -XGET ${ELASTICSEARCH_HOST}:${ELASTICSEARCH_PORT} | grep -q "number"; then
printString "ElasticSearch is available on ${ELASTICSEARCH_HOST}:${ELASTICSEARCH_PORT}."
return 0;
fi
printError "ElasticSearch is required for version 2.4.x.";
printError "ElasticSearch is not available on ${ELASTICSEARCH_HOST}:${ELASTICSEARCH_PORT}."
printErrorAndExit 300 "Use parameters to specify Elasticsearch --es-host <HOST> --es-port <PORT>"
}
################################################################################
# Action Controllers
################################################################################
function magentoInstallAction()
{
isElasticSearchRequired && validateElasticSearchIsAvailable
if [[ "${SOURCE}" ]]
then
cleanupCurrentDirectory
addStep "downloadSourceCode"
fi
addStep "linkEnterpriseEdition"
addStep "runComposerInstall"
addStep "installMagento"
if [[ "${USE_SAMPLE_DATA}" ]]
then
addStep "installSampleData"
fi
if [[ "$INSTALL_EE" ]] && [[ "$INSTALL_B2B" ]]
then
addStep "installB2B"
fi
}
function magentoDeployDumpsAction()
{
addStep "restore_code"
addStep "configure_files"
if [[ "$REMOTE_DB" ]]
then
addStep "add_remote"
else
addStep "restore_db"
addStep "configure_db"
addStep "validateDeploymentFromDumps"
addStep "configurePWA"
fi
}
function restoreTableAction()
{
CMD="{ echo 'SET FOREIGN_KEY_CHECKS=0;';
echo 'TRUNCATE ${DB_NAME}.$(getTablePrefix)$(getRequest restoreTableName);';
zgrep 'INSERT INTO \`$(getRequest restoreTableName)\`' $(getDbDumpFilename); }
| ${BIN_MYSQL} -h${DB_HOST} -u${DB_USER} --password=\"${DB_PASSWORD}\" --force $DB_NAME";
runCommand
}
function magentoCustomStepsAction()
{
prepareSteps
}
function generateWebsites()
{
[ -z "$(getWebsites)" ] && echo "There is no additional websites" && return 0;
prepareBaseURL
[ ! -d websites ] && mkdir websites
[ -f websites/index.php ] && rm websites/index.php
for websiteCode in $(getWebsites)
do
local websiteDir="websites/${websiteCode}"
createFileStructure "$websiteDir" && echo "Creating directory $websiteDir"
updateWebsiteIndexFile "$websiteCode"
createSymlinks "$websiteDir"
local baseUrl="${BASE_URL}${websiteDir}/"
generateWebsiteList "${websiteCode}" && echo "$baseUrl"
updateWebsiteBaseUrls "${websiteCode}"
done
echo "Websites list: ${BASE_URL}websites/"
${BIN_PHP} bin/magento cache:flush -q && echo "Flushing cache"
}
function createSymlinks()
{
local websiteDir="$1"
[ ! -L "`pwd`/${websiteDir}/pub" ] && ln -s `pwd`/pub "`pwd`/${websiteDir}/pub"
}
function generateWebsiteList()
{
local websiteCode="$1"
local websiteDir="websites/${websiteCode}/";
echo "<li><a href=\"${websiteCode}/\">${websiteDir}</a> (Store ID: $(getWebsiteIdByCode ${websiteCode}))</li>" >> websites/index.php
}
function updateWebsiteIndexFile()
{
local websiteCode="$1"
local websiteDir="websites/${websiteCode}";
local codeLine='$_SERVER[\\Magento\\Store\\Model\\StoreManager::PARAM_RUN_CODE] = '"'${websiteCode}';";
local typeLine='$_SERVER[\\Magento\\Store\\Model\\StoreManager::PARAM_RUN_TYPE] = '"'website';";
sed -i "36 i ${codeLine}" "${websiteDir}/index.php"
sed -i "37 i ${typeLine}" "${websiteDir}/index.php"
sed -i "s/[\/]app[\/]bootstrap[.]php/\/..\/..\/app\/bootstrap.php/" "${websiteDir}/index.php"
}
function createFileStructure()
{
local websiteDir="$1";
[ ! -d "${websiteDir}" ] && mkdir "${websiteDir}";
cp -f index.php "${websiteDir}/index.php"
}
function updateWebsiteBaseUrls()
{
local websiteCode="$1"
local websiteDir="websites/${websiteCode}";
local baseUrl="${BASE_URL}${websiteDir}/"
SQLQUERY="INSERT INTO ${DB_NAME}.$(getTablePrefix)core_config_data (config_id, scope, scope_id, path, value)
SELECT NULL, 'websites' AS scope, website_id, 'web/unsecure/base_url' AS path, '${baseUrl}' AS new_url
FROM ${DB_NAME}.$(getTablePrefix)store_website WHERE code = '${websiteCode}'
ON DUPLICATE KEY UPDATE value = '${baseUrl}'"
output="$(mysqlQuery)"
}
function getWebsites()
{
local output=
SQLQUERY="SELECT code FROM ${DB_NAME}.$(getTablePrefix)store_website WHERE website_id <> 0 AND is_default = 0";
output="$(mysqlQuery)"
echo "$output" | tail -n+3
}
function getAllWebsites()
{
local output=
SQLQUERY="SELECT code FROM ${DB_NAME}.$(getTablePrefix)store_website";
output="$(mysqlQuery)"
echo "$output" | tail -n+3
}
function getAllStores()
{
local output=
SQLQUERY="SELECT code FROM ${DB_NAME}.$(getTablePrefix)store";
output="$(mysqlQuery)"
echo "$output" | tail -n+3
}
function getAllTables()
{
local output=
SQLQUERY="SHOW TABLES FROM $DB_NAME LIKE '$1'"
output="$(mysqlQuery)"
echo "$output" | tail -n+2
}
function getWebsiteIdByCode()
{
local websiteCode="$1"
local output=
SQLQUERY="SELECT website_id FROM ${DB_NAME}.$(getTablePrefix)store_website WHERE code = '${websiteCode}'";
output="$(mysqlQuery)"
echo "$output" | tail -n+3
}
function parseMagentoVersion()
{
local valueToParse=""
if [ "$1" ]
then
valueToParse="$1"
else
valueToParse="$(${BIN_PHP} bin/magento -V)"
fi
echo "$valueToParse" | grep -oEh "[0-9\.-]+p*[0-9]*" | head -n1
}
################################################################################
# Tests
################################################################################
function assertEqual()
{
local expected=${1:-}
local current=${2:-}
if [[ "$1" == "$2" ]]
then
echo -n "."
return 0;
else
echo "===> Tests are failed."
echo "Expected [${expected}] but current [${current}]"
exit 1;
fi
}
function runTests()
{
echo "tests";
testMagentoVersionIsRequiredElasticSearch
testParseMagentoVersion
echo ""
echo "Tests completed"
exit 0;
}
function testMagentoVersionIsRequiredElasticSearch()
{
versionIsHigherThan "2.4.1"
local result="$?"
assertEqual "0" "$result"
versionIsHigherThan "2.3.1"
local result="$?"
assertEqual "1" "$result"
versionIsHigherThan "2.1.1-p2"
local result="$?"
assertEqual "1" "$result"
versionIsHigherThan "2.4.1-p2"
local result="$?"
assertEqual "0" "$result"
versionIsHigherThan "2.4.2" "2.4.2"
local result="$?"
assertEqual "0" "$result"
versionIsHigherThan "2.4.3" "2.4.2"
local result="$?"
assertEqual "0" "$result"
versionIsHigherThan "2.4.1" "2.4.2"
local result="$?"
assertEqual "1" "$result"
}
function testParseMagentoVersion()
{
local result=$(parseMagentoVersion "Magento CLI 2.3.4")
assertEqual "2.3.4" "$result"
local result=$(parseMagentoVersion "Magento CLI 2.4.4")
assertEqual "2.4.4" "$result"
local result=$(parseMagentoVersion "Magento CLI 2.4.4-p1")
assertEqual "2.4.4-p1" "$result"
local result=$(parseMagentoVersion "Magento CLI 2.2.4-p10")
assertEqual "2.2.4-p10" "$result"
}
################################################################################
# Main
################################################################################
export LC_CTYPE=C
export LANG=C
function main()
{
if [[ $1 == "--test" ]]
then
runTests;
exit 0;
fi
loadConfigFile $(getConfigFiles)
processOptions "$@"
initQuietMode
printString Current Directory: "$(pwd)"
printString "Configuration loaded from: $(getConfigFiles)"
checkDependencies
showWizard
START_TIME=$(date +%s)
if [[ "${STEPS[@]}" ]]
then
magentoCustomStepsAction;
elif foundSupportBackupFiles
then
if getRequest restoreTableName
then
restoreTableAction
else
magentoDeployDumpsAction;
fi
else
magentoInstallAction;
fi
addStep "afterInstall"
executeSteps "${STEPS[@]}"
printLine
printString "${BASE_URL}"
printString "${BASE_URL}${BACKEND_FRONTNAME}"
printString "User: ${ADMIN_NAME}"
printString "Pass: ${ADMIN_PASSWORD}"
}
main "${@}"