183462cc2SIngo Weinhold/*
21aaa0c21SAxel Dörfler * Copyright 2013-2015, Haiku, Inc. All Rights Reserved.
383462cc2SIngo Weinhold * Distributed under the terms of the MIT License.
483462cc2SIngo Weinhold *
583462cc2SIngo Weinhold * Authors:
683462cc2SIngo Weinhold *		Ingo Weinhold <ingo_weinhold@gmx.de>
7fe39d2ebSRene Gollent *		Rene Gollent <rene@gollent.com>
883462cc2SIngo Weinhold */
983462cc2SIngo Weinhold
1083462cc2SIngo Weinhold
1183462cc2SIngo Weinhold#include <package/manager/PackageManager.h>
1283462cc2SIngo Weinhold
1399e5e3fdSHumdinger#include <Catalog.h>
1483462cc2SIngo Weinhold#include <Directory.h>
150de3219eSIngo Weinhold#include <package/CommitTransactionResult.h>
16fe39d2ebSRene Gollent#include <package/DownloadFileRequest.h>
1783462cc2SIngo Weinhold#include <package/PackageRoster.h>
18fe39d2ebSRene Gollent#include <package/RefreshRepositoryRequest.h>
1981a828b6SIngo Weinhold#include <package/RepositoryCache.h>
2083462cc2SIngo Weinhold#include <package/solver/SolverPackage.h>
2183462cc2SIngo Weinhold#include <package/solver/SolverPackageSpecifier.h>
2283462cc2SIngo Weinhold#include <package/solver/SolverPackageSpecifierList.h>
2383462cc2SIngo Weinhold#include <package/solver/SolverProblem.h>
2483462cc2SIngo Weinhold#include <package/solver/SolverProblemSolution.h>
2583462cc2SIngo Weinhold#include <package/solver/SolverResult.h>
2683462cc2SIngo Weinhold
2783462cc2SIngo Weinhold#include <CopyEngine.h>
2883462cc2SIngo Weinhold#include <package/ActivationTransaction.h>
2983462cc2SIngo Weinhold#include <package/DaemonClient.h>
3083462cc2SIngo Weinhold#include <package/manager/RepositoryBuilder.h>
319345049aSRene Gollent#include <package/ValidateChecksumJob.h>
3283462cc2SIngo Weinhold
33106ae4ecSCodeforEvolution#include "FetchFileJob.h"
3483462cc2SIngo Weinhold#include "PackageManagerUtils.h"
3583462cc2SIngo Weinhold
3699e5e3fdSHumdinger#undef B_TRANSLATION_CONTEXT
3799e5e3fdSHumdinger#define B_TRANSLATION_CONTEXT "PackageManagerKit"
3899e5e3fdSHumdinger
3983462cc2SIngo Weinhold
409345049aSRene Gollentusing BPackageKit::BPrivate::FetchFileJob;
419345049aSRene Gollentusing BPackageKit::BPrivate::ValidateChecksumJob;
429345049aSRene Gollent
439345049aSRene Gollent
4483462cc2SIngo Weinholdnamespace BPackageKit {
4583462cc2SIngo Weinhold
4683462cc2SIngo Weinholdnamespace BManager {
4783462cc2SIngo Weinhold
4883462cc2SIngo Weinholdnamespace BPrivate {
4983462cc2SIngo Weinhold
5083462cc2SIngo Weinhold
5183462cc2SIngo Weinhold// #pragma mark - BPackageManager
5283462cc2SIngo Weinhold
5383462cc2SIngo Weinhold
546722e1aeSIngo WeinholdBPackageManager::BPackageManager(BPackageInstallationLocation location,
556722e1aeSIngo Weinhold	InstallationInterface* installationInterface,
566722e1aeSIngo Weinhold	UserInteractionHandler* userInteractionHandler)
5783462cc2SIngo Weinhold	:
58d228f29fSIngo Weinhold	fDebugLevel(0),
5983462cc2SIngo Weinhold	fLocation(location),
6083462cc2SIngo Weinhold	fSolver(NULL),
6183462cc2SIngo Weinhold	fSystemRepository(new (std::nothrow) InstalledRepository("system",
6283462cc2SIngo Weinhold		B_PACKAGE_INSTALLATION_LOCATION_SYSTEM, -1)),
6383462cc2SIngo Weinhold	fHomeRepository(new (std::nothrow) InstalledRepository("home",
6483462cc2SIngo Weinhold		B_PACKAGE_INSTALLATION_LOCATION_HOME, -3)),
6583462cc2SIngo Weinhold	fInstalledRepositories(10),
6683462cc2SIngo Weinhold	fOtherRepositories(10, true),
679002c943SStephan Aßmus	fLocalRepository(new (std::nothrow) MiscLocalRepository),
6883462cc2SIngo Weinhold	fTransactions(5, true),
696722e1aeSIngo Weinhold	fInstallationInterface(installationInterface),
706722e1aeSIngo Weinhold	fUserInteractionHandler(userInteractionHandler)
7183462cc2SIngo Weinhold{
7283462cc2SIngo Weinhold}
7383462cc2SIngo Weinhold
7483462cc2SIngo Weinhold
7583462cc2SIngo WeinholdBPackageManager::~BPackageManager()
7683462cc2SIngo Weinhold{
7783462cc2SIngo Weinhold	delete fSolver;
7883462cc2SIngo Weinhold	delete fSystemRepository;
7983462cc2SIngo Weinhold	delete fHomeRepository;
80f2f19f11SIngo Weinhold	delete fLocalRepository;
8183462cc2SIngo Weinhold}
8283462cc2SIngo Weinhold
8383462cc2SIngo Weinhold
8483462cc2SIngo Weinholdvoid
8583462cc2SIngo WeinholdBPackageManager::Init(uint32 flags)
8683462cc2SIngo Weinhold{
8783462cc2SIngo Weinhold	if (fSolver != NULL)
8883462cc2SIngo Weinhold		return;
8983462cc2SIngo Weinhold
9083462cc2SIngo Weinhold	// create the solver
9183462cc2SIngo Weinhold	status_t error = BSolver::Create(fSolver);
9283462cc2SIngo Weinhold	if (error != B_OK)
93ab8f11bfSBrian Hill		DIE(error, "Failed to create solver");
9483462cc2SIngo Weinhold
959002c943SStephan Aßmus	if (fSystemRepository == NULL || fHomeRepository == NULL
969002c943SStephan Aßmus		|| fLocalRepository == NULL) {
9783462cc2SIngo Weinhold		throw std::bad_alloc();
989002c943SStephan Aßmus	}
9983462cc2SIngo Weinhold
100d228f29fSIngo Weinhold	fSolver->SetDebugLevel(fDebugLevel);
101d228f29fSIngo Weinhold
1029002c943SStephan Aßmus	BRepositoryBuilder(*fLocalRepository).AddToSolver(fSolver, false);
103f2f19f11SIngo Weinhold
10483462cc2SIngo Weinhold	// add installation location repositories
10583462cc2SIngo Weinhold	if ((flags & B_ADD_INSTALLED_REPOSITORIES) != 0) {
10683462cc2SIngo Weinhold		// We add only the repository of our actual installation location as the
10783462cc2SIngo Weinhold		// "installed" repository. The repositories for the more general
10883462cc2SIngo Weinhold		// installation locations are added as regular repositories, but with
10983462cc2SIngo Weinhold		// better priorities than the actual (remote) repositories. This
11083462cc2SIngo Weinhold		// prevents the solver from showing conflicts when a package in a more
11183462cc2SIngo Weinhold		// specific installation location overrides a package in a more general
11283462cc2SIngo Weinhold		// one. Instead any requirement that is already installed in a more
11383462cc2SIngo Weinhold		// general installation location will turn up as to be installed as
11483462cc2SIngo Weinhold		// well. But we can easily filter those out.
11583462cc2SIngo Weinhold		_AddInstalledRepository(fSystemRepository);
11683462cc2SIngo Weinhold
11736a9daf6SAdrien Destugues		if (!fSystemRepository->IsInstalled()) {
118a22f114fSAdrien Destugues			// Only add the home repository if the directory exists
119a22f114fSAdrien Destugues			BPath path;
120a22f114fSAdrien Destugues			status_t error = find_directory(B_USER_PACKAGES_DIRECTORY, &path);
121a22f114fSAdrien Destugues			if (error == B_OK && BEntry(path.Path()).Exists())
1226262ccbbSAdrien Destugues				_AddInstalledRepository(fHomeRepository);
1236262ccbbSAdrien Destugues		}
12483462cc2SIngo Weinhold	}
12583462cc2SIngo Weinhold
12683462cc2SIngo Weinhold	// add other repositories
12783462cc2SIngo Weinhold	if ((flags & B_ADD_REMOTE_REPOSITORIES) != 0) {
12883462cc2SIngo Weinhold		BPackageRoster roster;
12983462cc2SIngo Weinhold		BStringList repositoryNames;
13083462cc2SIngo Weinhold		error = roster.GetRepositoryNames(repositoryNames);
13183462cc2SIngo Weinhold		if (error != B_OK) {
13283462cc2SIngo Weinhold			fUserInteractionHandler->Warn(error,
13399e5e3fdSHumdinger				B_TRANSLATE("Failed to get repository names"));
13483462cc2SIngo Weinhold		}
13583462cc2SIngo Weinhold
13683462cc2SIngo Weinhold		int32 repositoryNameCount = repositoryNames.CountStrings();
13783462cc2SIngo Weinhold		for (int32 i = 0; i < repositoryNameCount; i++) {
13883462cc2SIngo Weinhold			_AddRemoteRepository(roster, repositoryNames.StringAt(i),
13983462cc2SIngo Weinhold				(flags & B_REFRESH_REPOSITORIES) != 0);
14083462cc2SIngo Weinhold		}
14183462cc2SIngo Weinhold	}
14283462cc2SIngo Weinhold}
14383462cc2SIngo Weinhold
14483462cc2SIngo Weinhold
145d228f29fSIngo Weinholdvoid
146d228f29fSIngo WeinholdBPackageManager::SetDebugLevel(int32 level)
147d228f29fSIngo Weinhold{
148d228f29fSIngo Weinhold	fDebugLevel = level;
149d228f29fSIngo Weinhold
150d228f29fSIngo Weinhold	if (fSolver != NULL)
151d228f29fSIngo Weinhold		fSolver->SetDebugLevel(fDebugLevel);
152d228f29fSIngo Weinhold}
153d228f29fSIngo Weinhold
154d228f29fSIngo Weinhold
15583462cc2SIngo Weinholdvoid
15683462cc2SIngo WeinholdBPackageManager::Install(const char* const* packages, int packageCount)
1577e0d2c4fSIngo Weinhold{
1587e0d2c4fSIngo Weinhold	BSolverPackageSpecifierList packagesToInstall;
159f2f19f11SIngo Weinhold	_AddPackageSpecifiers(packages, packageCount, packagesToInstall);
1607e0d2c4fSIngo Weinhold	Install(packagesToInstall);
1617e0d2c4fSIngo Weinhold}
1627e0d2c4fSIngo Weinhold
1637e0d2c4fSIngo Weinhold
1647e0d2c4fSIngo Weinholdvoid
1657e0d2c4fSIngo WeinholdBPackageManager::Install(const BSolverPackageSpecifierList& packages)
16683462cc2SIngo Weinhold{
16783462cc2SIngo Weinhold	Init(B_ADD_INSTALLED_REPOSITORIES | B_ADD_REMOTE_REPOSITORIES
16883462cc2SIngo Weinhold		| B_REFRESH_REPOSITORIES);
16983462cc2SIngo Weinhold
17083462cc2SIngo Weinhold	// solve
17183462cc2SIngo Weinhold	const BSolverPackageSpecifier* unmatchedSpecifier;
1727e0d2c4fSIngo Weinhold	status_t error = fSolver->Install(packages, &unmatchedSpecifier);
17383462cc2SIngo Weinhold	if (error != B_OK) {
17483462cc2SIngo Weinhold		if (unmatchedSpecifier != NULL) {
175ab8f11bfSBrian Hill			DIE(error, "Failed to find a match for \"%s\"",
17683462cc2SIngo Weinhold				unmatchedSpecifier->SelectString().String());
17783462cc2SIngo Weinhold		} else
178ab8f11bfSBrian Hill			DIE(error, "Failed to compute packages to install");
17983462cc2SIngo Weinhold	}
18083462cc2SIngo Weinhold
18183462cc2SIngo Weinhold	_HandleProblems();
18283462cc2SIngo Weinhold
18383462cc2SIngo Weinhold	// install/uninstall packages
18483462cc2SIngo Weinhold	_AnalyzeResult();
18583462cc2SIngo Weinhold	_ConfirmChanges();
18683462cc2SIngo Weinhold	_ApplyPackageChanges();
18783462cc2SIngo Weinhold}
18883462cc2SIngo Weinhold
18983462cc2SIngo Weinhold
19083462cc2SIngo Weinholdvoid
19183462cc2SIngo WeinholdBPackageManager::Uninstall(const char* const* packages, int packageCount)
1927e0d2c4fSIngo Weinhold{
1937e0d2c4fSIngo Weinhold	BSolverPackageSpecifierList packagesToUninstall;
1947e0d2c4fSIngo Weinhold	if (!packagesToUninstall.AppendSpecifiers(packages, packageCount))
1957e0d2c4fSIngo Weinhold		throw std::bad_alloc();
1967e0d2c4fSIngo Weinhold	Uninstall(packagesToUninstall);
1977e0d2c4fSIngo Weinhold}
1987e0d2c4fSIngo Weinhold
1997e0d2c4fSIngo Weinhold
2007e0d2c4fSIngo Weinholdvoid
2017e0d2c4fSIngo WeinholdBPackageManager::Uninstall(const BSolverPackageSpecifierList& packages)
20283462cc2SIngo Weinhold{
20383462cc2SIngo Weinhold	Init(B_ADD_INSTALLED_REPOSITORIES);
20483462cc2SIngo Weinhold
20583462cc2SIngo Weinhold	// find the packages that match the specification
20683462cc2SIngo Weinhold	const BSolverPackageSpecifier* unmatchedSpecifier;
20783462cc2SIngo Weinhold	PackageList foundPackages;
2087e0d2c4fSIngo Weinhold	status_t error = fSolver->FindPackages(packages,
20983462cc2SIngo Weinhold		BSolver::B_FIND_INSTALLED_ONLY, foundPackages, &unmatchedSpecifier);
21083462cc2SIngo Weinhold	if (error != B_OK) {
21183462cc2SIngo Weinhold		if (unmatchedSpecifier != NULL) {
212ab8f11bfSBrian Hill			DIE(error, "Failed to find a match for \"%s\"",
21383462cc2SIngo Weinhold				unmatchedSpecifier->SelectString().String());
21483462cc2SIngo Weinhold		} else
215ab8f11bfSBrian Hill			DIE(error, "Failed to compute packages to uninstall");
21683462cc2SIngo Weinhold	}
21783462cc2SIngo Weinhold
21883462cc2SIngo Weinhold	// determine the inverse base package closure for the found packages
21983462cc2SIngo Weinhold// TODO: Optimize!
2205a5d1465SIngo Weinhold	InstalledRepository& installationRepository = InstallationRepository();
22183462cc2SIngo Weinhold	bool foundAnotherPackage;
22283462cc2SIngo Weinhold	do {
22383462cc2SIngo Weinhold		foundAnotherPackage = false;
22483462cc2SIngo Weinhold		int32 count = installationRepository.CountPackages();
22583462cc2SIngo Weinhold		for (int32 i = 0; i < count; i++) {
22683462cc2SIngo Weinhold			BSolverPackage* package = installationRepository.PackageAt(i);
22783462cc2SIngo Weinhold			if (foundPackages.HasItem(package))
22883462cc2SIngo Weinhold				continue;
22983462cc2SIngo Weinhold
23083462cc2SIngo Weinhold			if (_FindBasePackage(foundPackages, package->Info()) >= 0) {
23183462cc2SIngo Weinhold				foundPackages.AddItem(package);
23283462cc2SIngo Weinhold				foundAnotherPackage = true;
23383462cc2SIngo Weinhold			}
23483462cc2SIngo Weinhold		}
23583462cc2SIngo Weinhold	} while (foundAnotherPackage);
23683462cc2SIngo Weinhold
23783462cc2SIngo Weinhold	// remove the packages from the repository
23883462cc2SIngo Weinhold	for (int32 i = 0; BSolverPackage* package = foundPackages.ItemAt(i); i++)
23983462cc2SIngo Weinhold		installationRepository.DisablePackage(package);
24083462cc2SIngo Weinhold
24183462cc2SIngo Weinhold	for (;;) {
24283462cc2SIngo Weinhold		error = fSolver->VerifyInstallation(BSolver::B_VERIFY_ALLOW_UNINSTALL);
24383462cc2SIngo Weinhold		if (error != B_OK)
244ab8f11bfSBrian Hill			DIE(error, "Failed to compute packages to uninstall");
24583462cc2SIngo Weinhold
24683462cc2SIngo Weinhold		_HandleProblems();
24783462cc2SIngo Weinhold
24883462cc2SIngo Weinhold		// (virtually) apply the result to this repository
24983462cc2SIngo Weinhold		_AnalyzeResult();
25083462cc2SIngo Weinhold
25183462cc2SIngo Weinhold		for (int32 i = foundPackages.CountItems() - 1; i >= 0; i--) {
25283462cc2SIngo Weinhold			if (!installationRepository.PackagesToDeactivate()
25383462cc2SIngo Weinhold					.AddItem(foundPackages.ItemAt(i))) {
25483462cc2SIngo Weinhold				throw std::bad_alloc();
25583462cc2SIngo Weinhold			}
25683462cc2SIngo Weinhold		}
25783462cc2SIngo Weinhold
25883462cc2SIngo Weinhold		installationRepository.ApplyChanges();
25983462cc2SIngo Weinhold
26083462cc2SIngo Weinhold		// verify the next specific respository
26183462cc2SIngo Weinhold		if (!_NextSpecificInstallationLocation())
26283462cc2SIngo Weinhold			break;
26383462cc2SIngo Weinhold
26483462cc2SIngo Weinhold		foundPackages.MakeEmpty();
26583462cc2SIngo Weinhold
26683462cc2SIngo Weinhold		// NOTE: In theory, after verifying a more specific location, it would
26783462cc2SIngo Weinhold		// be more correct to compute the inverse base package closure for the
26883462cc2SIngo Weinhold		// packages we need to uninstall and (if anything changed) verify again.
26983462cc2SIngo Weinhold		// In practice, however, base packages are always required with an exact
27083462cc2SIngo Weinhold		// version (ATM). If that base package still exist in a more general
27183462cc2SIngo Weinhold		// location (the only reason why the package requiring the base package
27283462cc2SIngo Weinhold		// wouldn't be marked to be uninstalled as well) there shouldn't have
27383462cc2SIngo Weinhold		// been any reason to remove it from the more specific location in the
27483462cc2SIngo Weinhold		// first place.
27583462cc2SIngo Weinhold	}
27683462cc2SIngo Weinhold
27783462cc2SIngo Weinhold	_ConfirmChanges(true);
27883462cc2SIngo Weinhold	_ApplyPackageChanges(true);
27983462cc2SIngo Weinhold}
28083462cc2SIngo Weinhold
28183462cc2SIngo Weinhold
28283462cc2SIngo Weinholdvoid
28383462cc2SIngo WeinholdBPackageManager::Update(const char* const* packages, int packageCount)
2847e0d2c4fSIngo Weinhold{
2857e0d2c4fSIngo Weinhold	BSolverPackageSpecifierList packagesToUpdate;
286f2f19f11SIngo Weinhold	_AddPackageSpecifiers(packages, packageCount, packagesToUpdate);
2877e0d2c4fSIngo Weinhold	Update(packagesToUpdate);
2887e0d2c4fSIngo Weinhold}
2897e0d2c4fSIngo Weinhold
2907e0d2c4fSIngo Weinhold
2917e0d2c4fSIngo Weinholdvoid
2927e0d2c4fSIngo WeinholdBPackageManager::Update(const BSolverPackageSpecifierList& packages)
29383462cc2SIngo Weinhold{
29483462cc2SIngo Weinhold	Init(B_ADD_INSTALLED_REPOSITORIES | B_ADD_REMOTE_REPOSITORIES
29583462cc2SIngo Weinhold		| B_REFRESH_REPOSITORIES);
29683462cc2SIngo Weinhold
29783462cc2SIngo Weinhold	// solve
29883462cc2SIngo Weinhold	const BSolverPackageSpecifier* unmatchedSpecifier;
2997e0d2c4fSIngo Weinhold	status_t error = fSolver->Update(packages, true,
30083462cc2SIngo Weinhold		&unmatchedSpecifier);
30183462cc2SIngo Weinhold	if (error != B_OK) {
30283462cc2SIngo Weinhold		if (unmatchedSpecifier != NULL) {
303ab8f11bfSBrian Hill			DIE(error, "Failed to find a match for \"%s\"",
30483462cc2SIngo Weinhold				unmatchedSpecifier->SelectString().String());
30583462cc2SIngo Weinhold		} else
306ab8f11bfSBrian Hill			DIE(error, "Failed to compute packages to update");
30783462cc2SIngo Weinhold	}
30883462cc2SIngo Weinhold
30983462cc2SIngo Weinhold	_HandleProblems();
31083462cc2SIngo Weinhold
31183462cc2SIngo Weinhold	// install/uninstall packages
31283462cc2SIngo Weinhold	_AnalyzeResult();
31383462cc2SIngo Weinhold	_ConfirmChanges();
31483462cc2SIngo Weinhold	_ApplyPackageChanges();
31583462cc2SIngo Weinhold}
31683462cc2SIngo Weinhold
31783462cc2SIngo Weinhold
3186ef57ae2SIngo Weinholdvoid
3196ef57ae2SIngo WeinholdBPackageManager::FullSync()
3206ef57ae2SIngo Weinhold{
3216ef57ae2SIngo Weinhold	Init(B_ADD_INSTALLED_REPOSITORIES | B_ADD_REMOTE_REPOSITORIES
3226ef57ae2SIngo Weinhold		| B_REFRESH_REPOSITORIES);
3236ef57ae2SIngo Weinhold
3246ef57ae2SIngo Weinhold	// solve
3256ef57ae2SIngo Weinhold	status_t error = fSolver->FullSync();
3266ef57ae2SIngo Weinhold	if (error != B_OK)
327ab8f11bfSBrian Hill		DIE(error, "Failed to compute packages to synchronize");
3286ef57ae2SIngo Weinhold
3296ef57ae2SIngo Weinhold	_HandleProblems();
3306ef57ae2SIngo Weinhold
3316ef57ae2SIngo Weinhold	// install/uninstall packages
3326ef57ae2SIngo Weinhold	_AnalyzeResult();
3336ef57ae2SIngo Weinhold	_ConfirmChanges();
3346ef57ae2SIngo Weinhold	_ApplyPackageChanges();
3356ef57ae2SIngo Weinhold}
3366ef57ae2SIngo Weinhold
3376ef57ae2SIngo Weinhold
338c032903aSIngo Weinholdvoid
339c032903aSIngo WeinholdBPackageManager::VerifyInstallation()
340c032903aSIngo Weinhold{
341c032903aSIngo Weinhold	Init(B_ADD_INSTALLED_REPOSITORIES | B_ADD_REMOTE_REPOSITORIES
342c032903aSIngo Weinhold		| B_REFRESH_REPOSITORIES);
343c032903aSIngo Weinhold
344c032903aSIngo Weinhold	for (;;) {
345c032903aSIngo Weinhold		status_t error = fSolver->VerifyInstallation();
346c032903aSIngo Weinhold		if (error != B_OK)
347ab8f11bfSBrian Hill			DIE(error, "Failed to compute package dependencies");
348c032903aSIngo Weinhold
349c032903aSIngo Weinhold		_HandleProblems();
350c032903aSIngo Weinhold
351c032903aSIngo Weinhold		// (virtually) apply the result to this repository
352c032903aSIngo Weinhold		_AnalyzeResult();
353c032903aSIngo Weinhold		InstallationRepository().ApplyChanges();
354c032903aSIngo Weinhold
355c032903aSIngo Weinhold		// verify the next specific respository
356c032903aSIngo Weinhold		if (!_NextSpecificInstallationLocation())
357c032903aSIngo Weinhold			break;
358c032903aSIngo Weinhold	}
359c032903aSIngo Weinhold
360c032903aSIngo Weinhold	_ConfirmChanges();
361c032903aSIngo Weinhold	_ApplyPackageChanges();
362c032903aSIngo Weinhold}
363c032903aSIngo Weinhold
364c032903aSIngo Weinhold
3655a5d1465SIngo WeinholdBPackageManager::InstalledRepository&
3665a5d1465SIngo WeinholdBPackageManager::InstallationRepository()
3675a5d1465SIngo Weinhold{
3685a5d1465SIngo Weinhold	if (fInstalledRepositories.IsEmpty())
369ab8f11bfSBrian Hill		DIE("No installation repository");
3705a5d1465SIngo Weinhold
3715a5d1465SIngo Weinhold	return *fInstalledRepositories.LastItem();
3725a5d1465SIngo Weinhold}
3735a5d1465SIngo Weinhold
3745a5d1465SIngo Weinhold
3759345049aSRene Gollentvoid
376e711e6e4SAxel DörflerBPackageManager::JobStarted(BSupportKit::BJob* job)
3779345049aSRene Gollent{
3789345049aSRene Gollent	if (dynamic_cast<FetchFileJob*>(job) != NULL) {
3799345049aSRene Gollent		FetchFileJob* fetchJob = (FetchFileJob*)job;
3809345049aSRene Gollent		fUserInteractionHandler->ProgressPackageDownloadStarted(
3819345049aSRene Gollent			fetchJob->DownloadFileName());
3829345049aSRene Gollent	} else if (dynamic_cast<ValidateChecksumJob*>(job) != NULL) {
3839345049aSRene Gollent		fUserInteractionHandler->ProgressPackageChecksumStarted(
3849345049aSRene Gollent			job->Title().String());
3859345049aSRene Gollent	}
3869345049aSRene Gollent}
3879345049aSRene Gollent
3889345049aSRene Gollent
3899345049aSRene Gollentvoid
390e711e6e4SAxel DörflerBPackageManager::JobProgress(BSupportKit::BJob* job)
3919345049aSRene Gollent{
3929345049aSRene Gollent	if (dynamic_cast<FetchFileJob*>(job) != NULL) {
3939345049aSRene Gollent		FetchFileJob* fetchJob = (FetchFileJob*)job;
3949345049aSRene Gollent		fUserInteractionHandler->ProgressPackageDownloadActive(
3951aaa0c21SAxel Dörfler			fetchJob->DownloadFileName(), fetchJob->DownloadProgress(),
3961aaa0c21SAxel Dörfler			fetchJob->DownloadBytes(), fetchJob->DownloadTotalBytes());
3979345049aSRene Gollent	}
3989345049aSRene Gollent}
3999345049aSRene Gollent
4009345049aSRene Gollent
4019345049aSRene Gollentvoid
402e711e6e4SAxel DörflerBPackageManager::JobSucceeded(BSupportKit::BJob* job)
4039345049aSRene Gollent{
4049345049aSRene Gollent	if (dynamic_cast<FetchFileJob*>(job) != NULL) {
4059345049aSRene Gollent		FetchFileJob* fetchJob = (FetchFileJob*)job;
4069345049aSRene Gollent		fUserInteractionHandler->ProgressPackageDownloadComplete(
4079345049aSRene Gollent			fetchJob->DownloadFileName());
4089345049aSRene Gollent	} else if (dynamic_cast<ValidateChecksumJob*>(job) != NULL) {
4099345049aSRene Gollent		fUserInteractionHandler->ProgressPackageChecksumComplete(
4109345049aSRene Gollent			job->Title().String());
4119345049aSRene Gollent	}
4129345049aSRene Gollent}
4139345049aSRene Gollent
4149345049aSRene Gollent
41583462cc2SIngo Weinholdvoid
41683462cc2SIngo WeinholdBPackageManager::_HandleProblems()
41783462cc2SIngo Weinhold{
41883462cc2SIngo Weinhold	while (fSolver->HasProblems()) {
41983462cc2SIngo Weinhold		fUserInteractionHandler->HandleProblems();
42083462cc2SIngo Weinhold
42183462cc2SIngo Weinhold		status_t error = fSolver->SolveAgain();
42283462cc2SIngo Weinhold		if (error != B_OK)
423ab8f11bfSBrian Hill			DIE(error, "Failed to recompute packages to un/-install");
42483462cc2SIngo Weinhold	}
42583462cc2SIngo Weinhold}
42683462cc2SIngo Weinhold
42783462cc2SIngo Weinhold
42883462cc2SIngo Weinholdvoid
42983462cc2SIngo WeinholdBPackageManager::_AnalyzeResult()
43083462cc2SIngo Weinhold{
43183462cc2SIngo Weinhold	BSolverResult result;
43283462cc2SIngo Weinhold	status_t error = fSolver->GetResult(result);
43383462cc2SIngo Weinhold	if (error != B_OK)
434ab8f11bfSBrian Hill		DIE(error, "Failed to compute packages to un/-install");
43583462cc2SIngo Weinhold
4365a5d1465SIngo Weinhold	InstalledRepository& installationRepository = InstallationRepository();
43783462cc2SIngo Weinhold	PackageList& packagesToActivate
43883462cc2SIngo Weinhold		= installationRepository.PackagesToActivate();
43983462cc2SIngo Weinhold	PackageList& packagesToDeactivate
44083462cc2SIngo Weinhold		= installationRepository.PackagesToDeactivate();
44183462cc2SIngo Weinhold
44283462cc2SIngo Weinhold	PackageList potentialBasePackages;
44383462cc2SIngo Weinhold
44483462cc2SIngo Weinhold	for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
44583462cc2SIngo Weinhold			i++) {
44683462cc2SIngo Weinhold		BSolverPackage* package = element->Package();
44783462cc2SIngo Weinhold
44883462cc2SIngo Weinhold		switch (element->Type()) {
44983462cc2SIngo Weinhold			case BSolverResultElement::B_TYPE_INSTALL:
45083462cc2SIngo Weinhold			{
45183462cc2SIngo Weinhold				PackageList& packageList
45283462cc2SIngo Weinhold					= dynamic_cast<InstalledRepository*>(package->Repository())
45383462cc2SIngo Weinhold							!= NULL
45483462cc2SIngo Weinhold						? potentialBasePackages
45583462cc2SIngo Weinhold						: packagesToActivate;
45683462cc2SIngo Weinhold				if (!packageList.AddItem(package))
45783462cc2SIngo Weinhold					throw std::bad_alloc();
45883462cc2SIngo Weinhold				break;
45983462cc2SIngo Weinhold			}
46083462cc2SIngo Weinhold
46183462cc2SIngo Weinhold			case BSolverResultElement::B_TYPE_UNINSTALL:
46283462cc2SIngo Weinhold				if (!packagesToDeactivate.AddItem(package))
46383462cc2SIngo Weinhold					throw std::bad_alloc();
46483462cc2SIngo Weinhold				break;
46583462cc2SIngo Weinhold		}
46683462cc2SIngo Weinhold	}
46783462cc2SIngo Weinhold
46883462cc2SIngo Weinhold	// Make sure base packages are installed in the same location.
46983462cc2SIngo Weinhold	for (int32 i = 0; i < packagesToActivate.CountItems(); i++) {
47083462cc2SIngo Weinhold		BSolverPackage* package = packagesToActivate.ItemAt(i);
47183462cc2SIngo Weinhold		int32 index = _FindBasePackage(potentialBasePackages, package->Info());
47283462cc2SIngo Weinhold		if (index < 0)
47383462cc2SIngo Weinhold			continue;
47483462cc2SIngo Weinhold
47583462cc2SIngo Weinhold		BSolverPackage* basePackage = potentialBasePackages.RemoveItemAt(index);
47683462cc2SIngo Weinhold		if (!packagesToActivate.AddItem(basePackage))
47783462cc2SIngo Weinhold			throw std::bad_alloc();
47883462cc2SIngo Weinhold	}
479018173a2SIngo Weinhold
480018173a2SIngo Weinhold	fInstallationInterface->ResultComputed(installationRepository);
48183462cc2SIngo Weinhold}
48283462cc2SIngo Weinhold
48383462cc2SIngo Weinhold
48483462cc2SIngo Weinholdvoid
48583462cc2SIngo WeinholdBPackageManager::_ConfirmChanges(bool fromMostSpecific)
48683462cc2SIngo Weinhold{
48783462cc2SIngo Weinhold	// check, if there are any changes at all
48883462cc2SIngo Weinhold	int32 count = fInstalledRepositories.CountItems();
48983462cc2SIngo Weinhold	bool hasChanges = false;
49083462cc2SIngo Weinhold	for (int32 i = 0; i < count; i++) {
49183462cc2SIngo Weinhold		if (fInstalledRepositories.ItemAt(i)->HasChanges()) {
49283462cc2SIngo Weinhold			hasChanges = true;
49383462cc2SIngo Weinhold			break;
49483462cc2SIngo Weinhold		}
49583462cc2SIngo Weinhold	}
49683462cc2SIngo Weinhold
49783462cc2SIngo Weinhold	if (!hasChanges)
49883462cc2SIngo Weinhold		throw BNothingToDoException();
49983462cc2SIngo Weinhold
50083462cc2SIngo Weinhold	fUserInteractionHandler->ConfirmChanges(fromMostSpecific);
50183462cc2SIngo Weinhold}
50283462cc2SIngo Weinhold
50383462cc2SIngo Weinhold
50483462cc2SIngo Weinholdvoid
50583462cc2SIngo WeinholdBPackageManager::_ApplyPackageChanges(bool fromMostSpecific)
50683462cc2SIngo Weinhold{
50783462cc2SIngo Weinhold	int32 count = fInstalledRepositories.CountItems();
50883462cc2SIngo Weinhold	if (fromMostSpecific) {
50983462cc2SIngo Weinhold		for (int32 i = count - 1; i >= 0; i--)
51083462cc2SIngo Weinhold			_PreparePackageChanges(*fInstalledRepositories.ItemAt(i));
51183462cc2SIngo Weinhold	} else {
51283462cc2SIngo Weinhold		for (int32 i = 0; i < count; i++)
51383462cc2SIngo Weinhold			_PreparePackageChanges(*fInstalledRepositories.ItemAt(i));
51483462cc2SIngo Weinhold	}
51583462cc2SIngo Weinhold
51683462cc2SIngo Weinhold	for (int32 i = 0; Transaction* transaction = fTransactions.ItemAt(i); i++)
51783462cc2SIngo Weinhold		_CommitPackageChanges(*transaction);
51883462cc2SIngo Weinhold
51983462cc2SIngo Weinhold// TODO: Clean up the transaction directories on error!
52083462cc2SIngo Weinhold}
52183462cc2SIngo Weinhold
52283462cc2SIngo Weinhold
52383462cc2SIngo Weinholdvoid
52483462cc2SIngo WeinholdBPackageManager::_PreparePackageChanges(
52583462cc2SIngo Weinhold	InstalledRepository& installationRepository)
52683462cc2SIngo Weinhold{
52783462cc2SIngo Weinhold	if (!installationRepository.HasChanges())
52883462cc2SIngo Weinhold		return;
52983462cc2SIngo Weinhold
53083462cc2SIngo Weinhold	PackageList& packagesToActivate
53183462cc2SIngo Weinhold		= installationRepository.PackagesToActivate();
53283462cc2SIngo Weinhold	PackageList& packagesToDeactivate
53383462cc2SIngo Weinhold		= installationRepository.PackagesToDeactivate();
53483462cc2SIngo Weinhold
53583462cc2SIngo Weinhold	// create the transaction
53683462cc2SIngo Weinhold	Transaction* transaction = new Transaction(installationRepository);
53783462cc2SIngo Weinhold	if (!fTransactions.AddItem(transaction)) {
53883462cc2SIngo Weinhold		delete transaction;
53983462cc2SIngo Weinhold		throw std::bad_alloc();
54083462cc2SIngo Weinhold	}
54183462cc2SIngo Weinhold
542cf3bb0d7SIngo Weinhold	status_t error = fInstallationInterface->PrepareTransaction(*transaction);
54383462cc2SIngo Weinhold	if (error != B_OK)
544ab8f11bfSBrian Hill		DIE(error, "Failed to create transaction");
54583462cc2SIngo Weinhold
54683462cc2SIngo Weinhold	// download the new packages and prepare the transaction
54783462cc2SIngo Weinhold	for (int32 i = 0; BSolverPackage* package = packagesToActivate.ItemAt(i);
54883462cc2SIngo Weinhold		i++) {
54983462cc2SIngo Weinhold		// get package URL and target entry
55083462cc2SIngo Weinhold
55183462cc2SIngo Weinhold		BString fileName(package->Info().FileName());
55283462cc2SIngo Weinhold		if (fileName.IsEmpty())
55383462cc2SIngo Weinhold			throw std::bad_alloc();
55483462cc2SIngo Weinhold
55583462cc2SIngo Weinhold		BEntry entry;
55683462cc2SIngo Weinhold		error = entry.SetTo(&transaction->TransactionDirectory(), fileName);
55783462cc2SIngo Weinhold		if (error != B_OK)
558ab8f11bfSBrian Hill			DIE(error, "Failed to create package entry");
55983462cc2SIngo Weinhold
56083462cc2SIngo Weinhold		RemoteRepository* remoteRepository
56183462cc2SIngo Weinhold			= dynamic_cast<RemoteRepository*>(package->Repository());
562f2f19f11SIngo Weinhold		if (remoteRepository != NULL) {
56383462cc2SIngo Weinhold			// download the package
56483462cc2SIngo Weinhold			BString url = remoteRepository->Config().PackagesURL();
56583462cc2SIngo Weinhold			url << '/' << fileName;
56683462cc2SIngo Weinhold
567fe39d2ebSRene Gollent			status_t error = DownloadPackage(url, entry,
56883462cc2SIngo Weinhold				package->Info().Checksum());
56983462cc2SIngo Weinhold			if (error != B_OK)
570ab8f11bfSBrian Hill				DIE(error, "Failed to download package %s",
571ab8f11bfSBrian Hill					package->Info().Name().String());
572f2f19f11SIngo Weinhold		} else if (package->Repository() != &installationRepository) {
573f2f19f11SIngo Weinhold			// clone the existing package
574f2f19f11SIngo Weinhold			LocalRepository* localRepository
575f2f19f11SIngo Weinhold				= dynamic_cast<LocalRepository*>(package->Repository());
576f2f19f11SIngo Weinhold			if (localRepository == NULL) {
577ab8f11bfSBrian Hill				DIE("Internal error: repository %s is not a local repository",
578f2f19f11SIngo Weinhold					package->Repository()->Name().String());
579f2f19f11SIngo Weinhold			}
580f2f19f11SIngo Weinhold			_ClonePackageFile(localRepository, package, entry);
58183462cc2SIngo Weinhold		}
58283462cc2SIngo Weinhold
58383462cc2SIngo Weinhold		// add package to transaction
58483462cc2SIngo Weinhold		if (!transaction->ActivationTransaction().AddPackageToActivate(
58583462cc2SIngo Weinhold				fileName)) {
58683462cc2SIngo Weinhold			throw std::bad_alloc();
58783462cc2SIngo Weinhold		}
58883462cc2SIngo Weinhold	}
58983462cc2SIngo Weinhold
59083462cc2SIngo Weinhold	for (int32 i = 0; BSolverPackage* package = packagesToDeactivate.ItemAt(i);
59183462cc2SIngo Weinhold		i++) {
59283462cc2SIngo Weinhold		// add package to transaction
59383462cc2SIngo Weinhold		if (!transaction->ActivationTransaction().AddPackageToDeactivate(
59483462cc2SIngo Weinhold				package->Info().FileName())) {
59583462cc2SIngo Weinhold			throw std::bad_alloc();
59683462cc2SIngo Weinhold		}
59783462cc2SIngo Weinhold	}
59883462cc2SIngo Weinhold}
59983462cc2SIngo Weinhold
60083462cc2SIngo Weinhold
60183462cc2SIngo Weinholdvoid
60283462cc2SIngo WeinholdBPackageManager::_CommitPackageChanges(Transaction& transaction)
60383462cc2SIngo Weinhold{
60483462cc2SIngo Weinhold	InstalledRepository& installationRepository = transaction.Repository();
60583462cc2SIngo Weinhold
60683462cc2SIngo Weinhold	fUserInteractionHandler->ProgressStartApplyingChanges(
60783462cc2SIngo Weinhold		installationRepository);
60883462cc2SIngo Weinhold
60983462cc2SIngo Weinhold	// commit the transaction
6100de3219eSIngo Weinhold	BCommitTransactionResult transactionResult;
611cf3bb0d7SIngo Weinhold	status_t