⛏️ index : haiku.git

/*
 * Copyright 2013-2026, Haiku, Inc. All Rights Reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Ingo Weinhold <ingo_weinhold@gmx.de>
 * 		Stephan Aßmus <superstippi@gmx.de>
 * 		Rene Gollent <rene@gollent.com>
 *		Julian Harnath <julian.harnath@rwth-aachen.de>
 *		Andrew Lindesay <apl@lindesay.co.nz>
 *
 * Note that this file has been re-factored from `PackageManager.cpp` and
 * authors have been carried across in 2021.
 */


#include "UninstallPackageProcess.h"

#include <package/manager/Exceptions.h>
#include <package/solver/SolverPackage.h>

#include <AutoDeleter.h>
#include <Catalog.h>

#include "Alert.h"
#include "AppUtils.h"
#include "Logger.h"
#include "PackageManager.h"
#include "PackageUtils.h"


#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "UninstallPackageAction"


using namespace BPackageKit;
using namespace BPackageKit::BManager::BPrivate;

using BPackageKit::BSolverPackage;


UninstallPackageProcess::UninstallPackageProcess(const BString& packageName, Model* model)
	:
	AbstractPackageProcess(packageName, model)
{
	fDescription = B_TRANSLATE("Uninstalling \"%PackageName%\"");
	fDescription.ReplaceAll("%PackageName%", packageName);
}


UninstallPackageProcess::~UninstallPackageProcess()
{
}


const char*
UninstallPackageProcess::Name() const
{
	return "UninstallPackageAction";
}


const char*
UninstallPackageProcess::Description() const
{
	return fDescription;
}


status_t
UninstallPackageProcess::RunInternal()
{
	// TODO: ideally if the package is installed at multiple locations,
	// the user should be able to pick which one to remove.

	PackageManager* packageManager = new(std::nothrow)
		PackageManager(static_cast<BPackageInstallationLocation>(InstallLocation()));
	ObjectDeleter<PackageManager> solverDeleter(packageManager);

	packageManager->Init(BPackageManager::B_ADD_INSTALLED_REPOSITORIES);

	PackageInfoRef package = FindPackageByName(fPackageName);
	PackageState state = PackageUtils::State(package);

	packageManager->SetCurrentActionPackage(package, false);
	packageManager->AddProgressListener(this);

	const char* packageNameString = package->Name().String();

	try {
		packageManager->Uninstall(&packageNameString, 1);
	} catch (BFatalErrorException& ex) {
		BString errorString;
		errorString.SetToFormat("Fatal error occurred while uninstalling package %s: %s (%s)\n",
			fPackageName.String(), ex.Message().String(), ex.Details().String());
		AppUtils::NotifySimpleError(
			SimpleAlert(B_TRANSLATE("Fatal error"), errorString, B_STOP_ALERT));
		SetPackageState(fPackageName, state);
		return ex.Error();
	} catch (BAbortedByUserException& ex) {
		return B_OK;
	} catch (BNothingToDoException& ex) {
		return B_OK;
	} catch (BException& ex) {
		HDERROR("Exception occurred while uninstalling package %s: %s", fPackageName.String(),
			ex.Message().String());
		SetPackageState(fPackageName, state);
		return B_ERROR;
	}

	packageManager->RemoveProgressListener(this);

	return B_OK;
}


void
UninstallPackageProcess::StartApplyingChanges(BPackageManager::InstalledRepository& repository)
{
	BPackageManager::InstalledRepository::PackageList& packages = repository.PackagesToDeactivate();

	for (int32 i = 0; i < packages.CountItems(); i++) {
		BString packageName = packages.ItemAt(i)->Name();
		fRemovedPackageNames.insert(packageName);
	}
}


void
UninstallPackageProcess::ApplyingChangesDone(BPackageManager::InstalledRepository& repository)
{
	std::set<BString>::const_iterator it;
	for (it = fRemovedPackageNames.begin(); it != fRemovedPackageNames.end(); it++) {
		BString packageName = *it;
		SetPackageState(packageName, NONE);
		ClearPackageInstallationLocations(packageName);
	}
}