#!/bin/sh

# sbopkglint test, must be sourced by sbopkglint (not run standalone).

# PKG, PRGNAM, VERSION, ARCH are set by sbopkglint. also the current
# directory is the root of the installed package tree.

#######################################################################
# Test .pc (pkgconfig) files.
# - pkgconfig dir must match ARCH (lib vs. lib64).
# - pkg-config must be able to read and parse each file.
# - paths mentioned in the file must exist in the package.
# - for a 32-bit package, libdir must not be /usr/lib64.
# - for a 64-bit package, libdir must not be /usr/lib.
# - .pc files must be either ASCII or Unicode/UTF-8.

# note: quite a few .pc files don't use the standard variables like
# libdir. it's not required, so we can't just check for that. have to
# actually run pkg-config --cflags and --libs... but we have to
# rip any 'Requires:' or 'Requires.private:' line out first, because
# otherwise, pkg-config would pull in the flags/libs from any package
# mentioned there (if installed), or else complain that it doesn't
# exist.

check_libinc_dir() {
  local type=$1
  local flag=$2
  local file=$3
  local dir

  #echo "===> $flag"

  dir="$( printf "%s" $flag | tail -c+3 )"
  case "$dir" in
    /usr/local*)
      warn "$file references $type dir $dir; /usr/local is incorrect"
      return
      ;;
  esac

  [ -d $PKG/$dir ] || warn "$file references $type dir $dir, but it's missing from the package"
}

check_pc_file() {
  local file="$1"
  local tmpfile="./$1.tmp.pc"
  local mime
  local s

  ## echo "===> checking $file"

  if [ ! -f "$file" ]; then
    warn "$file is not a regular file:"
    ls -ld "$file"
    return
  fi

  s="$( stat -L -c '%a %U %G' "$file" )"
  case "$s" in
    "444 root root"|"644 root root") ;; # OK
    *)
      warn "$file has bad ownership/permissions (should be 0644, root/root)"
      ls -ld $file
      ;;
  esac

	if [ "$s" = "444 root root" ]; then
		: # we could warn here someday
	elif [ "$s" != "644 root root" ]; then
		BADPERMS+="$f "
	fi


  mime="$(file -bL --mime $file)"

  case "$mime" in
    text/plain*)
       case "$mime" in
         *charset=us-ascii|*charset=utf-8) ;; # OK
         *) warn "$file has bad character encoding '$( echo "$mime" | sed 's,.*charset=,,' )' (should be us-ascii or utf-8)"
            ;;
       esac
       ;;
    *) warn "$file is '$mime', not plain text (are you sure it's a .pc file?)"
       ;;
    esac

  case "$file" in
    *.pc) ;; # OK
    *) warn "$file is not a .pc file" ; return ;;
  esac

  if ! pkg-config --validate $file; then
    warn "$file is not a valid .pc file"
    return
  fi

  grep -v '^Requires' $file > $tmpfile

  # the environment stuff keeps pkg-config from stripping out
  # -L/usr/lib or -L/usr/lib64 on the grounds that it's a system dir.
  # GtkD's .pc file has --libs output like -L-lgstreamerd-3 -L-L/usr/lib64/,
  # which turn out to be not C flags but D flags for dmd. handled with
  # sed, below.
  for flag in xxx \
    $( env PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1 \
           PKG_CONFIG_SYSTEM_LIBRARY_PATH=1 \
           pkg-config --short-errors --libs --cflags $tmpfile )
  do
    flag="$( printf "%s" $flag | sed '/^-L=*-/s,^-L=*,,' )"
    case $flag in
      xxx) ;; # skip (it's just there in case there are no flags at all)
      -L/usr/$bad|-L/usr/$bad/)
         warn "$file has /usr/$bad for libdir, should be /usr/$good"
         ;;
      -L/usr/$good|-L/usr/$good/)
         ;; # OK
      -L*) check_libinc_dir library "$flag" "$file"
         ;;
      -I/usr/include|-I/usr/include/)
         ;; # OK
      -I/usr/local*) check_libinc_dir include "$flag" "$file"
         ;;
      -I*) ## check_libinc_dir include "$flag" "$file" # don't be picky about include dirs
         ;;
      *) ;; # skip any other flags (-lwhatever, -Dwhatever, etc)
    esac
  done

  rm -f $tmpfile
}

check_pc_dir() {
  local file
  local dir=$1

  if [ ! -d $dir ]; then
    warn "$dir exists but is not a directory!"
    return
  fi

  # cumbersome way to check if a dir is empty
  if [ "$( find $dir -maxdepth 0 -empty )" != "" ]; then
    return
  fi

  for file in $dir/*; do
    check_pc_file $file
  done
}

check_pkgconfig() {
  local good bad bits dir

  if [ "$ARCH" = "x86_64" -o "$ARCH" = "aarch64" ]; then
    good=lib64; bad=lib; bits=64
  else
    good=lib; bad=lib64; bits=32
  fi

  gooddir=usr/$good/pkgconfig
  baddir=usr/$bad/pkgconfig
  if [ -d $baddir ]; then
    if [ -d $gooddir ]; then
      warn "$bits-bit package has both $baddir (wrong) and $gooddir (OK)"
    else
      warn "$bits-bit package has $baddir, should be $gooddir"
    fi
  fi

  for dir in $baddir $gooddir usr/share/pkgconfig; do
    [ -d $dir ] && check_pc_dir $dir
  done
}

check_pkgconfig
