diff options
Diffstat (limited to 'src/libs/installer/packagemanagercore_p.cpp')
-rw-r--r-- | src/libs/installer/packagemanagercore_p.cpp | 139 |
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> ¶ms) { - 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> ¶ms } 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(); |