#!/bin/sh
#
# Copyright (c) 2008-2011 Juan Romero Pardines.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# 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.
#-

: ${XBPS_CONFIG_FILE:=@@XBPS_INSTALL_ETCDIR@@/xbps-src.conf}

: ${progname:=$(basename $0)}
: ${fakeroot_cmd:=/usr/bin/fakeroot}
: ${fakeroot_cmd_args:=--}
: ${sudo_cmd:=sudo}
: ${chroot_cmd:=chroot}
: ${xbps_machine:=$(uname -m)}

# Required utilities in host system.
REQHOST_UTILS="awk bash bison sed gcc msgfmt patch makeinfo \
	perl fakeroot tar xz gzip bzip2"

check_reqhost_utils()
{
	local broken

	[ -n "$IN_CHROOT" ] && return 0
	[ -r "$XBPS_MASTERDIR/.xbps_perms_done" ] && return 0

	for f in ${REQHOST_UTILS}; do
		if ! command -v ${f} 2>&1 >/dev/null; then
			echo "${f} is missing in your system, can't continue!"
			broken=1
		fi
	done

	[ -n "$broken" ] && exit 1
}

usage()
{
	cat << _EOF
$progname: [-BCDhKS] [-c file] [-m dir] [-p dir] [-s dir] [target] [pkgname]

Targets:
 bootstrap
  Build and install from source the bootstrap packages into <masterdir>.

 build [pkgname]
  Build package source (fetch + extract + configure + build).

 build-pkg [pkgname|all]
  Build a binary package from <pkgname> or all packages with the <all>
  keyword. The package(s) must be installed into <destdir> for this to work.

 checkvers
  Checks installed package versions in <masterdir> against the srcpkgs tree
  for new available versions.

 chroot
  Enter to the chroot in <masterdir>.

 clean [pkgname]
  Remove <pkgname> build directory.

 configure [pkgname]
  Configure a package (fetch + extract + configure).

 extract [pkgname]
  Extract package source distribution file(s) into the build directory.
  By default set to <masterdir>/builddir.

 fetch [pkgname]
  Download package source distribution file(s).

 info [pkgname]
  Show information for the specified package.

 install [pkgname]
  Installs a package into destination directory and \`stows' its files into
  <masterdir>. If a package is not from bootstrap group, its files will be
  symlinked rather than being fully copied.

 list
  List installed packages in <masterdir>.

 list-files <pkgname>
  List package files from <pkgname>. Package must be fully installed
  into <masterdir> for this to work.

 make-repoidx
  Build a package index for the local repository associated with the
  master directory <masterdir>. By default set to <masterdir/host/binpkgs.
  To specify another repo, use -p <dir>.

 remove [pkgname]
  Remove package completely from <destdir> and <masterdir>.

 stow [pkgname]
  Stow <pkgname> files from <destdir> into <masterdir> and register package
  in database. When a package is \`stown', its files will be available in
  <masterdir>, and other packages will be able to found it.

 unstow [pkgname]
  Remove <pkgname> files from <masterdir> and unregister package
  from database.

On targets that accept [pkgname], a package name can be specified and xbps-src
will execute the task on any CWD (Current Working Directory). If the argument
is omitted xbps-src assumes that CWD is in the target package. Example:

	$ cd srcpkgs/libX11 && xbps-src install
	$ xbps-src install libX11

Both ways are equivalent.

Options:
 -B  Used in the install target, a binary package is built for any
     required dependency as well as for <pkgname>. The local repository
     pkg-index is created or updated after a successful package installation.
 -C  Do not remove build directory after successful installation.
 -c  Path to global configuration file:
     if not specified @@XBPS_INSTALL_ETCDIR@@/xbps-src.conf is used.
 -D  Only install <pkgname> to package's destdir (set to
     <masterdir>/destdir/<pkgname>-<version> by default).
 -h  Usage output.
 -K  Do not remove automatic package dependencies while building
     or installing a package with XBPS_PREFER_BINPKG_DEPS enabled.
 -m  Master directory, overwritting the value set in the configuration
     file xbps-src.conf.
 -p  Local packages repository, overwritting default path at
     <masterdir>/host/binpkgs or if XBPS_HOSTDIR is set <hostdir>/binpkgs.
 -S  Overrides and disables XBPS_PREFER_BINPKG_DEPS even if it was
     set in the configuration file xbps-src.conf.
 -s  Source distribution files directory, overwritting default path at
     <masterdir>/host/sources or if XBPS_HOSTDIR is set <hostdir>/sources.
_EOF
}

basename_cwd()
{
	echo $(basename $(pwd))
}

check_path()
{
	eval local orig="$1"

	case "$orig" in
		/) ;;
		/*) orig="${orig%/}" ;;
		*) orig="$(pwd)/${orig%/}" ;;
	esac

	path_fixed="$orig"
}

run_file()
{
	local file="$1"

	check_path "$file"
	. $path_fixed
}

check_config_vars()
{
	local val cffound f cfpaths cf="xbps-src.conf"

	if [ -z "$XBPS_CONFIG_FILE" ]; then
		cfpaths="@@XBPS_INSTALL_PREFIX@@/etc/${cf} ./etc/${cf}"
		for f in $cfpaths; do
			if [ -f ${f} ]; then
				XBPS_CONFIG_FILE=${f}
				cffound=yes
				break
			fi
		done
		[ -z "$cffound" ] && msg_error "cannot find a config file\n"
	fi

	run_file ${XBPS_CONFIG_FILE}
	export XBPS_CONFIG_FILE=$path_fixed

	if [ ! -f "$XBPS_CONFIG_FILE" ]; then
		msg_error "cannot find configuration file: $XBPS_CONFIG_FILE\n"
	fi

	for f in XBPS_DISTRIBUTIONDIR XBPS_MASTERDIR; do
		eval val="\$${f}"
		if [ -z "$val" ]; then
			msg_error "'${f}' not set in configuration file!\n"
		fi
	done
	if [ ! -d "$XBPS_MASTERDIR" ]; then
		mkdir -p "$val"
		if [ $? -ne 0 ]; then
			msg_error "couldn't create 'XBPS_MASTERDIR' directory\n"
		fi
	fi
	[ -z "${_MASTERDIR_FLAG}" ] && export _MASTERDIR="$XBPS_MASTERDIR"
}

#
# main()
#
while getopts "CBc:DhKm:p:Ss:" opt; do
	case $opt in
	B) export BUILD_BINPKG=1;;
	C) export KEEP_WRKSRC=1;;
	c) XBPS_CONFIG_FILE="$OPTARG";;
	D) export DESTDIR_ONLY_INSTALL=1;;
	h) usage && exit 0;;
	K) export KEEP_AUTODEPS=1;;
	m)
		_MASTERDIR_FLAG=1
		_MASTERDIR="$OPTARG"
		if [ ! -d ${_MASTERDIR} ]; then
			mkdir -p ${_MASTERDIR}
		fi
		;;
	p)
		_PACKAGEDIR="$OPTARG"
		if [ ! -d ${_PACKAGEDIR} ]; then
			mkdir -p ${_PACKAGEDIR}/${xbps_machine}
			mkdir -p ${_PACKAGEDIR}/noarch
		fi
		;;
	S) UNSET_PREFER_BINPKG_DEPS=1;;
	s) export XBPS_SRCDISTDIR="$OPTARG";;
	--) shift; break;;
	esac
done
shift $(($OPTIND - 1))

[ $# -eq 0 -o $# -gt 2 ] && usage && exit 1

target="$1"
_pkgname="$2"

if [ -z "$target" ]; then
	echo "=> ERROR: missing target."
	usage && exit 1
fi

if [ -n "$IN_CHROOT" ]; then
	XBPS_CONFIG_FILE="/usr/local/etc/xbps-src.conf"
fi

#
# Check configuration vars before anyting else, and set defaults vars.
#
check_config_vars
if [ -n "${_MASTERDIR}" ]; then
	export XBPS_MASTERDIR=${_MASTERDIR}
fi
. @@XBPS_INSTALL_SHAREDIR@@/shutils/init_funcs.sh
set_defvars
for f in $XBPS_SHUTILSDIR/*.sh; do
	[ -r "$f" ] && . $f
done

# Disable XBPS_PREFER_BINPKG_DEPS if requested.
[ -n "$UNSET_PREFER_BINPKG_DEPS" ] && unset XBPS_PREFER_BINPKG_DEPS

#
# Check for required utilities in host system.
#
check_reqhost_utils

#
# Fix up some vars when XBPS_USE_CAPABILITIES is set.
#
if [ -n "$XBPS_USE_CAPABILITIES" ]; then
	chroot_cmd="@@XBPS_INSTALL_LIBEXECDIR@@/capchroot"
	unset sudo_cmd
fi

if [ "$(id -u)" -eq 0 ]; then
	# disable sudo and fakeroot if uid==0
	chroot_cmd="chroot"
	unset sudo_cmd
	if [ -n "$IN_CHROOT" ]; then
		unset fakeroot_cmd
		unset fakeroot_cmd_args
	fi
fi

#
# Sanitize PATH.
#
if [ -z "$IN_CHROOT" ]; then
	# In non chroot case always prefer host tools.
	MYPATH="$PATH:$XBPS_MASTERDIR/bin:$XBPS_MASTERDIR/usr/bin"
	MYPATH="$XBPS_MASTERDIR/usr/local/bin:$MYPATH"
	MYPATH="$XBPS_MASTERDIR/usr/local/sbin:$MYPATH"
else
	if [ -n "$XBPS_CCACHE" ]; then
		CCACHEPATH="/usr/lib/ccache/bin"
	fi
	# In chroot always prefer tools from bootstrap.
	MYPATH="$CCACHEPATH:/tools/bin:/usr/local/sbin:/bin:/usr/bin"
	MYPATH="$MYPATH:/sbin:/usr/local/bin:/usr/sbin"
fi
export PATH="$MYPATH"

#
# If masterdir is ready (base-chroot installed and chroot set up) and
# XBPS_PREFER_BINPKG_DEPS enabled, force ignoring rules to handle
# bootstrap packages.
#
if [ -n "$DESTDIR_ONLY_INSTALL" -a -n "$XBPS_PREFER_BINPKG_DEPS" \
     -a -f "$XBPS_MASTERDIR/.xbps_perms_done" ]; then
	export BOOTSTRAP_PKG_REBUILD=1
fi

#
# Main switch.
#
case "$target" in
bootstrap)
	[ ! -d $XBPS_SRCPKGDIR/base-chroot ] && \
		msg_error "Cannot find $XBPS_SRCPKGDIR/base-chroot directory!\n"
	cd $XBPS_SRCPKGDIR/base-chroot && _ORIGINPKG="$(basename_cwd)"
	setup_tmpl ${_ORIGINPKG} && install_pkg $pkgname
	;;
build|configure)
	if [ -z "${_pkgname}" ]; then
		[ ! -r ./template ] && msg_error "missing build template in $(pwd).\n"
		. ./template
		_pkgname=$(basename_cwd)
	fi

	if [ -z "$bootstrap" -a -z "$IN_CHROOT" ]; then
		xbps_chroot_handler $target ${_pkgname}
	else
		_ORIGINPKG="${_pkgname}"
		setup_tmpl ${_ORIGINPKG}
		# If pkg has dependencies, install them first.
		install_dependencies_pkg "$pkgname-$version"
		if [ $? -ne 0 ]; then
			msg_red "cannot install required deps for $pkgname.\n"
			exit 1
		fi
		# All deps were installed, continue with the origin pkg...
		setup_tmpl ${_ORIGINPKG}
		fetch_distfiles || exit $?
		if [ ! -f "$XBPS_EXTRACT_DONE" ]; then
			extract_distfiles || exit $?
		fi
		if [ "$target" = "configure" ]; then
			configure_src_phase || exit $?
		else
			if [ ! -f "$XBPS_CONFIGURE_DONE" ]; then
				configure_src_phase || exit $?
			fi
			build_src_phase || exit $?
		fi
	fi
	;;
build-pkg)
	if [ -n "${_PACKAGEDIR}" ]; then
		export XBPS_PACKAGESDIR=${_PACKAGEDIR}
	fi
	if [ "$2" = "all" ]; then
		for f in $($XBPS_BIN_CMD list|awk '{print $1}'); do
			pkg=$(${XBPS_PKGDB_CMD} getpkgname $f)
			setup_tmpl $pkg
			if [ "${pkg}" = "${sourcepkg}" ]; then
				xbps_make_binpkg
			fi
		done
	else
		if [ -z "${_pkgname}" ]; then
			[ ! -r ./template ] && msg_error "missing build template in $(pwd).\n"
			_pkgname=$(basename_cwd)
		fi
		setup_tmpl ${_pkgname}
		xbps_make_binpkg
	fi
	;;
checkvers)
	check_installed_packages
	;;
chroot)
	xbps_chroot_handler chroot dummy
	;;
clean)
	if [ -z "${_pkgname}" ]; then
		[ ! -r ./template ] && msg_error "missing build template in $(pwd).\n"
		_pkgname=$(basename_cwd)
	fi
	setup_tmpl ${_pkgname}
	remove_tmpl_wrksrc $wrksrc
	;;
extract|fetch|info)
	if [ -z "${_pkgname}" ]; then
		[ ! -r ./template ] && msg_error "missing build template in $(pwd).\n"
		_pkgname=$(basename_cwd)
	fi
	setup_tmpl ${_pkgname}
	if [ "$target" = "info" ]; then
		info_tmpl
		exit $?
	fi
	fetch_distfiles $update_checksum
	extract_distfiles
	;;
install)
	if [ -z "${_pkgname}" ]; then
		[ ! -r ./template ] && msg_error "missing build template in $(pwd).\n"
		_pkgname=$(basename_cwd)
	fi
	setup_tmpl ${_pkgname}
	_ORIGINPKG="${_pkgname}"
	if [ -z "$IN_CHROOT" -a -z "$bootstrap" ]; then
		xbps_chroot_handler $target ${_ORIGINPKG} || exit $?
	else
		setup_tmpl ${_ORIGINPKG}
		install_pkg $pkgname || exit $?
	fi
	;;
list)
	$XBPS_BIN_CMD list
	;;
list-files)
	list_pkg_files ${_pkgname}
	;;
make-repoidx)
	if [ -n "${_PACKAGEDIR}" ]; then
		export XBPS_PACKAGESDIR=${_PACKAGEDIR}
	fi
	msg_normal "Updating pkg-index for local repository at:\n"
	msg_normal " $XBPS_PACKAGESDIR\n"
	${XBPS_REPO_CMD} genindex ${XBPS_PACKAGESDIR} 2>/dev/null
	;;
remove)
	if [ -z "${_pkgname}" ]; then
		[ ! -r ./template ] && msg_error "missing build template in $(pwd).\n"
		_pkgname=$(basename_cwd)
	fi
	setup_tmpl ${_pkgname}
	if [ -z "$IN_CHROOT" -a -z "$bootstrap" ]; then
		xbps_chroot_handler $target ${_pkgname}
        else
		remove_pkg
	fi
	;;
stow)
	stow_flag=yes
	if [ -z "${_pkgname}" ]; then
		[ ! -r ./template ] && msg_error "missing build template in $(pwd).\n"
		_pkgname=$(basename_cwd)
	fi
	setup_tmpl ${_pkgname}
	stow_pkg_handler stow
	;;
unstow)
	if [ -z "${_pkgname}" ]; then
		[ ! -r ./template ] && msg_error "missing build template in $(pwd).\n"
		_pkgname=$(basename_cwd)
	fi
	setup_tmpl ${_pkgname}
	stow_pkg_handler unstow
	;;
*)
	msg_red "xbps-src: invalid target $target.\n"
	usage && exit 1
esac

# Agur
exit $?