diff options
Diffstat (limited to 'src/libs/installer')
25 files changed, 257 insertions, 68 deletions
diff --git a/src/libs/installer/binaryformat.cpp b/src/libs/installer/binaryformat.cpp index 9a46095ce..3e7dd5a2a 100644 --- a/src/libs/installer/binaryformat.cpp +++ b/src/libs/installer/binaryformat.cpp @@ -158,7 +158,7 @@ bool Resource::open() if (isOpen()) return false; - if (!m_file.open(QIODevice::ReadOnly)) { + if (!m_file.open(QIODevice::ReadOnly | QIODevice::Unbuffered)) { setErrorString(m_file.errorString()); return false; } diff --git a/src/libs/installer/componentselectionpage_p.cpp b/src/libs/installer/componentselectionpage_p.cpp index 88ea86b8a..84349e4ad 100644 --- a/src/libs/installer/componentselectionpage_p.cpp +++ b/src/libs/installer/componentselectionpage_p.cpp @@ -147,6 +147,10 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP m_treeViewVLayout->addWidget(m_treeView, 3); + // force a recalculation of components to install to keep the state correct + connect(q, &ComponentSelectionPage::left, + m_core, &PackageManagerCore::clearComponentsToInstallCalculated); + m_mainHLayout = new QHBoxLayout(q); m_mainHLayout->addLayout(m_treeViewVLayout, 3); m_mainHLayout->addLayout(m_descriptionVLayout, 2); diff --git a/src/libs/installer/createlocalrepositoryoperation.cpp b/src/libs/installer/createlocalrepositoryoperation.cpp index a2f7806a3..0eabc8c35 100644 --- a/src/libs/installer/createlocalrepositoryoperation.cpp +++ b/src/libs/installer/createlocalrepositoryoperation.cpp @@ -38,6 +38,7 @@ #include "lib7z_facade.h" #include "packagemanagercore.h" #include "productkeycheck.h" +#include "constants.h" #include "updateoperations.h" @@ -183,6 +184,23 @@ bool CreateLocalRepositoryOperation::performOperation() } setValue(QLatin1String("createddir"), mkDirOp.value(QLatin1String("createddir"))); +#if QT_VERSION >= QT_VERSION_CHECK(5,10,0) + // Internal changes to QTemporaryFile break copying Qt resources through + // QInstaller::RemoteFileEngine. We do not register resources to be handled by + // RemoteFileEngine, instead copying using 5.9 succeeded because QFile::copy() + // creates a QTemporaryFile object internally that is handled by the remote engine. + // + // This will not work with Qt 5.10 and above as QTemporaryFile introduced a new + // rename() implementation that explicitly uses its own QTemporaryFileEngine. + // + // Fail and return early if we are working on an elevated permission directory. + if (core && !core->directoryWritable(repoPath)) { + setError(UserDefinedError); + setErrorString(tr("Creating local repository into elevated permissions " + "directory: %1 is not supported.").arg(repoPath)); + return false; + } +#endif // copy the whole meta data into local repository CopyDirectoryOperation copyDirOp(core); copyDirOp.setArguments(QStringList() << QLatin1String(":/metadata/") << repoPath); diff --git a/src/libs/installer/fileutils.cpp b/src/libs/installer/fileutils.cpp index 4347c67da..18c5f90fd 100644 --- a/src/libs/installer/fileutils.cpp +++ b/src/libs/installer/fileutils.cpp @@ -286,7 +286,7 @@ void QInstaller::removeSystemGeneratedFiles(const QString &path) { if (path.isEmpty()) return; -#if defined Q_OS_OSX +#if defined Q_OS_MACOS QFile::remove(path + QLatin1String("/.DS_Store")); #elif defined Q_OS_WIN QFile::remove(path + QLatin1String("/Thumbs.db")); @@ -572,7 +572,7 @@ quint64 QInstaller::fileSize(const QFileInfo &info) bool QInstaller::isInBundle(const QString &path, QString *bundlePath) { -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS QFileInfo fi = QFileInfo(path).absoluteFilePath(); while (!fi.isRoot()) { if (fi.isBundle()) { diff --git a/src/libs/installer/messageboxhandler.cpp b/src/libs/installer/messageboxhandler.cpp index 286009e21..28e09df44 100644 --- a/src/libs/installer/messageboxhandler.cpp +++ b/src/libs/installer/messageboxhandler.cpp @@ -381,7 +381,7 @@ static QMessageBox::StandardButton showNewMessageBox(QWidget *parent, QMessageBo msgBox.setDefaultButton(button); } } -#if defined(Q_OS_OSX) +#if defined(Q_OS_MACOS) msgBox.setWindowModality(Qt::WindowModal); #endif if (msgBox.exec() == -1) diff --git a/src/libs/installer/metadatajob.cpp b/src/libs/installer/metadatajob.cpp index c69fda3d0..7d7b46e72 100644 --- a/src/libs/installer/metadatajob.cpp +++ b/src/libs/installer/metadatajob.cpp @@ -326,10 +326,21 @@ void MetadataJob::xmlTaskFinished() QHash<QString, QPair<Repository, Repository> > update; update.insert(QLatin1String("replace"), qMakePair(original, replacement)); + if (s.updateRepositoryCategories(update) == Settings::UpdatesApplied) + qDebug() << "Repository categories updated."; + if (s.updateDefaultRepositories(update) == Settings::UpdatesApplied || s.updateUserRepositories(update) == Settings::UpdatesApplied) { - if (m_core->isMaintainer()) + if (m_core->isMaintainer()) { + bool gainedAdminRights = false; + if (!m_core->directoryWritable(m_core->value(scTargetDir))) { + m_core->gainAdminRights(); + gainedAdminRights = true; + } m_core->writeMaintenanceConfigFiles(); + if (gainedAdminRights) + m_core->dropAdminRights(); + } } } status = XmlDownloadRetry; @@ -716,8 +727,16 @@ MetadataJob::Status MetadataJob::parseUpdatesXml(const QList<FileTaskResult> &re return XmlDownloadRetry; } } else if (s.updateDefaultRepositories(repositoryUpdates) == Settings::UpdatesApplied) { - if (m_core->isMaintainer()) + if (m_core->isMaintainer()) { + bool gainedAdminRights = false; + if (!m_core->directoryWritable(m_core->value(scTargetDir))) { + m_core->gainAdminRights(); + gainedAdminRights = true; + } m_core->writeMaintenanceConfigFiles(); + if (gainedAdminRights) + m_core->dropAdminRights(); + } m_metaFromDefaultRepositories.clear(); QFile::remove(result.target()); return XmlDownloadRetry; diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp index 4a7f42621..c154edf76 100644 --- a/src/libs/installer/packagemanagercore.cpp +++ b/src/libs/installer/packagemanagercore.cpp @@ -422,9 +422,7 @@ void PackageManagerCore::writeMaintenanceTool() d->writeMaintenanceTool(d->m_performedOperationsOld + d->m_performedOperationsCurrentSession); bool gainedAdminRights = false; - QTemporaryFile tempAdminFile(d->targetDir() - + QLatin1String("/testjsfdjlkdsjflkdsjfldsjlfds") + QString::number(qrand() % 1000)); - if (!tempAdminFile.open() || !tempAdminFile.isWritable()) { + if (!directoryWritable(d->targetDir())) { gainAdminRights(); gainedAdminRights = true; } @@ -539,6 +537,14 @@ void PackageManagerCore::componentsToInstallNeedsRecalculation() } /*! + \sa {installer::clearComponentsToInstallCalculated}{installer.clearComponentsToInstallCalculated} + */ +void PackageManagerCore::clearComponentsToInstallCalculated() +{ + d->m_componentsToInstallCalculated = false; +} + +/*! \sa {installer::autoAcceptMessageBoxes}{installer.autoAcceptMessageBoxes} \sa autoRejectMessageBoxes(), setMessageBoxAutomaticAnswer() */ @@ -665,7 +671,7 @@ int PackageManagerCore::downloadNeededArchives(double partProgressSize) } /*! - Returns \c true if essential component update is found. + Returns \c true if an essential component update is found. */ bool PackageManagerCore::foundEssentialUpdate() const { @@ -673,7 +679,7 @@ bool PackageManagerCore::foundEssentialUpdate() const } /*! - Sets the value of \a foundEssentialUpdate, defaults \c true. + Sets the value of \a foundEssentialUpdate, defaults to \c true. */ void PackageManagerCore::setFoundEssentialUpdate(bool foundEssentialUpdate) { @@ -1111,8 +1117,7 @@ void PackageManagerCore::networkSettingsChanged() if (isMaintainer() ) { bool gainedAdminRights = false; - QTemporaryFile tempAdminFile(d->targetDir() + QStringLiteral("/XXXXXX")); - if (!tempAdminFile.open() || !tempAdminFile.isWritable()) { + if (!directoryWritable(d->targetDir())) { gainAdminRights(); gainedAdminRights = true; } @@ -1580,6 +1585,16 @@ Component *PackageManagerCore::componentByName(const QString &name, const QList< return nullptr; } +bool PackageManagerCore::directoryWritable(const QString &path) const +{ + return d->directoryWritable(path); +} + +bool PackageManagerCore::subdirectoriesWritable(const QString &path) const +{ + return d->subdirectoriesWritable(path); +} + /*! Returns a list of components that are marked for installation. The list can be empty. @@ -2186,7 +2201,7 @@ QString PackageManagerCore::findLibrary(const QString &name, const QStringList & #if defined(Q_OS_WIN) return findPath(QString::fromLatin1("%1.lib").arg(name), findPaths); #else -#if defined(Q_OS_OSX) +#if defined(Q_OS_MACOS) if (findPaths.isEmpty()) { findPaths.push_back(QLatin1String("/lib")); findPaths.push_back(QLatin1String("/usr/lib")); diff --git a/src/libs/installer/packagemanagercore.h b/src/libs/installer/packagemanagercore.h index 4fa2f2554..f4240fde0 100644 --- a/src/libs/installer/packagemanagercore.h +++ b/src/libs/installer/packagemanagercore.h @@ -121,6 +121,9 @@ public: static Component *componentByName(const QString &name, const QList<Component *> &components); + bool directoryWritable(const QString &path) const; + bool subdirectoriesWritable(const QString &path) const; + bool fetchLocalPackagesTree(); LocalPackagesHash localInstalledPackages(); @@ -290,6 +293,7 @@ public Q_SLOTS: void setCompleteUninstallation(bool complete); void cancelMetaInfoJob(); void componentsToInstallNeedsRecalculation(); + void clearComponentsToInstallCalculated(); Q_SIGNALS: void aboutCalculateComponentsToInstall() const; diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp index 29c3fb03a..308bfa097 100644 --- a/src/libs/installer/packagemanagercore_p.cpp +++ b/src/libs/installer/packagemanagercore_p.cpp @@ -345,6 +345,27 @@ QString PackageManagerCorePrivate::targetDir() const return m_core->value(scTargetDir); } +bool PackageManagerCorePrivate::directoryWritable(const QString &path) const +{ + QTemporaryFile tempFile(path + QStringLiteral("/tempFile") + QString::number(qrand() % 1000)); + if (!tempFile.open() || !tempFile.isWritable()) + return false; + else + return true; +} + +bool PackageManagerCorePrivate::subdirectoriesWritable(const QString &path) const +{ + // Iterate over target directory subdirectories for writing access + QDirIterator iterator(path, QDir::AllDirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); + while (iterator.hasNext()) { + QTemporaryFile tempFile(iterator.next() + QLatin1String("/tempFile")); + if (!tempFile.open() || !tempFile.isWritable()) + return false; + } + return true; +} + QString PackageManagerCorePrivate::configurationFileName() const { return m_core->value(scTargetConfigurationFile, QLatin1String("components.xml")); @@ -569,7 +590,7 @@ void PackageManagerCorePrivate::initialize(const QHash<QString, QString> ¶ms #endif if (!m_core->isInstaller()) { -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS readMaintenanceConfigFiles(QCoreApplication::applicationDirPath() + QLatin1String("/../../..")); #else readMaintenanceConfigFiles(QCoreApplication::applicationDirPath()); @@ -697,7 +718,7 @@ Operation *PackageManagerCorePrivate::takeOwnedOperation(Operation *operation) QString PackageManagerCorePrivate::maintenanceToolName() const { QString filename = m_data.settings().maintenanceToolName(); -#if defined(Q_OS_OSX) +#if defined(Q_OS_MACOS) if (QInstaller::isInBundle(QCoreApplication::applicationDirPath())) filename += QLatin1String(".app/Contents/MacOS/") + filename; #elif defined(Q_OS_WIN) @@ -1013,7 +1034,7 @@ void PackageManagerCorePrivate::writeMaintenanceToolBinary(QFile *const input, q qDebug() << "Writing maintenance tool:" << maintenanceToolRenamedName; ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(tr("Writing maintenance tool.")); - QTemporaryFile out; + QFile out(generateTemporaryFileName()); QInstaller::openForWrite(&out); // throws an exception in case of error if (!input->seek(0)) @@ -1023,7 +1044,7 @@ void PackageManagerCorePrivate::writeMaintenanceToolBinary(QFile *const input, q if (writeBinaryLayout) { QDir resourcePath(QFileInfo(maintenanceToolRenamedName).dir()); -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS if (!resourcePath.path().endsWith(QLatin1String("Contents/MacOS"))) throw Error(tr("Maintenance tool is not a bundle")); resourcePath.cdUp(); @@ -1031,7 +1052,7 @@ void PackageManagerCorePrivate::writeMaintenanceToolBinary(QFile *const input, q #endif // It's a bit odd to have only the magic in the data file, but this simplifies // other code a lot (since installers don't have any appended data either) - QTemporaryFile dataOut; + QFile dataOut(generateTemporaryFileName()); QInstaller::openForWrite(&dataOut); QInstaller::appendInt64(&dataOut, 0); // operations start QInstaller::appendInt64(&dataOut, 0); // operations end @@ -1049,10 +1070,9 @@ void PackageManagerCorePrivate::writeMaintenanceToolBinary(QFile *const input, q } if (!dataOut.rename(resourcePath.filePath(QLatin1String("installer.dat")))) { - throw Error(tr("Cannot write maintenance tool data to %1: %2").arg(out.fileName(), - out.errorString())); + throw Error(tr("Cannot write maintenance tool data to %1: %2").arg(dataOut.fileName(), + dataOut.errorString())); } - dataOut.setAutoRemove(false); dataOut.setPermissions(dataOut.permissions() | QFile::WriteUser | QFile::ReadGroup | QFile::ReadOther); } @@ -1077,6 +1097,11 @@ void PackageManagerCorePrivate::writeMaintenanceToolBinary(QFile *const input, q } else { qDebug() << "Failed to write permissions for maintenance tool."; } + + if (out.exists() && !out.remove()) { + qWarning() << tr("Cannot remove temporary data file \"%1\": %2") + .arg(out.fileName(), out.errorString()); + } } void PackageManagerCorePrivate::writeMaintenanceToolBinaryData(QFileDevice *output, QFile *const input, @@ -1144,16 +1169,14 @@ void PackageManagerCorePrivate::writeMaintenanceToolBinaryData(QFileDevice *outp void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOperations) { bool gainedAdminRights = false; - QTemporaryFile tempAdminFile(targetDir() + QLatin1String("/testjsfdjlkdsjflkdsjfldsjlfds") - + QString::number(qrand() % 1000)); - if (!tempAdminFile.open() || !tempAdminFile.isWritable()) { + if (!directoryWritable(targetDir())) { m_core->gainAdminRights(); gainedAdminRights = true; } const QString targetAppDirPath = QFileInfo(maintenanceToolName()).path(); if (!QDir().exists(targetAppDirPath)) { - // create the directory containing the maintenance tool (like a bundle structure on OS X...) + // create the directory containing the maintenance tool (like a bundle structure on macOS...) Operation *op = createOwnedOperation(QLatin1String("Mkdir")); op->setArguments(QStringList() << targetAppDirPath); performOperationThreaded(op, Backup); @@ -1161,7 +1184,7 @@ void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOper performedOperations.append(takeOwnedOperation(op)); } -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS // if it is a bundle, we need some stuff in it... const QString sourceAppDirPath = QCoreApplication::applicationDirPath(); if (isInstaller() && QInstaller::isInBundle(sourceAppDirPath)) { @@ -1321,7 +1344,7 @@ void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOper // On Mac data is always in a separate file so that the binary can be signed. // On other platforms data is in separate file only after install so that the // maintenancetool sign does not break. -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS QDir dataPath(QFileInfo(binaryName).dir()); dataPath.cdUp(); dataPath.cd(QLatin1String("Resources")); @@ -1336,7 +1359,7 @@ void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOper newBinaryWritten = true; QFile tmp(binaryName); QInstaller::openForRead(&tmp); -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS writeMaintenanceToolBinary(&tmp, tmp.size(), true); #else writeMaintenanceToolBinary(&tmp, layout.endOfBinaryContent - layout.binaryContentSize, true); @@ -1348,7 +1371,7 @@ void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOper m_core->setValue(QLatin1String("installedOperationAreSorted"), QLatin1String("true")); try { - QTemporaryFile file; + QFile file(generateTemporaryFileName()); QInstaller::openForWrite(&file); writeMaintenanceToolBinaryData(&file, &input, performedOperations, layout); QInstaller::appendInt64(&file, BinaryContent::MagicCookieDat); @@ -1363,7 +1386,6 @@ void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOper throw Error(tr("Cannot write maintenance tool binary data to %1: %2") .arg(file.fileName(), file.errorString())); } - file.setAutoRemove(false); file.setPermissions(file.permissions() | QFile::WriteUser | QFile::ReadGroup | QFile::ReadOther); } catch (const Error &/*error*/) { @@ -1455,8 +1477,7 @@ bool PackageManagerCorePrivate::runInstaller() } } } else if (QDir(target).exists()) { - QTemporaryFile tempAdminFile(target + QLatin1String("/adminrights")); - if (!tempAdminFile.open() || !tempAdminFile.isWritable()) + if (!directoryWritable(targetDir())) adminRightsGained = m_core->gainAdminRights(); } @@ -1536,8 +1557,8 @@ bool PackageManagerCorePrivate::runInstaller() Operation *createRepo = createOwnedOperation(QLatin1String("CreateLocalRepository")); if (createRepo) { QString binaryFile = QCoreApplication::applicationFilePath(); -#ifdef Q_OS_OSX - // The installer binary on OSX does not contain the binary content, it's put into +#ifdef Q_OS_MACOS + // The installer binary on macOS does not contain the binary content, it's put into // the resources folder as separate file. Adjust the actual binary path. No error // checking here since we will fail later while reading the binary content. QDir resourcePath(QFileInfo(binaryFile).dir()); @@ -1622,10 +1643,16 @@ bool PackageManagerCorePrivate::runPackageUpdater() //to have some progress for the cleanup/write component.xml step ProgressCoordinator::instance()->addReservePercentagePoints(1); +#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS) // check if we need admin rights and ask before the action happens - if (!QTemporaryFile(targetDir() + QStringLiteral("/XXXXXX")).open()) + // on Linux and macOS also check target directory subdirectories + if (!directoryWritable(targetDir()) || !subdirectoriesWritable(targetDir())) adminRightsGained = m_core->gainAdminRights(); - +#else + // check if we need admin rights and ask before the action happens + if (!directoryWritable(targetDir())) + adminRightsGained = m_core->gainAdminRights(); +#endif const QList<Component *> componentsToInstall = m_core->orderedComponentsToInstall(); qDebug() << "Install size:" << componentsToInstall.size() << "components"; @@ -1792,8 +1819,7 @@ bool PackageManagerCorePrivate::runUninstaller() setStatus(PackageManagerCore::Running); // check if we need to run elevated and ask before the action happens - QTemporaryFile tempAdminFile(targetDir() + QLatin1String("/adminrights")); - if (!tempAdminFile.open() || !tempAdminFile.isWritable()) + if (!directoryWritable(targetDir())) adminRightsGained = m_core->gainAdminRights(); OperationList undoOperations = m_performedOperationsOld; @@ -2005,7 +2031,7 @@ void PackageManagerCorePrivate::deleteMaintenanceTool() // every other platform has no problem if we just delete ourselves now QFile maintenanceTool(QFileInfo(installerBinaryPath()).absoluteFilePath()); maintenanceTool.remove(); -# ifdef Q_OS_OSX +# ifdef Q_OS_MACOS if (QInstaller::isInBundle(installerBinaryPath())) { const QLatin1String cdUp("/../../.."); removeDirectoryThreaded(QFileInfo(installerBinaryPath() + cdUp).absoluteFilePath()); diff --git a/src/libs/installer/packagemanagercore_p.h b/src/libs/installer/packagemanagercore_p.h index e0817c573..3e8f831a3 100644 --- a/src/libs/installer/packagemanagercore_p.h +++ b/src/libs/installer/packagemanagercore_p.h @@ -92,6 +92,9 @@ public: QString targetDir() const; QString registerPath(); + bool directoryWritable(const QString &path) const; + bool subdirectoriesWritable(const QString &path) const; + QString maintenanceToolName() const; QString installerBinaryPath() const; diff --git a/src/libs/installer/packagemanagercoredata.cpp b/src/libs/installer/packagemanagercoredata.cpp index 41c6f111c..599352fb9 100644 --- a/src/libs/installer/packagemanagercoredata.cpp +++ b/src/libs/installer/packagemanagercoredata.cpp @@ -57,7 +57,7 @@ PackageManagerCoreData::PackageManagerCoreData(const QHash<QString, QString> &va #ifdef Q_OS_WIN m_variables.insert(QLatin1String("os"), QLatin1String("win")); -#elif defined(Q_OS_OSX) +#elif defined(Q_OS_MACOS) m_variables.insert(QLatin1String("os"), QLatin1String("mac")); #elif defined(Q_OS_LINUX) m_variables.insert(QLatin1String("os"), QLatin1String("x11")); @@ -110,10 +110,8 @@ void PackageManagerCoreData::setDynamicPredefinedVariables() TCHAR buffer[MAX_PATH + 1] = { 0 }; SHGetFolderPath(nullptr, CSIDL_PROGRAM_FILES, nullptr, 0, buffer); dir = QString::fromWCharArray(buffer); -#elif defined (Q_OS_OSX) - dir = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).value(1); - if (dir.isEmpty()) - dir = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).value(0); +#elif defined (Q_OS_MACOS) + dir = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).value(0); #endif m_variables.insert(QLatin1String("ApplicationsDir"), dir); diff --git a/src/libs/installer/packagemanagergui.cpp b/src/libs/installer/packagemanagergui.cpp index db1b99d3f..934570ae1 100644 --- a/src/libs/installer/packagemanagergui.cpp +++ b/src/libs/installer/packagemanagergui.cpp @@ -305,7 +305,7 @@ PackageManagerGui::PackageManagerGui(PackageManagerCore *core, QWidget *parent) setWindowTitle(tr("Maintain %1").arg(m_core->value(scTitle))); setWindowFlags(windowFlags() &~ Qt::WindowContextHelpButtonHint); -#ifndef Q_OS_OSX +#ifndef Q_OS_MACOS setWindowIcon(QIcon(m_core->settings().installerWindowIcon())); #else setPixmap(QWizard::BackgroundPixmap, m_core->settings().background()); @@ -408,7 +408,7 @@ PackageManagerGui::~PackageManagerGui() \list \li \c Classic - Classic UI style for Windows 7 and earlier. \li \c Modern - Modern UI style for Windows 8. - \li \c Mac - UI style for OS X. + \li \c Mac - UI style for macOS. \li \c Aero - Aero Peek for Windows 7. \endlist */ @@ -1543,7 +1543,7 @@ void IntroductionPage::setErrorMessage(const QString &error) { QPalette palette; const PackageManagerCore::Status s = packageManagerCore()->status(); - if (s == PackageManagerCore::Failure || s == PackageManagerCore::Failure) { + if (s == PackageManagerCore::Failure) { palette.setColor(QPalette::WindowText, Qt::red); } else { palette.setColor(QPalette::WindowText, palette.color(QPalette::WindowText)); @@ -1911,6 +1911,11 @@ void ComponentSelectionPage::entering() setColoredSubTitle(tr(strings[index])); d->updateTreeView(); + + // check component model state so we can enable needed component selection buttons + if (core->isUpdater()) + d->onModelStateChanged(d->m_currentModel->checkedState()); + setModified(isComplete()); if (core->settings().repositoryCategories().count() > 0 && !core->isOfflineOnly() && !core->isUpdater()) { @@ -2173,7 +2178,7 @@ bool TargetDirectoryPage::validatePage() const QFileInfo fi(targetDir); if (fi.isDir()) { QString fileName = packageManagerCore()->settings().maintenanceToolName(); -#if defined(Q_OS_OSX) +#if defined(Q_OS_MACOS) if (QInstaller::isInBundle(QCoreApplication::applicationDirPath())) fileName += QLatin1String(".app/Contents/MacOS/") + fileName; #elif defined(Q_OS_WIN) @@ -2844,7 +2849,7 @@ void FinishedPage::entering() } if (packageManagerCore()->isMaintainer()) { -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS gui()->setOption(QWizard::NoCancelButton, false); #endif if (QAbstractButton *cancel = gui()->button(QWizard::CancelButton)) { @@ -2908,7 +2913,7 @@ void FinishedPage::entering() */ void FinishedPage::leaving() { -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS gui()->setOption(QWizard::NoCancelButton, true); #endif diff --git a/src/libs/installer/remoteclient.cpp b/src/libs/installer/remoteclient.cpp index e208620cb..ad1e5ecf6 100644 --- a/src/libs/installer/remoteclient.cpp +++ b/src/libs/installer/remoteclient.cpp @@ -29,6 +29,8 @@ #include "remoteclient.h" #include "remoteclient_p.h" +#include <QDir> + namespace QInstaller { RemoteClient *RemoteClient::s_instance = nullptr; @@ -61,6 +63,18 @@ QString RemoteClient::authorizationKey() const return d->m_key; } +QString RemoteClient::socketPathName(const QString &socketName) const +{ + QString socketPathName; + if (socketName.startsWith(QLatin1Char('/'))) { + socketPathName = socketName; + } else { + socketPathName = QDir::tempPath(); + socketPathName += QLatin1Char('/') + socketName; + } + return socketPathName; +} + /*! Initializes the client with \a socketName, with the \a key the client sends to authenticate with the server, \a mode and \a startAs. @@ -69,7 +83,17 @@ void RemoteClient::init(const QString &socketName, const QString &key, Protocol: Protocol::StartAs startAs) { Q_D(RemoteClient); + + // Since Qt 5.12.0, we should determince the full socket path on Unix + // platforms before calling QLocalSocketPrivate::_q_connectToSocket(). + // Otherwise the new canonical implementation of QDir::tempPath() + // presents unintended usage of RemoteFileEngine. + +#if QT_VERSION >= QT_VERSION_CHECK(5,12,0) && defined(Q_OS_UNIX) + d->init(socketPathName(socketName), key, mode, startAs); +#else d->init(socketName, key, mode, startAs); +#endif } void RemoteClient::setAuthorizationFallbackDisabled(bool disabled) diff --git a/src/libs/installer/remoteclient.h b/src/libs/installer/remoteclient.h index c2090bf98..419acccfa 100644 --- a/src/libs/installer/remoteclient.h +++ b/src/libs/installer/remoteclient.h @@ -54,6 +54,7 @@ public: QString socketName() const; QString authorizationKey() const; + QString socketPathName(const QString &socketName) const; bool isActive() const; void setActive(bool active); diff --git a/src/libs/installer/remotefileengine.cpp b/src/libs/installer/remotefileengine.cpp index 05f4ec212..3c54d1e29 100644 --- a/src/libs/installer/remotefileengine.cpp +++ b/src/libs/installer/remotefileengine.cpp @@ -324,9 +324,9 @@ bool RemoteFileEngine::open(QIODevice::OpenMode mode) { if (connectToServer()) { return callRemoteMethod<bool>(QString::fromLatin1(Protocol::QAbstractFileEngineOpen), - static_cast<qint32>(mode)); + static_cast<qint32>(mode | QIODevice::Unbuffered)); } - return m_fileEngine.open(mode); + return m_fileEngine.open(mode | QIODevice::Unbuffered); } /*! diff --git a/src/libs/installer/remoteserver.cpp b/src/libs/installer/remoteserver.cpp index 9d178ca06..66cfefebb 100644 --- a/src/libs/installer/remoteserver.cpp +++ b/src/libs/installer/remoteserver.cpp @@ -65,7 +65,7 @@ void RemoteServer::start() if (d->m_localServer) return; -#if defined(Q_OS_UNIX) && !defined(Q_OS_OSX) +#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) // avoid writing to stderr: // the parent process has redirected stderr to a pipe to work with sudo, // but is not reading anymore -> writing to stderr will block after a while. @@ -93,7 +93,17 @@ void RemoteServer::start() void RemoteServer::init(const QString &socketName, const QString &key, Protocol::Mode mode) { Q_D(RemoteServer); + + // Since Qt 5.12.0, we should determince the full socket path on Unix + // platforms before calling QLocalSocketPrivate::_q_connectToSocket(). + // Otherwise the new canonical implementation of QDir::tempPath() + // presents unintended usage of RemoteFileEngine. + +#if QT_VERSION >= QT_VERSION_CHECK(5,12,0) && defined(Q_OS_UNIX) + d->m_socketName = socketPathName(socketName); +#else d->m_socketName = socketName; +#endif d->m_key = key; d->m_mode = mode; } @@ -116,6 +126,18 @@ QString RemoteServer::authorizationKey() const return d->m_key; } +QString RemoteServer::socketPathName(const QString &socketName) const +{ + QString socketPathName; + if (socketName.startsWith(QLatin1Char('/'))) { + socketPathName = socketName; + } else { + socketPathName = QDir::tempPath(); + socketPathName += QLatin1Char('/') + socketName; + } + return socketPathName; +} + /*! Restarts the watchdog that tries to kill the server. */ diff --git a/src/libs/installer/remoteserver.h b/src/libs/installer/remoteserver.h index e32bcf143..aa69baa55 100644 --- a/src/libs/installer/remoteserver.h +++ b/src/libs/installer/remoteserver.h @@ -53,6 +53,7 @@ public: QString socketName() const; QString authorizationKey() const; + QString socketPathName(const QString &socketName) const; private slots: void restartWatchdog(); diff --git a/src/libs/installer/remoteserverconnection.cpp b/src/libs/installer/remoteserverconnection.cpp index 5a47bc472..b188e694e 100644 --- a/src/libs/installer/remoteserverconnection.cpp +++ b/src/libs/installer/remoteserverconnection.cpp @@ -382,7 +382,14 @@ void RemoteServerConnection::handleQFSFileEngine(QIODevice *socket, const QStrin } else if (command == QLatin1String(Protocol::QAbstractFileEngineCopy)) { QString newName; data >>newName; +#ifdef Q_OS_LINUX + // QFileSystemEngine::copyFile() is currently unimplemented on Linux, + // copy using QFile instead of directly with QFSFileEngine. + QFile file(m_engine->fileName(QAbstractFileEngine::AbsoluteName)); + sendData(socket, file.copy(newName)); +#else sendData(socket, m_engine->copy(newName)); +#endif } else if (command == QLatin1String(Protocol::QAbstractFileEngineEntryList)) { qint32 filters; QStringList filterNames; diff --git a/src/libs/installer/repository.cpp b/src/libs/installer/repository.cpp index a165b8617..e186073ce 100644 --- a/src/libs/installer/repository.cpp +++ b/src/libs/installer/repository.cpp @@ -208,7 +208,7 @@ QString Repository::categoryname() const } /*! - Sets the category name to \a categoryname if the repository belongs to an category. + Sets the category name to \a categoryname if the repository belongs to a category. */ void Repository::setCategoryName(const QString &categoryname) { diff --git a/src/libs/installer/repositorycategory.cpp b/src/libs/installer/repositorycategory.cpp index 42fb41c99..ce06480c8 100644 --- a/src/libs/installer/repositorycategory.cpp +++ b/src/libs/installer/repositorycategory.cpp @@ -28,6 +28,7 @@ #include "repositorycategory.h" #include "filedownloaderfactory.h" +#include "constants.h" #include <QDataStream> #include <QFileInfo> @@ -102,16 +103,20 @@ void RepositoryCategory::setTooltip(const QString &tooltip) */ QSet<Repository> RepositoryCategory::repositories() const { - return variantListToSet<Repository>(m_data.values(QLatin1String("Repositories"))); + return variantListToSet<Repository>(m_data.values(scRepositories)); } /*! - Inserts a set of \a repositories to the category. + Inserts a set of \a repositories to the category. Removes old \a repositories + if \a replace is set to \c true. */ -void RepositoryCategory::setRepositories(const QSet<Repository> repositories) +void RepositoryCategory::setRepositories(const QSet<Repository> repositories, const bool replace) { + if (replace) + m_data.remove(scRepositories); + foreach (const Repository &repository, repositories) - m_data.insertMulti(QLatin1String("Repositories"), QVariant().fromValue(repository)); + m_data.insertMulti(scRepositories, QVariant().fromValue(repository)); } /*! @@ -119,7 +124,7 @@ void RepositoryCategory::setRepositories(const QSet<Repository> repositories) */ void RepositoryCategory::addRepository(const Repository repository) { - m_data.insertMulti(QLatin1String("Repositories"), QVariant().fromValue(repository)); + m_data.insertMulti(scRepositories, QVariant().fromValue(repository)); } /*! diff --git a/src/libs/installer/repositorycategory.h b/src/libs/installer/repositorycategory.h index 98d5df7bd..1996103a5 100644 --- a/src/libs/installer/repositorycategory.h +++ b/src/libs/installer/repositorycategory.h @@ -54,7 +54,7 @@ public: void setTooltip(const QString &tooltip); QSet<Repository> repositories() const; - void setRepositories(const QSet<Repository> repositories); + void setRepositories(const QSet<Repository> repositories, const bool replace = false); void addRepository(const Repository repository); bool isEnabled() const; diff --git a/src/libs/installer/settings.cpp b/src/libs/installer/settings.cpp index e0c9a3970..3aa0baf18 100644 --- a/src/libs/installer/settings.cpp +++ b/src/libs/installer/settings.cpp @@ -472,7 +472,7 @@ QString Settings::installerWindowIcon() const QString Settings::systemIconSuffix() const { -#if defined(Q_OS_OSX) +#if defined(Q_OS_MACOS) return QLatin1String(".icns"); #elif defined(Q_OS_WIN) return QLatin1String(".ico"); @@ -616,12 +616,46 @@ void Settings::addDefaultRepositories(const QSet<Repository> &repositories) d->m_data.insertMulti(scRepositories, QVariant().fromValue(repository)); } +void Settings::setRepositoryCategories(const QSet<RepositoryCategory> &repositories) +{ + d->m_data.remove(scRepositoryCategories); + addRepositoryCategories(repositories); +} + void Settings::addRepositoryCategories(const QSet<RepositoryCategory> &repositories) { foreach (const RepositoryCategory &repository, repositories) d->m_data.insertMulti(scRepositoryCategories, QVariant().fromValue(repository)); } +Settings::Update Settings::updateRepositoryCategories(const RepoHash &updates) +{ + if (updates.isEmpty()) + return Settings::NoUpdatesApplied; + + QSet<RepositoryCategory> categories = repositoryCategories(); + QList<RepositoryCategory> categoriesList = categories.values(); + QPair<Repository, Repository> updateValues = updates.value(QLatin1String("replace")); + + bool update = false; + + foreach (RepositoryCategory category, categoriesList) { + QSet<Repository> repositories = category.repositories(); + if (repositories.contains(updateValues.first)) { + update = true; + repositories.remove(updateValues.first); + repositories.insert(updateValues.second); + category.setRepositories(repositories, true); + categoriesList.replace(categoriesList.indexOf(category), category); + } + } + if (update) { + categories = categoriesList.toSet(); + setRepositoryCategories(categories); + } + return update ? Settings::UpdatesApplied : Settings::NoUpdatesApplied; +} + static bool apply(const RepoHash &updates, QHash<QUrl, Repository> *reposToUpdate) { bool update = false; diff --git a/src/libs/installer/settings.h b/src/libs/installer/settings.h index 55b94d745..fff2324f1 100644 --- a/src/libs/installer/settings.h +++ b/src/libs/installer/settings.h @@ -115,13 +115,16 @@ public: QSet<Repository> repositories() const; QSet<Repository> defaultRepositories() const; - QSet<RepositoryCategory> repositoryCategories() const; - QMap<QString, RepositoryCategory> organizedRepositoryCategories() const; void setDefaultRepositories(const QSet<Repository> &repositories); void addDefaultRepositories(const QSet<Repository> &repositories); - void addRepositoryCategories(const QSet<RepositoryCategory> &repositories); Settings::Update updateDefaultRepositories(const RepoHash &updates); + QSet<RepositoryCategory> repositoryCategories() const; + QMap<QString, RepositoryCategory> organizedRepositoryCategories() const; + void setRepositoryCategories(const QSet<RepositoryCategory> &repositories); + void addRepositoryCategories(const QSet<RepositoryCategory> &repositories); + Settings::Update updateRepositoryCategories(const RepoHash &updates); + QSet<Repository> temporaryRepositories() const; void setTemporaryRepositories(const QSet<Repository> &repositories, bool replace); void addTemporaryRepositories(const QSet<Repository> &repositories, bool replace); diff --git a/src/libs/installer/settingsoperation.cpp b/src/libs/installer/settingsoperation.cpp index e6d88b71e..ccded868d 100644 --- a/src/libs/installer/settingsoperation.cpp +++ b/src/libs/installer/settingsoperation.cpp @@ -180,7 +180,7 @@ bool SettingsOperation::undoOperation() if (!settingsFile.remove()) qWarning().noquote() << settingsFile.errorString(); if (!value(QLatin1String("createddir")).toString().isEmpty()) { - KDUpdater::MkdirOperation mkDirOperation; + KDUpdater::MkdirOperation mkDirOperation(packageManager()); mkDirOperation.setArguments(QStringList() << QFileInfo(path).absolutePath()); mkDirOperation.setValue(QLatin1String("createddir"), value(QLatin1String("createddir"))); diff --git a/src/libs/installer/systeminfo.cpp b/src/libs/installer/systeminfo.cpp index eb4e9cde9..6a1976c4a 100644 --- a/src/libs/installer/systeminfo.cpp +++ b/src/libs/installer/systeminfo.cpp @@ -76,7 +76,7 @@ QString SystemInfo::currentCpuArchitecture() const kernel the installer is running on, unless the host operating system is running a form of compatibility or virtualization layer. - For Windows, Linux, and OS X this will return: + For Windows, Linux, and macOS this will return: \list \li "winnt" \li "linux" @@ -96,7 +96,7 @@ QString SystemInfo::kernelType() const \property SystemInfo::kernelVersion The release version of the operating system kernel. On Windows, it returns the version of the - NT or CE kernel. On Unix systems, including OS X, it returns the same as the \c {uname -r} + NT or CE kernel. On Unix systems, including macOS, it returns the same as the \c {uname -r} command would return. Example values are: |