diff --git a/.travis.yml b/.travis.yml index 8d577a594..1466d5d89 100644 --- a/.travis.yml +++ b/.travis.yml @@ -168,6 +168,12 @@ script: - echo $CXXFLAGS - make -s -j2 - cd ../ +# Build triage + - cd ./tools/triage + - git clean -dfx . + - qmake + - make -s -j2 + - cd ../../ notifications: irc: diff --git a/tools/triage/mainwindow.cpp b/tools/triage/mainwindow.cpp index 6ded61442..80e1c17ea 100644 --- a/tools/triage/mainwindow.cpp +++ b/tools/triage/mainwindow.cpp @@ -17,7 +17,11 @@ MainWindow::MainWindow(QWidget *parent) : ui(new Ui::MainWindow) { ui->setupUi(this); - std::srand(std::time(0)); + std::srand(static_cast(std::time(Q_NULLPTR))); + QDir workFolder(WORK_FOLDER); + if (!workFolder.exists()) { + workFolder.mkdir(WORK_FOLDER); + } } MainWindow::~MainWindow() @@ -27,7 +31,8 @@ MainWindow::~MainWindow() void MainWindow::loadFile() { - const QString fileName = QFileDialog::getOpenFileName(this, tr("daca results file"), WORK_FOLDER, tr("Text files (*.txt)")); + ui->statusBar->clearMessage(); + const QString fileName = QFileDialog::getOpenFileName(this, tr("daca results file"), WORK_FOLDER, tr("Text files (*.txt);;All (*.*)")); if (fileName.isEmpty()) return; ui->results->clear(); @@ -75,34 +80,64 @@ void MainWindow::loadFile() } } -static bool wget(const QString url) +bool MainWindow::runProcess(const QString &programName, const QStringList &arguments) { QProcess process; process.setWorkingDirectory(WORK_FOLDER); - process.start("wget", QStringList() << url); - return process.waitForFinished(-1); + process.start(programName, arguments); + bool success = process.waitForFinished(-1); + if (!success) { + QString errorstr(programName); + errorstr.append(": "); + errorstr.append(process.errorString()); + ui->statusBar->showMessage(errorstr); + } else { + int exitCode = process.exitCode(); + if (exitCode != 0) { + success = false; + const QByteArray stderrOutput = process.readAllStandardError(); + QString errorstr(programName); + errorstr.append(QString(": exited with %1: ").arg(exitCode)); + errorstr.append(stderrOutput); + ui->statusBar->showMessage(errorstr); + } + } + return success; } -static bool unpackArchive(const QString archiveName) +bool MainWindow::wget(const QString url) +{ + return runProcess("wget", QStringList() << url); +} + +bool MainWindow::unpackArchive(const QString archiveName) { // Unpack archive QStringList args; +#ifdef Q_OS_WIN + /* On Windows --force-local is necessary because tar wants to connect to a remote system + * when a colon is found in the archiveName. So "C:/Users/blah/triage/package" would not work + * without it. */ + args << "--force-local"; +#endif if (archiveName.endsWith(".tar.gz")) - args << "xzvf"; + args << "-xzvf"; else if (archiveName.endsWith(".tar.bz2")) - args << "xjvf"; + args << "-xjvf"; else if (archiveName.endsWith(".tar.xz")) - args << "xJvf"; + args << "-xJvf"; + else { + // Try to automatically find an (un)compressor for this archive + args << "-xavf"; + } args << archiveName; - QProcess process; - process.setWorkingDirectory(WORK_FOLDER); - process.start("tar", args); - return process.waitForFinished(-1); + return runProcess("tar", args); } void MainWindow::showResult(QListWidgetItem *item) { + ui->statusBar->clearMessage(); if (!item->text().startsWith("ftp://")) return; const QStringList lines = item->text().split("\n"); @@ -115,7 +150,7 @@ void MainWindow::showResult(QListWidgetItem *item) const QString archiveName = url.mid(url.lastIndexOf("/") + 1); const int pos1 = msg.indexOf(":"); const int pos2 = msg.indexOf(":", pos1+1); - const QString fileName = msg.left(msg.indexOf(":")); + const QString fileName = WORK_FOLDER + '/' + msg.left(msg.indexOf(":")); const int lineNumber = msg.mid(pos1+1,pos2-pos1-1).toInt(); if (!QFileInfo(fileName).exists()) { @@ -135,12 +170,18 @@ void MainWindow::showResult(QListWidgetItem *item) // Open file ui->code->setFocus(); - QFile f(WORK_FOLDER + '/' + fileName); - f.open(QIODevice::ReadOnly | QIODevice::Text); - QTextStream textStream(&f); - const QString fileData = textStream.readAll(); - ui->code->setError(fileData, lineNumber, QStringList()); + QFile f(fileName); + if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) { + const QString errorMsg = + QString("Opening file %1 failed: %2").arg(f.fileName()).arg(f.errorString()); + ui->statusBar->showMessage(errorMsg); + } else { + QTextStream textStream(&f); + const QString fileData = textStream.readAll(); + ui->code->setError(fileData, lineNumber, QStringList()); - ui->edit1->setText(url); - ui->edit2->setText(WORK_FOLDER + '/' + fileName); + ui->edit1->setText(url); + ui->edit2->setText(fileName); + f.close(); + } } diff --git a/tools/triage/mainwindow.h b/tools/triage/mainwindow.h index 1365c494d..5abc8e9a0 100644 --- a/tools/triage/mainwindow.h +++ b/tools/triage/mainwindow.h @@ -12,7 +12,7 @@ class MainWindow : public QMainWindow { Q_OBJECT public: - explicit MainWindow(QWidget *parent = 0); + explicit MainWindow(QWidget *parent = Q_NULLPTR); MainWindow(const MainWindow &) = delete; ~MainWindow(); MainWindow &operator=(const MainWindow &) = delete; @@ -23,6 +23,10 @@ public slots: private: Ui::MainWindow *ui; + + bool runProcess(const QString &programName, const QStringList & arguments); + bool wget(const QString url); + bool unpackArchive(const QString archiveName); }; #endif // MAINWINDOW_H diff --git a/tools/triage/readme.txt b/tools/triage/readme.txt new file mode 100644 index 000000000..61c2e6fc6 --- /dev/null +++ b/tools/triage/readme.txt @@ -0,0 +1,18 @@ +triage tool +This tool lets you comfortably look at Cppcheck analysis results for daca packages. It automatically +downloads the package, extracts it and jumps to the corresponding source code for a Cppcheck +message. + +triage uses "wget" and "tar" +On Linux the tool can be directly run since the programs should be installed. +On Windows something like Cygwin is necessary and the directory containing the executables must be +in the PATH environment variable (for example "C:\cygwin\bin"). + +Usage: +After triage has been started you have to load a daca results file via the "Load" button. +The file must contain the package URL line beginning with "ftp://" and the Cppcheck messages. +When the results file has been parsed successfully you can see a list of Cppcheck messages directly +beneath the "Load" button. Double-click any entry to let the tool show the source code and jump to +and mark the corresponding line. If the package is not found it is downloaded and extracted +automatically. So after the first double-click it is normal that it takes some time until the +source code is shown.