################################################################################
#
# php.cygclass - functions for building PHP (PECL and PEAR) extensions
#
# Part of cygport - Cygwin packaging application
# Copyright (C) 2006-2015 Yaakov Selkowitz
# Provided by the Cygwin Ports project <http://sourceware.org/cygwinports/>
#
# cygport is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# cygport is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with cygport.  If not, see <http://www.gnu.org/licenses/>.
#
################################################################################

#****h* Cygclasses/php.cygclass
#  SYNOPSIS
#  [PHP_CHANNEL="..."]
#  inherit php
#  DESCRIPTION
#  PHP is a programming language most commonly used as an HTML preprocessor
#  for creating dynamic web pages.  The interpreter comes in three forms, known
#  as SAPIs: command-line, CGI, and Apache Web Server DSO.  Extensions written
#  in either PHP or C can be installed to provide additional functionality.
#
#  This cygclass is meant for building PHP extension packages.
#  EXAMPLES
#  A typical PEAR (pure PHP) module package looks like this:
#
#    PHP_CHANNEL=pear
#    inherit php
#    
#    NAME="php-Archive_Tar"
#    VERSION=1.3.11
#    RELEASE=1
#    CATEGORY="PHP"
#    SUMMARY="PHP class for creating and managing tarballs"
#    DESCRIPTION="The Archive_Tar class helps in creating and managing GNU tar
#    format files compressed by Gzip or not. The class offers basic functions
#    like creating an archive, adding files in the archive, extracting files
#    from the archive and listing the archive content."
#    
#    # these are loaded only conditionally
#    php_Archive_Tar_REQUIRES="php-bz2 php-zlib"
#
#  PECL extensions (written in C) are similarly straightforward:
#
#    PHP_CHANNEL=pecl
#    inherit php
#    
#    NAME="php-ncurses"
#    VERSION=1.0.2
#    RELEASE=1
#    CATEGORY="PHP"
#    SUMMARY="PHP ncurses extension"
#    DESCRIPTION="Terminal screen handling extension for PHP (cli-mode only)"
#    
#    CYGCONF_ARGS="--enable-ncursesw"
#
#  Third-party PEAR channels are also easily handled by setting PHP_CHANNEL:
#
#    PHP_CHANNEL="pear.phpunit.de"
#    inherit php
#    
#    NAME="php-PHPUnit"
#    VERSION=3.7.21
#    RELEASE=1
#    CATEGORY="PHP"
#    SUMMARY="PHP unit testing framework"
#    DESCRIPTION="An open source framework for test-driven development with the
#    PHP programming language."
#
#  REQUIRES
#  php, php-PEAR
#****

# cross-compiling is not (yet?) supported
__cross_compiling_error

check_prog_req php-config php-devel

#****d* php.cygclass/PHP
#  DESCRIPTION
#  Absolute path to the PHP interpreter.
#****
PHP=/usr/bin/php

#****d* php.cygclass/PHP_CONFIG
#  DESCRIPTION
#  Absolute path to the PHP configuration script.
#****
PHP_CONFIG=/usr/bin/php-config

#****d* php.cygclass/PHPIZE
#  DESCRIPTION
#  Absolute path to the PHP extension buildsystem preparation script.
#****
PHPIZE=/usr/bin/phpize

#****d* php.cygclass/PEAR
#  DESCRIPTION
#  Absolute path to the PHP script extension manager.
#****
PEAR=/usr/bin/pear

#****d* php.cygclass/PECL
#  DESCRIPTION
#  Absolute path to the PHP C extension manager.
#****
PECL=/usr/bin/pecl

#****d* php.cygclass/PHP_VERSION
#  DESCRIPTION
#  Version of the PHP interpreter.
#****
PHP_VERSION=$(${PHP_CONFIG} --version)

#****d* php.cygclass/PHP_INI_DIR
#  DESCRIPTION
#  Path to the PHP configuration file.
#****
PHP_INI_DIR=/etc/php5

#****d* php.cygclass/PHP_EXTENSION_DIR
#  DESCRIPTION
#  Installation directory for PHP C extensions.
#****
PHP_EXTENSION_DIR=$(${PHP_CONFIG} --extension-dir)

#****d* php.cygclass/PHP_PEAR_DIR
#  DESCRIPTION
#  Installation directory for PHP script extensions.
#****
PHP_PEAR_DIR=/usr/share/pear

#****d* php.cygclass/LIBPHP
#  DESCRIPTION
#  Link library for the PHP interpreter C library.
#  NOTE
#  This link library is Cygwin specific.  On ELF platforms, PHP modules are
#  linked with undefined symbols, which are resolved at runtime by the SAPI
#  in use.  Since the PE/COFF format used on Cygwin requires that all symbols
#  be resolved at link time, a library is used which all SAPIs and extensions
#  link against.
#****
LIBPHP=$(${PHP_CONFIG} --libs)

#****v* php.cygclass/PHP_CHANNEL
#  DESCRIPTION
#  Domain name, or well-known alias, of the PEAR/PECL server on which the PHP
#  extension is hosted. This variable must be defined before inherit()ing
#  php.cygclass to have any effect.
#
#  A list of known channels is available at http://pear.php.net/channels/ .
#****

case ${PN} in php-*)
ORIG_PN=${ORIG_PN:-${PN#php-}}

#****o* php.cygclass/CATEGORY (php)
#  DEFINITION
CATEGORY="PHP"
#  NOTE
#  This is defined only if PN begins with "php-".
#****
#****o* php.cygclass/SUMMARY (php)
#  DEFINITION
SUMMARY="PHP ${ORIG_PN} extension"
#  NOTE
#  This is defined only if PN begins with "php-".
#****
;;
esac

#****o* php.cygclass/HOMEPAGE (php)
#  DESCRIPTION
#  Web address for the PHP extension.  This variable is defined only if
#  PHP_CHANNEL was defined before inherit()ing php.cygclass.
#****
#****o* php.cygclass/SRC_URI (php)
#  DESCRIPTION
#  Download location for the PHP extension sources.  This variable is defined
#  only if PHP_CHANNEL was defined before inherit()ing php.cygclass.
#****

__php_channel_fixup() {
	local channel

	if ! defined PHP_CHANNEL
	then
		return 0
	fi

	case ${PHP_CHANNEL,,} in
		11abacus)	channel="pear.11abacus.com" ;;
		agavi)		channel="pear.agavi.org" ;;
		arbit)		channel="pear.arbittracker.org" ;;
		aws)		channel="pear.amazonwebservices.com" ;;
		complexml)	channel="pear.complexml.org" ;;
		crisscott)	channel="pear.crisscott.com" ;;
		deepend)	channel="pear.survivethedeepend.com" ;;
		docblox)	channel="pear.docblox-project.org" ;;
		doctrine)	channel="pear.doctrine-project.org" ;;
		domain51)	channel="pear.domain51.com" ;;
		dotsunited)	channel="pear.dotsunited.de" ;;
		erebot)		channel="pear.erebot.net" ;;
		eveyron)	channel="pear.eveyron.com" ;;
		ezc)		channel="components.ez.no" ;;
		fluentdom)	channel="pear.fluentdom.org" ;;
		geometria-lab)	channel="pear.geometria-lab.net" ;;
		horde)		channel="pear.horde.org" ;;
		invenzzia)	channel="pear.invenzzia.org" ;;
		michelf)	channel="pear.michelf.com" ;;
		openpear)	channel="openpear.org" ;;
		pat)		channel="pear.php-tools.net" ;;
		pdepend)	channel="pear.pdepend.org" ;;
		pear)		channel="pear.php.net" ;;
		pearflex)	channel="pear.pearplex.net" ;;
		pearhub)	channel="pearhub.org" ;;
		pecl)		channel="pecl.php.net" ;;
		phergie)	channel="pear.phergie.org" ;;
		phing)		channel="pear.phing.info" ;;
		phpdocs)	channel="doc.php.net" ;;
		phpmd)		channel="pear.phpmd.org" ;;
		phpseclib)	channel="phpseclib.sourceforge.net" ;;
		phpspec)	channel="pear.phpspec.net" ;;
		phpuc)		channel="pear.phpundercontrol.org" ;;
		phpunit)	channel="pear.phpunit.de" ;;
		piece)		channel="pear.piece-framework.com" ;;
		pirum)		channel="pear.pirum-project.org" ;;
		psx)		channel="pear.phpsx.org" ;;
		qubit)		channel="pear.qubit-toolkit.org" ;;
		querypath)	channel="pear.querypath.org" ;;
		ragnaroek)	channel="ragnaroek.pear.midgard-project.org" ;;
		sabredav)	channel="pear.sabredav.org" ;;
		sc)		channel="semanticscuttle.sourceforge.net" ;;
		sikz)		channel="pear.si.kz" ;;
		smarty)		channel="pear-smarty.googlecode.com/svn" ;;
		solar)		channel="solarphp.com" ;;
		sugar)		channel="pear.php-sugar.net" ;;
		swift)		channel="pear.swiftmailer.org" ;;
		symfony)	channel="pear.symfony-project.com" ;;
		symfony2)	channel="pear.symfony.com" ;;
		timj)		channel="pear.timj.co.uk" ;;
		twig)		channel="pear.twig-project.org" ;;
		typo3)		channel="pear.typo3.org" ;;
		zend)		channel="zend.googlecode.com/svn" ;;
		zero.mq)	channel="pear.zero.mq" ;;
		*.*)		channel=${PHP_CHANNEL} ;;
		# possible fallback; if non-existant, will error out later
		*)		channel="${PHP_CHANNEL}.pearfarm.org" ;;
	esac

	echo -n ${channel}
}

PHP_CHANNEL=$(__php_channel_fixup)

case "${PHP_CHANNEL}" in
'') ;;
pear.php.net)
	HOMEPAGE="http://pear.php.net/package/${ORIG_PN}/"
	SRC_URI="http://download.pear.php.net/package/${ORIG_PN}-${PV}.tgz"
	;;
pecl.php.net)
	HOMEPAGE="http://pecl.php.net/package/${ORIG_PN}/"
	SRC_URI="http://pecl.php.net/get/${ORIG_PN}-${PV}.tgz"
	;;
*)
	if ! $(${PEAR} list-channels | grep -q "^${PHP_CHANNEL} ")
	then
		if ! $(${PEAR} channel-discover ${PHP_CHANNEL} &> /dev/null)
		then
			error "php: channel not found: ${PHP_CHANNEL}"
		fi
	fi
	HOMEPAGE="http://${PHP_CHANNEL%%/*}"
	SRC_URI="http://${PHP_CHANNEL}/get/${ORIG_PN}-${PV}.tgz"
	;;
esac

__php_is_binary() {
	if [ -f ${S}/config.m4 ]
	then
		return 0
	else
		return 1
	fi
}

#****C* php.cygclass/php_autoreconf
#  SYNOPSIS
#  lndirs
#  cd $B
#  php_autoreconf
#  DESCRIPTION
#  Runs PHPIZE to prepare the PHP extension build system.  This function must
#  be run from the directory containing config.m4.
#****
php_autoreconf() {
	if [ ! -e config.m4 ]
	then
		error "config.m4 not found"
	fi

	__config_set with_aclocal 1
	__config_set with_autoconf 1
	__config_set with_autoheader 1
	__config_set with_automake 1
	__config_set with_libtool 1

	${PHPIZE} || error "phpize failed"
	# phpize uses its own copy of gnuconfig, no need to gnuconfigize here
}

#****C* php.cygclass/php_compile
#  SYNOPSIS
#  cd $B
#  php_compile [OPTIONS]
#  DESCRIPTION
#  Configures the PHP extension with cygconf, then compiles it with cygmake.
#  Arguments, if any, are passed as configure flags to cygconf.
#****
php_compile() {
	if __php_is_binary
	then
		test -e configure && CYGCONF_SOURCE=$PWD
		cygconf \
			--enable-${ORIG_PN}=shared --with-${ORIG_PN}=shared \
			"${@}"

		cygmake
	fi
}

#****I* php.cygclass/php_install
#  SYNOPSIS
#  cd $B
#  php_install
#  DESCRIPTION
#  Installs the PHP extension into $D.
#****
php_install() {
	local PEXX

	if __php_is_binary
	then
		cygmake -j1 install INSTALL_ROOT=${D}
		PEXX=PECL
	else
		PEXX=PEAR
	fi

	# FIXME: this won't register the binary extension file location
	${!PEXX} install \
		--force --loose --nobuild --nodeps --offline --packagingroot=${D} \
		./package.xml \
		|| error "${PEXX} install failed"
}

#****I* php.cygclass/php_postinst
#  SYNOPSIS
#  php_postinst
#  DESCRIPTION
#  Performs the following steps:
#  * If the package contains C extensions, creates configuration files which
#    will cause the extensions to be loaded by PHP automatically.
#  * If PHP_CHANNEL is other than 'pear' or 'pecl', a postinstall script is
#    created to register the channel with the installed PHP.
#  * Cleans up files which will collide with those already on the system.
#****
php_postinst() {
	local x

	if [ -d ${D}${PHP_EXTENSION_DIR} ]
	then
		dodir ${PHP_INI_DIR}/conf.d

		for x in ${D}${PHP_EXTENSION_DIR}/*.dll
		do
			xf=${x##*/}
			if $(${OBJDUMP} -p ${x} | grep -q zend_startup_module)
			then
				echo "zend_extension = ${PHP_EXTENSION_DIR}/${xf}" >> ${D}${PHP_INI_DIR}/conf.d/${xf%.dll}.ini
			else
				echo "extension = ${xf}" >> ${D}${PHP_INI_DIR}/conf.d/${xf%.dll}.ini
			fi
		done
	fi

	case "${PHP_CHANNEL}" in
	pear.php.net|pecl.php.net) ;;
	'') ;;
	*)	dodir /etc/postinstall
		cat >> ${D}/etc/postinstall/${PN}.sh <<-_EOF
			/usr/bin/pear channel-discover ${PHP_CHANNEL} || true

			_EOF
		;;
	esac

	if [ -d ${D}${PHP_PEAR_DIR} ]
	then
		pushd ${D}${PHP_PEAR_DIR}
		rm -fr .channels/ .depdb .depdblock .filemap .lock
		popd
	fi

	rm -fr ${D}/tmp/pear
}

#****I* php.cygclass/php_fix_shebang
#  SYNOPSIS
#  php_fix_shebang SCRIPT [SCRIPT ...]
#  DESCRIPTION
#  Fixes the designated interpreter of SCRIPT to PHP.  This would be necessary
#  if the original uses an incorrect path (e.g. /usr/local/bin) or an
#  incorrectly versioned binary.  SCRIPT need not be prefixed by $D.
#****
php_fix_shebang() {
    __fix_shebang ${PHP} ${D}/${@#${D}}
}

#****o* php.cygclass/src_compile (php)
#  DESCRIPTION
#  Copies $S into $B with lndirs, then, if the package is a PHP C extension,
#  calls php_autoreconf and php_compile.
#****
src_compile() {
	lndirs
	# http://pear.php.net/news/package.xml.1.0.php
	if [ -f ${S}/../package2.xml ]
	then
		ln -sf ${S}/../package2.xml ${B}/package.xml
	else
		ln -sf ${S}/../package.xml ${B}/package.xml
	fi

	if __php_is_binary
	then
		cd ${B}
		php_autoreconf
		php_compile
	fi
}

#****o* php.cygclass/src_install (php)
#  DEFINITION
src_install() {
	cd ${B}
	php_install
	php_postinst
}
#****

readonly -f __php_is_binary php_autoreconf php_compile php_install php_postinst \
            php_fix_shebang
