222 lines
6.7 KiB
Plaintext
222 lines
6.7 KiB
Plaintext
|
#!/bin/sh
|
||
|
|
||
|
#------------------------------------------------------------------------
|
||
|
# ${SELF} (${SELF_VERSION}) - Display a message on standard output
|
||
|
# Copyright © 2014 Pôle de compétences EOLE <eole@ac-dijon.fr>
|
||
|
#
|
||
|
# License CeCILL:
|
||
|
# * in french: http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html
|
||
|
# * in english http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
|
||
|
|
||
|
#------------------------------------------------------------------------
|
||
|
# Changes:
|
||
|
# 0.0.4 Add log utilities with a dedicated developper documentation
|
||
|
# 0.0.3 Add “--sources” option to write “${SELF}” code on standard output
|
||
|
# 0.0.2 Take care of DEBUG=yes environment variable
|
||
|
# 0.0.1 Initial release
|
||
|
|
||
|
#------------------------------------------------------------------------
|
||
|
# Usage: ${SELF} [--message <TEXT> | <OPTION>]
|
||
|
#
|
||
|
# Display a message on standard output.
|
||
|
#
|
||
|
# Options:
|
||
|
# --------
|
||
|
#
|
||
|
# -m, --message <TEXT> Display <TEXT> on standard output.
|
||
|
# Default: “${MESSAGE}"
|
||
|
# -d, --debug Enable debug messages
|
||
|
# -h, --help Show this message
|
||
|
# -v, --version Display version and copyright information
|
||
|
# -c, --copyright Display copyright information
|
||
|
# -l, --licence Display licence information
|
||
|
# --changes Display ChangeLog information
|
||
|
# -s, --sources Output software sources on standard output.
|
||
|
#
|
||
|
# Mandatory dependencies:
|
||
|
# -----------------------
|
||
|
# * “sh” like shell
|
||
|
# * “echo” with “-e” option
|
||
|
# * perl
|
||
|
#
|
||
|
# Optional dependencies:
|
||
|
# ----------------------
|
||
|
# None
|
||
|
#
|
||
|
# Bugs:
|
||
|
# ----
|
||
|
# Report bug to Équipe EOLE <eole@ac-dijon.fr>
|
||
|
# bugtracker: http://dev-eole.ac-dijon.fr/projects/<EOLE-SKELETOR>/issues
|
||
|
|
||
|
#------------------------------------------------------------------------
|
||
|
# Debug, first thing to do if something goes wrong, even in utilities
|
||
|
#
|
||
|
# “${DEBUG}” can be:
|
||
|
# - “all” to set “-x” option of the shell
|
||
|
# - “true” to enable the “debug()” function, set by “--debug” option
|
||
|
set -e
|
||
|
|
||
|
if [ "${DEBUG}" = 'all' ]
|
||
|
then
|
||
|
set -x
|
||
|
fi
|
||
|
|
||
|
#------------------------------------------------------------------------
|
||
|
# Utilities for developpers:
|
||
|
#
|
||
|
# log ($@): write all parameters on standard output and call “flog()” to
|
||
|
# write them in a file named “${LOG_FILE}” if it's:
|
||
|
# - defined
|
||
|
# - not a symlink
|
||
|
# - a file or a named pipe or a socket
|
||
|
# - writable or its parent directory is writable to create
|
||
|
# a regular file.
|
||
|
#
|
||
|
# warn($@): call “log()” with all parameters, output of log() is
|
||
|
# redirected to standard error.
|
||
|
#
|
||
|
# die($@): call “warn()” with all parameters, exit with code stored in
|
||
|
# “${EXIT_CODE}” or “1” if it does not exit.
|
||
|
#
|
||
|
# debug($@): call “warn()” with all parameters if “${DEBUG}" is
|
||
|
# “true”, the message is prefixed by the script name stored
|
||
|
# in “${SELF}”
|
||
|
#
|
||
|
# flog ($@): write all parameters prefixed by current date and time
|
||
|
# in a file named “${LOG_FILE}" if the variable is not empty.
|
||
|
# The caller is responsible of the writable check of “${LOG_FILE}”.
|
||
|
|
||
|
# Take care of “-e” option to echo
|
||
|
type shopt > /dev/null && ECHO=echo || ECHO=/bin/echo
|
||
|
|
||
|
## Logger functions
|
||
|
# Check if “log()” could write to “${LOG_FILE}”
|
||
|
log_writable() {
|
||
|
# First: check that filename is defined and not a symlink
|
||
|
# Second: check that filename is a file, a named pipe or a socket
|
||
|
# Thirt: if filename is writable or if its parent directory is writable
|
||
|
[ -n "${1}" -a ! -L "${1}" ] \
|
||
|
&& [ -f "${1}" -o -p "${1}" -o -S "${1}" ] \
|
||
|
&& [ -w "${1}" -o -w "$(dirname ${1})" ]
|
||
|
}
|
||
|
|
||
|
flog() { [ -z "${LOG_FILE}" ] || ${ECHO} -e "$(date "+%Y-%m-%d %H:%M:%S"): $@" >> "${LOG_FILE}"; }
|
||
|
log() { ${ECHO} -e "$@"; log_writable "${LOG_FILE}" && flog "$@" || true; }
|
||
|
warn() { log "$@" >&2; }
|
||
|
debug() { [ "${DEBUG}" = all -o "${DEBUG}" = true ] && warn "${SELF}: $@" || true; }
|
||
|
die() { warn "$@"; exit ${EXIT_CODE:-1}; }
|
||
|
|
||
|
## Common option functions
|
||
|
# Display list of changes
|
||
|
changes(){
|
||
|
${ECHO} -e "${SELF}\n"
|
||
|
perl -lne "s<\\$\\{([^\\}]+)\\}><\$ENV{\$1}>gxms;
|
||
|
print substr(\$_, 2) if (/^# Changes/ .. /^\$/) =~ /^\\d+\$/" < "${0}"
|
||
|
}
|
||
|
|
||
|
# Set SELF_VERSION variable
|
||
|
self_version() {
|
||
|
[ -z "${SELF_VERSION}" ] || return
|
||
|
export SELF_VERSION=$(changes 2>&1 \
|
||
|
| perl -lane 'if (m/^\s+\d+(?:\.\d+)*/) {print $F[0]; exit}')
|
||
|
}
|
||
|
|
||
|
# Display usage
|
||
|
usage() {
|
||
|
self_version
|
||
|
perl -lne "s<\\$\\{([^\\}]+)\\}><\$ENV{\$1}>gxms;
|
||
|
print substr(\$_, 2) if (/^# Usage/ .. /^\$/) =~ /^\\d+\$/" < "${0}"
|
||
|
}
|
||
|
|
||
|
# Display licence
|
||
|
licence() {
|
||
|
self_version
|
||
|
perl -lne "s<\\$\\{([^\\}]+)\\}><\$ENV{\$1}>gxms;
|
||
|
print substr(\$_, 2) if (/^# ${SELF} \(${SELF_VERSION}\)/ .. /^\$/) =~ /^\\d+\$/" < "${0}"
|
||
|
}
|
||
|
|
||
|
# Display sources making the software AGPL-3 ready
|
||
|
sources() {
|
||
|
cat < "${0}"
|
||
|
}
|
||
|
|
||
|
#------------------------------------------------------------------------
|
||
|
# Global variables:
|
||
|
#
|
||
|
# Use “export” to make them available to subprocesses
|
||
|
#
|
||
|
# Empty log file by default
|
||
|
LOG_FILE=
|
||
|
|
||
|
# Used by common options functions, do not unexport or they fail
|
||
|
export SELF=$(basename $(readlink -e "${0}"))
|
||
|
export SELF_VERSION= # Set by function, here for reference
|
||
|
|
||
|
# Program specific variables, export to use it in “usage()”
|
||
|
export MESSAGE="Hello World!"
|
||
|
|
||
|
#------------------------------------------------------------------------
|
||
|
# Options
|
||
|
TEMP=$(getopt -o m:dhvcls --long message:,debug,help,version,copyright,licence,changes,sources -- "$@")
|
||
|
|
||
|
test $? = 0 || exit 1
|
||
|
eval set -- "${TEMP}"
|
||
|
|
||
|
while true
|
||
|
do
|
||
|
case "${1}" in
|
||
|
# Default options for utilities
|
||
|
-h|--help)
|
||
|
usage
|
||
|
exit 0
|
||
|
;;
|
||
|
-v|--version)
|
||
|
licence | head -n 2
|
||
|
exit 0
|
||
|
;;
|
||
|
-c|--copyright)
|
||
|
licence | tail -n +2
|
||
|
exit 0
|
||
|
;;
|
||
|
-l|--licence)
|
||
|
licence
|
||
|
exit 0
|
||
|
;;
|
||
|
--changes)
|
||
|
changes
|
||
|
exit 0
|
||
|
;;
|
||
|
-s|--sources)
|
||
|
sources
|
||
|
exit 0
|
||
|
;;
|
||
|
|
||
|
-d|--debug)
|
||
|
DEBUG=true
|
||
|
shift
|
||
|
;;
|
||
|
|
||
|
# Program options
|
||
|
-m|--message)
|
||
|
[ -n "${2}" ] || die "Message must not be empty"
|
||
|
export MESSAGE="${2}"
|
||
|
shift 2
|
||
|
;;
|
||
|
|
||
|
# End of options
|
||
|
--)
|
||
|
shift
|
||
|
break
|
||
|
;;
|
||
|
*)
|
||
|
die "Error: unknown argument '${1}'"
|
||
|
;;
|
||
|
esac
|
||
|
done
|
||
|
|
||
|
#------------------------------------------------------------------------
|
||
|
# Start program
|
||
|
|
||
|
debug "This is a debug message on standard error"
|
||
|
${ECHO} "${MESSAGE}"
|