HaikuDepot: Flesh out PackageActions a bit.

- Add background worker thread for asynchronous processing of
  package actions.
- Implement InstallPackageAction. As such, installing packages now
  actually works.
- Wrap requests in exception handlers, as the package manager uses those
  for various error cases. Fixes several cases of HaikuDepot spontaneously
  closing if a problem occurred. Still TODO: user error reporting, errors
  are currently reported on the console.
This commit is contained in:
Rene Gollent 2013-09-19 11:45:21 +02:00
parent 5af9dc2a77
commit db259584ca
4 changed files with 155 additions and 20 deletions

View File

@ -24,6 +24,7 @@
#include <TabView.h>
#include <package/Context.h>
#include <package/manager/Exceptions.h>
#include <package/RefreshRepositoryRequest.h>
#include <package/PackageRoster.h>
#include "package/RepositoryCache.h"
@ -47,6 +48,8 @@ enum {
using namespace BPackageKit;
using BManager::BPrivate::BException;
using BManager::BPrivate::BFatalErrorException;
typedef std::map<BString, PackageInfoRef> PackageInfoMap;
@ -252,11 +255,17 @@ MainWindow::_RefreshRepositories(bool force)
if (roster.GetRepositoryCache(repoName, &cache) != B_OK
|| force) {
BRefreshRepositoryRequest refreshRequest(context, repoConfig);
result = refreshRequest.Process();
if (result != B_OK) {
// TODO: notify user
continue;
try {
BRefreshRepositoryRequest refreshRequest(context, repoConfig);
result = refreshRequest.Process();
} catch (BFatalErrorException ex) {
fprintf(stderr, "Fatal error occurred while refreshing "
"repository: %s (%s)\n", ex.Message().String(),
ex.Details().String());
} catch (BException ex) {
fprintf(stderr, "Exception occurred while refreshing "
"repository: %s\n", ex.Message().String());
}
}
}
@ -279,8 +288,14 @@ MainWindow::_RefreshPackageList()
depots[repoName] = DepotInfo(repoName);
}
fPackageManager.Init(PackageManager::B_ADD_INSTALLED_REPOSITORIES
try {
fPackageManager.Init(PackageManager::B_ADD_INSTALLED_REPOSITORIES
| PackageManager::B_ADD_REMOTE_REPOSITORIES);
} catch (BException ex) {
fprintf(stderr, "Exception occurred while initializing PackageManager:"
"%s\n", ex.Message().String());
return;
}
BObjectList<BSolverPackage> packages;
result = fPackageManager.Solver()->FindPackages("",

View File

@ -514,10 +514,13 @@ public:
const PackageActionRef& action
= fPackageActions.ItemAt(index);
if (action.Get() != NULL) {
status_t result = action->Perform();
PackageActionList actions;
actions.Add(action);
status_t result = fPackageManager
->SchedulePackageActions(actions);
if (result != B_OK) {
fprintf(stderr, "Package action failed: %s '%s'\n",
action->Label(),
fprintf(stderr, "Failed to schedule action: "
"%s '%s'\n", action->Label(),
action->Package().Title().String());
}
}

View File

@ -11,14 +11,19 @@
#include "PackageManager.h"
#include <stdio.h>
#include <Catalog.h>
#include <package/DownloadFileRequest.h>
#include <package/manager/Exceptions.h>
#include <package/RefreshRepositoryRequest.h>
#include <package/solver/SolverPackage.h>
#include <package/solver/SolverProblem.h>
#include <package/solver/SolverProblemSolution.h>
#include "AutoLocker.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "PackageManager"
@ -27,13 +32,17 @@
using BPackageKit::BRefreshRepositoryRequest;
using BPackageKit::DownloadFileRequest;
using namespace BPackageKit::BPrivate;
using BPackageKit::BManager::BPrivate::BException;
using BPackageKit::BManager::BPrivate::BFatalErrorException;
// #pragma mark - PackageAction
PackageAction::PackageAction(const PackageInfo& package)
PackageAction::PackageAction(const PackageInfo& package,
PackageManager* manager)
:
fPackageManager(manager),
fPackage(package)
{
}
@ -49,9 +58,9 @@ PackageAction::~PackageAction()
class InstallPackageAction : public PackageAction {
public:
InstallPackageAction(const PackageInfo& package)
InstallPackageAction(const PackageInfo& package, PackageManager* manager)
:
PackageAction(package)
PackageAction(package, manager)
{
}
@ -62,8 +71,20 @@ public:
virtual status_t Perform()
{
// TODO: Trigger asynchronous installation of the package
return B_ERROR;
const char* packageName = Package().Title().String();
try {
fPackageManager->Install(&packageName, 1);
} catch (BFatalErrorException ex) {
fprintf(stderr, "Fatal error occurred while installing package "
"%s: %s (%s)\n", packageName, ex.Message().String(),
ex.Details().String());
return ex.Error();
} catch (BException ex) {
fprintf(stderr, "Exception occurred while installing package "
"%s: %s\n", packageName, ex.Message().String());
}
return B_OK;
}
};
@ -83,14 +104,26 @@ PackageManager::PackageManager(BPackageInstallationLocation location)
fInstallationInterface = &fClientInstallationInterface;
fRequestHandler = this;
fUserInteractionHandler = this;
fPendingActionsSem = create_sem(0, "PendingPackageActions");
if (fPendingActionsSem >= 0) {
fPendingActionsWorker = spawn_thread(&_PackageActionWorker,
"Planet Express", B_NORMAL_PRIORITY, this);
if (fPendingActionsWorker >= 0)
resume_thread(fPendingActionsWorker);
}
}
PackageManager::~PackageManager()
{
delete_sem(fPendingActionsSem);
status_t result;
wait_for_thread(fPendingActionsWorker, &result);
}
PackageState
PackageManager::GetPackageState(const PackageInfo& package)
{
@ -113,16 +146,44 @@ PackageManager::GetPackageActions(const PackageInfo& package)
// * activated
// If the package is not installed, it can be
// * installed (and it will be automatically activated)
actionList.Add(PackageActionRef(new InstallPackageAction(package), true));
actionList.Add(PackageActionRef(new InstallPackageAction(package, this),
true));
return actionList;
}
status_t
PackageManager::SchedulePackageActions(PackageActionList& list)
{
AutoLocker<BLocker> lock(&fPendingActionsLock);
for (int32 i = 0; i < list.CountItems(); i++) {
if (!fPendingActions.Add(list.ItemAtFast(i))) {
return B_NO_MEMORY;
}
}
return release_sem_etc(fPendingActionsSem, list.CountItems(), 0);
}
status_t
PackageManager::RefreshRepository(const BRepositoryConfig& repoConfig)
{
return BRefreshRepositoryRequest(fContext, repoConfig).Process();
status_t result;
try {
result = BRefreshRepositoryRequest(fContext, repoConfig).Process();
} catch (BFatalErrorException ex) {
fprintf(stderr, "Fatal error occurred while refreshing repository: "
"%s (%s)\n", ex.Message().String(), ex.Details().String());
result = ex.Error();
} catch (BException ex) {
fprintf(stderr, "Exception occurred while refreshing "
"repository: %s\n", ex.Message().String());
result = B_ERROR;
}
return result;
}
@ -130,8 +191,22 @@ status_t
PackageManager::DownloadPackage(const BString& fileURL,
const BEntry& targetEntry, const BString& checksum)
{
return DownloadFileRequest(fContext, fileURL, targetEntry, checksum)
.Process();
status_t result;
try {
result = DownloadFileRequest(fContext, fileURL, targetEntry, checksum)
.Process();
} catch (BFatalErrorException ex) {
fprintf(stderr, "Fatal error occurred while downloading package: "
"%s: %s (%s)\n", fileURL.String(), ex.Message().String(),
ex.Details().String());
result = ex.Error();
} catch (BException ex) {
fprintf(stderr, "Exception occurred while downloading package "
"%s: %s\n", fileURL.String(), ex.Message().String());
result = B_ERROR;
}
return result;
}
@ -176,3 +251,25 @@ PackageManager::ProgressApplyingChangesDone(InstalledRepository& repository)
{
// TODO: implement
}
status_t
PackageManager::_PackageActionWorker(void* arg)
{
PackageManager* manager = reinterpret_cast<PackageManager*>(arg);
while (acquire_sem(manager->fPendingActionsSem) == B_OK) {
PackageActionRef ref;
{
AutoLocker<BLocker> lock(&manager->fPendingActionsLock);
ref = manager->fPendingActions.ItemAt(0);
if (ref.Get() == NULL)
break;
manager->fPendingActions.Remove(0);
}
ref->Perform();
}
return 0;
}

View File

@ -8,6 +8,8 @@
#ifndef PACKAGE_MANAGER_H
#define PACKAGE_MANAGER_H
#include <Locker.h>
#include <package/DaemonClient.h>
#include <package/manager/PackageManager.h>
@ -16,9 +18,13 @@
#include "PackageInfo.h"
class PackageManager;
class PackageAction : public BReferenceable {
public:
PackageAction(const PackageInfo& package);
PackageAction(const PackageInfo& package,
PackageManager* manager);
virtual ~PackageAction();
virtual const char* Label() const = 0;
@ -31,6 +37,9 @@ public:
const PackageInfo& Package() const
{ return fPackage; }
protected:
PackageManager* fPackageManager;
private:
PackageInfo fPackage;
};
@ -57,6 +66,9 @@ public:
virtual PackageState GetPackageState(const PackageInfo& package);
virtual PackageActionList GetPackageActions(const PackageInfo& package);
status_t SchedulePackageActions(
PackageActionList& list);
private:
// RequestHandler
virtual status_t RefreshRepository(
@ -79,12 +91,20 @@ private:
virtual void ProgressApplyingChangesDone(
InstalledRepository& repository);
private:
static status_t _PackageActionWorker(void* arg);
private:
DecisionProvider fDecisionProvider;
JobStateListener fJobStateListener;
BContext fContext;
BPackageManager::ClientInstallationInterface
fClientInstallationInterface;
fClientInstallationInterface;
thread_id fPendingActionsWorker;
PackageActionList fPendingActions;
BLocker fPendingActionsLock;
sem_id fPendingActionsSem;
};
#endif // PACKAGE_MANAGER_H