FIXME, TODO: decouple dependency resolution from loading FIXME: This works directly with the PackProfile internals. It shouldn't! It needs richer data types than PackProfile uses. FIXME: throw all this away and use a graph
| 459 | // FIXME: This works directly with the PackProfile internals. It shouldn't! It needs richer data types than PackProfile uses. |
| 460 | // FIXME: throw all this away and use a graph |
| 461 | void ComponentUpdateTask::resolveDependencies(bool checkOnly) |
| 462 | { |
| 463 | qCDebug(instanceProfileResolveC) << "Resolving dependencies"; |
| 464 | /* |
| 465 | * this is a naive dependency resolving algorithm. all it does is check for following conditions and react in simple ways: |
| 466 | * 1. There are conflicting dependencies on the same uid with different exact version numbers |
| 467 | * -> hard error |
| 468 | * 2. A dependency has non-matching exact version number |
| 469 | * -> hard error |
| 470 | * 3. A dependency is entirely missing and needs to be injected before the dependee(s) |
| 471 | * -> requirements are injected |
| 472 | * |
| 473 | * NOTE: this is a placeholder and should eventually be replaced with something 'serious' |
| 474 | */ |
| 475 | auto& components = d->m_profile->d->components; |
| 476 | auto& componentIndex = d->m_profile->d->componentIndex; |
| 477 | |
| 478 | RequireExSet allRequires; |
| 479 | QStringList toRemove; |
| 480 | do { |
| 481 | allRequires.clear(); |
| 482 | toRemove.clear(); |
| 483 | if (!gatherRequirementsFromComponents(components, allRequires)) { |
| 484 | finalizeComponents(); |
| 485 | emitFailed(tr("Conflicting requirements detected during dependency checking!")); |
| 486 | return; |
| 487 | } |
| 488 | getTrivialRemovals(components, allRequires, toRemove); |
| 489 | if (!toRemove.isEmpty()) { |
| 490 | qCDebug(instanceProfileResolveC) << "Removing obsolete components..."; |
| 491 | for (auto& remove : toRemove) { |
| 492 | qCDebug(instanceProfileResolveC) << "Removing" << remove; |
| 493 | d->m_profile->remove(remove); |
| 494 | } |
| 495 | } |
| 496 | } while (!toRemove.isEmpty()); |
| 497 | RequireExSet toAdd; |
| 498 | RequireExSet toChange; |
| 499 | bool succeeded = getTrivialComponentChanges(componentIndex, allRequires, toAdd, toChange); |
| 500 | if (!succeeded) { |
| 501 | finalizeComponents(); |
| 502 | emitFailed(tr("Instance has conflicting dependencies.")); |
| 503 | return; |
| 504 | } |
| 505 | if (checkOnly) { |
| 506 | finalizeComponents(); |
| 507 | if (toAdd.size() || toChange.size()) { |
| 508 | emitFailed(tr("Instance has unresolved dependencies while loading/checking for launch.")); |
| 509 | } else { |
| 510 | emitSucceeded(); |
| 511 | } |
| 512 | return; |
| 513 | } |
| 514 | |
| 515 | bool recursionNeeded = false; |
| 516 | if (toAdd.size()) { |
| 517 | // add stuff... |
| 518 | for (auto& add : toAdd) { |
nothing calls this directly
no test coverage detected