#!/bin/sh
# Различная статистика по пакетам

v_pkg_detail_status="$STATE_ROOT/pkg_detail"
v_pkg_detail_status_tmp="${TMP_ROOT}/pkg_detail"

v_pkg_update_status="${TMP_ROOT}/pkg_update"
v_pkg_update_status_res="${STATE_ROOT}/pkg_update"
v_pkg_detail_status_list="${TMP_ROOT}/pkg_detail_status_list"

pkg_init () {
  if ! [ -d "$v_pkg_detail_status" ]; then
    mkdir -p "$v_pkg_detail_status"
  fi

  if ! [ -d "${v_pkg_detail_status_tmp}" ] ; then
    mkdir -p "${v_pkg_detail_status_tmp}"
  fi

  log "Update pakages"
  pkg update 2>&1 | log
  # Обновление базы аудита происходит на получении общих данных по пакетам

  touch "${v_pkg_detail_status_list}"
}


pkg_get_detail_pkg_list () {
  local vl_pkg_name
  local vl_buf

  cat "${USER_MON_PKG_LIST}" | while read vl_buf; do
    vl_pkg_name=$(pkg query '%n' "${vl_buf}")
    [ -n "${vl_pkg_fullname}" ] && echo "${vl_pkg_name}" >> "${v_pkg_detail_status_list}"
  done

  service -e | awk '$1 ~ "^/usr/local" {print $1}' | while read vl_buf; do
    if ! [ -f "$vl_buf" ] ; then
      continue
    fi

    vl_pkg_name="$(pkg which "$vl_buf" | awk '$0 ~ "was installed by package" {print $6}')"

    if [ -z "$vl_pkg_name" ] ; then
      log "$vl_buf have no matched pkg"
      continue
    fi

    vl_pkg_name="$(pkg query '%n' "$vl_pkg_name")"

    {
      echo "${vl_pkg_name}"
      pkg query '%rn' "${vl_pkg_name}"
      pkg query '%dn' "${vl_pkg_name}"
    } >> "${v_pkg_detail_status_list}"
  done
}


pkg_make_detail () {
  local vl_pkg_buf
  local vl_pkg_fullname
  local vl_pkg_repo
  local vl_pkg_name
  local vl_pkg_ver
  local vl_status_file
  local vl_status_tmp_file
  local vl_pkg_status

  pkg_get_detail_pkg_list
  cat "${v_pkg_detail_status_list}" | sort | uniq | while read vl_pkg_buf; do
    log "Working with $vl_pkg_buf"

    vl_pkg_fullname="$(pkg query '%n-%v' "${vl_pkg_buf}")"
    vl_pkg_name="$(pkg query '%n' "$vl_pkg_fullname")"
    vl_pkg_repo="$(pkg query '%R' "$vl_pkg_fullname")"
    vl_pkg_ver="$(pkg query '%v' "$vl_pkg_fullname")"
    vl_pkg_status="$(pkg version -r "$vl_pkg_repo" -qUn "$vl_pkg_name" | tail -n 1 | awk '{print $2}')"

    case "$vl_pkg_status" in
      = )
        vl_pkg_status=OK
        ;;

      "<" )
        vl_pkg_status="NEED UPDATE"
        ;;

      ">" )
        vl_pkg_status="REPO VERSION LOWER"
        ;;

      "?" )
        vl_pkg_status="NO PACKAGE IN REPO"
        ;;

      "!" )
        vl_pkg_status="ERROR"
        log_err -s "${vl_pkg_name}: pkg can not compare version of package"
        ;;

      * )
        log_err -s "${vl_pkg_name}: unknown status ${vl_pkg_status}"
        vl_pkg_status="ERROR"
        ;;

    esac

    vl_status_file="${v_pkg_detail_status}/${vl_pkg_name}"
    vl_status_tmp_file="${v_pkg_detail_status_tmp}/${vl_pkg_name}"

    pkg query 'installed=%t\nmainteiner=%m\nsize=%sb\nlocked=%k' "$vl_pkg_fullname" \
      > "${vl_status_tmp_file}"

    printf 'ver=%s\nrepo=%s\nstatus=%s\n' "${vl_pkg_ver}" "${vl_pkg_repo}" "${vl_pkg_status}" >> "$vl_status_tmp_file"
    
    (
      if [ -n "$(pkg audit -q "$vl_pkg_fullname")" ];  then
        pkg audit "$vl_pkg_fullname"
      fi
    ) > "${vl_status_tmp_file}.audit"

    mv -f "${vl_status_tmp_file}" "${vl_status_file}"
    mv -f "${vl_status_tmp_file}.audit" "${vl_status_file}.audit"
  done
}


pkg_check_up_status () {
  # Проверка статуса наличия обновления для пакета
  local vl_pkg_name
  local vl_pkg_repo

  cat /dev/null > "$v_pkg_update_status"
  pkg version -qUL = | awk '$2 != ">" {print $1}' | while read _pkg; do
      vl_pkg_name="$(pkg query '%n' "${_pkg}")"
      vl_pkg_repo="$(pkg query '%R' "${_pkg}")"
      log "Check update for ${vl_pkg_name} in ${vl_pkg_repo}"
      pkg version -Ur "${vl_pkg_repo}" -n "${vl_pkg_name}" \
      | awk '$2 == "!" || $2 == "<" || $2 == "?"  {print $1}' \
      | tee -a "$v_pkg_update_status" \
      | awk '$0 != "" {print "UPDATE STATUS:", $0}' | log
  done

  pkg upgrade -Uqn | tee -a "$v_pkg_update_status" | awk '$0 != "" {print "PKG UPGRADE:", $0}' | log
  mv -f "$v_pkg_update_status" "$v_pkg_update_status_res"

}


pkg_check_pkg_binary () {
  # Проверяет, нет ли в системе других запущенных приложений pkg. 
  # Необходимо, чтобы не мешать оперативным процессам обновления

  {
    ps -Ao comm | awk '$1 == "pkg" {print $1}' | wc -l | tr -d ' '
  } 2>/dev/null
  
}


pkg_finaly () {
  # Процедура завершения обработки пакетов

  # -
  # Удаляем старые файлы, в которые давно не не пишутся данные по пакетам
  log "Clean old files -- detail and audit pakages"
  find "$v_pkg_detail_status" -type f -cmin +30 -print0 | xargs -0n 1 rm -frv 2>&1 | log
}


pkg_do () {
  local _other_pkgs

  log_start "pkg_do"

  _other_pkgs="$(pkg_check_pkg_binary)"

  if [ "$_other_pkgs" -ne 0 ] ; then
    log "Pakages update check fail: other '${_other_pkgs}' binary working"
    ps -Ao comm,ppid,pid,time | awk '$1 == "pkg" {print $0}' | log

  else
    pkg_init

    pkg_check_up_status
    pkg audit -qrF > "${v_pkg_update_status}.audit"
    mv -f "${v_pkg_update_status}.audit" "${v_pkg_update_status_res}.audit"

    pkg_make_detail
  fi

  pkg_finaly
  log_end
}