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:
parent
5af9dc2a77
commit
db259584ca
@ -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("",
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user