#!/bin/bash
#
# Installation script for Cirata build of Apache Subversion binaries.
# Copyright (C) 2013-2023 WANdisco plc
# Copyright (C) 2023-2025 Cirata plc
#
# Please contact opensource@cirata.com if you have any problems with this
# script.

set -e

SVN_VERSION=1.14.5-1
REPO_SERVER=${REPO_SERVER:-opensource.cirata.com}
ARCH=$(uname -m)
DNF_MODULE=

# Functions

handle_error() {
  echo
  echo "There has been an error, exiting"
  exit 2
}

check_connection() {
  if command -v curl > /dev/null 2>&1; then
    GET='curl -s -f'
  elif command -v wget > /dev/null 2>&1; then
    GET='wget -O - -q'
  else
    echo -n "You do not have curl or wget installed. At least one of these is "
    echo    "required to install Apache Subversion from Cirata"
    exit 1
  fi
}

check_root() {
  test $EUID -eq 0 ||
  {
    echo "You need to be root to install Apache Subversion binaries built by Cirata."
    echo
    echo "Please re-run this script as the root user."
    exit 1
  }
}

unsupported() {
  echo "Your operating system is not currently supported."
  echo
  echo -n "Please visit https://www.cirata.com/subversion/download for a list"
  echo    " of supported systems."
  exit 1
}

confirm() {
  local confirm=
  local message=$1
  local default=${2:-y}
  local prompt=

  test -n "${NON_INTERACTIVE:-}" && return 0

  prompt="$message ("
  if test "$default" = "y"; then
    prompt="${prompt}Y/n"
  else
    prompt="${prompt}y/N"
  fi
  prompt="$prompt) "

  while test "$confirm" != "$default"; do
    read -r -n 1 -p "$prompt" confirm
    echo
    confirm=${confirm:-$default}
    confirm=${confirm/Y/y}
    confirm=${confirm/N/n}

    if test "$default" = "y"; then
      test "$confirm" = "n" && return 1
      test "$confirm" = "y" && return 0
    else
      test "$confirm" = "y" && return 1
      test "$confirm" = "n" && return 0
    fi

    echo "Invalid input, please enter 'y' or 'n'"
  done
  return 0
}

remove_other() {
  local other=$1

  echo -n "You currently have subversion installed for another architecture "
  echo -n "($other). This should be removed before installing "
  echo    "Apache Subversion."
  echo

  if ! confirm "Remove Subversion $other?"; then
    echo "Exiting at user request"
    exit 1
  fi

  case $OS in
    rhel|centos) yum erase -y "subversion.$other" ;;
    debian|ubuntu) apt-get -y --purge remove "libsvn1:$other" ;;
    suse) zypper rm -y "subversion.$other" ;;
  esac

  return 0
}

check_alternative_arch() {
  local other=
  local confirm=

  case $OS in
    centos|rhel|suse)
      for foreign in $(rpm --showrc | awk -F: '/compatible archs/{print $2}')
      do
        test "$foreign" = "$ARCH" && continue
        if other=$(rpm -q --queryformat='%{arch}' \
          "subversion.$foreign" 2>/dev/null); then
          test -z "$other" && continue
          remove_other "$other"
          unset other
        fi
      done
    ;;
    debian|ubuntu)
      dpkg --print-foreign-architectures >/dev/null 2>&1 || return 0
      ARCH=$(dpkg --print-architecture)
      for foreign in $(dpkg --print-foreign-architectures); do
        if other=$(dpkg-query -f '${Architecture}' -W "libsvn1:$foreign" \
          2>/dev/null); then
          remove_other "$other"
          unset other
        fi
      done
    ;;
  esac

  test -z "$other" && return 0


  return 0
}

is_lsb() {
  which lsb_release >/dev/null 2>&1 || return 1

  OS=$(lsb_release -si | tr '[:upper:]' '[:lower:]')
  OS=${OS%% *}
  OSVER=$(lsb_release -sr)
  OSVER=${OSVER%%.*}
  OSNAME=$(lsb_release -sc | tr '[:upper:]' '[:lower:]')

  case $OS in
    redhat*|rocky*|alma*)
      OS=rhel
    ;;
    oracle*)
      OS=rhel
    ;;
  esac

  return 0
}

is_debian() {
  test -r /etc/debian_version || return 1

  OS="debian"
  OSVER=$(cat /etc/debian_version)
  OSVER=${OSVER%%.*}
  case "$OSVER" in
    6) OSNAME="squeeze" ;;
    7) OSNAME="wheezy" ;;
    8) OSNAME="jessie" ;;
    9) OSNAME="stretch" ;;
    10) OSNAME="buster" ;;
    11) OSNAME="bullseye" ;;
    12) OSNAME="bookworm" ;;
    squeeze) OSNAME=$OSVER; OSVER=6 ;;
    wheezy) OSNAME=$OSVER; OSVER=7 ;;
    jessie) OSNAME=$OSVER; OSVER=8 ;;
    stretch) OSNAME=$OSVER; OSVER=9 ;;
    buster) OSNAME=$OSVER; OSVER=10 ;;
    bullseye) OSNAME=$OSVER; OSVER=11 ;;
    bookworm) OSNAME=$OSVER; OSVER=12 ;;
    *) return 1 ;;
  esac

  return 0
}

is_os_release() {
  local os_id

  test -r /etc/os-release || return 1

  os_id="$(. /etc/os-release; echo "${ID:-}")"

  case "$os_id" in
    sles) OS="suse" ;;
    *) OS="$os_id" ;;
  esac

  OSVER="$(. /etc/os-release; echo "${VERSION_ID%%.*}")"
  OSNAME="$(. /etc/os-release; echo "${VERSION_CODENAME:-}")"
}

is_redhat() {
  local release=

  test -r /etc/redhat-release || return 1

  release=$(tr '[:upper:]' '[:lower:]' </etc/redhat-release)
  OS=${release%% release *}
  OSVER=${release##* release }
  OSVER=${OSVER%%.*}

  case "$OS" in
    red*|rocky*|alma*) OS="rhel" ;;
    centos*) OS="centos" ;;
    *) return 1 ;;
  esac

  return 0
}

is_suse() {
  test -r /etc/SuSE-release || return 1

  OS="suse"
  OSVER=$(awk '$1 == "VERSION" {print $NF}' /etc/SuSE-release)
  OSVER=${OSVER%%.*}

  return 0
}

is_oracle() {
  test -r /etc/oracle-release || return 1

  OS="rhel"
  OSVER=$(sed -e 's/.*release \([0-9]+\).*/\1/' /etc/oracle-release)

  return 0
}

find_os() {
  is_lsb && return 0
  is_redhat && return 0
  is_debian && return 0
  is_suse && return 0
  is_oracle && return 0
  is_os_release && return 0

  return 1
}

check_os() {
  case $OS in
    rhel|centos)
      case $OSVER in
        7|8|9) return 0 ;;
      esac
    ;;
    suse)
      case $OSVER in
        12|15) return 0 ;;
      esac
    ;;
    debian)
      case $OSVER in
        10|11|12) return 0 ;;
      esac
    ;;
    ubuntu)
      case $OSVER in
        20|22|24) return 0 ;;
      esac
    ;;
  esac

  return 1
}

find_pkg_version() {
  case $OS in
    rhel|centos|suse)
      if ! PKG_VERSION=$(rpm -q --queryformat='%{version}-%{release}' \
        "subversion.$ARCH" 2>/dev/null); then
        return 1
      fi
    ;;
    debian|ubuntu)
      PKG_VERSION=$(dpkg-query -f='${Version}' -W subversion 2>/dev/null)
      PKG_VERSION=${PKG_VERSION%%+*}
    ;;
  esac

  return 0
}

check_install() {
  if ! SVN=$(svn --version --quiet 2>/dev/null); then
    echo "This script will install Subversion $SVN_VERSION."
    echo
    if ! confirm "Do you want to continue?"; then
      echo
      echo "Exiting at user request"
      exit 1
    fi
    return 0
  fi

  find_pkg_version ||
  {
    echo -n "You currently have Subversion $SVN installed, however it's not "
    echo -n "been installed with your systems package manager. Please remove "
    echo    "this version of Subversion and re-run this script."
    echo
    exit 2
  }

  if test "$PKG_VERSION" = "$SVN_VERSION"; then
    echo "You currently have the latest version of Subversion installed."
    exit 0
  fi

  echo -n "You currently have Subversion $PKG_VERSION installed. If you "
  echo "continue with the installation it will be upgraded to $SVN_VERSION."
  echo

  if ! confirm "Do you want to continue?"; then
    echo
    echo "Exiting at user request"
    exit 1
  fi

  return 0
}

configure_apt_repo() {
  export DEBIAN_FRONTEND=noninteractive
  export DEBCONF_PRIORITY=critical
  PKG_INSTALLER="apt-get -y install"

  SVN_RELEASE=${SVN_VERSION%.*}
  SVN_RELEASE="svn${SVN_RELEASE//\./}"
  rm -f /etc/apt/sources.list.d/WANdisco.list
  cat <<EOF > "/etc/apt/sources.list.d/Cirata-$SVN_RELEASE.list"
# Cirata Open Source Repo
deb https://$REPO_SERVER/$OS $OSNAME $SVN_RELEASE
EOF

  KEY_URL="https://$REPO_SERVER/wandisco-debian-new.gpg"
  $GET -q -O - "$KEY_URL" | apt-key add -
  apt-get update

  case "$OSNAME" in
    focal|buster ) PKG_LIST=(subversion libsvn-perl python-subversion subversion-tools) ;;
    * ) PKG_LIST=(subversion libsvn-perl python3-subversion subversion-tools) ;;
  esac
}


configure_yum_repo() {
  PKG_INSTALLER="yum install -y"
  PKG_LIST=("subversion.$ARCH" subversion-perl subversion-tools)
  SVN_RELEASE="${SVN_VERSION%.*}"
  rm -f /etc/yum.repos.d/WANdisco.repo /etc/yum.repos.d/WANdisco-rhel?.repo
  cat <<EOF > "/etc/yum.repos.d/Cirata-svn$SVN_RELEASE.repo"
[Cirata-svn${SVN_RELEASE//\./}]
name=Cirata SVN Repo $SVN_RELEASE
enabled=1
baseurl=https://$REPO_SERVER/$OS/$OSVER/svn-$SVN_RELEASE/RPMS/\$basearch/
gpgcheck=1
gpgkey=https://$REPO_SERVER/RPM-GPG-KEY-WANdisco
EOF

  case $OSVER in
    7 ) yum makecache ;;
    * ) dnf makecache; DNF_MODULE=1 ;;
  esac
  case $OSVER in
    7|8 )
      PKG_LIST+=(subversion-python)
      ;;
    *)
      PKG_LIST+=(python3-subversion)
      ;;
  esac
}

configure_zypp_repo() {
  PKG_LIST=(subversion subversion-perl subversion-python subversion-ruby subversion-tools)
  SVN_RELEASE=${SVN_VERSION%.*}
  SVN_RELEASE="svn${SVN_RELEASE//\./}"
  PKG_INSTALLER="zypper install -y -f --from Cirata-$SVN_RELEASE"

  rm -f /etc/zypp/repos.d/WANdisco-suse11.repo \
        /etc/zypp/repos.d/WANdisco-svn.repo

  zypper rr "Cirata-$SVN_RELEASE" > /dev/null 2>&1

  if ! rpm -q gpg-pubkey-3bbf077a-51260c0f >/dev/null 2>&1 ; then
    $GET "https://$REPO_SERVER/RPM-GPG-KEY-WANdisco" > /tmp/RPM-GPG-KEY-WANdisco
    rpm --import /tmp/RPM-GPG-KEY-WANdisco
  fi

  zypper addservice --type=YUM "https://$REPO_SERVER/suse/$OSVER/$SVN_RELEASE/" "Cirata-$SVN_RELEASE"
  zypper refresh
}

configure_repo() {
  case $OS in
    debian|ubuntu) configure_apt_repo ;;
    rhel|centos) configure_yum_repo ;;
    suse) configure_zypp_repo ;;
  esac
}

check_mod_dav() {
  HAS_MOD_DAV=
  case $OS in
    rhel|centos|suse)
      rpm -q mod_dav_svn > /dev/null 2>&1 && HAS_MOD_DAV=1
      rpm -q subversion-server > /dev/null 2>&1 && HAS_MOD_DAV=1
      return 0
    ;;
    debian|ubuntu)
      dpkg-query -W libapache2-mod-svn > /dev/null 2>&1 && HAS_MOD_DAV=1
      return 0
    ;;
  esac
}

add_packages() {
  case $OS in
    rhel|centos|suse) return 0 ;;
  esac

  mapfile PKG_LIST < <(dpkg-query -f '${Package} ${Source}\n' -W '*' | awk '$2 == "subversion" {print $1}')

  return 0
}

handle_module() {
  dnf module list --enabled subversion > /dev/null 2>&1 && dnf -y module reset subversion
  dnf module list --enabled subversion-devel > /dev/null 2>&1 && dnf -y module reset subversion-devel
  dnf -y remove "subversion*"
  dnf -y module install subversion:wd-vanilla
  dnf -y module enable subversion:wd-vanilla
}

install_svn() {
  test -n "$SVN" && add_packages

  if [ -n "$DNF_MODULE" ]; then
    handle_module
    return $?
  fi

  $PKG_INSTALLER "${PKG_LIST[@]}"
}

install_mod_dav() {
  test -n "$NO_MOD_DAV" && return 0

  if [ -n "$DNF_MODULE" ]; then
    dnf -y -q install mod_dav_svn
    return $?
  fi

  case $OS in
    rhel|centos) MOD_DAV_PKG="mod_dav_svn" ;;
    debian|ubuntu) MOD_DAV_PKG="libapache2-mod-svn" ;;
    suse)
      case "$OSVER" in
        12) MOD_DAV_PKG="mod_dav_svn" ;;
        *) MOD_DAV_PKG="subversion-server" ;;
      esac
  esac

  $PKG_INSTALLER "$MOD_DAV_PKG"
}

# Main Script

trap handle_error ERR

cat <<EOF

                                               /        /
                                          ///       //
                                    /////       ///
                             //////        ////          /
                /////////////       //////          ///
                              /////        ////////
                    ///////////////////////             ##
                                                        ##
     #########     ##    ##  #####    #########  ##   #########    #########  ##
  ####       ###   ##    #####     ####       #####     ##      ####       #####
 ###               ##    ###      ###           ###     ##     ###           ###
###                ##    ##      ###             ##     ##    ###             ##
##                 ##    ##      ##              ##     ##    ##              ##
##                 ##    ##      ##              ##     ##    ##              ##
###                ##    ##      ###             ##     ##    ###             ##
 ###               ##    ##       ###           ###     ##     ###           ###
  ####       ###   ##    ##        ####       ## ##     ##      ####       ## ##
     #########      #     #           #########   #      #         #########   #


EOF

check_connection
find_os || unsupported
check_os || unsupported
check_root
check_alternative_arch
check_install
configure_repo
check_mod_dav
install_svn

echo "Subversion has been installed or upgraded successfully"

test -n "$HAS_MOD_DAV" && exit 0

echo
echo "Do you want to install the subversion server modules for apache?"
echo
if confirm "Install mod_dav_svn?"; then
  install_mod_dav
fi

echo
echo "Installation complete"
