* Copyright 2013-2020, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ingo Weinhold <ingo_weinhold@gmx.de>
* Rene Gollent <rene@gollent.com>
*/
#include <package/manager/PackageManager.h>
#include <glob.h>
#include <Catalog.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/manager/RepositoryBuilder.h>
#include <package/ValidateChecksumJob.h>
#include "FetchFileJob.h"
#include "FetchUtils.h"
using BPackageKit::BPrivate::FetchUtils;
#include "PackageManagerUtils.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "PackageManagerKit"
using BPackageKit::BPrivate::FetchFileJob;
using BPackageKit::BPrivate::ValidateChecksumJob;
namespace BPackageKit {
namespace BManager {
namespace BPrivate {
BPackageManager::BPackageManager(BPackageInstallationLocation location,
InstallationInterface* installationInterface,
UserInteractionHandler* userInteractionHandler)
:
fDebugLevel(0),
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),
fLocalRepository(new (std::nothrow) MiscLocalRepository),
fTransactions(5),
fInstallationInterface(installationInterface),
fUserInteractionHandler(userInteractionHandler)
{
}
BPackageManager::~BPackageManager()
{
delete fSolver;
delete fSystemRepository;
delete fHomeRepository;
delete fLocalRepository;
}
void
BPackageManager::Init(uint32 flags)
{
if (fSolver != NULL)
return;
status_t error = BSolver::Create(fSolver);
if (error != B_OK)
DIE(error, "Failed to create solver");
if (fSystemRepository == NULL || fHomeRepository == NULL
|| fLocalRepository == NULL) {
throw std::bad_alloc();
}
fSolver->SetDebugLevel(fDebugLevel);
BRepositoryBuilder(*fLocalRepository).AddToSolver(fSolver, false);
if ((flags & B_ADD_INSTALLED_REPOSITORIES) != 0) {
_AddInstalledRepository(fSystemRepository);
if (!fSystemRepository->IsInstalled()) {
BPath path;
status_t error = find_directory(B_USER_PACKAGES_DIRECTORY, &path);
if (error == B_OK && BEntry(path.Path()).Exists())
_AddInstalledRepository(fHomeRepository);
}
}
if ((flags & B_ADD_REMOTE_REPOSITORIES) != 0) {
BPackageRoster roster;
BStringList repositoryNames;
error = roster.GetRepositoryNames(repositoryNames);
if (error != B_OK) {
fUserInteractionHandler->Warn(error,
B_TRANSLATE("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::SetDebugLevel(int32 level)
{
fDebugLevel = level;
if (fSolver != NULL)
fSolver->SetDebugLevel(fDebugLevel);
}
void
BPackageManager::Install(const char* const* packages, int packageCount, bool refresh)
{
BSolverPackageSpecifierList packagesToInstall;
_AddPackageSpecifiers(packages, packageCount, packagesToInstall);
Install(packagesToInstall, refresh);
}
void
BPackageManager::Install(const BSolverPackageSpecifierList& packages, bool refresh)
{
uint32 flags = B_ADD_INSTALLED_REPOSITORIES | B_ADD_REMOTE_REPOSITORIES;
if (refresh)
flags |= B_REFRESH_REPOSITORIES;
Init(flags);
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();
_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);
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");
}
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);
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();
_AnalyzeResult();
for (int32 i = foundPackages.CountItems() - 1; i >= 0; i--) {
if (!installationRepository.PackagesToDeactivate()
.AddItem(foundPackages.ItemAt(i))) {
throw std::bad_alloc();
}
}
installationRepository.ApplyChanges();
if (!_NextSpecificInstallationLocation())
break;
foundPackages.MakeEmpty();
}
_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);
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();
_AnalyzeResult();
_ConfirmChanges();
_ApplyPackageChanges();
}
void
BPackageManager::FullSync()
{
Init(B_ADD_INSTALLED_REPOSITORIES | B_ADD_REMOTE_REPOSITORIES
| B_REFRESH_REPOSITORIES);
status_t error = fSolver->FullSync();
if (error != B_OK)
DIE(error, "Failed to compute packages to synchronize");
_HandleProblems();
_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();
_AnalyzeResult();
InstallationRepository().ApplyChanges();
if (!_NextSpecificInstallationLocation())
break;
}
_ConfirmChanges();
_ApplyPackageChanges();
}
BPackageManager::InstalledRepository&
BPackageManager::InstallationRepository()
{
if (fInstalledRepositories.IsEmpty())
DIE("No installation repository");
return *fInstalledRepositories.LastItem();
}
void
BPackageManager::JobStarted(BSupportKit::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(BSupportKit::BJob* job)
{
if (dynamic_cast<FetchFileJob*>(job) != NULL) {
FetchFileJob* fetchJob = (FetchFileJob*)job;
fUserInteractionHandler->ProgressPackageDownloadActive(
fetchJob->DownloadFileName(), fetchJob->DownloadProgress(),
fetchJob->DownloadBytes(), fetchJob->DownloadTotalBytes());
}
}
void
BPackageManager::JobSucceeded(BSupportKit::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;
}
}
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)
{
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);
}
void
BPackageManager::_PreparePackageChanges(
InstalledRepository& installationRepository)
{
if (!installationRepository.HasChanges())
return;
PackageList& packagesToActivate
= installationRepository.PackagesToActivate();
PackageList& packagesToDeactivate
= installationRepository.PackagesToDeactivate();
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");
for (int32 i = 0; BSolverPackage* package = packagesToActivate.ItemAt(i);
i++) {
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) {
bool reusingDownload = false;
BPath path(&transaction->TransactionDirectory());
BPath parent;
if (path.GetParent(&parent) == B_OK) {
BString globPath = parent.Path();
globPath << "/*/" << fileName;
glob_t globbuf;
if (glob(globPath.String(), GLOB_NOSORT, NULL, &globbuf) == 0) {
off_t bestSize = 0;
const char* bestFile = NULL;
for (size_t i = 0; i < globbuf.gl_pathc; i++) {
off_t size = 0;
BNode node(globbuf.gl_pathv[i]);
if (node.GetSize(&size) == B_OK && size > bestSize) {
bestSize = size;
bestFile = globbuf.gl_pathv[i];
}
}
path.Append(fileName);
if (bestFile != NULL && BCopyEngine().CopyEntry(bestFile,
path.Path()) == B_OK) {
reusingDownload = true;
printf("Re-using download '%s' from previous "
"transaction%s\n", bestFile,
FetchUtils::IsDownloadCompleted(
path.Path()) ? "" : " (partial)");
}
globfree(&globbuf);
}
}
BString url = remoteRepository->Config().PackagesURL();
url << '/' << fileName;
status_t error;
retryDownload:
error = DownloadPackage(url, entry,
package->Info().Checksum());
if (error != B_OK) {
if (error == B_BAD_DATA || error == ERANGE) {
entry.Remove();
if (reusingDownload) {
printf("\nPrevious download '%s' was invalid. Redownloading.\n",
path.Path());
reusingDownload = false;
goto retryDownload;
}
}
DIE(error, "Failed to download package %s",
package->Info().Name().String());
}
} else if (package->Repository() != &installationRepository) {
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);
}
if (!transaction->ActivationTransaction().AddPackageToActivate(
fileName)) {
throw std::bad_alloc();
}
}
for (int32 i = 0; BSolverPackage* package = packagesToDeactivate.ItemAt(i);
i++) {
if (!transaction->ActivationTransaction().AddPackageToDeactivate(
package->Info().FileName())) {
throw std::bad_alloc();
}
}
}
void
BPackageManager::_CommitPackageChanges(Transaction& transaction)
{
InstalledRepository& installationRepository = transaction.Repository();
fUserInteractionHandler->ProgressStartApplyingChanges(
installationRepository);
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,
B_TRANSLATE("Failed to remove transaction directory"));
}
fUserInteractionHandler->ProgressApplyingChangesDone(
installationRepository);
}
void
BPackageManager::_ClonePackageFile(LocalRepository* repository,
BSolverPackage* package, const BEntry& entry)
{
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());
}
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;
BPackageResolvableExpression* basePackage = NULL;
int32 count = info.RequiresList().CountItems();
for (int32 i = 0; i < count; i++) {
BPackageResolvableExpression* require = info.RequiresList().ItemAt(i);
if (require->Name() == info.BasePackage()) {
basePackage = require;
break;
}
}
if (basePackage == NULL) {
fUserInteractionHandler->Warn(B_OK, B_TRANSLATE("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;
}
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, B_TRANSLATE(
"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, B_TRANSLATE(
"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, B_TRANSLATE(
"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)
{
struct stat st;
return strstr(fileName, ".hpkg") != NULL && stat(fileName, &st) == 0
&& S_ISREG(st.st_mode);
}
BSolverPackage*
BPackageManager::_AddLocalPackage(const char* fileName)
{
if (fLocalRepository == NULL)
throw std::bad_alloc();
return fLocalRepository->AddLocalPackage(fileName);
}
bool
BPackageManager::_NextSpecificInstallationLocation()
{
try {
if (fLocation == B_PACKAGE_INSTALLATION_LOCATION_SYSTEM) {
fLocation = B_PACKAGE_INSTALLATION_LOCATION_HOME;
fSystemRepository->SetInstalled(false);
_AddInstalledRepository(fHomeRepository);
return true;
}
} catch (BFatalErrorException& e) {
}
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();
}
BPackageManager::RemoteRepository::RemoteRepository(
const BRepositoryConfig& config)
:
BSolverRepository(),
fConfig(config)
{
}
const BRepositoryConfig&
BPackageManager::RemoteRepository::Config() const
{
return fConfig;
}
BPackageManager::LocalRepository::LocalRepository()
:
BSolverRepository()
{
}
BPackageManager::LocalRepository::LocalRepository(const BString& name)
:
BSolverRepository(name)
{
}
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());
}
BPackageManager::InstalledRepository::InstalledRepository(const char* name,
BPackageInstallationLocation location, int32 priority)
:
LocalRepository(),
fDisabledPackages(10),
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());
}
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()
{
for (int32 i = 0; BSolverPackage* package = fPackagesToDeactivate.ItemAt(i);
i++) {
if (!fDisabledPackages.HasItem(package))
DisablePackage(package);
}
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());
}
}
}
BPackageManager::Transaction::Transaction(InstalledRepository& repository)
:
fRepository(repository),
fTransaction(),
fTransactionDirectory()
{
}
BPackageManager::Transaction::~Transaction()
{
}
BPackageManager::InstallationInterface::~InstallationInterface()
{
}
void
BPackageManager::InstallationInterface::ResultComputed(
InstalledRepository& repository)
{
}
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);
}
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, off_t bytes,
off_t totalBytes)
{
}
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)
{
}
}
}
}