From 500bb6305c339017d7d7302dc1f63ac90443f267 Mon Sep 17 00:00:00 2001 From: Oliver Tappe Date: Fri, 21 Jan 2011 22:18:58 +0000 Subject: [PATCH] * WIP-commit of the first parts of the package kit and the pkgman (console-)tool git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40261 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- build/jam/BuildSetup | 3 +- headers/os/package/AddRepositoryRequest.h | 42 +++ headers/os/package/Context.h | 42 +++ headers/os/package/Job.h | 88 ++++++ headers/os/package/JobQueue.h | 51 ++++ headers/os/package/RepositoryCache.h | 24 ++ headers/os/package/RepositoryConfig.h | 75 +++++ headers/os/package/Request.h | 43 +++ headers/os/package/Roster.h | 55 ++++ headers/os/package/TempEntryManager.h | 43 +++ .../package/ActivateRepositoryConfigJob.h | 47 ++++ headers/private/package/FetchFileJob.h | 44 +++ src/bin/Jamfile | 1 + src/bin/pkgman/Jamfile | 12 + src/bin/pkgman/command_add_repo.cpp | 120 ++++++++ src/bin/pkgman/command_list_repos.cpp | 145 ++++++++++ src/bin/pkgman/pkgman.cpp | 72 +++++ src/bin/pkgman/pkgman.h | 44 +++ src/kits/Jamfile | 1 + .../package/ActivateRepositoryConfigJob.cpp | 92 ++++++ src/kits/package/AddRepositoryRequest.cpp | 83 ++++++ src/kits/package/Context.cpp | 67 +++++ src/kits/package/FetchFileJob.cpp | 70 +++++ src/kits/package/Jamfile | 19 ++ src/kits/package/Job.cpp | 207 ++++++++++++++ src/kits/package/JobQueue.cpp | 155 +++++++++++ src/kits/package/RepositoryConfig.cpp | 261 ++++++++++++++++++ src/kits/package/Request.cpp | 54 ++++ src/kits/package/Roster.cpp | 130 +++++++++ src/kits/package/TempEntryManager.cpp | 61 ++++ src/tests/kits/Jamfile | 3 +- src/tests/kits/package/Jamfile | 4 + src/tests/kits/package/make_repo.cpp | 80 ++++++ 33 files changed, 2236 insertions(+), 2 deletions(-) create mode 100644 headers/os/package/AddRepositoryRequest.h create mode 100644 headers/os/package/Context.h create mode 100644 headers/os/package/Job.h create mode 100644 headers/os/package/JobQueue.h create mode 100644 headers/os/package/RepositoryCache.h create mode 100644 headers/os/package/RepositoryConfig.h create mode 100644 headers/os/package/Request.h create mode 100644 headers/os/package/Roster.h create mode 100644 headers/os/package/TempEntryManager.h create mode 100644 headers/private/package/ActivateRepositoryConfigJob.h create mode 100644 headers/private/package/FetchFileJob.h create mode 100644 src/bin/pkgman/Jamfile create mode 100644 src/bin/pkgman/command_add_repo.cpp create mode 100644 src/bin/pkgman/command_list_repos.cpp create mode 100644 src/bin/pkgman/pkgman.cpp create mode 100644 src/bin/pkgman/pkgman.h create mode 100644 src/kits/package/ActivateRepositoryConfigJob.cpp create mode 100644 src/kits/package/AddRepositoryRequest.cpp create mode 100644 src/kits/package/Context.cpp create mode 100644 src/kits/package/FetchFileJob.cpp create mode 100644 src/kits/package/Jamfile create mode 100644 src/kits/package/Job.cpp create mode 100644 src/kits/package/JobQueue.cpp create mode 100644 src/kits/package/RepositoryConfig.cpp create mode 100644 src/kits/package/Request.cpp create mode 100644 src/kits/package/Roster.cpp create mode 100644 src/kits/package/TempEntryManager.cpp create mode 100644 src/tests/kits/package/Jamfile create mode 100644 src/tests/kits/package/make_repo.cpp diff --git a/build/jam/BuildSetup b/build/jam/BuildSetup index 793b4588bc..d4856cbd7e 100644 --- a/build/jam/BuildSetup +++ b/build/jam/BuildSetup @@ -529,7 +529,8 @@ HAIKU_BUILD_DESCRIPTION ?= "Unknown Build" ; { local i ; for i in be bnetapi debug game GL locale mail media midi midi2 network - opengl root screensaver textencoding tracker translation z { + opengl package root screensaver textencoding tracker translation + z { HAIKU_LIBRARY_NAME_MAP_$(i) = lib$(i).so ; } HAIKU_LIBRARY_NAME_MAP_libstdc++ = $(HAIKU_LIBSTDC++) ; diff --git a/headers/os/package/AddRepositoryRequest.h b/headers/os/package/AddRepositoryRequest.h new file mode 100644 index 0000000000..ed18e49739 --- /dev/null +++ b/headers/os/package/AddRepositoryRequest.h @@ -0,0 +1,42 @@ +/* + * Copyright 2011, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _HAIKU__PACKAGE__ADD_REPOSITORY_REQUEST_H_ +#define _HAIKU__PACKAGE__ADD_REPOSITORY_REQUEST_H_ + + +#include + +#include +#include + + +namespace Haiku { + +namespace Package { + + +class AddRepositoryRequest : public Request { + typedef Request inherited; + +public: + AddRepositoryRequest(const Context& context, + const BString& repositoryURL, + bool asUserRepository); + virtual ~AddRepositoryRequest(); + + virtual status_t CreateJobsToRun(JobQueue& jobQueue); + +private: + BString fRepositoryURL; + bool fAsUserRepository; +}; + + +} // namespace Package + +} // namespace Haiku + + +#endif // _HAIKU__PACKAGE__ADD_REPOSITORY_REQUEST_H_ diff --git a/headers/os/package/Context.h b/headers/os/package/Context.h new file mode 100644 index 0000000000..eb4f9300c3 --- /dev/null +++ b/headers/os/package/Context.h @@ -0,0 +1,42 @@ +/* + * Copyright 2011, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _HAIKU__PACKAGE__CONTEXT_H_ +#define _HAIKU__PACKAGE__CONTEXT_H_ + + +#include + + +namespace Haiku { + +namespace Package { + + +class JobStateListener; + + +class Context { +public: + Context(); + ~Context(); + + TempEntryManager& GetTempEntryManager() const; + + JobStateListener* DefaultJobStateListener() const; + void SetDefaultJobStateListener( + JobStateListener* listener); + +private: + mutable TempEntryManager fTempEntryManager; + JobStateListener* fDefaultJobStateListener; +}; + + +} // namespace Package + +} // namespace Haiku + + +#endif // _HAIKU__PACKAGE__CONTEXT_H_ diff --git a/headers/os/package/Job.h b/headers/os/package/Job.h new file mode 100644 index 0000000000..e403257d8e --- /dev/null +++ b/headers/os/package/Job.h @@ -0,0 +1,88 @@ +/* + * Copyright 2011, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _HAIKU__PACKAGE__JOB_H_ +#define _HAIKU__PACKAGE__JOB_H_ + + +#include +#include + + +namespace Haiku { + +namespace Package { + + +class Job; + +struct JobStateListener { + virtual ~JobStateListener(); + + // these default implementations do nothing + virtual void JobStarted(Job* job); + virtual void JobSucceeded(Job* job); + virtual void JobFailed(Job* job); + virtual void JobAborted(Job* job); +}; + + +enum JobState { + JOB_STATE_WAITING_TO_RUN, + JOB_STATE_RUNNING, + JOB_STATE_SUCCEEDED, + JOB_STATE_FAILED, + JOB_STATE_ABORTED, +}; + + +class Job { +public: + Job(const BString& title); + virtual ~Job(); + + status_t InitCheck() const; + + virtual status_t Run(); + + const BString& Title() const; + JobState State() const; + status_t Result() const; + + status_t AddStateListener(JobStateListener* listener); + status_t RemoveStateListener( + JobStateListener* listener); + + status_t AddDependency(Job* job); + status_t RemoveDependency(Job* job); + int32 CountDependencies() const; + + Job* DependantJobAt(int32 index) const; +protected: + virtual status_t Execute() = 0; + virtual void Cleanup(status_t jobResult); + + void NotifyStateListeners(); + +private: + status_t fInitStatus; + BString fTitle; + JobState fState; + status_t fResult; + + typedef BObjectList JobList; + JobList fDependencies; + JobList fDependantJobs; + + typedef BObjectList StateListenerList; + StateListenerList fStateListeners; +}; + + +} // namespace Package + +} // namespace Haiku + + +#endif // _HAIKU__PACKAGE__JOB_H_ diff --git a/headers/os/package/JobQueue.h b/headers/os/package/JobQueue.h new file mode 100644 index 0000000000..b0342c9812 --- /dev/null +++ b/headers/os/package/JobQueue.h @@ -0,0 +1,51 @@ +/* + * Copyright 2011, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _HAIKU__PACKAGE__JOB_QUEUE_H_ +#define _HAIKU__PACKAGE__JOB_QUEUE_H_ + + +#include +#include + +#include + + +namespace Haiku { + +namespace Package { + + +class JobQueue : public JobStateListener { +public: + JobQueue(); + ~JobQueue(); + + status_t AddJob(Job* job); + status_t RemoveJob(Job* job); + + Job* Pop(); + + // JobStateListener + virtual void JobSucceeded(Job* job); + virtual void JobFailed(Job* job); + +private: + struct JobPriorityLess; + class JobPriorityQueue; + +private: + void _UpdateDependantJobsOf(Job* job); + + BLocker fLock; + JobPriorityQueue* fQueuedJobs; +}; + + +} // namespace Package + +} // namespace Haiku + + +#endif // _HAIKU__PACKAGE__JOB_QUEUE_H_ diff --git a/headers/os/package/RepositoryCache.h b/headers/os/package/RepositoryCache.h new file mode 100644 index 0000000000..4525b8556b --- /dev/null +++ b/headers/os/package/RepositoryCache.h @@ -0,0 +1,24 @@ +/* + * Copyright 2011, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _REPOSITORY_H_ +#define _REPOSITORY_H_ + + +#include + + +class BMessage; + + +class BRepository { +public: + BRepository(const char* url); + +public: + static BArchivable* Instantiate(BMessage* archive); +}; + + +#endif // _REPOSITORY_H_ diff --git a/headers/os/package/RepositoryConfig.h b/headers/os/package/RepositoryConfig.h new file mode 100644 index 0000000000..61525f8b5e --- /dev/null +++ b/headers/os/package/RepositoryConfig.h @@ -0,0 +1,75 @@ +/* + * Copyright 2011, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _HAIKU__PACKAGE__REPOSITORY_CONFIG_H_ +#define _HAIKU__PACKAGE__REPOSITORY_CONFIG_H_ + + +#include +#include + + +class BEntry; + + +namespace Haiku { + +namespace Package { + + +class RepositoryConfig : public BArchivable { + typedef BArchivable inherited; + +public: + RepositoryConfig(); + RepositoryConfig(const BString& name, + const BString& url, + uint8 priority = kDefaultPriority); + RepositoryConfig(const BEntry& entry); + RepositoryConfig(BMessage* data); + virtual ~RepositoryConfig(); + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + status_t StoreAsConfigFile(const BEntry& entry) const; + + status_t InitCheck() const; + + const BString& Name() const; + const BString& URL() const; + uint8 Priority() const; + bool IsUserSpecific() const; + + void SetName(const BString& name); + void SetURL(const BString& url); + void SetPriority(uint8 priority); + void SetIsUserSpecific(bool isUserSpecific); + +public: + static RepositoryConfig* Instantiate(BMessage* data); + + static const uint8 kDefaultPriority = 50; + static const char* kNameField; + static const char* kURLField; + static const char* kPriorityField; + +private: + status_t _InitFrom(const BEntry& entry); + status_t _InitFrom(const BMessage* data); + + status_t fInitStatus; + + BString fName; + BString fURL; + uint8 fPriority; + bool fIsUserSpecific; +}; + + +} // namespace Package + +} // namespace Haiku + + +#endif // _HAIKU__PACKAGE__REPOSITORY_CONFIG_H_ diff --git a/headers/os/package/Request.h b/headers/os/package/Request.h new file mode 100644 index 0000000000..52aa0fbef7 --- /dev/null +++ b/headers/os/package/Request.h @@ -0,0 +1,43 @@ +/* + * Copyright 2011, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _HAIKU__PACKAGE__REQUEST_H_ +#define _HAIKU__PACKAGE__REQUEST_H_ + + +#include + + +namespace Haiku { + +namespace Package { + + +class Context; +class Job; +class JobQueue; + + +class Request { +public: + Request(const Context& context); + virtual ~Request(); + + virtual status_t CreateJobsToRun(JobQueue& jobQueue) = 0; + + const Context& GetContext() const; + +protected: + status_t QueueJob(Job* job, JobQueue& jobQueue) const; +private: + const Context& fContext; +}; + + +} // namespace Package + +} // namespace Haiku + + +#endif // _HAIKU__PACKAGE__REQUEST_H_ diff --git a/headers/os/package/Roster.h b/headers/os/package/Roster.h new file mode 100644 index 0000000000..004095c2e1 --- /dev/null +++ b/headers/os/package/Roster.h @@ -0,0 +1,55 @@ +/* + * Copyright 2011, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _HAIKU__PACKAGE__ROSTER_H_ +#define _HAIKU__PACKAGE__ROSTER_H_ + + +#include +#include +#include + + +namespace Haiku { + +namespace Package { + + +struct RepositoryConfigVisitor { + virtual ~RepositoryConfigVisitor() + { + } + + virtual status_t operator()(const BEntry& entry) = 0; +}; + + +class Roster { +public: + Roster(); + ~Roster(); + + status_t GetCommonRepositoryConfigPath(BPath* path, + bool create = false) const; + status_t GetUserRepositoryConfigPath(BPath* path, + bool create = false) const; + + status_t VisitCommonRepositoryConfigs( + RepositoryConfigVisitor& visitor); + status_t VisitUserRepositoryConfigs( + RepositoryConfigVisitor& visitor); + +private: + status_t _VisitRepositoryConfigs(const BPath& path, + RepositoryConfigVisitor& visitor); + +}; + + +} // namespace Package + +} // namespace Haiku + + +#endif // _HAIKU__PACKAGE__ROSTER_H_ diff --git a/headers/os/package/TempEntryManager.h b/headers/os/package/TempEntryManager.h new file mode 100644 index 0000000000..0b530d0ffe --- /dev/null +++ b/headers/os/package/TempEntryManager.h @@ -0,0 +1,43 @@ +/* + * Copyright 2011, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _HAIKU__PACKAGE__TEMP_ENTRY_MANAGER_H_ +#define _HAIKU__PACKAGE__TEMP_ENTRY_MANAGER_H_ + + +#include +#include +#include +#include + + +namespace Haiku { + +namespace Package { + + +class TempEntryManager { +public: + TempEntryManager(); + ~TempEntryManager(); + + void SetBaseDirectory(const BDirectory& baseDir); + + BEntry Create(const BString& baseName = kDefaultName); + +private: + static const BString kDefaultName; + +private: + BDirectory fBaseDirectory; + vint32 fNextNumber; +}; + + +} // namespace Package + +} // namespace Haiku + + +#endif // _HAIKU__PACKAGE__TEMP_ENTRY_MANAGER_H_ diff --git a/headers/private/package/ActivateRepositoryConfigJob.h b/headers/private/package/ActivateRepositoryConfigJob.h new file mode 100644 index 0000000000..84bfb48acf --- /dev/null +++ b/headers/private/package/ActivateRepositoryConfigJob.h @@ -0,0 +1,47 @@ +/* + * Copyright 2011, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _HAIKU__PACKAGE__ACTIVATE_REPOSITORY_CONFIG_JOB_H_ +#define _HAIKU__PACKAGE__ACTIVATE_REPOSITORY_CONFIG_JOB_H_ + + +#include +#include +#include + +#include + + +namespace Haiku { + +namespace Package { + + +class ActivateRepositoryConfigJob : public Job { + typedef Job inherited; + +public: + ActivateRepositoryConfigJob( + const BString& title, + const BEntry& archivedRepoConfigEntry, + const BDirectory& targetDirectory); + virtual ~ActivateRepositoryConfigJob(); + +protected: + virtual status_t Execute(); + virtual void Cleanup(status_t jobResult); + +private: + BEntry fArchivedRepoConfigEntry; + BDirectory fTargetDirectory; + BEntry fTargetEntry; +}; + + +} // namespace Package + +} // namespace Haiku + + +#endif // _HAIKU__PACKAGE__ACTIVATE_REPOSITORY_CONFIG_JOB_H_ diff --git a/headers/private/package/FetchFileJob.h b/headers/private/package/FetchFileJob.h new file mode 100644 index 0000000000..e76c650de8 --- /dev/null +++ b/headers/private/package/FetchFileJob.h @@ -0,0 +1,44 @@ +/* + * Copyright 2011, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _HAIKU__PACKAGE__FETCH_FILE_JOB_H_ +#define _HAIKU__PACKAGE__FETCH_FILE_JOB_H_ + + +#include +#include + +#include + + +namespace Haiku { + +namespace Package { + + +class FetchFileJob : public Job { + typedef Job inherited; + +public: + FetchFileJob(const BString& title, + const BString& fileURL, + const BEntry& targetEntry); + virtual ~FetchFileJob(); + +protected: + virtual status_t Execute(); + virtual void Cleanup(status_t jobResult); + +private: + BString fFileURL; + BEntry fTargetEntry; +}; + + +} // namespace Package + +} // namespace Haiku + + +#endif // _HAIKU__PACKAGE__FETCH_FILE_JOB_H_ diff --git a/src/bin/Jamfile b/src/bin/Jamfile index 77d17d7d4e..56abcf9745 100644 --- a/src/bin/Jamfile +++ b/src/bin/Jamfile @@ -258,6 +258,7 @@ SubInclude HAIKU_TOP src bin package ; SubInclude HAIKU_TOP src bin patch ; SubInclude HAIKU_TOP src bin pc ; SubInclude HAIKU_TOP src bin pcmcia-cs ; +SubInclude HAIKU_TOP src bin pkgman ; SubInclude HAIKU_TOP src bin playsound ; SubInclude HAIKU_TOP src bin rc ; SubInclude HAIKU_TOP src bin rmd160 ; diff --git a/src/bin/pkgman/Jamfile b/src/bin/pkgman/Jamfile new file mode 100644 index 0000000000..ccb52290c5 --- /dev/null +++ b/src/bin/pkgman/Jamfile @@ -0,0 +1,12 @@ +SubDir HAIKU_TOP src bin pkgman ; + +UsePrivateHeaders shared support ; + +BinCommand pkgman : + command_add_repo.cpp + command_list_repos.cpp + pkgman.cpp + : + package be + $(TARGET_LIBSUPC++) +; diff --git a/src/bin/pkgman/command_add_repo.cpp b/src/bin/pkgman/command_add_repo.cpp new file mode 100644 index 0000000000..56d24cb51f --- /dev/null +++ b/src/bin/pkgman/command_add_repo.cpp @@ -0,0 +1,120 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ + + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "pkgman.h" + + +// TODO: internationalization! + + +using namespace Haiku::Package; + + +static const char* kCommandUsage = + "Usage: %s add-repo [ ...]\n" + "Adds one or more repositories by downloading them from the given URL(s).\n" + "\n" +; + + +static void +print_command_usage_and_exit(bool error) +{ + fprintf(error ? stderr : stdout, kCommandUsage, kProgramName); + exit(error ? 1 : 0); +} + + +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) +{ + bool asUserRepository = false; + + while (true) { + static struct option sLongOptions[] = { + { "help", no_argument, 0, 'h' }, + { "user", no_argument, 0, 'u' }, + { 0, 0, 0, 0 } + }; + + opterr = 0; // don't print errors + int c = getopt_long(argc, (char**)argv, "hu", sLongOptions, NULL); + if (c == -1) + break; + + switch (c) { + case 'h': + print_command_usage_and_exit(false); + break; + + case 'u': + asUserRepository = true; + break; + + default: + print_command_usage_and_exit(true); + break; + } + } + + // The remaining arguments are repo URLs, i. e. at least one more argument. + if (argc < optind + 1) + print_command_usage_and_exit(true); + + const char* const* repoURLs = argv + optind; + int urlCount = argc - optind; + + Context context; + status_t result; + Listener listener; + context.SetDefaultJobStateListener(&listener); + for (int i = 0; i < urlCount; ++i) { + AddRepositoryRequest request(context, repoURLs[i], asUserRepository); + JobQueue jobQueue; + result = request.CreateJobsToRun(jobQueue); + if (result != B_OK) + DIE(result, "unable to create necessary jobs"); + + while (Job* job = jobQueue.Pop()) { + result = job->Run(); + delete job; + if (result == B_INTERRUPTED) + break; + } + } + + return 0; +} diff --git a/src/bin/pkgman/command_list_repos.cpp b/src/bin/pkgman/command_list_repos.cpp new file mode 100644 index 0000000000..71ba4a37ce --- /dev/null +++ b/src/bin/pkgman/command_list_repos.cpp @@ -0,0 +1,145 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ + + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include "pkgman.h" + + +// TODO: internationalization! + + +using namespace Haiku::Package; + + +static const char* kCommandUsage = + "Usage:\n" + " %s list-repos [options]\n" + "Lists all configured package repositories.\n" + "\n" +; + + +static void +print_command_usage_and_exit(bool error) +{ + fprintf(error ? stderr : stdout, kCommandUsage, kProgramName); + exit(error ? 1 : 0); +} + + +typedef BObjectList RepositoryConfigList; + + +struct RepositoryConfigCollector : public RepositoryConfigVisitor { + RepositoryConfigCollector(RepositoryConfigList& _repositoryConfigList); + + status_t operator()(const BEntry& entry); + + RepositoryConfigList& repositoryConfigList; +}; + + +RepositoryConfigCollector::RepositoryConfigCollector( + RepositoryConfigList& _repositoryConfigList) + : + repositoryConfigList(_repositoryConfigList) +{ +} + + +status_t +RepositoryConfigCollector::operator()(const BEntry& entry) +{ + RepositoryConfig* repoConfig = new (std::nothrow) RepositoryConfig(entry); + if (repoConfig == NULL) + DIE(B_NO_MEMORY, "can't create repository-config object"); + + status_t result = repoConfig->InitCheck(); + if (result != B_OK) { + BPath path; + entry.GetPath(&path); + WARN(result, "skipping repository-config '%s'", path.Path()); + delete repoConfig; + + return B_OK; + // let collector continue + } + + return repositoryConfigList.AddItem(repoConfig) ? B_OK : B_NO_MEMORY; +} + + +int +command_list_repos(int argc, const char* const* argv) +{ + bool verbose = false; + + while (true) { + static struct option sLongOptions[] = { + { "help", no_argument, 0, 'h' }, + { "verbose", no_argument, 0, 'v' }, + { 0, 0, 0, 0 } + }; + + opterr = 0; // don't print errors + int c = getopt_long(argc, (char**)argv, "hv", sLongOptions, NULL); + if (c == -1) + break; + + switch (c) { + case 'h': + print_command_usage_and_exit(false); + break; + + case 'v': + verbose = true; + break; + + default: + print_command_usage_and_exit(true); + break; + } + } + + // No remaining arguments. + if (argc != optind) + print_command_usage_and_exit(true); + + Roster roster; + RepositoryConfigList repositoryConfigs; + RepositoryConfigCollector repositoryConfigCollector(repositoryConfigs); + status_t result + = roster.VisitCommonRepositoryConfigs(repositoryConfigCollector); + if (result != B_OK && result != B_ENTRY_NOT_FOUND) + DIE(result, "can't collect common repository configs"); + + result = roster.VisitUserRepositoryConfigs(repositoryConfigCollector); + if (result != B_OK && result != B_ENTRY_NOT_FOUND) + DIE(result, "can't collect user's repository configs"); + + int32 count = repositoryConfigs.CountItems(); + for (int32 i = 0; i < count; ++i) { + RepositoryConfig* repoConfig = repositoryConfigs.ItemAt(i); + printf(" %s %s\n", + repoConfig->IsUserSpecific() ? "[User]" : " ", + repoConfig->Name().String()); + } + + return 0; +} diff --git a/src/bin/pkgman/pkgman.cpp b/src/bin/pkgman/pkgman.cpp new file mode 100644 index 0000000000..55a6acb939 --- /dev/null +++ b/src/bin/pkgman/pkgman.cpp @@ -0,0 +1,72 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ + + +#include "pkgman.h" + +#include +#include +#include +#include + + +extern const char* __progname; +const char* kProgramName = __progname; + + +static const char* kUsage = + "Usage: %s \n" + "Creates, inspects, or extracts a Haiku package.\n" + "\n" + "Commands:\n" + " add-repo \n" + " Adds the repository with the given .\n" + "\n" + " list-repos\n" + " Lists all repositories.\n" + "\n" + " drop-repo \n" + " Drops the repository with the given .\n" + "\n" + "Common Options:\n" + " -h, --help - Print this usage info.\n" +; + + +void +print_usage_and_exit(bool error) +{ + fprintf(error ? stderr : stdout, kUsage, kProgramName); + exit(error ? 1 : 0); +} + + +int +main(int argc, const char* const* argv) +{ + if (argc < 2) + print_usage_and_exit(true); + + const char* command = argv[1]; + if (strcmp(command, "add-repo") == 0) + return command_add_repo(argc - 1, argv + 1); + +// if (strcmp(command, "drop-repo") == 0) +// return command_drop_repo(argc - 1, argv + 1); + + if (strcmp(command, "list-repos") == 0) + return command_list_repos(argc - 1, argv + 1); + +// if (strcmp(command, "search") == 0) +// return command_search(argc - 1, argv + 1); + + if (strcmp(command, "help") == 0) + print_usage_and_exit(false); + else + print_usage_and_exit(true); + + // never gets here + return 0; +} diff --git a/src/bin/pkgman/pkgman.h b/src/bin/pkgman/pkgman.h new file mode 100644 index 0000000000..9f27d4d130 --- /dev/null +++ b/src/bin/pkgman/pkgman.h @@ -0,0 +1,44 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ +#ifndef PKGMAN_H +#define PKGMAN_H + + +#include +#include +#include + + +extern const char* kProgramName; + + +#define DIE(result, msg...) \ +do { \ + fprintf(stderr, "*** " msg); \ + fprintf(stderr, " : %s\n", strerror(result)); \ + exit(5); \ +} while(0) + +#define ERROR(result, msg...) \ +do { \ + fprintf(stderr, "*** " msg); \ + fprintf(stderr, " : %s\n", strerror(result)); \ +} while(0) + +#define WARN(result, msg...) \ +do { \ + fprintf(stderr, "* " msg); \ + fprintf(stderr, " : %s\n", strerror(result)); \ +} while(0) + + +void print_usage_and_exit(bool error); + +int command_add_repo(int argc, const char* const* argv); +int command_drop_repo(int argc, const char* const* argv); +int command_list_repos(int argc, const char* const* argv); + + +#endif // PKGMAN_H diff --git a/src/kits/Jamfile b/src/kits/Jamfile index 7a09a4c4db..b635fda824 100644 --- a/src/kits/Jamfile +++ b/src/kits/Jamfile @@ -83,6 +83,7 @@ SubInclude HAIKU_TOP src kits midi2 ; SubInclude HAIKU_TOP src kits network ; SubInclude HAIKU_TOP src kits notification ; SubInclude HAIKU_TOP src kits opengl ; +SubInclude HAIKU_TOP src kits package ; SubInclude HAIKU_TOP src kits print ; SubInclude HAIKU_TOP src kits screensaver ; SubInclude HAIKU_TOP src kits shared ; diff --git a/src/kits/package/ActivateRepositoryConfigJob.cpp b/src/kits/package/ActivateRepositoryConfigJob.cpp new file mode 100644 index 0000000000..4121e651ec --- /dev/null +++ b/src/kits/package/ActivateRepositoryConfigJob.cpp @@ -0,0 +1,92 @@ +#include +#include +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Oliver Tappe + */ + + +#include + +#include + +#include + +#include + + +namespace Haiku { + +namespace Package { + + +ActivateRepositoryConfigJob::ActivateRepositoryConfigJob(const BString& title, + const BEntry& archivedRepoConfigEntry, const BDirectory& targetDirectory) + : + inherited(title), + fArchivedRepoConfigEntry(archivedRepoConfigEntry), + fTargetDirectory(targetDirectory) +{ +} + + +ActivateRepositoryConfigJob::~ActivateRepositoryConfigJob() +{ +} + + +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; + } + +printf("Execute(): 6\n"); + if ((result = repoConfig->StoreAsConfigFile(fTargetEntry)) != B_OK) + return result; + +printf("Execute(): 7\n"); + return B_OK; +} + + +void +ActivateRepositoryConfigJob::Cleanup(status_t jobResult) +{ + if (jobResult != B_OK && State() != JOB_STATE_ABORTED) + fTargetEntry.Remove(); +} + + +} // namespace Package + +} // namespace Haiku diff --git a/src/kits/package/AddRepositoryRequest.cpp b/src/kits/package/AddRepositoryRequest.cpp new file mode 100644 index 0000000000..9a00870afb --- /dev/null +++ b/src/kits/package/AddRepositoryRequest.cpp @@ -0,0 +1,83 @@ +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Oliver Tappe + */ + + +#include + +#include +#include + +#include +#include +#include +#include + + +namespace Haiku { + +namespace Package { + + +AddRepositoryRequest::AddRepositoryRequest(const Context& context, + const BString& repositoryURL, bool asUserRepository) + : + inherited(context), + fRepositoryURL(repositoryURL), + fAsUserRepository(asUserRepository) +{ +} + + +AddRepositoryRequest::~AddRepositoryRequest() +{ +} + + +status_t +AddRepositoryRequest::CreateJobsToRun(JobQueue& jobQueue) +{ + BEntry tempEntry + = GetContext().GetTempEntryManager().Create("repoconfig-"); + FetchFileJob* fetchJob = new (std::nothrow) FetchFileJob( + BString("Fetching repository-config from ") << fRepositoryURL, + fRepositoryURL, tempEntry); + if (fetchJob == NULL) + return B_NO_MEMORY; + status_t result = QueueJob(fetchJob, jobQueue); + if (result != B_OK) { + delete fetchJob; + return result; + } + + Roster roster; + BPath targetRepoConfigPath; + result = fAsUserRepository + ? roster.GetUserRepositoryConfigPath(&targetRepoConfigPath, true) + : roster.GetCommonRepositoryConfigPath(&targetRepoConfigPath, true); + if (result != B_OK) + return result; + BDirectory targetDirectory(targetRepoConfigPath.Path()); + ActivateRepositoryConfigJob* activateJob + = new (std::nothrow) ActivateRepositoryConfigJob( + BString("Activating repository-config from ") << fRepositoryURL, + tempEntry, targetDirectory); + if (activateJob == NULL) + return B_NO_MEMORY; + activateJob->AddDependency(fetchJob); + if ((result = QueueJob(activateJob, jobQueue)) != B_OK) { + delete activateJob; + return result; + } + + return B_OK; +} + + +} // namespace Package + +} // namespace Haiku diff --git a/src/kits/package/Context.cpp b/src/kits/package/Context.cpp new file mode 100644 index 0000000000..38c42f615e --- /dev/null +++ b/src/kits/package/Context.cpp @@ -0,0 +1,67 @@ +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Oliver Tappe + */ + + +#include + +#include +#include +#include +#include + + +namespace Haiku { + +namespace Package { + + +Context::Context() + : + fDefaultJobStateListener(NULL) +{ + BPath tempPath; + if (find_directory(B_COMMON_TEMP_DIRECTORY, &tempPath) != B_OK) + tempPath.SetTo("/tmp"); + BDirectory tempDirectory(tempPath.Path()); + + BString contextName = BString("pkgkit-context-") << find_thread(NULL); + BDirectory baseDirectory; + tempDirectory.CreateDirectory(contextName.String(), &baseDirectory); + fTempEntryManager.SetBaseDirectory(baseDirectory); +} + + +Context::~Context() +{ +} + + +TempEntryManager& +Context::GetTempEntryManager() const +{ + return fTempEntryManager; +} + + +JobStateListener* +Context::DefaultJobStateListener() const +{ + return fDefaultJobStateListener; +} + + +void +Context::SetDefaultJobStateListener(JobStateListener* listener) +{ + fDefaultJobStateListener = listener; +} + + +} // namespace Package + +} // namespace Haiku diff --git a/src/kits/package/FetchFileJob.cpp b/src/kits/package/FetchFileJob.cpp new file mode 100644 index 0000000000..9ba0fcd50a --- /dev/null +++ b/src/kits/package/FetchFileJob.cpp @@ -0,0 +1,70 @@ +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Oliver Tappe + */ + + +#include + +#include +#include + +#include + + +namespace Haiku { + +namespace Package { + + +FetchFileJob::FetchFileJob(const BString& title, const BString& fileURL, + const BEntry& targetEntry) + : + inherited(title), + fFileURL(fileURL), + fTargetEntry(targetEntry) +{ +} + + +FetchFileJob::~FetchFileJob() +{ +} + + +status_t +FetchFileJob::Execute() +{ + BPath targetPath; + status_t result = fTargetEntry.GetPath(&targetPath); + if (result != B_OK) + return result; + + // TODO: implement for real, maybe using the "service kit"-GSOC HTTP-stuff? + BString cmd = BString("curl -# -o ") << targetPath.Path() << " " + << fFileURL.String(); + + int cmdResult = system(cmd.String()); + if (WIFSIGNALED(cmdResult) + && (WTERMSIG(cmdResult) == SIGINT || WTERMSIG(cmdResult) == SIGQUIT)) { + return B_INTERRUPTED; + } + + return cmdResult == 0 ? B_OK : B_ERROR; +} + + +void +FetchFileJob::Cleanup(status_t jobResult) +{ + if (jobResult != B_OK) + fTargetEntry.Remove(); +} + + +} // namespace Package + +} // namespace Haiku diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile new file mode 100644 index 0000000000..5b5ff4c09e --- /dev/null +++ b/src/kits/package/Jamfile @@ -0,0 +1,19 @@ +SubDir HAIKU_TOP src kits package ; + +UsePrivateHeaders package ; + +SharedLibrary libpackage.so + : + ActivateRepositoryConfigJob.cpp + AddRepositoryRequest.cpp + Context.cpp + FetchFileJob.cpp + Job.cpp + JobQueue.cpp + RepositoryConfig.cpp + Request.cpp + Roster.cpp + TempEntryManager.cpp + : + be $(TARGET_LIBSTDC++) +; diff --git a/src/kits/package/Job.cpp b/src/kits/package/Job.cpp new file mode 100644 index 0000000000..eff34e43ef --- /dev/null +++ b/src/kits/package/Job.cpp @@ -0,0 +1,207 @@ +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Oliver Tappe + */ + + +#include + +#include + + +namespace Haiku { + +namespace Package { + + +JobStateListener::~JobStateListener() +{ +} + + +void +JobStateListener::JobStarted(Job* job) +{ +} + + +void +JobStateListener::JobSucceeded(Job* job) +{ +} + + +void +JobStateListener::JobFailed(Job* job) +{ +} + + +void +JobStateListener::JobAborted(Job* job) +{ +} + + +Job::Job(const BString& title) + : + fTitle(title), + fState(JOB_STATE_WAITING_TO_RUN) +{ + if (fTitle.Length() == 0) + fInitStatus = B_BAD_VALUE; + else + fInitStatus = B_OK; +} + + +Job::~Job() +{ +} + + +status_t +Job::InitCheck() const +{ + return fInitStatus; +} + + +const BString& +Job::Title() const +{ + return fTitle; +} + + +JobState +Job::State() const +{ + return fState; +} + + +status_t +Job::Result() const +{ + return fResult; +} + + +status_t +Job::Run() +{ + if (fState != JOB_STATE_WAITING_TO_RUN) + return B_NOT_ALLOWED; + + fState = JOB_STATE_RUNNING; + NotifyStateListeners(); + + fResult = Execute(); + Cleanup(fResult); + + fState = fResult == B_OK + ? JOB_STATE_SUCCEEDED + : fResult == B_INTERRUPTED + ? JOB_STATE_ABORTED + : JOB_STATE_FAILED; + NotifyStateListeners(); + + return fResult; +} + + +void +Job::Cleanup(status_t /*jobResult*/) +{ +} + + +status_t +Job::AddStateListener(JobStateListener* listener) +{ + return fStateListeners.AddItem(listener) ? B_OK : B_ERROR; +} + + +status_t +Job::RemoveStateListener(JobStateListener* listener) +{ + return fStateListeners.RemoveItem(listener) ? B_OK : B_ERROR; +} + + +status_t +Job::AddDependency(Job* job) +{ + if (fDependencies.HasItem(job)) + return B_ERROR; + + if (fDependencies.AddItem(job) && job->fDependantJobs.AddItem(this)) + return B_OK; + + return B_ERROR; +} + + +status_t +Job::RemoveDependency(Job* job) +{ + if (!fDependencies.HasItem(job)) + return B_ERROR; + + if (fDependencies.RemoveItem(job) && job->fDependantJobs.RemoveItem(this)) + return B_OK; + + return B_ERROR; +} + + +int32 +Job::CountDependencies() const +{ + return fDependencies.CountItems(); +} + + +Job* +Job::DependantJobAt(int32 index) const +{ + return fDependantJobs.ItemAt(index); +} + + +void +Job::NotifyStateListeners() +{ + int32 count = fStateListeners.CountItems(); + for (int i = 0; i < count; ++i) { + JobStateListener* listener = fStateListeners.ItemAt(i); + if (listener == NULL) + continue; + switch (fState) { + case JOB_STATE_RUNNING: + listener->JobStarted(this); + break; + case JOB_STATE_SUCCEEDED: + listener->JobSucceeded(this); + break; + case JOB_STATE_FAILED: + listener->JobFailed(this); + break; + case JOB_STATE_ABORTED: + listener->JobAborted(this); + break; + default: + break; + } + } +} + + +} // namespace Package + +} // namespace Haiku diff --git a/src/kits/package/JobQueue.cpp b/src/kits/package/JobQueue.cpp new file mode 100644 index 0000000000..7f0f378db0 --- /dev/null +++ b/src/kits/package/JobQueue.cpp @@ -0,0 +1,155 @@ +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Oliver Tappe + */ + + +#include + +#include + +#include + +#include + + +namespace Haiku { + +namespace Package { + + +struct JobQueue::JobPriorityLess { + bool operator()(const Job* left, const Job* right) const; +}; + + +bool +JobQueue::JobPriorityLess::operator()(const Job* left, const Job* right) const +{ + int32 difference = left->CountDependencies() - right->CountDependencies(); + if (difference < 0) + return true; + if (difference > 0) + return false; + + return left->Title() < right->Title(); +}; + + +class JobQueue::JobPriorityQueue + : public std::set { + +}; + + +JobQueue::JobQueue() + : + fLock("job queue"), + fQueuedJobs(new (std::nothrow) JobPriorityQueue()) +{ +} + + +JobQueue::~JobQueue() +{ +} + + +status_t +JobQueue::AddJob(Job* job) +{ + if (fQueuedJobs == NULL) + return B_NO_INIT; + + BAutolock lock(&fLock); + if (lock.IsLocked()) { + try { + fQueuedJobs->insert(job); + } catch (const std::bad_alloc& e) { + return B_NO_MEMORY; + } catch (...) { + return B_NO_MEMORY; + } + job->AddStateListener(this); + } + + return B_OK; +} + + +status_t +JobQueue::RemoveJob(Job* job) +{ + if (fQueuedJobs == NULL) + return B_NO_INIT; + + BAutolock lock(&fLock); + if (lock.IsLocked()) { + try { + fQueuedJobs->erase(job); + } catch (...) { + return B_ERROR; + } + job->RemoveStateListener(this); + } + + return B_OK; +} + + +void +JobQueue::JobSucceeded(Job* job) +{ + _UpdateDependantJobsOf(job); +} + + +void +JobQueue::JobFailed(Job* job) +{ + _UpdateDependantJobsOf(job); +} + + +Job* +JobQueue::Pop() +{ + BAutolock lock(&fLock); + if (lock.IsLocked()) { + JobPriorityQueue::iterator head = fQueuedJobs->begin(); + if (head == fQueuedJobs->end()) + return NULL; + fQueuedJobs->erase(head); + return *head; + } + + return NULL; +} + + +void +JobQueue::_UpdateDependantJobsOf(Job* job) +{ + BAutolock lock(&fLock); + if (lock.IsLocked()) { + while (Job* dependantJob = job->DependantJobAt(0)) { + try { + fQueuedJobs->erase(dependantJob); + } catch (...) { + } + dependantJob->RemoveDependency(job); + try { + fQueuedJobs->insert(dependantJob); + } catch (...) { + } + } + } +} + + +} // namespace Package + +} // namespace Haiku diff --git a/src/kits/package/RepositoryConfig.cpp b/src/kits/package/RepositoryConfig.cpp new file mode 100644 index 0000000000..73abb6cdc9 --- /dev/null +++ b/src/kits/package/RepositoryConfig.cpp @@ -0,0 +1,261 @@ +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Oliver Tappe + */ + + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + + +namespace Haiku { + +namespace Package { + + +const char* RepositoryConfig::kNameField = "name"; +const char* RepositoryConfig::kURLField = "url"; +const char* RepositoryConfig::kPriorityField = "priority"; + + +RepositoryConfig::RepositoryConfig() + : + fInitStatus(B_NO_INIT), + fPriority(kDefaultPriority), + fIsUserSpecific(false) +{ +} + + +RepositoryConfig::RepositoryConfig(const BEntry& entry) +{ + fInitStatus = _InitFrom(entry); +} + + +RepositoryConfig::RepositoryConfig(BMessage* data) + : + inherited(data) +{ + fInitStatus = _InitFrom(data); +} + + +RepositoryConfig::RepositoryConfig(const BString& name, const BString& url, + uint8 priority) + : + fInitStatus(B_OK), + fName(name), + fURL(url), + fPriority(priority), + fIsUserSpecific(false) +{ +} + + +RepositoryConfig::~RepositoryConfig() +{ +} + + +/*static*/ RepositoryConfig* +RepositoryConfig::Instantiate(BMessage* data) +{ + if (validate_instantiation(data, "Haiku::Package::RepositoryConfig")) + return new (std::nothrow) RepositoryConfig(data); + + return NULL; +} + + +status_t +RepositoryConfig::Archive(BMessage* data, bool deep) const +{ + status_t result = inherited::Archive(data, deep); + if (result != B_OK) + return result; + + if ((result = data->AddString(kNameField, fName)) != B_OK) + return result; + if ((result = data->AddString(kURLField, fURL)) != B_OK) + return result; + if ((result = data->AddUInt8(kPriorityField, fPriority)) != B_OK) + return result; + + return B_OK; +} + + +status_t +RepositoryConfig::StoreAsConfigFile(const BEntry& entry) const +{ + BFile file(&entry, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); + status_t result = file.InitCheck(); + if (result != B_OK) + return result; + + BString configString; + configString + << "name=" << fName << "\n" + << "url=" << fURL << "\n" + << "priority=" << fPriority << "\n"; + + int32 size = configString.Length(); + if ((result = file.Write(configString.String(), size)) < size) + return (result >= 0) ? B_ERROR : result; + + return B_OK; +} + + +status_t +RepositoryConfig::InitCheck() const +{ + return fInitStatus; +} + + +const BString& +RepositoryConfig::Name() const +{ + return fName; +} + + +const BString& +RepositoryConfig::URL() const +{ + return fURL; +} + + +uint8 +RepositoryConfig::Priority() const +{ + return fPriority; +} + + +bool +RepositoryConfig::IsUserSpecific() const +{ + return fIsUserSpecific; +} + + +void +RepositoryConfig::SetName(const BString& name) +{ + fName = name; +} + + +void +RepositoryConfig::SetURL(const BString& url) +{ + fURL = url; +} + + +void +RepositoryConfig::SetPriority(uint8 priority) +{ + fPriority = priority; +} + + +void +RepositoryConfig::SetIsUserSpecific(bool isUserSpecific) +{ + fIsUserSpecific = isUserSpecific; +} + + +status_t +RepositoryConfig::_InitFrom(const BEntry& entry) +{ + BFile file(&entry, B_READ_ONLY); + status_t result = file.InitCheck(); + if (result != B_OK) + return result; + + off_t size; + if ((result = file.GetSize(&size)) != B_OK) + return result; + + BString configString; + char* buffer = configString.LockBuffer(size); + if (buffer == NULL) + return B_NO_MEMORY; + + if ((result = file.Read(buffer, size)) < size) + return (result >= 0) ? B_ERROR : result; + + configString.UnlockBuffer(size); + + void* settingsHandle = parse_driver_settings_string(configString.String()); + if (settingsHandle == NULL) + return B_BAD_DATA; + + const char* name = get_driver_parameter(settingsHandle, "name", NULL, NULL); + const char* url = get_driver_parameter(settingsHandle, "url", NULL, NULL); + const char* priorityString + = get_driver_parameter(settingsHandle, "priority", NULL, NULL); + + unload_driver_settings(settingsHandle); + + if (name == NULL || *name == '\0' || url == NULL || *url == '\0') + return B_BAD_DATA; + + fName = name; + fURL = url; + fPriority = priorityString == NULL + ? kDefaultPriority : atoi(priorityString); + + BPath userSettingsPath; + if (find_directory(B_USER_SETTINGS_DIRECTORY, &userSettingsPath) == B_OK) { + BDirectory userSettingsDir(userSettingsPath.Path()); + fIsUserSpecific = userSettingsDir.Contains(&entry); + } else + fIsUserSpecific = false; + + return B_OK; +} + + +status_t +RepositoryConfig::_InitFrom(const BMessage* data) +{ + if (data == NULL) + return B_BAD_VALUE; + + status_t result; + if ((result = data->FindString(kNameField, &fName)) != B_OK) + return result; + if ((result = data->FindString(kURLField, &fURL)) != B_OK) + return result; + if ((result = data->FindUInt8(kPriorityField, &fPriority)) != B_OK) + return result; + + fIsUserSpecific = false; + + return B_OK; +} + + +} // namespace Package + +} // namespace Haiku diff --git a/src/kits/package/Request.cpp b/src/kits/package/Request.cpp new file mode 100644 index 0000000000..c436c1e846 --- /dev/null +++ b/src/kits/package/Request.cpp @@ -0,0 +1,54 @@ +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Oliver Tappe + */ + + +#include + +#include +#include +#include + + +namespace Haiku { + +namespace Package { + + +Request::Request(const Context& context) + : + fContext(context) +{ +} + + +Request::~Request() +{ +} + + +const Context& +Request::GetContext() const +{ + return fContext; +} + + +status_t +Request::QueueJob(Job* job, JobQueue& jobQueue) const +{ + JobStateListener* defaultListener = fContext.DefaultJobStateListener(); + if (defaultListener != NULL) + job->AddStateListener(defaultListener); + + return jobQueue.AddJob(job); +} + + +} // namespace Package + +} // namespace Haiku diff --git a/src/kits/package/Roster.cpp b/src/kits/package/Roster.cpp new file mode 100644 index 0000000000..7a77397079 --- /dev/null +++ b/src/kits/package/Roster.cpp @@ -0,0 +1,130 @@ +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Oliver Tappe + */ + + +#include + +#include +#include + +#include +#include +#include +#include + + +namespace Haiku { + +namespace Package { + + +Roster::Roster() +{ +} + + +Roster::~Roster() +{ +} + + +status_t +Roster::GetCommonRepositoryConfigPath(BPath* path, bool create) const +{ + if (path == NULL) + return B_BAD_VALUE; + + status_t result = find_directory(B_COMMON_SETTINGS_DIRECTORY, path); + if (result != B_OK) + return result; + if ((result = path->Append("package-repositories")) != B_OK) + return result; + + if (create) { + BEntry entry(path->Path(), true); + if (!entry.Exists()) { + if (mkdir(path->Path(), 0755) != 0) + return errno; + } + } + + return B_OK; +} + + +status_t +Roster::GetUserRepositoryConfigPath(BPath* path, bool create) const +{ + if (path == NULL) + return B_BAD_VALUE; + + status_t result = find_directory(B_USER_SETTINGS_DIRECTORY, path); + if (result != B_OK) + return result; + if ((result = path->Append("package-repositories")) != B_OK) + return result; + + if (create) { + BEntry entry(path->Path(), true); + if (!entry.Exists()) { + if (mkdir(path->Path(), 0755) != 0) + return errno; + } + } + + return B_OK; +} + + +status_t +Roster::VisitCommonRepositoryConfigs(RepositoryConfigVisitor& visitor) +{ + BPath commonRepositoryConfigPath; + status_t result + = GetCommonRepositoryConfigPath(&commonRepositoryConfigPath); + if (result == B_OK) + result = _VisitRepositoryConfigs(commonRepositoryConfigPath, visitor); + + return result; +} + + +status_t +Roster::VisitUserRepositoryConfigs(RepositoryConfigVisitor& visitor) +{ + BPath userRepositoryConfigPath; + status_t result = GetUserRepositoryConfigPath(&userRepositoryConfigPath); + if (result == B_OK) + result = _VisitRepositoryConfigs(userRepositoryConfigPath, visitor); + + return result; +} + + +status_t +Roster::_VisitRepositoryConfigs(const BPath& path, + RepositoryConfigVisitor& visitor) +{ + BDirectory directory(path.Path()); + status_t result = directory.InitCheck(); + if (result != B_OK) + return result; + + BEntry entry; + while (directory.GetNextEntry(&entry, true) == B_OK) { + if ((result = visitor(entry)) != B_OK) + return result; + } + + return B_OK; +} + + +} // namespace Package + +} // namespace Haiku diff --git a/src/kits/package/TempEntryManager.cpp b/src/kits/package/TempEntryManager.cpp new file mode 100644 index 0000000000..96baedb8ee --- /dev/null +++ b/src/kits/package/TempEntryManager.cpp @@ -0,0 +1,61 @@ +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Oliver Tappe + */ + + +#include + + +namespace Haiku { + +namespace Package { + + +const BString TempEntryManager::kDefaultName = "tmp-pkgkit-file-"; + + +TempEntryManager::TempEntryManager() + : + fNextNumber(1) +{ +} + + +TempEntryManager::~TempEntryManager() +{ + if (fBaseDirectory.InitCheck() != B_OK) + return; + + fBaseDirectory.Rewind(); + BEntry entry; + while (fBaseDirectory.GetNextEntry(&entry) == B_OK) + entry.Remove(); + + fBaseDirectory.GetEntry(&entry); + entry.Remove(); +} + + +void +TempEntryManager::SetBaseDirectory(const BDirectory& baseDirectory) +{ + fBaseDirectory = baseDirectory; +} + + +BEntry +TempEntryManager::Create(const BString& baseName) +{ + BString name = BString(baseName) << atomic_add(&fNextNumber, 1); + + return BEntry(&fBaseDirectory, name.String()); +} + + +} // namespace Package + +} // namespace Haiku diff --git a/src/tests/kits/Jamfile b/src/tests/kits/Jamfile index bb3a1dbd4b..9cfa4fbafa 100644 --- a/src/tests/kits/Jamfile +++ b/src/tests/kits/Jamfile @@ -7,9 +7,10 @@ SubInclude HAIKU_TOP src tests kits locale ; SubInclude HAIKU_TOP src tests kits media ; SubInclude HAIKU_TOP src tests kits midi ; SubInclude HAIKU_TOP src tests kits net ; +SubInclude HAIKU_TOP src tests kits opengl ; +SubInclude HAIKU_TOP src tests kits package ; SubInclude HAIKU_TOP src tests kits shared ; SubInclude HAIKU_TOP src tests kits storage ; SubInclude HAIKU_TOP src tests kits support ; SubInclude HAIKU_TOP src tests kits translation ; -SubInclude HAIKU_TOP src tests kits opengl ; diff --git a/src/tests/kits/package/Jamfile b/src/tests/kits/package/Jamfile new file mode 100644 index 0000000000..cf47f18aa0 --- /dev/null +++ b/src/tests/kits/package/Jamfile @@ -0,0 +1,4 @@ +SubDir HAIKU_TOP src tests kits package ; + +SimpleTest make_repo : make_repo.cpp : package be ; + diff --git a/src/tests/kits/package/make_repo.cpp b/src/tests/kits/package/make_repo.cpp new file mode 100644 index 0000000000..7ef859751e --- /dev/null +++ b/src/tests/kits/package/make_repo.cpp @@ -0,0 +1,80 @@ +#include +#include + +#include +#include +#include + +#include + + +using namespace Haiku::Package; + + +int +main(int argc, const char** argv) +{ + if (argc < 5) { + fprintf(stderr, "usage: %s \n", + argv[0]); + return 1; + } + + RepositoryConfig repoConfig(argv[1], argv[2], atoi(argv[3])); + status_t status = repoConfig.InitCheck(); + if (status != B_OK) { + fprintf(stderr, "couldn't initialize repository-config\n"); + return 1; + } + + BMessage repoConfigArchive; + if ((status = repoConfig.Archive(&repoConfigArchive)) != B_OK) { + fprintf(stderr, "couldn't archive repository-config\n"); + return 1; + } + + BFile output(argv[1], B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + if ((status = repoConfigArchive.Flatten(&output)) != B_OK) { + fprintf(stderr, "couldn't flatten repository-config archive\n"); + return 1; + } + + int pkgCount = atoi(argv[4]); + for (int i = 0; i < pkgCount; ++i) { + BMessage pkg('PKGp'); + + BString name = BString("pkg") << i + 1; + pkg.AddString("name", name.String()); + + BString majorVersion + = BString() << 1 + i % 5 << "." << i % 10; + BString minorVersion + = BString() << i % 100; + pkg.AddString("version", + (BString() << majorVersion << "." << minorVersion).String()); + + pkg.AddString("provides", + (BString() << name << "-" << majorVersion).String()); + if (i % 2 == 1) + pkg.AddString("provides", (BString("lib") << name).String()); + if (i % 3 != 1) + pkg.AddString("provides", (BString("cmd:") << name).String()); + + if (i > 1) { + int requiresCount = rand() % 10 % i; + for (int r = 0; r < requiresCount; ++r) { + int reqIndex = rand() % i; + pkg.AddString("requires", + (BString("pkg") << reqIndex).String()); + } + } + + status = pkg.Flatten(&output); + if (status != B_OK) { + fprintf(stderr, "couldn't flatten pkg message #%d\n", i + 1); + return 1; + } + } + + return 0; +}