#!/bin/bash

#Preupgrade Assistant performs system upgradability assessment
#and gathers information required for successful operating system upgrade.
#Copyright (C) 2013 Red Hat Inc.
#Ondrej Vasik <ovasik@redhat.com>, Petr Stodulka <pstodulk@redhat.com>
#
#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/>.
. /usr/share/preupgrade/common.sh
check_rpm_to "" ""
#END GENERATED SECTION

# is created/copied by ReplacedPackages
_DST_NOAUTO_POSTSCRIPT="$NOAUTO_POSTUPGRADE_D/install_rpmlist.sh"
FILENAME_BASIS="RHRHEL7rpmlist_obsoleted"

get_repo_id() {
  grep -E "^[^-]*-$1;" "$COMMON_DIR/default_nreponames" | cut -d ";" -f3
}

[ ! -f "$VALUE_RPM_CENTOSSIGNED" ] || [ ! -r "$COMMON_DIR" ] && {
  log_error "Signed RPM list or common file directory is missing. Contact the support."
  exit $RESULT_ERROR
}

ObsoletedPkgs=$(mktemp .obsoletedpkgsXXX --tmpdir=/tmp)
MoveObsoletedPkgs=$(mktemp .mvreplacedpkgsXXX --tmpdir=/tmp)
NotBasePkgs=$(mktemp .notbasepkgsXXX --tmpdir=/tmp)
cat $COMMON_DIR/default*_*obsoleted* | cut -f1,3 -d' ' | tr ' ' '|' | sort | uniq >"$ObsoletedPkgs"
grep -Hr "..*" $COMMON_DIR/default*_moved-obsoleted_?* | sed -r "s|^$COMMON_DIR/([^:]+):([^[:space:]]*).*$|\2 \1|" | sort | uniq >"$MoveObsoletedPkgs"
grep -Hr "..*" $COMMON_DIR/default-*_obsoleted | sed -r "s|^$COMMON_DIR/([^:]+):([^[:space:]]*).*$|\2 \1|" | sort | uniq >"$NotBasePkgs"



[ ! -r "$ObsoletedPkgs" ] \
      || [ ! -r "$MoveObsoletedPkgs" ] \
      || [ ! -r "$NotBasePkgs" ] && {
  log_error "Package content lists missing. Contact the support."
  rm -f "$ObsoletedPkgs" "$MoveObsoletedPkgs" "$NotBasePkgs"
  exit $RESULT_ERROR
}

found=0
other_repositories=""
rm -f solution.txt "$KICKSTART_DIR/${FILENAME_BASIS}"*

echo \
"Some packages became obsolete between CentOS 6 and CentOS 7.
CentOS provides alternatives for them, but these
alternatives might not be fully compatible. For this reason,
the packages are not replaced automatically.

For some of the obsolete packages you will get the
incompatibilities list from separate preupgrade
modules, and you can adjust your migration or upgrade
as required.

Sometimes the functionality of a package requires
more than one new package to achieve the same
functionality.

Note: All packages from the debug repositories
are skipped, and CentOS recommends that you remove
them before upgrade.

The following packages are obsolete, and they are replaced by
new ones:" >solution.txt

#Check for package obsolete type replacements in packages
# - packages from *debug repositories aren't important - ignore them (at least for now)
while read line
do
  orig_pkg=$(echo "$line" | cut -d'|' -f1)
  new_pkgs=$(echo "$line" | cut -d'|' -f2)
  #skip non-rh and unavailable packages
  is_pkg_installed "$orig_pkg" && is_dist_native $orig_pkg || continue

  is_moved=0
  is_not_base=0
  filename_suffix=""
  msg_channel=""
  req_pkgs=""
  msg_req=""
  func_log_risk=log_medium_risk

  for k in $(rpm -q --whatrequires $orig_pkg | grep -v "^no package requires" \
    | rev | cut -d'-' -f3- | rev | sort | uniq)
  do
    is_pkg_installed "$k" || continue
    is_dist_native "$k" || req_pkgs="$req_pkgs$k "
  done
  [ -n "$req_pkgs" ] && {
    req_pkgs="${req_pkgs% }"
    msg_req=" (required by packages not signed by CentOS:$req_pkgs)"
    func_log_risk=log_high_risk
  }
  channel="$(grep "^$orig_pkg[[:space:]]" "$MoveObsoletedPkgs" | rev | cut -d "_" -f 1 | rev)"

  if [ -n "$channel" ]; then
    [[ "$channel" =~ debug$ ]] && continue
    is_moved=1
  else
    channel=$(grep "^$orig_pkg[[:space:]]" "$NotBasePkgs" | sed -r "s/^.*default-(.*)_obsoleted$/\1/" )
    [[ "$channel" =~ debug$ ]] && continue
    [ -n "$channel" ] && is_not_base=1
  fi


  if [ $is_moved -eq 1 ] || [ $is_not_base -eq 1 ]; then
    # [ "$channel" == "optional" ] && optional=1 # unused variable
    other_repositories="${other_repositories}$channel "
    msg_channel=" ($channel channel in CentOS 7)"
  fi

  # logs / prints
  [ -n "$msg_req" ] && $func_log_risk "The package ${orig_pkg}$msg_req was removed between CentOS 6 and CentOS 7."
  [ $is_moved -eq 1 ] && $func_log_risk "The partial replacement for the $orig_pkg package moved to the $channel channel between CentOS 6 and CentOS 7."
  [ $is_not_base -eq 1 ] && $func_log_risk "The partial replacement for the $orig_pkg package is available in the $channel channel in CentOS 7."
  echo "${orig_pkg}$msg_req was replaced by ${new_pkgs}$msg_channel" >>solution.txt
  {
    # store data to kickstart files
    [ -n "$msg_req" ] && filename_suffix="${filename_suffix}-required"
    [ -n "$channel" ] && filename_suffix="${filename_suffix}-notbase"
    echo "${orig_pkg}|$req_pkgs|$(echo $new_pkgs | tr ',' ' ')|$(get_repo_id $channel)" >> "$KICKSTART_DIR/${FILENAME_BASIS}${filename_suffix}"
  }
  found=1
done < "$ObsoletedPkgs"
rm -f "$ObsoletedPkgs" "$MoveObsoletedPkgs" "$NotBasePkgs"

# transform my-repo-names to known names
[ -n "$other_repositories" ] && [ $MIGRATE -eq 1 ] && {
  regexp_part="$(echo "${other_repositories}" | tr ' ' '|' | sed -e "s/^|*//" -e "s/|*$//" | sort | uniq )"
  migrate_repos="$(grep -E "^[^-]*(-($regexp_part))?;" < "$COMMON_DIR/default_nreponames")"
  repos_texts="$(echo "$migrate_repos" | cut -d ";" -f4)"

  echo "
One or more replacement packages are available only in other repositories.
If you want to install them later, attach the subscriptions that provide:
$repos_texts

Then, enable any equivalent repositories (if they are disabled), and install any needed packages.
For this purpose, run a prepared script:
$_DST_NOAUTO_POSTSCRIPT <path/to/pkglist-file>

The script will install the available packages listed in the file.
See the ${KICKSTART_README} file for the details about pkglist files.
" >>solution.txt
}

# it looks better sorted
for file in $(ls $KICKSTART_DIR/${FILENAME_BASIS}*); do
  # add header line
  echo "# old-package|required-by-pkgs|obsoleted-by-pkgs|repo-id" > ${file}.bak
  cat "$file" | sort | uniq >> ${file}.bak
  mv ${file}.bak $file
done


  echo -n "
 * ${FILENAME_BASIS} - This file contains all CentOS 6 packages that were replaced in CentOS 7 by a not fully compatible alternative, and that are a part of the Base channel. Direct dependency from the packages not signed by CentOS was not discovered.
 * ${FILENAME_BASIS}-required - This file is similar to the ${FILENAME_BASIS} file, but in addition these packages are required by the packages not signed by CentOS. As some of your packages depend on it, check the changes in detail.
 * ${FILENAME_BASIS}-notbase - This file is similar to the ${FILENAME_BASIS} file, but these packages are not a part of the Base channel in CentOS 7. Register the new machine, and attach subscriptions with the correct repositories if you want to install them.
 * ${FILENAME_BASIS}-required-notbase - This file is similar to the ${FILENAME_BASIS}-required and ${FILENAME_BASIS}-notbase files. The packages are required by the packages not signed by CentOS, and they are not a part of the Base channel.
" >> "$KICKSTART_README"

echo \
"
If a package not signed by CentOS requires these packages, check if an alternative solution provided by CentOS works for you. You might need to get the missing package from a source other than the CentOS repositories.

Install these new packages manually after the assessment, as CentOS cannot assess the suitability of the replacements for your workload." >>solution.txt

[ $found -eq 1 ] && log_medium_risk "\
Some packages installed on the system were removed between CentOS 6 and CentOS 7. This might break the functionality of the packages depending on these removed packages." && exit $RESULT_FAIL

rm -f solution.txt && touch solution.txt

exit $RESULT_PASS
