Gentoo Archives: gentoo-dev

From: Andrew Ammerlaan <andrewammerlaan@××××××.net>
To: gentoo-dev@l.g.o
Subject: Re: [gentoo-dev] Fwd: New eclass suggestion: docs.eclass
Date: Tue, 28 Apr 2020 07:59:35
Message-Id: 6ccdc3f3-8437-b334-0a70-dc5d1fcf33de@riseup.net
In Reply to: Re: [gentoo-dev] Fwd: New eclass suggestion: docs.eclass by Joonas Niilola
1 On 28/04/2020 07:41, Joonas Niilola wrote:
2 > On 4/27/20 7:10 PM, Andrew Ammerlaan wrote:
3 >> Hi all,
4 >>
5 > Hey,
6 >
7 > could you please plaintext your whole patch in this thread, so it can be
8 > viewed and commented by replying? See how lanodan did. Or check:
9 >
10 > https://archives.gentoo.org/gentoo-dev/message/f2a7abcc8506ae3e56a0ebb0ea0cadc8
11 >
12 > -- juippis
13
14 I inserted this below.
15
16
17 On 27/04/2020 22:37, Haelwenn (lanodan) Monnier wrote:
18 > [2020-04-27 18:10:43+0200] Andrew Ammerlaan:
19 >> # Copyright 1999-2020 Gentoo Authors
20 >> # Distributed under the terms of the GNU General Public License v2
21 >>
22 >> # @ECLASS: docs.eclass
23 >> # @MAINTAINER:
24 >> # Andrew Ammerlaan <andrewammerlaan@××××××.net>
25 >> # @AUTHOR:
26 >> # Author: Andrew Ammerlaan <andrewammerlaan@××××××.net>
27 >> # Based on the work of: Michał Górny <mgorny@g.o>
28 >> # @SUPPORTED_EAPIS: 5 6 7
29 >> # @BLURB: A simple eclass to build documentation.
30 >> # @DESCRIPTION:
31 >> # A simple eclass providing functions to build documentation.
32 >> #
33 >> # Please note that docs sets RDEPEND and DEPEND unconditionally
34 >> # for you.
35 >> #
36 >> # This eclass also appends "doc" to IUSE, and sets HTML_DOCS
37 >> # to the location of the compiled documentation
38 >> #
39 >> # The aim of this eclass is to make it easy to add additional
40 >> # doc builders. To do this, add a <DOCBUILDER>-setup and
41 >> # <DOCBUILDER>-build function for your doc builder.
42 >> # For python based doc builders you can use the
43 >> # python_append_deps function to append [${PYTHON_USEDEP}]
44 >> # automatically to additional dependencies
45 >> #
46 >> # For more information, please see the Python Guide:
47 >> # https://dev.gentoo.org/~mgorny/python-guide/
48 > Should change this part to not be about python docs, right?
49
50
51 Thanks, this was a remnant from before I added doxygen support. I
52 removed the line as it is not really relevant anymore.
53
54 >> case "${EAPI:-0}" in
55 >> 0|1|2|3|4)
56 >> die "Unsupported EAPI=${EAPI:-0} (too old) for ${ECLASS}"
57 >> ;;
58 >> 5|6|7)
59 >> ;;
60 >> *)
61 >> die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
62 >> ;;
63 >> esac
64 >>
65 >> # @ECLASS-VARIABLE: DOCBUILDER
66 >> # @REQUIRED
67 >> # @PRE_INHERIT
68 >> # @DESCRIPTION:
69 >> # Sets the doc builder to use, currently supports
70 >> # sphinx and mkdocs
71 >>
72 >> # @ECLASS-VARIABLE: DOCDIR
73 >> # @DESCRIPTION:
74 >> # Sets the location of the doc builder config file.
75 > Suggestion:
76 > Path containing the doc builder config file(s).
77
78 Thanks, changed it to this
79
80
81 commit 60ca34730b8a5b090997e2f48a522f615fe9b680
82 Author: Andrew Ammerlaan <andrewammerlaan@××××××.net>
83 Date:   Sat Apr 11 10:57:44 2020 +0200
84
85     eclass/docs: setup mkdocs deps and build docs
86
87     works with sphinx and mkdocs. Based on distutils_enable_sphinx,
88     but unlike distutils also works for non-python packages
89
90     Package-Manager: Portage-2.3.98, Repoman-2.3.22
91     Signed-off-by: Andrew Ammerlaan <andrewammerlaan@××××××.net>
92
93 diff --git a/eclass/docs.eclass b/eclass/docs.eclass
94 new file mode 100644
95 index 00000000000..f3d4eb2ce41
96 --- /dev/null
97 +++ b/eclass/docs.eclass
98 @@ -0,0 +1,365 @@
99 +# Copyright 1999-2020 Gentoo Authors
100 +# Distributed under the terms of the GNU General Public License v2
101 +
102 +# @ECLASS: docs.eclass
103 +# @MAINTAINER:
104 +# Andrew Ammerlaan <andrewammerlaan@××××××.net>
105 +# @AUTHOR:
106 +# Author: Andrew Ammerlaan <andrewammerlaan@××××××.net>
107 +# Based on the work of: Micha艂 G贸rny <mgorny@g.o>
108 +# @SUPPORTED_EAPIS: 5 6 7
109 +# @BLURB: A simple eclass to build documentation.
110 +# @DESCRIPTION:
111 +# A simple eclass providing functions to build documentation.
112 +#
113 +# Please note that docs sets RDEPEND and DEPEND unconditionally
114 +# for you.
115 +#
116 +# This eclass also appends "doc" to IUSE, and sets HTML_DOCS
117 +# to the location of the compiled documentation
118 +#
119 +# The aim of this eclass is to make it easy to add additional
120 +# doc builders. To do this, add a <DOCBUILDER>-setup and
121 +# <DOCBUILDER>-build function for your doc builder.
122 +# For python based doc builders you can use the
123 +# python_append_deps function to append [${PYTHON_USEDEP}]
124 +# automatically to additional dependencies.
125 +
126 +case "${EAPI:-0}" in
127 +    0|1|2|3|4)
128 +        die "Unsupported EAPI=${EAPI:-0} (too old) for ${ECLASS}"
129 +        ;;
130 +    5|6|7)
131 +        ;;
132 +    *)
133 +        die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
134 +        ;;
135 +esac
136 +
137 +# @ECLASS-VARIABLE: DOCBUILDER
138 +# @REQUIRED
139 +# @PRE_INHERIT
140 +# @DESCRIPTION:
141 +# Sets the doc builder to use, currently supports
142 +# sphinx, mkdocs and doxygen
143 +
144 +# @ECLASS-VARIABLE: DOCDIR
145 +# @DESCRIPTION:
146 +# Path containing the doc builder config file(s).
147 +#
148 +# For sphinx this is the location of "conf.py"
149 +# For mkdocs this is the location of "mkdocs.yml"
150 +#
151 +# Note that mkdocs.yml often does not reside
152 +# in the same directory as the actual doc files
153 +#
154 +# Defaults to ${S}
155 +
156 +# @ECLASS-VARIABLE: DOCDEPEND
157 +# @DEFAULT_UNSET
158 +# @PRE_INHERIT
159 +# @DESCRIPTION:
160 +# Sets additional dependencies to build docs.
161 +# For sphinx and mkdocs these dependencies should
162 +# be specified without [${PYTHON_USEDEP}], this
163 +# is added by the eclass. E.g. to depend on mkdocs-material:
164 +#
165 +# DOCDEPEND="dev-python/mkdocs-material"
166 +#
167 +# This eclass appends to this variable, so you can
168 +# call it later in your ebuild again if necessary.
169 +
170 +# @ECLASS-VARIABLE: AUTODOC
171 +# @PRE_INHERIT
172 +# @DESCRIPTION:
173 +# Sets whether to use sphinx.ext.autodoc/mkautodoc
174 +# Defaults to 1 (True) for sphinx, and 0 (False) for mkdocs
175 +
176 +# @ECLASS-VARIABLE: OUTDIR
177 +# @DESCRIPTION:
178 +# Sets where the compiled files will be put.
179 +# There's no real reason to change this, but this
180 +# variable is useful if you want to overwrite the HTML_DOCS
181 +# added by this eclass. E.g.:
182 +#
183 +# HTML_DOCS=( "${yourdocs}" "${OUTDIR}/." )
184 +#
185 +# Defaults to ${DOCDIR}/_build/html
186 +
187 +# @ECLASS-VARIABLE: DOCS_CONFIG_NAME
188 +# @DESCRIPTION:
189 +# Name of the doc builder config file.
190 +#
191 +# Only relevant for doxygen, as it allows
192 +# config files with non-standard names
193 +#
194 +# Defaults to Doxyfile for doxygen
195 +
196 +if [[ ! ${_DOCS} ]]; then
197 +
198 +# For the python based DOCBUILDERS we need to inherit python-any-r1
199 +case "${DOCBUILDER}" in
200 +    "sphinx"|"mkdocs")
201 +        # If this is not a python package then
202 +        # this is not already set, so we need
203 +        # to set this to inherit python-any-r1
204 +        if [[ -z "${PYTHON_COMPAT}" ]]; then
205 +            PYTHON_COMPAT=( python3_{6,7,8} )
206 +        fi
207 +
208 +        # Inherit python-any-r1 if neither python-any-r1 nor
209 +        # python-r1 have been inherited, because we need the
210 +        # python_gen_any_dep function
211 +        if [[ ! ${_PYTHON_R1} && ! ${_PYTHON_ANY_R1} ]]; then
212 +            inherit python-any-r1
213 +        fi
214 +        ;;
215 +    "doxygen")
216 +        # do not need to inherit anything for doxygen
217 +        true
218 +        ;;
219 +    "")
220 +        die "DOCBUILDER unset, should be set to use ${ECLASS}"
221 +        ;;
222 +    *)
223 +        die "Unsupported DOCBUILDER=${DOCBUILDER} (unknown) for ${ECLASS}"
224 +        ;;
225 +esac
226 +
227 +# @FUNCTION: python_check_deps
228 +# @DESCRIPTION:
229 +# Check if the dependencies are valid
230 +python_check_deps() {
231 +    debug-print-function ${FUNCNAME}
232 +    use doc || return 0
233 +
234 +    local dep
235 +    for dep in ${check_deps[@]}; do
236 +        has_version "${dep}[${PYTHON_USEDEP}]" || return 1
237 +    done
238 +}
239 +# Save this before we start manipulating it
240 +check_deps=${DOCDEPEND}
241 +
242 +# @FUNCTION: python_append_dep
243 +# @DESCRIPTION:
244 +# Appends [\${PYTHON_USEDEP}] to all dependencies
245 +# for python based DOCBUILDERs such as mkdocs or
246 +# sphinx.
247 +python_append_deps() {
248 +    debug-print-function ${FUNCNAME}
249 +
250 +    local temp=()
251 +    local dep
252 +    for dep in ${DOCDEPEND[@]}; do
253 +        temp+=" ${dep}[\${PYTHON_USEDEP}]"
254 +    done
255 +    DOCDEPEND=${temp}
256 +}
257 +
258 +# @FUNCTION: sphinx_setup
259 +# @DESCRIPTION:
260 +# Sets dependencies for sphinx
261 +sphinx_setup() {
262 +    debug-print-function ${FUNCNAME}
263 +
264 +    : ${AUTODOC:=1}
265 +
266 +    if [[ ${AUTODOC} == 0 && -n "${DOCDEPEND}" ]]; then
267 +        die "${FUNCNAME}: do not set autodoc to 0 if external plugins
268 are used"
269 +    fi
270 +    if [[ ${AUTODOC} == 1 ]]; then
271 +        DOCDEPEND="$(python_gen_any_dep "
272 +            dev-python/sphinx[\${PYTHON_USEDEP}]
273 +            ${DOCDEPEND}")"
274 +
275 +    else
276 +        DOCDEPEND="dev-python/sphinx"
277 +    fi
278 +}
279 +
280 +# @FUNCTION: sphinx_compile
281 +# @DESCRIPTION:
282 +# Calls sphinx to build docs.
283 +#
284 +# If you overwrite src_compile or python_compile_all
285 +# do not call this function, call docs_compile instead
286 +sphinx_compile() {
287 +    debug-print-function ${FUNCNAME}
288 +    use doc || return
289 +
290 +    local confpy=${DOCDIR}/conf.py
291 +    [[ -f ${confpy} ]] ||
292 +        die "${confpy} not found, DOCDIR=${DOCDIR} call wrong"
293 +
294 +    if [[ ${AUTODOC} == 0 ]]; then
295 +        if grep -F -q 'sphinx.ext.autodoc' "${confpy}"; then
296 +            die "${FUNCNAME}: autodoc disabled but sphinx.ext.autodoc
297 found in ${confpy}"
298 +        fi
299 +    elif [[ ${AUTODOC} == 1 ]]; then
300 +        if ! grep -F -q 'sphinx.ext.autodoc' "${confpy}"; then
301 +            die "${FUNCNAME}: sphinx.ext.autodoc not found in
302 ${confpy}, set AUTODOC=0"
303 +        fi
304 +    fi
305 +
306 +    sed -i -e 's:^intersphinx_mapping:disabled_&:' \
307 +        "${DOCDIR}"/conf.py || die
308 +    # not all packages include the Makefile in pypi tarball
309 +    sphinx-build -b html -d "${DOCDIR}"/_build/doctrees "${DOCDIR}" \
310 +    "${OUTDIR}" || die
311 +}
312 +
313 +# @FUNCTION: mkdocs_setup
314 +# @DESCRIPTION:
315 +# Sets dependencies for mkdocs
316 +mkdocs_setup() {
317 +    debug-print-function ${FUNCNAME}
318 +
319 +    : ${AUTODOC:=0}
320 +
321 +    if [[ ${AUTODOC} == 1 ]]; then
322 +        DOCDEPEND="$(python_gen_any_dep "
323 +            dev-python/mkdocs[\${PYTHON_USEDEP}]
324 +            dev-python/mkautodoc[\${PYTHON_USEDEP}]
325 +        ${DOCDEPEND}")"
326 +    else
327 +        DOCDEPEND="$(python_gen_any_dep "
328 +            dev-python/mkdocs[\${PYTHON_USEDEP}]
329 +            ${DOCDEPEND}")"
330 +    fi
331 +}
332 +
333 +# @FUNCTION: mkdocs_compile
334 +# @DESCRIPTION:
335 +# Calls mkdocs to build docs.
336 +#
337 +# If you overwrite src_compile or python_compile_all
338 +# do not call this function, call docs_compile instead
339 +mkdocs_compile() {
340 +    debug-print-function ${FUNCNAME}
341 +    use doc || return
342 +
343 +    local mkdocsyml=${DOCDIR}/mkdocs.yml
344 +    [[ -f ${mkdocsyml} ]] ||
345 +        die "${mkdocsyml} not found, DOCDIR=${DOCDIR} wrong"
346 +
347 +    pushd "${DOCDIR}"
348 +    mkdocs build -d "${OUTDIR}" || die
349 +    popd
350 +
351 +    # remove generated .gz variants
352 +    # mkdocs currently has no option to disable this
353 +    # and portage complains: "Colliding files found by ecompress"
354 +    rm "${OUTDIR}"/*.gz || die
355 +}
356 +
357 +# @FUNCTION: doxygen_setup
358 +# @DESCRIPTION:
359 +# Sets dependencies for doxygen
360 +doxygen_setup() {
361 +    debug-print-function ${FUNCNAME}
362 +
363 +    DOCDEPEND="app-doc/doxygen
364 +            ${DOCDEPEND}"
365 +}
366 +
367 +# @FUNCTION: doxygen_compile
368 +# @DESCRIPTION:
369 +# Calls doxygen to build docs.
370 +#
371 +# If you overwrite src_compile or python_compile_all
372 +# do not call this function, call docs_compile instead
373 +doxygen_compile() {
374 +    debug-print-function ${FUNCNAME}
375 +    use doc || return
376 +
377 +    : ${DOCS_CONFIG_NAME:="Doxyfile"}
378 +
379 +    local doxyfile=${DOCDIR}/${DOCS_CONFIG_NAME}
380 +    [[ -f ${doxyfile} ]] ||
381 +        die "${doxyfile} not found, DOCDIR=${DOCDIR} or
382 DOCS_CONFIG_NAME=${DOCS_CONFIG_NAME} wrong"
383 +
384 +    # doxygen wants the HTML_OUTPUT dir to already exist
385 +    mkdir -p "${OUTDIR}"
386 +
387 +    pushd "${DOCDIR}"
388 +    (cat "${doxyfile}" ; echo "HTML_OUTPUT=${OUTDIR}") | doxygen - || die
389 +    popd
390 +}
391 +
392 +# @FUNCTION: docs_compile
393 +# @DESCRIPTION:
394 +# Calls DOCBUILDER and sets HTML_DOCS
395 +#
396 +# This function must be called in global scope.  Take care not to
397 +# overwrite the variables set by it. Has support for distutils-r1
398 +# eclass, but only if this eclass is inherited *after*
399 +# distutils-r1. If you need to extend src_compile() or
400 +# python_compile_all(), you can call the original implementation
401 +# as docs_compile.
402 +docs_compile() {
403 +    debug-print-function ${FUNCNAME}
404 +    use doc || return
405 +
406 +    # Set a sensible default as DOCDIR
407 +    : ${DOCDIR:="${S}"}
408 +
409 +    # Where to put the compiled files?
410 +    : ${OUTDIR:="${DOCDIR}/_build/html"}
411 +
412 +    case "${DOCBUILDER}" in
413 +        "sphinx")
414 +            sphinx_compile
415 +            ;;
416 +        "mkdocs")
417 +            mkdocs_compile
418 +            ;;
419 +        "doxygen")
420 +            doxygen_compile
421 +            ;;
422 +    esac
423 +
424 +    HTML_DOCS+=( "${OUTDIR}/." )
425 +
426 +    # we need to ensure successful return in case we're called last,
427 +    # otherwise Portage may wrongly assume sourcing failed
428 +    return 0
429 +}
430 +
431 +
432 +# This is where we setup the USE/(B)DEPEND variables
433 +# and call the doc builder specific setup functions
434 +IUSE+=" doc"
435 +
436 +# Call the correct setup function
437 +case "${DOCBUILDER}" in
438 +    "sphinx")
439 +        python_append_deps
440 +        sphinx_setup
441 +        ;;
442 +    "mkdocs")
443 +        python_append_deps
444 +        mkdocs_setup
445 +        ;;
446 +    "doxygen")
447 +        doxygen_setup
448 +        ;;
449 +esac
450 +
451 +if [[ ${EAPI} == [56] ]]; then
452 +    DEPEND+=" doc? ( ${DOCDEPEND} )"
453 +else
454 +    BDEPEND+=" doc? ( ${DOCDEPEND} )"
455 +fi
456 +
457 +# If this is a python package using distutils-r1
458 +# then put the compile function in the specific
459 +# python function, else just put it in src_compile
460 +if [[ ${_DISTUTILS_R1} && ( ${DOCBUILDER}="mkdocs" ||
461 ${DOCBUILDER}="sphinx" ) ]]; then
462 +    python_compile_all() { docs_compile; }
463 +else
464 +    src_compile() { docs_compile; }
465 +fi
466 +
467 +_DOCS=1
468 +fi