#!/bin/bash

. /usr/share/preupgrade/common.sh
switch_to_content
#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 was not found. Contact the support." && \
  exit $RESULT_ERROR

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

ReplacedPkgs=$(mktemp .replacedpkgsXXX --tmpdir=/tmp)
MoveReplacedPkgs=$(mktemp .mvreplacedpkgsXXX --tmpdir=/tmp)
#RemovedOrObsoletedPkgs=$(mktemp .removedpkgsXXX --tmpdir=/tmp)
NotBasePkgs=$(mktemp .notbasepkgsXXX --tmpdir=/tmp)
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"
#cat $COMMON_DIR/default*_removed $COMMON_DIR/default*_*obsolete* \
#    | cut -f1 -d' ' | sort | uniq > "$RemovedOrObsoletedPkgs"

[ ! -r "$COMMON_DIR/ProvidesonlyMissing" ] \
       || [ ! -r "$COMMON_DIR/BothMissing" ] \
       || [ ! -r "$COMMON_DIR/default_nreponames" ] \
       || [ ! -r "$ReplacedPkgs" ] \
       || [ ! -r "$MoveReplacedPkgs" ] \
       || [ ! -r "$NotBasePkgs" ] && {
  log_error "Package change lists not found. Contact the support."
  rm -f "$ReplacedPkgs" "$MoveReplacedPkgs" "$NotBasePkgs"
  exit $RESULT_ERROR
}

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

# create these 2 files - just to be sure - should be created always
touch "$KICKSTART_DIR/${FILENAME_BASIS}"
touch "$KICKSTART_DIR/${FILENAME_BASIS}-notbase"

cp "$_NOAUTO_POSTSCRIPT" "$_DST_NOAUTO_POSTSCRIPT"

echo \
"Between Red Hat Enterprise Linux 6 and Red Hat Enterprise Linux 7, some packages have either been replaced or
renamed. The new packages are compatible with their previous versions.
In some cases, the Preupgrade Assistant will migrate the packages after the
upgrade is completed.

Note: This tool will not check debug repositories. It is recommended that all debuginfo packages are removed before the upgrade, and
manually reinstalled as required on the upgraded system.

The following packages were replaced:" >solution.txt

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

#Check for package replacements in the packages
while read 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 packages not signed by Red Hat:$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 || {
      [ $UPGRADE -eq 1] && func_log_risk=log_high_risk
    }
    other_repositories="${other_repositories}$channel "
    msg_channel=" ($channel channel in Red Hat Enterprise Linux 7)"
    statuscode=$RESULT_FAIL
    filename_suffix="-notbase"
  fi

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

  # logs / prints
  [ -n "$msg_req" ] && log_slight_risk "The ${orig_pkg} package $msg_req was replaced between Red Hat Enterprise Linux 6 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 6 and Red Hat Enterprise Linux 7. Enable this channel for the 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. Enable this channel for the upgrade."
  echo "${orig_pkg}$msg_req was replaced by ${repl_pkgs}$msg_channel." >>solution.txt
  found=1
done < <(get_dist_native_list | sort | uniq)

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

[ -n "$other_repositories" ] && {
  echo -n "
One or more replacement packages are available only in other repositories.
Provide these repositories to make the upgrade or migration successful." >>solution.txt
[ $UPGRADE -eq 1 ] && echo -n "
For in-place upgrades, only the Optional repository is supported.
First, remove the packages from other repositories." >> solution.txt

 [ $optional -eq 1 ] && [ $UPGRADE -eq 1 ] && echo "
For this purpose, if you want to upgrade, use the following additional option
to redhat-upgrade-tool:

    --addrepo rhel-7-optional=<path to the Optional repository>

Alternatively,before you start the system upgrade, you could remove all the packages where the replacement is a 
part of the Red Hat Enterprise Linux 7 Optional repository." >> 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, 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 this purpose (installation), run a prepared script:
$_DST_NOAUTO_POSTSCRIPT $KICKSTART_DIR/${FILENAME_BASIS}-notbase

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

[ $UPGRADE -eq 1 ] && {
  #Relevant only for in-place upgrade. It's not important for migration

  #Packages not handled properly according to http://fedoraproject.org/wiki/Packaging:Guidelines#Renaming.2FReplacing_Existing_Packages
  # -> Package should have both obsoletes and provides, otherwise it can cause troubles during the update.
  l=""
  for i in $(get_dist_native_list | sort | uniq)
  do
    # For now, handle them same way, we want them installed...
    # Notice: not-base channel are important mainly for migration, where
    # not-base channels are not available during system installation. In-place
    # upgrade can update these packages directly, so keep here we will
    # check all replaced packages.
    m=$(grep "^$i|" "$COMMON_DIR/ProvidesonlyMissing")
    [ -n "$m" ] || m=$(grep "^$i|" "$COMMON_DIR/BothMissing")
    [ -z "$m" ] && continue
    replacement=$(echo $m | cut -d'|' -f2)
    notprovided=1
    log_debug "The $i package is not in the RPM 'provides' directives of the replacement; $replacement. The in-place upgrade might not work properly, and it will be finished by the postupgrade script."
    l="$l $m"
  done

  #Create a postupgrade script which ensures that the replacement packages are installed
  mkdir $VALUE_TMP_PREUPGRADE/postupgrade.d/replacedpkg 2>/dev/null
  cat <<\EOF >$VALUE_TMP_PREUPGRADE/postupgrade.d/replacedpkg/fixreplaced.sh
#!/bin/bash

#Generated file, part of preupgrade-assistant content, should not be used
#separately, see preupgrade-assistant license for licensing details
#Do the upgrade for the packages with potentially broken obsoletes/provides

prep_source_right() {
  # return 0 - mounted successfully
  # return 1 - nothing to do
  # return 2 - mount failed

  RHELUP_CONF="/root/preupgrade/upgrade.conf"
  mount_path="$(grep "^device" "$RHELUP_CONF" | sed -r "s/^.*rawmnt='([^']+)', .*$/\1/")"
  iso_path="$(grep "^iso" "$RHELUP_CONF" | cut -d " " -f 3- | grep -vE "^None$")"
  device_line="$(grep "^device" "$RHELUP_CONF"  | cut -d " " -f 3- | grep -vE "^None$")"
  device_path="$(echo "$device_line"  | sed -r "s/^.*dev='([^']+)',.*/\1/")"
  fs_type="$(echo "$device_line" | grep -o "type='[^']*'," | sed -r "s/^type='(.*)',$/\1/" )"
  m_opts="$(echo "$device_line" | grep -o "opts='[^']*'," | sed -r "s/^opts='(.*)',$/\1/" )"

  # is used iso or device? if not, return 1
  [ -n "$mount_path" ] && { [ -n "$iso_path" ] || [ -n "$device_path" ]; } || return 1
  mountpoint -q "$mount_path" && return 1 # is already mounted
  if [ -n "$iso_path" ]; then
    mount -t iso9660 -o loop,ro "$iso_path"  "$mount_path" || return 2
  else
    # device
    [ -n "$fs_type" ] && fs_type="-t $fs_type"
    [ -n "$m_opts" ] && m_opts="-o $m_opts"
    mount $fs_type $m_opts "$device_path" "$mount_path" || return 2
  fi

  return 0
}


for i in $(echo "SEDMEHERE")
do
  old="$(echo $i | cut -d'|' -f1)"
  new="$(echo $i | cut -d'|' -f2 | tr ',' ' ')"
  #we want to remove the old package if still present
  rpm -q $old 2>/dev/null >/dev/null && {
  #Store the modified files as .preupsave
  for j in $(rpm -V $old | rev | cut -d' ' -f1 | rev | grep -v "(replaced)")
  do
    cp $j $j.preupsave
    echo "Storing a modified $j file from the $old package as $j.preupsave"
  done
  #deinstall the old package
  rpm -e $old --nodeps
  echo "The $old package was uninstalled."
  }
  #do we already have all new installed? Skip it...
  rpm -q $new >/dev/null && continue
  yum install -y $new || {
    prep_source_right && \
      yum install -y $new
  }
  rpm -q $new 2>/dev/null >/dev/null && echo "The $new package or packages installed" && continue
  #when we are here, installation got wrong and we should warn the user.
  echo  "The automatic installation of the $new package or packages failed, install the package or packages manually."
done
for old in $(echo "SEDME2HERE")
do
  #we want to remove the old package if still present
  rpm -q $old 2>/dev/null >/dev/null && {
  #Store the modified files as .preupsave
  for j in $(rpm -V $old | rev | cut -d' ' -f1 | rev | grep -v "(replaced)")
  do
    cp $j $j.preupsave
    echo "Storing the modified $j file from the $old package as $j.preupsave"
  done
  #deinstall the old package
  rpm -e $old --nodeps
  echo "The $old package was uninstalled."
  }
done
EOF
  sed -i -e "s/SEDMEHERE/$l/" $VALUE_TMP_PREUPGRADE/postupgrade.d/replacedpkg/fixreplaced.sh
  sed -i -e "s/SEDME2HERE/$removeme/" $VALUE_TMP_PREUPGRADE/postupgrade.d/replacedpkg/fixreplaced.sh
  chmod +x $VALUE_TMP_PREUPGRADE/postupgrade.d/replacedpkg/fixreplaced.sh
}

# TBD Do the comps groups replacements (when someone had full yum group
# on RHEL 6, assume he wants it on RHEL 7 as well, rather than having only
# limited set of packages)

# it looks better sorted
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 6 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 - This file is similar to the ${FILENAME_BASIS} file, but the packages are a part of other channels, and they 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 names between Red Hat Enterprise Linux 6 and Red Hat Enterprise Linux 7. Although they should be compatible, monitor them after the update." && exit $statuscode

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

exit $RESULT_PASS
