#!/bin/bash
# ^ Requires GNU bash 2.xx or later (not ash nor sh)
#
#############################################################################
#
# Copyright (C) 2005 Lasse Collin <lasse.collin@slackware.fi>
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#
#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
#  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
#  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
#  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
#  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
#  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
#  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
#  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
#  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
#  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#############################################################################
#
# Last modified: 2005-06-27
#
#############################################################################


# Check how we are called; we need at least two parameters.
if [ "$2" = "" -o "$1" = "--help" ]; then
	cat << EOF

fakedestdir is an utility to help creating packages if makefile does not
support DESTDIR or similar feature. fakedestdir is used as a replacement
for the command 'make install'. Because fakedestdir is a script that makes
a couple ugly tricks to achieve its destination, you should use it only
when the makefile doesn't have a better alternative.

Usage: fakedestdir <destdir> <make_arguments>

Two log files, 'fakedestdir_make.log' and 'fakedestdir_faked.log', are
created to the current directory. They can be useful in case of problems.

Common and recommended use:
    ./configure --prefix=/usr
    make
    fakedestdir /tmp/mypkg install

Sometimes it might be needed to combine fakedestdir with DESTDIR or prefix:
    ./configure --prefix=/usr
    make
    fakedestdir /tmp/package DESTDIR=/tmp/mypkg prefix=/tmp/mypkg/usr install

WARNING: Don't use fakedestdir as root unless you know what you are doing!

EOF
	exit 0
fi

__fakedestdir_validate__() {
	# No spaces, dots or other problematic characters!
	[ "$(echo "$1" | sed -n '/^\/[a-zA-Z0-9._/-]*$/p')" = "" ] || return 0
	echo "$(basename "$0"): $2" \
			"a-z, A-Z, 0-9, dot (.), underscore (_) and hyphen (-)."
	exit 1
}

if [ "${__FAKEDESTDIR_DESTDIR__}" = "" ]; then
	# Validate the path to the fakedestdir script:
	__fakedestdir_validate__ "$0" \
			"The full path to the script '$0' can" \
			"contain only characters"
	# Validate the PATH where we are installing from:
	__fakedestdir_validate__ "$PWD" \
			"The full path to the current directory" \
			"characters other than"
	# Validate the given DESTDIR. We want it to be simple and absolute
	# path so we can be lazier later.
	__fakedestdir_validate__ "$1" \
			"Destination directory must be an absolute path" \
			"(i.e. begin with '/') and can contain only characters"
	# Make sure the destdir exists:
	if [ ! -d "$1" ]; then
		mkdir -p "$1" || exit $? # mkdir shows an error message.
	fi
	export __FAKEDESTDIR_DESTDIR__="/.$1" # Prevent destdir being replaced.
	export __FAKEDESTDIR_SOURCEDIR__=$(echo "$PWD" | sed 's,\.,\\.,g')
	export __FAKEDESTDIR_LOG__="$PWD/fakedestdir_faked.log"
	rm -f "${__FAKEDESTDIR_LOG__}"
	shift 1
	set -o pipefail
	make "SHELL=/.$0" "$@" 2>&1 | tee fakedestdir_make.log
	exit $?
fi


# The tricks begin...

# make can call us with or without '-c' but we don't need it:
[ "$1" = "-c" ] && shift 1

__FAKEDESTDIR_CMD__=$*
ROOTDIRS='(bin|boot|dev|etc|home|lib|media|mnt|opt|sbin|tmp|usr|var)'

# Everybody loves sed, right? ;-)
__FAKEDESTDIR_CMD__=$(echo "${__FAKEDESTDIR_CMD__}" | sed -r "

	# Protect the paths pointing to the source directory tree:
	s,${__FAKEDESTDIR_SOURCEDIR__},/.&,g

	# libtool commands:
	s,(libtool )((--[^ ]* *)* )(/*${ROOTDIRS})\b,\1\2/.\4,g

	# Redirects to /dev/null or other devs:
	s,(>+ *)(/dev/[a-zA-Z0-9]+),\1/.\2,g

	# Other command names:
	s,(^|; *|; *do +|&& +|\|\| +)(/+${ROOTDIRS})\b,\1/.\2,g

	# Finaly replace paths pointing to directories in the filesystem root:
	s,( |'|:|=|-D)(/+${ROOTDIRS})\b,\1${__FAKEDESTDIR_DESTDIR__}\2,g")

# Argument manipulation complete, good luck.
unset ROOTDIRS
echo "${__FAKEDESTDIR_CMD__}" >> "${__FAKEDESTDIR_LOG__}"
eval "${__FAKEDESTDIR_CMD__}"

# EOF
