From cc8148606a5c5d5817e5366f0ce21ed2568025f5 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 27 May 2020 14:08:49 +0200 Subject: Move unarchiving code out of the plugin dialog code Change-Id: I2b6510ae527d57a06692336cfd7b0434cdcbda51 Reviewed-by: Alessandro Portale --- src/libs/utils/CMakeLists.txt | 1 + src/libs/utils/archive.cpp | 124 ++++++++++++++++++++++++++++++++ src/libs/utils/archive.h | 42 +++++++++++ src/libs/utils/utils-lib.pri | 6 +- src/libs/utils/utils.qbs | 2 + src/plugins/coreplugin/plugindialog.cpp | 104 ++++----------------------- 6 files changed, 185 insertions(+), 94 deletions(-) create mode 100644 src/libs/utils/archive.cpp create mode 100644 src/libs/utils/archive.h diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index ee001a311d..a474b5c2f4 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -10,6 +10,7 @@ add_qtc_library(Utils algorithm.h ansiescapecodehandler.cpp ansiescapecodehandler.h appmainwindow.cpp appmainwindow.h + archive.cpp archive.h basetreeview.cpp basetreeview.h benchmarker.cpp benchmarker.h buildablehelperlibrary.cpp buildablehelperlibrary.h diff --git a/src/libs/utils/archive.cpp b/src/libs/utils/archive.cpp new file mode 100644 index 0000000000..daab53451f --- /dev/null +++ b/src/libs/utils/archive.cpp @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "archive.h" + +#include "algorithm.h" +#include "checkablemessagebox.h" +#include "environment.h" +#include "mimetypes/mimedatabase.h" +#include "qtcassert.h" +#include "synchronousprocess.h" + +#include +#include + +namespace { + +struct Tool +{ + Utils::FilePath executable; + QStringList arguments; +}; + +Utils::optional unzipTool(const Utils::FilePath &src, const Utils::FilePath &dest) +{ + const Utils::FilePath unzip = Utils::Environment::systemEnvironment().searchInPath( + Utils::HostOsInfo::withExecutableSuffix("unzip")); + if (!unzip.isEmpty()) + return Tool{unzip, {"-o", src.toString(), "-d", dest.toString()}}; + + const Utils::FilePath sevenzip = Utils::Environment::systemEnvironment().searchInPath( + Utils::HostOsInfo::withExecutableSuffix("7z")); + if (!sevenzip.isEmpty()) + return Tool{sevenzip, {"x", QString("-o") + dest.toString(), "-y", src.toString()}}; + + const Utils::FilePath cmake = Utils::Environment::systemEnvironment().searchInPath( + Utils::HostOsInfo::withExecutableSuffix("cmake")); + if (!cmake.isEmpty()) + return Tool{cmake, {"-E", "tar", "xvf", src.toString()}}; + + return {}; +} + +} // namespace + +namespace Utils { + +bool Archive::supportsFile(const FilePath &filePath, QString *reason) +{ + const QList mimeType = mimeTypesForFileName(filePath.toString()); + if (!anyOf(mimeType, [](const MimeType &mt) { return mt.inherits("application/zip"); })) { + if (reason) + *reason = tr("File format not supported."); + return false; + } + if (!unzipTool({}, {})) { + if (reason) + *reason = tr("Could not find unzip, 7z, or cmake executable in PATH."); + return false; + } + return true; +} + +bool Archive::unarchive(const FilePath &src, const FilePath &dest, QWidget *parent) +{ + const Utils::optional tool = unzipTool(src, dest); + QTC_ASSERT(tool, return false); + const QString workingDirectory = dest.toFileInfo().absoluteFilePath(); + QDir(workingDirectory).mkpath("."); + CheckableMessageBox box(parent); + box.setIcon(QMessageBox::Information); + box.setWindowTitle(tr("Unzipping File")); + box.setText(tr("Unzipping \"%1\" to \"%2\".").arg(src.toUserOutput(), dest.toUserOutput())); + box.setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + box.button(QDialogButtonBox::Ok)->setEnabled(false); + box.setCheckBoxVisible(false); + box.setDetailedText( + tr("Running %1\nin \"%2\".\n\n", "Running in ") + .arg(CommandLine(tool->executable, tool->arguments).toUserOutput(), workingDirectory)); + QProcess process; + process.setProcessChannelMode(QProcess::MergedChannels); + QObject::connect(&process, &QProcess::readyReadStandardOutput, &box, [&box, &process]() { + box.setDetailedText(box.detailedText() + QString::fromUtf8(process.readAllStandardOutput())); + }); + QObject::connect(&process, + QOverload::of(&QProcess::finished), + [&box](int, QProcess::ExitStatus) { + box.button(QDialogButtonBox::Ok)->setEnabled(true); + box.button(QDialogButtonBox::Cancel)->setEnabled(false); + }); + QObject::connect(&box, &QMessageBox::rejected, &process, [&process] { + SynchronousProcess::stopProcess(process); + }); + process.setProgram(tool->executable.toString()); + process.setArguments(tool->arguments); + process.setWorkingDirectory(workingDirectory); + process.start(QProcess::ReadOnly); + box.exec(); + return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0; +} + +} // namespace Utils diff --git a/src/libs/utils/archive.h b/src/libs/utils/archive.h new file mode 100644 index 0000000000..1447b9898a --- /dev/null +++ b/src/libs/utils/archive.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "utils_global.h" + +#include "fileutils.h" + +namespace Utils { + +class QTCREATOR_UTILS_EXPORT Archive +{ + Q_DECLARE_TR_FUNCTIONS(Utils::Archive) +public: + static bool supportsFile(const FilePath &filePath, QString *reason = nullptr); + static bool unarchive(const FilePath &src, const FilePath &dest, QWidget *parent); +}; + +} // namespace Utils diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri index 69db3b63a0..42cab2704d 100644 --- a/src/libs/utils/utils-lib.pri +++ b/src/libs/utils/utils-lib.pri @@ -133,7 +133,8 @@ SOURCES += \ $$PWD/namevaluevalidator.cpp \ $$PWD/camelcasecursor.cpp \ $$PWD/infolabel.cpp \ - $$PWD/overlaywidget.cpp + $$PWD/overlaywidget.cpp \ + $$PWD/archive.cpp HEADERS += \ $$PWD/environmentfwd.h \ @@ -281,7 +282,8 @@ HEADERS += \ $$PWD/namevaluevalidator.h \ $$PWD/camelcasecursor.h \ $$PWD/infolabel.h \ - $$PWD/overlaywidget.h + $$PWD/overlaywidget.h \ + $$PWD/archive.h FORMS += $$PWD/filewizardpage.ui \ $$PWD/projectintropage.ui \ diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index 2c1b098c9e..1724da6e48 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -44,6 +44,8 @@ Project { "ansiescapecodehandler.h", "appmainwindow.cpp", "appmainwindow.h", + "archive.cpp", + "archive.h", "basetreeview.cpp", "basetreeview.h", "benchmarker.cpp", diff --git a/src/plugins/coreplugin/plugindialog.cpp b/src/plugins/coreplugin/plugindialog.cpp index 7bca53412c..03c840eccc 100644 --- a/src/plugins/coreplugin/plugindialog.cpp +++ b/src/plugins/coreplugin/plugindialog.cpp @@ -37,15 +37,10 @@ #include #include -#include -#include -#include +#include #include #include -#include #include -#include -#include #include #include @@ -72,45 +67,13 @@ static bool s_isRestartRequired = false; const char kPath[] = "Path"; const char kApplicationInstall[] = "ApplicationInstall"; -static bool hasLibSuffix(const QString &path) +static bool hasLibSuffix(const FilePath &path) { - return (HostOsInfo().isWindowsHost() && path.endsWith(".dll", Qt::CaseInsensitive)) - || (HostOsInfo().isLinuxHost() && QFileInfo(path).completeSuffix().startsWith(".so")) + return (HostOsInfo().isWindowsHost() && path.endsWith(".dll")) + || (HostOsInfo().isLinuxHost() && path.toFileInfo().completeSuffix().startsWith(".so")) || (HostOsInfo().isMacHost() && path.endsWith(".dylib")); } -static bool isZipFile(const QString &path) -{ - const QList mimeType = mimeTypesForFileName(path); - return anyOf(mimeType, [](const MimeType &mt) { return mt.inherits("application/zip"); }); -} - -struct Tool -{ - FilePath executable; - QStringList arguments; -}; - -static Utils::optional unzipTool(const FilePath &src, const FilePath &dest) -{ - const FilePath unzip = Utils::Environment::systemEnvironment().searchInPath( - Utils::HostOsInfo::withExecutableSuffix("unzip")); - if (!unzip.isEmpty()) - return Tool{unzip, {"-o", src.toString(), "-d", dest.toString()}}; - - const FilePath sevenzip = Utils::Environment::systemEnvironment().searchInPath( - Utils::HostOsInfo::withExecutableSuffix("7z")); - if (!sevenzip.isEmpty()) - return Tool{sevenzip, {"x", QString("-o") + dest.toString(), "-y", src.toString()}}; - - const FilePath cmake = Utils::Environment::systemEnvironment().searchInPath( - Utils::HostOsInfo::withExecutableSuffix("cmake")); - if (!cmake.isEmpty()) - return Tool{cmake, {"-E", "tar", "xvf", src.toString()}}; - - return {}; -} - class SourcePage : public WizardPage { public: @@ -149,21 +112,17 @@ public: bool isComplete() const { - const QString path = field(kPath).toString(); - if (!QFile::exists(path)) { + const auto path = FilePath::fromVariant(field(kPath)); + if (!QFile::exists(path.toString())) { m_info->setText(PluginDialog::tr("File does not exist.")); return false; } if (hasLibSuffix(path)) return true; - if (!isZipFile(path)) { - m_info->setText(PluginDialog::tr("File format not supported.")); - return false; - } - if (!unzipTool({}, {})) { - m_info->setText( - PluginDialog::tr("Could not find unzip, 7z, or cmake executable in PATH.")); + QString error; + if (!Archive::supportsFile(path, &error)) { + m_info->setText(error); return false; } return true; @@ -367,45 +326,6 @@ static bool copyPluginFile(const FilePath &src, const FilePath &dest) return true; } -static bool unzip(const FilePath &src, const FilePath &dest) -{ - const Utils::optional tool = unzipTool(src, dest); - QTC_ASSERT(tool, return false); - const QString workingDirectory = dest.toFileInfo().absoluteFilePath(); - QDir(workingDirectory).mkpath("."); - CheckableMessageBox box(ICore::dialogParent()); - box.setIcon(QMessageBox::Information); - box.setWindowTitle(PluginDialog::tr("Unzipping File")); - box.setText(PluginDialog::tr("Unzipping \"%1\" to \"%2\".") - .arg(src.toUserOutput(), dest.toUserOutput())); - box.setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - box.button(QDialogButtonBox::Ok)->setEnabled(false); - box.setCheckBoxVisible(false); - box.setDetailedText( - PluginDialog::tr("Running %1\nin \"%2\".\n\n", "Running in ") - .arg(CommandLine(tool->executable, tool->arguments).toUserOutput(), workingDirectory)); - QProcess process; - process.setProcessChannelMode(QProcess::MergedChannels); - QObject::connect(&process, &QProcess::readyReadStandardOutput, &box, [&box, &process]() { - box.setDetailedText(box.detailedText() + QString::fromUtf8(process.readAllStandardOutput())); - }); - QObject::connect(&process, - QOverload::of(&QProcess::finished), - [&box](int, QProcess::ExitStatus) { - box.button(QDialogButtonBox::Ok)->setEnabled(true); - box.button(QDialogButtonBox::Cancel)->setEnabled(false); - }); - QObject::connect(&box, &QMessageBox::rejected, &process, [&process] { - SynchronousProcess::stopProcess(process); - }); - process.setProgram(tool->executable.toString()); - process.setArguments(tool->arguments); - process.setWorkingDirectory(workingDirectory); - process.start(QProcess::ReadOnly); - box.exec(); - return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0; -} - void PluginDialog::showInstallWizard() { Wizard wizard(ICore::dialogParent()); @@ -423,11 +343,11 @@ void PluginDialog::showInstallWizard() if (wizard.exec()) { const FilePath path = pluginFilePath(&wizard); const FilePath installPath = pluginInstallPath(&wizard); - if (hasLibSuffix(path.toString())) { + if (hasLibSuffix(path)) { if (copyPluginFile(path, installPath)) updateRestartRequired(); - } else if (isZipFile(path.toString())) { - if (unzip(path, installPath)) + } else if (Archive::supportsFile(path)) { + if (Archive::unarchive(path, installPath, ICore::dialogParent())) updateRestartRequired(); } } -- cgit v1.2.1