2016-10-31 13:49:45 +00:00
# Copyright 1999-2016 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Id$
# @ECLASS: golang-utils.eclass
# @MAINTAINER:
# Mauro Toffanin <toffanin.mauro@gmail.com>
# @AUTHOR:
# Mauro Toffanin <toffanin.mauro@gmail.com>
# @BLURB: Base eclass for GoLang packages
# @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 versionator eutils multiprocessing
if [ [ -z ${ _GOLANG_BASE_ECLASS } ] ] ; then
_GOLANG_BASE_ECLASS = 1
# Silences repoman warnings.
case " ${ EAPI :- 0 } " in
5| 6)
case " ${ GOLANG_PKG_DEPEND_ON_GO_SUBSLOT :- yes } " in
yes)
GO_DEPEND = "dev-lang/go:0="
; ;
*)
GO_DEPEND = "dev-lang/go:*"
; ;
esac
; ;
*)
die " ${ ECLASS } : Unsupported eapi (EAPI= ${ EAPI } ) "
; ;
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.
2016-10-31 13:59:10 +00:00
GOLANG_PKG_VENDOR = " ${ GOLANG_PKG_VENDOR :- } "
2016-10-31 13:49:45 +00:00
# @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: 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
# Enables USE 'test' when required by GOLANG_PKG_HAVE_TEST.
IUSE = " ${ IUSE } debug "
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: golang_setup
# @DESCRIPTION:
# Determines where is the GoLang implementation and then set-up the
# GoLang build environment.
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
# 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
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: golang-base_src_prepare
# @DESCRIPTION:
# Prepare source code.
golang-base_src_prepare( ) {
debug-print-function ${ FUNCNAME } " ${ @ } "
pushd " ${ WORKDIR } " > /dev/null
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 } "
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 pkg_setup() 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 -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
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 'golang-base_src_prepare' doesn't support ' ${ DEPENDENCY [importpath] } ' " ; ;
esac
done
fi
popd > /dev/null
# Auto-detects the presence of Go's vendored
# dependencies inside $S/vendor.
local VENDOR = " ${ S } /vendor "
if [ [ -d " ${ VENDOR } " ] ] ; then
golang_add_vendor " ${ VENDOR } "
fi
# Auto-detects the presence of Go's vendored
# dependencies inside $S/*/vendor
if [ [ -n ${ GOLANG_PKG_BUILDPATH } && ${ GOLANG_PKG_BUILDPATH ##*/ } != "..." ] ] ; then
while read -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
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
2016-10-31 13:59:10 +00:00
GOLANG_PKG_VENDOR += " ${ VENDOR } "
2016-10-31 13:49:45 +00:00
fi
# Evaluates PATCHES array.
default_src_prepare
}
# @FUNCTION: golang-base_src_configure
# @DESCRIPTION:
# Configure the package.
golang-base_src_configure( ) {
debug-print-function ${ FUNCNAME } " ${ @ } "
[ [ ${ EGO } ] ] || die "No GoLang implementation set (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 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 $( get_version_component_range 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 -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] } "
# 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
einfo " ${ EGO } generate ${ EGO_VERBOSE } ${ GOLANG_PKG_IMPORTPATH_ALIAS } / ${ GOLANG_PKG_NAME } /... "
${ EGO } generate \
${ EGO_VERBOSE } \
./... \
|| die
popd > /dev/null
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: golang-base_src_compile
# @DESCRIPTION:
# Compiles the package.
golang-base_src_compile( ) {
debug-print-function ${ FUNCNAME } " ${ @ } "
[ [ ${ EGO } ] ] || die "No GoLang implementation set (golang_setup not called?)."
# Populates env variable GOPATH with vendored workspaces (if present).
2016-10-31 13:59:10 +00:00
if [ [ -n ${ GOLANG_PKG_VENDOR } || "1" = = ${ GO15VENDOREXPERIMENT } ] ] ; then
2016-10-31 13:49:45 +00:00
einfo "Using vendored dependencies from:"
2016-10-31 13:59:10 +00:00
# Prints Go's vendored directory.
if [ [ "1" = = ${ GO15VENDOREXPERIMENT } ] ] ; then
einfo "- vendor"
fi
fi
# Prints user defined vendored directories.
if [ [ -n ${ GOLANG_PKG_VENDOR } ] ] ; then
2016-10-31 13:49:45 +00:00
for path in " ${ GOLANG_PKG_VENDOR [@] } " ; do
[ -d ${ path } ] || continue
debug-print " $FUNCNAME : GOPATH: Adding vendor path ${ path } "
2016-10-31 13:59:10 +00:00
ebegin " - ${ path // ${ WORKDIR } \/ / } "
2016-10-31 13:49:45 +00:00
GOPATH = " ${ GOPATH } : $( echo ${ path } ) "
eend
done
export GOPATH
fi
# 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 } ) "
[ [ -n ${ EGO_INSTALLSUFFIX } ] ] && EGO_BUILD_FLAGS += " $( echo ${ EGO_INSTALLSUFFIX } ) "
# Defines the output binary name of the package.
# If the package is a multiple package then this eclass doesn't specify
# the output name.
[ [ -z ${ GOLANG_PKG_BUILDPATH } ] ] && EGO_BUILD_FLAGS += " -o ${ GOBIN } / ${ GOLANG_PKG_OUTPUT_NAME } "
# Builds the package.
einfo "Compiling package(s):"
if [ [ -n ${ GOLANG_PKG_BUILDPATH } && ${ GOLANG_PKG_BUILDPATH ##*/ } != "..." ] ] ; 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 -d $' ' cmd; do
# Ignores $cmd when it's empty or a string of white spaces
#einfo "cmd: |$cmd| cmd: |${cmd##*/}|"
[ [ -n $cmd ] ] || continue
golang_do_build \
${ EGO_BUILD_FLAGS } \
-o " ${ GOBIN } / ${ cmd ##*/ } " \
" ${ GOLANG_PKG_IMPORTPATH_ALIAS } / ${ GOLANG_PKG_NAME } ${ cmd } "
done <<< " $( echo ${ GOLANG_PKG_BUILDPATH } ) "
else
golang_do_build \
${ EGO_BUILD_FLAGS } \
" ${ GOLANG_PKG_IMPORTPATH_ALIAS } / ${ GOLANG_PKG_NAME } ${ GOLANG_PKG_BUILDPATH } "
fi
}
# @FUNCTION: golang-base_src_install
# @DESCRIPTION:
# Installs binaries and documents from DOCS or HTML_DOCS arrays.
golang-base_src_install( ) {
debug-print-function ${ FUNCNAME } " ${ @ } "
[ [ ${ EGO } ] ] || die "No GoLang implementation set (golang_setup not called?)."
# 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 } ) "
[ [ -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: golang-base_src_test
# @DESCRIPTION:
# Runs the unit tests for the main package.
golang-base_src_test( ) {
debug-print-function ${ FUNCNAME } " ${ @ } "
[ [ ${ EGO } ] ] || die "No GoLang implementation set (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 } ) "
# Defines sub-packages.
local EGO_SUBPACKAGES = " ${ GOLANG_PKG_IMPORTPATH_ALIAS } / ${ GOLANG_PKG_NAME } ${ GOLANG_PKG_BUILDPATH } "
2016-10-31 13:59:10 +00:00
[ [ -n ${ GOLANG_PKG_IS_MULTIPLE } ] ] || EGO_SUBPACKAGES = "./..."
2016-10-31 13:49:45 +00:00
# Runs the unit tests.
einfo " ${ EGO } test ${ EGO_BUILD_FLAGS } ${ EGO_SUBPACKAGES } "
${ EGO } test \
${ EGO_BUILD_FLAGS } \
" ${ EGO_SUBPACKAGES } " \
|| die
}
# @FUNCTION: golang_do_build
# @INTERNAL
# @USAGE: <flags> <buildpath>
# @DESCRIPTION:
#
# @CODE
# Example:
# GOLANG_PKG_LDFLAGS="-extldflags=-static"
# GOLANG_PKG_TAGS="netgo"
#
# golang_do_build ${EGO_BUILD_FLAGS} ${GOLANG_PKG_IMPORTPATH}/${GOLANG_PKG_NAME}${GOLANG_PKG_BUILDPATH}
# @CODE
golang_do_build( ) {
debug-print-function ${ FUNCNAME } $*
[ [ ${ GOLANG_VERSION } ] ] || die "No GoLang implementation set (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 [ [ $( get_version_component_range 1-2 ${ GOLANG_VERSION } ) = = "1.4" ] ] ; then
GOLANG_PKG_LDFLAGS = " ${ GOLANG_PKG_LDFLAGS //=/ } "
fi
# Disables debug symbols (DWARF) when not required.
! use debug && GOLANG_PKG_LDFLAGS = " -s -w ${ GOLANG_PKG_LDFLAGS } "
# 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: golang_add_vendor
# @INTERNAL
# @USAGE: <path>
# @DESCRIPTION:
#
# @CODE
# Example
#
# golang_add_vendor "${S}"/vendor
# golang_add_vendor "${S}"/${PN}/vendor
# @CODE
golang_add_vendor( ) {
debug-print-function ${ FUNCNAME } $*
[ [ ${ 1 } ] ] || die " ${ FUNCNAME } : no paths given "
[ [ ${ GOLANG_VERSION } ] ] || die "No Golang implementation set (golang_setup not called?)."
2016-10-31 13:59:10 +00:00
case $( get_version_component_range 1-2 ${ GOLANG_VERSION } ) in
1.4*)
# TODO: traverse $1 and expose all the bundled /vendor
# sub-directories to GOLANG_PKG_VENDOR
if [ [ ! -d " ${ 1 } " /src ] ] ; then
ebegin " Fixing $1 "
ln -s " ${ 1 } " " ${ 1 } " /src || die
eend
fi
2016-10-31 13:49:45 +00:00
2016-10-31 13:59:10 +00:00
GOLANG_PKG_VENDOR += " ${ 1 } "
; ;
1.5*)
export GO15VENDOREXPERIMENT = 1
; ;
esac
2016-10-31 13:49:45 +00:00
}
# @FUNCTION: 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() {
# golang-single_src_prepare
#
# golang_fix_importpath_alias \
# "github.com/GoogleCloudPlatform/gcloud-golang" \
# "google.golang.org/cloud"
# }
# @CODE
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 (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