bool ResultWindow::_AddPackages(BGroupLayout* packagesGroup, const PackageList& packages, const PackageSet& ignorePackages, bool install) { bool packagesAdded = false; for (int32 i = 0; BSolverPackage* package = packages.ItemAt(i); i++) { if (ignorePackages.find(package) != ignorePackages.end()) continue; BString text; if (install) { text.SetToFormat("install package %s from repository %s\n", package->Info().FileName().String(), package->Repository()->Name().String()); } else { text.SetToFormat("uninstall package %s\n", package->VersionedName().String()); } BStringView* packageView = new BStringView(NULL, text); packagesGroup->AddView(packageView); packageView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); packagesAdded = true; } return packagesAdded; }
int32 BPackageManager::_FindBasePackage(const PackageList& packages, const BPackageInfo& info) { if (info.BasePackage().IsEmpty()) return -1; // find the requirement matching the base package BPackageResolvableExpression* basePackage = NULL; int32 count = info.RequiresList().CountItems(); for (int32 i = 0; i < count; i++) { BPackageResolvableExpression* requires = info.RequiresList().ItemAt(i); if (requires->Name() == info.BasePackage()) { basePackage = requires; break; } } if (basePackage == NULL) { fUserInteractionHandler->Warn(B_OK, "package %s-%s doesn't have a " "matching requires for its base package \"%s\"", info.Name().String(), info.Version().ToString().String(), info.BasePackage().String()); return -1; } // find the first package matching the base package requires count = packages.CountItems(); for (int32 i = 0; i < count; i++) { BSolverPackage* package = packages.ItemAt(i); if (package->Name() == basePackage->Name() && package->Info().Matches(*basePackage)) { return i; } } return -1; }
void BPackageManager::Uninstall(const BSolverPackageSpecifierList& packages) { Init(B_ADD_INSTALLED_REPOSITORIES); // find the packages that match the specification const BSolverPackageSpecifier* unmatchedSpecifier; PackageList foundPackages; status_t error = fSolver->FindPackages(packages, BSolver::B_FIND_INSTALLED_ONLY, foundPackages, &unmatchedSpecifier); if (error != B_OK) { if (unmatchedSpecifier != NULL) { DIE(error, "failed to find a match for \"%s\"", unmatchedSpecifier->SelectString().String()); } else DIE(error, "failed to compute packages to uninstall"); } // determine the inverse base package closure for the found packages // TODO: Optimize! InstalledRepository& installationRepository = InstallationRepository(); bool foundAnotherPackage; do { foundAnotherPackage = false; int32 count = installationRepository.CountPackages(); for (int32 i = 0; i < count; i++) { BSolverPackage* package = installationRepository.PackageAt(i); if (foundPackages.HasItem(package)) continue; if (_FindBasePackage(foundPackages, package->Info()) >= 0) { foundPackages.AddItem(package); foundAnotherPackage = true; } } } while (foundAnotherPackage); // remove the packages from the repository for (int32 i = 0; BSolverPackage* package = foundPackages.ItemAt(i); i++) installationRepository.DisablePackage(package); for (;;) { error = fSolver->VerifyInstallation(BSolver::B_VERIFY_ALLOW_UNINSTALL); if (error != B_OK) DIE(error, "failed to compute packages to uninstall"); _HandleProblems(); // (virtually) apply the result to this repository _AnalyzeResult(); for (int32 i = foundPackages.CountItems() - 1; i >= 0; i--) { if (!installationRepository.PackagesToDeactivate() .AddItem(foundPackages.ItemAt(i))) { throw std::bad_alloc(); } } installationRepository.ApplyChanges(); // verify the next specific respository if (!_NextSpecificInstallationLocation()) break; foundPackages.MakeEmpty(); // NOTE: In theory, after verifying a more specific location, it would // be more correct to compute the inverse base package closure for the // packages we need to uninstall and (if anything changed) verify again. // In practice, however, base packages are always required with an exact // version (ATM). If that base package still exist in a more general // location (the only reason why the package requiring the base package // wouldn't be marked to be uninstalled as well) there shouldn't have // been any reason to remove it from the more specific location in the // first place. } _ConfirmChanges(true); _ApplyPackageChanges(true); }