#!/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}"