summaryrefslogtreecommitdiffstats
path: root/src/libs/installer
diff options
context:
space:
mode:
authorArttu Tarkiainen <arttu.tarkiainen@qt.io>2022-10-12 15:52:42 +0300
committerArttu Tarkiainen <arttu.tarkiainen@qt.io>2022-10-19 13:25:32 +0300
commit499a7a0add7780b4af929716479a18015973a0e9 (patch)
tree078fd5c10355eaaa0089b42b3df8d0dc60d90d53 /src/libs/installer
parente5bf28baa1f8246005efebd6203c6b07f246980c (diff)
Fix possible uncaught exceptions while loading package data
This affects exceptions thrown when failing to load user interface and license files from package, which are now handled properly. Change-Id: Ibfe9da8f2b8b7e3e08945ae81eb40ae0b045e9b1 Reviewed-by: Katja Marttila <katja.marttila@qt.io>
Diffstat (limited to 'src/libs/installer')
-rw-r--r--src/libs/installer/packagemanagercore.cpp389
1 files changed, 200 insertions, 189 deletions
diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp
index bfe8e75b0..0c9533c8d 100644
--- a/src/libs/installer/packagemanagercore.cpp
+++ b/src/libs/installer/packagemanagercore.cpp
@@ -4080,134 +4080,145 @@ bool PackageManagerCore::fetchAllPackages(const PackagesList &remotes, const Loc
{
emit startAllComponentsReset();
- d->clearAllComponentLists();
- QHash<QString, QInstaller::Component*> allComponents;
+ try {
+ d->clearAllComponentLists();
+ QHash<QString, QInstaller::Component*> allComponents;
- Data data;
- data.components = &allComponents;
- data.installedPackages = &locals;
+ Data data;
+ data.components = &allComponents;
+ data.installedPackages = &locals;
- QMap<QString, QString> remoteTreeNameComponents;
- QMap<QString, QString> allTreeNameComponents;
+ QMap<QString, QString> remoteTreeNameComponents;
+ QMap<QString, QString> allTreeNameComponents;
- std::function<bool(PackagesList *, bool)> loadRemotePackages;
- loadRemotePackages = [&](PackagesList *treeNamePackages, bool firstRun) -> bool {
- foreach (Package *const package, (firstRun ? remotes : *treeNamePackages)) {
- if (d->statusCanceledOrFailed())
- return false;
+ std::function<bool(PackagesList *, bool)> loadRemotePackages;
+ loadRemotePackages = [&](PackagesList *treeNamePackages, bool firstRun) -> bool {
+ foreach (Package *const package, (firstRun ? remotes : *treeNamePackages)) {
+ if (d->statusCanceledOrFailed())
+ return false;
- if (!ProductKeyCheck::instance()->isValidPackage(package->data(scName).toString()))
- continue;
+ if (!ProductKeyCheck::instance()->isValidPackage(package->data(scName).toString()))
+ continue;
- if (firstRun && !package->data(scTreeName)
- .value<QPair<QString, bool>>().first.isEmpty()) {
- // Package has a tree name, leave for later
- treeNamePackages->append(package);
- continue;
- }
+ if (firstRun && !package->data(scTreeName)
+ .value<QPair<QString, bool>>().first.isEmpty()) {
+ // Package has a tree name, leave for later
+ treeNamePackages->append(package);
+ continue;
+ }
- QScopedPointer<QInstaller::Component> remoteComponent(new QInstaller::Component(this));
- data.package = package;
- remoteComponent->loadDataFromPackage(*package);
- if (updateComponentData(data, remoteComponent.data())) {
- // Create a list where is name and treename. Repo can contain a package with
- // a different treename of component which is already installed. We don't want
- // to move already installed local packages.
- const QString treeName = remoteComponent->value(scTreeName);
- if (!treeName.isEmpty())
- remoteTreeNameComponents.insert(remoteComponent->name(), treeName);
- const QString name = remoteComponent->treeName();
- allComponents.insert(name, remoteComponent.take());
+ QScopedPointer<QInstaller::Component> remoteComponent(new QInstaller::Component(this));
+ data.package = package;
+ remoteComponent->loadDataFromPackage(*package);
+ if (updateComponentData(data, remoteComponent.data())) {
+ // Create a list where is name and treename. Repo can contain a package with
+ // a different treename of component which is already installed. We don't want
+ // to move already installed local packages.
+ const QString treeName = remoteComponent->value(scTreeName);
+ if (!treeName.isEmpty())
+ remoteTreeNameComponents.insert(remoteComponent->name(), treeName);
+ const QString name = remoteComponent->treeName();
+ allComponents.insert(name, remoteComponent.take());
+ }
}
+ // Second pass with leftover packages
+ return firstRun ? loadRemotePackages(treeNamePackages, false) : true;
+ };
+
+ {
+ // Loading remote package data is performed in two steps: first, components without
+ // - and then components with tree names. This is to ensure components with tree
+ // names do not replace other components when registering fails to a name conflict.
+ PackagesList treeNamePackagesTmp;
+ if (!loadRemotePackages(&treeNamePackagesTmp, true))
+ return false;
}
- // Second pass with leftover packages
- return firstRun ? loadRemotePackages(treeNamePackages, false) : true;
- };
+ allTreeNameComponents = remoteTreeNameComponents;
- {
- // Loading remote package data is performed in two steps: first, components without
- // - and then components with tree names. This is to ensure components with tree
- // names do not replace other components when registering fails to a name conflict.
- PackagesList treeNamePackagesTmp;
- if (!loadRemotePackages(&treeNamePackagesTmp, true))
- return false;
- }
- allTreeNameComponents = remoteTreeNameComponents;
+ foreach (auto &package, locals) {
+ if (package.virtualComp && package.autoDependencies.isEmpty()) {
+ if (!d->m_localVirtualComponents.contains(package.name))
+ d->m_localVirtualComponents.append(package.name);
+ }
- foreach (auto &package, locals) {
- if (package.virtualComp && package.autoDependencies.isEmpty()) {
- if (!d->m_localVirtualComponents.contains(package.name))
- d->m_localVirtualComponents.append(package.name);
- }
+ QScopedPointer<QInstaller::Component> localComponent(new QInstaller::Component(this));
+ localComponent->loadDataFromPackage(package);
+ const QString name = localComponent->treeName();
+
+ // 1. Component has a treename in local but not in remote, add with local treename
+ if (!remoteTreeNameComponents.contains(localComponent->name()) && !localComponent->value(scTreeName).isEmpty()) {
+ delete allComponents.take(localComponent->name());
+ // 2. Component has different treename in local and remote, add with local treename
+ } else if (remoteTreeNameComponents.contains(localComponent->name())) {
+ const QString remoteTreeName = remoteTreeNameComponents.value(localComponent->name());
+ const QString localTreeName = localComponent->value(scTreeName);
+ if (remoteTreeName != localTreeName) {
+ delete allComponents.take(remoteTreeNameComponents.value(localComponent->name()));
+ } else {
+ // 3. Component has same treename in local and remote, don't add the component again.
+ continue;
+ }
+ // 4. Component does not have treename in local or remote, don't add the component again.
+ } else if (allComponents.contains(localComponent->name())) {
+ Component *const component = allComponents.value(localComponent->name());
+ if (component->value(scTreeName).isEmpty() && localComponent->value(scTreeName).isEmpty())
+ continue;
+ }
+ // 5. Remote has treename for a different component that is already reserved
+ // by this local component, Or, remote adds component without treename
+ // but it conflicts with a local treename.
+ if (allComponents.contains(name)) {
+ const QString key = remoteTreeNameComponents.key(name);
+ qCritical() << "Cannot register component" << (key.isEmpty() ? name : key)
+ << "with name" << name << "! Component with identifier" << name
+ << "already exists.";
+
+ if (!key.isEmpty())
+ allTreeNameComponents.remove(key);
+
+ // Try to re-add the remote component as unstable
+ if (!key.isEmpty() && !allComponents.contains(key) && settings().allowUnstableComponents()) {
+ qCDebug(lcInstallerInstallLog)
+ << "Registering component with the original indetifier:" << key;
+
+ Component *component = allComponents.take(name);
+ component->removeValue(scTreeName);
+ const QString errorString = QLatin1String("Tree name conflicts with an existing indentifier");
+ d->m_pendingUnstableComponents.insert(component->name(),
+ QPair<Component::UnstableError, QString>(Component::InvalidTreeName, errorString));
- QScopedPointer<QInstaller::Component> localComponent(new QInstaller::Component(this));
- localComponent->loadDataFromPackage(package);
- const QString name = localComponent->treeName();
-
- // 1. Component has a treename in local but not in remote, add with local treename
- if (!remoteTreeNameComponents.contains(localComponent->name()) && !localComponent->value(scTreeName).isEmpty()) {
- delete allComponents.take(localComponent->name());
- // 2. Component has different treename in local and remote, add with local treename
- } else if (remoteTreeNameComponents.contains(localComponent->name())) {
- const QString remoteTreeName = remoteTreeNameComponents.value(localComponent->name());
- const QString localTreeName = localComponent->value(scTreeName);
- if (remoteTreeName != localTreeName) {
- delete allComponents.take(remoteTreeNameComponents.value(localComponent->name()));
- } else {
- // 3. Component has same treename in local and remote, don't add the component again.
- continue;
+ allComponents.insert(key, component);
+ } else {
+ delete allComponents.take(name);
+ }
}
- // 4. Component does not have treename in local or remote, don't add the component again.
- } else if (allComponents.contains(localComponent->name())) {
- Component *const component = allComponents.value(localComponent->name());
- if (component->value(scTreeName).isEmpty() && localComponent->value(scTreeName).isEmpty())
- continue;
+
+ const QString treeName = localComponent->value(scTreeName);
+ if (!treeName.isEmpty())
+ allTreeNameComponents.insert(localComponent->name(), treeName);
+ allComponents.insert(name, localComponent.take());
}
- // 5. Remote has treename for a different component that is already reserved
- // by this local component, Or, remote adds component without treename
- // but it conflicts with a local treename.
- if (allComponents.contains(name)) {
- const QString key = remoteTreeNameComponents.key(name);
- qCritical() << "Cannot register component" << (key.isEmpty() ? name : key)
- << "with name" << name << "! Component with identifier" << name
- << "already exists.";
-
- if (!key.isEmpty())
- allTreeNameComponents.remove(key);
-
- // Try to re-add the remote component as unstable
- if (!key.isEmpty() && !allComponents.contains(key) && settings().allowUnstableComponents()) {
- qCDebug(lcInstallerInstallLog)
- << "Registering component with the original indetifier:" << key;
- Component *component = allComponents.take(name);
- component->removeValue(scTreeName);
- const QString errorString = QLatin1String("Tree name conflicts with an existing indentifier");
- d->m_pendingUnstableComponents.insert(component->name(),
- QPair<Component::UnstableError, QString>(Component::InvalidTreeName, errorString));
+ // store all components that got a replacement
+ storeReplacedComponents(allComponents, data, &allTreeNameComponents);
- allComponents.insert(key, component);
- } else {
- delete allComponents.take(name);
- }
- }
+ // Move children of treename components
+ createAutoTreeNames(allComponents, allTreeNameComponents);
- const QString treeName = localComponent->value(scTreeName);
- if (!treeName.isEmpty())
- allTreeNameComponents.insert(localComponent->name(), treeName);
- allComponents.insert(name, localComponent.take());
- }
+ if (!d->buildComponentTree(allComponents, true))
+ return false;
- // store all components that got a replacement
- storeReplacedComponents(allComponents, data, &allTreeNameComponents);
+ d->commitPendingUnstableComponents();
- // Move children of treename components
- createAutoTreeNames(allComponents, allTreeNameComponents);
+ } catch (const Error &error) {
+ d->clearAllComponentLists();
+ d->setStatus(PackageManagerCore::Failure, error.message());
- if (!d->buildComponentTree(allComponents, true))
+ // TODO: make sure we remove all message boxes inside the library at some point.
+ MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("Error"),
+ tr("Error"), error.message());
return false;
-
- d->commitPendingUnstableComponents();
+ }
emit finishAllComponentsReset(d->m_rootComponents);
return true;
@@ -4217,104 +4228,104 @@ bool PackageManagerCore::fetchUpdaterPackages(const PackagesList &remotes, const
{
emit startUpdaterComponentsReset();
- d->clearUpdaterComponentLists();
- QHash<QString, QInstaller::Component *> components;
+ try {
+ d->clearUpdaterComponentLists();
+ QHash<QString, QInstaller::Component *> components;
- Data data;
- data.components = &components;
- data.installedPackages = &locals;
+ Data data;
+ data.components = &components;
+ data.installedPackages = &locals;
- setFoundEssentialUpdate(false);
- LocalPackagesMap installedPackages = locals;
- QStringList replaceMes;
+ setFoundEssentialUpdate(false);
+ LocalPackagesMap installedPackages = locals;
+ QStringList replaceMes;
- foreach (Package *const update, remotes) {
- if (d->statusCanceledOrFailed())
- return false;
+ foreach (Package *const update, remotes) {
+ if (d->statusCanceledOrFailed())
+ return false;
- if (!ProductKeyCheck::instance()->isValidPackage(update->data(scName).toString()))
- continue;
+ if (!ProductKeyCheck::instance()->isValidPackage(update->data(scName).toString()))
+ continue;
- QScopedPointer<QInstaller::Component> component(new QInstaller::Component(this));
- data.package = update;
- component->loadDataFromPackage(*update);
- if (updateComponentData(data, component.data())) {
- // Keep a reference so we can resolve dependencies during update.
- d->m_updaterComponentsDeps.append(component.take());
-
-// const QString isNew = update->data(scNewComponent).toString();
-// if (isNew.toLower() != scTrue)
-// continue;
-
- const QString &name = d->m_updaterComponentsDeps.last()->name();
- const QString replaces = data.package->data(scReplaces).toString();
- installedPackages.take(name); // remove from local installed packages
-
- bool isValidUpdate = locals.contains(name);
- if (!replaces.isEmpty()) {
- const QStringList possibleNames = replaces.split(QInstaller::commaRegExp(),
- Qt::SkipEmptyParts);
- foreach (const QString &possibleName, possibleNames) {
- if (locals.contains(possibleName)) {
- isValidUpdate = true;
- replaceMes << possibleName;
+ QScopedPointer<QInstaller::Component> component(new QInstaller::Component(this));
+ data.package = update;
+ component->loadDataFromPackage(*update);
+ if (updateComponentData(data, component.data())) {
+ // Keep a reference so we can resolve dependencies during update.
+ d->m_updaterComponentsDeps.append(component.take());
+
+ // const QString isNew = update->data(scNewComponent).toString();
+ // if (isNew.toLower() != scTrue)
+ // continue;
+
+ const QString &name = d->m_updaterComponentsDeps.last()->name();
+ const QString replaces = data.package->data(scReplaces).toString();
+ installedPackages.take(name); // remove from local installed packages
+
+ bool isValidUpdate = locals.contains(name);
+ if (!replaces.isEmpty()) {
+ const QStringList possibleNames = replaces.split(QInstaller::commaRegExp(),
+ Qt::SkipEmptyParts);
+ foreach (const QString &possibleName, possibleNames) {
+ if (locals.contains(possibleName)) {
+ isValidUpdate = true;
+ replaceMes << possibleName;
+ }
}
}
- }
- // break if the update is not valid and if it's not the maintenance tool (we might get an update
- // for the maintenance tool even if it's not currently installed - possible offline installation)
- if (!isValidUpdate && (update->data(scEssential, scFalse).toString().toLower() == scFalse))
- continue; // Update for not installed package found, skip it.
+ // break if the update is not valid and if it's not the maintenance tool (we might get an update
+ // for the maintenance tool even if it's not currently installed - possible offline installation)
+ if (!isValidUpdate && (update->data(scEssential, scFalse).toString().toLower() == scFalse))
+ continue; // Update for not installed package found, skip it.
- const LocalPackage &localPackage = locals.value(name);
- if (!d->packageNeedsUpdate(localPackage, update))
- continue;
- // It is quite possible that we may have already installed the update. Lets check the last
- // update date of the package and the release date of the update. This way we can compare and
- // figure out if the update has been installed or not.
- const QDate updateDate = update->data(scReleaseDate).toDate();
- if (localPackage.lastUpdateDate > updateDate)
- continue;
+ const LocalPackage &localPackage = locals.value(name);
+ if (!d->packageNeedsUpdate(localPackage, update))
+ continue;
+ // It is quite possible that we may have already installed the update. Lets check the last
+ // update date of the package and the release date of the update. This way we can compare and
+ // figure out if the update has been installed or not.
+ const QDate updateDate = update->data(scReleaseDate).toDate();
+ if (localPackage.lastUpdateDate > updateDate)
+ continue;
- if (update->data(scEssential, scFalse).toString().toLower() == scTrue ||
- update->data(scForcedUpdate, scFalse).toString().toLower() == scTrue) {
- setFoundEssentialUpdate(true);
- }
+ if (update->data(scEssential, scFalse).toString().toLower() == scTrue ||
+ update->data(scForcedUpdate, scFalse).toString().toLower() == scTrue) {
+ setFoundEssentialUpdate(true);
+ }
- // this is not a dependency, it is a real update
- components.insert(name, d->m_updaterComponentsDeps.takeLast());
+ // this is not a dependency, it is a real update
+ components.insert(name, d->m_updaterComponentsDeps.takeLast());
+ }
}
- }
-
- QHash<QString, QInstaller::Component *> localReplaceMes;
- foreach (const QString &key, installedPackages.keys()) {
- QInstaller::Component *component = new QInstaller::Component(this);
- component->loadDataFromPackage(installedPackages.value(key));
- d->m_updaterComponentsDeps.append(component);
- }
- foreach (const QString &key, locals.keys()) {
- LocalPackage package = locals.value(key);
- if (package.virtualComp && package.autoDependencies.isEmpty()) {
- if (!d->m_localVirtualComponents.contains(package.name))
- d->m_localVirtualComponents.append(package.name);
- }
- // Keep a list of local components that should be replaced
- // Remove from components list - we don't want to update the component
- // as it is replaced by other component
- if (replaceMes.contains(key)) {
+ QHash<QString, QInstaller::Component *> localReplaceMes;
+ foreach (const QString &key, installedPackages.keys()) {
QInstaller::Component *component = new QInstaller::Component(this);
- component->loadDataFromPackage(locals.value(key));
- localReplaceMes.insert(component->name(), component);
- delete components.take(component->name());
+ component->loadDataFromPackage(installedPackages.value(key));
+ d->m_updaterComponentsDeps.append(component);
}
- }
- // store all components that got a replacement, but do not modify the components list
- storeReplacedComponents(localReplaceMes.unite(components), data);
+ foreach (const QString &key, locals.keys()) {
+ LocalPackage package = locals.value(key);
+ if (package.virtualComp && package.autoDependencies.isEmpty()) {
+ if (!d->m_localVirtualComponents.contains(package.name))
+ d->m_localVirtualComponents.append(package.name);
+ }
+ // Keep a list of local components that should be replaced
+ // Remove from components list - we don't want to update the component
+ // as it is replaced by other component
+ if (replaceMes.contains(key)) {
+ QInstaller::Component *component = new QInstaller::Component(this);
+ component->loadDataFromPackage(locals.value(key));
+ localReplaceMes.insert(component->name(), component);
+ delete components.take(component->name());
+ }
+ }
+
+ // store all components that got a replacement, but do not modify the components list
+ storeReplacedComponents(localReplaceMes.unite(components), data);
- try {
if (!components.isEmpty()) {
// append all components w/o parent to the direct list
foreach (QInstaller::Component *component, components) {