diff --git a/headers/os/package/Context.h b/headers/os/package/Context.h index eb4f9300c3..1ab9fdd9cd 100644 --- a/headers/os/package/Context.h +++ b/headers/os/package/Context.h @@ -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; }; diff --git a/headers/os/package/Job.h b/headers/os/package/Job.h index e403257d8e..800389533f 100644 --- a/headers/os/package/Job.h +++ b/headers/os/package/Job.h @@ -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; diff --git a/headers/private/package/ActivateRepositoryConfigJob.h b/headers/private/package/ActivateRepositoryConfigJob.h index 84bfb48acf..c11405e381 100644 --- a/headers/private/package/ActivateRepositoryConfigJob.h +++ b/headers/private/package/ActivateRepositoryConfigJob.h @@ -23,6 +23,7 @@ class ActivateRepositoryConfigJob : public Job { public: ActivateRepositoryConfigJob( + const Context& context, const BString& title, const BEntry& archivedRepoConfigEntry, const BDirectory& targetDirectory); diff --git a/headers/private/package/FetchFileJob.h b/headers/private/package/FetchFileJob.h index e76c650de8..f9b38c2b8a 100644 --- a/headers/private/package/FetchFileJob.h +++ b/headers/private/package/FetchFileJob.h @@ -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(); diff --git a/src/bin/pkgman/Jamfile b/src/bin/pkgman/Jamfile index ccb52290c5..74791bbc9b 100644 --- a/src/bin/pkgman/Jamfile +++ b/src/bin/pkgman/Jamfile @@ -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 diff --git a/src/bin/pkgman/MyDecisionProvider.cpp b/src/bin/pkgman/MyDecisionProvider.cpp new file mode 100644 index 0000000000..59a3f4c954 --- /dev/null +++ b/src/bin/pkgman/MyDecisionProvider.cpp @@ -0,0 +1,47 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ + + +#include +#include + +#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()); + } + } +} diff --git a/src/bin/pkgman/MyDecisionProvider.h b/src/bin/pkgman/MyDecisionProvider.h new file mode 100644 index 0000000000..57bafdf480 --- /dev/null +++ b/src/bin/pkgman/MyDecisionProvider.h @@ -0,0 +1,19 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ +#ifndef MY_DECISION_PROVIDER_H +#define MY_DECISION_PROVIDER_H + + +#include + + +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 diff --git a/src/bin/pkgman/MyJobStateListener.cpp b/src/bin/pkgman/MyJobStateListener.cpp new file mode 100644 index 0000000000..1b9c925841 --- /dev/null +++ b/src/bin/pkgman/MyJobStateListener.cpp @@ -0,0 +1,40 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ + + +#include + +#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"); +} diff --git a/src/bin/pkgman/MyJobStateListener.h b/src/bin/pkgman/MyJobStateListener.h new file mode 100644 index 0000000000..42f2ed0d57 --- /dev/null +++ b/src/bin/pkgman/MyJobStateListener.h @@ -0,0 +1,20 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ +#ifndef MY_JOB_STATE_LISTENER_H +#define MY_JOB_STATE_LISTENER_H + + +#include + + +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 diff --git a/src/bin/pkgman/command_add_repo.cpp b/src/bin/pkgman/command_add_repo.cpp index 56d24cb51f..0c9c871ac1 100644 --- a/src/bin/pkgman/command_add_repo.cpp +++ b/src/bin/pkgman/command_add_repo.cpp @@ -15,15 +15,17 @@ #include #include +#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 [ ...]\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; } } diff --git a/src/bin/pkgman/pkgman.h b/src/bin/pkgman/pkgman.h index 9f27d4d130..1c95643413 100644 --- a/src/bin/pkgman/pkgman.h +++ b/src/bin/pkgman/pkgman.h @@ -13,7 +13,6 @@ extern const char* kProgramName; - #define DIE(result, msg...) \ do { \ fprintf(stderr, "*** " msg); \ diff --git a/src/kits/package/ActivateRepositoryConfigJob.cpp b/src/kits/package/ActivateRepositoryConfigJob.cpp index 4121e651ec..274fb6b12e 100644 --- a/src/kits/package/ActivateRepositoryConfigJob.cpp +++ b/src/kits/package/ActivateRepositoryConfigJob.cpp @@ -1,5 +1,3 @@ -#include -#include /* * Copyright 2011, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. @@ -15,6 +13,7 @@ #include +#include #include @@ -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(); } diff --git a/src/kits/package/AddRepositoryRequest.cpp b/src/kits/package/AddRepositoryRequest.cpp index 9a00870afb..4da28a393f 100644 --- a/src/kits/package/AddRepositoryRequest.cpp +++ b/src/kits/package/AddRepositoryRequest.cpp @@ -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) diff --git a/src/kits/package/Context.cpp b/src/kits/package/Context.cpp index 38c42f615e..c04400baa2 100644 --- a/src/kits/package/Context.cpp +++ b/src/kits/package/Context.cpp @@ -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; } diff --git a/src/kits/package/FetchFileJob.cpp b/src/kits/package/FetchFileJob.cpp index 9ba0fcd50a..e60b64855b 100644 --- a/src/kits/package/FetchFileJob.cpp +++ b/src/kits/package/FetchFileJob.cpp @@ -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; diff --git a/src/kits/package/Job.cpp b/src/kits/package/Job.cpp index eff34e43ef..02a7f99187 100644 --- a/src/kits/package/Job.cpp +++ b/src/kits/package/Job.cpp @@ -11,6 +11,8 @@ #include +#include + 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(); diff --git a/src/kits/package/Request.cpp b/src/kits/package/Request.cpp index c436c1e846..c9dbf8b46a 100644 --- a/src/kits/package/Request.cpp +++ b/src/kits/package/Request.cpp @@ -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); }