• [gentoo-dev] New eclass: gap-pkg

    From Michael Orlitzky@21:1/5 to All on Tue Jan 16 02:10:01 2024
    A new eclass for the GAP system and its packages,

    * https://www.gap-system.org/
    * https://www.gap-system.org/Packages/packages.html
    * https://bugs.gentoo.org/49282

    A pull request is open with a category full of examples:

    * https://github.com/gentoo/gentoo/pull/34472

    Comments, suggestions, and complaints are appreciated.

    --

    # Copyright 2024 Gentoo Authors
    # Distributed under the terms of the GNU General Public License v2

    # @ECLASS: gap-pkg.eclass
    # @MAINTAINER:
    # François Bissey <frp.bissey@gmail.com>
    # Michael Orlitzky <mjo@gentoo.org>
    # Gentoo Mathematics Project <sci-mathematics@gentoo.org>
    # @AUTHOR:
    # François Bissey <frp.bissey@gmail.com>
    # Michael Orlitzky <mjo@gentoo.org>
    # @SUPPORTED_EAPIS: 8
    # @BLURB: Simplify the installation of GAP packages.
    # @DESCRIPTION:
    # The main purpose of this eclass is to build and install GAP packages
    # that typically occupy the dev-gap category. Most GAP packages do not
    # support an install target out of the box, so the default installation
    # is "by hand," with attention paid to those directories that are part
    # of the recommended layout. The prepare, configure, and compile phases
    # do however try to support packages having a real build system.
    #
    # GAP itself has four "required" packages that are packaged separately,
    # making dependencies between them somewhat weird. The four required
    # packages are,
    #
    # * dev-gap/gapdoc
    # * dev-gap/primgrp
    # * dev-gap/smallgrp
    # * dev-gap/transgrp
    #
    # Those four packages will have only sci-mathematics/gap added to
    # RDEPEND. All other packages will have the four required packages above
    # added to RDEPEND in addition to sci-mathematics/gap. In theory it
    # would be better to list all dependencies explicitly rather than
    # grouping together the "required" four, but this is how upstream GAP
    # works, and is what all GAP packages expect; for example, most test
    # suites fail without the required packages but make no attempt to load
    # them.
    #
    # If you need a version constraint on sci-mathematics/gap, you'll have
    # to specify it yourself. Compiled packages will likely need
    # sci-mathematics/gap in DEPEND as well, and may also want a subslot
    # dependency.

    case ${EAPI} in
    8) ;;
    *) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
    esac

    # For eshopts_push and eshopts_pop
    inherit estack

    # Some packages have additional homepages, but pretty much every GAP
    # package can be found at this URL. HOMEPAGE="https://www.gap-system.org/Packages/${PN}.html"

    # _GAP_PKG_IS_REQUIRED is an internal variable that indicates whether or
    # not $PN is one of the four "required" GAP packages that are always
    # loaded, even when GAP is started with the "-A" flag. We treat this
    # four somewhat differently since they are implicit dependencies of
    # everything else in the GAP ecosystem.
    _GAP_PKG_IS_REQUIRED=no
    case ${CATEGORY}/${PN} in
    dev-gap/gapdoc|dev-gap/smallgrp|dev-gap/primgrp|dev-gap/transgrp)
    _GAP_PKG_IS_REQUIRED=yes
    ;;
    *)
    ;;
    esac

    # _GAP_PKG_RDEPEND is an internal variable to hold the RDEPEND entries
    # added by this eclass. We use a separate variable for this because we
    # need its contents later in gap-pkg_enable_tests, and that function is
    # called from an ebuild context where the list of RDEPEND is maintained
    # separately. Basically: the values we add to RDEPEND here do not appear
    # in RDEPEND when gap-pkg_enable_tests is called. _GAP_PKG_RDEPEND="sci-mathematics/gap"

    # The four "required" packages depend only on GAP itself, while every
    # other package depends (also) on the four required ones.
    if [[ "${_GAP_PKG_IS_REQUIRED}" = "no" ]]; then
    _GAP_PKG_RDEPEND+="
    dev-gap/gapdoc
    dev-gap/smallgrp
    dev-gap/primgrp
    dev-gap/transgrp"
    fi
    RDEPEND="${_GAP_PKG_RDEPEND}"

    # @FUNCTION: gap-pkg_dir
    # @DESCRIPTION:
    # The directory into which the gap package should be installed. The
    # accepted current location is /usr/$(get_libdir)/gap/pkg, but
    # technically this depends on the econf call in sci-mathematics/gap. gap-pkg_dir() {
    echo "/usr/$(get_libdir)/gap/pkg/${PN}"
    }

    # @FUNCTION: _gap-pkg_gaproot
    # @INTERNAL
    # @DESCRIPTION:
    # The directory containing sysinfo.gap. This is frequently passed to GAP
    # packages via ./configure --with-gaproot or as a positional argument to
    # hand-written configure scripts. We also use it to find the value of
    # $GAParch, which is contained in sysinfo.gap. The "gaproot" is
    # implicitly determined by the econf call in sci-mathematics/gap. As a
    # result, calling this function requires sci-mathematics/gap at
    # build-time.
    _gap-pkg_gaproot() {
    echo "${ESYSROOT}/usr/$(get_libdir)/gap"
    }

    # @FUNCTION: gap-pkg_econf
    # @USAGE: [extra econf args]
    # @DESCRIPTION:
    # Call econf, passing the value of _gap-pkg_gaproot to --with-gaproot.
    # All arguments to gap-pkg_econf are passed through to econf.
    #
    # @EXAMPLE
    # src_configure() {
    # gap-pkg_econf --with-external-libsemigroups
    # }
    #
    gap-pkg_econf() {
    econf --with-gaproot="$(_gap-pkg_gaproot)" "${@}"
    }

    # @FUNCTION: gap-pkg_src_configure
    # @DESCRIPTION:
    # Handle both autoconf configure scripts and the hand-written ones used
    # by many GAP packages. We determine which one we're dealing with by
    # running ./configure --help; an autoconf configure script will mention
    # "PREFIX" in the output, the others will not.
    #
    # Autoconf configure scripts are configured using gap-pkg_econf, while
    # hand-written ones are executed directly with _gap-pkg_gaproot as their
    # sole positional argument.
    gap-pkg_src_configure() {
    local _configure="${ECONF_SOURCE:-.}/configure"
    if [[ -x ${_configure} ]] ; then
    if ${_configure} --help | grep PREFIX &>/dev/null; then
    # This is an autoconf ./configure script
    gap-pkg_econf
    else
    # It's an "old-style" handwritten script that does
    # not print usage information with --help.
    ${_configure} $(_gap-pkg_gaproot) || die
    fi
    fi
    }

    # @FUNCTION: gap-pkg_src_compile
    # @DESCRIPTION:
    # The default src_compile with the addition of V=1 to emake. The
    # Makefile.gappkg used to build most C packages defaults to a quiet
    # build without this.
    gap-pkg_src_compile() {
    if [[ -f Makefile ]] || [[ -f GNUmakefile ]] || [[ -f makefile ]]; then
    emake V=1 || die "emake failed"
    fi
    }

    # @FUNCTION: gap-pkg_enable_tests
    # @DESCRIPTION:
    # Amend IUSE, RESTRICT, and BDEPEND for a package with a test suite.
    # This is modeled on similar functions in the distutils-r1 and
    # elisp-common eclasses, except here only a single default testing
    # strategy is supported. All runtime and post-merge dependencies are
    # added as build dependencies if USE=test is set.
    gap-pkg_enable_tests() {
    IUSE+=" test "
    RESTRICT+=" !test? ( test ) "

    # Use the internal variable here, too, because the RDEPEND list from
    # the ebuild is maintained separately by the package manager. We add
    # PDEPEND too because we use it to break some circular dependencies
    # between e.g. polycyclic and alnuth.
    BDEPEND+=" test? ( ${_GAP_PKG_RDEPEND} ${RDEPEND} ${PDEPEND} ) "
    }

    # @FUNCTION: gap-pkg_src_test
    # @DESCRIPTION:
    # Run this package's test suite if it has one. The GAP TestPackage
    # function is the standard way to do this, but it does rely on the
    # package itself to get a few things right, like running the tests
    # verbosely and exiting with the appropriate code. The alternative would
    # be run TestDirectory ourselves on "tst", but that has its own issues;
    # in particular many packages have set-up code that is run only with
    # TestPackage. YMMV.
    gap-pkg_src_test() {
    [[ -f PackageInfo.g ]] || return

    # We would prefer --bare to -A so that we can test (say) primgrp
    # after installing only gapdoc and not smallgrp or transgrp. But,
    # that would cause problems for basically every non-required
    # package, because they usually don't explicitly load the four
    # "required" packages in their test suites. So we use -A unless
    # this is one of the chosen four.
    local bareflag="--bare"
    if [[ "${_GAP_PKG_IS_REQUIRED}" = "no" ]]; then
    bareflag="-A"
    fi

    # Run GAP non-interactively to test the just-built package. We omit
    # the "-r" flag here because we use the UserGapRoot directory to
    # store AtlasRep data, and without it, the atlasrep tests (and the
    # tests of any packages depending on it) will fail.
    local gapcmd="gap -R ${bareflag} --nointeract"

    # ForceQuitGap translates a boolean return value to the expected
    # zero or one, useful for packages that set a single *.tst file as
    # their TestFile.
    gapcmd+=" -c ForceQuitGap(TestPackage(\"${PN}\"));"

    # Fake the directory structure that GAP needs to be able to find
    # packages with a symlink under ${T}, then prepend ${T} to the list
    # of search paths so that if this package is already installed, we
    # load the just-built copy first.
    ln -s "${WORKDIR}" "${T}/pkg" || die
    gapcmd+=" --roots ${T}/; "

    # False negatives can occur if GAP fails to start, or if there are
    # syntax errors:
    #
    # https://github.com/gap-system/gap/issues/5541
    #
    # There's nothing you can do about that, but now you know.
    #
    # The pipe to tee is more important than it looks. Any test suite
    # involving dev-gap/browse is likely to bork the user's terminal.
    # The "browse" package is however smart enough to figure out when
    # stdout is not a tty, and avoids breaking it in that case. So by
    # piping to tee, we encourage it not to do anything too crazy.
    ${gapcmd} | tee test-suite.log \
    || die "test suite failed, see test-suite.log"
    }

    # @ECLASS_VARIABLE: GAP_PKG_EXTRA_INSTALL
    # @DEFAULT_UNSET
    # @DESCRIPTION:
    # A bash array of extra files and directories to install recursively at
    # the root of this package's directory tree. For example, if you have a
    # package that mostly follows the suggested layout (described in the
    # gap-pkg_src_install documentation) but also includes a "data"
    # directory, you should set
    #
    # GAP_PKG_EXTRA_INSTALL=( data )
    #
    # to install the data directory without having to override the entire
    # src_install phase.

    # @ECLASS_VARIABLE: GAP_PKG_HTML_DOCDIR
    # @DESCRIPTION:
    # The directory inside the tarball where the HTML documentation is
    # located. This is _usually_ "doc", which conforms to the suggested
    # GAPDoc layout and is the default value of this variable. Many
    # packages however use a top-level "htm" directory instead. The named
    # directory will be installed to gap-pkg_dir and symlinked to the usual
    # location under /usr/share/doc. As a result, you should only use this
    # for directories referenced by PackageInfo.g or by some other part of
    # the package. HTML documentation whose location doesn't need to be
    # known to the package at runtime should instead be installed with
    # HTML_DOCS or a similar mechanism.
    : "${GAP_PKG_HTML_DOCDIR:=doc}"

    # @FUNCTION: gap-pkg_src_install
    # @DESCRIPTION:
    # Install a GAP package that follows the suggested layout,
    #
    # https://docs.gap-system.org/doc/ref/chap76.html
    #
    # In particular:
    #
    # 1. All GAP source files (*.g) in $S are installed.
    #
    # 2. If a library directory named "gap" or "lib" exists,
    # it is installed.
    #
    # 3. If a binary directory "bin" exists, it is installed.
    #
    # 4. If a "doc" directory exists, we assume GAPDoc conventions
    # (https://docs.gap-system.org/pkg/gapdoc/doc/chap5.html) and install
    # what we find there. Unfortunately for us, each package's
    # PackageInfo.g contains a "PackageDoc" section that points to this
    # documentation, and we can't break the paths it references. Instead,
    # we try to dosym the human-readable parts of the documentation (PDF
    # manuals) into appropriate Gentoo locations.
    #
    # 5. We consult GAP_PKG_HTML_DOCDIR for the HTML documentation and repeat
    # the process above.
    #
    # A few GAP packages have autotools build systems with working "make
    # install" routines, but most don't. So for the time being we omit that
    # step. It's harder to work around the packages that don't support it
    # than the other way around.
    gap-pkg_src_install() {
    einstalldocs

    # So we don't have to "test -f" on the result of every glob.
    eshopts_push -s nullglob

    # Install the "normal" documentation from the doc directory. This
    # includes anything the interactive GAP help might need in addition
    # to the documentation intended for direct user consumption.
    if [[ -d doc ]]; then
    pushd doc > /dev/null || die

    local docdir="$(gap-pkg_dir)/doc"
    insinto "${docdir}"

    # These files are needed by the GAP interface. We don't symlink
    # these because they're not meant for direct human consumption;
    # the text files are not *plain* text -- they contain color
    # codes. I'm not sure if the BibTeX files are actually used,
    # but the GAP packaging documentation mentions specifically
    # that they should be included. XML files are included in case
    # the bibliography is in BibXMLext format, but you may wind up
    # with some additional GAPDoc (XML) source files as a result.
    for f in *.{bib,lab,six,tex,txt,xml}; do
    doins "${f}"
    done

    # The PDF docs are also potentially used by the interface, since
    # they appear in PackageInfo.g, so we install them "as is." But
    # then afterwards we symlink them to their proper Gentoo
    # locations
    for f in *.pdf; do
    doins "${f}"
    dosym -r "${docdir}/${f}" "/usr/share/doc/${PF}/${f}"
    done

    popd > /dev/null || die
    fi

    # Install the HTML documentation. The procedure is basically the
    # same as for the PDF docs.
    if [[ -d "${GAP_PKG_HTML_DOCDIR}" ]]; then
    pushd "${GAP_PKG_HTML_DOCDIR}" > /dev/null || die

    local docdir="$(gap-pkg_dir)/${GAP_PKG_HTML_DOCDIR}"
    insinto "${docdir}"

    # See above
    for f in *.{htm,html,css,js,png}; do
    doins "${f}"
    dosym -r "${docdir}/${f}" "/usr/share/doc/${PF}/html/${f}"
    done

    popd > /dev/null || die
    fi

    # Any GAP source files that live in the top-level directory.
    insinto $(gap-pkg_dir)
    for f in *.g; do
    doins "${f}"
    done

    # We're done globbing
    eshopts_pop

    # The gap and lib dirs that usually also contain GAP code.
    [[ -d gap ]] && doins -r gap
    [[ -d lib ]] && doins -r lib

    # Any additional user-specified files or directories.
    for f in "${GAP_PKG_EXTRA_INSTALL[@]}"; do
    doins -r "${f}"
    done

    # The bin dir, that contains shared libraries but also sometimes
    # regular executables in an arch-specific subdirectory. We do
    # this last because it messes with insopts -- doexe doesn't work
    # recursively and we don't care what the subdirectory structure is.
    if [[ -d bin ]]; then
    insopts -m0755
    doins -r bin

    # Find and remove .la files from this package's bindir. The
    # usual "find" command doesn't work here because occasionally we
    # find *.la files in GAP packages that are not libtool archives
    # and should not be deleted.
    find "${ED%/}$(gap-pkg_dir)/bin" -type f -name '*.la' -delete || die
    fi
    }

    EXPORT_FUNCTIONS src_configure src_compile src_test src_install

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)