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 &parameterValue, 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