#!/usr/bin/env bash ############################################################################# ## ## Documentation automation script ## Last updated on October 2, 2023 ## ## This file is part of Logtalk ## SPDX-FileCopyrightText: 1998-2023 Paulo Moura ## SPDX-License-Identifier: Apache-2.0 ## ## Licensed under the Apache License, Version 2.0 (the "License"); ## you may not use this file except in compliance with the License. ## You may obtain a copy of the License at ## ## http://www.apache.org/licenses/LICENSE-2.0 ## ## Unless required by applicable law or agreed to in writing, software ## distributed under the License is distributed on an "AS IS" BASIS, ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## See the License for the specific language governing permissions and ## limitations under the License. ## ############################################################################# export LC_ALL=C print_version() { echo "$(basename "$0") 2.6" exit 0 } operating_system=$(uname -s) if [ "${operating_system:0:10}" == "MINGW32_NT" ] ; then # assume that we're running on Windows using the Git for Windows bash shell extension='.sh' elif [ "$LOGTALKHOME" != "" ] && [ "$LOGTALKUSER" != "" ] && [ "$LOGTALKHOME" == "$LOGTALKUSER" ] ; then # assume that we're running Logtalk without using the installer scripts extension='.sh' else extension='' fi # first, make sure that we don't peak Windows own timeout command, which is not usable for this purpose if [[ "$(command -v timeout)" == *"System32"* ]] || [[ "$(command -v timeout)" == *"system32"* ]] ; then timeout_command="" # second, look for GNU coreutils package timeout command elif [ -x "$(command -v timeout)" ] && [[ "$(timeout --version)" == *"GNU coreutils"* ]] ; then timeout_command="timeout -k 1" elif [ -x "$(command -v gtimeout)" ] && [[ "$(gtimeout --version)" == *"GNU coreutils"* ]] ; then timeout_command="gtimeout -k 1" else timeout_command="" fi # default argument values base="$PWD" results="$base/logtalk_doclet_logs" backend=swipl dot="" prolog='SWI-Prolog' logtalk=swilgt$extension logtalk_call="$logtalk -g" # disable timeouts to maintain backward compatibility timeout=0 prefix="$HOME/" run_doclets() { directory=$(dirname "$1") directory_short=${directory#$prefix} cd "$directory" || exit 1 echo '*******************************************************************************' echo "***** Documenting $directory_short" name=${directory////__} run_doclet "$name" "$documenting_goal" doclet_exit=$? if [ $doclet_exit -eq 0 ] ; then return 0 elif [ $doclet_exit -eq 124 ] ; then echo "***** timeout" echo "LOGTALK_TIMEOUT" >> "$results/$name.errors" else echo "***** crash" echo "LOGTALK_CRASH" >> "$results/$name.errors" fi return 0 } run_doclet() { name="$1" goal="$2" if [ "$timeout_command" != "" ] && [ $timeout -ne 0 ] ; then $timeout_command $timeout $logtalk_call "$goal" -- "$@" < /dev/null > "$results/$name.results" 2> "$results/$name.errors" else $logtalk_call "$goal" -- "$@" < /dev/null > "$results/$name.results" 2> "$results/$name.errors" fi return $? } usage_help() { echo echo "This script automates running doclets found on the current directory and recursively" echo "in its sub-directories by scanning for doclet.lgt and doclet.logtalk source files. In" echo "case of failed doclets or doclet errors, this script returns a non-zero exit code." echo echo "Usage:" echo " $(basename "$0") -p prolog [-d results] [-t timeout] [-s prefix] [-- arguments]" echo " $(basename "$0") -v" echo " $(basename "$0") -h" echo echo "Required arguments:" echo " -p backend Prolog compiler" echo " (possible values are b, ciao, cx, eclipse, gnu, gnunc, ji, lvm, sicstus, swi, swipack, tau, trealla, xsb, and yap)" echo echo "Optional arguments:" echo " -d directory to store the doclet logs (default is ./logtalk_doclet_logs)" echo " -t timeout in seconds for running each doclet (default is $timeout; i.e. disabled)" echo " -s suppress path prefix (default is $prefix)" echo " -- arguments to be passed to the integration script used to run the doclets (no default)" echo " -v print version" echo " -h help" echo } while getopts "vp:m:f:d:t:s:h" option do case $option in v) print_version;; p) p_arg="$OPTARG";; d) d_arg="$OPTARG";; t) t_arg="$OPTARG";; s) s_arg="$OPTARG";; h) usage_help; exit;; *) usage_help; exit 1;; esac done shift $((OPTIND - 1)) if [ "$p_arg" == "" ] ; then echo "Error! Backend Prolog compiler not specified!" >&2 usage_help exit 1 elif [ "$p_arg" == "b" ] ; then prolog='B-Prolog' logtalk=bplgt$extension logtalk_call="$logtalk -g" elif [ "$p_arg" == "ciao" ] ; then prolog='Ciao Prolog' logtalk=ciaolgt$extension logtalk_call="$logtalk -e" elif [ "$p_arg" == "cx" ] ; then prolog='CxProlog' logtalk=cxlgt$extension logtalk_call="$logtalk --goal" elif [ "$p_arg" == "eclipse" ] ; then prolog='ECLiPSe' logtalk=eclipselgt$extension logtalk_call="$logtalk -e" elif [ "$p_arg" == "gnu" ] ; then prolog='GNU Prolog' logtalk=gplgt$extension logtalk_call="$logtalk --query-goal" elif [ "$p_arg" == "gnunc" ] ; then prolog='GNU Prolog (native code)' logtalk=gplgtnc logtalk_call="$logtalk --query-goal" elif [ "$p_arg" == "ji" ] ; then prolog='JIProlog' logtalk=jiplgt$extension logtalk_call="$logtalk -n -g" elif [ "$p_arg" == "lvm" ] ; then prolog='LVM' logtalk=lvmlgt$extension logtalk_call="$logtalk -g" dot="." elif [ "$p_arg" == "sicstus" ] ; then prolog='SICStus Prolog' logtalk=sicstuslgt$extension logtalk_call="$logtalk --goal" dot="." elif [ "$p_arg" == "swi" ] ; then prolog='SWI-Prolog' logtalk=swilgt$extension logtalk_call="$logtalk -g" elif [ "$p_arg" == "swipack" ] ; then prolog='SWI-Prolog' logtalk=swipl logtalk_call="$logtalk -g" elif [ "$p_arg" == "tau" ] ; then prolog='Tau Prolog' logtalk=taulgt$extension logtalk_call="$logtalk -g" elif [ "$p_arg" == "trealla" ] ; then prolog='Trealla Prolog' logtalk=tplgt$extension logtalk_call="$logtalk -g" elif [ "$p_arg" == "xsb" ] ; then prolog='XSB' logtalk=xsblgt$extension logtalk_call="$logtalk -e" dot="." elif [ "$p_arg" == "yap" ] ; then prolog='YAP' logtalk=yaplgt$extension logtalk_call="$logtalk -g" elif [ "$p_arg" != "" ] ; then echo "Error! Unsupported backend Prolog compiler: $p_arg" >&2 usage_help exit 1 elif [ ! "$(command -v $backend)" ] ; then echo "Error! Default backend Prolog compiler not found: $prolog" >&2 usage_help exit 1 elif [ ! "$(command -v $logtalk)" ] ; then echo "Error! $logtalk integration script for $prolog not found." >&2 echo " Check that its directory is in your execution path." >&2 exit 1 fi if [ "$p_arg" == "swipack" ] ; then versions_goal="use_module(library(logtalk)),$versions_goal" fi if [ "$d_arg" != "" ] ; then results="$d_arg" fi if [ "$t_arg" != "" ] ; then timeout="$t_arg" fi if [ "$s_arg" != "" ] ; then prefix="$s_arg" fi if [ "$timeout_command" == "" ] ; then echo "Warning! Timeout support not available. The timeout option will be ignored." >&2 fi # documenting goals versions_goal="logtalk_load(library(tester_versions)),halt$dot" documenting_goal="logtalk_load([doclet(loader),doclet]),halt$dot" mkdir -p "$results" rm -f "$results"/*.results rm -f "$results"/*.errors rm -f "$results"/errors.all rm -f "$results"/tester_versions.txt touch "$results"/*.results touch "$results"/*.errors start_date=$(eval date \"+%Y-%m-%d %H:%M:%S\") echo '*******************************************************************************' echo "***** Batch documentation processing started @ $start_date" $logtalk_call $versions_goal > "$results"/tester_versions.txt 2> /dev/null grep -a "Logtalk version:" "$results"/tester_versions.txt grep -a "Prolog version:" "$results"/tester_versions.txt | sed "s/Prolog/$prolog/" doclets=0 output="$(find "$base" -name "doclet.lgt" -or -name "doclet.logtalk")" while read -r file && [ "$file" != "" ]; do ((doclets++)) run_doclets "$file" done <<< "$output" cd "$results" || exit 1 timeouts=$(cat -- *.errors | grep -c 'LOGTALK_TIMEOUT') crashes=$(cat -- *.errors | grep -c 'LOGTALK_CRASH') failures=$(cat -- *.results | grep -c 'failed') echo "*******************************************************************************" echo "***** Compilation errors/warnings and failed doclets" echo "*******************************************************************************" grep -s -a -A2 'syntax_error' -- *.results | sed 's/.results//' | tee errors.all grep -s -a -A2 'syntax_error' -- *.errors | sed 's/.errors//' | tee -a errors.all grep -s -a -h '! ' -- *.errors | sed 's/.errors//' | tee -a errors.all grep -s -a -h '! ' -- *.results | sed 's/.results//' | tee -a errors.all grep -s -a -h -F '* ' -- *.errors | sed 's/.errors//' | tee -a errors.all grep -s -a -h -F '* ' -- *.results | sed 's/.results//' | tee -a errors.all echo "*******************************************************************************" echo "***** Timeouts" echo "*******************************************************************************" grep -s -a 'LOGTALK_TIMEOUT' -- *.errors | sed 's/LOGTALK_TIMEOUT//' | sed 's/.errors://' | sed 's|__|/|g' | sed "s|^$prefix||" echo "*******************************************************************************" echo "***** Crashes" echo "*******************************************************************************" grep -s -a 'LOGTALK_CRASH' -- *.errors | sed 's/LOGTALK_CRASH//' | sed 's/.errors://' | sed 's|__|/|g' | sed "s|^$prefix||" echo "*******************************************************************************" echo "***** Failures" echo "*******************************************************************************" grep -s -a 'failed' -- *.results echo "*******************************************************************************" echo "***** $doclets doclets: $timeouts timeouts, $crashes crashes, $failures failures" echo "*******************************************************************************" end_date=$(eval date \"+%Y-%m-%d %H:%M:%S\") echo "***** Batch documentation processing ended @ $end_date" echo '*******************************************************************************' if [ "$crashes" -gt 0 ] ; then exit 7 elif [ "$timeouts" -gt 0 ] ; then exit 3 elif [ "$failures" -gt 0 ] ; then exit 1 else exit 0 fi