#!/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

_NOAUTO_POSTSCRIPT="noauto_postupgrade.d/install_rpmlist.sh"
_DST_NOAUTO_POSTSCRIPT="$NOAUTO_POSTUPGRADE_D/install_rpmlist.sh"
FILENAME_BASIS="RHRHEL7rpmlist_replaced"

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

[ ! -f "$VALUE_RPM_RHSIGNED" ] && \
  log_error "Signed RPM list not found. Contact the support." && \
  exit $RESULT_ERROR

[ ! -r "$COMMON_DIR" ] || [ ! -r "$_NOAUTO_POSTSCRIPT" ] && \
  log_error "The directory for common files not found. Contact the support." && \
  exit $RESULT_ERROR

ReplacedPkgs=$(mktemp /tmp/.replacedpkgsXXX)
MoveReplacedPkgs=$(mktemp /tmp/.mvreplacedpkgsXXX)
#RemovedOrObsoletedPkgs=$(mktemp /tmp/.removedpkgsXXX)
NotBasePkgs=$(mktemp /tmp/.notbasepkgsXXX)
DistNativePkgs=$(mktemp /tmp.distnativeXXX)
cat $COMMON_DIR/default*_*replaced* | cut -f1,3 -d' ' | tr ' ' '|' | sort | uniq >"$ReplacedPkgs"
# without move to base channel - hasn't benefit for us
grep -Hr "..*" $COMMON_DIR/default*_moved-replaced_?* | sed -r "s|^$COMMON_DIR/([^:]+):([^[:space:]]*).*$|\2 \1|" | sort | uniq >"$MoveReplacedPkgs"
grep -Hr "..*" $COMMON_DIR/default-*_replaced | sed -r "s|^$COMMON_DIR/([^:]+):([^[:space:]]*).*$|\2 \1|" | sort | uniq >"$NotBasePkgs"
get_dist_native_list | sort | uniq > $DistNativePkgs
#cat $COMMON_DIR/default*_removed $COMMON_DIR/default*_*obsolete* \
#    | cut -f1 -d' ' | sort | uniq > "$RemovedOrObsoletedPkgs"


# Note: Files ProvidesonlyMissing & BothMissing are not used for migration
# now anywhere.
#[ ! -r "$COMMON_DIR/ProvidesonlyMissing" ] \
#       || [ ! -r "$COMMON_DIR/BothMissing" ] \
[ ! -r "$COMMON_DIR/default_nreponames" ] \
       || [ ! -r "$ReplacedPkgs"        ] \
       || [ ! -r "$MoveReplacedPkgs"    ] \
       || [ ! -r "$NotBasePkgs"         ] \
       || [ ! -r "$DistNativePkgs"      ] && {
  log_error "Package change lists not found. Contact the support."
  rm -f "$ReplacedPkgs" "$MoveReplacedPkgs" "$NotBasePkgs" "$DistNativePkgs"
  exit $RESULT_ERROR
}

found=0
optional=0
notprovided=0
other_repositories=""
statuscode=$RESULT_INFORMATIONAL # PASS is separated on the bottom
rm -f "$KICKSTART_DIR/${FILENAME_BASIS}"* >/dev/null
rm -f solution.txt

# create the file - just to be sure :-)
touch "$KICKSTART_DIR/${FILENAME_BASIS}"
touch "$KICKSTART_DIR/${FILENAME_BASIS}-notbase"

cp "$_NOAUTO_POSTSCRIPT" "$_DST_NOAUTO_POSTSCRIPT"

echo \
"Between Red Hat Enterprise Linux 5 and Red Hat Enterprise Linux 7, some packages have either been replaced or
renamed.  Replacement packages are compatible with previous versions.
In some cases, the Preupgrade Assistant will migrate the packages after the
migration has completed.

Note: This tool will not check debug repositories. Red Hat
recommends that all debuginfo packages are removed before migration and
manually reinstalled as required on the new system.

The following packages were replaced:" >solution.txt

###################################

#Check for package replacements in the packages
line=
while IFS= read line || [ -n "$line" ];
do
  orig_pkg=$(echo "$line" | cut -f1 )

  replaced_line=$(grep -e "^$orig_pkg|" "$ReplacedPkgs")
  [ -z "$replaced_line" ] && {
    # this could be obsoleted or removed package
    # in that case just skip it
    # grep "^$orig_pkg$" "$RemovedOrObsoletedPkgs" >/dev/null && continue

    # or it could be kept package, which we want totally install if we can.
    # Kept packages are handled by content notbase-channels
    # (originally labeled optionnal-channel) which is more suitable for this
    # so skip it too
    continue
  }


  repl_pkgs=$(echo "$replaced_line" | cut -d'|' -f2 )
  is_moved=0
  is_not_base=0
  filename_suffix=""
  msg_channel=""
  req_pkgs=""
  msg_req=""
  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" || msg_req="${req_pkgs}$k "
  done
  [ -n "$req_pkgs" ] && {
    req_pkgs="${req_pkgs% }"
    msg_req=" (required by Non Red Hat signed package(s):$req_pkg)"
  }
  channel="$(grep "^$orig_pkg[[:space:]]" "$MoveReplacedPkgs" | rev | cut -d "_" -f 1 | rev)"

  func_log_risk=log_high_risk
  #packages from *debug repositories aren't important - ignore them (at least for now)
  # below
  #[[ "$channel" =~ debug$ && -z "$msg_req" ]] && func_log_risk=log_slight_risk

  if [ -n "$channel" ]; then
    [[ "$channel" =~ debug$ ]] && continue
    is_moved=1
  else
    channel=$(grep "^$orig_pkg[[:space:]]" "$NotBasePkgs" | sed -r "s/^.*default-(.*)_replaced$/\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
    other_repositories="${other_repositories}$channel "
    msg_channel=" ($channel channel in RHEL 7)"
    statuscode=$RESULT_FAILED
    filename_suffix="-notbase"
  fi

  echo "${orig_pkg}|$req_pkgs|$(echo $repl_pkgs | tr ',' ' ')|$(get_repo_id $channel)" >> "$KICKSTART_DIR/${FILENAME_BASIS}${filename_suffix}"

  # logs / prints
  [ -n "$msg_req" ] && log_slight_risk "The ${orig_pkg}$msg_req package was replaced between Red Hat Enterprise Linux 5 and Red Hat Enterprise Linux 7."
  [ $is_moved -eq 1 ] && $func_log_risk "The $orig_pkg package replacement moved to the $channel channel between Red Hat Enterprise Linux 5 and Red Hat Enterprise Linux 7. You need to enable this channel for upgrade."
  [ $is_not_base -eq 1 ] && $func_log_risk "The $orig_pkg package replacement is a part of the $channel channel in Red Hat Enterprise Linux 7. You need to enable this channel for upgrade."
  echo "${orig_pkg}$msg_req was replaced by ${repl_pkgs}$msg_channel" >>solution.txt
  found=1
done < "$DistNativePkgs"

echo \
"
If a package not signed by Red Hat requires these packages, you may want
to monitor them closely. Although the replacement should be compatible,
it might have some minor differences, even in the case of common
application lifecycles." >>solution.txt

[ -n "$other_repositories" ] && {
  echo -n "
One or more replacement packages are available only in other repositories.
You need to provide these repositories to make the migration successful." >>solution.txt

# another channels could be added when we support addons

  [ $MIGRATE -eq 1 ] && {
    #migrate_repos="$(echo "${other_repositories% }" | tr ' ' '\n' | sort | uniq \
    #                  | sed -r "s/^(.+)$/rhel-7-\1=baseurl=<RHEL-7-\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 "
If you want to migrate, you will need to register your machine with subscription-manager
after the first boot of your new system and attach subscriptions that provide:
$repos_texts

Then, enable any equivalent repositories (if they are disabled), and
install any needed packages.
For the purpose of installation, you can run a prepared script:
$_DST_NOAUTO_POSTSCRIPT $KICKSTART_DIR/${FILENAME_BASIS}-notbase

It will install any remaining available packages from these repositories.
" >> solution.txt
  }
}
rm -f "$ReplacedPkgs" "$MoveReplacedPkgs" "$NotBasePkgs" "$DistNativePkgs"

# TBD Do the comps groups replacements (when someone had full yum group
# on RHEL 5, assume he wants it on RHEL 7 as well, rather than having only
# limited set of packages)
# Note: PA do something like that already!

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

echo -n "
 * ${FILENAME_BASIS} - This file contains a list of packages that replace the original Red Hat Enterprise Linux 5 packages on the Red Hat Enterprise Linux 7 system and that are available in the 'base' channel. These packages will always be installed.
 * ${FILENAME_BASIS}-notbase - The file is similar to the ${FILENAME_BASIS} file but the packages are a part of other channels and must be installed manually.
" >> "$KICKSTART_README"

[ $notprovided -eq 1 ] && [ -z "$other_repositories" ] && statuscode=$RESULT_FIXED

[ $found -eq 1 ] && log_slight_risk "\
Some packages installed on the system changed their name between Red Hat Enterprise Linux 5 and Red Hat Enterprise Linux 7. Although they should be compatible, monitoring them after the migration is recommended." && exit $statuscode

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

exit $RESULT_PASS
