#! /bin/bash
#  This program is part of the Qi package manager
#
#  Copyright (C) 2015, 2016  Matias A. Fonzo
#
#  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 2 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/>.

# EXIT STATUS
# 0   = Successful completion
# 1   = Minor common errors (e.g: help usage, support not available)
# 2   = Command execution error
# 3   = Integrity check error for compressed files
# 4   = File empty, not regular, or expected

# Override locale settings
export LC_ALL=C

# Functions
show_help() {
  printf '%s\n' \
   "Usage: qi install [options] package(s).tlz"                            \
   "Installs .tlz packages combined with graft(1) to link."                \
   ""                                                                      \
   "Install command options:"                                              \
   "  -h          display this help and exit"                              \
   "  -N          don't read runtime configuration file"                   \
   "  -P          package installation tree"                               \
   "  -T          target directory for linking"                            \
   "  -p          prune conflicts"                                         \
   "  -r          read package from the named pipe"                        \
   "  -v          graft(1) verbosity (use -V instead for more verbosity)"  \
   "  -w          warn about the files that will be linked"                \
   ""                                                                      \
   "Aliases for this command: \`add'"                                      \
   ""
}

# A function to reflect the base name
_basename() { local name="${1##*/}" ; printf %s "${name%$2}"; }

# Ignore some signals during the install
isignal() {
  trap "" HUP INT
  eval_cmd "$@"
  trap - HUP INT
}

# Directory of functions
readonly fndir="${LIBEXECDIR}/functions"

# Load (externally) internal functions
source "${fndir}"/helpers	|| exit 1
source "${fndir}"/readconfig	|| exit 1
source "${fndir}"/showvar	|| exit 1

# Default variable values
rcfile=rcfile
packagedir=/usr/packages
targetdir=/
prune_conflicts=no_prune_conflicts
read_pipe=noread_pipe
verbose=""
warn=nowarn

# Handle command-line options.
#
# An indexed array is created when an option is set.  It helps to the
# command line in order to take precedence over the config file

while getopts ":hNprvVw P:T:" option ; do
  case "$option" in
    (N)
      rcfile=no_rcfile
      ;;
    (P)
      packagedir="$OPTARG"
      cmdLineSets+=( packagedir )
      ;;
    (T)
      targetdir="$OPTARG"
      cmdLineSets+=( targetdir )
      ;;
    (p)
      prune_conflicts=prune_conflicts
      ;;
    (r)
      read_pipe=read_pipe
      ;;
    (v)
      verbose=-v
      ;;
    (V)
      verbose=-V
      ;;
    (w)
      warn=warn
      ;;
    (h)
      show_help
      exit 0
      ;;
     :)
      quit 1 \
       "The option '-${OPTARG}' requires an argument" \
       "Usage: qi install [-hNprvVw] [-P <dir>] [-T <dir>] package(s).tlz"
      ;;
    \?)
      quit 1 \
       "qi: install: illegal option -- '-${OPTARG}'" \
       "Usage: qi install [-hNprvVw] [-P <dir>] [-T <dir>] package(s).tlz"
      ;;
  esac
done
shift "$((OPTIND - 1))"

# If there are no arguments, one package is required
if (( $# == 0 )) && [[ $read_pipe != read_pipe ]] ; then
  quit 4 \
   "\nqi: install: You must specify at least one package." \
   "Try 'qi install -h' for more information."
fi

# Sanity check: graft's availability
if ! type -P graft > /dev/null ; then
  quit 1 "\"qi install\" cannot operate without graft(1).  Please check your PATH."
fi

# Read configuration file
if [[ $rcfile = rcfile ]] ; then
  # To mark some variables.  Redefinitions of this
  # variables are not allowed from the config file
  readonly prune_conflicts read_pipe verbose warn

  # Check existence, from where to read
  if [[ -e ~/.qirc ]] ; then
    configFrom="~/.qirc"		# $HOME.
  elif [[ -e @SYSCONFDIR@/qirc ]] ; then
    configFrom="@SYSCONFDIR@/qirc"	# System-wide.
  fi

  # Check file integrity, content
  if [[ -f $configFrom && -s $configFrom ]] ; then
    echo "Processing '${configFrom}' ..."
    readConfig < "$configFrom"
  else
    warn "WARNING: ${configFrom}: File empty or not regular."
  fi
fi

# Unset from memory unnecessary variables, arrays, functions
unset rcfile configFrom cmdLineSets readConfig

# Set default mask
umask 022

# Create required directories (if needed)
eval_cmd "mkdir -p "$packagedir" "$targetdir""

# Set default graft options for the user or for the super-user
graft_options="-u -l ${packagedir}/graft-log"
if (( $UID == 0 )) ; then
  graft_options="-P -l ${packagedir}/graft-log"
fi

# Read package from the named pipe if -r was given (client/reader)
if [[ $read_pipe = read_pipe ]] ; then
  echo "qi: install: PIPE: Waiting for server to create the pipe ..."
  until [[ -p /var/tmp/qi-pipe ]] ; do
    sleep 10;
  done

  set --	# Unset positional parameters, setting '#' to zero.
  IFS="" read -r < /var/tmp/qi-pipe
  set -- "$@" "$REPLY"
  unset REPLY
fi

# Main loop
for package in "$@" ; do
  if [[ ! -f $package ]] ; then
    quit 4 "qi: install: File '${package}' not found or not regular."
  fi

  # Check file extension
  if [[ ${package##*.} != tlz ]] ; then
    quit 4 "qi: install: File '${package}' does not end in .tlz"
  fi

  # Check and run the warn, if -w is given
  if [[ $warn = warn ]] ; then
    printf '%s\n' ""  "%%% Scanning package '${package}' ..."

    # Show file list inside the package excluding the directories
    eval_cmd "tar -tvvf "$package" | awk '!/^drwx/'"

    continue;
  fi

  # Get the name of the package without the extension
  name="$(_basename "$package" .tlz)"

  # Check the integrity of the tarball
  echo "==> Checking integrity of '${name}.tlz' ..."
  isignal 3 "tar -tf "$package" > /dev/null"

  # To install the package
  echo "==> Installing package \"${name}\" in \`${packagedir}' ..."
  eval_cmd "mkdir -p "${packagedir}/$name""

  # Proceed to unpack the package
  isignal 3 "tar xpf "$package" -C "${packagedir}/$name""

  # Remove objects (files, links or directories) from the target
  # directory that are in conflict with the package directory
  if [[ $prune_conflicts = prune_conflicts ]] ; then
    isignal "graft -p -D $verbose -t "$targetdir" "${packagedir}/$name""
  fi

  # Graft the package
  isignal "graft -i $graft_options $verbose -t "$targetdir" "${packagedir}/$name""

  # Show package information from the recipe.
  #
  # Get the name of the package removing the last two segments "-"
  pkgname="${name%-*-*}"	# Removes -version-arch+build.

  # Include possible recipe names composed as "kernel3.10"
  for recipe in ""${packagedir}/${name}/var/lib/qi/recipes/${pkgname}*.recipe"" ; do
    if [[ -f $recipe ]] ; then
      # Display information using fold(1) for fancy format
      showVar description notes homepage licenses "$recipe" | fold -w 72
      break;
    fi
  done

  unset name pkgname recipe
done

