#---------------------------------------------------------------------
##
##=head1 SYNOPSIS
##
## Functions for dealing with the actual compiling/installation of spells
## and walking through casts 'pass 4' pipeline.
##
##=head1 DESCRIPTION
##
##
##=head1 COPYRIGHT
##
## Copyright (C) 2002 The Source Mage Team <http://www.sourcemage.org>
##
##=head1 FUNCTIONS
#---------------------------------------------------------------------

# checks for a security file
# returns 0 if spell should be cast, 1 otherwise
#---------------------------------------------------------------------
## Prompts the user about possible security problems with the current
## spell. Allows a safe way of failing a spell due to security problems.
## @return 0 if there are no security problem or the user acknowledges them.
## @return 1 if the user decides not to accept the security concerns
#---------------------------------------------------------------------
function run_security() {
    debug "build_api/common" "Starting run_security() on $SPELL"
    if    [  -f  $SCRIPT_DIRECTORY/SECURITY  ]; then
      echo -e "${SPELL_COLOR}${SPELL}:${DEFAULT_COLOR}"
      tee -a $SECURITY_LOG < $SCRIPT_DIRECTORY/SECURITY
        if [ `grep critical $SCRIPT_DIRECTORY/SECURITY` ]; then
          if query "${RED}SECURITY CRITICAL:${QUERY_COLOR} Do you still want to cast ${SPELL_COLOR}${SPELL}${DEFAULT_COLOR}?" "n"; then
            return 0
          fi
          return 1
        else
          if query "SECURITY: Do you still want to cast ${SPELL_COLOR} $SPELL ${QUERY_COLOR}?" "y"; then
            return 0
          fi
          return 1
        fi
    fi
    return 0
}


#---------------------------------------------------------------------
## pokes around for a configure or src/configure and if it exists
## asks the user if they want to edit the custom options
#---------------------------------------------------------------------
function run_config_loc () {
  debug "build_api/common" "Starting run_config_loc() on $SPELL"
  pushd . > /dev/null # may have been somewhere else
  [  -d  "$SOURCE_DIRECTORY"  ]  &&
  cd      $SOURCE_DIRECTORY   # we need to be in here for this function to work
  if  [[  $CONFIG_LOC  == on  ]]; then

    if  [ -x ./configure ] || [ -x ./src/configure ] ; then

      if  [  !  -d  $SM_CONFIG_OPTION_CACHE  ] ; then
        mkdir --parents --mode=0755 $SM_CONFIG_OPTION_CACHE
      fi

      if  [  -f $SM_CONFIG_OPTION_CACHE/$SPELL  ] ; then
        message "${MESSAGE_COLOR}These are your current -- config options for spell ${SPELL_COLOR}$SPELL"
        message "${FILE_COLOR}($SM_CONFIG_OPTION_CACHE/$SPELL)"
        cat $SM_CONFIG_OPTION_CACHE/$SPELL | column
      fi

      if    query  "Do you wish to add -- options to ./configure?"  n ;  then
        F_TMP=$TMP_DIR/cast.$$.configure
        rm -f $F_TMP

        if [ -x ./configure ]; then
          ./configure --help > $F_TMP
        elif [ -x ./src/configure ]; then
          ./src/configure --help > $F_TMP
        fi

        if [ -f $F_TMP ]; then
          sedit 's/^/# /' $F_TMP
        fi

        cat $SM_CONFIG_OPTION_CACHE/$SPELL >> $F_TMP 2>/dev/null
        edit_file $F_TMP
        rm -f $SM_CONFIG_OPTION_CACHE/$SPELL
        sedit '/^#.*$/d' $F_TMP
        mv $F_TMP $SM_CONFIG_OPTION_CACHE/$SPELL
      fi

      # load custom OPTS
      if  [  -f $SM_CONFIG_OPTION_CACHE/$SPELL  ];  then
        OPTS="$OPTS $(< $SM_CONFIG_OPTION_CACHE/$SPELL)"
        message "${MESSAGE_COLOR} OPTS= ${DEFAULT_COLOR}$OPTS"
      fi

    fi

  fi

  popd &>/dev/null

}

#---------------------------------------------------------------------
## @Type API
## Prepares to install the spell.  If the spell is installed already,
## the libraries are saved with save_libraries() and the spell is dispelled.
## Usually called from the BUILD or PRE_INSTALL script of a spell.
## Locks "libgrimoire" "install" before proceeding.
## If the spell is not installed (or held) the spell is not dispelled.
##
#---------------------------------------------------------------------
function real_prepare_install() { (

  debug  "libgrimoire" "Running prepare_install() on $SPELL"

  message  "${MESSAGE_COLOR}Preparing to install"  \
           "${SPELL_COLOR}${SPELL}${DEFAULT_COLOR}"

  lock_resources "libgrimoire" "install"

    if  spell_installed  $SPELL   ||
        spell_held       $SPELL
    then

      trap  "spell_recover"  SIGINT
      save_libraries
      save_binaries
      dispel  --notriggers --nosustain  $SPELL

    fi
) &&
save_bin_lib_paths
}

#--------------------------------------------------------------------
##
## append old libraries and binaries to the appropriate environmental
## variables so that they can be found by sorcery if they get
## dispelled
##
#--------------------------------------------------------------------
function save_bin_lib_paths()
{
  # TODO this is a dirty hack we need to remove it
  if test -d "$SOURCE_DIRECTORY/old.binaries" ; then
    for dir in $( find "$SOURCE_DIRECTORY/old.binaries" -type d); do
      export PATH="$dir:$PATH"
    done
  fi
  if test -d "$SOURCE_DIRECTORY/old.libraries" ; then
    for dir in $( find "$SOURCE_DIRECTORY/old.libraries" -type d); do
      export LD_LIBRARY_PATH="$dir:$LD_LIBRARY_PATH"
      export LD_RUN_PATH="$dir:$LD_RUN_PATH"
    done
  fi
}

#---------------------------------------------------------------------
##
## Gathers all documentation files from source archive and installs
## them as part of the spell
##
#---------------------------------------------------------------------
function real_gather_docs()  { (

  if  [  "$GATHER_DOCS"  ==  "on"  ]; then

    debug  "libgrimoire" "Running gather_docs() on $SPELL DOCS=$DOCS"

    if [[ $STAGED_INSTALL == off ]]; then
      DEST_DIR=$DOCUMENT_DIRECTORY/$SPELL
    else
      DEST_DIR=$STAGE_DIRECTORY/TRANSL/$DOCUMENT_DIRECTORY/$SPELL
    fi
    mkdir  -p  $DEST_DIR

    cd $SOURCE_DIRECTORY
    shopt -s nullglob
    for i in ${DOCS}; do
      if test -f "$i"; then
        file -bi $i|grep -q ^application && continue
        cp $SOURCE_DIRECTORY/${i} $DEST_DIR 2>/dev/null
      fi
    done

    for i in ${DOC_DIRS}; do
      if test -d "$i"; then
        cp -r $SOURCE_DIRECTORY/${i} $DEST_DIR 2>/dev/null
      fi
    done

    # making installed docs readable for all users.
    chmod -fR a+r $DEST_DIR

  fi

) }


#---------------------------------------------------------------------
##
## Copies pam configuration files to /etc/pam.d/
##
#---------------------------------------------------------------------
function install_pam_confs()  {

  debug  "libgrimoire" "Running install_pam_confs() on $SPELL"

  if  [  -d  "$SCRIPT_DIRECTORY/pam.d"  ];  then
    cd       "$SCRIPT_DIRECTORY/pam.d"

    mkdir  -p  $INSTALL_ROOT/etc/pam.d
    local FILE
    for  FILE  in  `ls`;  do
      if  !  [  -f  $INSTALL_ROOT/etc/pam.d/$FILE  ];  then
        cp  $FILE   $INSTALL_ROOT/etc/pam.d
      fi
    done

  fi

}

#---------------------------------------------------------------------
## Stuff that should be done if run_build_spell succeeds
## This is intended to be overridable at some point
#---------------------------------------------------------------------
function run_spell_success() {
    debug "build_api/common" "cast of $SPELL-$VERSION was successful"

    local INST_LOG="$INSTALL_LOGS/$SPELL-$VERSION"
    local MD5_LOG="$MD5SUM_LOGS/$SPELL-$VERSION"
    local TMP_INST_LOG="$TMP_DIR/$SPELL-$VERSION.install"
    local TMP_MD5_LOG="$TMP_DIR/$SPELL-$VERSION.md5"
    local CACHE="$INSTALL_CACHE/$SPELL-$VERSION-$HOST.tar"
    local CACHE_COMP=${CACHE}${EXTENSION}
    local C_LOG_COMP="$COMPILE_LOGS/$SPELL-$VERSION$EXTENSION"

    sound  SUCCESS

    # announce to everyone the spell succeeded
    activity_log  "cast"  "$SPELL"  "$VERSION"  "success"
    add_spell $SPELL installed $VERSION
    echo $SPELL >> $SUCCESS_LIST
    pop_install_queue "$SPELL"

    # update depends info
    debug "build_api/common" "Merging depends info"

    # none of the old values are valid, only the new, uncommitted values are
    remove_depends_status $DEPENDS_STATUS $SPELL
    local spell_depends spell_sub_depends spell_rsub_depends
    local t_DEPENDS_STATUS
    lock_start_transaction "$DEPENDS_STATUS" t_DEPENDS_STATUS
    get_uncommitted_depends_file $SPELL spell_depends
    if [ -e "$spell_depends" ] ; then
      cat  $spell_depends >> $t_DEPENDS_STATUS
    fi
    lock_commit_transaction $DEPENDS_STATUS

    # since the database is now accurate, no reason to keep old answers
    # floating around
    test -e "$ABANDONED_DEPENDS/$SPELL" &&
    rm -f $ABANDONED_DEPENDS/$SPELL &>/dev/null

    # none of the old values are valid, only the new, uncommitted values are
    remove_sub_depends $SUB_DEPENDS_STATUS "" "$SPELL"
    local spell_sub_depends
    local t_SUB_DEPENDS_STATUS
    lock_start_transaction "$SUB_DEPENDS_STATUS" t_SUB_DEPENDS_STATUS
    get_uncommitted_sub_depends_file $SPELL spell_sub_depends
    if [ -e "$spell_sub_depends" ] ; then
      cat  $spell_sub_depends >> $t_SUB_DEPENDS_STATUS
    fi
    lock_commit_transaction $SUB_DEPENDS_STATUS
    get_uncommitted_rsub_depends_file $SPELL spell_rsub_depends

    # compile log
    create_compile_log
    view_compile_log

    local tablet_dir=$(tablet_get_path $SPELL)
    if [ "$?" != 0 ] ; then
      message "failed to make a tablet directory: $tablet_dir" \
              "this may be a bug"
      unset tablet_dir
      local TABLET_IGNORE=yes
    else
      message  "${MESSAGE_COLOR}Creating tablet in directory"        \
               "${FILE_COLOR}${tablet_dir}${DEFAULT_COLOR}"
      tablet_install_spell_files $tablet_dir
      local TABLET_SPELL_DIR=$tablet_dir spell_config_stage
      spell_config_stage=$CONFIG_STAGE_DIRECTORY/$SPELL
      lock_file "$spell_config_stage"
      if [[ $STAGED_INSTALL != "off" && -d $spell_config_stage/current ]]
      then
        rmdir $spell_config_stage/current $spell_config_stage 2>/dev/null
        if [[ -d $spell_config_stage/current ]]
        then
          # check if a config we staged was already staged and if so, remove it.
          # this way users don't have to merge the same old default config again
          # and again if they cast a spell multiple times
          local deferred_file file quasi_basename
          find $spell_config_stage/current -type f |
          while read deferred_file; do
            quasi_basename=$(sed "s,$spell_config_stage/current/,," <<< "$deferred_file")
            find $spell_config_stage -wholename $spell_config_stage/current \
                 -prune -o -type f -wholename "*/$quasi_basename" -print |
            while read file; do
              if cmp -s $deferred_file $file; then
                recursive_config_stage_cleanup $deferred_file $SPELL
                continue 2
              fi &>/dev/null
            done
          done

          [[ -d $spell_config_stage/current ]] &&
          mv $spell_config_stage/current \
             $spell_config_stage/$(basename $tablet_dir)
        fi
      fi
      unlock_file "$spell_config_stage"
      # this data is now doubly stale, remove it
      rm  -f $ABANDONED_PERSIST/$SPELL.p
    fi

    # install log
    message  "${MESSAGE_COLOR}Creating install log" \
             "${FILE_COLOR}${INST_LOG}${DEFAULT_COLOR}"
    # this will make a "root" format install log it will need to be
    # reformatted to "log" format (see log_adjuster in libtrack for details)
    # but basically replacing INSTALL_ROOT with TRACK_ROOT
    create_install_log $IW_LOG $TMP_INST_LOG
    if [[ $STAGED_INSTALL == on ]]; then
      # save the md5sums of the files in the stage and not the target
      # ones on the system, otherwise config merging breaks #13835
      # for this we need an "install" log of what is in the stage
      local STAGE_INST_LOG="$TMP_DIR/$SPELL-$VERSION.stage.install"
      create_stage_install_log $TMP_INST_LOG $STAGE_INST_LOG
      if [[ $tablet_dir ]] ; then
        find $tablet_dir >> $STAGE_INST_LOG
      fi
    fi
    if [[ $tablet_dir ]] ; then
      find $tablet_dir >> $TMP_INST_LOG
    fi
    log_adjuster $TMP_INST_LOG $INST_LOG root log

    # md5sum log
    message  "${MESSAGE_COLOR}Creating MD5 log"        \
             "${FILE_COLOR}${MD5_LOG}${DEFAULT_COLOR}"
    if [[ $STAGED_INSTALL == on ]]; then
      create_md5list $STAGE_INST_LOG $TMP_MD5_LOG
      sed -i "s#${STAGE_DIRECTORY}/TRANSL##g" $TMP_MD5_LOG
    else
      create_md5list $TMP_INST_LOG $TMP_MD5_LOG
    fi
    log_adjuster $TMP_MD5_LOG $MD5_LOG root log md5_log_filter

    # do this before cache archive creation (bug 8249)
    rm_source_dir
    if [[ $STAGED_INSTALL != off ]]
    then
      destroy_stage_root
    fi

    # cache archive

    # Archives are stored with INSTALL_ROOT and STATE_ROOT stripped.
    # this way they can be unpacked anywhere and sorcery will know
    # where things will be.
    create_cache_archive $TMP_INST_LOG $CACHE $CACHE_COMP

    report_install
    rm  -f $IW_LOG $C_LOG $TMP_INST_LOG $TMP_MD5_LOG "$STAGE_INST_LOG" \
           "$spell_sub_depends" "$spell_rsub_depends" "$spell_depends"
}

#---------------------------------------------------------------------
## Stuff that should be done if run_build_spell fails
## This is intended to be overridable at some point
#---------------------------------------------------------------------
function run_spell_failure() {
    debug "build_api/common" "cast of $SPELL-$VERSION failed"
    local rc=$1

    sound  FAILURE

    activity_log "cast" "$SPELL"  "$VERSION" "failure"
    echo $SPELL >> $FAILED_LIST

    # if it failed after PRE_BUILD make a compile log
    if [ "$rc" != 1 ] ; then
      create_compile_log
      view_compile_log
    fi

    # put the answers somewhere where they can still be used later
    mkdir -p $ABANDONED_DEPENDS
    local spell_depends
    get_uncommitted_depends_file $SPELL spell_depends
    [ -e "$spell_depends" ] && mv $spell_depends $ABANDONED_DEPENDS/$SPELL

    # This may have been locked if there was a failure during the install
    unlock_resources "libgrimoire" "install"

    IW_LOG="$INSTALLWATCHFILE"
    devoke_installwatch

    rm -f $IW_LOG $C_LOG

    local spell_sub_depends spell_rsub_depends
    get_uncommitted_sub_depends_file $SPELL spell_sub_depends
    get_uncommitted_rsub_depends_file $SPELL spell_rsub_depends
    rm -f "$spell_sub_depends" "$spell_rsub_depends"

    if [[  $CLEAN_SOURCE == on ]]
    then
      rm_source_dir
      if [[ $STAGED_INSTALL != off ]]
      then
        destroy_stage_root
      fi
    fi
    CAST_EXIT_STATUS=1
}
