tuchulcha  0.10.1
Graphical Workflow Configuration Editor
CommunicationHandler.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2011 Jens-Malte Gottfried
2 
3  This file is part of Tuchulcha.
4 
5  Tuchulcha is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  Tuchulcha is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public License
16  along with Tuchulcha. If not, see <http://www.gnu.org/licenses/>.
17 */
24 #include "CommunicationHandler.h"
25 
26 #include <QTextStream>
27 #include <QApplication>
28 #include <QFileInfo>
29 
31  const QStringList& args, QObject* pp) :
32  QThread(pp),
33  _interactive(true), _quiet(false),
34  _taskCount(0), _args(args), _errorCode(EXIT_SUCCESS)
35 {
36  _helpMsg = QString(
37  "Tuchulcha Workflow Executor version %1\n"
38  "This executable is part of Charon-Suite\n"
39  "Heidelberg Collaboratory for Image Processing,\n"
40  "University of Heidelberg, 2009-2013\n"
41  "http://sourceforge.net/projects/charon-suite/\n\n"
42  "PURPOSE\n"
43  "\tThis program will execute charon workflow files\n"
44  "SYNTAX\n"
45  "\ttuchlucha-run <options> command <workflow>\n"
46  "COMMANDS\n"
47  "\tsetup-settings, -s : setup default path settings if unset\n"
48  "\trun, -f : run the workflow file defined in <workflow>\n"
49  "\tupdate, -u : update the plugin cache\n"
50  "\tupdate-dynamics, -d : update dynamic plugin metadata\n"
51  "\thelp, --help, -? , -h : display this help text\n"
52  "OPTIONS\n"
53  "\t--non-interactive, -n : exit directly after processing of all "
54  "given commands.\n\t "
55  "Otherwise program will only exit after sending "
56  "\"quit\"\n\t "
57  "via stdin or on EOF (aka Ctrl+D)\n"
58  "\t--quiet, -q : suppress banner message at startup\n"
59  "NOTE\n\t"
60  "It is possible to combine the short options and commands\n\t"
61  "e.g. like \"tuchulcha-run -nqf <workflow>\", but please note \n\t"
62  "that the -d or -f argument have to be the last\n\t"
63  "before the file argument and that -d and -f cannot be used\n\t"
64  "together in one concatenation\n\t"
65  "(but e.g. \"tuchulcha-run -nq -d <wflow1> -f <wflow2>\" works)\n\n"
66  ).arg(TUCHULCHA_VERSION) ;
67 
68  _helpMsgI = QString(
69  "COMMANDS\n\t"
70  "help\n\t\tshow this help message\n\t"
71  "setup-settings\n\t\tsetup default path settings if unset\n\t"
72  "update\n\t\tupdate plugin information cache\n\t"
73  "update-dynamics <workflow>\n\t\tupdate plugin information cache\n\t"
74  "\tfor dynamic modules in workflow file\n\t"
75  "run <workflow>\n\t\trun the given workflow file\n\t"
76  "quit\n\t\tquit interactive mode and exit\n\t\t"
77  "(running commands will be finished before exit)"
78  );
79 
80  // increase task counter if sending task to task queue
81  connect(this,
82  SIGNAL(setupSettings()), SLOT(_startTask()),
83  Qt::DirectConnection);
84  connect(this,
85  SIGNAL(updatePlugins()), SLOT(_startTask()),
86  Qt::DirectConnection);
87  connect(this,
88  SIGNAL(updateDynamics(QString)), SLOT(_startTask()),
89  Qt::DirectConnection);
90  connect(this,
91  SIGNAL(runWorkflow(QString)), SLOT(_startTask()),
92  Qt::DirectConnection);
93 }
94 
96  QStringListIterator& iter, QString cmd) {
97  if(!iter.hasNext()) {
98  QTextStream qerr(stderr,QIODevice::WriteOnly);
99  qerr << tr("No workflow file provided for command \"%1\"").arg(cmd)
100  << endl;
101  _errorCode=EXIT_FAILURE;
102  return false;
103  }
104  if (!QFileInfo(iter.peekNext()).exists()) {
105  QTextStream qerr(stderr,QIODevice::WriteOnly);
106  qerr << tr("File provided for command \"%1\" does not exist: %2")
107  .arg(cmd).arg(iter.peekNext())
108  << endl;
109  _errorCode=EXIT_FAILURE;
110  return false;
111  }
112  return true;
113 }
114 
116  return _errorCode;
117 }
118 
120  // commandline argument parsing
121  QStringListIterator argIter(_args);
122  QRegExp runShortRgx("-[qnus]*(?:f|d)?");
123  argIter.next(); // skip first item (command name)
124  while (argIter.hasNext()) {
125  QString s = argIter.next();
126  if(s == "help" || s == "--help" || s == "-h" || s == "-?" || s == "/?") {
127  QTextStream qout(stdout,QIODevice::WriteOnly);
128  qout << _helpMsg << endl;
129  return ;
130  }
131  else if(s == "--non-interactive" || s == "-n") {
132  _interactive = false;
133  }
134  else if (s == "--quiet" || s == "-q") {
135  _quiet = true;
136  }
137  else if (s == "setup-settings") {
138  emit setupSettings();
139  }
140  else if (s == "update" || s == "-u") {
141  emit updatePlugins();
142  }
143  else if (s == "run" || s == "-f") {
144  if (!_checkForFileArg(argIter, s)) return;
145  emit runWorkflow(argIter.next());
146  }
147  else if (s == "update-dynamics" || s == "-d") {
148  if (!_checkForFileArg(argIter, s)) return;
149  emit updateDynamics(argIter.next());
150  }
151  // concatenated form of -q -n -s -u -f -d, f/d must be last !
152  else if (runShortRgx.exactMatch(s)) {
153  if (s.contains("q")) {
154  _quiet = true;
155  }
156  if (s.contains("n")) {
157  _interactive = false;
158  }
159  if (s.contains("s")) {
160  emit setupSettings();
161  }
162  if (s.contains("u")) {
163  emit updatePlugins();
164  }
165  if (s.contains("f")) {
166  if (!_checkForFileArg(argIter, s)) return;
167  emit runWorkflow(argIter.next());
168  }
169  else if (s.contains("d")) {
170  if (!_checkForFileArg(argIter, s)) return;
171  emit updateDynamics(argIter.next());
172  }
173  }
174  else {
175  QTextStream qerr(stderr,QIODevice::WriteOnly);
176  qerr << tr("Argument \"%1\" not recognized.").arg(s) << endl;
177  QThread::exit(-1);
178  return ;
179  }
180  }
181 
182  // check interactive loop
183  if (!_interactive) {
184  return;
185  }
186 
187  if (!_quiet) {
188  QTextStream qout(stdout,QIODevice::WriteOnly);
189  qout << tr("Tuchulcha Workflow Executor version %1")
190  .arg(TUCHULCHA_VERSION) << "\n"
191  << tr("Type \"quit\" to exit this application.") << "\n"
192  << tr("Type \"help\" for command summary.") << endl;
193  }
194 
195  // interactive command handling
196  QTextStream qin(stdin,QIODevice::ReadOnly);
197  QTextStream qout(stdout, QIODevice::WriteOnly);
198  QString line;
199  QRegExp runRgx("run\\s+(\\S.*)");
200  QRegExp updRgx("update-dynamics\\s+(\\S.*)");
201  do {
202  _printPrompt();
203  line = qin.readLine();
204  if(line == "quit") {
205  break;
206  }
207  else if (line == "help") {
208  qout << _helpMsgI << endl;
209  }
210  else if (line == "setup-settings") {
211  emit setupSettings();
212  }
213  else if (line == "update") {
214  emit updatePlugins();
215  }
216  else if (runRgx.exactMatch(line)) {
217  emit runWorkflow(runRgx.cap(1));
218  }
219  else if (updRgx.exactMatch(line)) {
220  emit updateDynamics(updRgx.cap(1));
221  }
222  else if (!line.isEmpty()) {
223  QTextStream qerr(stderr,QIODevice::WriteOnly);
224  qerr << tr("Command \"%1\" not recognized.").arg(line) << endl;
225  }
226  } while (!line.isNull());
227  if (line.isNull()) {
228  qout << endl; // newline e.g. if terminated by CTRL-D, i.e. EOF
229  }
230  if (!_quiet) {
231  qout << tr("bye") << endl;
232  }
233 }
234 
236  _taskCount++;
237 }
238 
240  if (_taskCount == 0) {
241  qDebug("%s", "Trying to decrease zero task counter");
242  }
243  else {
244  _taskCount--;
245  }
246  _printPrompt();
247 }
248 
250  if (_taskCount > 0 || _quiet || !_interactive) {
251  return;
252  }
253  QTextStream qout(stdout, QIODevice::WriteOnly);
254  qout << "TC-Run > " << flush; // input prompt (hidden if quiet)
255 }
QString _helpMsg
message to display when –help argument was provided
Declaration of class CommunicationHandler.
int errorCode() const
get CommunicatonHandler return code, zero means no error
CommunicationHandler(const QStringList &args, QObject *parent=0)
constructor with cmdline arguments
uint _taskCount
task counter
bool charon_core_DLL_PUBLIC exists(const std::string &file)
QStringList _args
cmd line argument cache
virtual void run()
thread execution code
void updateDynamics(QString fName)
update dynamic plugins of given workflow file
void _printPrompt()
print command line prompt for interactive session
bool _quiet
avoid info output
void setupSettings()
setup settings
QString _helpMsgI
help message for interactive session
int _errorCode
error code cache, zero means no error
bool _checkForFileArg(QStringListIterator &iter, QString cmd)
check for file argument during command line processing
void runWorkflow(QString fName)
run given workflow file
bool _interactive
enter interactive loop
void _startTask()
handle task starting
void taskFinished()
handle task finishing
void updatePlugins()
update module metadata