improved waiting for elements: defaults to timeout-1 if element should be there, defaults to timeout/3 if element is optional
This commit is contained in:
@@ -274,9 +274,9 @@ AC_DEFUN([AX_QT_NO_KEYWORDS], [
|
||||
])
|
||||
|
||||
AC_DEFUN([AX_INIT_QT], [
|
||||
if test -n "${AX_ADDITIONAL_QT_RULES_HACK}"; then
|
||||
test -f src/makefile.in && cat >> src/makefile.in <<EOF
|
||||
#### HERE
|
||||
${AX_ADDITIONAL_QT_RULES_HACK}
|
||||
#### WE ARE
|
||||
EOF
|
||||
fi
|
||||
])
|
||||
|
@@ -90,7 +90,7 @@ dnl refers to ${prefix}. Thus we have to use `eval' twice.
|
||||
# $3 = filename of makefile.in
|
||||
AC_DEFUN([AX_ADD_MAKEFILE_TARGET_DEP], [
|
||||
sh_add_makefile_target_dep() {
|
||||
sed -i -e ':a;/^'${1}':.*\\$/{N;s/\\\n//;ta};s/^'${1}':.*$/& '${2}'/' "${srcdir}/${3}"
|
||||
sed -i -e ':a;/^'${1}':.*\\$/{N;s/\\\n//;ta};s/^'"${1}"':.*$/& '"${2}"'/' "${srcdir}/${3}"
|
||||
if ! egrep -q "${1}:.* ${2}" "${srcdir}/${3}"; then
|
||||
echo "${1}: ${2}" >> "${srcdir}/${3}"
|
||||
fi
|
||||
@@ -1229,4 +1229,5 @@ AC_DEFUN([AX_OUTPUT], [
|
||||
AX_RPM_RESOLVE
|
||||
AC_OUTPUT
|
||||
AX_INIT_QT
|
||||
AC_MSG_NOTICE([configured for ${PACKAGE_NAME}-${VERSION}])
|
||||
])
|
||||
|
37
bootstrap.sh
37
bootstrap.sh
@@ -138,6 +138,8 @@ GENERATED FILES
|
||||
* build-resource-file.sh - build resource.qrc file from a resource directory
|
||||
* sql-to-dot.sed - script to convert SQL schema files to graphviz dot in doxygen
|
||||
* mac-create-app-bundle.sh - script to create apple mac os-x app-bundle
|
||||
* dependency-graph.sh - script to draw project dependencies
|
||||
* template.sh - generic template for bash scripts
|
||||
* test/runtests.sh - template file to run test scripts, i.e. docker based
|
||||
* AUTHORS - replace your name in AUTHORS before first run
|
||||
* NEWS - empty file add your project's news
|
||||
@@ -549,6 +551,8 @@ copy rpmsign.exp
|
||||
copy build-resource-file.sh
|
||||
copy sql-to-dot.sed
|
||||
copy mac-create-app-bundle.sh
|
||||
copy dependency-graph.sh
|
||||
copy template.sh
|
||||
AUTHOR=$(gpg -K 2>/dev/null | sed -n 's,uid *\(\[ultimate\] *\)\?,,p' | head -1)
|
||||
if test -z "${AUTHOR}"; then
|
||||
AUTHOR="FIRSTNAME LASTNAME (URL) <EMAIL>"
|
||||
@@ -1635,7 +1639,7 @@ BuildRequires: which, pkgconfig, gnupg, expect, ${VCSDEPENDS_RPM}make, automake,
|
||||
%if 0%{?suse_version} || 0%{?sles_version}
|
||||
BuildRequires: lsb-release$(
|
||||
if testtag AX_REQUIRE_QT || testtag AX_CHECK_QT; then
|
||||
echo -n ", libqt5-qtbase-devel, libqt5-qttools, libQt5WebKit5-devel libqt5-qtwebengine-devel libQt5WebKitWidgets-devel";
|
||||
echo -n ", libqt5-qtbase-devel, libqt5-qttools, libqt5-linguist-devel, libQt5WebKit5-devel libqt5-qtwebengine-devel libQt5WebKitWidgets-devel";
|
||||
fi)
|
||||
%else
|
||||
$(
|
||||
@@ -1695,25 +1699,20 @@ rm -rf \$RPM_BUILD_ROOT
|
||||
$(if testtag AX_USE_LIBTOOL; then
|
||||
echo '/usr/%_lib/*.so.*'
|
||||
else
|
||||
echo '/usr/bin/*'
|
||||
echo '/usr/share/applications/*'
|
||||
echo '/usr/bin'
|
||||
echo '/usr/share/applications'
|
||||
fi)
|
||||
$(if testtag AX_USE_NODEJS AX_BUILD_HTML AX_BUILD_HTML_NPM; then
|
||||
echo '/usr/share/@PACKAGE_NAME@'
|
||||
/usr/share/@PACKAGE_NAME@
|
||||
$(if testtag AX_USE_ETC; then
|
||||
|
||||
cat <<EOF2
|
||||
%config
|
||||
/etc/*
|
||||
|
||||
EOF2
|
||||
fi)
|
||||
%doc
|
||||
$(if testtag AX_USE_LIBTOOL; then
|
||||
cat <<EOF2
|
||||
/usr/share/doc/packages/@PACKAGE_NAME@/AUTHORS
|
||||
/usr/share/doc/packages/@PACKAGE_NAME@/COPYING
|
||||
/usr/share/doc/packages/@PACKAGE_NAME@/ChangeLog
|
||||
/usr/share/doc/packages/@PACKAGE_NAME@/INSTALL
|
||||
/usr/share/doc/packages/@PACKAGE_NAME@/NEWS
|
||||
/usr/share/doc/packages/@PACKAGE_NAME@/README
|
||||
EOF2
|
||||
else
|
||||
echo '/usr/share'
|
||||
fi)
|
||||
/usr/share/doc
|
||||
|
||||
$(if testtag AX_USE_LIBTOOL; then
|
||||
cat <<EOF2
|
||||
@@ -1792,12 +1791,14 @@ ${HEADER}SUBDIRS =${SUBDIRS}
|
||||
|
||||
desktopdir = \${datadir}/applications
|
||||
desktop_DATA = @PACKAGE_DESKTOP@
|
||||
dist_pkgdata_DATA = @PACKAGE_ICON@ ax_check_qt.m4 bootstrap.sh \\
|
||||
dist_pkgdata_DATA = @PACKAGE_ICON@
|
||||
dist_noinst_DATA = ax_check_qt.m4 bootstrap.sh \\
|
||||
resolve-rpmbuilddeps.sh autogen.sh \\
|
||||
ax_cxx_compile_stdcxx_11.m4 build-in-docker.sh \\
|
||||
build-resource-file.sh \\
|
||||
ax_init_standard_project.m4 \\
|
||||
mac-create-app-bundle.sh resolve-debbuilddeps.sh \\
|
||||
dependency-graph.sh template.sh \\
|
||||
sql-to-dot.sed
|
||||
dist_doc_DATA = AUTHORS NEWS README COPYING INSTALL ChangeLog
|
||||
|
||||
|
171
dependency-graph.sh
Executable file
171
dependency-graph.sh
Executable file
@@ -0,0 +1,171 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
# template for bash scripts
|
||||
|
||||
# internal use only
|
||||
append_msg() {
|
||||
if test $# -ne 0; then
|
||||
echo -en ":\e[0m \e[1m$*"
|
||||
fi
|
||||
echo -e "\e[0m"
|
||||
}
|
||||
|
||||
# write a notice
|
||||
notice() {
|
||||
if test $# -eq 0; then
|
||||
return
|
||||
fi
|
||||
echo -e "\e[1m$*\e[0m" 1>&3
|
||||
}
|
||||
|
||||
# write error message
|
||||
error() {
|
||||
echo -en "\e[1;31merror" 1>&2
|
||||
append_msg $* 1>&2
|
||||
}
|
||||
|
||||
# write a warning message
|
||||
warning() {
|
||||
echo -en "\e[1;33mwarning" 1>&2
|
||||
append_msg $* 1>&2
|
||||
}
|
||||
|
||||
# write a success message
|
||||
success() {
|
||||
echo -en "\e[1;32msuccess" 1>&2
|
||||
append_msg $* 1>&2
|
||||
}
|
||||
|
||||
# commandline parameter evaluation
|
||||
files=${0%/*}/configure.ac
|
||||
short=0
|
||||
while test $# -gt 0; do
|
||||
case "$1" in
|
||||
(--short|-s) short=1;;
|
||||
(--help|-h) less <<EOF
|
||||
SYNOPSIS
|
||||
|
||||
$0 [OPTIONS] <files>
|
||||
|
||||
OPTIONS
|
||||
|
||||
--help, -h show this help
|
||||
--short, -s short graph with no external dependencies
|
||||
|
||||
<files> list of zero or more configure.ac files
|
||||
(default: ${files})
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
Evaluates dependencies of all the given configure.ac file. By
|
||||
default takes the local configure.ac. Outputs a graphwiz dot file
|
||||
with the dependencies. Solid lines are required dependencies, dotted
|
||||
lines are optional dependencies.
|
||||
|
||||
EXAMPLE
|
||||
|
||||
Evaluate all dependencies between all local subversion and git
|
||||
projects, if they are in the path ~/svn and ~/git:
|
||||
|
||||
$0 ~/svn/*/configure.ac ~/git/*/configure.ac
|
||||
|
||||
EOF
|
||||
exit;;
|
||||
(*) files=$*; break;;
|
||||
esac
|
||||
if test $# -eq 0; then
|
||||
error "missing parameter, try $0 --help"; exit 1
|
||||
fi
|
||||
shift;
|
||||
done
|
||||
|
||||
# run a command, print the result and abort in case of error
|
||||
# option: --no-check: ignore the result, continue in case of error
|
||||
run() {
|
||||
check=1
|
||||
while test $# -gt 0; do
|
||||
case "$1" in
|
||||
(--no-check) check=0;;
|
||||
(*) break;;
|
||||
esac
|
||||
shift;
|
||||
done
|
||||
echo -en "\e[1m-> running:\e[0m $* ..."
|
||||
result=$($* 2>&1)
|
||||
res=$?
|
||||
if test $res -ne 0; then
|
||||
if test $check -eq 1; then
|
||||
error "failed with return code: $res"
|
||||
if test -n "$result"; then
|
||||
echo "$result"
|
||||
fi
|
||||
exit 1
|
||||
else
|
||||
warning "ignored return code: $res"
|
||||
fi
|
||||
else
|
||||
success
|
||||
fi
|
||||
}
|
||||
|
||||
# error handler
|
||||
function traperror() {
|
||||
set +x
|
||||
local err=($1) # error status
|
||||
local line="$2" # LINENO
|
||||
local linecallfunc="$3"
|
||||
local command="$4"
|
||||
local funcstack="$5"
|
||||
for e in ${err[@]}; do
|
||||
if test -n "$e" -a "$e" != "0"; then
|
||||
error "line $line - command '$command' exited with status: $e (${err[@]})"
|
||||
if [ "${funcstack}" != "main" -o "$linecallfunc" != "0" ]; then
|
||||
echo -n " ... error at ${funcstack} "
|
||||
if [ "$linecallfunc" != "" ]; then
|
||||
echo -n "called at line $linecallfunc"
|
||||
fi
|
||||
echo
|
||||
fi
|
||||
exit $e
|
||||
fi
|
||||
done
|
||||
success
|
||||
exit 0
|
||||
}
|
||||
|
||||
# catch errors
|
||||
trap 'traperror "$? ${PIPESTATUS[@]}" $LINENO $BASH_LINENO "$BASH_COMMAND" "${FUNCNAME[@]}" "${FUNCTION}"' ERR SIGINT INT TERM EXIT
|
||||
|
||||
##########################################################################################
|
||||
|
||||
filter() {
|
||||
if test $short -eq 1; then
|
||||
all=$(cat)
|
||||
allowed=$(sed -n '/"\(.*\)" \[style=solid\];/{s//\1/;H};${x;s/\n//;s/\n/\\|/gp}' <<<"${all}")
|
||||
sed -n '/"\('"${allowed}"'\)" -> "\('"${allowed}"'\)"/p' <<<"${all}"
|
||||
else
|
||||
cat
|
||||
fi
|
||||
}
|
||||
|
||||
echo "digraph G {"
|
||||
if test $short -eq 0; then
|
||||
echo "node [style=dashed];"
|
||||
fi
|
||||
(
|
||||
for file in $files; do
|
||||
if ! test -e $file; then
|
||||
error "file $file not found"; exit 1
|
||||
fi
|
||||
sed -n '
|
||||
/^ *m4_define(x_package_name, */ {s//"/;s/ *).*/"/;h;s/.*/& [style=solid];/p}
|
||||
/^ *AX_REQUIRE_QT/ {s/.*/"qt" -> /;G;s/\n//;s/.*/&;/p}
|
||||
/^ *AX_PKG_REQUIRE(\[\?\([^],)]\+\)\]\?, \[\?\([^],)]\+\)\]\?.*/ {s//"\2" -> /;G;s/\n//;s/.*/&;/p}
|
||||
/^ *AX_PKG_REQUIRE(\[\?\([^],)]\+\)\]\?.*/ {s//"\1" -> /;G;s/\n//;s/.*/&;/p}
|
||||
/^ *AX_CHECK_QT/ {s/.*/"qt" -> /;G;s/\n//;s/.*/& [style=dashed];/p}
|
||||
/^ *AX_PKG_CHECK(\[\?\([^],)]\+\)\]\?, \[\?\([^],)]\+\)\]\?.*/ {s//"\2" -> /;G;s/\n//;s/.*/& [style=dotted];/p}
|
||||
/^ *AX_PKG_CHECK(\[\?\([^],)]\+\)\]\?.*/ {s//"\1" -> /;G;s/\n//;s/.*/& [style=dotted];/p}
|
||||
' $file
|
||||
done
|
||||
) | filter
|
||||
echo "}"
|
@@ -33,6 +33,7 @@
|
||||
#include <sstream>
|
||||
#include <cassert>
|
||||
#include <xml-cxx/xml.hxx>
|
||||
#include <mrw/stdext.hxx>
|
||||
|
||||
#ifdef HAVE_CXXABI_H
|
||||
#include <cxxabi.h>
|
||||
@@ -151,11 +152,8 @@ class Command: public QObject {
|
||||
virtual bool isTestcase() {
|
||||
return true;
|
||||
}
|
||||
static void realMouseClick(Logger& log, QWebFrame* frame, QString selector) {
|
||||
QWebElement element(find(frame, selector));
|
||||
if (element.isNull()) error(log, ElementNotFound(selector));
|
||||
realMouseClick(element);
|
||||
}
|
||||
static void realMouseClick(Logger& log, QWebFrame* frame,
|
||||
Script* script, QString selector);
|
||||
static void realMouseClick(const QWebElement& element) {
|
||||
QWidget* web(element.webFrame()->page()->view());
|
||||
QRect elGeom=element.geometry();
|
||||
@@ -248,8 +246,9 @@ class Command: public QObject {
|
||||
return element;
|
||||
}
|
||||
static QWebElement find1(QWebFrame* frame, QString selector,
|
||||
int repeat = 5, int sleepsec = 1) {
|
||||
int repeat = 2, int sleepsec = 1) {
|
||||
QWebElement element;
|
||||
if (repeat<1) repeat=1;
|
||||
for (int i=0; i<repeat; ++i) {
|
||||
element = frame->findFirstElement(selector);
|
||||
if (!element.isNull()) return element;
|
||||
@@ -257,7 +256,7 @@ class Command: public QObject {
|
||||
element = find1(childFrame, selector, 1, 0);
|
||||
if (!element.isNull()) return element;
|
||||
}
|
||||
if (sleepsec) sleep(sleepsec);
|
||||
if (i+1<repeat && sleepsec) sleep(sleepsec);
|
||||
}
|
||||
return element;
|
||||
}
|
||||
@@ -855,7 +854,8 @@ class Script: public QObject {
|
||||
void ignore(const Script& o) {
|
||||
_ignore = o._ignore;
|
||||
}
|
||||
bool ignore(const QString& sig) {
|
||||
bool ignores(const QString& sig = QString()) {
|
||||
if (sig.isEmpty()) return !_ignore.empty();
|
||||
return _ignore.contains(sig);
|
||||
}
|
||||
void ignore(QStringList sigs = QStringList()) {
|
||||
@@ -932,6 +932,9 @@ class Script: public QObject {
|
||||
void timeout(int t) {
|
||||
_timeout = t;
|
||||
}
|
||||
int timeout() {
|
||||
return _timeout;
|
||||
}
|
||||
void defaultTimeout(int t) {
|
||||
_defaultTimeout = t;
|
||||
}
|
||||
@@ -995,7 +998,7 @@ class Script: public QObject {
|
||||
SLOT(titleChanged(const QString&))));
|
||||
assert(connect(frame, SIGNAL(urlChanged(const QUrl&)),
|
||||
SLOT(urlChanged(const QUrl&))));
|
||||
assert(connect(&_timer, SIGNAL(timeout()), SLOT(timeout())));
|
||||
assert(connect(&_timer, SIGNAL(timeout()), SLOT(timedout())));
|
||||
}
|
||||
void removeSignals(QWebFrame* frame) {
|
||||
disconnect(dynamic_cast<NetworkAccessManager*>
|
||||
@@ -1023,7 +1026,7 @@ class Script: public QObject {
|
||||
this, SLOT(urlChanged(const QUrl&)));
|
||||
disconnect(frame, SIGNAL(urlChanged(const QUrl&)),
|
||||
this, SLOT(urlChanged(const QUrl&)));
|
||||
disconnect(&_timer, SIGNAL(timeout()), this, SLOT(timeout()));
|
||||
disconnect(&_timer, SIGNAL(timeout()), this, SLOT(timedout()));
|
||||
}
|
||||
public Q_SLOTS:
|
||||
void log(QString text, Command* command = 0) {
|
||||
@@ -1144,7 +1147,7 @@ class Script: public QObject {
|
||||
_signals.push(std::make_pair("urlChanged",
|
||||
QStringList(url.toString())));
|
||||
}
|
||||
void timeout() {
|
||||
void timedout() {
|
||||
error(TimeOut());
|
||||
}
|
||||
private:
|
||||
@@ -1222,7 +1225,7 @@ class Do: public Command {
|
||||
Logger log(this, script);
|
||||
QWebElement element(frame->documentElement());
|
||||
if (_selector.size()) {
|
||||
element = find(frame, script->replacevars(_selector));
|
||||
element = find(frame, script->replacevars(_selector), script->timeout()-1);
|
||||
if (element.isNull())
|
||||
error(log, ElementNotFound(script->replacevars(_selector)));
|
||||
}
|
||||
@@ -1305,7 +1308,7 @@ class Expect: public Command {
|
||||
Logger log(this, script);
|
||||
QStringList args(script->replacevars(_signal._args));
|
||||
if (_signal._signal=="load") { // special signal load
|
||||
while (!script->ignore("loadStarted") && script->checkSignal("loadStarted")) {
|
||||
while (!script->ignores("loadStarted") && script->checkSignal("loadStarted")) {
|
||||
log("ignore signal: loadStarted"); // ignore optional loadStarted
|
||||
}
|
||||
if (!script->checkSignal("urlChanged", args))
|
||||
@@ -1532,7 +1535,7 @@ class Upload: public Command {
|
||||
if (files.size()==1) filename=files[0];
|
||||
}
|
||||
page->setNextUploadFile(filename);
|
||||
realMouseClick(log, frame, script->replacevars(_selector));
|
||||
realMouseClick(log, frame, script, script->replacevars(_selector));
|
||||
if (page->uploadPrepared())
|
||||
error(log, SetFileUploadFailed(script->replacevars(_selector), filename));
|
||||
return true;
|
||||
@@ -1576,7 +1579,7 @@ class Exists: public Command {
|
||||
QString selector(script->replacevars(_selector));
|
||||
QString text(script->replacevars(_text));
|
||||
QStringList notfound;
|
||||
QWebElement firstelement(find(frame, selector));
|
||||
QWebElement firstelement(find(frame, selector, script->timeout()-1));
|
||||
Q_FOREACH(QWebElement element, frame->findAllElements(selector)) {
|
||||
if (text.isEmpty()) return true; // just find element
|
||||
if (element.toOuterXml().indexOf(text)!=-1) return true;
|
||||
@@ -1631,6 +1634,8 @@ class Not: public Command {
|
||||
Logger log(this, script);
|
||||
QString selector(script->replacevars(_selector));
|
||||
QString text(script->replacevars(_text));
|
||||
QWebElement firstelement(find(frame, selector,
|
||||
mrw::max(mrw::min(script->timeout()/3, 10), 2)));
|
||||
Q_FOREACH(QWebElement element, frame->findAllElements(selector)) {
|
||||
if (text.isEmpty())
|
||||
error(log, AssertionFailed("element must not exists: "+selector));
|
||||
@@ -1828,12 +1833,12 @@ class Click: public Command {
|
||||
QString clicktarget(script->replacevars(_selector));
|
||||
switch (_clicktype ? *_clicktype : script->clicktype()) {
|
||||
case Script::REAL_MOUSE_CLICK: {
|
||||
realMouseClick(log, frame, clicktarget);
|
||||
realMouseClick(log, frame, script, clicktarget);
|
||||
break;
|
||||
}
|
||||
case Script::JAVASCRIPT_CLICK:
|
||||
default: {
|
||||
QWebElement element(find(frame, clicktarget));
|
||||
QWebElement element(find(frame, clicktarget, script->timeout()-1));
|
||||
if (element.isNull())
|
||||
error(log, ElementNotFound(clicktarget));
|
||||
_result = element.evaluateJavaScript("this.click();").toString();
|
||||
@@ -2145,7 +2150,8 @@ class SetValue: public Command {
|
||||
}
|
||||
bool execute(Script* script, QWebFrame* frame) {
|
||||
Logger log(this, script);
|
||||
QWebElement element(find(frame, script->replacevars(_selector)));
|
||||
QWebElement element(find(frame, script->replacevars(_selector),
|
||||
script->timeout()-1));
|
||||
if (element.isNull())
|
||||
error(log, ElementNotFound(script->replacevars(_selector)));
|
||||
QString value(script->replacevars(_value));
|
||||
@@ -2334,6 +2340,8 @@ class If: public CommandContainer {
|
||||
QString selector(script->replacevars(_variable));
|
||||
bool check(false);
|
||||
if (_cmp=="->") {
|
||||
QWebElement firstelement(find(frame, selector,
|
||||
mrw::max(mrw::min(script->timeout()/3, 10), 2)));
|
||||
Q_FOREACH(QWebElement element, frame->findAllElements(selector)) {
|
||||
if (value.isEmpty() || // just find element
|
||||
element.toOuterXml().indexOf(value)!=-1 ||
|
||||
@@ -2439,6 +2447,8 @@ class While: public CommandContainer {
|
||||
for (bool check(true); check;) {
|
||||
if (_cmp=="->") {
|
||||
check = false;
|
||||
QWebElement firstelement(find(frame, selector,
|
||||
mrw::max(mrw::min(script->timeout()/3, 10), 2)));
|
||||
Q_FOREACH(QWebElement element, frame->findAllElements(selector)) {
|
||||
if (value.isEmpty() || // just find element
|
||||
element.toOuterXml().indexOf(value)!=-1 ||
|
||||
@@ -2899,6 +2909,8 @@ class Case: public Command {
|
||||
log("terminate with default branch");
|
||||
check = true;
|
||||
} else if (condition.cmp=="->") {
|
||||
QWebElement firstelement(find(frame, selector,
|
||||
mrw::max(mrw::min(script->timeout()/3, 10), 2)));
|
||||
Q_FOREACH(QWebElement element, frame->findAllElements(selector)) {
|
||||
if (value.isEmpty() || // just find element
|
||||
element.toOuterXml().indexOf(value)!=-1 ||
|
||||
@@ -3159,6 +3171,13 @@ inline Logger::~Logger() {
|
||||
}
|
||||
}
|
||||
|
||||
inline void Command::realMouseClick(Logger& log, QWebFrame* frame,
|
||||
Script* script, QString selector) {
|
||||
QWebElement element(find(frame, selector, script->timeout()-1));
|
||||
if (element.isNull()) error(log, ElementNotFound(selector));
|
||||
realMouseClick(element);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Script> Command::subParser(Script* parent, const QStringList& in,
|
||||
const QString& file,
|
||||
int line, int indent) {
|
||||
|
121
template.sh
Executable file
121
template.sh
Executable file
@@ -0,0 +1,121 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
# template for bash scripts
|
||||
|
||||
# internal use only
|
||||
append_msg() {
|
||||
if test $# -ne 0; then
|
||||
echo -en ":\e[0m \e[1m$*"
|
||||
fi
|
||||
echo -e "\e[0m"
|
||||
}
|
||||
|
||||
# write a notice
|
||||
notice() {
|
||||
if test $# -eq 0; then
|
||||
return
|
||||
fi
|
||||
echo -e "\e[1m$*\e[0m" 1>&3
|
||||
}
|
||||
|
||||
# write error message
|
||||
error() {
|
||||
echo -en "\e[1;31merror" 1>&2
|
||||
append_msg $* 1>&2
|
||||
}
|
||||
|
||||
# write a warning message
|
||||
warning() {
|
||||
echo -en "\e[1;33mwarning" 1>&2
|
||||
append_msg $* 1>&2
|
||||
}
|
||||
|
||||
# write a success message
|
||||
success() {
|
||||
echo -en "\e[1;32msuccess" 1>&2
|
||||
append_msg $* 1>&2
|
||||
}
|
||||
|
||||
# commandline parameter evaluation
|
||||
while test $# -gt 0; do
|
||||
case "$1" in
|
||||
(--help|-h) less <<EOF
|
||||
SYNOPSIS
|
||||
|
||||
$0 [OPTIONS]
|
||||
|
||||
OPTIONS
|
||||
|
||||
--help, -h show this help
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
EOF
|
||||
exit;;
|
||||
(*) error "unknow option $1, try $0 --help"; exit 1;;
|
||||
esac
|
||||
if test $# -eq 0; then
|
||||
error "missing parameter, try $0 --help"; exit 1
|
||||
fi
|
||||
shift;
|
||||
done
|
||||
|
||||
# run a command, print the result and abort in case of error
|
||||
# option: --no-check: ignore the result, continue in case of error
|
||||
run() {
|
||||
check=1
|
||||
while test $# -gt 0; do
|
||||
case "$1" in
|
||||
(--no-check) check=0;;
|
||||
(*) break;;
|
||||
esac
|
||||
shift;
|
||||
done
|
||||
echo -en "\e[1m-> running:\e[0m $* ..."
|
||||
result=$($* 2>&1)
|
||||
res=$?
|
||||
if test $res -ne 0; then
|
||||
if test $check -eq 1; then
|
||||
error "failed with return code: $res"
|
||||
if test -n "$result"; then
|
||||
echo "$result"
|
||||
fi
|
||||
exit 1
|
||||
else
|
||||
warning "ignored return code: $res"
|
||||
fi
|
||||
else
|
||||
success
|
||||
fi
|
||||
}
|
||||
|
||||
# error handler
|
||||
function traperror() {
|
||||
set +x
|
||||
local err=($1) # error status
|
||||
local line="$2" # LINENO
|
||||
local linecallfunc="$3"
|
||||
local command="$4"
|
||||
local funcstack="$5"
|
||||
for e in ${err[@]}; do
|
||||
if test -n "$e" -a "$e" != "0"; then
|
||||
error "line $line - command '$command' exited with status: $e (${err[@]})"
|
||||
if [ "${funcstack}" != "main" -o "$linecallfunc" != "0" ]; then
|
||||
echo -n " ... error at ${funcstack} "
|
||||
if [ "$linecallfunc" != "" ]; then
|
||||
echo -n "called at line $linecallfunc"
|
||||
fi
|
||||
echo
|
||||
fi
|
||||
exit $e
|
||||
fi
|
||||
done
|
||||
success
|
||||
exit 0
|
||||
}
|
||||
|
||||
# catch errors
|
||||
trap 'traperror "$? ${PIPESTATUS[@]}" $LINENO $BASH_LINENO "$BASH_COMMAND" "${FUNCNAME[@]}" "${FUNCTION}"' ERR SIGINT INT TERM EXIT
|
||||
|
||||
##########################################################################################
|
||||
|
Reference in New Issue
Block a user