예제 #1
0
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);
}