diff --git a/blast/blastqueries.cpp b/blast/blastqueries.cpp index 85f8f7d1..3c546eea 100644 --- a/blast/blastqueries.cpp +++ b/blast/blastqueries.cpp @@ -23,12 +23,8 @@ #include "program/settings.h" #include -BlastQueries::BlastQueries() : - m_tempNuclFile(0), m_tempProtFile(0) -{ - m_presetColours = getPresetColours(); -} - +BlastQueries::BlastQueries() +: m_presetColours{getPresetColours()} {} BlastQueries::~BlastQueries() { @@ -36,12 +32,6 @@ BlastQueries::~BlastQueries() } -void BlastQueries::createTempQueryFiles() -{ - m_tempNuclFile.reset(new QFile(g_blastSearch->m_tempDirectory + "nucl_queries.fasta")); - m_tempProtFile.reset(new QFile(g_blastSearch->m_tempDirectory + "prot_queries.fasta")); -} - BlastQuery * BlastQueries::getQueryFromName(QString queryName) { for (size_t i = 0; i < m_queries.size(); ++i) @@ -63,7 +53,6 @@ void BlastQueries::addQuery(BlastQuery * newQuery) newQuery->setColour(m_presetColours[colourIndex]); m_queries.push_back(newQuery); - updateTempFiles(); } @@ -73,7 +62,6 @@ void BlastQueries::addQuery(BlastQuery * newQuery) QString BlastQueries::renameQuery(BlastQuery * newQuery, QString newName) { newQuery->setName(getUniqueName(newName)); - updateTempFiles(); return newQuery->getName(); } @@ -105,7 +93,6 @@ void BlastQueries::clearAllQueries() for (size_t i = 0; i < m_queries.size(); ++i) delete m_queries[i]; m_queries.clear(); - deleteTempFiles(); } void BlastQueries::clearSomeQueries(std::vector queriesToRemove) @@ -115,47 +102,8 @@ void BlastQueries::clearSomeQueries(std::vector queriesToRemove) m_queries.erase(std::remove(m_queries.begin(), m_queries.end(), queriesToRemove[i]), m_queries.end()); delete queriesToRemove[i]; } - - updateTempFiles(); -} - -void BlastQueries::deleteTempFiles() -{ - if (tempNuclFileExists()) - m_tempNuclFile->remove(); - if (tempProtFileExists()) - m_tempProtFile->remove(); -} - -void BlastQueries::updateTempFiles() -{ - deleteTempFiles(); - - if (getQueryCount(NUCLEOTIDE) > 0) - writeTempFile(m_tempNuclFile, NUCLEOTIDE); - - if (getQueryCount(PROTEIN) > 0) - writeTempFile(m_tempProtFile, PROTEIN); } - -void BlastQueries::writeTempFile(QSharedPointer file, QuerySequenceType sequenceType) -{ - file->open(QIODevice::Append | QIODevice::Text); - QTextStream out(file.data()); - for (size_t i = 0; i < m_queries.size(); ++i) - { - if (m_queries[i]->getSequenceType() == sequenceType) - { - out << ">" << m_queries[i]->getName() << "\n"; - out << m_queries[i]->getSequence(); - out << "\n"; - } - } - file->close(); -} - - void BlastQueries::searchOccurred() { for (size_t i = 0; i < m_queries.size(); ++i) @@ -208,21 +156,6 @@ int BlastQueries::getQueryCount(QuerySequenceType sequenceType) return count; } - -bool BlastQueries::tempNuclFileExists() -{ - if (m_tempNuclFile.isNull()) - return false; - return m_tempNuclFile->exists(); -} -bool BlastQueries::tempProtFileExists() -{ - if (m_tempProtFile.isNull()) - return false; - return m_tempProtFile->exists(); -} - - //This function looks to see if a query pointer is in the list //of queries. The query pointer given may or may not still //actually exist, so it can't be dereferenced. diff --git a/blast/blastqueries.h b/blast/blastqueries.h index d5c7c7c2..c342d194 100644 --- a/blast/blastqueries.h +++ b/blast/blastqueries.h @@ -26,12 +26,8 @@ #include -//This class manages all BLAST queries. It holds BlastQuery -//objects itself, and it creates/modifies/deletes the temp -//files which hold the queries for use in BLAST. -//There are two separate temp files, one for nucleotide -//queries (for blastn) and one for protein queries (for -//tblasn). +// This class manages all BLAST queries. It holds BlastQuery +// objects class BlastQueries { @@ -43,7 +39,6 @@ class BlastQueries BlastQuery * getQueryFromName(QString queryName); - void createTempQueryFiles(); void addQuery(BlastQuery * newQuery); QString renameQuery(BlastQuery * newQuery, QString newName); void clearAllQueries(); @@ -60,16 +55,7 @@ class BlastQueries std::vector m_presetColours; private: - QSharedPointer m_tempNuclFile; - QSharedPointer m_tempProtFile; - - void deleteTempFiles(); - void updateTempFiles(); - bool tempNuclFileExists(); - bool tempProtFileExists(); - void writeTempFile(QSharedPointer file, QuerySequenceType sequenceType); QString getUniqueName(QString name); - }; #endif // BLASTQUERIES_H diff --git a/blast/blastsearch.cpp b/blast/blastsearch.cpp index 1b57bacd..3c522b33 100644 --- a/blast/blastsearch.cpp +++ b/blast/blastsearch.cpp @@ -32,14 +32,13 @@ #include #include -BlastSearch::BlastSearch() : - m_blastQueries(), m_tempDirectory("bandage_temp/") -{ -} +BlastSearch::BlastSearch(const QDir &workDir) : + m_blastQueries(), m_tempDirectory(workDir.filePath("bandage_temp_XXXXXX")) {} BlastSearch::~BlastSearch() { - cleanUp(); + clearBlastHits(); + m_blastQueries.clearAllQueries(); } void BlastSearch::clearBlastHits() @@ -244,13 +243,7 @@ void BlastSearch::clearSomeQueries(std::vector queriesToRemove) void BlastSearch::emptyTempDirectory() const { - //Safety checks - if (g_blastSearch->m_tempDirectory == "") - return; - if (!g_blastSearch->m_tempDirectory.contains("bandage_temp")) - return; - - QDir tempDirectory(m_tempDirectory); + QDir tempDirectory(m_tempDirectory.path()); tempDirectory.setNameFilters(QStringList() << "*.*"); tempDirectory.setFilter(QDir::Files); foreach(QString dirFile, tempDirectory.entryList()) diff --git a/blast/blastsearch.h b/blast/blastsearch.h index 4ea63a5d..39e92e0b 100644 --- a/blast/blastsearch.h +++ b/blast/blastsearch.h @@ -21,12 +21,10 @@ #include "blasthit.h" #include "blastqueries.h" -#include "program/scinot.h" -#include #include -#include -#include +#include +#include #include @@ -34,10 +32,12 @@ //An instance of it is made available to the whole program //as a global. +class QProcess; + class BlastSearch { public: - BlastSearch(); + explicit BlastSearch(const QDir &workDir = QDir::temp()); ~BlastSearch(); BlastQueries m_blastQueries; @@ -46,7 +46,7 @@ class BlastSearch bool m_cancelRunBlastSearch{}; QProcess *m_makeblastdb{}; QProcess *m_blast{}; - QString m_tempDirectory; + QTemporaryDir m_tempDirectory; std::vector> m_allHits; static QString getNodeNameFromString(const QString& nodeString); diff --git a/blast/buildblastdatabaseworker.cpp b/blast/buildblastdatabaseworker.cpp index 05994553..4d5ca832 100644 --- a/blast/buildblastdatabaseworker.cpp +++ b/blast/buildblastdatabaseworker.cpp @@ -38,8 +38,11 @@ void BuildBlastDatabaseWorker::buildBlastDatabase() { g_blastSearch->m_cancelBuildBlastDatabase = false; - QFile file(g_blastSearch->m_tempDirectory + "all_nodes.fasta"); - file.open(QIODevice::WriteOnly | QIODevice::Text); + QFile file(g_blastSearch->m_tempDirectory.filePath("all_nodes.fasta")); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + emit finishedBuild("Failed to open: " + file.fileName()); + return; + } QTextStream out(&file); for (auto &entry : g_assemblyGraph->m_deBruijnGraphNodes) { @@ -72,7 +75,7 @@ void BuildBlastDatabaseWorker::buildBlastDatabase() } QStringList makeBlastdbOptions; - makeBlastdbOptions << "-in" << (g_blastSearch->m_tempDirectory + "all_nodes.fasta") + makeBlastdbOptions << "-in" << (g_blastSearch->m_tempDirectory.filePath("all_nodes.fasta")) << "-dbtype" << "nucl"; g_blastSearch->m_makeblastdb = new QProcess(); diff --git a/blast/runblastsearchworker.cpp b/blast/runblastsearchworker.cpp index b11dc3e1..a0ebf42b 100644 --- a/blast/runblastsearchworker.cpp +++ b/blast/runblastsearchworker.cpp @@ -22,6 +22,8 @@ #include "program/globals.h" #include "program/settings.h" +#include + RunBlastSearchWorker::RunBlastSearchWorker(QString blastnCommand, QString tblastnCommand, QString parameters) : m_blastnCommand(blastnCommand), m_tblastnCommand(tblastnCommand), m_parameters(parameters) { @@ -64,14 +66,36 @@ void RunBlastSearchWorker::runBlastSearch() emit finishedSearch(m_error); } +static void writeQueryFile(QFile *file, + const BlastQueries &queries, + QuerySequenceType sequenceType) { -QString RunBlastSearchWorker::runOneBlastSearch(QuerySequenceType sequenceType, bool * success) -{ + QTextStream out(file); + for (const auto *query: queries.m_queries) { + if (query->getSequenceType() != sequenceType) + continue; + + out << '>' << query->getName() << '\n' + << query->getSequence() + << '\n'; + } +} + +QString RunBlastSearchWorker::runOneBlastSearch(QuerySequenceType sequenceType, bool * success) { QStringList blastOptions; - blastOptions << "-query" << (g_blastSearch-> m_tempDirectory + - (sequenceType == NUCLEOTIDE ? "nucl_queries.fasta" : "prot_queries.fasta")) - << "-db" << (g_blastSearch->m_tempDirectory + "all_nodes.fasta") + QTemporaryFile tmpFile(g_blastSearch->m_tempDirectory.filePath(sequenceType == NUCLEOTIDE ? + "nucl_queries.XXXXXX.fasta" : "prot_queries.XXXXXX.fasta")); + if (!tmpFile.open()) { + m_error = "Failed to create temporary query file"; + *success = false; + return ""; + } + + writeQueryFile(&tmpFile, g_blastSearch->m_blastQueries, sequenceType); + + blastOptions << "-query" << tmpFile.fileName() + << "-db" << (g_blastSearch->m_tempDirectory.filePath("all_nodes.fasta")) << "-outfmt" << "6"; blastOptions << m_parameters.split(" ", Qt::SkipEmptyParts); diff --git a/command_line/commoncommandlinefunctions.cpp b/command_line/commoncommandlinefunctions.cpp index cb2bf2b9..6097bf52 100644 --- a/command_line/commoncommandlinefunctions.cpp +++ b/command_line/commoncommandlinefunctions.cpp @@ -1189,28 +1189,6 @@ void getCommonHelp(QStringList * text) -bool createBlastTempDirectory() -{ - //Running from the command line, it makes more sense to put the temp - //directory in the current directory. - g_blastSearch->m_tempDirectory = "bandage_temp-" + QString::number(QApplication::applicationPid()) + "/"; - - if (!QDir().mkdir(g_blastSearch->m_tempDirectory)) - return false; - - g_blastSearch->m_blastQueries.createTempQueryFiles(); - return true; -} - -void deleteBlastTempDirectory() -{ - if (g_blastSearch->m_tempDirectory != "" && - QDir(g_blastSearch->m_tempDirectory).exists() && - QDir(g_blastSearch->m_tempDirectory).dirName().contains("bandage_temp")) - QDir(g_blastSearch->m_tempDirectory).removeRecursively(); -} - - QString getElapsedTime(const QDateTime& start, const QDateTime& end) { diff --git a/command_line/commoncommandlinefunctions.h b/command_line/commoncommandlinefunctions.h index 1daf0db0..9590be62 100644 --- a/command_line/commoncommandlinefunctions.h +++ b/command_line/commoncommandlinefunctions.h @@ -73,9 +73,6 @@ void parseSettings(QStringList arguments); void getCommonHelp(QStringList * text); void getSettingsUsage(QStringList *text); -bool createBlastTempDirectory(); -void deleteBlastTempDirectory(); - QString getElapsedTime(const QDateTime& start, const QDateTime& end); void getGraphScopeOptions(QStringList * text); diff --git a/command_line/image.cpp b/command_line/image.cpp index 12bade8a..102dc882 100644 --- a/command_line/image.cpp +++ b/command_line/image.cpp @@ -119,9 +119,9 @@ int bandageImage(QStringList arguments) if (blastUsed) { - if (!createBlastTempDirectory()) + if (!g_blastSearch->m_tempDirectory.isValid()) { - err << "Error creating temporary directory for BLAST files" << Qt::endl; + err << "Error creating temporary directory for BLAST files: " << g_blastSearch->m_tempDirectory.errorString() << Qt::endl; return 1; } @@ -227,8 +227,6 @@ int bandageImage(QStringList arguments) else returnCode = 0; - if (blastUsed) - deleteBlastTempDirectory(); return returnCode; } diff --git a/command_line/querypaths.cpp b/command_line/querypaths.cpp index 5ccaa24d..7e85a9cb 100644 --- a/command_line/querypaths.cpp +++ b/command_line/querypaths.cpp @@ -118,9 +118,9 @@ int bandageQueryPaths(QStringList arguments) return 1; out << "done" << Qt::endl; - if (!createBlastTempDirectory()) + if (!g_blastSearch->m_tempDirectory.isValid()) { - err << "Error creating temporary directory for BLAST files" << Qt::endl; + err << "Error creating temporary directory for BLAST files: " << g_blastSearch->m_tempDirectory.errorString() << Qt::endl; return 1; } @@ -261,7 +261,6 @@ int bandageQueryPaths(QStringList arguments) out << Qt::endl << "Elapsed time: " << getElapsedTime(startTime, QDateTime::currentDateTime()) << Qt::endl; - deleteBlastTempDirectory(); return 0; } diff --git a/command_line/reduce.cpp b/command_line/reduce.cpp index 43db10ba..bef2696c 100644 --- a/command_line/reduce.cpp +++ b/command_line/reduce.cpp @@ -90,9 +90,9 @@ int bandageReduce(QStringList arguments) bool blastUsed = isOptionPresent("--query", &arguments); if (blastUsed) { - if (!createBlastTempDirectory()) + if (!g_blastSearch->m_tempDirectory.isValid()) { - err << "Error creating temporary directory for BLAST files" << Qt::endl; + err << "Error creating temporary directory for BLAST files: " << g_blastSearch->m_tempDirectory.errorString() << Qt::endl; return 1; } @@ -125,7 +125,6 @@ int bandageReduce(QStringList arguments) return 1; } - deleteBlastTempDirectory(); return 0; } diff --git a/tests/bandagetests.cpp b/tests/bandagetests.cpp index 5256a2cf..72e678c2 100644 --- a/tests/bandagetests.cpp +++ b/tests/bandagetests.cpp @@ -85,18 +85,12 @@ private slots: void init() { g_settings.reset(new Settings()); g_memory.reset(new Memory()); - g_blastSearch.reset(new BlastSearch()); + g_blastSearch.reset(new BlastSearch(QDir("."))); g_assemblyGraph.reset(new AssemblyGraph()); g_annotationsManager = std::make_shared(); } void cleanup() { - if (g_blastSearch->m_tempDirectory == "") - return; - - QDir tmpdir(g_blastSearch->m_tempDirectory); - if (tmpdir.exists() && tmpdir.dirName().contains("bandage_temp")) - tmpdir.removeRecursively(); } void loadFastg(); @@ -132,7 +126,6 @@ private slots: private: - bool createBlastTempDirectory(); DeBruijnEdge * getEdgeFromNodeNames(QString startingNodeName, QString endingNodeName) const; bool doCircularSequencesMatch(QByteArray s1, QByteArray s2) const; @@ -517,7 +510,6 @@ void BandageTests::blastSearch() { QVERIFY(g_assemblyGraph->loadGraphFromFile(testFile("test.fastg"))); g_settings->blastQueryFilename = testFile("test_queries1.fasta"); - createBlastTempDirectory(); auto errorString = g_blastSearch->doAutoBlastSearch(); @@ -563,7 +555,6 @@ void BandageTests::blastSearchFilters() { QVERIFY(g_assemblyGraph->loadGraphFromFile(testFile("test.fastg"))); g_settings->blastQueryFilename = testFile("test_queries2.fasta"); - createBlastTempDirectory(); //First do the search with no filters g_blastSearch->doAutoBlastSearch(); @@ -724,8 +715,6 @@ void BandageTests::graphScope() drawnNodes = g_assemblyGraph->getDrawnNodeCount(); QCOMPARE(drawnNodes, 42); - createBlastTempDirectory(); - g_settings->blastQueryFilename = testFile("test_queries1.fasta"); g_blastSearch->doAutoBlastSearch(); @@ -1339,8 +1328,6 @@ void BandageTests::blastQueryPaths() g_settings->blastQueryFilename = testFile("test_query_paths.fasta"); defaultSettings.blastQueryFilename = testFile("test_query_paths.fasta"); - createBlastTempDirectory(); - //Now filter by e-value to get only strong hits and do the BLAST search. g_settings->blastEValueFilter.on = true; g_settings->blastEValueFilter = SciNot(1.0, -5); @@ -1600,19 +1587,6 @@ void BandageTests::sequenceDoubleReverseComplement() { -bool BandageTests::createBlastTempDirectory() -{ - //Running from the command line, it makes more sense to put the temp - //directory in the current directory. - g_blastSearch->m_tempDirectory = "bandage_temp-" + QString::number(QCoreApplication::applicationPid()) + "/"; - - if (!QDir().mkdir(g_blastSearch->m_tempDirectory)) - return false; - - g_blastSearch->m_blastQueries.createTempQueryFiles(); - return true; -} - DeBruijnEdge * BandageTests::getEdgeFromNodeNames(QString startingNodeName, QString endingNodeName) const { diff --git a/ui/blastsearchdialog.cpp b/ui/blastsearchdialog.cpp index 3212206d..3fa4cb85 100644 --- a/ui/blastsearchdialog.cpp +++ b/ui/blastsearchdialog.cpp @@ -94,7 +94,7 @@ BlastSearchDialog::BlastSearchDialog(QWidget *parent, const QString& autoQuery) //If a BLAST database already exists, move to step 2. - QFile databaseFile(g_blastSearch->m_tempDirectory + "all_nodes.fasta"); + QFile databaseFile =g_blastSearch->m_tempDirectory.filePath("all_nodes.fasta"); if (databaseFile.exists()) setUiStep(BLAST_DB_BUILT_BUT_NO_QUERIES); diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index 65b00eb6..fc5d2546 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -92,17 +92,10 @@ MainWindow::MainWindow(QString fileToLoadOnStartup, bool drawGraphAfterLoad) : srand(time(nullptr)); - //Make a temp directory to hold the BLAST files. - //Since Bandage is running in GUI mode, we make it in the system's - //temp area - out of the way for the user. - g_blastSearch->m_tempDirectory = QDir::tempPath() + "/bandage_temp-" + QString::number(QApplication::applicationPid()) + "/"; - if (!QDir().mkdir(g_blastSearch->m_tempDirectory)) - { - QMessageBox::warning(this, "Error", "A temporary directory could not be created. BLAST search functionality will not be available"); + if (!g_blastSearch->m_tempDirectory.isValid()) { + QMessageBox::warning(this, "Error", "A temporary directory could not be created. BLAST search functionality will not be available. Error: " + g_blastSearch->m_tempDirectory.errorString()); return; } - else - g_blastSearch->m_blastQueries.createTempQueryFiles(); m_previousZoomSpinBoxValue = ui->zoomSpinBox->value(); ui->zoomSpinBox->setMinimum(g_settings->minZoom * 100.0); @@ -265,15 +258,9 @@ MainWindow::~MainWindow() cleanUp(); delete m_graphicsViewZoom; delete ui; - - if (g_blastSearch->m_tempDirectory != "" && - QDir(g_blastSearch->m_tempDirectory).exists() && - QDir(g_blastSearch->m_tempDirectory).dirName().contains("bandage_temp")) - QDir(g_blastSearch->m_tempDirectory).removeRecursively(); } - void MainWindow::cleanUp() { ui->blastQueryComboBox->clear();