summaryrefslogtreecommitdiffstats
path: root/src/libs/installer
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/installer')
-rw-r--r--src/libs/installer/binaryformat.cpp2
-rw-r--r--src/libs/installer/componentselectionpage_p.cpp4
-rw-r--r--src/libs/installer/createlocalrepositoryoperation.cpp18
-rw-r--r--src/libs/installer/fileutils.cpp4
-rw-r--r--src/libs/installer/messageboxhandler.cpp2
-rw-r--r--src/libs/installer/metadatajob.cpp23
-rw-r--r--src/libs/installer/packagemanagercore.cpp31
-rw-r--r--src/libs/installer/packagemanagercore.h4
-rw-r--r--src/libs/installer/packagemanagercore_p.cpp78
-rw-r--r--src/libs/installer/packagemanagercore_p.h3
-rw-r--r--src/libs/installer/packagemanagercoredata.cpp8
-rw-r--r--src/libs/installer/packagemanagergui.cpp17
-rw-r--r--src/libs/installer/remoteclient.cpp24
-rw-r--r--src/libs/installer/remoteclient.h1
-rw-r--r--src/libs/installer/remotefileengine.cpp4
-rw-r--r--src/libs/installer/remoteserver.cpp24
-rw-r--r--src/libs/installer/remoteserver.h1
-rw-r--r--src/libs/installer/remoteserverconnection.cpp7
-rw-r--r--src/libs/installer/repository.cpp2
-rw-r--r--src/libs/installer/repositorycategory.cpp15
-rw-r--r--src/libs/installer/repositorycategory.h2
-rw-r--r--src/libs/installer/settings.cpp36
-rw-r--r--src/libs/installer/settings.h9
-rw-r--r--src/libs/installer/settingsoperation.cpp2
-rw-r--r--src/libs/installer/systeminfo.cpp4
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> &params
#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: