From 2eb26d82d818fa13e0a78ef308020fa3909ac8ad Mon Sep 17 00:00:00 2001 From: Katja Marttila Date: Mon, 20 Mar 2023 10:41:22 +0200 Subject: Fix custom error message in Execute operation If the program execution failed the custom message was not always shown. Fixed so that custom error message given in the addOperation is shown instead of the general message. Task-number: QTIFW-3007 Change-Id: I811cf0a3d9efaa2cbedd72a7c1e3097536501f5e Reviewed-by: Arttu Tarkiainen --- src/libs/installer/elevatedexecuteoperation.cpp | 34 ++++++++++++++----------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/libs/installer/elevatedexecuteoperation.cpp b/src/libs/installer/elevatedexecuteoperation.cpp index 5db0c887a..59f9f22bf 100644 --- a/src/libs/installer/elevatedexecuteoperation.cpp +++ b/src/libs/installer/elevatedexecuteoperation.cpp @@ -1,6 +1,6 @@ /************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -65,10 +65,12 @@ public: private: bool needsRerunWithReplacedVariables(QStringList &arguments, const OperationType type); + void setErrorMessage(const QString &message); - +private: QProcessWrapper *process; bool showStandardError; + QString m_customErrorMessage; }; ElevatedExecuteOperation::ElevatedExecuteOperation(PackageManagerCore *core) @@ -120,13 +122,12 @@ int ElevatedExecuteOperation::Private::run(QStringList &arguments, const Operati args.removeAll(workingDirectoryArgument); } - QString customErrorMessage; QStringList filteredCustomErrorMessage = args.filter(QLatin1String("errormessage="), Qt::CaseInsensitive); if (!filteredCustomErrorMessage.isEmpty()) { QString customErrorMessageArgument = filteredCustomErrorMessage.at(0); - customErrorMessage = customErrorMessageArgument; - customErrorMessage.replace(QLatin1String("errormessage="), QString(), Qt::CaseInsensitive); + m_customErrorMessage = customErrorMessageArgument; + m_customErrorMessage.replace(QLatin1String("errormessage="), QString(), Qt::CaseInsensitive); args.removeAll(customErrorMessageArgument); } @@ -156,7 +157,8 @@ int ElevatedExecuteOperation::Private::run(QStringList &arguments, const Operati const bool success = QProcessWrapper::startDetached(args.front(), args.mid(1)); if (!success) { q->setError(UserDefinedError); - q->setErrorString(tr("Cannot start detached: \"%1\"").arg(callstr)); + setErrorMessage(tr("Cannot start detached: \"%1\"").arg(callstr)); + returnValue = Error; } return returnValue; @@ -201,8 +203,7 @@ int ElevatedExecuteOperation::Private::run(QStringList &arguments, const Operati int returnValue = NoError; if (!success) { q->setError(UserDefinedError); - //TODO: pass errorString() through the wrapper */ - q->setErrorString(tr("Cannot start: \"%1\": %2").arg(callstr, + setErrorMessage(tr("Cannot start: \"%1\": %2").arg(callstr, process->errorString())); if (!needsRerunWithReplacedVariables(arguments, type)) { returnValue = Error; @@ -228,17 +229,13 @@ int ElevatedExecuteOperation::Private::run(QStringList &arguments, const Operati if (process->exitStatus() == QProcessWrapper::CrashExit) { q->setError(UserDefinedError); - q->setErrorString(tr("Program crashed: \"%1\"").arg(callstr)); + setErrorMessage(tr("Program crashed: \"%1\"").arg(callstr)); returnValue = Error; } else if (!allowedExitCodes.contains(process->exitCode()) && returnValue != NeedsRerun) { if (!needsRerunWithReplacedVariables(arguments, type)) { q->setError(UserDefinedError); - if (customErrorMessage.isEmpty()) { - q->setErrorString(tr("Execution failed (Unexpected exit code: %1): \"%2\"") - .arg(QString::number(process->exitCode()), callstr)); - } else { - q->setErrorString(customErrorMessage); - } + setErrorMessage(tr("Execution failed (Unexpected exit code: %1): \"%2\"") + .arg(QString::number(process->exitCode()), callstr)); returnValue = Error; } else { returnValue = NeedsRerun; @@ -275,6 +272,13 @@ bool ElevatedExecuteOperation::Private::needsRerunWithReplacedVariables(QStringL return rerun; } +void ElevatedExecuteOperation::Private::setErrorMessage(const QString &message) +{ + if (m_customErrorMessage.isEmpty()) + q->setErrorString(message); + else + q->setErrorString(m_customErrorMessage); +} /*! Cancels the ElevatedExecuteOperation. This methods tries to terminate the process gracefully by calling QProcessWrapper::terminate. After 10 seconds, the process gets killed. -- cgit v1.2.3 From 686f93362ca3495b92b584ecb99b63662f6213d6 Mon Sep 17 00:00:00 2001 From: Katja Marttila Date: Tue, 7 Mar 2023 13:17:59 +0200 Subject: Fix dependency resolution error In GUI, toggling between updater view, packagemanager view and updater view could cause impossible dependency resolution error, or wrong components to be updated. There are two component lists, one for updater and one for package manager. Same component can exist in both list with different pointers. m_componentByNameHash contains a quick lookups for the components - as the component pointers change between updater and package manager the list needs to be cleared between each updater/package manager toggle so that correct component is searched. Task-number: QTIFW-3001 Change-Id: Ia42370a286c45d831864ec632a6958f66209a4cd Reviewed-by: Arttu Tarkiainen --- src/libs/installer/packagemanagercore.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp index c598e6c52..85beeb727 100644 --- a/src/libs/installer/packagemanagercore.cpp +++ b/src/libs/installer/packagemanagercore.cpp @@ -3743,6 +3743,7 @@ bool PackageManagerCore::isUninstaller() const void PackageManagerCore::setUpdater() { d->m_magicBinaryMarker = BinaryContent::MagicUpdaterMarker; + d->m_componentByNameHash.clear(); emit installerBinaryMarkerChanged(d->m_magicBinaryMarker); } @@ -3763,6 +3764,7 @@ bool PackageManagerCore::isUpdater() const void PackageManagerCore::setPackageManager() { d->m_magicBinaryMarker = BinaryContent::MagicPackageManagerMarker; + d->m_componentByNameHash.clear(); emit installerBinaryMarkerChanged(d->m_magicBinaryMarker); } -- cgit v1.2.3 From e07cbae2cc1ae113fea71d0e6da6bcee148a0055 Mon Sep 17 00:00:00 2001 From: Katja Marttila Date: Mon, 13 Mar 2023 15:53:41 +0200 Subject: Add more verbose when archive download fails Occasionally installer might throw "Cannot download archive" messages for unknown reason. Adding more detailed verbose to catch the root cause. Also trying to create a parent folder when starting to download an reopening the file just in case. Task-number: QTBUG-110684 Change-Id: I8bc4fc31371043e1f9eae8f7d9779ab434221ff3 Reviewed-by: Arttu Tarkiainen --- src/libs/kdtools/filedownloader.cpp | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/libs/kdtools/filedownloader.cpp b/src/libs/kdtools/filedownloader.cpp index 2510dc4c8..6152811aa 100644 --- a/src/libs/kdtools/filedownloader.cpp +++ b/src/libs/kdtools/filedownloader.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) +** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -1483,21 +1484,35 @@ void KDUpdater::HttpDownloader::startDownload(const QUrl &url) void (QNetworkReply::*errorSignal)(QNetworkReply::NetworkError) = &QNetworkReply::error; connect(d->http, errorSignal, this, &HttpDownloader::httpError); + bool fileOpened = false; if (d->destFileName.isEmpty()) { QTemporaryFile *file = new QTemporaryFile(this); - file->open(); + fileOpened = file->open(); d->destination = file; } else { d->destination = new QFile(d->destFileName, this); - d->destination->open(QIODevice::ReadWrite | QIODevice::Truncate); + fileOpened = d->destination->open(QIODevice::ReadWrite | QIODevice::Truncate); } - - if (!d->destination->isOpen()) { - const QString error = d->destination->errorString(); - const QString fileName = d->destination->fileName(); - d->shutDown(); - setDownloadAborted(tr("Cannot download %1. Cannot create file \"%2\": %3").arg( - url.toString(), fileName, error)); + if (!fileOpened) { + qCWarning(QInstaller::lcInstallerInstallLog).nospace() << "Failed to open file " << d->destFileName + << ": "<destination->errorString() << ". Trying again."; + QFileInfo fileInfo; + fileInfo.setFile(d->destination->fileName()); + if (!QDir().mkpath(fileInfo.absolutePath())) { + setDownloadAborted(tr("Cannot download %1. Cannot create directory for \"%2\"").arg( + url.toString(), fileInfo.filePath())); + } else { + fileOpened = d->destination->open(QIODevice::ReadWrite | QIODevice::Truncate); + if (fileOpened) + return; + if (d->destination->exists()) + qCWarning(QInstaller::lcInstallerInstallLog) << "File exists but installer is unable to open it."; + else + qCWarning(QInstaller::lcInstallerInstallLog) << "File does not exist."; + d->shutDown(); + setDownloadAborted(tr("Cannot download %1. Cannot create file \"%2\": %3").arg( + url.toString(), d->destination->fileName(), d->destination->errorString())); + } } } -- cgit v1.2.3 From f25efeed5aeadbe2f477a4330d29da52617db083 Mon Sep 17 00:00:00 2001 From: Katja Marttila Date: Fri, 8 Apr 2016 10:44:48 +0300 Subject: Fix showSettingsButton functionality showSettingsButton() called from control script had no effect. Fixed it so that if showSettingsButton will overwrite the IFW decision to show the settings button. Change-Id: Ia08c03cc13db58168fd371f230517bcc83ee0e12 Task-number: QTIFW-810 Reviewed-by: Arttu Tarkiainen Reviewed-by: Leena Miettinen --- doc/scripting-api/gui.qdoc | 6 +++- src/libs/installer/packagemanagergui.cpp | 47 ++++++++++++++++++++++---------- src/libs/installer/packagemanagergui.h | 1 + src/sdk/tabcontroller.cpp | 2 +- 4 files changed, 39 insertions(+), 17 deletions(-) diff --git a/doc/scripting-api/gui.qdoc b/doc/scripting-api/gui.qdoc index 7047cfe0e..7b9e22328 100644 --- a/doc/scripting-api/gui.qdoc +++ b/doc/scripting-api/gui.qdoc @@ -121,7 +121,11 @@ /*! \qmlmethod void gui::showSettingsButton(boolean show) - Shows the \uicontrol Settings button if \a show is \c true. + Shows the \uicontrol Settings button if \a show is \c true. This function + overrides the visibility of the \uicontrol Settings button in all pages. Be + careful when showing the settings button so that users cannot change network + settings while downloading data in the background. Changing the + settings will restart the wizard and switch back to the introduction page. */ /*! diff --git a/src/libs/installer/packagemanagergui.cpp b/src/libs/installer/packagemanagergui.cpp index 9cdea0356..a83c3a094 100644 --- a/src/libs/installer/packagemanagergui.cpp +++ b/src/libs/installer/packagemanagergui.cpp @@ -210,8 +210,9 @@ Q_DECLARE_METATYPE(DynamicInstallerPage*) class PackageManagerGui::Private { public: - Private() - : m_currentId(-1) + Private(PackageManagerGui *qq) + : q(qq) + , m_currentId(-1) , m_modified(false) , m_autoSwitchPage(true) , m_showSettingsButton(false) @@ -235,6 +236,20 @@ public: QLatin1String("unknown button")); } + void showSettingsButton(bool show) + { + if (m_showSettingsButton == show) + return; + q->setOption(QWizard::HaveCustomButton1, show); + q->setButtonText(QWizard::CustomButton1, tr("&Settings")); + q->button(QWizard::CustomButton1)->setToolTip( + PackageManagerGui::tr("Specify proxy settings and configure repositories for add-on components.")); + + q->updateButtonLayout(); + m_showSettingsButton = show; + } + + PackageManagerGui *q; int m_currentId; bool m_modified; bool m_autoSwitchPage; @@ -294,7 +309,7 @@ public: */ PackageManagerGui::PackageManagerGui(PackageManagerCore *core, QWidget *parent) : QWizard(parent) - , d(new Private) + , d(new Private(this)) , m_core(core) { if (m_core->isInstaller()) @@ -1029,16 +1044,18 @@ void PackageManagerGui::showFinishedPage() */ void PackageManagerGui::showSettingsButton(bool show) { - if (d->m_showSettingsButton == show) - return; - - d->m_showSettingsButton = show; - setOption(QWizard::HaveCustomButton1, show); - setButtonText(QWizard::CustomButton1, tr("&Settings")); - button(QWizard::CustomButton1)->setToolTip( - PackageManagerGui::tr("Specify proxy settings and configure repositories for add-on components.")); + m_core->setValue(QLatin1String("ShowSettingsButton"), QString::number(show)); + d->showSettingsButton(show); +} - updateButtonLayout(); +/*! + Shows the \uicontrol Settings button if \a request is \c true. If script has + set the settings button visibility, this function has no effect. +*/ +void PackageManagerGui::requestSettingsButtonByInstaller(bool request) +{ + if (m_core->value(QLatin1String("ShowSettingsButton")).isEmpty()) + d->showSettingsButton(request); } /*! @@ -1824,7 +1841,7 @@ void IntroductionPage::setUpdater(bool value) { if (value) { entering(); - gui()->showSettingsButton(true); + gui()->requestSettingsButtonByInstaller(true); packageManagerCore()->setUpdater(); emit packageManagerCoreTypeChanged(); @@ -1836,7 +1853,7 @@ void IntroductionPage::setUninstaller(bool value) { if (value) { entering(); - gui()->showSettingsButton(true); + gui()->requestSettingsButtonByInstaller(true); packageManagerCore()->setUninstaller(); emit packageManagerCoreTypeChanged(); @@ -1848,7 +1865,7 @@ void IntroductionPage::setPackageManager(bool value) { if (value) { entering(); - gui()->showSettingsButton(true); + gui()->requestSettingsButtonByInstaller(true); packageManagerCore()->setPackageManager(); emit packageManagerCoreTypeChanged(); diff --git a/src/libs/installer/packagemanagergui.h b/src/libs/installer/packagemanagergui.h index 0b804e934..764c31375 100644 --- a/src/libs/installer/packagemanagergui.h +++ b/src/libs/installer/packagemanagergui.h @@ -84,6 +84,7 @@ public: bool isButtonEnabled(int wizardButton); void showSettingsButton(bool show); + void requestSettingsButtonByInstaller(bool request); void setSettingsButtonEnabled(bool enable); void updateButtonLayout(); diff --git a/src/sdk/tabcontroller.cpp b/src/sdk/tabcontroller.cpp index cb3242841..6edc758a5 100644 --- a/src/sdk/tabcontroller.cpp +++ b/src/sdk/tabcontroller.cpp @@ -222,7 +222,7 @@ void TabController::onCurrentIdChanged(int newId) { if (d->m_gui) { if (PackageManagerPage *page = qobject_cast(d->m_gui->page(newId))) - d->m_gui->showSettingsButton(page->settingsButtonRequested()); + d->m_gui->requestSettingsButtonByInstaller(page->settingsButtonRequested()); } } -- cgit v1.2.3