summaryrefslogtreecommitdiffstats
path: root/src/libs/installer/packagemanagercore_p.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/installer/packagemanagercore_p.cpp')
-rw-r--r--src/libs/installer/packagemanagercore_p.cpp139
1 files changed, 103 insertions, 36 deletions
diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp
index 3cc44a7e5..a840d6d1e 100644
--- a/src/libs/installer/packagemanagercore_p.cpp
+++ b/src/libs/installer/packagemanagercore_p.cpp
@@ -43,10 +43,13 @@
#include "adminauthorization.h"
#include "binaryformat.h"
#include "component.h"
+#include "scriptengine.h"
#include "componentmodel.h"
#include "errors.h"
#include "fileutils.h"
#include "fsengineclient.h"
+#include "globals.h"
+#include "graph.h"
#include "messageboxhandler.h"
#include "packagemanagercore.h"
#include "progresscoordinator.h"
@@ -58,7 +61,6 @@
#include "kdupdaterfiledownloaderfactory.h"
#include "kdupdaterupdatesourcesinfo.h"
#include "kdupdaterupdateoperationfactory.h"
-#include "kdupdaterupdatefinder.h"
#include <productkeycheck.h>
@@ -94,7 +96,8 @@ public:
{
if (!m_operation)
return;
- qDebug() << QString::fromLatin1("%1 operation: %2").arg(state, m_operation->name());
+ qDebug() << QString::fromLatin1("%1 %2 operation: %3").arg(state, m_operation->value(
+ QLatin1String("component")).toString(), m_operation->name());
qDebug() << QString::fromLatin1("\t- arguments: %1").arg(m_operation->arguments()
.join(QLatin1String(", ")));
}
@@ -201,6 +204,7 @@ static void deferredRename(const QString &oldName, const QString &newName, bool
PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core)
: m_updateFinder(0)
+ , m_updaterApplication(new DummyConfigurationInterface)
, m_FSEngineClientHandler(0)
, m_core(core)
, m_repoMetaInfoJob(0)
@@ -208,6 +212,7 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core)
, m_repoFetched(false)
, m_updateSourcesAdded(false)
, m_componentsToInstallCalculated(false)
+ , m_scriptEngine(0)
, m_proxyFactory(0)
, m_defaultModel(0)
, m_updaterModel(0)
@@ -217,6 +222,7 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core)
PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, qint64 magicInstallerMaker,
const OperationList &performedOperations)
: m_updateFinder(0)
+ , m_updaterApplication(new DummyConfigurationInterface)
, m_FSEngineClientHandler(initFSEngineClientHandler())
, m_status(PackageManagerCore::Unfinished)
, m_forceRestart(false)
@@ -233,6 +239,7 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, q
, m_updateSourcesAdded(false)
, m_magicBinaryMarker(magicInstallerMaker)
, m_componentsToInstallCalculated(false)
+ , m_scriptEngine(0)
, m_proxyFactory(0)
, m_defaultModel(0)
, m_updaterModel(0)
@@ -258,6 +265,7 @@ PackageManagerCorePrivate::~PackageManagerCorePrivate()
m_FSEngineClientHandler->setActive(false);
delete m_updateFinder;
+ delete m_scriptEngine;
delete m_proxyFactory;
delete m_defaultModel;
@@ -373,7 +381,7 @@ bool PackageManagerCorePrivate::buildComponentTree(QHash<QString, Component*> &c
std::sort(m_rootComponents.begin(), m_rootComponents.end(), Component::SortingPriorityGreaterThan());
} catch (const Error &error) {
clearAllComponentLists();
- emit m_core->finishAllComponentsReset();
+ emit m_core->finishAllComponentsReset(QList<QInstaller::Component*>());
setStatus(PackageManagerCore::Failure, error.message());
// TODO: make sure we remove all message boxes inside the library at some point.
@@ -384,6 +392,13 @@ bool PackageManagerCorePrivate::buildComponentTree(QHash<QString, Component*> &c
return true;
}
+ScriptEngine *PackageManagerCorePrivate::scriptEngine()
+{
+ if (!m_scriptEngine)
+ m_scriptEngine = new ScriptEngine(m_core);
+ return m_scriptEngine;
+}
+
void PackageManagerCorePrivate::clearAllComponentLists()
{
qDeleteAll(m_rootComponents);
@@ -422,14 +437,14 @@ void PackageManagerCorePrivate::clearUpdaterComponentLists()
m_componentsToInstallCalculated = false;
}
-QList<Component *> &PackageManagerCorePrivate::replacementDependencyComponents(RunMode mode)
+QList<Component *> &PackageManagerCorePrivate::replacementDependencyComponents()
{
- return mode == AllMode ? m_rootDependencyReplacements : m_updaterDependencyReplacements;
+ return (!isUpdater()) ? m_rootDependencyReplacements : m_updaterDependencyReplacements;
}
-QHash<QString, QPair<Component*, Component*> > &PackageManagerCorePrivate::componentsToReplace(RunMode mode)
+QHash<QString, QPair<Component*, Component*> > &PackageManagerCorePrivate::componentsToReplace()
{
- return mode == AllMode ? m_componentsToReplaceAllMode : m_componentsToReplaceUpdaterMode;
+ return (!isUpdater()) ? m_componentsToReplaceAllMode : m_componentsToReplaceUpdaterMode;
}
void PackageManagerCorePrivate::clearComponentsToInstall()
@@ -453,7 +468,7 @@ bool PackageManagerCorePrivate::appendComponentsToInstall(const QList<Component
relevantComponentForAutoDependOn = m_updaterComponents + m_updaterComponentsDeps;
else {
foreach (QInstaller::Component *component, m_rootComponents)
- relevantComponentForAutoDependOn += component->childComponents(true, AllMode);
+ relevantComponentForAutoDependOn += component->childComponents(Component::Descendants);
}
QList<Component*> notAppendedComponents; // for example components with unresolved dependencies
@@ -557,13 +572,13 @@ QString PackageManagerCorePrivate::installReason(Component *component)
void PackageManagerCorePrivate::initialize(const QHash<QString, QString> &params)
{
- if (!ProductKeyCheck::instance()->hasValidKey()) {
+ if (!ProductKeyCheck::instance(m_core)->hasValidKey()) {
if (m_core->isInstaller()) {
- setStatus(PackageManagerCore::Failure, ProductKeyCheck::instance()->lastErrorString());
+ setStatus(PackageManagerCore::Failure, ProductKeyCheck::instance(m_core)->lastErrorString());
} else {
MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(),
- QLatin1String("ProductKeyCheckError"), ProductKeyCheck::instance()->lastErrorString(),
- ProductKeyCheck::instance()->maintainanceToolDetailErrorNotice(), QMessageBox::Ok);
+ QLatin1String("ProductKeyCheckError"), ProductKeyCheck::instance(m_core)->lastErrorString(),
+ ProductKeyCheck::instance(m_core)->maintainanceToolDetailErrorNotice(), QMessageBox::Ok);
}
}
@@ -617,7 +632,7 @@ void PackageManagerCorePrivate::initialize(const QHash<QString, QString> &params
}
if (!m_repoMetaInfoJob) {
- m_repoMetaInfoJob = new GetRepositoriesMetaInfoJob(this);
+ m_repoMetaInfoJob = new GetRepositoriesMetaInfoJob(m_core);
m_repoMetaInfoJob->setAutoDelete(false);
connect(m_repoMetaInfoJob, SIGNAL(infoMessage(KDJob*, QString)), this, SLOT(infoMessage(KDJob*,
QString)));
@@ -769,13 +784,22 @@ static QSet<Repository> readRepositories(QXmlStreamReader &reader, bool isDefaul
void PackageManagerCorePrivate::writeMaintenanceConfigFiles()
{
+ bool gainedAdminRights = false;
// write current state (variables) to the uninstaller ini file
const QString iniPath = targetDir() + QLatin1Char('/') + m_data.settings().uninstallerIniFile();
+ {
+ QFile tmp(iniPath); // force gaining admin rights in case we haven't done already and we need it
+ if (!tmp.open(QIODevice::ReadWrite) || !tmp.isWritable()) {
+ if (!m_FSEngineClientHandler->isActive()) // check if nobody did it before...
+ gainedAdminRights = m_core->gainAdminRights();
+ }
+ tmp.close();
+ }
QVariantHash variables;
QSettingsWrapper cfg(iniPath, QSettingsWrapper::IniFormat);
foreach (const QString &key, m_data.keys()) {
- if (key != scRunProgramDescription && key != scRunProgram)
+ if (key != scRunProgramDescription && key != scRunProgram && key != scRunProgramArguments)
variables.insert(key, m_data.value(key));
}
cfg.setValue(QLatin1String("Variables"), variables);
@@ -787,6 +811,8 @@ void PackageManagerCorePrivate::writeMaintenanceConfigFiles()
cfg.sync();
if (cfg.status() != QSettingsWrapper::NoError) {
+ if (gainedAdminRights)
+ m_core->dropAdminRights();
const QString reason = cfg.status() == QSettingsWrapper::AccessError ? tr("Access error")
: tr("Format error");
throw Error(tr("Could not write installer configuration to %1: %2").arg(iniPath, reason));
@@ -828,6 +854,9 @@ void PackageManagerCorePrivate::writeMaintenanceConfigFiles()
writer.writeEndElement();
writer.writeEndElement();
}
+
+ if (gainedAdminRights)
+ m_core->dropAdminRights();
}
void PackageManagerCorePrivate::readMaintenanceConfigFiles(const QString &targetDir)
@@ -1301,9 +1330,15 @@ void PackageManagerCorePrivate::writeUninstaller(OperationList performedOperatio
#endif
}
+ performedOperations = sortOperationsBasedOnComponentDependencies(
+ performedOperations);
+
+ m_core->setValue(QLatin1String("installedOperationAreSorted"), QLatin1String("true"));
+
try {
KDSaveFile file(dataFile + QLatin1String(".new"));
openForWrite(&file, file.fileName());
+
writeUninstallerBinaryData(&file, &input, performedOperations, layout);
appendInt64(&file, MagicCookieDat);
file.setPermissions(file.permissions() | QFile::WriteUser | QFile::ReadGroup
@@ -1584,8 +1619,14 @@ bool PackageManagerCorePrivate::runPackageUpdater()
OperationList nonRevertedOperations;
QHash<QString, Component *> componentsByName;
+ // order the operations in the right component dependency order
+ // next loop will save the needed operations in reverse order for uninstallation
+ OperationList performedOperationsOld = m_performedOperationsOld;
+ if (m_core->value(QLatin1String("installedOperationAreSorted")) != QLatin1String("true"))
+ performedOperationsOld = sortOperationsBasedOnComponentDependencies(m_performedOperationsOld);
+
// build a list of undo operations based on the checked state of the component
- foreach (Operation *operation, m_performedOperationsOld) {
+ foreach (Operation *operation, performedOperationsOld) {
const QString &name = operation->value(QLatin1String("component")).toString();
Component *component = componentsByName.value(name, 0);
if (!component)
@@ -1636,6 +1677,7 @@ bool PackageManagerCorePrivate::runPackageUpdater()
continue;
}
+ // uninstallation should be in reverse order so prepend it here
undoOperations.prepend(operation);
updateAdminRights |= operation->value(QLatin1String("admin")).toBool();
}
@@ -1837,7 +1879,6 @@ void PackageManagerCorePrivate::installComponent(Component *component, double pr
// Remember that the operation was performed, that allows us to undo it if a following operation
// fails or if this operation failed but still needs an undo call to cleanup.
addPerformed(operation);
- operation->setValue(QLatin1String("component"), component->name());
}
if (becameAdmin)
@@ -1990,25 +2031,21 @@ void PackageManagerCorePrivate::runUndoOperations(const OperationList &undoOpera
const QString componentName = undoOperation->value(QLatin1String("component")).toString();
if (!componentName.isEmpty()) {
- while (!ok && !ignoreError && m_core->status() != PackageManagerCore::Canceled) {
- const QMessageBox::StandardButton button =
- MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(),
- QLatin1String("installationErrorWithRetry"), tr("Installer Error"),
- tr("Error during uninstallation process:\n%1").arg(undoOperation->errorString()),
- QMessageBox::Retry | QMessageBox::Ignore, QMessageBox::Retry);
-
- if (button == QMessageBox::Retry) {
- ok = performOperationThreaded(undoOperation, Undo);
- } else if (button == QMessageBox::Ignore) {
- ignoreError = true;
- }
- }
- }
-
- if (!componentName.isEmpty()) {
+ while (!ok && !ignoreError && m_core->status() != PackageManagerCore::Canceled) {
+ const QMessageBox::StandardButton button =
+ MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(),
+ QLatin1String("installationErrorWithRetry"), tr("Installer Error"),
+ tr("Error during uninstallation process:\n%1").arg(undoOperation->errorString()),
+ QMessageBox::Retry | QMessageBox::Ignore, QMessageBox::Retry);
+
+ if (button == QMessageBox::Retry)
+ ok = performOperationThreaded(undoOperation, Undo);
+ else if (button == QMessageBox::Ignore)
+ ignoreError = true;
+ }
Component *component = m_core->componentByName(componentName);
if (!component)
- component = componentsToReplace(m_core->runMode()).value(componentName).second;
+ component = componentsToReplace().value(componentName).second;
if (component) {
component->setUninstalled();
packages.removePackage(component->name());
@@ -2041,7 +2078,6 @@ PackagesList PackageManagerCorePrivate::remotePackages()
m_updateFinder = new KDUpdater::UpdateFinder(&m_updaterApplication);
m_updateFinder->setAutoDelete(false);
- m_updateFinder->setUpdateType(KDUpdater::PackageUpdate | KDUpdater::NewPackage);
m_updateFinder->run();
if (m_updateFinder->updates().isEmpty()) {
@@ -2285,8 +2321,8 @@ bool PackageManagerCorePrivate::appendComponentsToUninstall(const QList<Componen
foreach (Component *c, installedComponents) {
const QString replaces = c->value(scReplaces);
- QStringList possibleNames = replaces.split(scCommaRegExp, QString::SkipEmptyParts);
- possibleNames.append(c->name());
+ const QStringList possibleNames = replaces.split(QInstaller::commaRegExp(),
+ QString::SkipEmptyParts) << c->name();
foreach (const QString &possibleName, possibleNames)
autoDependencies.removeAll(possibleName);
}
@@ -2333,6 +2369,37 @@ void PackageManagerCorePrivate::connectOperationCallMethodRequest(Operation *con
}
}
+OperationList PackageManagerCorePrivate::sortOperationsBasedOnComponentDependencies(const OperationList &operationList)
+{
+ OperationList sortedOperations;
+ QHash<QString, OperationList> componentOperationHash;
+
+ // sort component unrelated operations to the beginning
+ foreach (Operation *operation, operationList) {
+ const QString componentName = operation->value(QLatin1String("component")).toString();
+ if (componentName.isEmpty())
+ sortedOperations.append(operation);
+ else {
+ OperationList componentOperationList = componentOperationHash.value(componentName);
+ componentOperationList.append(operation);
+ componentOperationHash.insert(operation->value(QLatin1String("component")).toString(),
+ componentOperationList);
+ }
+ }
+
+ // create the complete component graph
+ Graph<QString> componentGraph;
+ foreach (const Component* componentNode, m_core->availableComponents()) {
+ componentGraph.addNode(componentNode->name());
+ componentGraph.addEdges(componentNode->name(), componentNode->dependencies());
+ }
+
+ foreach (const QString &componentName, componentGraph.sort())
+ sortedOperations.append(componentOperationHash.value(componentName));
+
+ return sortedOperations;
+}
+
void PackageManagerCorePrivate::handleMethodInvocationRequest(const QString &invokableMethodName)
{
QObject *obj = QObject::sender();