diff options
-rw-r--r-- | eclass/dub.eclass | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/eclass/dub.eclass b/eclass/dub.eclass new file mode 100644 index 0000000..41fff29 --- /dev/null +++ b/eclass/dub.eclass @@ -0,0 +1,312 @@ +# Copyright 2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +# @ECLASS: dub.eclass +# @MAINTAINER: +# Andrei Horodniceanu <a.horodniceanu@proton.me> +# @AUTHOR: +# Andrei Horodniceanu <a.horodniceanu@proton.me> +# @BUGREPORTS: +# Please report bugs via https://github.com/gentoo/dlang/issues +# @VCSURL: https://github.com/gentoo/dlang +# @SUPPORTED_EAPIS: 8 +# @BLURB: common functions and variables for dub builds +# @DESCRIPTION: +# This eclass provides a wrapper for calling dub as well as default +# implementations for src_compile and src_test. It also provides +# dub_src_unpack which will make dub dependencies available as well +# as configure it to work best in an ebuild environment. +# +# By default this eclass will set *DEPEND to depend on both dub and a D +# compiler. For this reason you *must* inherit either dlang-single or +# dlang-r1 before inheriting dub. The only alternative is using +# DUB_OPTIONAL. +# @EXAMPLE: +# A program using dub.eclass: +# +# @CODE +# DLANG_COMPAT=( dmd-2_109 gdc-1{3,4} ldc2-1_39 ) +# DUB_DEPENDENCIES=( +# "automem@0.6.9" +# "cachetools@0.4.1" +# "dcd@0.16.0-beta.2" +# "program@8.0.3" +# "silly@1.1.1" +# ) +# inherit dlang-single dub +# SRC_URI="${DUB_DEPENDENCIES_URIS}" +# +# src_install() { +# dobin "${S}/program" +# } +# @CODE + +case ${EAPI} in + 8) ;; + *) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;; +esac + +if [[ ! ${_DUB_ECLASS} ]]; then +_DUB_ECLASS=1 + +inherit dlang-utils edo + +# @ECLASS_VARIABLE: DUB_DEPEND +# @OUTPUT_VARIABLE +# @DESCRIPTION: +# Dependency string on dev-util/dub and other needed programs that can +# be used in BDEPEND when DUB_OPTIONAL is set. When DUB_OPTIONAL is +# empty the dependency is added automatically to BDEPEND. +DUB_DEPEND=">=dev-util/dub-1.38.0 app-arch/unzip" +# 1.38 - respect skipRegistry value in configuration file + +EDUB_HOME="${WORKDIR}/dub_home" + +# @ECLASS_VARIABLE: DUB_OPTIONAL +# @DEFAULT_UNSET +# @PRE_INHERIT +# @DESCRIPTION: +# Setting this to a non-empty value inhibits the eclass from modifying +# variables like *DEPEND and REQUIRED_USE and from exporting phase +# functions. +# +# If set, you may need to call dub_gen_settings or dub_src_unpack +# manually. + +# @ECLASS_VARIABLE: DUB_DEPENDENCIES +# @DEFAULT_UNSET +# @PRE_INHERIT +# @DESCRIPTION: +# A bash array of dub dependencies. Each dependency should be a string +# in the form `name@version`. +# +# Example: +# @CODE +# DUB_DEPENDENCIES=( +# "dfmt@0.15.1" +# "silly@1.1.1" +# ) +# @CODE + +# @ECLASS_VARIABLE: DUB_DEPENDENCIES_URIS +# @OUTPUT_VARIABLE +# @DESCRIPTION: +# The transformed DUB_DEPENDENCIES as a string to be placed in +# SRC_URI + +# @FUNCTION: dub_dependencies_uris +# @USAGE: [dependencies]... +# @DESCRIPTION: +# print a string to be placed in SRC_URI for all the dependencies given +# as arguments. Each dependency should be in the form `name@version`, +# just like the elements in DUB_DEPENDENCIES. +dub_dependencies_uris() { + debug-print-function ${FUNCNAME} "${@}" + + local registry="https://code.dlang.org/packages" + local dep name ver + for dep; do + name="${dep%@*}" + ver="${dep#*@}" + echo "${registry}/${name}/${ver}.zip -> ${name}-${ver}.zip" + done +} + +# @FUNCTION: _handle_dub_variables +# @INTERNAL +# @DESCRIPTION: +# Verify that DUB_DEPENDENCIES is set appropriately, transform it into +# DUB_DEPENDENCIES_URIS, and set any other variables. +_handle_dub_variables() { + [[ -v DUB_DEPENDENCIES && ${DUB_DEPENDENCIES@a} != *a* ]] \ + && die "DUB_DEPENDENCIES must be an array" + export DUB_DEPENDENCIES_URIS="$(dub_dependencies_uris "${DUB_DEPENDENCIES[@]}")" + + [[ ${DUB_OPTIONAL} ]] && return + + if ! has dlang-single ${INHERITED} && ! has dlang-r1 ${INHERITED}; then + eerror + eerror "dlang-single or dlang-r1 have not been inherited before dub.eclass" + eerror "and DUB_OPTIONAL has not been set." + eerror "Please inherit dlang-single or dlang-r1 before inheriting dub." + die "Neither dlang-single nor dlang-r1 are inherited" + fi + + [[ ${CATEGORY}/${PN} != dev-util/dub ]] \ + && BDEPEND="${DUB_DEPEND}" + + BDEPEND+=" ${DLANG_DEPS}" + DEPEND="${DLANG_DEPS}" + RDEPEND="${DLANG_DEPS}" + REQUIRED_USE="${DLANG_REQUIRED_USE}" +} +_handle_dub_variables +unset -f _handle_dub_variables + +# @FUNCTION: edub +# @USAGE: [dub_args]... +# @DESCRIPTION: +# A dub wrapper that will automatically set relevant variables and die +# on failure. nonfatal can be used with edub. +# +# Meaningful variables for this function are: +# +# $DC - typically set by dlang-r1.eclass or dlang-single.eclass to point +# to the D compiler and respected by dub. +# +# $DFLAGS - dub will use these flags when compiling + linking. If the +# variable is unset (empty does not count) this eclass will default to +# "${DCFLAGS} ${DLANG_LDFLAGS} /-Wno-error/" for its value. +# +# $NO_COLOR - if non-empty dub will not print colors +edub() { + debug-print-function ${FUNCNAME} "${@}" + + local -x DFLAGS=${DFLAGS-${DCFLAGS} ${DLANG_LDFLAGS} $(dlang_get_wno_error_flag)} + local -x DC=${DC} NO_COLOR=${NO_COLOR} + # FIXME dub directly calls pkg-config without a way to configure it + + debug-print "${FUNCNAME}: DC=${DC}" + debug-print "${FUNCNAME}: DFLAGS=${DFLAGS}" + + edo dub --verbose "${@}" +} + +# @ECLASS_VARIABLE: DUB_LOCAL_REGISTRY +# @DESCRIPTION: +# A directory in which dub package archives can be placed for dub to be +# able to fetch them in the future. This is useful only if dub _must_ +# perform a fetch operation, perhaps as part of tests, in all other +# cases DUB_DEPENDENCIES should be used instead. +# +# You can use dub_copy_dependencies_locally as a convenience function. +# +# Example: +# @CODE +# src_unpack() { +# dub_src_unpack +# use test && dub_copy_dependencies_locally "my_packages@1.1.0" +# } +# src_test() { +# dub_src_test +# +# # additional test that performs `dub fetch my_package@1.1.0` +# } +# @CODE +DUB_LOCAL_REGISTRY="${EDUB_HOME}/local_registry" + +# @FUNCTION: dub_copy_dependencies_locally +# @USAGE: [dependencies]... +# @DESCRIPTION: +# Copy the given dependencies to ${DUB_LOCAL_REGISTRY}. This function +# can only be called inside src_unpack. +# +# The format of the arguments is the same as the format of +# ${DUB_DEPENDENCIES}. +dub_copy_dependencies_locally() { + debug-print-function ${FUNCNAME} "${@}" + + [[ ${EBUILD_PHASE} == unpack ]] \ + || die "${FUNCNAME} must only be called inside src_unpack" + + local dep + for dep; do + einfo "Making ${dep} available locally" + cp "${DISTDIR}/${dep/@/-}.zip" "${DUB_LOCAL_REGISTRY}" || die + done +} + +# @FUNCTION: dub_gen_settings +# @DESCRIPTION: +# Generate a settings.json file for dub. +dub_gen_settings() { + debug-print-function ${FUNCNAME} "${@}" + + mkdir -p "${EDUB_HOME}" || die "Could not create dub home directory" + mkdir -p "${DUB_LOCAL_REGISTRY}" || die "Could not create dub registry directory" + + # dub merges the settings from all configuration files so settings + # which greatly change the build need to be set to a safe + # value. Unfortunately the 'customCachePaths' and 'registryUrls' + # settings are cumulative, i.e. they will append to the previous + # value, not overwrite it. + cat > "${EDUB_HOME}/settings.json" <<-EOF || die "Failed to create dub settings.json file" + { + "registryUrls": [ + "file://${DUB_LOCAL_REGISTRY}" + ], + "skipRegistry": "standard", + + "customCachePaths": [], + "defaultCompiler": "", + "defaultArchitecture": "" + } + EOF + + export DUB_HOME="${EDUB_HOME}" +} + +# @FUNCTION: dub_src_unpack +# @DESCRIPTION: +# Unpack all sources and generate a dub configuration file +dub_src_unpack() { + dub_gen_settings + + # DUB_DEPENDENCIES can contain entries like: + # dfmt@0.15.1 which maps to the archive dmft-0.15.1.zip + # + # There can also be dependencies like: + # botan-math@1.0.4 -> botan-math-1.0.4.zip + # botan@1.13.6 -> botan-1.13.6.zip + # + # Because of the ambiguous `-' character create a map + # from the archive back to the dependency. + local -A dubFiles + local dep + for dep in "${DUB_DEPENDENCIES[@]}"; do + dubFiles["${dep/@/-}.zip"]="${dep}" + done + + local dubFetch=( + dub + --skip-registry=all + --registry="file://${DISTDIR}" + fetch + ) + local dep file + for file in ${A}; do + if [[ ${dubFiles[${file}]} ]]; then + # file can be 'dfmt-0.15.1.zip' + # in which case dubFiles[${file}] wil be 'dfmt@0.15.1' + dep="${dubFiles[${file}]}" + edo "${dubFetch[@]}" "${dep}" + + # If it's the main package extract it for ${S}. + # In case of prereleases: + # serve-d-0.8.0_beta17 -> serve-d-0.8.0-beta.17.zip + [[ ${file} == ${PN}-$(ver_rs 3 - 4 .)* ]] \ + && unpack "${file}" + else + unpack "${file}" + fi + done +} + +# @FUNCTION: dub_src_compile +# @DESCRIPTION: +# Compile the package using dub +dub_src_compile() { + edub build +} + +# @FUNCTION: dub_src_test +# @DESCRIPTION: +# Test the package using dub +dub_src_test() { + edub test +} + +fi + +[[ ${DUB_OPTIONAL} ]] \ + || EXPORT_FUNCTIONS src_unpack src_compile src_test |