#!/bin/bash
#---------------------------------------------------------------------
## @Synopsis Functions for desling with the stage root and installing files from the stage root
## @Copyright Copyright (C) 2004 The Source Mage Team <http://www.sourcemage.org>
## Functions for desling with the stage root and installing files from the stage root
#---------------------------------------------------------------------

#---------------------------------------------------------------------
## @param stage root
## Main for installing staged spell called imediatly after devoking
## installwatch and stage root
#---------------------------------------------------------------------
function transfer_staged_spell()
{
  stage_install_ordinary
  lock_file "$CONFIG_STAGE_DIRECTORY/$SPELL"
  mkdir -p "$CONFIG_STAGE_DIRECTORY/$SPELL/current"
  stage_install_configs
  unlock_file "$CONFIG_STAGE_DIRECTORY/$SPELL"
}

function filter_spell_configs()
{
  filter_generic "$*" configs $CONFIGS codex
}

#---------------------------------------------------------------------
## Install config files to a staged location on the system or if
## they are also excluded, just install them normally.
#---------------------------------------------------------------------
function stage_install_configs()
{
  local spell_configs=$(get_all_package_files | filter_spell_configs -v)

  # install excluded configs as ordinary files - do not stage them
  message "${MESSAGE_COLOR}Installing excluded config files${DEFAULT_COLOR}"
  echo "$spell_configs"      |
  filter_excluded -v         |
  stage_install_files

  message "${MESSAGE_COLOR}Staging config files into the system${DEFAULT_COLOR}"
  echo "$spell_configs"      |
  filter_excluded            |
  stage_install_files config
}

#---------------------------------------------------------------------
## Install non-configs in the stage root
#---------------------------------------------------------------------
function stage_install_ordinary()
{
  message "${MESSAGE_COLOR}Installing ordinary files${DEFAULT_COLOR}"
  get_all_package_files        |
  filter_spell_configs         |
  stage_install_files
}

#---------------------------------------------------------------------
## @Stdout list of files installed by package
## lists all files the package installs relative to /
#---------------------------------------------------------------------
function get_all_package_files()
{
  find $STAGE_DIRECTORY/TRANSL | sed "s:$STAGE_DIRECTORY/TRANSL::"
}

#---------------------------------------------------------------------
## @Stdin list of files to install
## install the files from the stage directory to the system
#---------------------------------------------------------------------
function stage_install_files()
{
  local file
  while read file ; do
    [ "$file" ] || continue
    stage_install_list "$file" "$1"
  done
}

function stage_install_directory()
{
  local DIR=$1
  local PERMISSION=$(stat -c %a "${STAGE_DIRECTORY}/TRANSL/${DIR}")
  local OWNER=$(stat -c %U "${STAGE_DIRECTORY}/TRANSL/${DIR}")
  local GROUP=$(stat -c %G "${STAGE_DIRECTORY}/TRANSL/${DIR}")
  if [[ ! -d $(dirname "${INSTALL_ROOT}/$DIR") ]]
  then
    # this shouldn't happen but just in case
    message "${PROBLEM_COLOR}Ah, not preserving permissions making $(dirname $DIR)${DEFAULT_COLOR}" &&
    mkdir -p $(dirname "${INSTALL_ROOT}/$DIR")
  fi &&
  message "${FILE_COLOR}$PERMISSION $OWNER:$GROUP $DIR${DEFAULT_COLOR}" &&
  if [[ -d "${INSTALL_ROOT}/$DIR" ]]
  then
    chmod "$PERMISSION" "${INSTALL_ROOT}/$DIR" &&
    chown $OWNER:$GROUP "${INSTALL_ROOT}/$DIR"
  else
    mkdir "${INSTALL_ROOT}/$DIR"   &&
    chmod "$PERMISSION" "${INSTALL_ROOT}/$DIR" &&
    chown $OWNER:$GROUP "${INSTALL_ROOT}/$DIR"
  fi
}

function stage_install_file()
{
  local FILE=$1
  local PERMISSION=$(stat -c %a "${STAGE_DIRECTORY}/TRANSL/$FILE")
  local OWNER=$(stat -c %U "${STAGE_DIRECTORY}/TRANSL/$FILE")
  local GROUP=$(stat -c %G "${STAGE_DIRECTORY}/TRANSL/$FILE")
  local SAVE="$CONFIG_STAGE_DIRECTORY/$SPELL/current/$FILE"
  message "${FILE_COLOR}$PERMISSION $OWNER:$GROUP $FILE${DEFAULT_COLOR}"
  case $2 in
    config)
      if [[ -e "${INSTALL_ROOT}/$FILE" ]]
      then
        message "${MESSAGE_COLOR}Staging config to $CONFIG_STAGE_DIRECTORY${DEFAULT_COLOR}"
        mkdir -p "$(dirname $SAVE)" &&
        cp -dp "$STAGE_DIRECTORY/TRANSL/$FILE" "${INSTALL_ROOT}/$SAVE"
      else
        cp -dp "$STAGE_DIRECTORY/TRANSL/$FILE" "${INSTALL_ROOT}/$FILE"
      fi
      ;;
    *)
      cp -fdp "$STAGE_DIRECTORY/TRANSL/$FILE" "${INSTALL_ROOT}/$FILE"
      ;;
  esac
}

function stage_install_symlink()
{
  local FILE=$1
  local SAVE=$CONFIG_STAGE_DIRECTORY/$FILE.$(date +%Y%m%d%H%M%S)
  local LINK=$(readlink "$STAGE_DIRECTORY/TRANSL/$FILE")
  message "${FILE_COLOR}Symlink $FILE -> $LINK${DEFAULT_COLOR}"
  case $2 in
    config)
      if [[ -e "${INSTALL_ROOT}/$FILE" ]]
      then
        touch "${INSTALL_ROOT}/$FILE" &&
        mkdir -p $(dirname $SAVE) &&
        ln -sfn "$LINK" "${INSTALL_ROOT}/$SAVE"
      else
        ln -sfn "$LINK" "${INSTALL_ROOT}/$FILE"
      fi
      ;;
    *)
      ln -sfn $(readlink "$STAGE_DIRECTORY/TRANSL/$FILE") "${INSTALL_ROOT}/$FILE"
      ;;
  esac
}

function stage_install_fifo()
{
  local FILE=$1
  local SAVE=$CONFIG_STAGE_DIRECTORY/$FILE.$(date +%Y%m%d%H%M%S)
  local PERMISSION=$(stat -c %a "${STAGE_DIRECTORY}/TRANSL/$FILE")
  local OWNER=$(stat -c %U "${STAGE_DIRECTORY}/TRANSL/$FILE")
  local GROUP=$(stat -c %G "${STAGE_DIRECTORY}/TRANSL/$FILE")
  message "${FILE_COLOR}Fifo $PERMISSION $OWNER:$GROUP $FILE${DEFAULT_COLOR}"
  case $2 in
    config)
      if [[ -e "${INSTALL_ROOT}/$FILE" ]]
      then
        touch "${INSTALL_ROOT}/$FILE" &&
        mkdir -p $(dirname $SAVE) &&
        mkfifo "${INSTALL_ROOT}/$SAVE" &&
        chmod $PERMISSION "${INSTALL_ROOT}/$SAVE" &&
        chown $OWNER:$GROUP "${INSTALL_ROOT}/$SAVE"
      else
        mkfifo "${INSTALL_ROOT}/$FILE" &&
        chmod $PERMISSION "${INSTALL_ROOT}/$FILE" &&
        chown $OWNER:$GROUP "${INSTALL_ROOT}/$FILE"
      fi
      ;;
    *)
      mkfifo "${INSTALL_ROOT}/$FILE" &&
      chmod $PERMISSION "${INSTALL_ROOT}/$FILE" &&
      chown $OWNER:$GROUP "${INSTALL_ROOT}/$FILE"
      ;;
  esac
}

function stage_install_char_block()
{
  local FILE=$1
  local PERMISSION=$(stat -c %a "${STAGE_DIRECTORY}/TRANSL/$FILE")
  local MAJOR=$(stat -c %t "${STAGE_DIRECTORY}/TRANSL/$FILE")
  local MINOR=$(stat -c %T "${STAGE_DIRECTORY}/TRANSL/$FILE")
  local OWNER=$(stat -c %U "${STAGE_DIRECTORY}/TRANSL/$FILE")
  local GROUP=$(stat -c %G "${STAGE_DIRECTORY}/TRANSL/$FILE")
  local SAVE=$CONFIG_STAGE_DIRECTORY/$FILE.$(date +%Y%m%d%H%M%S)
  local TYPE=$3
  message "${FILE_COLOR}${PERMISSION} $OWNER:$GROUP $TYPE $MAJOR $MINOR $FILE${DEFAULT_COLOR}"
  case $2 in
    config)
      if [[ -e "${INSTALL_ROOT}/$FILE" ]]
      then
        touch "${INSTALL_ROOT}/$FILE" &&
        mkdir -p $(dirname $SAVE) &&
        mknod -m "${PERMISSION}" "${INSTALL_ROOT}/$SAVE" "${TYPE}" "${MAJOR}" "${MINOR}" &&
        chown $OWNER:$GROUP "${INSTALL_ROOT}/$SAVE"
      else
        mknod -m "${PERMISSION}" "${INSTALL_ROOT}/$FILE" "${TYPE}" "${MAJOR}" "${MINOR}" &&
        chown $OWNER:$GROUP "${INSTALL_ROOT}/$FILE"
      fi
      ;;
    *)
      mknod -m "${PERMISSION}" "${INSTALL_ROOT}/$FILE" "${TYPE}" "${MAJOR}" "${MINOR}" &&
      chown $OWNER:$GROUP "${INSTALL_ROOT}/$FILE"
      ;;
  esac
}

#---------------------------------------------------------------------
## @param file
## install the file from the stage root to the system does check for
## dir so that the file can be moved
#---------------------------------------------------------------------
function stage_install_list()
{
  if [[ -h $STAGE_DIRECTORY/TRANSL/$1 ]]
  then
    stage_install_symlink "$@"
  elif [[ -b $STAGE_DIRECTORY/TRANSL/$1 ]]
  then
    stage_install_char_block "$@" b
  elif [[ -c $STAGE_DIRECTORY/TRANSL/$1 ]]
  then
    stage_install_char_block "$@" c
  elif [[ -p $STAGE_DIRECTORY/TRANSL/$1 ]]
  then
    stage_install_fifo "$@"
  elif [[ -f $STAGE_DIRECTORY/TRANSL/$1 ]]
  then
    stage_install_file "$@"
  elif [[ -d $STAGE_DIRECTORY/TRANSL/$1 ]]
  then
    stage_install_directory "$@"
  else
    message "${PROBLEM_COLOR}Oh, God I don't know what to do..."
    message "${FILE_COLOR}$(dirname ${1})${PROBLEM_COLOR}"
    message "is some other kind of a file and not a directory${DEFAULT_COLOR}"
  fi
}

#--------------------------------------------------------------------
## Removes the passed file and possibly its parent directories up
## to $CONFIG_STAGE_DIRECTORY if they are empty
##
## @param file
## @param spell  owner of the file, so we don't need to look that up
#--------------------------------------------------------------------
function recursive_config_stage_cleanup()
{
  local file=$1 dirname
  local spell=$2

  smgl_dirname "$file" dirname
  # make it a relative path for rmdir -p
  dirname="${dirname#$CONFIG_STAGE_DIRECTORY/}"

  # lock_file works on dirs too
  lock_file "$CONFIG_STAGE_DIRECTORY/$spell"
  rm "$file"
  {
    pushd $CONFIG_STAGE_DIRECTORY
    rmdir -p "$dirname"
    popd
  } &> /dev/null
  unlock_file "$CONFIG_STAGE_DIRECTORY/$spell"
}
