We have moved to Git. This repository is only provided for compatibility with old installations. Learn how to migrate your installation here.

view eclass/x-mgcf-golang-common.eclass @ 249:0685ed0fb913

[sync] imported 2c6bf87..18f98a6 from upstream commit 18f98a6f47cd77c1007b60dbfc7a838ffa99df0c Author: Daniel Neugebauer <dneuge@energiequant.de> Date: Mon Mar 27 21:11:43 2023 +0200 app-crypt/acmetool: version bump to 0.2.2 commit ee2df4ec1deab61cd7bb7de2cd13ffdd066cc41a Author: Daniel Neugebauer <dneuge@energiequant.de> Date: Mon Mar 27 19:30:58 2023 +0200 app-crypt/acmetool: split 0.2.1 from 9999, changed dependencies commit f3c9cf1c7a24619446390b0b71bf5bc090dfce77 Author: Daniel Neugebauer <dneuge@energiequant.de> Date: Mon Mar 27 19:29:33 2023 +0200 removed dependency to go-overlay commit b2057a9b0ba65917f3840a6b121c1e78397c4723 Author: Daniel Neugebauer <dneuge@energiequant.de> Date: Mon Mar 27 19:27:28 2023 +0200 golang eclasses: prefixed exported functions x-mgcf- commit e8d02d1edc997fec9e0b1e5d053a5b82ca4accf2 Author: Daniel Neugebauer <dneuge@energiequant.de> Date: Mon Mar 27 19:08:52 2023 +0200 renamed golang eclasses, updated maintainer, added disclaimer commit 748ea4be8ee777bc788cb2a8801b118b41e6f8aa Author: Daniel Neugebauer <dneuge@energiequant.de> Date: Mon Mar 27 18:43:56 2023 +0200 copied eclasses for Go from go-overlay Reason: These eclasses are used to build app-crypt/acmetool. We previously imported go-overlay as a master repository to use the eclasses defined there but the overlay has been removed from official Gentoo overlay index due to inactivity. The removal broke new initial checkouts for this repository as go-overlay can no longer be found. Gentoo bug for MegaCoffee: https://bugs.gentoo.org/903167 Gentoo bug that caused removal: https://bugs.gentoo.org/864653 Original repository: https://github.com/Dr-Terrible/go-overlay
author Migration Sync <gentoo-overlay@megacoffee.net>
date Mon, 27 Mar 2023 19:15:01 +0000
parents
children 32efd9258ce5
line wrap: on
line source

# Copyright 1999-2017 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Id$

# @ECLASS: x-mgcf-golang-common.eclass
# @MAINTAINER:
# MegaCoffee Overlay <gentoo-overlay@megacoffee.net>
# @AUTHOR:
# Mauro Toffanin <toffanin.mauro@gmail.com>
# @BLURB: Base eclass for GoLang packages
# @SUPPORTED_EAPIS: 7
# @DESCRIPTION:
# This eclass provides functionalities which are used by golang-single.eclass,
# golang-live.eclass, and as well as from ebuilds.
#
# This eclass should not be inherited directly from an ebuild.
# Instead, you should inherit golang-single or golang-live for GoLang packages.

inherit eutils multiprocessing

# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# !!!                                                             !!!
# !!!                L E G A C Y    E C L A S S                   !!!
# !!!                                                             !!!
# !!!         DO NOT USE OUTSIDE OF MEGACOFFEE OVERLAY            !!!
# !!!                                                             !!!
# !!!                DO NOT USE FOR NEW EBUILDS                   !!!
# !!!                                                             !!!
# !!! This eclass has only been copied to megacoffee overlay from !!!
# !!! go-overlay: https://github.com/Dr-Terrible/go-overlay       !!!
# !!!                                                             !!!
# !!! The only purpose is to keep currently depending ebuilds     !!!
# !!! until they could be migrated to standard eclasses for Go,   !!!
# !!! if suitable.                                                !!!
# !!!                                                             !!!
# !!! go-overlay was previously imported by megacoffee until it   !!!
# !!! got removed from Gentoo overlay index in March 2023,        !!!
# !!! rendering megacoffee overlay unreachable as a result.       !!!
# !!!                                                             !!!
# !!! Related bugs: https://bugs.gentoo.org/864653                !!!
# !!!               https://bugs.gentoo.org/903167                !!!
# !!!                                                             !!!
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


if [[ -z ${_GOLANG_BASE_ECLASS} ]]; then
_GOLANG_BASE_ECLASS=1

# Silences repoman warnings.
case "${EAPI:-0}" in
	7)
		case "${GOLANG_PKG_DEPEND_ON_GO_SUBSLOT:-yes}" in
			yes)
				GO_DEPEND="dev-lang/go:0="
				;;
			*)
				GO_DEPEND="dev-lang/go:*"
				;;
		esac
		;;
	*)
		die "${ECLASS}: EAPI=${EAPI:-0} is not supported" ;;
esac

DEPEND+=" ${GO_DEPEND}"

RESTRICT+=" mirror strip"

QA_FLAGS_IGNORED="usr/bin/.*
	usr/sbin/.*"

# @ECLASS-VARIABLE: GOLANG_PKG_NAME
# @DESCRIPTION:
# Sets the GoLang name for the generated package.
# GOLANG_PKG_NAME="${PN}"
GOLANG_PKG_NAME="${GOLANG_PKG_NAME:-${PN}}"

# @ECLASS-VARIABLE: GOLANG_PKG_VERSION
# @DESCRIPTION:
# Sets the GoLang version for the generated package.
# GOLANG_PKG_VERSION="${PV}"
GOLANG_PKG_VERSION="${GOLANG_PKG_VERSION:-${PV/_pre/.pre}}"

# @ECLASS-VARIABLE: GOLANG_PKG_IMPORTPATH
# @DESCRIPTION:
# Sets the remote import path for the generated package.
# GOLANG_PKG_IMPORTPATH="github.com/captObvious/"
GOLANG_PKG_IMPORTPATH="${GOLANG_PKG_IMPORTPATH:-}"

# @ECLASS-VARIABLE: GOLANG_PKG_IMPORTPATH_ALIAS
# @DESCRIPTION:
# Sets an alias of the remote import path for the generated package.
# GOLANG_PKG_IMPORTPATH_ALIAS="privaterepo.com/captObvious/"
GOLANG_PKG_IMPORTPATH_ALIAS="${GOLANG_PKG_IMPORTPATH_ALIAS:=${GOLANG_PKG_IMPORTPATH}}"

# @ECLASS-VARIABLE: GOLANG_PKG_ARCHIVEPREFIX
# @DESCRIPTION:
# Sets the archive prefix for the file URI of the package.
# Most projects hosted on GitHub's mirrors provide archives with prefix as
# 'v' or 'source-', other hosted services offer different archive formats.
# This eclass defaults to an empty prefix.
GOLANG_PKG_ARCHIVEPREFIX="${GOLANG_PKG_ARCHIVEPREFIX:-}"

# @ECLASS-VARIABLE: GOLANG_PKG_ARCHIVESUFFIX
# @DESCRIPTION:
# Sets the archive suffix for the file URI of the package.
# Most projects hosted on GitHub's mirrors provide archives with suffix as
# '.tar.gz' or '.zip', other hosted services offer different archive formats.
# This eclass defaults to '.tar.gz'.
GOLANG_PKG_ARCHIVESUFFIX="${GOLANG_PKG_ARCHIVESUFFIX:=".tar.gz"}"

# @ECLASS-VARIABLE: GOLANG_PKG_OUTPUT_NAME
# @DESCRIPTION:
# Specifies the output file name of the package.
# If not set, it derives from the name of the package, such as $GOLANG_PKG_NAME.
# This eclass defaults to $PN.
GOLANG_PKG_OUTPUT_NAME="${GOLANG_PKG_OUTPUT_NAME:=${PN}}"

# @ECLASS-VARIABLE: GOLANG_PKG_BUILDPATH
# @DESCRIPTION:
# Specifies a go source file to be compiled as a single main package.
# This eclass defaults to an empty value.
# This eclass defaults to "/..." when the user declares GOLANG_PKG_IS_MULTIPLE=1
GOLANG_PKG_BUILDPATH="${GOLANG_PKG_BUILDPATH:-}"

# @ECLASS-VARIABLE: GOLANG_PKG_INSTALLPATH
# @DESCRIPTION:
# Sets the root path into which a binary, or a list of binaries, will be
# installed (e.x.: ${GOLANG_PKG_INSTALLPATH}/bin).
# This eclass defaults to "/usr"
GOLANG_PKG_INSTALLPATH="${GOLANG_PKG_INSTALLPATH:="/usr"}"

# @ECLASS-VARIABLE: GOLANG_PKG_INSTALLSUFFIX
# @DESCRIPTION:
# Sets a suffix to use in the name of the package installation directory.
# This eclass defaults to an empty install suffix.
GOLANG_PKG_INSTALLSUFFIX="${GOLANG_PKG_INSTALLSUFFIX:-}"

# @ECLASS-VARIABLE: GOLANG_PKG_IS_MULTIPLE
# @DESCRIPTION:
# Set to enable the building of multiple packages from a single import path.

# @ECLASS-VARIABLE: GOLANG_PKG_HAVE_TEST
# @DEFAULT_UNSET
# @DESCRIPTION:
# Set to enable the execution of automated testing.

# @ECLASS-VARIABLE: GOLANG_PKG_HAVE_TEST_RACE
# @DEFAULT_UNSET
# @DESCRIPTION:
# Set to enable the execution of automated testing with support for
# data race detection.

# @ECLASS-VARIABLE: GOLANG_PKG_USE_CGO
# @DEFAULT_UNSET
# @DESCRIPTION:
# Set to enable the compilation of the package with CGO.

# @ECLASS-VARIABLE: GOLANG_PKG_USE_GENERATE
# @DEFAULT_UNSET
# @DESCRIPTION:
# Set to run commands described by directives within existing golang files.

# @ECLASS-VARIABLE: GOLANG_PKG_DEPEND_ON_GO_SUBSLOT
# @DESCRIPTION:
# Set to ensure the package does depend on the dev-lang/go subslot value.
# Possible values: {yes,no}
# This eclass defaults to "no"
GOLANG_PKG_DEPEND_ON_GO_SUBSLOT=${GOLANG_PKG_DEPEND_ON_GO_SUBSLOT:="no"}

# @ECLASS-VARIABLE: GOLANG_PKG_LDFLAGS
# @DESCRIPTION:
# Sets the linker arguments to pass to 5l, 6l, or 8l.
# This eclass defaults to an empty list.
GOLANG_PKG_LDFLAGS="${GOLANG_PKG_LDFLAGS:-}"

# @ECLASS-VARIABLE: GOLANG_PKG_TAGS
# @DESCRIPTION:
# Sets the list of build tags during the build.
# This eclass defaults to an empty list.
GOLANG_PKG_TAGS="${GOLANG_PKG_TAGS:-}"

# @ECLASS-VARIABLE: GOLANG_PKG_VENDOR
# @DESCRIPTION:
# Sets additional standard Go workspaces to be appended to the environment
# variable GOPATH, as described in http://golang.org/doc/code.html.
# This eclass defaults to an empty list.
GOLANG_PKG_VENDOR=()

# @ECLASS-VARIABLE: GOLANG_PKG_STATIK
# @DESCRIPTION:
# Sets the arguments to pass to dev-go/statik.
# This eclass defaults to an empty list.
GOLANG_PKG_STATIK="${GOLANG_PKG_STATIK:-}"

# @ECLASS-VARIABLE: GOLANG_PKG_USE_MODULES
# @DESCRIPTION:
# Set to enable the compilation of the package with Go modules support.


# @ECLASS-VARIABLE: GO
# @DEFAULT_UNSET
# @DESCRIPTION:
# The absolute path to the current GoLang interpreter.
#
# This variable is set automatically after calling golang_setup().
#
# Default value:
# @CODE
# /usr/bin/go
# @CODE

# @ECLASS-VARIABLE: EGO
# @DEFAULT_UNSET
# @DESCRIPTION:
# The executable name of the current GoLang interpreter.
#
# This variable is set automatically after calling golang_setup().
#
# Default value:
# @CODE
# go
# @CODE

# @ECLASS-VARIABLE: PATCHES
# @DEFAULT_UNSET
# @DESCRIPTION:
# Array variable containing all the patches to be applied. This variable
# is expected to be defined in the global scope of ebuilds. Make sure to
# specify the full path. This variable is used in src_prepare phase.
#
# Example:
# @CODE
#	PATCHES=(
#		"${FILESDIR}/mypatch.patch"
#		"${FILESDIR}/mypatch2.patch"
#	)
# @CODE



# Adds gccgo as a compile-time dependency when GOLANG_PKG_USE_CGO is set.
#[[ -n ${GOLANG_PKG_USE_CGO} ]] && DEPEND+=" >=sys-devel/gcc-4.8.4[go]"

# Adds dev-go/statik as a compile-time dependency when GOLANG_PKG_STATIK is set.
[[ -n ${GOLANG_PKG_STATIK} ]] && DEPEND+=" dev-go/statik"

# Validates GOLANG_PKG_IMPORTPATH.
if [[ -z ${GOLANG_PKG_IMPORTPATH} ]]; then
	eerror "The remote import path for this package has not been declared"
	die "Mandatory variable GOLANG_PKG_IMPORTPATH is unset"
fi

# Forces a multiple package build when user specifies GOLANG_PKG_IS_MULTIPLE=1.
if [[ -n ${GOLANG_PKG_IS_MULTIPLE} && -z ${GOLANG_PKG_BUILDPATH} ]]; then
	GOLANG_PKG_BUILDPATH="/..."
fi

# Validates use of GOLANG_PKG_BUILDPATH combined with GOLANG_PKG_IS_MULTIPLE
# FIX: makes sure user isn't overriding GOLANG_PKG_BUILDPATH with inane values.
if [[ -n ${GOLANG_PKG_IS_MULTIPLE} && ${GOLANG_PKG_BUILDPATH##*/} != "..." ]]; then
	ewarn "Ebuild ${CATEGORY}/${PF} specifies GOLANG_PKG_IS_MULTIPLE=1,"
	ewarn "but then GOLANG_PKG_BUILDPATH is overridden with \"${GOLANG_PKG_BUILDPATH}\"."
	ewarn "Please, fix it by appending \"/...\" to your GOLANG_PKG_BUILDPATH."
	ewarn "If in doubt, remove GOLANG_PKG_BUILDPATH entirely."
fi

# Even though xz-utils are in @system, they must still be added to DEPEND; see
# http://archives.gentoo.org/gentoo-dev/msg_a0d4833eb314d1be5d5802a3b710e0a4.xml
if [[ ${GOLANG_PKG_ARCHIVESUFFIX/.*} == "xz" ]]; then
	DEPEND+=" app-arch/xz-utils"
fi

# Defines common USE flags
IUSE="${IUSE} debug pie"
# Enables USE 'test' when required by GOLANG_PKG_HAVE_TEST.
if [[ -n ${GOLANG_PKG_HAVE_TEST} ]]; then
	IUSE+=" test"
fi

# Defines HOMEPAGE.
[ -z "$HOMEPAGE" ] && HOMEPAGE="https://${GOLANG_PKG_IMPORTPATH}/${PN}"

# Defines SOURCE directory.
S="${WORKDIR}/gopath/src/${GOLANG_PKG_IMPORTPATH_ALIAS}/${GOLANG_PKG_NAME}"


# @FUNCTION: _factorize_dependency_entities
# @INTERNAL
# @DESCRIPTION:
# Factorizes the dependency declaration in specific tokens such as the import
# path, the import path alias, the host name, the author name, the project name,
# and the revision tag.
_factorize_dependency_entities() {
	debug-print-function ${FUNCNAME} "${@}"

	local -A dependency=()
	local key_list=(importpathalias importpath host project_name author_name revision)

	# Strips all the white spaces from the supplied argument.
	local raw_dependency="${1//\ /}"

	# Determines the alias of the import path (if present).
	dependency[importpathalias]="${raw_dependency##*->}"

	# Strips the import path alias from the supplied argument.
	raw_dependency="${raw_dependency%%->*}"

	# Determines the import path.
	dependency[importpath]="${raw_dependency%:*}"

	# When the importpath alias is not specified, then this eclass sets the
	# alias as equal to the import path minus the project name.
	if [[ "${raw_dependency}" == "${dependency[importpathalias]}" ]]; then
		dependency[importpathalias]="${dependency[importpath]%/*}"
	fi

	# Determines the host.
	dependency[host]="${dependency[importpath]%%/*}"

	# Determines the project name.
	dependency[project_name]="${dependency[importpath]##*/}"

	# Determines the author name.
	dependency[author_name]="${dependency[importpath]#*/}"
	dependency[author_name]="${dependency[author_name]%/*}"

	# Determines the revision.
	dependency[revision]="${raw_dependency#*:}"

	# Exports all the dependency tokens as an associated list.
	for key in ${key_list[@]}; do
		echo "${key} ${dependency[${key}]}"
	done
}


# @FUNCTION: x-mgcf-golang_setup
# @DESCRIPTION:
# Determines where is the GoLang implementation and then set-up the
# GoLang build environment.
x-mgcf-golang_setup() {
	debug-print-function ${FUNCNAME} "${@}"

	# NOTE: Keep /usr/bin/go as index [0] and never overwrite it,
	#       always append other binary paths after the index [0]
	local GOLANG_BINS=(
		/usr/bin/go
		/usr/bin/gofmt
	)

	[[ -n ${GOLANG_PKG_STATIK} ]] && GOLANG_BINS+=(/usr/bin/statik)

	# Reset GoLang environment variables
	unset EGO
	unset EGOFMT
	unset ESTATIK
	unset GO
	unset GOPATH
	unset GOBIN

	# Determine is the GoLang interpreter is working
	local IS_EXECUTABLE=1
	for binary in "${GOLANG_BINS[@]}"; do
		debug-print "${FUNCNAME}: Checking ... ${binary}"

		[[ -x "${EPREFIX}/${binary}" ]] && continue
		IS_EXECUTABLE=0
		ewarn "It seems that the binary '${binary}' is not executable."
	done

	# dev-lang/go isn't installed or one of its binaries aren't executable.
	# Either way, the Gentoo box is screwed; no need to set up the GoLang environment
	[[ ${IS_EXECUTABLE} == 0 ]] && exit

	# dev-lang/go is available and working.
	# Exports GO/EGO/EGOFMT global variables.
	export GO="${GOLANG_BINS[0]}"
	export EGO="${GOLANG_BINS[0]##*/}"
	export EGOFMT="${GOLANG_BINS[1]}"

	# dev-go/statik is available and working.
	# Exports ESTATIK global variable.
	[[ -n ${GOLANG_PKG_STATIK} ]] && export ESTATIK="${GOLANG_BINS[2]##*/}"

	debug-print "${FUNCNAME}: GO = ${GO}"
	debug-print "${FUNCNAME}: EGO = ${EGO}"
	debug-print "${FUNCNAME}: EGOFMT = ${EGOFMT}"
	debug-print "${FUNCNAME}: ESTATIK = ${ESTATIK}"

	# Determines go interpreter version.
	GOLANG_VERSION="$( ${GO} version )"
	GOLANG_VERSION="${GOLANG_VERSION/go\ version\ go}"
	export GOLANG_VERSION="${GOLANG_VERSION%\ *}"
	einfo "Found GoLang version: ${GOLANG_VERSION}"

	# Determines statik interpreter version.
	# TODO: add version detection when statik will provide a -version option.
	if [[ -n ${GOLANG_PKG_STATIK} ]]; then
		local STATIK_VERSION=""
		einfo "Found statik version: ${STATIK_VERSION}"
	fi

	# Enable/Disable frame pointers
    local GOEXPERIMENT="noframepointer"
    use debug && GOEXPERIMENT="framepointer"

	# Sets the build environment inside Portage's WORKDIR.
	ebegin "Setting up GoLang build environment"

		# Prepares CGO_ENABLED.
		CGO_ENABLED=0
		[[ -z ${GOLANG_PKG_USE_CGO} ]] || CGO_ENABLED=1
		use pie && CGO_ENABLED=1 # PIE requires CGO

		# Prepares gopath / gobin directories inside WORKDIR.
		local _GOPATH="${WORKDIR}/gopath"
		local _GOBIN="${WORKDIR}/gobin"
		mkdir -p "${_GOBIN}" || die
		mkdir -p "${_GOPATH}"/src || die

		# Exports special env variable EGO_SRC.
		export EGO_SRC="${_GOPATH}/src"

		# Exports GoLang env variables.
		export GOPATH="$_GOPATH"
		export GOBIN="$_GOBIN"
		export CGO_ENABLED
		#export GOEXPERIMENT
		#export GO15VENDOREXPERIMENT=0

		GO111MODULE="off"
		[[ -z ${GOLANG_PKG_USE_MODULES} ]] || GO111MODULE="on"
		export GO111MODULE

		debug-print "${FUNCNAME}: GOPATH = ${GOPATH}"
		debug-print "${FUNCNAME}: GOBIN = ${GOBIN}"
		debug-print "${FUNCNAME}: EGO_SRC = ${EGO_SRC}"
		debug-print "${FUNCNAME}: CGO_ENABLED = ${CGO_ENABLED}"
	eend
}


# @FUNCTION: x-mgcf-golang-common_src_prepare
# @DESCRIPTION:
# Prepare source code.
x-mgcf-golang-common_src_prepare() {
	debug-print-function ${FUNCNAME} "${@}"

	pushd "${WORKDIR}" > /dev/null || die
		einfo "Preparing GoLang build environment in ${GOPATH}/src"

		# If the ebuild declares an importpath alias, then its path was
		# already created during the src_unpack phase. That means the eclass
		# needs to create the missing original import path (GOLANG_PKG_IMPORTPATH)
		# as a simbolic link pointing to the alias.
		if [[ "${GOLANG_PKG_IMPORTPATH}" != "${GOLANG_PKG_IMPORTPATH_ALIAS}" ]]; then

			# If the ebuild declares a GOLANG_PKG_NAME different from PN, then
			# the latter will be used as the simbolic link target.
			local TARGET="${GOLANG_PKG_NAME}"
			[[ "${PN}" != "${GOLANG_PKG_NAME}" ]] && TARGET="${PN}"

			x-mgcf-golang_fix_importpath_alias \
				"${GOLANG_PKG_IMPORTPATH_ALIAS}/${TARGET}" \
				"${GOLANG_PKG_IMPORTPATH}/${GOLANG_PKG_NAME}"
		fi

		# If the ebuild declares some GoLang dependencies, then they need to be
		# correctly installed into the sand-boxed GoLang build environment which
		# was set up automatically during src_unpack) phase.
		if [[ ${#GOLANG_PKG_DEPENDENCIES[@]} -gt 0 ]]; then

			for i in ${!GOLANG_PKG_DEPENDENCIES[@]} ; do

				# Collects all the tokens of the dependency.
				local -A DEPENDENCY=()
				while read -r -d $'\n' key value; do
					[[ -z ${key} ]] && continue
					DEPENDENCY[$key]="${value}"
				done <<-EOF
					$( _factorize_dependency_entities "${GOLANG_PKG_DEPENDENCIES[$i]}" )
				EOF

				# Debug
				debug-print "${FUNCNAME}: DEPENDENCY      = ${GOLANG_PKG_DEPENDENCIES[$i]}"
				debug-print "${FUNCNAME}: importpath      = ${DEPENDENCY[importpath]}"
				debug-print "${FUNCNAME}: importpathalias = ${DEPENDENCY[importpathalias]}"
				debug-print "${FUNCNAME}: host            = ${DEPENDENCY[host]}"
				debug-print "${FUNCNAME}: author          = ${DEPENDENCY[author_name]}"
				debug-print "${FUNCNAME}: project         = ${DEPENDENCY[project_name]}"
				debug-print "${FUNCNAME}: revision        = ${DEPENDENCY[revision]}"

				local message="Importing ${DEPENDENCY[importpath]}"
				local destdir

				# Prepares GOPATH structure.
				case ${DEPENDENCY[importpathalias]} in
					gopkg.in*)
						message+=" as ${DEPENDENCY[importpathalias]}"
						destdir="${DEPENDENCY[importpathalias]}"

						# Creates the import path in GOPATH.
						mkdir -p "${GOPATH}/src/${DEPENDENCY[importpathalias]%/*}" || die
						#einfo "\n${GOPATH}/src/${DEPENDENCY[importpathalias]%/*}"
						;;
					*)
						[[ "${DEPENDENCY[importpath]}" != "${DEPENDENCY[importpathalias]}/${DEPENDENCY[project_name]}" ]] && message+=" as ${DEPENDENCY[importpathalias]}/${DEPENDENCY[project_name]}"
						destdir="${DEPENDENCY[importpathalias]}/${DEPENDENCY[project_name]}"

						# Creates the import path in GOPATH.
						mkdir -p "${GOPATH}/src/${DEPENDENCY[importpathalias]}" || die
						#einfo "\n${GOPATH}/src/${DEPENDENCY[importpathalias]}"
						;;
				esac

				# Moves sources from WORKDIR into GOPATH.
				case ${DEPENDENCY[host]} in
					github*)
						ebegin "${message}"
							mv ${DEPENDENCY[project_name]}-${DEPENDENCY[revision]}* "${GOPATH}"/src/${destdir} || die
						eend

						# FIX: sometimes the source code inside an importpath alias
						#      (such as gopkg.in/mylib.v1) invokes imports from
						#      the original import path instead of using the alias,
						#      thus we need a symbolic link between the alias and
						#      the original import path to avoid compilation issues.
						#      Example: gopkg.in/Shopify/sarama.v1 erroneously
						#      invokes imports from github.com/shopify/sarama
						if [[ ${destdir} != ${DEPENDENCY[importpath]} ]]; then
							x-mgcf-golang_fix_importpath_alias ${destdir} ${DEPENDENCY[importpath]}
						fi
						;;
					bitbucket*)
						#einfo "path: ${DEPENDENCY[author_name]}-${DEPENDENCY[project_name]}-${DEPENDENCY[revision]}"
						ebegin "${message}"
							mv ${DEPENDENCY[author_name]}-${DEPENDENCY[project_name]}-${DEPENDENCY[revision]}* "${GOPATH}"/src/${destdir} || die
						eend
						;;
					code.google*)
						ebegin "${message}"
							mv ${DEPENDENCY[project_name]}-${DEPENDENCY[revision]}* "${GOPATH}"/src/${destdir} || die
						eend
						;;
					*) die "Function 'x-mgcf-golang-common_src_prepare' doesn't support '${DEPENDENCY[importpath]}'" ;;
				esac
			done

		fi

	popd > /dev/null || die


	# Auto-detects the presence of Go's vendored
	# dependencies inside $S/vendor.
	local VENDOR="${S}/vendor"
	if [[ -d "${VENDOR}" ]]; then
		x-mgcf-golang_add_vendor "${VENDOR}"
		export GO15VENDOREXPERIMENT=1
	fi

	# Auto-detects the presence of Go's vendored
	# dependencies inside $S/*/vendor
	if [[ -n ${GOLANG_PKG_BUILDPATH} && ${GOLANG_PKG_BUILDPATH##*/} != "..." ]]; then
		while read -r -d $' ' path; do
			# Trims leading slash (if any).
			path="${path/\//}"

			# Extracts the root path.
			path="${path%%/*}"

			# Ignores $path when it's empty or a string of white spaces.
			[[ -n $path ]] || continue

			local vendor="${S}/${path}/vendor"
			if [[ -d "${vendor}" ]]; then
				x-mgcf-golang_add_vendor "${vendor}"
			fi
		done <<< "$( echo ${GOLANG_PKG_BUILDPATH}) "
	fi


	# Auto-detects the presence of Godep's workspace
	# (see github.com/tools/godep for more infos).
	VENDOR="${S}/Godeps/_workspace"
	if [[ -d "${VENDOR}" ]]; then
		x-mgcf-golang_add_vendor "${VENDOR}"
	fi

	# Evaluates PATCHES array.
	default_src_prepare
}


# @FUNCTION: x-mgcf-golang-common_src_configure
# @DESCRIPTION:
# Configure the package.
x-mgcf-golang-common_src_configure() {
	debug-print-function ${FUNCNAME} "${@}"

	[[ ${EGO} ]] || die "No GoLang implementation set (x-mgcf-golang_setup not called?)."

	# Defines the level of verbosity.
	local EGO_VERBOSE="-v"
	[[ -z ${PORTAGE_VERBOSE} ]] || EGO_VERBOSE+=" -x"

	# GoLang doesn't have a configure phase,
	# so instead this eclass prints the output of 'go env'.
	local -a GOLANG_ENV=()
	while read -r line; do
		GOLANG_ENV+=("${line}")
	done <<-EOF
		$( ${GO} env )
	EOF

	# Prints an error when 'go env' output is missing.
	if [[ ${#GOLANG_ENV[@]} -eq 1 ]]; then
		eerror "Your GoLang environment should be more verbose"
	fi

	# Prints GoLang environment summary.
	einfo " ${EGO} env"
	for env in "${GOLANG_ENV[@]}"; do
		einfo " - ${env}"
	done


	# Removes GoLang object files from package source directories (pkg/)
	# and temporary directories (_obj/ _test*/).
	local EGO_SUBPACKAGES="${GOLANG_PKG_IMPORTPATH_ALIAS}/${GOLANG_PKG_NAME}"
	case $( ver_cut 1-2 ${GOLANG_VERSION} ) in
		1.4*) ;;
		*)
			EGO_SUBPACKAGES+="/..."
			;;
	esac
#	einfo "${EGO} clean -i ${EGO_VERBOSE} ${EGO_SUBPACKAGES}"
#	${EGO} clean -i \
#		${EGO_VERBOSE} \
#		"${EGO_SUBPACKAGES}" \
#		|| die

	# Removes GoLang objects files from all the dependencies too.
#	if [[ ${#GOLANG_PKG_DEPENDENCIES[@]} -gt 0 ]]; then
#
#		for i in ${!GOLANG_PKG_DEPENDENCIES[@]} ; do
#
#			# Collects all the tokens of the dependency.
#			local -A DEPENDENCY=()
#			while read -r -d $'\n' key value; do
#				[[ -z ${key} ]] && continue
#				DEPENDENCY[$key]="${value}"
#			done <<-EOF
#				$( _factorize_dependency_entities "${GOLANG_PKG_DEPENDENCIES[$i]}" )
#			EOF
#
#			[[ ! -d ${DEPENDENCY[importpath]} ]] && continue
#
#			# Debug
#			debug-print "${FUNCNAME}: DEPENDENCY = ${GOLANG_PKG_DEPENDENCIES[$i]}"
#			debug-print "${FUNCNAME}: importpath = ${DEPENDENCY[importpath]}"
#
#			# Cleans object files of the dependency.
#			einfo "${EGO} clean -i ${EGO_VERBOSE} ${DEPENDENCY[importpath]}"
#			${EGO} clean \
#				-i ${EGO_VERBOSE} \
#				"${DEPENDENCY[importpath]}" \
#				|| die
#		done
#	fi

	# Before to compile Godep's dependencies it's wise to wipe out
	# all pre-built object files from Godep's package source directories.
	if [[ -d "${S}"/Godeps/_workspace/pkg ]]; then
		ebegin "Cleaning up pre-built object files in Godep workspace"
			rm -r "${S}"/Godeps/_workspace/pkg || die
		eend
	fi
	if [[ -d "${S}"/Godeps/_workspace/bin ]]; then
		ebegin "Cleaning up executables in Godep workspace"
			rm -r "${S}"/Godeps/_workspace/bin || die
		eend
	fi


	# Executes 'go generate'.
	# NOTE: generate should never run automatically. It must be run explicitly.
	if [[ -n ${GOLANG_PKG_USE_GENERATE} ]]; then
		pushd "${GOPATH}/src/${GOLANG_PKG_IMPORTPATH_ALIAS}/${GOLANG_PKG_NAME}" > /dev/null || die
			einfo "${EGO} generate ${EGO_VERBOSE} ${GOLANG_PKG_IMPORTPATH_ALIAS}/${GOLANG_PKG_NAME}/..."
			${EGO} generate \
				${EGO_VERBOSE} \
				./... \
				|| die
		popd > /dev/null || die
	fi


	# Executes 'statik' when explicitly asked.
	if [[ -n ${GOLANG_PKG_STATIK} ]]; then
		ebegin "${ESTATIK} $GOLANG_PKG_STATIK"
			${ESTATIK} $GOLANG_PKG_STATIK || die
		eend
	fi
}


# @FUNCTION: x-mgcf-golang-common_src_compile
# @DESCRIPTION:
# Compiles the package.
x-mgcf-golang-common_src_compile() {
	debug-print-function ${FUNCNAME} "${@}"

	[[ ${EGO} ]] || die "No GoLang implementation set (x-mgcf-golang_setup not called?)."

	# Populates env variable GOPATH with vendored workspaces (if present).
	if [[ -n ${GOLANG_PKG_VENDOR} ]]; then
		einfo "Using vendored dependencies from:"

		for path in "${GOLANG_PKG_VENDOR[@]}"; do
			[ -d ${path} ] || continue

			if [[ ${path//${S}\//} == "vendor" ]]; then
				einfo "- vendor/ (native vendoring support)"
				continue
			fi

			debug-print "$FUNCNAME: GOPATH: Adding vendor path ${path}"
			ebegin "- ${path//${S}\//}"
				GOPATH="${GOPATH}:$( echo ${path} )"
			eend
		done

		export GOPATH
	fi

	# Enables position-independent executables (PIE)
	local EGO_PIE
	use pie && EGO_PIE="-buildmode=pie"

	# Defines the install suffix.
	local EGO_INSTALLSUFFIX
	[[ -z ${GOLANG_PKG_INSTALLSUFFIX} ]] || EGO_INSTALLSUFFIX="-installsuffix=${GOLANG_PKG_INSTALLSUFFIX}"

	# Defines the level of verbosity.
	local EGO_VERBOSE="-v"
	[[ -z ${PORTAGE_VERBOSE} ]] || EGO_VERBOSE+=" -x"

	# Defines the number of builds that can be run in parallel.
	local EGO_PARALLEL="-p $(makeopts_jobs)"

	# Defines extra options.
	local EGO_EXTRA_OPTIONS="-a"

	# Prepares build flags for the go toolchain.
	local EGO_BUILD_FLAGS="$( echo ${EGO_VERBOSE} ) $( echo ${EGO_PARALLEL} ) $( echo ${EGO_EXTRA_OPTIONS} ) $( echo ${EGO_PIE} )"
	[[ -n ${EGO_INSTALLSUFFIX} ]] && EGO_BUILD_FLAGS+=" $( echo ${EGO_INSTALLSUFFIX} )"

	# Detects the total number of packages.
	local pkgs=0 ifs_save=${IFS} IFS=$' '
	for path in ${GOLANG_PKG_BUILDPATH[@]} ; do
		pkgs=$(( $pkgs + 1 ))
	done
	[[ ${pkgs} -eq 0 ]] && pkgs=1 # there is always at least 1 package
	IFS=${ifs_save}

	# Builds the package
	einfo "Compiling ${pkgs} package(s):"
	if [[ -n ${GOLANG_PKG_BUILDPATH} && ${GOLANG_PKG_BUILDPATH##*/} != "..." && ${pkgs} -gt 1 ]]; then

		# NOTE: This eclass trims all leading and trailing white spaces from the
		#       input of the following 'while read' loop, then appends an extra
		#       trailing space; this is necessary to avoid undefined behaviours
		#       within the loop when GOLANG_PKG_BUILDPATH is populated with only
		#       a single element.
		while read -r -d $' ' cmd; do
			# Ignores $cmd when it's empty or a string of white spaces
			#einfo "cmd: |$cmd| cmd: |${cmd##*/}|"
			[[ -n $cmd ]] || continue

			x-mgcf-golang_do_build \
				${EGO_BUILD_FLAGS} \
				-o "${GOBIN}/${cmd##*/}" \
				"${GOLANG_PKG_IMPORTPATH_ALIAS}/${GOLANG_PKG_NAME}${cmd}"
		done <<< "$( echo ${GOLANG_PKG_BUILDPATH}) "
	else
		# If the package is a multiple package (/...)
		# then this eclass doesn't specify the output name.
		[[ ${GOLANG_PKG_BUILDPATH##*/} != "..." ]] && EGO_BUILD_FLAGS+=" -o ${GOBIN}/${GOLANG_PKG_OUTPUT_NAME}"

		x-mgcf-golang_do_build \
			${EGO_BUILD_FLAGS} \
			"${GOLANG_PKG_IMPORTPATH_ALIAS}/${GOLANG_PKG_NAME}${GOLANG_PKG_BUILDPATH}"
	fi
}


# @FUNCTION: x-mgcf-golang-common_src_install
# @DESCRIPTION:
# Installs binaries and documents from DOCS or HTML_DOCS arrays.
x-mgcf-golang-common_src_install() {
	debug-print-function ${FUNCNAME} "${@}"

	[[ ${EGO} ]] || die "No GoLang implementation set (x-mgcf-golang_setup not called?)."

	# Enables position-independent executables (PIE)
	local EGO_PIE
	use pie && EGO_PIE="-buildmode=pie"

	# Defines the install suffix.
	local EGO_INSTALLSUFFIX
	[[ -z ${GOLANG_PKG_INSTALLSUFFIX} ]] || EGO_INSTALLSUFFIX="-installsuffix=${GOLANG_PKG_INSTALLSUFFIX}"

	# Defines the level of verbosity.
	local EGO_VERBOSE="-v"
	[[ -z ${PORTAGE_VERBOSE} ]] || EGO_VERBOSE+=" -x"

	# Defines the number of builds that can be run in parallel.
	local EGO_PARALLEL="-p $(makeopts_jobs)"

	# Defines extra options.
	local EGO_EXTRA_OPTIONS

	# Prepares build flags for the go toolchain.
	local EGO_BUILD_FLAGS="$( echo ${EGO_VERBOSE} ) $( echo ${EGO_PARALLEL} ) $( echo ${EGO_EXTRA_OPTIONS} ) $( echo ${EGO_PIE} )"
	[[ -n ${EGO_INSTALLSUFFIX} ]] && EGO_BUILD_FLAGS+=" $( echo ${EGO_INSTALLSUFFIX} )"

	# Defines sub-packages.
	local EGO_SUBPACKAGES="${GOLANG_PKG_IMPORTPATH_ALIAS}/${GOLANG_PKG_NAME}${GOLANG_PKG_BUILDPATH}"

	# Executes the pre-install phase (go install).
	if [[ -n ${GOLANG_PKG_IS_MULTIPLE} ]]; then
		einfo "${EGO} install -ldflags '$GOLANG_PKG_LDFLAGS' -tags '$GOLANG_PKG_TAGS' ${EGO_BUILD_FLAGS} ${EGO_SUBPACKAGES}"
		${EGO} install \
			-ldflags "${GOLANG_PKG_LDFLAGS}" \
			-tags "${GOLANG_PKG_TAGS}" \
			${EGO_BUILD_FLAGS} \
			"${EGO_SUBPACKAGES}" \
			|| die
	fi

	# Installs binaries.
	into ${GOLANG_PKG_INSTALLPATH}
	for bin in "${GOBIN}"/* ; do
		dobin ${bin}
	done

	# Installs documentation.
	einstalldocs
}

# @FUNCTION: x-mgcf-golang-common_src_test
# @DESCRIPTION:
# Runs the unit tests for the main package.
x-mgcf-golang-common_src_test() {
	debug-print-function ${FUNCNAME} "${@}"

	[[ ${EGO} ]] || die "No GoLang implementation set (x-mgcf-golang_setup not called?)."

	# Appends S and GOBIN to exported main paths.
	# FIX: this is necessary for unit tests that need to invoke bins from
	#       $GOBIN or from within $S/bin.
	export PATH="${S}/bin:${GOBIN}:${PATH}"

	# Defines the level of verbosity.
	local EGO_VERBOSE="-v"
	[[ -z ${PORTAGE_VERBOSE} ]] || EGO_VERBOSE+=" -x"

	# Defines the number of builds that can be run in parallel.
	local EGO_PARALLEL="-p $(makeopts_jobs)"

	# Defines extra options.
	#local EGO_EXTRA_OPTIONS="-a"

	# Enables data race detection.
	local EGO_RACE
	[[ -n ${GOLANG_PKG_HAVE_TEST_RACE} ]] && EGO_RACE=" -race"

	# Prepares build flags for the go toolchain.
	local EGO_BUILD_FLAGS="$( echo ${EGO_VERBOSE} ) $( echo ${EGO_PARALLEL} ) $( echo ${EGO_EXTRA_OPTIONS} )"
	[[ -n ${EGO_RACE} ]] && EGO_BUILD_FLAGS+=" $( echo ${EGO_RACE} )"

	# Sanitizes vars from entra white spaces.
    GOLANG_PKG_LDFLAGS="$( echo ${GOLANG_PKG_LDFLAGS} )"
    GOLANG_PKG_TAGS="$( echo ${GOLANG_PKG_TAGS} )"

	# Defines sub-packages.
	local EGO_SUBPACKAGES="${GOLANG_PKG_IMPORTPATH_ALIAS}/${GOLANG_PKG_NAME}${GOLANG_PKG_BUILDPATH}"
	[[ -z ${GOLANG_PKG_IS_MULTIPLE} ]] || EGO_SUBPACKAGES="./..."

	# Detects the total number of packages.
	local pkgs=0 ifs_save=${IFS} IFS=$' '
	for path in ${GOLANG_PKG_BUILDPATH[@]} ; do
		pkgs=$(( $pkgs + 1 ))
	done
	[[ ${pkgs} -eq 0 ]] && pkgs=1 # there is always at least 1 package
	IFS=${ifs_save}

	# Runs the Unit Tests
	einfo "Testing ${pkgs} package(s):"
	if [[ -n ${GOLANG_PKG_BUILDPATH} && ${GOLANG_PKG_BUILDPATH##*/} != "..." && ${pkgs} -gt 1 ]]; then

		# NOTE: This eclass trims all leading and trailing white spaces from the
		#       input of the following 'while read' loop, then appends an extra
		#       trailing space; this is necessary to avoid undefined behaviours
		#       within the loop when GOLANG_PKG_BUILDPATH is populated with only
		#       a single element.
		while read -r -d $' ' cmd; do
			# Ignores $cmd when it's empty or a string of white spaces
			#einfo "cmd: |$cmd| cmd: |${cmd##*/}|"
			[[ -n $cmd ]] || continue

			einfo "${EGO} test -ldflags '$GOLANG_PKG_LDFLAGS' -tags '$GOLANG_PKG_TAGS' ${EGO_BUILD_FLAGS} ${GOLANG_PKG_IMPORTPATH_ALIAS}/${GOLANG_PKG_NAME}${cmd}/..."
			${EGO} test \
				-ldflags "${GOLANG_PKG_LDFLAGS}" \
				-tags "${GOLANG_PKG_TAGS}" \
				${EGO_BUILD_FLAGS} \
				"${GOLANG_PKG_IMPORTPATH_ALIAS}/${GOLANG_PKG_NAME}${cmd}/..." \
				|| die
       done <<< "$( echo ${GOLANG_PKG_BUILDPATH}) "
	else
		# It's a single package
		einfo "${EGO} test -ldflags '$GOLANG_PKG_LDFLAGS' -tags '$GOLANG_PKG_TAGS' ${EGO_BUILD_FLAGS} ${EGO_SUBPACKAGES}"
		${EGO} test \
			-ldflags "${GOLANG_PKG_LDFLAGS}" \
			-tags "${GOLANG_PKG_TAGS}" \
			${EGO_BUILD_FLAGS} \
			"${EGO_SUBPACKAGES}" \
			|| die
	fi
}


# @FUNCTION: x-mgcf-golang_do_build
# @INTERNAL
# @USAGE: <flags> <buildpath>
# @DESCRIPTION:
#
# @CODE
# Example:
#   GOLANG_PKG_LDFLAGS="-extldflags=-static"
#   GOLANG_PKG_TAGS="netgo"
#
#	x-mgcf-golang_do_build ${EGO_BUILD_FLAGS} ${GOLANG_PKG_IMPORTPATH}/${GOLANG_PKG_NAME}${GOLANG_PKG_BUILDPATH}
# @CODE
x-mgcf-golang_do_build() {
	debug-print-function ${FUNCNAME} $*

	[[ ${GOLANG_VERSION} ]] || die "No GoLang implementation set (x-mgcf-golang_setup not called?)."

	# Filters "=" chars from ldflags declaration.
	# NOTE: from go1.5+ linker syntax is no more compatible with <go1.4;
	#       this hack ensures that the old behaviour is honoured.
	if [[ $( ver_cut 1-2 ${GOLANG_VERSION} ) == "1.4" ]]; then
		GOLANG_PKG_LDFLAGS="${GOLANG_PKG_LDFLAGS//=/ }"
	fi

	# Disables debug symbols (DWARF) when not required.
	if ! use debug; then
		case "${GOLANG_PKG_LDFLAGS}" in
			*-s*|*-w*)
			    # Do nothing
    			;;
			*)
				GOLANG_PKG_LDFLAGS+=" -s -w"
		esac
	fi

	# Sanitizes vars from entra white spaces.
	GOLANG_PKG_LDFLAGS="$( echo ${GOLANG_PKG_LDFLAGS} )"
	GOLANG_PKG_TAGS="$( echo ${GOLANG_PKG_TAGS} )"

	einfo "${EGO} build -ldflags '$GOLANG_PKG_LDFLAGS' -tags '$GOLANG_PKG_TAGS' $*"
	${EGO} build \
		-ldflags "${GOLANG_PKG_LDFLAGS}" \
		-tags "${GOLANG_PKG_TAGS}" \
		$( echo $* ) \
		|| die
}


# @FUNCTION: x-mgcf-golang_add_vendor
# @INTERNAL
# @USAGE: <path>
# @DESCRIPTION:
#
# @CODE
# Example
#
#   x-mgcf-golang_add_vendor "${S}"/vendor
#   x-mgcf-golang_add_vendor "${S}"/${PN}/vendor
# @CODE
x-mgcf-golang_add_vendor() {
	debug-print-function ${FUNCNAME} $*

	[[ ${1} ]] || die "${FUNCNAME}: no paths given"

	[[ ${GOLANG_VERSION} ]] || die "No Golang implementation set (x-mgcf-golang_setup not called?)."

	[[ ! -d "${1}" ]] && return

	# NOTE: this hack is required by Go v1.4 and older versions.
	#if [[ ! -d "${1}"/src ]]; then
	#	ebegin "Fixing $1"
	#		ln -s "${1}" "${1}"/src || die
	#	eend
	#fi

	GOLANG_PKG_VENDOR+=(${1})
}


# @FUNCTION: x-mgcf-golang_fix_importpath_alias
# @USAGE: <target> <alias>
# @DESCRIPTION:
# Helper functions for generating a symbolic link for import path <target> as
# <alias>.
#
# WARNING: Use this function only if GOLANG_PKG_DEPENDENCIES declaration of
# import path aliases doesn't work (e.g.: the package name differs from both the
# import path and the alias, or if the package name is case sensitive but the
# import path is not).
#
# @CODE
# Example:
#
#   src_prepare() {
#   	x-mgcf-golang-single_src_prepare
#
#   	x-mgcf-golang_fix_importpath_alias \
#   		"github.com/GoogleCloudPlatform/gcloud-golang" \
#   		"google.golang.org/cloud"
#   }
# @CODE
x-mgcf-golang_fix_importpath_alias() {
	debug-print-function ${FUNCNAME} "${@}"

	[[ ${1} ]] || die "${FUNCNAME}: no target specified"
	[[ ${2} ]] || die "${FUNCNAME}: no alias specified"

	[[ ${EGO} ]] || die "No GoLang implementation set (x-mgcf-golang_setup not called?)."


	local TARGET="${1}"
	local ALIAS="${2}"

	if [[ ${ALIAS%/*} != ${ALIAS} ]]; then
		mkdir -p "${GOPATH}/src/${ALIAS%/*}" || die
	fi
	ebegin "Linking ${TARGET} as ${ALIAS}"
		ln -s "${GOPATH}/src/${TARGET}" \
			"${GOPATH}/src/${ALIAS}" \
			|| die
	eend
}


fi