1 /**
2 * UGENE - Integrated Bioinformatics Tools.
3 * Copyright (C) 2008-2021 UniPro <ugene@unipro.ru>
4 * http://ugene.net
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
22 #include "GalaxyConfigTask.h"
23
24 #include <QApplication>
25
26 #include <U2Core/AppContext.h>
27 #include <U2Core/CMDLineRegistry.h>
28 #include <U2Core/CMDLineUtils.h>
29 #include <U2Core/DocumentImport.h>
30 #include <U2Core/DocumentModel.h>
31 #include <U2Core/U2SafePoints.h>
32
33 #include <U2Designer/DelegateEditors.h>
34
35 #include <U2Lang/BaseAttributes.h>
36 #include <U2Lang/BasePorts.h>
37 #include <U2Lang/BaseTypes.h>
38 #include <U2Lang/HRSchemaSerializer.h>
39 #include <U2Lang/WorkflowEnv.h>
40
41 namespace U2 {
42 using namespace WorkflowSerialize;
43
44 /*******************************************
45 * GalaxyConfigTask
46 *******************************************/
47
48 #define TOOL "tool"
49 #define NAME "name"
50 #define VALUE "value"
51 #define LABEL "label"
52 #define ID "id"
53 #define COMMAND "command"
54 #define INPUT "input"
55 #define INPUTS "inputs"
56 #define OUTPUTS "outputs"
57 #define PARAM "param"
58 #define FORMAT "format"
59 #define OPTION "option"
60 #define OPTIONS "options"
61 #define SELECTED "selected"
62 #define MAX "max"
63 #define MIN "min"
64 #define DISPLAY "display"
65 #define HIERARCHY "hierarchy"
66 #define MULTIPLE "multiple"
67 #define SEPARATOR "separator"
68 #define DATA "data"
69 #define CHANGE_FORMAT "change-format"
70 #define WHEN "when"
71 #define HELP "help"
72 #define WORKFLOW_RUN_LOG "ugene_workflow_run_log"
73 #define STDERR_TO_STDOUT "2>&1"
74 #define SUBSTRING_NOT_FOUND -1
75
76 const QString GalaxyConfigTask::GALAXY_CONFIG_OPTION = "galaxy-config";
77 const QString GalaxyConfigTask::UGENE_PATH_OPTION = "ugene-path";
78 const QString GalaxyConfigTask::GALAXY_PATH_OPTION = "galaxy-path";
79
GalaxyConfigTask(const QString & _schemePath,const QString & _ugenePath,const QString & _galaxyPath,const QString & _destinationPath)80 GalaxyConfigTask::GalaxyConfigTask(const QString &_schemePath, const QString &_ugenePath, const QString &_galaxyPath, const QString &_destinationPath)
81 : Task(tr("Create Galaxy config from existing workflow"), TaskFlag_None), schemePath(_schemePath), ugenePath(_ugenePath),
82 galaxyPath(_galaxyPath), destinationPath(_destinationPath) {
83 }
84
~GalaxyConfigTask()85 GalaxyConfigTask::~GalaxyConfigTask() {
86 }
87
tryToAppendSlash(QString & path)88 void tryToAppendSlash(QString &path) {
89 if (!path.endsWith("/") && !path.endsWith("\\") && path.length() > 0) {
90 path.append("/");
91 }
92 }
93
fillGObjectTypeMap()94 void GalaxyConfigTask::fillGObjectTypeMap() {
95 portGObjectTypeMap[BasePorts::OUT_MSA_PORT_ID()] = GObjectTypes::MULTIPLE_SEQUENCE_ALIGNMENT;
96 portGObjectTypeMap[BasePorts::IN_MSA_PORT_ID()] = GObjectTypes::MULTIPLE_SEQUENCE_ALIGNMENT;
97 portGObjectTypeMap[BasePorts::OUT_SEQ_PORT_ID()] = GObjectTypes::SEQUENCE;
98 portGObjectTypeMap[BasePorts::IN_SEQ_PORT_ID()] = GObjectTypes::SEQUENCE;
99 portGObjectTypeMap[BasePorts::OUT_ANNOTATIONS_PORT_ID()] = GObjectTypes::ANNOTATION_TABLE;
100 portGObjectTypeMap[BasePorts::IN_ANNOTATIONS_PORT_ID()] = GObjectTypes::ANNOTATION_TABLE;
101 portGObjectTypeMap[BasePorts::OUT_TEXT_PORT_ID()] = GObjectTypes::TEXT;
102 portGObjectTypeMap[BasePorts::IN_TEXT_PORT_ID()] = GObjectTypes::TEXT;
103 portGObjectTypeMap[BasePorts::OUT_VARIATION_TRACK_PORT_ID()] = GObjectTypes::VARIANT_TRACK;
104 portGObjectTypeMap[BasePorts::IN_VARIATION_TRACK_PORT_ID()] = GObjectTypes::VARIANT_TRACK;
105 portGObjectTypeMap[BasePorts::OUT_ASSEMBLY_PORT_ID()] = GObjectTypes::ASSEMBLY;
106 portGObjectTypeMap[BasePorts::IN_ASSEMBLY_PORT_ID()] = GObjectTypes::ASSEMBLY;
107 portGObjectTypeMap["in-url"] = GObjectTypes::TEXT;
108 portGObjectTypeMap["out-url"] = GObjectTypes::TEXT;
109 portGObjectTypeMap["unknown"] = GObjectTypes::UNKNOWN;
110 }
111
prepare()112 void GalaxyConfigTask::prepare() {
113 schemeName.clear();
114 schemeContent.clear();
115 galaxyToolName.clear();
116 galaxyHelpMessage.clear();
117 schemeConfigName.clear();
118 schemeConfigPath.clear();
119
120 elemAliases.clear();
121 inputElementsPositions.clear();
122 outputElementsPositions.clear();
123 optionElementsPositions.clear();
124
125 appDirPath = QApplication::applicationDirPath();
126
127 tryToAppendSlash(appDirPath);
128 tryToAppendSlash(ugenePath);
129 tryToAppendSlash(galaxyPath);
130 tryToAppendSlash(destinationPath);
131
132 if (galaxyPath.isEmpty() && !getGalaxyPath()) {
133 coreLog.info("Galaxy folder is not found");
134 }
135
136 fillGObjectTypeMap();
137 }
138
run()139 void GalaxyConfigTask::run() {
140 CHECK(getSchemeName(), );
141 CHECK(getSchemeContent(), );
142 CHECK(getHelpMessage(), );
143 CHECK(getWorkflowName(), );
144 CHECK(defineAliases(), );
145 CHECK(createConfigForGalaxy(), );
146 if (tryToCopySchemeConfigFile()) {
147 addToolToGalaxy();
148 }
149 }
150
tryToFindInPath(const QString & objectName,QString & objectPath)151 void GalaxyConfigTask::tryToFindInPath(const QString &objectName, QString &objectPath) {
152 QString envVariable = qgetenv("GALAXY_DIR");
153 if (envVariable.isEmpty()) {
154 coreLog.info(QString("Environment variable GALAXY_DIR is not found"));
155 }
156
157 QString pathVariable = qgetenv("PATH").constData();
158 const int objectNamePosition = pathVariable.indexOf(objectName);
159 if (objectNamePosition == SUBSTRING_NOT_FOUND) {
160 coreLog.info(QString("Path to %1 folder is not found in PATH variable").arg(objectName));
161 return;
162 }
163 int currPos = objectNamePosition;
164 for (; currPos >= 0; currPos--) {
165 if (QString(pathVariable[currPos]) == Constants::COLON) {
166 break;
167 }
168 }
169 const int pathStartPosition = currPos + 1,
170 pathEndPosition = pathVariable.indexOf(Constants::COLON, objectNamePosition),
171 pathLength = pathEndPosition - pathStartPosition;
172 objectPath = pathVariable.mid(pathStartPosition, pathLength);
173
174 tryToAppendSlash(objectPath);
175 }
176
tryToFindByLocate(const QString & objectName,QString & objectPath)177 void GalaxyConfigTask::tryToFindByLocate(const QString &objectName, QString &objectPath) {
178 if (!objectPath.isEmpty()) {
179 return;
180 }
181 QString fileName = objectName + "_path.txt";
182 QString locateCommand = QString("locate %1 -l 1 > %2").arg(objectName).arg(fileName);
183 int rc = system(locateCommand.toLocal8Bit().constData());
184 if (rc == -1) { // From docs: The value returned is -1 on error, and the return status of the command otherwise.
185 coreLog.info(QString("Locate command returned -1: %1").arg(locateCommand));
186 return;
187 }
188
189 QFile file(fileName);
190 if (!file.open(QIODevice::ReadOnly)) {
191 coreLog.info(QString("Can not read %1_path.txt file to get path to %1 folder. Check user privileges").arg(objectName));
192 return;
193 }
194 QTextStream inFile(&file);
195 inFile >> objectPath;
196 file.close();
197
198 QFile::remove(fileName);
199 if (!objectPath.length()) {
200 coreLog.info(QString("Path to %1 folder is not found by \"locate\" command").arg(objectName));
201 return;
202 }
203
204 tryToAppendSlash(objectPath);
205 }
206
fileExists(const QString & objectPath,const QString & suffix)207 bool GalaxyConfigTask::fileExists(const QString &objectPath, const QString &suffix) {
208 if (!objectPath.isEmpty()) {
209 const QString fullPath = objectPath + suffix;
210 if (QFile::exists(fullPath)) {
211 return true;
212 }
213 coreLog.info(QString("Galaxy folder does not contain %1 file").arg(suffix));
214 }
215 return false;
216 }
217
findPathToObject(const QString & objectName,QString & objectPath)218 bool GalaxyConfigTask::findPathToObject(const QString &objectName, QString &objectPath) {
219 const QString suffix = "tool_conf.xml";
220 tryToFindInPath(objectName, objectPath);
221
222 #ifdef __linux__
223 tryToFindByLocate(objectName, objectPath);
224 #endif
225 return fileExists(objectPath, suffix);
226 }
227
getGalaxyPath()228 bool GalaxyConfigTask::getGalaxyPath() {
229 if (galaxyPath.isEmpty()) {
230 return findPathToObject("galaxy", galaxyPath);
231 }
232 return true;
233 }
234
getSchemeName()235 bool GalaxyConfigTask::getSchemeName() {
236 if (!schemePath.length() || !QFile::exists(schemePath)) {
237 stateInfo.setError("Workflow file is incorrect. Check it exists");
238 return false;
239 }
240 schemeName = schemePath.split("/").last();
241 return true;
242 }
243
getSchemeContent()244 bool GalaxyConfigTask::getSchemeContent() {
245 QFile schemeFile(schemePath);
246 QFileInfo schemeFileInfo(schemePath);
247 if (!schemeFileInfo.isReadable()) {
248 stateInfo.setError(QString("Workflow file %1 is not readable by this user").arg(schemePath));
249 return false;
250 }
251 if (!schemeFile.open(QIODevice::ReadOnly)) {
252 stateInfo.setError(QString("Can not open %1 file. Check user privileges ").arg(schemePath));
253 return false;
254 }
255 QTextStream input(&schemeFile);
256 schemeContent = input.readAll();
257 schemeFile.close();
258 return true;
259 }
260
setError(const QString & keyword)261 void GalaxyConfigTask::setError(const QString &keyword) {
262 stateInfo.setError(QString("Workflow file is corrupted. It does not contain %1 keyword").arg(keyword));
263 }
264
getHelpMessage()265 bool GalaxyConfigTask::getHelpMessage() {
266 galaxyHelpMessage = "\n**Description**\n";
267 int commentStartPosition = schemeContent.indexOf(Constants::HEADER_LINE);
268 if (commentStartPosition == SUBSTRING_NOT_FOUND) {
269 setError(Constants::HEADER_LINE);
270 return false;
271 }
272 commentStartPosition += Constants::HEADER_LINE.length();
273 const int commentEndPosition = schemeContent.lastIndexOf(Constants::BODY_START);
274 if (commentEndPosition == SUBSTRING_NOT_FOUND) {
275 setError(Constants::BODY_START);
276 return false;
277 }
278 const int commentLength = commentEndPosition - commentStartPosition;
279
280 QString comment;
281 comment = schemeContent.mid(commentStartPosition, commentLength);
282 comment.replace(Constants::SERVICE_SYM, "\n");
283 galaxyHelpMessage += comment;
284 return true;
285 }
286
getWorkflowName()287 bool GalaxyConfigTask::getWorkflowName() {
288 int nameStartPosition = schemeContent.lastIndexOf(Constants::BODY_START);
289 nameStartPosition += Constants::BODY_START.length() + 1;
290 const int nameEndPosition = schemeContent.indexOf(Constants::BLOCK_START, nameStartPosition);
291 CHECK_OPERATIONS(nameEndPosition != SUBSTRING_NOT_FOUND,
292 stateInfo.setError("Workflow file is corrupted. It does not contain start of body block"),
293 return false;);
294 const int nameLength = nameEndPosition - nameStartPosition;
295
296 galaxyToolName = schemeContent.mid(nameStartPosition, nameLength);
297 galaxyToolName.replace(QRegExp("^\""), "");
298 galaxyToolName.replace(QRegExp("\"$"), "");
299 return true;
300 }
301
getParameterValue(const QString & keyword,const int searchFrom,QString & parameterValue,int & nextSearchFrom)302 bool GalaxyConfigTask::getParameterValue(const QString &keyword, const int searchFrom, QString ¶meterValue, int &nextSearchFrom) {
303 const int keywordPosition = schemeContent.indexOf(keyword, searchFrom);
304 const int blockEndPosition = schemeContent.indexOf(Constants::BLOCK_END, searchFrom);
305 if (keyword == Constants::DESCRIPTION && (keywordPosition == -1 || blockEndPosition < keywordPosition)) {
306 nextSearchFrom = searchFrom;
307 return true;
308 }
309
310 const int parameterStartPosition = schemeContent.indexOf(Constants::COLON, keywordPosition) + 1,
311 parameterEndPosition = schemeContent.indexOf(Constants::SEMICOLON, parameterStartPosition);
312 CHECK_OPERATIONS(parameterStartPosition != SUBSTRING_NOT_FOUND,
313 stateInfo.setError("Workflow file is corrupted. Begin of alias value is not found"),
314 return false;);
315 CHECK_OPERATIONS(parameterEndPosition != SUBSTRING_NOT_FOUND,
316 stateInfo.setError("Worklow file is corrupted. End of alias value is not found"),
317 return false;);
318 const int parameterLength = parameterEndPosition - parameterStartPosition;
319 parameterValue = schemeContent.mid(parameterStartPosition, parameterLength);
320
321 nextSearchFrom = parameterEndPosition;
322 return true;
323 }
324
defineAliases()325 bool GalaxyConfigTask::defineAliases() {
326 int aliasesStartPosition = schemeContent.indexOf(Constants::PARAM_ALIASES_START);
327 CHECK_OPERATIONS(aliasesStartPosition != SUBSTRING_NOT_FOUND,
328 setError(Constants::PARAM_ALIASES_START),
329 return false;);
330 aliasesStartPosition += Constants::PARAM_ALIASES_START.length();
331 const int visualKeywordPosition = schemeContent.indexOf(Constants::VISUAL_START, aliasesStartPosition);
332 CHECK_OPERATIONS(visualKeywordPosition != SUBSTRING_NOT_FOUND,
333 setError(Constants::VISUAL_START),
334 return false;);
335
336 int elementNameStartPosition = schemeContent.indexOf(QRegExp("[a-z]"), aliasesStartPosition);
337 while (elementNameStartPosition < visualKeywordPosition) {
338 const int elementNameEndPosition = schemeContent.indexOf(Constants::DOT, elementNameStartPosition);
339 CHECK_OPERATIONS(elementNameEndPosition != SUBSTRING_NOT_FOUND,
340 stateInfo.setError("Workflow file contains wrong alias"),
341 return false;);
342 const int elementNameLength = elementNameEndPosition - elementNameStartPosition;
343 QString elementName = schemeContent.mid(elementNameStartPosition, elementNameLength);
344 elementName.replace(QRegExp("[0-9]$"), "");
345
346 const int elementAliasStartPosition = elementNameEndPosition + 1,
347 elementAliasEndPosition = schemeContent.indexOf(Constants::BLOCK_START, elementAliasStartPosition);
348 const int elementAliasLength = elementAliasEndPosition - elementAliasStartPosition;
349 QString elementAlias = schemeContent.mid(elementAliasStartPosition, elementAliasLength);
350 elementAlias.replace(" ", "");
351
352 QString aliasName = QString(),
353 aliasDescription = QString();
354 int aliasNameEndPosition = -1,
355 aliasDescriptionEndPosition = -1;
356
357 if (!getParameterValue(Constants::ALIAS, elementAliasEndPosition, aliasName, aliasNameEndPosition)) {
358 return false;
359 }
360 if (!getParameterValue(Constants::DESCRIPTION, aliasNameEndPosition, aliasDescription, aliasDescriptionEndPosition)) {
361 return false;
362 }
363
364 QMap<QString, QStringList> elementProperties;
365 QStringList elementAliasParameters;
366 elementAliasParameters << elementAlias << aliasName << aliasDescription;
367 elementProperties[elementName] = elementAliasParameters;
368 elemAliases.push_back(elementProperties);
369
370 elementNameStartPosition = schemeContent.indexOf(QRegExp("[a-z]"), aliasDescriptionEndPosition);
371 }
372 return true;
373 }
374
writeToolUnit()375 void GalaxyConfigTask::writeToolUnit() {
376 galaxyConfigOutput.writeStartElement(TOOL); // tool unit begin
377 galaxyConfigOutput.writeAttribute(ID, galaxyToolName + "_tool");
378 QString toolName = galaxyToolName;
379 toolName.replace(" ", "_");
380 galaxyConfigOutput.writeAttribute(NAME, toolName);
381 }
382
getElementFromActorPrototypeRegistry(const QString & elementName)383 ActorPrototype *GalaxyConfigTask::getElementFromActorPrototypeRegistry(const QString &elementName) {
384 U2::Workflow::ActorPrototypeRegistry *prototypeRegistry =
385 U2::Workflow::WorkflowEnv::getProtoRegistry();
386 assert(nullptr != prototypeRegistry);
387 return prototypeRegistry->getProto(elementName);
388 }
389
fillPositionsList(const QString & elementAttribute,const int elementPosition)390 void GalaxyConfigTask::fillPositionsList(const QString &elementAttribute, const int elementPosition) {
391 if (BaseAttributes::URL_IN_ATTRIBUTE().getId() == elementAttribute) {
392 inputElementsPositions.push_back(elementPosition);
393 } else if (BaseAttributes::URL_OUT_ATTRIBUTE().getId() == elementAttribute) {
394 outputElementsPositions.push_back(elementPosition);
395 } else {
396 optionElementsPositions.push_back(elementPosition);
397 }
398 }
399
divideElementsByType()400 bool GalaxyConfigTask::divideElementsByType() {
401 QList<QMap<QString, QStringList>>::iterator elemAliasesIterator;
402 elemAliasesIterator = elemAliases.begin();
403 while (elemAliasesIterator != elemAliases.end()) {
404 const QMap<QString, QStringList>::iterator elementProperties = (*elemAliasesIterator).begin();
405 const QString elementName = elementProperties.key();
406 const QString attributeName = elementProperties.value().at(0);
407
408 ActorPrototype *currElement = getElementFromActorPrototypeRegistry(elementName);
409 assert(nullptr != currElement);
410
411 const QList<Attribute *> elementAttributes = currElement->getAttributes();
412 if (elementAttributes.isEmpty()) {
413 stateInfo.setError(QString("Config generation error: can not get attributes from \"%1\" element").arg(currElement->getId()));
414 return false;
415 }
416
417 foreach (Attribute *elementAttribute, elementAttributes) {
418 if (elementAttribute->getId() == attributeName) {
419 fillPositionsList(attributeName, std::distance(elemAliases.begin(), elemAliasesIterator));
420 }
421 }
422 elemAliasesIterator++;
423 }
424 return true;
425 }
426
writeRunUgeneCommand(const QString & ugeneExecutable)427 void GalaxyConfigTask::writeRunUgeneCommand(const QString &ugeneExecutable) {
428 if (ugenePath.isEmpty()) {
429 ugenePath = appDirPath;
430 }
431 QString runUgene = ugenePath + ugeneExecutable + " --task=" + schemePath + " ";
432 QList<QMap<QString, QStringList>>::iterator elemAliasesIterator;
433 elemAliasesIterator = elemAliases.begin();
434 while (elemAliasesIterator != elemAliases.end()) {
435 QMap<QString, QStringList>::iterator elementParameters = (*elemAliasesIterator).begin();
436 const QString aliasName = elementParameters.value().at(1);
437 runUgene += "--" + aliasName + "=$" + aliasName + " ";
438 elemAliasesIterator++;
439 }
440 runUgene += QString(" >> $") + WORKFLOW_RUN_LOG + " " + STDERR_TO_STDOUT;
441 galaxyConfigOutput.writeCharacters(runUgene);
442 }
443
writeOutputFilesChecks()444 void GalaxyConfigTask::writeOutputFilesChecks() {
445 QList<int>::iterator outputElementsPositionsIterator;
446 outputElementsPositionsIterator = outputElementsPositions.begin();
447 while (outputElementsPositionsIterator != outputElementsPositions.end()) {
448 QMap<QString, QStringList>::iterator elementParameters = elemAliases[*outputElementsPositionsIterator].begin();
449 const QString aliasName = elementParameters.value().at(1);
450 galaxyConfigOutput.writeDTD(QString("\nif [ ! -s $" + aliasName + " ]; then"));
451 galaxyConfigOutput.writeDTD(QString("\necho \"EMPTY RESULT FILE\" > $" + aliasName + ";"));
452 galaxyConfigOutput.writeDTD(QString("\nfi;\n"));
453 outputElementsPositionsIterator++;
454 }
455 }
456
writeCommandUnit()457 bool GalaxyConfigTask::writeCommandUnit() {
458 galaxyConfigOutput.writeStartElement(COMMAND); // command unit begin
459 CHECK(divideElementsByType(), false);
460
461 QString ugeneExecutable;
462 #ifdef QT_DEBUG
463 ugeneExecutable = "ugened";
464 #else
465 ugeneExecutable = "ugene";
466 #endif
467 writeRunUgeneCommand(ugeneExecutable);
468 writeOutputFilesChecks();
469
470 galaxyConfigOutput.writeEndElement(); // command unit end
471 return true;
472 }
473
getConstraint(const QString & typeName,QString & resultType)474 void GalaxyConfigTask::getConstraint(const QString &typeName, QString &resultType) {
475 resultType = portGObjectTypeMap[typeName];
476 if (resultType.isEmpty()) {
477 resultType = portGObjectTypeMap["unknown"];
478 }
479 }
480
getResultType(const ActorPrototype & currElement,QString & resultType)481 bool GalaxyConfigTask::getResultType(const ActorPrototype &currElement, QString &resultType) {
482 PortDescriptor *port = currElement.getPortDesciptors().first();
483 assert(nullptr != port);
484
485 const QString formatType = port->getId();
486 getConstraint(formatType, resultType);
487 if (resultType == GObjectTypes::UNKNOWN) {
488 stateInfo.setError(QString("Config generation error: element \"%1\" has unknown type").arg(currElement.getId()));
489 return false;
490 }
491 return true;
492 }
493
writeFormatAttribute(const QString & resultType)494 void GalaxyConfigTask::writeFormatAttribute(const QString &resultType) {
495 DocumentFormatRegistry *docFormatRegistry = AppContext::getDocumentFormatRegistry();
496 assert(nullptr != docFormatRegistry);
497
498 DocumentFormatConstraints constraint;
499 constraint.supportedObjectTypes.insert(resultType);
500 constraint.addFlagToExclude(DocumentFormatFlag_CannotBeCreated);
501 QList<QString> selectedFormats = docFormatRegistry->selectFormats(constraint);
502
503 QString resultFormatString = QString();
504 QList<QString>::iterator selectedFormatsIterator;
505 selectedFormatsIterator = selectedFormats.begin();
506 while (selectedFormatsIterator != selectedFormats.end() - 1) {
507 resultFormatString += *selectedFormatsIterator;
508 resultFormatString += Constants::COMMA;
509 selectedFormatsIterator++;
510 }
511 resultFormatString += (*selectedFormatsIterator);
512 galaxyConfigOutput.writeAttribute(FORMAT, resultFormatString);
513 }
514
writeLabelAttribute(const QStringList & elementParameters,const ActorPrototype & element)515 void GalaxyConfigTask::writeLabelAttribute(const QStringList &elementParameters, const ActorPrototype &element) {
516 const QString attributeName = elementParameters.at(0);
517 QString aliasDescription = elementParameters.at(2);
518 QString copyStr = aliasDescription;
519 if (aliasDescription.length() == 0 || (!copyStr.contains("[a-zA-Z0-9]"))) {
520 aliasDescription.clear();
521 aliasDescription += element.getDisplayName();
522 aliasDescription += ".";
523 aliasDescription += element.getAttribute(attributeName)->getDocumentation();
524 }
525 aliasDescription = aliasDescription.trimmed();
526 if (aliasDescription.startsWith(Constants::QUOTE)) {
527 aliasDescription.remove(0, 1);
528 }
529 if (aliasDescription.endsWith(Constants::QUOTE)) {
530 aliasDescription.remove(aliasDescription.length() - 1, 1);
531 }
532 galaxyConfigOutput.writeAttribute(LABEL, aliasDescription);
533 }
534
writeInputElements()535 bool GalaxyConfigTask::writeInputElements() {
536 QList<int>::iterator inputElementsIterator;
537 inputElementsIterator = inputElementsPositions.begin();
538 while (inputElementsIterator != inputElementsPositions.end()) {
539 galaxyConfigOutput.writeStartElement(PARAM);
540 const QMap<QString, QStringList> currAlias = elemAliases[*inputElementsIterator];
541 QMap<QString, QStringList>::const_iterator currAliasIterator = currAlias.begin();
542 const QString elementName = (currAliasIterator).key(),
543 aliasName = (currAliasIterator).value().at(1);
544
545 galaxyConfigOutput.writeAttribute(Constants::NAME_ATTR, aliasName);
546 galaxyConfigOutput.writeAttribute(Constants::TYPE_ATTR, DATA);
547
548 ActorPrototype *currElement = getElementFromActorPrototypeRegistry(elementName);
549 assert(nullptr != currElement);
550
551 QString resultType = QString();
552 CHECK(getResultType(*currElement, resultType), false);
553
554 writeFormatAttribute(resultType);
555 writeLabelAttribute((currAliasIterator).value(), *currElement);
556 galaxyConfigOutput.writeEndElement();
557 inputElementsIterator++;
558 }
559 return true;
560 }
561
isDelegateComboBox(PropertyDelegate * pd)562 bool GalaxyConfigTask::isDelegateComboBox(PropertyDelegate *pd) {
563 ComboBoxDelegate *cbd = dynamic_cast<ComboBoxDelegate *>(pd);
564 if (cbd != nullptr) {
565 return true;
566 }
567 return false;
568 }
569
isDelegateComboBoxWithChecks(PropertyDelegate * pd)570 bool GalaxyConfigTask::isDelegateComboBoxWithChecks(PropertyDelegate *pd) {
571 ComboBoxWithChecksDelegate *cbwcd = dynamic_cast<ComboBoxWithChecksDelegate *>(pd);
572 if (cbwcd != nullptr) {
573 return true;
574 }
575 return false;
576 }
577
isDelegateSpinBox(PropertyDelegate * pd)578 bool GalaxyConfigTask::isDelegateSpinBox(PropertyDelegate *pd) {
579 SpinBoxDelegate *sbd = dynamic_cast<SpinBoxDelegate *>(pd);
580 if (sbd != nullptr) {
581 return true;
582 }
583 DoubleSpinBoxDelegate *dsbd = dynamic_cast<DoubleSpinBoxDelegate *>(pd);
584 if (dsbd != nullptr) {
585 return true;
586 }
587 return false;
588 }
589
isDelegateStringList(PropertyDelegate * pd)590 bool GalaxyConfigTask::isDelegateStringList(PropertyDelegate *pd) {
591 StringListDelegate *sld = dynamic_cast<StringListDelegate *>(pd);
592 if (sld != nullptr) {
593 return true;
594 }
595 return false;
596 }
597
tryToWriteSimpleType(const PropertyDelegate * pd,QString & attributeType)598 bool GalaxyConfigTask::tryToWriteSimpleType(const PropertyDelegate *pd, QString &attributeType) {
599 if (pd != nullptr) {
600 return false;
601 }
602 if (attributeType == BaseTypes::BOOL_TYPE()->getId()) {
603 attributeType = "boolean";
604 } else if (attributeType == BaseTypes::STRING_TYPE()->getId()) {
605 attributeType = "text";
606 } else if (attributeType == BaseTypes::NUM_TYPE()->getId()) {
607 attributeType = "integer";
608 } else {
609 return false;
610 }
611 galaxyConfigOutput.writeAttribute(Constants::TYPE_ATTR, attributeType);
612 return true;
613 }
614
writeSelectAttribute(const PropertyDelegate & pd)615 void GalaxyConfigTask::writeSelectAttribute(const PropertyDelegate &pd) {
616 QVariantMap items;
617 pd.getItems(items);
618 QVariantMap ::iterator itemsIterator;
619 itemsIterator = items.begin();
620 while (itemsIterator != items.end()) {
621 galaxyConfigOutput.writeStartElement(OPTION);
622 galaxyConfigOutput.writeAttribute(VALUE, itemsIterator.value().toString());
623 if (itemsIterator == items.begin()) {
624 galaxyConfigOutput.writeAttribute(SELECTED, "true");
625 }
626 galaxyConfigOutput.writeDTD(itemsIterator.key());
627 galaxyConfigOutput.writeEndElement();
628 itemsIterator++;
629 }
630 }
631
writeDrillDownAttribute(const PropertyDelegate & pd)632 void GalaxyConfigTask::writeDrillDownAttribute(const PropertyDelegate &pd) {
633 QVariantMap items;
634 pd.getItems(items);
635 galaxyConfigOutput.writeStartElement(OPTIONS);
636 QVariantMap ::iterator itemsIterator;
637 itemsIterator = items.begin();
638 while (itemsIterator != items.end()) {
639 galaxyConfigOutput.writeStartElement(OPTION);
640 galaxyConfigOutput.writeAttribute(NAME, itemsIterator.key());
641 galaxyConfigOutput.writeAttribute(VALUE, itemsIterator.value().toString());
642 galaxyConfigOutput.writeEndElement();
643 itemsIterator++;
644 }
645 galaxyConfigOutput.writeEndElement();
646 }
647
writeMinAndMaxAttributes(const PropertyDelegate & pd)648 void GalaxyConfigTask::writeMinAndMaxAttributes(const PropertyDelegate &pd) {
649 QVariantMap items;
650 pd.getItems(items);
651 QString minValue = items.value("minimum").toString();
652 QString maxValue = items.value("maximum").toString();
653 galaxyConfigOutput.writeAttribute(MIN, minValue);
654 galaxyConfigOutput.writeAttribute(MAX, maxValue);
655 }
656
tryToWriteComplexType(PropertyDelegate * pd,const QString &)657 bool GalaxyConfigTask::tryToWriteComplexType(PropertyDelegate *pd, const QString & /*attributeName*/) {
658 QString attributeType = QString();
659 assert(pd != nullptr);
660 if (isDelegateComboBox(pd)) {
661 attributeType = "select";
662 galaxyConfigOutput.writeAttribute(Constants::TYPE_ATTR, attributeType);
663 writeSelectAttribute(*pd);
664 } else if (isDelegateComboBoxWithChecks(pd)) {
665 attributeType = "drill_down";
666 galaxyConfigOutput.writeAttribute(Constants::TYPE_ATTR, attributeType);
667 galaxyConfigOutput.writeAttribute(DISPLAY, "checkbox");
668 galaxyConfigOutput.writeAttribute(HIERARCHY, "recurse");
669 galaxyConfigOutput.writeAttribute(MULTIPLE, "true");
670 galaxyConfigOutput.writeAttribute(SEPARATOR, Constants::COMMA);
671 writeDrillDownAttribute(*pd);
672 } else if (isDelegateSpinBox(pd)) {
673 QVariantMap items;
674 pd->getItems(items);
675 const QString typeName1 = items.value("minimum").typeName();
676 const QString typeName2 = items.value("maximum").typeName();
677 if (typeName1 == "double" || typeName2 == "double") {
678 attributeType = "float";
679 } else {
680 attributeType = "integer";
681 }
682 galaxyConfigOutput.writeAttribute(Constants::TYPE_ATTR, attributeType);
683 writeMinAndMaxAttributes(*pd);
684 } else if (isDelegateStringList(pd)) {
685 attributeType = "text";
686 galaxyConfigOutput.writeAttribute(Constants::TYPE_ATTR, attributeType);
687 }
688 return true;
689 }
690
691 // FIXME
692 // look at tryToWriteSimpleType and tryToWriteComplexType functions
writeTypeForOptionElement(const QStringList & elementParameters,const ActorPrototype & element)693 bool GalaxyConfigTask::writeTypeForOptionElement(const QStringList &elementParameters, const ActorPrototype &element) {
694 const QString attributeName = elementParameters.at(0);
695 Attribute *elementAttribute = element.getAttribute(attributeName);
696 assert(elementAttribute != nullptr);
697
698 ConfigurationEditor *editor = element.getEditor();
699 PropertyDelegate *pd = nullptr;
700 if (editor != nullptr) {
701 pd = editor->getDelegate(attributeName);
702 }
703
704 QString attributeType = elementAttribute->getAttributeType()->getId();
705 if (tryToWriteSimpleType(pd, attributeType)) {
706 if (attributeType == "integer") {
707 galaxyConfigOutput.writeAttribute(VALUE, "1");
708 }
709 } else if (!tryToWriteComplexType(pd, attributeName)) {
710 stateInfo.setError("Config generation error: unknown attribute type: " + attributeType);
711 return false;
712 }
713
714 return true;
715 }
716
writeOptionElements()717 bool GalaxyConfigTask::writeOptionElements() {
718 QList<int>::iterator optionElementsIterator;
719 optionElementsIterator = optionElementsPositions.begin();
720 while (optionElementsIterator != optionElementsPositions.end()) {
721 galaxyConfigOutput.writeStartElement(PARAM);
722 const QMap<QString, QStringList> currAlias = elemAliases[*optionElementsIterator];
723 QMap<QString, QStringList>::const_iterator currAliasIterator = currAlias.begin();
724
725 const QString elementName = (currAliasIterator).key(),
726 aliasName = (currAliasIterator).value().at(1);
727 galaxyConfigOutput.writeAttribute(Constants::NAME_ATTR, aliasName);
728
729 ActorPrototype *currElement = getElementFromActorPrototypeRegistry(elementName);
730 assert(nullptr != currElement);
731
732 writeLabelAttribute((currAliasIterator).value(), *currElement);
733 CHECK(writeTypeForOptionElement((currAliasIterator).value(), *currElement), false);
734
735 galaxyConfigOutput.writeEndElement();
736 optionElementsIterator++;
737 }
738 return true;
739 }
740
writeInputsUnit()741 bool GalaxyConfigTask::writeInputsUnit() {
742 galaxyConfigOutput.writeStartElement(INPUTS); // inputs unit begin
743 CHECK(writeInputElements(), false);
744 CHECK(writeOptionElements(), false);
745 galaxyConfigOutput.writeEndElement(); // inputs unit end
746 return true;
747 }
748
writeFormatAttributeForOutputElement(const QString & resultType)749 void GalaxyConfigTask::writeFormatAttributeForOutputElement(const QString &resultType) {
750 DocumentFormatRegistry *docFormatRegistry = AppContext::getDocumentFormatRegistry();
751 assert(nullptr != docFormatRegistry);
752
753 DocumentFormatConstraints constraint;
754 constraint.supportedObjectTypes.insert(resultType);
755 constraint.addFlagToExclude(DocumentFormatFlag_CannotBeCreated);
756 const QList<QString> selectedFormats = docFormatRegistry->selectFormats(constraint);
757 galaxyConfigOutput.writeAttribute(FORMAT, selectedFormats.first());
758 }
759
checkDocumentFormatAttribute(const ActorPrototype & element)760 bool GalaxyConfigTask::checkDocumentFormatAttribute(const ActorPrototype &element) {
761 const QList<Attribute *> elementAttibutes = element.getAttributes();
762 foreach (Attribute *elementAttribute, elementAttibutes) {
763 if (elementAttribute->getId() == BaseAttributes::DOCUMENT_FORMAT_ATTRIBUTE().getId()) {
764 return true;
765 }
766 }
767 return false;
768 }
769
writeChangeFormatAttribute(const QString & aliasName,const ActorPrototype & element)770 void GalaxyConfigTask::writeChangeFormatAttribute(const QString &aliasName, const ActorPrototype &element) {
771 galaxyConfigOutput.writeStartElement(CHANGE_FORMAT);
772
773 CHECK(nullptr != element.getEditor(), );
774 PropertyDelegate *pd = element.getEditor()->getDelegate(BaseAttributes::DOCUMENT_FORMAT_ATTRIBUTE().getId());
775 assert(nullptr != pd);
776
777 QVariantMap items;
778 pd->getItems(items);
779 QVariantMap ::iterator itemsIterator;
780 itemsIterator = items.begin();
781 while (itemsIterator != items.end()) {
782 galaxyConfigOutput.writeStartElement(WHEN);
783 galaxyConfigOutput.writeAttribute(INPUT, aliasName);
784 galaxyConfigOutput.writeAttribute(VALUE, itemsIterator.value().toString());
785 galaxyConfigOutput.writeAttribute(FORMAT, itemsIterator.value().toString());
786 galaxyConfigOutput.writeEndElement();
787 itemsIterator++;
788 }
789 galaxyConfigOutput.writeEndElement();
790 }
791
tryToWriteChangeFormatAttribute(const ActorPrototype & element,QList<int> & usedOptionElements)792 void GalaxyConfigTask::tryToWriteChangeFormatAttribute(const ActorPrototype &element, QList<int> &usedOptionElements) {
793 if (!checkDocumentFormatAttribute(element)) {
794 return;
795 }
796 QList<int>::iterator optionElementsIterator;
797 optionElementsIterator = optionElementsPositions.begin();
798 while (optionElementsIterator != optionElementsPositions.end()) {
799 QMap<QString, QStringList>::iterator elementProperties = elemAliases[*optionElementsIterator].begin();
800
801 const QString elementName = elementProperties.key(),
802 attributeName = elementProperties.value().at(0),
803 aliasName = elementProperties.value().at(1);
804
805 if (elementName == element.getId() &&
806 attributeName == BaseAttributes::DOCUMENT_FORMAT_ATTRIBUTE().getId() &&
807 !usedOptionElements.count(*optionElementsIterator)) {
808 usedOptionElements.push_back(*optionElementsIterator);
809 writeChangeFormatAttribute(aliasName, element);
810 break;
811 }
812 optionElementsIterator++;
813 }
814 }
815
writeOutputsUnit()816 bool GalaxyConfigTask::writeOutputsUnit() {
817 galaxyConfigOutput.writeStartElement(OUTPUTS); // outputs unit begin
818 QList<int> usedOptionElements;
819
820 QList<int>::iterator outputElementsIterator;
821 outputElementsIterator = outputElementsPositions.begin();
822 while (outputElementsIterator != outputElementsPositions.end()) {
823 const QMap<QString, QStringList> currAlias = elemAliases[*outputElementsIterator];
824 QMap<QString, QStringList>::const_iterator currAliasIterator = currAlias.begin();
825
826 const QString elementName = (currAliasIterator).key(),
827 aliasName = (currAliasIterator).value().at(1);
828
829 ActorPrototype *currElement = getElementFromActorPrototypeRegistry(elementName);
830 assert(nullptr != currElement);
831
832 QString resultType = QString();
833 CHECK(getResultType(*currElement, resultType), false);
834
835 galaxyConfigOutput.writeStartElement(DATA);
836 writeFormatAttributeForOutputElement(resultType);
837 galaxyConfigOutput.writeAttribute(Constants::NAME_ATTR, aliasName);
838 tryToWriteChangeFormatAttribute(*currElement, usedOptionElements);
839 galaxyConfigOutput.writeEndElement();
840 outputElementsIterator++;
841 }
842
843 galaxyConfigOutput.writeStartElement(DATA);
844 galaxyConfigOutput.writeAttribute(FORMAT, "txt");
845 galaxyConfigOutput.writeAttribute(Constants::NAME_ATTR, WORKFLOW_RUN_LOG);
846 galaxyConfigOutput.writeAttribute("label", WORKFLOW_RUN_LOG);
847 galaxyConfigOutput.writeEndElement();
848
849 galaxyConfigOutput.writeEndElement(); // outputs unit end
850 return true;
851 }
852
writeHelpUnit()853 void GalaxyConfigTask::writeHelpUnit() {
854 galaxyConfigOutput.writeStartElement(HELP);
855 galaxyConfigOutput.writeDTD(galaxyHelpMessage);
856 galaxyConfigOutput.writeEndElement();
857 }
858
createConfigForGalaxy()859 bool GalaxyConfigTask::createConfigForGalaxy() {
860 schemeConfigPath = schemePath;
861 schemeConfigPath.replace(".uwl", ".xml");
862 QFile galaxyConfigFile(schemeConfigPath);
863 galaxyConfigFile.open(QIODevice::WriteOnly);
864 if (!galaxyConfigFile.isOpen()) {
865 this->stateInfo.setError("Config generation error: can not open " + schemeConfigPath);
866 return false;
867 }
868 galaxyConfigOutput.setDevice(&galaxyConfigFile);
869
870 writeToolUnit();
871 CHECK(writeCommandUnit(), false);
872 CHECK(writeInputsUnit(), false);
873 CHECK(writeOutputsUnit(), false);
874 writeHelpUnit();
875 galaxyConfigOutput.writeEndElement(); // tool unit end
876
877 galaxyConfigFile.close();
878 coreLog.info("Tool config was created");
879 coreLog.info("Workflow config path is " + schemeConfigPath);
880 return true;
881 }
882
tryToCopySchemeConfigFile()883 bool GalaxyConfigTask::tryToCopySchemeConfigFile() {
884 if (destinationPath.isEmpty()) {
885 return true;
886 }
887 QFileInfo destinationDirInfo(destinationPath);
888 if (!destinationDirInfo.isWritable()) {
889 stateInfo.setError(QString("Folder %1 is not writable by this user").arg(destinationPath));
890 return false;
891 }
892
893 schemeConfigName = schemeName;
894 schemeConfigName.replace(".uwl", ".xml");
895 QString destinationFilePath = destinationPath + schemeConfigName;
896 QString schemeConfigPathCopy = schemeConfigPath;
897 destinationFilePath.replace("\\", "/");
898 schemeConfigPathCopy.replace("\\", "/");
899
900 if (!QString::compare(destinationFilePath, schemeConfigPath)) {
901 return true;
902 }
903 bool copied = QFile::copy(schemeConfigPath, destinationFilePath);
904 if (!copied) {
905 stateInfo.setError(QString("Can not copy %1 to %2").arg(schemeConfigPath).arg(destinationPath));
906 return false;
907 }
908 return true;
909 }
910
rewriteFile(const QString & sourceFileName,const QString & targetFileName)911 bool GalaxyConfigTask::rewriteFile(const QString &sourceFileName, const QString &targetFileName) {
912 if (QFile::exists(targetFileName)) {
913 if (!QFile::remove(targetFileName)) {
914 stateInfo.setError(QString("Can not remove %1").arg(targetFileName));
915 return false;
916 }
917 }
918 if (!QFile::copy(sourceFileName, targetFileName)) {
919 stateInfo.setError(QString("Can not copy %1 to %2").arg(sourceFileName).arg(targetFileName));
920 return false;
921 }
922 return true;
923 }
924
doCopyCommands(const QString & pathToCopy)925 bool GalaxyConfigTask::doCopyCommands(const QString &pathToCopy) {
926 CHECK(rewriteFile(schemeConfigPath, pathToCopy + schemeConfigName), false);
927 CHECK(rewriteFile(schemePath, pathToCopy + schemeName), false);
928 return true;
929 }
doDeleteCommands()930 void GalaxyConfigTask::doDeleteCommands() {
931 if (!QFile::remove(schemeConfigPath)) {
932 coreLog.info(QString("Can not delete %1").arg(schemeConfigPath));
933 }
934 }
935
prepareToolDirectory()936 bool GalaxyConfigTask::prepareToolDirectory() {
937 if (galaxyPath.isEmpty()) {
938 return true;
939 }
940 const QString truncatedSchemeName = schemeName.left(schemeName.length() - 4);
941 QString pathToCopy = galaxyPath + "tools/" + truncatedSchemeName;
942 QDir directory(pathToCopy);
943
944 if (!directory.exists()) {
945 bool created = directory.mkdir(pathToCopy);
946 if (!created) {
947 stateInfo.setError(QString("Can not create %1 folder. Check user privileges").arg(pathToCopy));
948 return false;
949 }
950 }
951 QFileInfo copyPathDirectory(pathToCopy);
952 if (!copyPathDirectory.isWritable()) {
953 stateInfo.setError(QString("Folder %1 is not writable by this user").arg(pathToCopy));
954 return false;
955 }
956
957 tryToAppendSlash(pathToCopy);
958 CHECK(doCopyCommands(pathToCopy), false);
959 doDeleteCommands();
960 return true;
961 }
962
makeCopyOfGalaxyToolConfig()963 bool GalaxyConfigTask::makeCopyOfGalaxyToolConfig() {
964 const QString toolConfigurationPath = galaxyPath + "tool_conf.xml";
965 QString backupFile = toolConfigurationPath;
966 backupFile.replace(".xml", ".bak");
967 if (!QFile::exists(backupFile)) {
968 bool copied = QFile::copy(toolConfigurationPath, backupFile);
969 if (!copied) {
970 stateInfo.setError(QString("Can not copy %1 to %2").arg(toolConfigurationPath).arg(backupFile));
971 return false;
972 }
973 }
974 return true;
975 }
976
writeNewSection(const QString & config)977 void GalaxyConfigTask::writeNewSection(const QString &config) {
978 const int toolboxPosition = config.indexOf("<toolbox>");
979 const int beginLength = toolboxPosition + QString("<toolbox>").length();
980 const QString begin = config.mid(0, beginLength);
981 const QString end = config.mid(beginLength, config.length() - begin.length());
982
983 const QString toolsConfigurationPath = galaxyPath + "tool_conf.xml";
984 QFile configFile(toolsConfigurationPath);
985 if (!configFile.open(QIODevice::WriteOnly)) {
986 return;
987 }
988 QXmlStreamWriter galaxyToolsConfigOutput;
989 galaxyToolsConfigOutput.setDevice(&configFile);
990
991 QString idStrCopy = galaxyToolName;
992 idStrCopy.replace(" ", "_");
993 const QString truncatedSchemeName = schemeName.left(schemeName.length() - 4);
994
995 galaxyToolsConfigOutput.writeDTD(begin);
996 galaxyToolsConfigOutput.writeDTD("\n");
997 galaxyToolsConfigOutput.writeStartElement("section");
998 galaxyToolsConfigOutput.writeAttribute("name", galaxyToolName + "-tool");
999
1000 galaxyToolsConfigOutput.writeAttribute("id", idStrCopy);
1001 galaxyToolsConfigOutput.writeDTD("\n");
1002 galaxyToolsConfigOutput.writeStartElement("tool");
1003
1004 galaxyToolsConfigOutput.writeAttribute("file", QString("%1/%1.xml").arg(truncatedSchemeName));
1005 galaxyToolsConfigOutput.writeEndElement();
1006 galaxyToolsConfigOutput.writeDTD("\n");
1007 galaxyToolsConfigOutput.writeEndElement();
1008 galaxyToolsConfigOutput.writeDTD("\n");
1009 galaxyToolsConfigOutput.writeDTD(end);
1010 }
1011
addNewTool()1012 void GalaxyConfigTask::addNewTool() {
1013 const QString toolConfigurationPath = galaxyPath + "tool_conf.xml";
1014
1015 QFile configFile(toolConfigurationPath);
1016 if (!configFile.open(QIODevice::ReadOnly)) {
1017 coreLog.info(QString("Can not open %1").arg(toolConfigurationPath));
1018 return;
1019 }
1020 QTextStream input(&configFile);
1021 QString config = input.readAll();
1022 configFile.close();
1023 if (config.indexOf(galaxyToolName) != SUBSTRING_NOT_FOUND) {
1024 return;
1025 }
1026 writeNewSection(config);
1027 }
1028
modifyToolConfig()1029 void GalaxyConfigTask::modifyToolConfig() {
1030 CHECK(makeCopyOfGalaxyToolConfig(), );
1031 addNewTool();
1032 }
1033
addToolToGalaxy()1034 void GalaxyConfigTask::addToolToGalaxy() {
1035 CHECK(prepareToolDirectory(), );
1036 modifyToolConfig();
1037 }
1038
1039 } // namespace U2
1040