Files
asterisk/build_tools/make_xml_documentation
George Joseph 797e258be1 docs: Add "Provided-by" to doc XML and CLI output.
For application, function, manager, managerEvent, managerEventInstance
and info XML documentation nodes, the make_xml_documentation script will
add a "module" attribute if not already present.  For XML in separate
"*_doc.xml" files, the script figures out the correct module name.  For
documentation in the "main" directory, the module name is set to "builtin".

The CLI handlers for "core show application", "core show function",
"manager show command" and "manager show event", have been updated to
show the following after the Synopsis...

```
[Provided By]
<modulename>
```

For modules that provide additional "info" elements (like the technologies
do for Dial), the providing module has also been added.

```
Technology: WebSocket  Provided by: chan_websocket
WebSocket Dial Strings:
...
```

UserNote: The CLI help for applications, functions, manager commands and
manager events now shows the module that provides its functionality.
2026-03-03 18:55:56 +00:00

277 lines
8.3 KiB
Bash
Executable File

#!/bin/sh
# shellcheck disable=SC2154
PROGNAME="${0##*/}"
# Fail on errors
set -e
usage() {
cat <<-EOF
Usage: ${PROGNAME} --command=(create_xml | print_dependencies)
--source-tree=<asterisk_source_tree> [ --mod-subdirs=<subdir_search_list> ]
[ --with-moduleinfo ] [--for-wiki ] [ --validate ]
[ --output-file=<output_xml_file> ]
[ --core-output-file=<core_output_xml_file> ]
command:
print_dependencies: Print the source files that have documentation
for use by "make" as dependencies.
create_xml: Create the actual XML output file.
source-tree: The path to the Asterisk source tree.
mod-subdirs: A quoted, space-separated list of module sub-directories
to search for documentation. Defaults to
"channels pbx apps codecs formats cdr cel bridges funcs tests main res addons"
with-moduleinfo: Include the "MODULEINFO" block from source files.
Default is to not include MODULEINFO
for-wiki: Perform special post processing for wiki documentation.
This creates two output files and therefore needs both
<output-file> and <core-output-file>.
Default is to not perform wiki post-processing.
validate: Run xmllint or xmlstarlet to validate output-file.
output-file: The XML file to write to if the command was
"create_xml".
core-output-file: The additional XML file to write to if the command was
"create_xml" with "for-wiki".
EOF
}
with_moduleinfo=0
for_wiki=0
validate=0
command=""
mod_subdirs="channels pbx apps codecs formats cdr cel bridges funcs tests main res addons"
source_tree=""
output_file=""
core_output_file=""
for arg in "$@" ; do
case ${arg} in
--for-wiki)
for_wiki=1
;;
--with-moduleinfo)
with_moduleinfo=1
;;
--validate)
validate=1
;;
--command=*)
command=${arg#*=}
;;
--source-tree=*)
source_tree=${arg#*=}
;;
--mod-subdirs=*)
mod_subdirs="${arg#*=}"
;;
--output-file=*)
output_file=${arg#*=}
;;
--core-output-file=*)
core_output_file=${arg#*=}
;;
-h|--help)
usage
exit 0
;;
*)
echo "unknown option '${arg}'."
usage
exit 1
;;
esac
done
if [ "${command}" = "" ] ; then
echo "No command specified"
usage
exit 1
fi
if [ "${source_tree}" = "" ] ; then
echo "No source-tree specified"
usage
exit 1;
fi
if [ ! -d "${source_tree}" ] ; then
echo "Asterisk source tree '${source_tree}' doesn't exist."
exit 1
fi
if [ ! -f "${source_tree}/makeopts" ] ; then
echo "There's no 'makeopts' in '${source_tree}'. Maybe you need to run ./configure?"
exit 1
fi
# This script is normally run from the top-level Makefile which
# will set the tools variables to actual paths, or ':' if
# the tool isn't found. If this script is run from the
# command line for testing purposes however, we'll need to
# set some sane defaults.
if [ "${GREP}" = "" ] ; then GREP="grep" ; fi
if [ "${FIND}" = "" ] ; then FIND="find" ; fi
if [ "${AWK}" = "" ] ; then AWK="awk" ; fi
if [ "${DIRNAME}" = "" ] ; then DIRNAME="dirname" ; fi
if [ "${BASENAME}" = "" ] ; then BASENAME="basename" ; fi
if [ "${SED}" = "" ] ; then SED="sed" ; fi
if [ "${CAT}" = "" ] ; then CAT="cat" ; fi
if [ "${XMLLINT}" = "" ] ; then XMLLINT="xmllint" ; fi
if [ "${XMLSTARLET}" = "" ] ; then XMLSTARLET="xmlstarlet" ; fi
if [ "${for_wiki}" -eq "1" ] || [ "${validate}" -eq "1" ]; then
if [ "${XMLLINT}${XMLSTARLET}" = "::" ] ; then
echo "Either xmllint or xmlstarlet is required for wiki post-processing or validation."
exit 1
fi
fi
make_absolute() {
case "$1" in
/*) echo "$1" ;;
*) echo "$source_tree/$1" ;;
esac
}
if [ "${command}" = "print_dependencies" ] ; then
for subdir in ${mod_subdirs} ; do
subpath=$(make_absolute "$subdir")
${FIND} "${subpath}" \( -name '*.c' -o -name '*.cc' -o -name '*.xml' \) \
-exec ${GREP} -l -E '(language="en_US"|appdocsxml.dtd)' '{}' \;
done
exit
fi
if [ "${command}" != "create_xml" ] ; then
echo "Command '${command}' is invalid."
usage
exit 1
fi
if [ "${output_file}" = "" ] ; then
echo "output-file is required for command '${command}'."
usage
exit 1;
fi
output_dir=$(${DIRNAME} "${output_file}")
if [ ! -d "${output_dir}" ] ; then
echo "output destination directory '${output_dir}' doesn't exist."
exit 1
fi
if [ "${for_wiki}" -eq "1" ] && [ "${core_output_file}" = "" ] ; then
echo "core-output-file is required for command '${command}' and 'for-wiki'."
usage
exit 1;
fi
core_output_dir=$(${DIRNAME} "${core_output_file}")
if [ ! -d "${core_output_dir}" ] ; then
echo "core destination directory '${core_output_dir}' doesn't exist."
exit 1
fi
${CAT} > "${output_file}" <<-EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE docs SYSTEM "appdocsxml.dtd">
<?xml-stylesheet type="text/xsl" href="appdocsxml.xslt"?>
<docs xmlns:xi="http://www.w3.org/2001/XInclude">
EOF
printf "Building Documentation For: "
for subdir in ${mod_subdirs} ; do
printf "%s " "${subdir}"
subdir_path=$(make_absolute "$subdir")
for i in $(${FIND} "${subdir_path}" -name '*.c' -or -name '*.cc'); do
if [ "${with_moduleinfo}" -eq "1" ] ; then
MODULEINFO=$(${AWK} -f "${source_tree}/build_tools/get_moduleinfo" "${i}")
if [ "${MODULEINFO}" != "" ] ; then
${CAT} >> "${output_file}" <<-EOF
<module language="en_US" name="$(${BASENAME} "${i}" .c)">
${MODULEINFO}
</module>
EOF
fi
fi
if [ "${for_wiki}" -eq "1" ] ; then
${PYTHON} build_tools/get_documentation.py < "${i}" > /tmp/xmldoc.tmp.xml
else
${AWK} -f "${source_tree}/build_tools/get_documentation" "${i}" > /tmp/xmldoc.tmp.xml
fi
if [ "${subdir}" = "main" ] ; then
# Force the module to be "builtin" if the source is in the main directory.
mn="builtin"
else
# Otherwise, let's just get the basename of the module.
bn=${i##*/}
mn=${bn%%.*}
fi
# Set the module name on specific elements
${SED} -r -e "s/<(manager|managerEvent|managerEventInstance|function|application|info)\s+([^>]+)>/<\1 \2 module=\"${mn}\">/g" /tmp/xmldoc.tmp.xml >> "${output_file}"
done
for i in $(${FIND} "${subdir_path}" -name '*.xml') ; do
${GREP} -q "appdocsxml.dtd" "${i}" || continue
if [ "${validate}" -eq "1" ] ;then
if [ "${XMLLINT}" != ":" ] ; then
${XMLLINT} --dtdvalid "${source_tree}/doc/appdocsxml.dtd" --path "${source_tree}/doc" --noout "${i}" || { echo "" ; exit 1 ; }
else
${XMLSTARLET} val -q -d "${source_tree}/doc/appdocsxml.dtd" "${i}" ||
${XMLSTARLET} val -e -d "${source_tree}/doc/appdocsxml.dtd" "${i}" || { echo "" ; exit 1 ; }
fi
fi
${SED} -r "/^\s*(<[?]xml|<.DOCTYPE|<.?docs)/d" "${i}" > /tmp/xmldoc.tmp.xml
dirname=${i%/*}
if [ "${dirname}" != "${subdir_path}" ] ; then
# If we're in a subdirectory like channels/pjsip, we need to check channels/Makefile
# to see which module xml files in this directory belong to.
bn=${dirname##*/}
mn=$(${SED} -n -r -e "s/^[$]\(call MOD_ADD_C,([^,]+),[$]\(wildcard\s+${bn}\/.*/\1/gp" "${subdir_path}/Makefile")
else
if [ "${subdir}" = "main" ] ; then
# Force the module to be "builtin" if the XML is in the main directory.
mn="builtin"
else
# Otherwise the xml should have be "<module>_doc.xml" suffix so
# get the basename then strip the suffix.
bn=${i##*/}
mn=${bn%%_doc.xml}
fi
fi
# Set the module name on specific elements
${SED} -r -e "s/<(manager|managerEvent|managerEventInstance|function|application|info)\s+([^>]+)>/<\1 \2 module=\"${mn}\">/g" /tmp/xmldoc.tmp.xml >> "${output_file}"
done
done
echo "</docs>" >> "${output_file}"
echo ""
# Some entries may already have a module attribute so remove the dup.
# It's easier to do this once on the entire file rather on a source-by-source basis.
cp "${output_file}" /tmp/xmldoc.tmp.xml
${SED} -r -e 's/module="([^"]+)"\s+module="([^"]+)">/module="\1">/g' /tmp/xmldoc.tmp.xml > "${output_file}"
if [ "${for_wiki}" -eq "1" ] ; then
${PYTHON} build_tools/post_process_documentation.py -i "${output_file}" -o "${core_output_file}"
fi
if [ "${validate}" -eq "1" ] ;then
if [ "${XMLLINT}" != ":" ] ; then
${XMLLINT} --dtdvalid "${source_tree}/doc/appdocsxml.dtd" --path "${source_tree}/doc" --noout "${output_file}" || exit 1
else
${XMLSTARLET} val -q -d "${source_tree}/doc/appdocsxml.dtd" "${output_file}" ||
${XMLSTARLET} val -e -d "${source_tree}/doc/appdocsxml.dtd" "${output_file}" || { echo "" ; exit 1 ; }
fi
fi