* added support for interactive decisions to package kit and pkgman
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40268 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
ea3e07b3f1
commit
11a4ecfd82
@ -17,20 +17,37 @@ namespace Package {
|
||||
class JobStateListener;
|
||||
|
||||
|
||||
struct DecisionProvider {
|
||||
virtual ~DecisionProvider();
|
||||
|
||||
virtual bool YesNoDecisionNeeded(const BString& description,
|
||||
const BString& question,
|
||||
const BString& yes, const BString& no,
|
||||
const BString& defaultChoice) = 0;
|
||||
// virtual bool ActionsAcceptanceDecisionNeeded(
|
||||
// const BString& description,
|
||||
// const BString& question) = 0;
|
||||
// virtual int32 ChoiceDecisionNeeded(
|
||||
// const BString& question) = 0;
|
||||
};
|
||||
|
||||
|
||||
class Context {
|
||||
public:
|
||||
Context();
|
||||
Context(DecisionProvider& decisionProvider);
|
||||
~Context();
|
||||
|
||||
TempEntryManager& GetTempEntryManager() const;
|
||||
|
||||
JobStateListener* DefaultJobStateListener() const;
|
||||
void SetDefaultJobStateListener(
|
||||
JobStateListener* listener);
|
||||
JobStateListener* GetJobStateListener() const;
|
||||
void SetJobStateListener(JobStateListener* listener);
|
||||
|
||||
DecisionProvider& GetDecisionProvider() const;
|
||||
|
||||
private:
|
||||
mutable TempEntryManager fTempEntryManager;
|
||||
JobStateListener* fDefaultJobStateListener;
|
||||
DecisionProvider& fDecisionProvider;
|
||||
JobStateListener* fJobStateListener;
|
||||
};
|
||||
|
||||
|
||||
|
@ -15,6 +15,7 @@ namespace Haiku {
|
||||
namespace Package {
|
||||
|
||||
|
||||
class Context;
|
||||
class Job;
|
||||
|
||||
struct JobStateListener {
|
||||
@ -39,7 +40,8 @@ enum JobState {
|
||||
|
||||
class Job {
|
||||
public:
|
||||
Job(const BString& title);
|
||||
Job(const Context& context,
|
||||
const BString& title);
|
||||
virtual ~Job();
|
||||
|
||||
status_t InitCheck() const;
|
||||
@ -65,9 +67,11 @@ protected:
|
||||
|
||||
void NotifyStateListeners();
|
||||
|
||||
const Context& fContext;
|
||||
private:
|
||||
status_t fInitStatus;
|
||||
BString fTitle;
|
||||
|
||||
JobState fState;
|
||||
status_t fResult;
|
||||
|
||||
|
@ -23,6 +23,7 @@ class ActivateRepositoryConfigJob : public Job {
|
||||
|
||||
public:
|
||||
ActivateRepositoryConfigJob(
|
||||
const Context& context,
|
||||
const BString& title,
|
||||
const BEntry& archivedRepoConfigEntry,
|
||||
const BDirectory& targetDirectory);
|
||||
|
@ -21,7 +21,8 @@ class FetchFileJob : public Job {
|
||||
typedef Job inherited;
|
||||
|
||||
public:
|
||||
FetchFileJob(const BString& title,
|
||||
FetchFileJob(const Context& context,
|
||||
const BString& title,
|
||||
const BString& fileURL,
|
||||
const BEntry& targetEntry);
|
||||
virtual ~FetchFileJob();
|
||||
|
@ -5,6 +5,8 @@ UsePrivateHeaders shared support ;
|
||||
BinCommand pkgman :
|
||||
command_add_repo.cpp
|
||||
command_list_repos.cpp
|
||||
MyDecisionProvider.cpp
|
||||
MyJobStateListener.cpp
|
||||
pkgman.cpp
|
||||
:
|
||||
package be
|
||||
|
47
src/bin/pkgman/MyDecisionProvider.cpp
Normal file
47
src/bin/pkgman/MyDecisionProvider.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "MyDecisionProvider.h"
|
||||
|
||||
|
||||
bool
|
||||
MyDecisionProvider::YesNoDecisionNeeded(const BString& description,
|
||||
const BString& question, const BString& yes, const BString& no,
|
||||
const BString& defaultChoice)
|
||||
{
|
||||
if (description.Length() > 0)
|
||||
printf("%s\n", description.String());
|
||||
|
||||
bool haveDefault = defaultChoice.Length() > 0;
|
||||
|
||||
while (true) {
|
||||
printf("%s [%s/%s]%s: ", question.String(), yes.String(), no.String(),
|
||||
haveDefault
|
||||
? (BString(" (") << defaultChoice << ") ").String() : "");
|
||||
|
||||
char buffer[32];
|
||||
if (fgets(buffer, 32, stdin)) {
|
||||
if (haveDefault && (buffer[0] == '\n' || buffer[0] == '\0'))
|
||||
return defaultChoice == yes;
|
||||
int length = strlen(buffer);
|
||||
for (int i = 1; i <= length; ++i) {
|
||||
if (yes.ICompare(buffer, i) == 0) {
|
||||
if (no.ICompare(buffer, i) != 0)
|
||||
return true;
|
||||
} else if (no.Compare(buffer, i) == 0) {
|
||||
if (yes.ICompare(buffer, i) != 0)
|
||||
return false;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, "*** please enter '%s' or '%s'\n", yes.String(),
|
||||
no.String());
|
||||
}
|
||||
}
|
||||
}
|
19
src/bin/pkgman/MyDecisionProvider.h
Normal file
19
src/bin/pkgman/MyDecisionProvider.h
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef MY_DECISION_PROVIDER_H
|
||||
#define MY_DECISION_PROVIDER_H
|
||||
|
||||
|
||||
#include <package/Context.h>
|
||||
|
||||
|
||||
struct MyDecisionProvider : public Haiku::Package::DecisionProvider {
|
||||
virtual bool YesNoDecisionNeeded(const BString& description,
|
||||
const BString& question, const BString& yes, const BString& no,
|
||||
const BString& defaultChoice);
|
||||
};
|
||||
|
||||
|
||||
#endif // MY_DECISION_PROVIDER_H
|
40
src/bin/pkgman/MyJobStateListener.cpp
Normal file
40
src/bin/pkgman/MyJobStateListener.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "MyJobStateListener.h"
|
||||
#include "pkgman.h"
|
||||
|
||||
|
||||
using Haiku::Package::Job;
|
||||
|
||||
|
||||
void
|
||||
MyJobStateListener::JobStarted(Job* job)
|
||||
{
|
||||
printf("%s ...\n", job->Title().String());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MyJobStateListener::JobSucceeded(Job* job)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MyJobStateListener::JobFailed(Job* job)
|
||||
{
|
||||
DIE(job->Result(), "failed!");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MyJobStateListener::JobAborted(Job* job)
|
||||
{
|
||||
DIE(job->Result(), "aborted");
|
||||
}
|
20
src/bin/pkgman/MyJobStateListener.h
Normal file
20
src/bin/pkgman/MyJobStateListener.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef MY_JOB_STATE_LISTENER_H
|
||||
#define MY_JOB_STATE_LISTENER_H
|
||||
|
||||
|
||||
#include <package/Job.h>
|
||||
|
||||
|
||||
struct MyJobStateListener : public Haiku::Package::JobStateListener {
|
||||
virtual void JobStarted(Haiku::Package::Job* job);
|
||||
virtual void JobSucceeded(Haiku::Package::Job* job);
|
||||
virtual void JobFailed(Haiku::Package::Job* job);
|
||||
virtual void JobAborted(Haiku::Package::Job* job);
|
||||
};
|
||||
|
||||
|
||||
#endif // MY_JOB_STATE_LISTENER_H
|
@ -15,15 +15,17 @@
|
||||
#include <package/Context.h>
|
||||
#include <package/JobQueue.h>
|
||||
|
||||
#include "MyDecisionProvider.h"
|
||||
#include "MyJobStateListener.h"
|
||||
#include "pkgman.h"
|
||||
|
||||
|
||||
// TODO: internationalization!
|
||||
|
||||
|
||||
using namespace Haiku::Package;
|
||||
|
||||
|
||||
// TODO: internationalization!
|
||||
|
||||
|
||||
static const char* kCommandUsage =
|
||||
"Usage: %s add-repo <repo-URL> [<repo-URL> ...]\n"
|
||||
"Adds one or more repositories by downloading them from the given URL(s).\n"
|
||||
@ -39,25 +41,6 @@ print_command_usage_and_exit(bool error)
|
||||
}
|
||||
|
||||
|
||||
struct Listener : public JobStateListener {
|
||||
virtual void JobStarted(Job* job)
|
||||
{
|
||||
printf("%s ...\n", job->Title().String());
|
||||
}
|
||||
virtual void JobSucceeded(Job* job)
|
||||
{
|
||||
}
|
||||
virtual void JobFailed(Job* job)
|
||||
{
|
||||
DIE(job->Result(), "failed!");
|
||||
}
|
||||
virtual void JobAborted(Job* job)
|
||||
{
|
||||
DIE(job->Result(), "aborted");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
command_add_repo(int argc, const char* const* argv)
|
||||
{
|
||||
@ -97,10 +80,12 @@ command_add_repo(int argc, const char* const* argv)
|
||||
const char* const* repoURLs = argv + optind;
|
||||
int urlCount = argc - optind;
|
||||
|
||||
Context context;
|
||||
MyDecisionProvider decisionProvider;
|
||||
Context context(decisionProvider);
|
||||
MyJobStateListener listener;
|
||||
context.SetJobStateListener(&listener);
|
||||
|
||||
status_t result;
|
||||
Listener listener;
|
||||
context.SetDefaultJobStateListener(&listener);
|
||||
for (int i = 0; i < urlCount; ++i) {
|
||||
AddRepositoryRequest request(context, repoURLs[i], asUserRepository);
|
||||
JobQueue jobQueue;
|
||||
@ -111,7 +96,7 @@ command_add_repo(int argc, const char* const* argv)
|
||||
while (Job* job = jobQueue.Pop()) {
|
||||
result = job->Run();
|
||||
delete job;
|
||||
if (result == B_INTERRUPTED)
|
||||
if (result == B_CANCELED)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,6 @@
|
||||
|
||||
extern const char* kProgramName;
|
||||
|
||||
|
||||
#define DIE(result, msg...) \
|
||||
do { \
|
||||
fprintf(stderr, "*** " msg); \
|
||||
|
@ -1,5 +1,3 @@
|
||||
#include <stdio.h>
|
||||
#include <Path.h>
|
||||
/*
|
||||
* Copyright 2011, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
@ -15,6 +13,7 @@
|
||||
|
||||
#include <File.h>
|
||||
|
||||
#include <package/Context.h>
|
||||
#include <package/RepositoryConfig.h>
|
||||
|
||||
|
||||
@ -23,10 +22,11 @@ namespace Haiku {
|
||||
namespace Package {
|
||||
|
||||
|
||||
ActivateRepositoryConfigJob::ActivateRepositoryConfigJob(const BString& title,
|
||||
const BEntry& archivedRepoConfigEntry, const BDirectory& targetDirectory)
|
||||
ActivateRepositoryConfigJob::ActivateRepositoryConfigJob(const Context& context,
|
||||
const BString& title, const BEntry& archivedRepoConfigEntry,
|
||||
const BDirectory& targetDirectory)
|
||||
:
|
||||
inherited(title),
|
||||
inherited(context, title),
|
||||
fArchivedRepoConfigEntry(archivedRepoConfigEntry),
|
||||
fTargetDirectory(targetDirectory)
|
||||
{
|
||||
@ -42,39 +42,36 @@ status_t
|
||||
ActivateRepositoryConfigJob::Execute()
|
||||
{
|
||||
BFile archiveFile(&fArchivedRepoConfigEntry, B_READ_ONLY);
|
||||
BPath p;
|
||||
fArchivedRepoConfigEntry.GetPath(&p);
|
||||
printf("Execute(): arce=%s\n", p.Path());
|
||||
status_t result = archiveFile.InitCheck();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
printf("Execute(): 2\n");
|
||||
BMessage archive;
|
||||
if ((result = archive.Unflatten(&archiveFile)) != B_OK)
|
||||
return result;
|
||||
|
||||
printf("Execute(): 3\n");
|
||||
RepositoryConfig* repoConfig = RepositoryConfig::Instantiate(&archive);
|
||||
if (repoConfig == NULL)
|
||||
return B_BAD_DATA;
|
||||
printf("Execute(): 4\n");
|
||||
if ((result = repoConfig->InitCheck()) != B_OK)
|
||||
return result;
|
||||
|
||||
printf("Execute(): 5\n");
|
||||
fTargetEntry.SetTo(&fTargetDirectory, repoConfig->Name().String());
|
||||
if (fTargetEntry.Exists()) {
|
||||
// TODO: ask user whether to clobber or not
|
||||
printf("Execute(): 5b\n");
|
||||
return B_INTERRUPTED;
|
||||
BString description = BString("A repository configuration for ")
|
||||
<< repoConfig->Name() << " already exists.";
|
||||
BString question("overwrite?");
|
||||
bool yes = fContext.GetDecisionProvider().YesNoDecisionNeeded(
|
||||
description, question, "yes", "no", "no");
|
||||
if (!yes) {
|
||||
fTargetEntry.Unset();
|
||||
return B_CANCELED;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Execute(): 6\n");
|
||||
if ((result = repoConfig->StoreAsConfigFile(fTargetEntry)) != B_OK)
|
||||
return result;
|
||||
|
||||
printf("Execute(): 7\n");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -82,7 +79,8 @@ printf("Execute(): 7\n");
|
||||
void
|
||||
ActivateRepositoryConfigJob::Cleanup(status_t jobResult)
|
||||
{
|
||||
if (jobResult != B_OK && State() != JOB_STATE_ABORTED)
|
||||
if (jobResult != B_OK && State() != JOB_STATE_ABORTED
|
||||
&& fTargetEntry.InitCheck() == B_OK)
|
||||
fTargetEntry.Remove();
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ AddRepositoryRequest::CreateJobsToRun(JobQueue& jobQueue)
|
||||
{
|
||||
BEntry tempEntry
|
||||
= GetContext().GetTempEntryManager().Create("repoconfig-");
|
||||
FetchFileJob* fetchJob = new (std::nothrow) FetchFileJob(
|
||||
FetchFileJob* fetchJob = new (std::nothrow) FetchFileJob(GetContext(),
|
||||
BString("Fetching repository-config from ") << fRepositoryURL,
|
||||
fRepositoryURL, tempEntry);
|
||||
if (fetchJob == NULL)
|
||||
@ -63,7 +63,7 @@ AddRepositoryRequest::CreateJobsToRun(JobQueue& jobQueue)
|
||||
return result;
|
||||
BDirectory targetDirectory(targetRepoConfigPath.Path());
|
||||
ActivateRepositoryConfigJob* activateJob
|
||||
= new (std::nothrow) ActivateRepositoryConfigJob(
|
||||
= new (std::nothrow) ActivateRepositoryConfigJob(GetContext(),
|
||||
BString("Activating repository-config from ") << fRepositoryURL,
|
||||
tempEntry, targetDirectory);
|
||||
if (activateJob == NULL)
|
||||
|
@ -20,9 +20,15 @@ namespace Haiku {
|
||||
namespace Package {
|
||||
|
||||
|
||||
Context::Context()
|
||||
DecisionProvider::~DecisionProvider()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Context::Context(DecisionProvider& decisionProvider)
|
||||
:
|
||||
fDefaultJobStateListener(NULL)
|
||||
fDecisionProvider(decisionProvider),
|
||||
fJobStateListener(NULL)
|
||||
{
|
||||
BPath tempPath;
|
||||
if (find_directory(B_COMMON_TEMP_DIRECTORY, &tempPath) != B_OK)
|
||||
@ -49,16 +55,23 @@ Context::GetTempEntryManager() const
|
||||
|
||||
|
||||
JobStateListener*
|
||||
Context::DefaultJobStateListener() const
|
||||
Context::GetJobStateListener() const
|
||||
{
|
||||
return fDefaultJobStateListener;
|
||||
return fJobStateListener;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Context::SetDefaultJobStateListener(JobStateListener* listener)
|
||||
Context::SetJobStateListener(JobStateListener* listener)
|
||||
{
|
||||
fDefaultJobStateListener = listener;
|
||||
fJobStateListener = listener;
|
||||
}
|
||||
|
||||
|
||||
DecisionProvider&
|
||||
Context::GetDecisionProvider() const
|
||||
{
|
||||
return fDecisionProvider;
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,10 +20,10 @@ namespace Haiku {
|
||||
namespace Package {
|
||||
|
||||
|
||||
FetchFileJob::FetchFileJob(const BString& title, const BString& fileURL,
|
||||
const BEntry& targetEntry)
|
||||
FetchFileJob::FetchFileJob(const Context& context, const BString& title,
|
||||
const BString& fileURL, const BEntry& targetEntry)
|
||||
:
|
||||
inherited(title),
|
||||
inherited(context, title),
|
||||
fFileURL(fileURL),
|
||||
fTargetEntry(targetEntry)
|
||||
{
|
||||
@ -50,7 +50,7 @@ FetchFileJob::Execute()
|
||||
int cmdResult = system(cmd.String());
|
||||
if (WIFSIGNALED(cmdResult)
|
||||
&& (WTERMSIG(cmdResult) == SIGINT || WTERMSIG(cmdResult) == SIGQUIT)) {
|
||||
return B_INTERRUPTED;
|
||||
return B_CANCELED;
|
||||
}
|
||||
|
||||
return cmdResult == 0 ? B_OK : B_ERROR;
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
#include <Errors.h>
|
||||
|
||||
#include <package/Context.h>
|
||||
|
||||
|
||||
namespace Haiku {
|
||||
|
||||
@ -46,8 +48,9 @@ JobStateListener::JobAborted(Job* job)
|
||||
}
|
||||
|
||||
|
||||
Job::Job(const BString& title)
|
||||
Job::Job(const Context& context, const BString& title)
|
||||
:
|
||||
fContext(context),
|
||||
fTitle(title),
|
||||
fState(JOB_STATE_WAITING_TO_RUN)
|
||||
{
|
||||
@ -105,7 +108,7 @@ Job::Run()
|
||||
|
||||
fState = fResult == B_OK
|
||||
? JOB_STATE_SUCCEEDED
|
||||
: fResult == B_INTERRUPTED
|
||||
: fResult == B_CANCELED
|
||||
? JOB_STATE_ABORTED
|
||||
: JOB_STATE_FAILED;
|
||||
NotifyStateListeners();
|
||||
|
@ -41,9 +41,9 @@ Request::GetContext() const
|
||||
status_t
|
||||
Request::QueueJob(Job* job, JobQueue& jobQueue) const
|
||||
{
|
||||
JobStateListener* defaultListener = fContext.DefaultJobStateListener();
|
||||
if (defaultListener != NULL)
|
||||
job->AddStateListener(defaultListener);
|
||||
JobStateListener* listener = fContext.GetJobStateListener();
|
||||
if (listener != NULL)
|
||||
job->AddStateListener(listener);
|
||||
|
||||
return jobQueue.AddJob(job);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user