#!/usr/bin/env bash
# --------------------( LICENSE                            )--------------------
# Copyright (c) 2014-2024 Beartype authors.
# See "LICENSE" for further details.
#
# --------------------( SYNOPSIS                           )--------------------
# Bash shell script wrapping this project's Sphinx-based documentation build
# system, passing sane default options suitable for interactive terminal
# building and otherwise passing all passed arguments as is to the
# "sphinx-build" command via the "SPHINXOPTS" environment variable.
#
# This script is defined as a Bash rather than Bourne script purely for the
# canonical ${BASH_SOURCE} string global, reliably providing the absolute
# pathnames of this script and hence this script's directory.

# ....................{ PREAMBLE                           }....................
# Enable strictness for sanity.
set -e

# ....................{ ARRAYS                             }....................
# Array of all shell words with which to invoke "sphinx-build" below.
#
# Bizarrely, note that these Sphinx options are *ONLY* available in the short
# and long forms listed here. (This is us collectively shrugging.)
SPHINX_BUILD_ARGS=(
    command sphinx-build

    # ..................{ SPHINX ~ mode                      }..................
    # Generate HTML documentation.
    #
    # Note that we intentionally prefer the "html" to "dirhtml" build type when
    # locally revising documentation, despite ReadTheDocs (RTD) preferring the
    # latter. Why? Because the latter incorrectly links to directories rather
    # than HTML files in directories when generating local documentation.
    -M html
    # -b dirhtml

    # ..................{ SPHINX ~ paths                     }..................
    # Relative dirname of the directory containing source documentation in
    # reStructuredText (reST) format.
    doc/src/

    # Relative dirname of the directory containing target documentation in the
    # format corresponding to the "-M" option above (typically, HTML).
    doc/trg/

    # Pass all remaining non-option arguments to "sphinx-build" as is,
    # comprising the set of all relative or absolute filenames to be built. If
    # unpassed, "sphinx-build" rebuilds all outdated files by default.
    "${@}"

    # ..................{ SPHINX ~ options                   }..................
    #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    # CAUTION: In flagrant violation of POSIX standards, sensible norms, and its
    # own bloody documentation in both "--help" text and error messages,
    # "sphinx-build" requires that options be passed *AFTER* pathnames. By
    # inspection, the autogenerated "doc/Makefile" does so. If options are
    # erroneously passed *BEFORE* pathnames, "sphinx-build" fails with this
    # non-human-readable fatal error:
    #     $ ./sphinx
    #     usage: sphinx-build [OPTIONS] SOURCEDIR OUTPUTDIR [FILENAMES...]
    #     sphinx-build: error: argument -d: expected one argument
    #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    # Suffix raised exceptions with tracebacks. This is *CRITICAL.* By default,
    # Sphinx insanely emits *ONLY* useless exception messages.
    -T

    # Treat non-fatal warnings as fatal errors. This is *CRITICAL.* By default,
    # Sphinx insanely emits non-fatal warnings for fatal errors... Not kidding.
    -W

    #FIXME: Uncomment this when caching issues inevitably arise.
    # Unconditionally rebuild *EVERY* target output documentation regardless of
    # whether the source input files providing that documentation have been
    # modified or not. By default, Sphinx only conditionally rebuilds target
    # documentation whose underlying source files have since been modified.
    # -a

    #FIXME: This appears to redundantly do the same thing as "-a" and is thus
    #currently disabled. That said, if and when caching issues arise, consider
    #uncommenting this as well just to be sure. *shrug*
    # -E

    # Parallelize the build process across *ALL* available CPU cores.
    -j auto

    # Collect *ALL* warnings before failing rather than immediately failing on
    # the first warning.
    --keep-going

    #FIXME: Temporarily disabled until we either resolve exactly why the Sphinx
    #"autodoc" extension is failing to generate *ANY* working references or
    #(more likely) ditch "autodoc" for something sane based on AST parsing.
    #Currently, "autodoc" fails to generate working references for even
    #standard pure-Python modules guaranteed to exist (e.g., "typing").
    # Enable "nit-picky mode," generating one warning for each broken reference
    # (e.g., interdocument or intrasection link).
    -n

    #FIXME: Uncomment to assist in debugging, please.
    # Increase verbosity.
    #-vv
)
echo "Running: ${SPHINX_BUILD_ARGS[*]}"

# ....................{ FUNCTIONS                          }....................
# str canonicalize_path(str pathname)
#
# Canonicalize the passed pathname.
function canonicalize_path() {
    # Validate and localize all passed arguments.
    (( $# == 1 )) || {
        echo 'Expected exactly one argument.' 1>&2
        return 1
    }
    local pathname="${1}"

    # The "readlink" command's GNU-specific "-f" option would be preferable but
    # is unsupported by macOS's NetBSD-specific version of "readlink". Instead,
    # just defer to Python for portability.
    command python3 -c "
import os, sys
print(os.path.realpath(os.path.expanduser(sys.argv[1])))" "${pathname}"
}

# ....................{ PATHS                              }....................
# Absolute or relative filename of this script.
SCRIPT_FILENAME="$(canonicalize_path "${BASH_SOURCE[0]}")"

# Absolute or relative dirname of the directory directly containing this
# script, equivalent to the top-level directory for this project.
SCRIPT_DIRNAME="$(dirname "${SCRIPT_FILENAME}")"

# ....................{ MAIN                               }....................
# Temporarily change the current working directory to that of this project.
# pushd "${SCRIPT_DIRNAME}/doc" >/dev/null
pushd "${SCRIPT_DIRNAME}" >/dev/null

# Build this project's documentation with all passed arguments.
"${SPHINX_BUILD_ARGS[@]}"

# 0-based exit code reported by the prior command.
exit_code=$?

# Revert the current working directory to the prior such directory.
popd >/dev/null

# Report the same exit code from this script.
exit ${exit_code}
