Files
haiku-beta6/src/kits/package/manager/PackageManager.cpp
T
Ingo Weinhold f2f19f110d BPackageManager: Support installing/updating local package files
* The Install() and Update() versions that take a const char* array
  now check whether a string looks like a path to a local package file.
  If so, they use that file instead of interpreting the string as a
  search string.
* Extend the repository hierarchy. There's now a LocalRepository base
  class from which InstalledRepository and the new MiscLocalRepository
  derive. The latter is instantiated once and collects all package files
  specified by path.
2014-06-15 17:21:01 +02:00

1148 lines
28 KiB
C++

/*
* Copyright 2013-2014, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ingo Weinhold <[email protected]>
* Rene Gollent <[email protected]>
*/
#include <package/manager/PackageManager.h>
#include <Directory.h>
#include <package/CommitTransactionResult.h>
#include <package/DownloadFileRequest.h>
#include <package/PackageRoster.h>
#include <package/RefreshRepositoryRequest.h>
#include <package/RepositoryCache.h>
#include <package/solver/SolverPackage.h>
#include <package/solver/SolverPackageSpecifier.h>
#include <package/solver/SolverPackageSpecifierList.h>
#include <package/solver/SolverProblem.h>
#include <package/solver/SolverProblemSolution.h>
#include <package/solver/SolverResult.h>
#include <CopyEngine.h>
#include <package/ActivationTransaction.h>
#include <package/DaemonClient.h>
#include <package/FetchFileJob.h>
#include <package/manager/RepositoryBuilder.h>
#include <package/ValidateChecksumJob.h>
#include "PackageManagerUtils.h"
using BPackageKit::BPrivate::FetchFileJob;
using BPackageKit::BPrivate::ValidateChecksumJob;
namespace BPackageKit {
namespace BManager {
namespace BPrivate {
// #pragma mark - BPackageManager
BPackageManager::BPackageManager(BPackageInstallationLocation location,
InstallationInterface* installationInterface,
UserInteractionHandler* userInteractionHandler)
:
fLocation(location),
fSolver(NULL),
fSystemRepository(new (std::nothrow) InstalledRepository("system",
B_PACKAGE_INSTALLATION_LOCATION_SYSTEM, -1)),
fHomeRepository(new (std::nothrow) InstalledRepository("home",
B_PACKAGE_INSTALLATION_LOCATION_HOME, -3)),
fInstalledRepositories(10),
fOtherRepositories(10, true),
fLocalRepository(NULL),
fTransactions(5, true),
fInstallationInterface(installationInterface),
fUserInteractionHandler(userInteractionHandler)
{
}
BPackageManager::~BPackageManager()
{
delete fSolver;
delete fSystemRepository;
delete fHomeRepository;
delete fLocalRepository;
}
void
BPackageManager::Init(uint32 flags)
{
if (fSolver != NULL)
return;
// create the solver
status_t error = BSolver::Create(fSolver);
if (error != B_OK)
DIE(error, "failed to create solver");
if (fSystemRepository == NULL || fHomeRepository == NULL)
throw std::bad_alloc();
if (fLocalRepository != NULL)
BRepositoryBuilder(*fLocalRepository).AddToSolver(fSolver, false);
// add installation location repositories
if ((flags & B_ADD_INSTALLED_REPOSITORIES) != 0) {
// We add only the repository of our actual installation location as the
// "installed" repository. The repositories for the more general
// installation locations are added as regular repositories, but with
// better priorities than the actual (remote) repositories. This
// prevents the solver from showing conflicts when a package in a more
// specific installation location overrides a package in a more general
// one. Instead any requirement that is already installed in a more
// general installation location will turn up as to be installed as
// well. But we can easily filter those out.
_AddInstalledRepository(fSystemRepository);
if (!fSystemRepository->IsInstalled())
_AddInstalledRepository(fHomeRepository);
}
// add other repositories
if ((flags & B_ADD_REMOTE_REPOSITORIES) != 0) {
BPackageRoster roster;
BStringList repositoryNames;
error = roster.GetRepositoryNames(repositoryNames);
if (error != B_OK) {
fUserInteractionHandler->Warn(error,
"failed to get repository names");
}
int32 repositoryNameCount = repositoryNames.CountStrings();
for (int32 i = 0; i < repositoryNameCount; i++) {
_AddRemoteRepository(roster, repositoryNames.StringAt(i),
(flags & B_REFRESH_REPOSITORIES) != 0);
}
}
}
void
BPackageManager::Install(const char* const* packages, int packageCount)
{
BSolverPackageSpecifierList packagesToInstall;
_AddPackageSpecifiers(packages, packageCount, packagesToInstall);
Install(packagesToInstall);
}
void
BPackageManager::Install(const BSolverPackageSpecifierList& packages)
{
Init(B_ADD_INSTALLED_REPOSITORIES | B_ADD_REMOTE_REPOSITORIES
| B_REFRESH_REPOSITORIES);
// solve
const BSolverPackageSpecifier* unmatchedSpecifier;
status_t error = fSolver->Install(packages, &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 install");
}
_HandleProblems();
// install/uninstall packages
_AnalyzeResult();
_ConfirmChanges();
_ApplyPackageChanges();
}
void
BPackageManager::Uninstall(const char* const* packages, int packageCount)
{
BSolverPackageSpecifierList packagesToUninstall;
if (!packagesToUninstall.AppendSpecifiers(packages, packageCount))
throw std::bad_alloc();
Uninstall(packagesToUninstall);
}
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);
}
void
BPackageManager::Update(const char* const* packages, int packageCount)
{
BSolverPackageSpecifierList packagesToUpdate;
_AddPackageSpecifiers(packages, packageCount, packagesToUpdate);
Update(packagesToUpdate);
}
void
BPackageManager::Update(const BSolverPackageSpecifierList& packages)
{
Init(B_ADD_INSTALLED_REPOSITORIES | B_ADD_REMOTE_REPOSITORIES
| B_REFRESH_REPOSITORIES);
// solve
const BSolverPackageSpecifier* unmatchedSpecifier;
status_t error = fSolver->Update(packages, true,
&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 update");
}
_HandleProblems();
// install/uninstall packages
_AnalyzeResult();
_ConfirmChanges();
_ApplyPackageChanges();
}
void
BPackageManager::FullSync()
{
Init(B_ADD_INSTALLED_REPOSITORIES | B_ADD_REMOTE_REPOSITORIES
| B_REFRESH_REPOSITORIES);
// solve
status_t error = fSolver->FullSync();
if (error != B_OK)
DIE(error, "failed to compute packages to synchronize");
_HandleProblems();
// install/uninstall packages
_AnalyzeResult();
_ConfirmChanges();
_ApplyPackageChanges();
}
void
BPackageManager::VerifyInstallation()
{
Init(B_ADD_INSTALLED_REPOSITORIES | B_ADD_REMOTE_REPOSITORIES
| B_REFRESH_REPOSITORIES);
for (;;) {
status_t error = fSolver->VerifyInstallation();
if (error != B_OK)
DIE(error, "failed to compute package dependencies");
_HandleProblems();
// (virtually) apply the result to this repository
_AnalyzeResult();
InstallationRepository().ApplyChanges();
// verify the next specific respository
if (!_NextSpecificInstallationLocation())
break;
}
_ConfirmChanges();
_ApplyPackageChanges();
}
BPackageManager::InstalledRepository&
BPackageManager::InstallationRepository()
{
if (fInstalledRepositories.IsEmpty())
DIE("no installation repository");
return *fInstalledRepositories.LastItem();
}
void
BPackageManager::JobStarted(BJob* job)
{
if (dynamic_cast<FetchFileJob*>(job) != NULL) {
FetchFileJob* fetchJob = (FetchFileJob*)job;
fUserInteractionHandler->ProgressPackageDownloadStarted(
fetchJob->DownloadFileName());
} else if (dynamic_cast<ValidateChecksumJob*>(job) != NULL) {
fUserInteractionHandler->ProgressPackageChecksumStarted(
job->Title().String());
}
}
void
BPackageManager::JobProgress(BJob* job)
{
if (dynamic_cast<FetchFileJob*>(job) != NULL) {
FetchFileJob* fetchJob = (FetchFileJob*)job;
fUserInteractionHandler->ProgressPackageDownloadActive(
fetchJob->DownloadFileName(), fetchJob->DownloadProgress());
}
}
void
BPackageManager::JobSucceeded(BJob* job)
{
if (dynamic_cast<FetchFileJob*>(job) != NULL) {
FetchFileJob* fetchJob = (FetchFileJob*)job;
fUserInteractionHandler->ProgressPackageDownloadComplete(
fetchJob->DownloadFileName());
} else if (dynamic_cast<ValidateChecksumJob*>(job) != NULL) {
fUserInteractionHandler->ProgressPackageChecksumComplete(
job->Title().String());
}
}
void
BPackageManager::_HandleProblems()
{
while (fSolver->HasProblems()) {
fUserInteractionHandler->HandleProblems();
status_t error = fSolver->SolveAgain();
if (error != B_OK)
DIE(error, "failed to recompute packages to un/-install");
}
}
void
BPackageManager::_AnalyzeResult()
{
BSolverResult result;
status_t error = fSolver->GetResult(result);
if (error != B_OK)
DIE(error, "failed to compute packages to un/-install");
InstalledRepository& installationRepository = InstallationRepository();
PackageList& packagesToActivate
= installationRepository.PackagesToActivate();
PackageList& packagesToDeactivate
= installationRepository.PackagesToDeactivate();
PackageList potentialBasePackages;
for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
i++) {
BSolverPackage* package = element->Package();
switch (element->Type()) {
case BSolverResultElement::B_TYPE_INSTALL:
{
PackageList& packageList
= dynamic_cast<InstalledRepository*>(package->Repository())
!= NULL
? potentialBasePackages
: packagesToActivate;
if (!packageList.AddItem(package))
throw std::bad_alloc();
break;
}
case BSolverResultElement::B_TYPE_UNINSTALL:
if (!packagesToDeactivate.AddItem(package))
throw std::bad_alloc();
break;
}
}
// Make sure base packages are installed in the same location.
for (int32 i = 0; i < packagesToActivate.CountItems(); i++) {
BSolverPackage* package = packagesToActivate.ItemAt(i);
int32 index = _FindBasePackage(potentialBasePackages, package->Info());
if (index < 0)
continue;
BSolverPackage* basePackage = potentialBasePackages.RemoveItemAt(index);
if (!packagesToActivate.AddItem(basePackage))
throw std::bad_alloc();
}
fInstallationInterface->ResultComputed(installationRepository);
}
void
BPackageManager::_ConfirmChanges(bool fromMostSpecific)
{
// check, if there are any changes at all
int32 count = fInstalledRepositories.CountItems();
bool hasChanges = false;
for (int32 i = 0; i < count; i++) {
if (fInstalledRepositories.ItemAt(i)->HasChanges()) {
hasChanges = true;
break;
}
}
if (!hasChanges)
throw BNothingToDoException();
fUserInteractionHandler->ConfirmChanges(fromMostSpecific);
}
void
BPackageManager::_ApplyPackageChanges(bool fromMostSpecific)
{
int32 count = fInstalledRepositories.CountItems();
if (fromMostSpecific) {
for (int32 i = count - 1; i >= 0; i--)
_PreparePackageChanges(*fInstalledRepositories.ItemAt(i));
} else {
for (int32 i = 0; i < count; i++)
_PreparePackageChanges(*fInstalledRepositories.ItemAt(i));
}
for (int32 i = 0; Transaction* transaction = fTransactions.ItemAt(i); i++)
_CommitPackageChanges(*transaction);
// TODO: Clean up the transaction directories on error!
}
void
BPackageManager::_PreparePackageChanges(
InstalledRepository& installationRepository)
{
if (!installationRepository.HasChanges())
return;
PackageList& packagesToActivate
= installationRepository.PackagesToActivate();
PackageList& packagesToDeactivate
= installationRepository.PackagesToDeactivate();
// create the transaction
Transaction* transaction = new Transaction(installationRepository);
if (!fTransactions.AddItem(transaction)) {
delete transaction;
throw std::bad_alloc();
}
status_t error = fInstallationInterface->PrepareTransaction(*transaction);
if (error != B_OK)
DIE(error, "failed to create transaction");
// download the new packages and prepare the transaction
for (int32 i = 0; BSolverPackage* package = packagesToActivate.ItemAt(i);
i++) {
// get package URL and target entry
BString fileName(package->Info().FileName());
if (fileName.IsEmpty())
throw std::bad_alloc();
BEntry entry;
error = entry.SetTo(&transaction->TransactionDirectory(), fileName);
if (error != B_OK)
DIE(error, "failed to create package entry");
RemoteRepository* remoteRepository
= dynamic_cast<RemoteRepository*>(package->Repository());
if (remoteRepository != NULL) {
// download the package
BString url = remoteRepository->Config().PackagesURL();
url << '/' << fileName;
status_t error = DownloadPackage(url, entry,
package->Info().Checksum());
if (error != B_OK)
DIE(error, "failed to download package");
} else if (package->Repository() != &installationRepository) {
// clone the existing package
LocalRepository* localRepository
= dynamic_cast<LocalRepository*>(package->Repository());
if (localRepository == NULL) {
DIE("internal error: repository %s is not a local repository",
package->Repository()->Name().String());
}
_ClonePackageFile(localRepository, package, entry);
}
// add package to transaction
if (!transaction->ActivationTransaction().AddPackageToActivate(
fileName)) {
throw std::bad_alloc();
}
}
for (int32 i = 0; BSolverPackage* package = packagesToDeactivate.ItemAt(i);
i++) {
// add package to transaction
if (!transaction->ActivationTransaction().AddPackageToDeactivate(
package->Info().FileName())) {
throw std::bad_alloc();
}
}
}
void
BPackageManager::_CommitPackageChanges(Transaction& transaction)
{
InstalledRepository& installationRepository = transaction.Repository();
fUserInteractionHandler->ProgressStartApplyingChanges(
installationRepository);
// commit the transaction
BCommitTransactionResult transactionResult;
status_t error = fInstallationInterface->CommitTransaction(transaction,
transactionResult);
if (error != B_OK)
DIE(error, "failed to commit transaction");
if (transactionResult.Error() != B_TRANSACTION_OK)
DIE(transactionResult);
fUserInteractionHandler->ProgressTransactionCommitted(
installationRepository, transactionResult);
BEntry transactionDirectoryEntry;
if ((error = transaction.TransactionDirectory()
.GetEntry(&transactionDirectoryEntry)) != B_OK
|| (error = transactionDirectoryEntry.Remove()) != B_OK) {
fUserInteractionHandler->Warn(error,
"failed to remove transaction directory");
}
fUserInteractionHandler->ProgressApplyingChangesDone(
installationRepository);
}
void
BPackageManager::_ClonePackageFile(LocalRepository* repository,
BSolverPackage* package, const BEntry& entry)
{
// get source and destination path
BPath sourcePath;
repository->GetPackagePath(package, sourcePath);
BPath destinationPath;
status_t error = entry.GetPath(&destinationPath);
if (error != B_OK) {
DIE(error, "failed to entry path of package file to install \"%s\"",
package->Info().FileName().String());
}
// Copy the package. Ideally we would just hard-link it, but BFS doesn't
// support that.
error = BCopyEngine().CopyEntry(sourcePath.Path(), destinationPath.Path());
if (error != B_OK)
DIE(error, "failed to copy package file \"%s\"", sourcePath.Path());
}
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::_AddInstalledRepository(InstalledRepository* repository)
{
fInstallationInterface->InitInstalledRepository(*repository);
BRepositoryBuilder(*repository)
.AddToSolver(fSolver, repository->Location() == fLocation);
repository->SetPriority(repository->InitialPriority());
if (!fInstalledRepositories.AddItem(repository))
throw std::bad_alloc();
}
void
BPackageManager::_AddRemoteRepository(BPackageRoster& roster, const char* name,
bool refresh)
{
BRepositoryConfig config;
status_t error = roster.GetRepositoryConfig(name, &config);
if (error != B_OK) {
fUserInteractionHandler->Warn(error,
"failed to get config for repository \"%s\". Skipping.", name);
return;
}
BRepositoryCache cache;
error = _GetRepositoryCache(roster, config, refresh, cache);
if (error != B_OK) {
fUserInteractionHandler->Warn(error,
"failed to get cache for repository \"%s\". Skipping.", name);
return;
}
RemoteRepository* repository = new RemoteRepository(config);
if (!fOtherRepositories.AddItem(repository)) {
delete repository;
throw std::bad_alloc();
}
BRepositoryBuilder(*repository, cache, config.Name())
.AddToSolver(fSolver, false);
}
status_t
BPackageManager::_GetRepositoryCache(BPackageRoster& roster,
const BRepositoryConfig& config, bool refresh, BRepositoryCache& _cache)
{
if (!refresh && roster.GetRepositoryCache(config.Name(), &_cache) == B_OK)
return B_OK;
status_t error = RefreshRepository(config);
if (error != B_OK) {
fUserInteractionHandler->Warn(error,
"refreshing repository \"%s\" failed", config.Name().String());
}
return roster.GetRepositoryCache(config.Name(), &_cache);
}
void
BPackageManager::_AddPackageSpecifiers(const char* const* searchStrings,
int searchStringCount, BSolverPackageSpecifierList& specifierList)
{
for (int i = 0; i < searchStringCount; i++) {
const char* searchString = searchStrings[i];
if (_IsLocalPackage(searchString)) {
BSolverPackage* package = _AddLocalPackage(searchString);
if (!specifierList.AppendSpecifier(package))
throw std::bad_alloc();
} else {
if (!specifierList.AppendSpecifier(searchString))
throw std::bad_alloc();
}
}
}
bool
BPackageManager::_IsLocalPackage(const char* fileName)
{
// Simple heuristic: fileName contains ".hpkg" and there's actually a file
// it refers to.
struct stat st;
return strstr(fileName, ".hpkg") != NULL && stat(fileName, &st) == 0
&& S_ISREG(st.st_mode);
}
BSolverPackage*
BPackageManager::_AddLocalPackage(const char* fileName)
{
// We need a local repository.
if (fLocalRepository == NULL)
fLocalRepository = new MiscLocalRepository;
return fLocalRepository->AddLocalPackage(fileName);
}
bool
BPackageManager::_NextSpecificInstallationLocation()
{
if (fLocation == B_PACKAGE_INSTALLATION_LOCATION_SYSTEM) {
fLocation = B_PACKAGE_INSTALLATION_LOCATION_HOME;
fSystemRepository->SetInstalled(false);
_AddInstalledRepository(fHomeRepository);
return true;
}
return false;
}
status_t
BPackageManager::DownloadPackage(const BString& fileURL,
const BEntry& targetEntry, const BString& checksum)
{
BDecisionProvider provider;
BContext context(provider, *this);
return DownloadFileRequest(context, fileURL, targetEntry, checksum)
.Process();
}
status_t
BPackageManager::RefreshRepository(const BRepositoryConfig& repoConfig)
{
BDecisionProvider provider;
BContext context(provider, *this);
return BRefreshRepositoryRequest(context, repoConfig).Process();
}
// #pragma mark - RemoteRepository
BPackageManager::RemoteRepository::RemoteRepository(
const BRepositoryConfig& config)
:
BSolverRepository(),
fConfig(config)
{
}
const BRepositoryConfig&
BPackageManager::RemoteRepository::Config() const
{
return fConfig;
}
// #pragma mark - LocalRepository
BPackageManager::LocalRepository::LocalRepository()
:
BSolverRepository()
{
}
BPackageManager::LocalRepository::LocalRepository(const BString& name)
:
BSolverRepository(name)
{
}
// #pragma mark - MiscLocalRepository
BPackageManager::MiscLocalRepository::MiscLocalRepository()
:
LocalRepository("local"),
fPackagePaths()
{
SetPriority(-127);
}
BSolverPackage*
BPackageManager::MiscLocalRepository::AddLocalPackage(const char* fileName)
{
BSolverPackage* package;
BRepositoryBuilder(*this).AddPackage(fileName, &package);
fPackagePaths[package] = fileName;
return package;
}
void
BPackageManager::MiscLocalRepository::GetPackagePath(BSolverPackage* package,
BPath& _path)
{
PackagePathMap::const_iterator it = fPackagePaths.find(package);
if (it == fPackagePaths.end()) {
DIE("package %s not in local repository",
package->VersionedName().String());
}
status_t error = _path.SetTo(it->second.c_str());
if (error != B_OK)
DIE(error, "failed to init package path %s", it->second.c_str());
}
// #pragma mark - InstalledRepository
BPackageManager::InstalledRepository::InstalledRepository(const char* name,
BPackageInstallationLocation location, int32 priority)
:
LocalRepository(),
fDisabledPackages(10, true),
fPackagesToActivate(),
fPackagesToDeactivate(),
fInitialName(name),
fLocation(location),
fInitialPriority(priority)
{
}
void
BPackageManager::InstalledRepository::GetPackagePath(BSolverPackage* package,
BPath& _path)
{
directory_which packagesWhich;
switch (fLocation) {
case B_PACKAGE_INSTALLATION_LOCATION_SYSTEM:
packagesWhich = B_SYSTEM_PACKAGES_DIRECTORY;
break;
case B_PACKAGE_INSTALLATION_LOCATION_HOME:
packagesWhich = B_USER_PACKAGES_DIRECTORY;
break;
default:
DIE("don't know packages directory path for installation location "
"\"%s\"", Name().String());
}
BString fileName(package->Info().FileName());
status_t error = find_directory(packagesWhich, &_path);
if (error != B_OK || (error = _path.Append(fileName)) != B_OK) {
DIE(error, "failed to get path of package file \"%s\" in installation "
"location \"%s\"", fileName.String(), Name().String());
}
}
void
BPackageManager::InstalledRepository::DisablePackage(BSolverPackage* package)
{
if (fDisabledPackages.HasItem(package))
DIE("package %s already disabled", package->VersionedName().String());
if (package->Repository() != this) {
DIE("package %s not in repository %s",
package->VersionedName().String(), Name().String());
}
// move to disabled list
if (!fDisabledPackages.AddItem(package))
throw std::bad_alloc();
RemovePackage(package);
}
bool
BPackageManager::InstalledRepository::EnablePackage(BSolverPackage* package)
{
return fDisabledPackages.RemoveItem(package);
}
bool
BPackageManager::InstalledRepository::HasChanges() const
{
return !fPackagesToActivate.IsEmpty() || !fPackagesToDeactivate.IsEmpty();
}
void
BPackageManager::InstalledRepository::ApplyChanges()
{
// disable packages to deactivate
for (int32 i = 0; BSolverPackage* package = fPackagesToDeactivate.ItemAt(i);
i++) {
if (!fDisabledPackages.HasItem(package))
DisablePackage(package);
}
// add packages to activate
for (int32 i = 0; BSolverPackage* package = fPackagesToActivate.ItemAt(i);
i++) {
status_t error = AddPackage(package->Info());
if (error != B_OK) {
DIE(error, "failed to add package %s to %s repository",
package->Name().String(), Name().String());
}
}
}
// #pragma mark - Transaction
BPackageManager::Transaction::Transaction(InstalledRepository& repository)
:
fRepository(repository),
fTransaction(),
fTransactionDirectory()
{
}
BPackageManager::Transaction::~Transaction()
{
}
// #pragma mark - InstallationInterface
BPackageManager::InstallationInterface::~InstallationInterface()
{
}
void
BPackageManager::InstallationInterface::ResultComputed(
InstalledRepository& repository)
{
}
// #pragma mark - ClientInstallationInterface
BPackageManager::ClientInstallationInterface::ClientInstallationInterface()
:
fDaemonClient()
{
}
BPackageManager::ClientInstallationInterface::~ClientInstallationInterface()
{
}
void
BPackageManager::ClientInstallationInterface::InitInstalledRepository(
InstalledRepository& repository)
{
const char* name = repository.InitialName();
BRepositoryBuilder(repository, name)
.AddPackages(repository.Location(), name);
}
status_t
BPackageManager::ClientInstallationInterface::PrepareTransaction(
Transaction& transaction)
{
return fDaemonClient.CreateTransaction(transaction.Repository().Location(),
transaction.ActivationTransaction(),
transaction.TransactionDirectory());
}
status_t
BPackageManager::ClientInstallationInterface::CommitTransaction(
Transaction& transaction, BCommitTransactionResult& _result)
{
return fDaemonClient.CommitTransaction(transaction.ActivationTransaction(),
_result);
}
// #pragma mark - UserInteractionHandler
BPackageManager::UserInteractionHandler::~UserInteractionHandler()
{
}
void
BPackageManager::UserInteractionHandler::HandleProblems()
{
throw BAbortedByUserException();
}
void
BPackageManager::UserInteractionHandler::ConfirmChanges(bool fromMostSpecific)
{
throw BAbortedByUserException();
}
void
BPackageManager::UserInteractionHandler::Warn(status_t error,
const char* format, ...)
{
}
void
BPackageManager::UserInteractionHandler::ProgressPackageDownloadStarted(
const char* packageName)
{
}
void
BPackageManager::UserInteractionHandler::ProgressPackageDownloadActive(
const char* packageName, float completionPercentage)
{
}
void
BPackageManager::UserInteractionHandler::ProgressPackageDownloadComplete(
const char* packageName)
{
}
void
BPackageManager::UserInteractionHandler::ProgressPackageChecksumStarted(
const char* title)
{
}
void
BPackageManager::UserInteractionHandler::ProgressPackageChecksumComplete(
const char* title)
{
}
void
BPackageManager::UserInteractionHandler::ProgressStartApplyingChanges(
InstalledRepository& repository)
{
}
void
BPackageManager::UserInteractionHandler::ProgressTransactionCommitted(
InstalledRepository& repository, const BCommitTransactionResult& result)
{
}
void
BPackageManager::UserInteractionHandler::ProgressApplyingChangesDone(
InstalledRepository& repository)
{
}
} // namespace BPrivate
} // namespace BManager
} // namespace BPackageKit