#!/bin/bash
#
# deb-rearch -- a script to change the architecture from a .deb file.
#
# The programme has been published under the terms of the Artistic Licence.
# Please see https://www.opensource.org/licenses/artistic-license.php for more
# information.
#
# Based on
# deb-reversion © 2004-5 by martin f. krafft <madduck@debian.org>
# contributors: Goswin von Brederlow, Filippo Giunchedi
# deb-rearch © 2006, 2011, 2015 Guillem Jover <guillem@debian.org>
#

set -eu

PROGNAME=${0##*/}
PROGVERSION=0.2

error()
{
  echo "$PROGNAME error: $@" >&2
}

warn()
{
  echo "$PROGNAME $@" >&2
}

version()
{
  cat <<EOF
$PROGNAME version $PROGVERSION -- change a .deb file's architecture
EOF
}

usage()
{
  cat <<EOF
Usage: $PROGNAME [<options>...] <file>

The script will change the .deb file's architecture. The new .deb file will
be placed in the current directory.

Options:
  -a, --new-arch <arch>      The new arch to be used.
  -k, --hook                 Call the specified hook before repacking.
  -D, --debug                Debug mode (passed to dpkg-deb).
  -V, --version              Display version information.
  -h, --help                 Display this help text.
EOF
}

DIR=$(pwd)
SHORTOPTS=hVa:k:D
LONGOPTS=help,version,arch:,hook:,debug
# mode will track whether we are reading options, a deb-name or the changelog
# entry
mode=opts

# Need to use eval to handle multiword hooks
TEMP=$(getopt -s bash -o $SHORTOPTS -l $LONGOPTS --n $PROGNAME -- "$@")
eval set -- $TEMP

while [ $# -gt 0 ]; do
  opt=$1
  shift

  if [ "$mode" = opts ]; then
    case $opt in
    -*) unset OPT_STATE;;
    *)
      case $OPT_STATE in
      SET_ARCH)
        ARCH=$opt
        continue;;
      SET_HOOK)
        HOOK=$opt
        continue;;
      esac
    esac

    case $opt in
    -h|--help) usage >&2; exit 0;;
    -a|--arch) OPT_STATE=SET_ARCH;;
    -k|--hook) OPT_STATE=SET_HOOK;;
    -D|--debug) DPKGDEB_DEBUG=--debug;;
    -V|--version) version >&2; exit 0;;
    --) mode=debfile; continue;;
    esac
  elif [ "$mode" = debfile ]; then
    case $opt in
    /*.deb) DEB=$opt;;
    *.deb) DEB=${DIR}/$opt;;
    *)
      error "no .deb file has been specified"
      usage
      exit 1;;
    esac
  fi
done


if [ -z "$DEB" ]; then
  error "no .deb file has been specified"
  usage
  exit 1
elif [ ! -f $DEB ]; then
  error "$DEB does not exist"
  exit 2
fi

make_temp_dir()
{
  TMPDIR=$(mktemp -d /tmp/deb-rearch.XXXXXX)
  trap "rm -rf $TMPDIR" 0
  mkdir -p ${TMPDIR}/package
  TMPDIR=${TMPDIR}/package
}

extract_deb_file()
{
  dpkg-deb $DPKGDEB_DEBUG --raw-extract $1 .
}

get_package_name()
{
  dpkg-deb --field $1 'Package'
}

get_arch()
{
  dpkg-deb --field $1 'Architecture'
}

call_hook()
{
  export ARCH
  sh -c "$HOOK"
}

change_arch()
{
  PACKAGE=$(sed -ne 's,^Package: ,,p' DEBIAN/control)
  ARCH=$1
  call_hook
  sed -i -e "s,^Architecture: .*,Architecture: $ARCH," DEBIAN/control
}

repack_file()
{
  cd ..
  dpkg-deb -b package >/dev/null
  dpkg-name package.deb | sed -e 's,.*to `\(.*\).,\1,'
}

if [ "$ARCH" = "$(get_arch $DEB)" ]; then
  error "trying to change to the same architecture!"
  exit 2
fi

if [ `id -u` -ne 0 ]; then
  error "need to run me as root or using fakeroot!"
  exit 3
fi

make_temp_dir
cd $TMPDIR

PACKAGE=$(get_package_name $DEB)
extract_deb_file $DEB
change_arch $ARCH
FILE=$(repack_file)

if [ -f $DIR/$FILE ]; then
  warn "$DIR/$FILE exists, moving to $DIR/$FILE.orig"
  mv -i $DIR/$FILE $DIR/$FILE.orig
fi

mv ../$FILE $DIR

warn "arch $ARCH of $PACKAGE is now available in $FILE"
