#!/usr/bin/env bash

# Microsoft Azure Linux Agent
#
# Copyright 2018 Microsoft Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

#
# Installs the tools in ~/bin/scripts/* to ~/bin, as well as Pypy.
#
# It also makes Pypy the default python for the current user.
#

set -euo pipefail

PATH="$HOME/bin:$PATH"

printf "\n========== Installing test tools ==========\n\n"

echo "========== Python info"
python=$(get-agent-python)
echo "Python executable: $python"
echo "Python version: $($python --version)"

#
# Install Pypy as ~/bin/pypy3
#
# Note that bzip2/lbzip2 (used by tar to uncompress *.bz2 files) are not available by default in some distros;
# use Python to uncompress the Pypy tarball.
#
echo "========== Installing Pypy 3.7"
$python ~/bin/uncompress.py ~/tmp/pypy3.7-*.tar.bz2 ~/tmp/pypy3.7.tar
tar xf ~/tmp/pypy3.7.tar -C ~/bin
echo "Pypy was installed in $(ls -d ~/bin/pypy*)"
echo "Creating symbolic link to Pypy at ~/bin/pypy3"
ln -vs ~/bin/pypy*/bin/pypy3.7 ~/bin/pypy3

#
# The 'distro' and 'platform' modules in Pypy have small differences with the ones in the system's Python.
# This can create problems in tests that use the get_distro() method in the Agent's 'version.py' module.
# To work around this, we copy the system's 'distro' module to Pypy.
#
# In the case of 'platform', the 'linux_distribution' method was removed on Python 3.7 so we check the
# system's module and, if the method does not exist, we also remove it from Pypy. Ubuntu 16 and 18 are
# special cases in that the 'platform' module in Pypy identifies the distro as 'debian';
# Alma 8 identifies the distro as 'centos'; in this case we copy the system's 'platform' module to Pypy.
#
distro_path=$($python -c '
try:
    import distro
except:
    exit(0)
print(distro.__file__.replace("__init__.py", "distro.py"))
exit(0)
')
if [[ "$distro_path" != "" ]]; then
  echo "Copying the system's distro module to Pypy"
  cp -v "$distro_path" ~/bin/pypy*/site-packages
else
  echo "The distro module is not is not installed on the system; skipping."
fi

has_linux_distribution=$($python -c 'import platform; print(hasattr(platform, "linux_distribution"))')
if [[ "$has_linux_distribution" == "False" ]]; then
  echo "Python does not have platform.linux_distribution; removing it from Pypy"
  sed -i 's/def linux_distribution(/def __linux_distribution__(/' ~/bin/pypy*/lib-python/3/platform.py
else
  echo "Python has platform.linux_distribution"
  uname=$(uname -v)
  test -f /etc/almalinux-release && grep -qiE "AlmaLinux .*release 8\." /etc/almalinux-release # Only Alma 8 requires the patch (file contents are similar to "AlmaLinux release 8.10 (Cerulean Leopard)")
  alma_linux=$?
  test -f /etc/oracle-release && grep -qiE "Oracle .*release 8\." /etc/oracle-release && true # Only Oracle 8 requires the patch (file contents are similar to "Oracle Linux Server release 8.10")
  oracle_linux=$?
  if [[ "$uname" == *~18*-Ubuntu* || "$uname" == *~16*-Ubuntu* || "$alma_linux" == "0"  || "$oracle_linux" == "0" ]]; then
    echo "Copying the system's platform module to Pypy"
    pypy_platform=$(pypy3 -c 'import platform; print(platform.__file__)')
    python_platform=$($python -c 'import platform; print(platform.__file__)')
    cp -v "$python_platform" "$pypy_platform"
  fi
fi

#
# Now install the test Agent as a module package in Pypy.
#
echo "========== Installing Agent modules to Pypy"
unzip.py ~/tmp/WALinuxAgent-*.zip ~/tmp/WALinuxAgent
unzip.py ~/tmp/WALinuxAgent/bin/WALinuxAgent-*.egg ~/tmp/WALinuxAgent/bin/WALinuxAgent.egg
mv -v ~/tmp/WALinuxAgent/bin/WALinuxAgent.egg/azurelinuxagent ~/bin/pypy*/site-packages

#
# Validate that get_distro() returns the same value when called from Pypy (used by the tests) and the system Python (used by the Agent).
# Any difference could cause different of behavior between the tests and the Agent.
#
echo "========== Validating Pypy using get_distro()"
pypy_get_distro=$(pypy3 -c 'from azurelinuxagent.common.version import get_distro; print(get_distro())')
python_get_distro=$($python -c 'from azurelinuxagent.common.version import get_distro; print(get_distro())')
echo "Pypy   get_distro(): $pypy_get_distro"
echo "Python get_distro(): $python_get_distro"
if [[ "$pypy_get_distro" != "$python_get_distro" ]]; then
  echo "*** WARNING: azurelinuxagent.common.version.get_distro() returns different values in Pypy and Python. This can lead to subtle test bugs."
else
  echo "get_distro() is consistent across Pypy and the system Python"
fi

#
# Create ~/bin/set-agent-env to set PATH and PYTHONPATH.
#
# We append $HOME/bin to PATH and set PYTHONPATH to $HOME/lib (bin contains the scripts used by tests, while
# lib contains the Python libraries used by tests).
#
echo "========== Setting up environment"
echo "Creating ~/bin/set-agent-env to set PATH and PYTHONPATH"

echo "
if [[ \$PATH != *\"$HOME/bin\"* ]]; then
  PATH=\"$HOME/bin:\$PATH:\"
fi

export PYTHONPATH=\"$HOME/lib\"
" > ~/bin/set-agent-env

chmod u+x ~/bin/set-agent-env

#
# Add ~/bin/set-agent-env to .bash_profile to simplify interactive debugging sessions
#
# Note that in some distros .bash_profile is a symbolic link to a read-only file. Make a copy in that case.
#
echo "Adding ~/bin/set-agent-env to ~/.bash_profile"
if test -e ~/.bash_profile && ls -l .bash_profile | grep '\->'; then
  cp ~/.bash_profile ~/.bash_profile-bk
  rm ~/.bash_profile
  mv ~/.bash_profile-bk ~/.bash_profile
fi
if ! test -e ~/.bash_profile || ! grep '~/bin/set-agent-env' ~/.bash_profile > /dev/null; then
  echo 'source ~/bin/set-agent-env
' >> ~/.bash_profile
fi
