From 35edda8f0befb8667b593e2314f6d555a7db44d8 Mon Sep 17 00:00:00 2001 From: Oliver Tappe Date: Mon, 24 Jan 2011 20:48:03 +0000 Subject: [PATCH] * more work on the package kit, repositories can now be added and refreshed git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40280 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/package/AddRepositoryRequest.h | 22 ++- headers/os/package/Attributes.h | 31 +++ headers/os/package/Context.h | 7 +- headers/os/package/Job.h | 5 + headers/os/package/RefreshRepositoryRequest.h | 56 ++++++ headers/os/package/RepositoryCache.h | 47 ++++- headers/os/package/RepositoryConfig.h | 12 +- headers/os/package/Request.h | 18 +- headers/os/package/Roster.h | 21 +++ .../package/ActivateRepositoryCacheJob.h | 52 +++++ .../package/ActivateRepositoryConfigJob.h | 18 +- headers/private/package/ChecksumAccessors.h | 61 ++++++ headers/private/package/FetchFileJob.h | 12 +- headers/{os => private}/package/JobQueue.h | 4 + .../package/TempfileManager.h} | 18 +- headers/private/package/ValidateChecksumJob.h | 57 ++++++ src/bin/pkgman/Jamfile | 3 +- src/bin/pkgman/MyJobStateListener.cpp | 5 + src/bin/pkgman/command_add_repo.cpp | 28 ++- src/bin/pkgman/command_list_repos.cpp | 73 ++----- src/bin/pkgman/command_refresh.cpp | 119 ++++++++++++ src/bin/pkgman/pkgman.cpp | 14 +- src/bin/pkgman/pkgman.h | 1 + .../package/ActivateRepositoryCacheJob.cpp | 59 ++++++ .../package/ActivateRepositoryConfigJob.cpp | 21 ++- src/kits/package/AddRepositoryRequest.cpp | 48 +++-- src/kits/package/Attributes.cpp | 33 ++++ src/kits/package/ChecksumAccessors.cpp | 136 +++++++++++++ src/kits/package/Context.cpp | 8 +- src/kits/package/FetchFileJob.cpp | 4 + src/kits/package/Jamfile | 13 +- src/kits/package/Job.cpp | 14 ++ src/kits/package/JobQueue.cpp | 4 + src/kits/package/RefreshRepositoryRequest.cpp | 171 +++++++++++++++++ src/kits/package/RepositoryCache.cpp | 106 +++++++++++ src/kits/package/RepositoryConfig.cpp | 171 +++++++++-------- src/kits/package/Request.cpp | 16 +- src/kits/package/Roster.cpp | 178 ++++++++++++++---- ...mpEntryManager.cpp => TempfileManager.cpp} | 18 +- src/kits/package/ValidateChecksumJob.cpp | 86 +++++++++ 40 files changed, 1507 insertions(+), 263 deletions(-) create mode 100644 headers/os/package/Attributes.h create mode 100644 headers/os/package/RefreshRepositoryRequest.h create mode 100644 headers/private/package/ActivateRepositoryCacheJob.h create mode 100644 headers/private/package/ChecksumAccessors.h rename headers/{os => private}/package/JobQueue.h (94%) rename headers/{os/package/TempEntryManager.h => private/package/TempfileManager.h} (58%) create mode 100644 headers/private/package/ValidateChecksumJob.h create mode 100644 src/bin/pkgman/command_refresh.cpp create mode 100644 src/kits/package/ActivateRepositoryCacheJob.cpp create mode 100644 src/kits/package/Attributes.cpp create mode 100644 src/kits/package/ChecksumAccessors.cpp create mode 100644 src/kits/package/RefreshRepositoryRequest.cpp create mode 100644 src/kits/package/RepositoryCache.cpp rename src/kits/package/{TempEntryManager.cpp => TempfileManager.cpp} (66%) create mode 100644 src/kits/package/ValidateChecksumJob.cpp diff --git a/headers/os/package/AddRepositoryRequest.h b/headers/os/package/AddRepositoryRequest.h index ed18e49739..fe038f5f45 100644 --- a/headers/os/package/AddRepositoryRequest.h +++ b/headers/os/package/AddRepositoryRequest.h @@ -17,20 +17,36 @@ namespace Haiku { namespace Package { +namespace Private { + class ActivateRepositoryConfigJob; +} +using Private::ActivateRepositoryConfigJob; + + class AddRepositoryRequest : public Request { typedef Request inherited; public: AddRepositoryRequest(const Context& context, - const BString& repositoryURL, + const BString& repositoryBaseURL, bool asUserRepository); virtual ~AddRepositoryRequest(); - virtual status_t CreateJobsToRun(JobQueue& jobQueue); + virtual status_t CreateInitialJobs(); + + const BString& RepositoryName() const; + +protected: + // JobStateListener + virtual void JobSucceeded(Job* job); private: - BString fRepositoryURL; + BString fRepositoryBaseURL; bool fAsUserRepository; + + ActivateRepositoryConfigJob* fActivateJob; + + BString fRepositoryName; }; diff --git a/headers/os/package/Attributes.h b/headers/os/package/Attributes.h new file mode 100644 index 0000000000..c2e3359c63 --- /dev/null +++ b/headers/os/package/Attributes.h @@ -0,0 +1,31 @@ +/* + * Copyright 2011, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _HAIKU__PACKAGE__ATTRIBUTES_H_ +#define _HAIKU__PACKAGE__ATTRIBUTES_H_ + + +namespace Haiku { + +namespace Package { + + +// attributes used in package and as file attribute, too +extern const char* kNameAttribute; +extern const char* kVendorAttribute; +extern const char* kVersionAttribute; + +// attributes kept local to packages +extern const char* kCopyrightAttribute; +extern const char* kLicenseAttribute; +extern const char* kProvidesAttribute; +extern const char* kRequiresAttribute; + + +} // namespace Package + +} // namespace Haiku + + +#endif // _HAIKU__PACKAGE__ATTRIBUTES_H_ diff --git a/headers/os/package/Context.h b/headers/os/package/Context.h index 1ab9fdd9cd..4c5ace011c 100644 --- a/headers/os/package/Context.h +++ b/headers/os/package/Context.h @@ -6,7 +6,7 @@ #define _HAIKU__PACKAGE__CONTEXT_H_ -#include +#include namespace Haiku { @@ -15,6 +15,7 @@ namespace Package { class JobStateListener; +using Private::TempfileManager; struct DecisionProvider { @@ -37,7 +38,7 @@ public: Context(DecisionProvider& decisionProvider); ~Context(); - TempEntryManager& GetTempEntryManager() const; + TempfileManager& GetTempfileManager() const; JobStateListener* GetJobStateListener() const; void SetJobStateListener(JobStateListener* listener); @@ -45,7 +46,7 @@ public: DecisionProvider& GetDecisionProvider() const; private: - mutable TempEntryManager fTempEntryManager; + mutable TempfileManager fTempfileManager; DecisionProvider& fDecisionProvider; JobStateListener* fJobStateListener; }; diff --git a/headers/os/package/Job.h b/headers/os/package/Job.h index 800389533f..00b75be6f3 100644 --- a/headers/os/package/Job.h +++ b/headers/os/package/Job.h @@ -18,6 +18,7 @@ namespace Package { class Context; class Job; + struct JobStateListener { virtual ~JobStateListener(); @@ -51,6 +52,7 @@ public: const BString& Title() const; JobState State() const; status_t Result() const; + const BString& ErrorString() const; status_t AddStateListener(JobStateListener* listener); status_t RemoveStateListener( @@ -65,6 +67,8 @@ protected: virtual status_t Execute() = 0; virtual void Cleanup(status_t jobResult); + void SetErrorString(const BString&); + void NotifyStateListeners(); const Context& fContext; @@ -74,6 +78,7 @@ private: JobState fState; status_t fResult; + BString fErrorString; typedef BObjectList JobList; JobList fDependencies; diff --git a/headers/os/package/RefreshRepositoryRequest.h b/headers/os/package/RefreshRepositoryRequest.h new file mode 100644 index 0000000000..8ff4c16414 --- /dev/null +++ b/headers/os/package/RefreshRepositoryRequest.h @@ -0,0 +1,56 @@ +/* + * Copyright 2011, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _HAIKU__PACKAGE__REFRESH_REPOSITORY_REQUEST_H_ +#define _HAIKU__PACKAGE__REFRESH_REPOSITORY_REQUEST_H_ + + +#include +#include + +#include +#include +#include + + +namespace Haiku { + +namespace Package { + + +namespace Private { + class ValidateChecksumJob; +} +using Private::ValidateChecksumJob; + +class RefreshRepositoryRequest : public Request { + typedef Request inherited; + +public: + RefreshRepositoryRequest(const Context& context, + const RepositoryConfig& repoConfig); + virtual ~RefreshRepositoryRequest(); + + virtual status_t CreateInitialJobs(); + +protected: + // JobStateListener + virtual void JobSucceeded(Job* job); + +private: + status_t _FetchRepositoryCache(); + + BEntry fFetchedChecksumFile; + RepositoryConfig fRepoConfig; + + ValidateChecksumJob* fValidateChecksumJob; +}; + + +} // namespace Package + +} // namespace Haiku + + +#endif // _HAIKU__PACKAGE__REFRESH_REPOSITORY_REQUEST_H_ diff --git a/headers/os/package/RepositoryCache.h b/headers/os/package/RepositoryCache.h index 4525b8556b..f63a7d627a 100644 --- a/headers/os/package/RepositoryCache.h +++ b/headers/os/package/RepositoryCache.h @@ -2,23 +2,52 @@ * Copyright 2011, Haiku, Inc. * Distributed under the terms of the MIT License. */ -#ifndef _REPOSITORY_H_ -#define _REPOSITORY_H_ +#ifndef _HAIKU__PACKAGE__REPOSITORY_CACHE_H_ +#define _HAIKU__PACKAGE__REPOSITORY_CACHE_H_ -#include +#include +#include -class BMessage; +class BEntry; -class BRepository { +namespace Haiku { + +namespace Package { + + +//class RepositoryHeader; + + +class RepositoryCache { public: - BRepository(const char* url); + RepositoryCache(); + RepositoryCache(const BEntry& entry); + virtual ~RepositoryCache(); -public: - static BArchivable* Instantiate(BMessage* archive); + status_t SetTo(const BEntry& entry); + status_t InitCheck() const; + +// const RepositoryHeader* Header() const; + const BEntry& Entry() const; + bool IsUserSpecific() const; + + void SetIsUserSpecific(bool isUserSpecific); + +private: + status_t fInitStatus; + + BEntry fEntry; +// RepositoryHeader* fHeader; + bool fIsUserSpecific; }; -#endif // _REPOSITORY_H_ +} // namespace Package + +} // namespace Haiku + + +#endif // _HAIKU__PACKAGE__REPOSITORY_CACHE_H_ diff --git a/headers/os/package/RepositoryConfig.h b/headers/os/package/RepositoryConfig.h index 61525f8b5e..1ee3c2e732 100644 --- a/headers/os/package/RepositoryConfig.h +++ b/headers/os/package/RepositoryConfig.h @@ -7,6 +7,7 @@ #include +#include #include @@ -34,6 +35,8 @@ public: status_t StoreAsConfigFile(const BEntry& entry) const; + status_t SetTo(const BEntry& entry); + status_t SetTo(const BMessage* data); status_t InitCheck() const; const BString& Name() const; @@ -41,6 +44,8 @@ public: uint8 Priority() const; bool IsUserSpecific() const; + const BEntry& Entry() const; + void SetName(const BString& name); void SetURL(const BString& url); void SetPriority(uint8 priority); @@ -49,21 +54,20 @@ public: public: static RepositoryConfig* Instantiate(BMessage* data); - static const uint8 kDefaultPriority = 50; + static const uint8 kDefaultPriority; 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; + + BEntry fEntry; }; diff --git a/headers/os/package/Request.h b/headers/os/package/Request.h index 52aa0fbef7..8763feafb3 100644 --- a/headers/os/package/Request.h +++ b/headers/os/package/Request.h @@ -8,6 +8,8 @@ #include +#include + namespace Haiku { @@ -15,23 +17,25 @@ namespace Package { class Context; -class Job; -class JobQueue; +using Private::JobQueue; -class Request { +class Request : protected JobStateListener { public: Request(const Context& context); virtual ~Request(); - virtual status_t CreateJobsToRun(JobQueue& jobQueue) = 0; + virtual status_t CreateInitialJobs() = 0; - const Context& GetContext() const; + Job* PopRunnableJob(); protected: - status_t QueueJob(Job* job, JobQueue& jobQueue) const; -private: + status_t QueueJob(Job* job); + const Context& fContext; + +private: + JobQueue fJobQueue; }; diff --git a/headers/os/package/Roster.h b/headers/os/package/Roster.h index 004095c2e1..5834083598 100644 --- a/headers/os/package/Roster.h +++ b/headers/os/package/Roster.h @@ -7,10 +7,14 @@ #include +#include #include #include +template class BObjectList; + + namespace Haiku { namespace Package { @@ -25,22 +29,39 @@ struct RepositoryConfigVisitor { }; +class RepositoryCache; +class RepositoryConfig; + + class Roster { public: Roster(); ~Roster(); + status_t GetCommonRepositoryCachePath(BPath* path, + bool create = false) const; + status_t GetUserRepositoryCachePath(BPath* path, + bool create = false) const; + status_t GetCommonRepositoryConfigPath(BPath* path, bool create = false) const; status_t GetUserRepositoryConfigPath(BPath* path, bool create = false) const; + status_t GetRepositoryNames(BObjectList& names); + status_t VisitCommonRepositoryConfigs( RepositoryConfigVisitor& visitor); status_t VisitUserRepositoryConfigs( RepositoryConfigVisitor& visitor); + status_t GetRepositoryCache(const BString& name, + RepositoryCache* repositoryCache); + status_t GetRepositoryConfig(const BString& name, + RepositoryConfig* repositoryConfig); private: + status_t _GetRepositoryPath(BPath* path, bool create, + directory_which whichDir) const; status_t _VisitRepositoryConfigs(const BPath& path, RepositoryConfigVisitor& visitor); diff --git a/headers/private/package/ActivateRepositoryCacheJob.h b/headers/private/package/ActivateRepositoryCacheJob.h new file mode 100644 index 0000000000..78414af072 --- /dev/null +++ b/headers/private/package/ActivateRepositoryCacheJob.h @@ -0,0 +1,52 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ +#ifndef _HAIKU__PACKAGE__PRIVATE__ACTIVATE_REPOSITORY_CACHE_JOB_H_ +#define _HAIKU__PACKAGE__PRIVATE__ACTIVATE_REPOSITORY_CACHE_JOB_H_ + + +#include +#include +#include + +#include + + +namespace Haiku { + +namespace Package { + +namespace Private { + + +class ActivateRepositoryCacheJob : public Job { + typedef Job inherited; + +public: + ActivateRepositoryCacheJob( + const Context& context, + const BString& title, + const BEntry& fetchedRepoCacheEntry, + const BString& repositoryName, + const BDirectory& targetDirectory); + virtual ~ActivateRepositoryCacheJob(); + +protected: + virtual status_t Execute(); + +private: + BEntry fFetchedRepoCacheEntry; + BString fRepositoryName; + BDirectory fTargetDirectory; +}; + + +} // namespace Private + +} // namespace Package + +} // namespace Haiku + + +#endif // _HAIKU__PACKAGE__PRIVATE__ACTIVATE_REPOSITORY_CACHE_JOB_H_ diff --git a/headers/private/package/ActivateRepositoryConfigJob.h b/headers/private/package/ActivateRepositoryConfigJob.h index c11405e381..5aef02c091 100644 --- a/headers/private/package/ActivateRepositoryConfigJob.h +++ b/headers/private/package/ActivateRepositoryConfigJob.h @@ -1,9 +1,9 @@ /* - * Copyright 2011, Haiku, Inc. + * Copyright 2011, Oliver Tappe * Distributed under the terms of the MIT License. */ -#ifndef _HAIKU__PACKAGE__ACTIVATE_REPOSITORY_CONFIG_JOB_H_ -#define _HAIKU__PACKAGE__ACTIVATE_REPOSITORY_CONFIG_JOB_H_ +#ifndef _HAIKU__PACKAGE__PRIVATE__ACTIVATE_REPOSITORY_CONFIG_JOB_H_ +#define _HAIKU__PACKAGE__PRIVATE__ACTIVATE_REPOSITORY_CONFIG_JOB_H_ #include @@ -17,6 +17,8 @@ namespace Haiku { namespace Package { +namespace Private { + class ActivateRepositoryConfigJob : public Job { typedef Job inherited; @@ -26,23 +28,31 @@ public: const Context& context, const BString& title, const BEntry& archivedRepoConfigEntry, + const BString& repositoryBaseURL, const BDirectory& targetDirectory); virtual ~ActivateRepositoryConfigJob(); + const BString& RepositoryName() const; + protected: virtual status_t Execute(); virtual void Cleanup(status_t jobResult); private: BEntry fArchivedRepoConfigEntry; + BString fRepositoryBaseURL; BDirectory fTargetDirectory; BEntry fTargetEntry; + + BString fRepositoryName; }; +} // namespace Private + } // namespace Package } // namespace Haiku -#endif // _HAIKU__PACKAGE__ACTIVATE_REPOSITORY_CONFIG_JOB_H_ +#endif // _HAIKU__PACKAGE__PRIVATE__ACTIVATE_REPOSITORY_CONFIG_JOB_H_ diff --git a/headers/private/package/ChecksumAccessors.h b/headers/private/package/ChecksumAccessors.h new file mode 100644 index 0000000000..4555e55987 --- /dev/null +++ b/headers/private/package/ChecksumAccessors.h @@ -0,0 +1,61 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ +#ifndef _HAIKU__PACKAGE__PRIVATE__CHECKSUM_ACCESSORS_H_ +#define _HAIKU__PACKAGE__PRIVATE__CHECKSUM_ACCESSORS_H_ + + +#include +#include + + +namespace Haiku { + +namespace Package { + +namespace Private { + + +class ChecksumAccessor { +public: + virtual ~ChecksumAccessor(); + + virtual status_t GetChecksum(BString& checksum) const = 0; +}; + + +class ChecksumFileChecksumAccessor : public ChecksumAccessor { +public: + ChecksumFileChecksumAccessor( + const BEntry& checksumFileEntry); + + virtual status_t GetChecksum(BString& checksum) const; + +private: + BEntry fChecksumFileEntry; +}; + + +class GeneralFileChecksumAccessor : public ChecksumAccessor { +public: + GeneralFileChecksumAccessor( + const BEntry& fileEntry, + bool skipMissingFile = false); + + virtual status_t GetChecksum(BString& checksum) const; + +private: + BEntry fFileEntry; + bool fSkipMissingFile; +}; + + +} // namespace Private + +} // namespace Package + +} // namespace Haiku + + +#endif // _HAIKU__PACKAGE__PRIVATE__CHECKSUM_ACCESSORS_H_ diff --git a/headers/private/package/FetchFileJob.h b/headers/private/package/FetchFileJob.h index f9b38c2b8a..44e3248d19 100644 --- a/headers/private/package/FetchFileJob.h +++ b/headers/private/package/FetchFileJob.h @@ -1,9 +1,9 @@ /* - * Copyright 2011, Haiku, Inc. + * Copyright 2011, Oliver Tappe * Distributed under the terms of the MIT License. */ -#ifndef _HAIKU__PACKAGE__FETCH_FILE_JOB_H_ -#define _HAIKU__PACKAGE__FETCH_FILE_JOB_H_ +#ifndef _HAIKU__PACKAGE__PRIVATE__FETCH_FILE_JOB_H_ +#define _HAIKU__PACKAGE__PRIVATE__FETCH_FILE_JOB_H_ #include @@ -16,6 +16,8 @@ namespace Haiku { namespace Package { +namespace Private { + class FetchFileJob : public Job { typedef Job inherited; @@ -37,9 +39,11 @@ private: }; +} // namespace Private + } // namespace Package } // namespace Haiku -#endif // _HAIKU__PACKAGE__FETCH_FILE_JOB_H_ +#endif // _HAIKU__PACKAGE__PRIVATE__FETCH_FILE_JOB_H_ diff --git a/headers/os/package/JobQueue.h b/headers/private/package/JobQueue.h similarity index 94% rename from headers/os/package/JobQueue.h rename to headers/private/package/JobQueue.h index b0342c9812..37c8d06766 100644 --- a/headers/os/package/JobQueue.h +++ b/headers/private/package/JobQueue.h @@ -16,6 +16,8 @@ namespace Haiku { namespace Package { +namespace Private { + class JobQueue : public JobStateListener { public: @@ -43,6 +45,8 @@ private: }; +} // namespace Private + } // namespace Package } // namespace Haiku diff --git a/headers/os/package/TempEntryManager.h b/headers/private/package/TempfileManager.h similarity index 58% rename from headers/os/package/TempEntryManager.h rename to headers/private/package/TempfileManager.h index 0b530d0ffe..835a30fc79 100644 --- a/headers/os/package/TempEntryManager.h +++ b/headers/private/package/TempfileManager.h @@ -1,9 +1,9 @@ /* - * Copyright 2011, Haiku, Inc. + * Copyright 2011, Oliver Tappe * Distributed under the terms of the MIT License. */ -#ifndef _HAIKU__PACKAGE__TEMP_ENTRY_MANAGER_H_ -#define _HAIKU__PACKAGE__TEMP_ENTRY_MANAGER_H_ +#ifndef _HAIKU__PACKAGE__PRIVATE__TEMPFILE_MANAGER_H_ +#define _HAIKU__PACKAGE__PRIVATE__TEMPFILE_MANAGER_H_ #include @@ -16,11 +16,13 @@ namespace Haiku { namespace Package { +namespace Private { -class TempEntryManager { + +class TempfileManager { public: - TempEntryManager(); - ~TempEntryManager(); + TempfileManager(); + ~TempfileManager(); void SetBaseDirectory(const BDirectory& baseDir); @@ -35,9 +37,11 @@ private: }; +} // namespace Private + } // namespace Package } // namespace Haiku -#endif // _HAIKU__PACKAGE__TEMP_ENTRY_MANAGER_H_ +#endif // _HAIKU__PACKAGE__PRIVATE__TEMPFILE_MANAGER_H_ diff --git a/headers/private/package/ValidateChecksumJob.h b/headers/private/package/ValidateChecksumJob.h new file mode 100644 index 0000000000..aafd065b84 --- /dev/null +++ b/headers/private/package/ValidateChecksumJob.h @@ -0,0 +1,57 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ +#ifndef _HAIKU__PACKAGE__PRIVATE__VALIDATE_CHECKSUM_JOB_H_ +#define _HAIKU__PACKAGE__PRIVATE__VALIDATE_CHECKSUM_JOB_H_ + + +#include +#include +#include + +#include +#include + + +namespace Haiku { + +namespace Package { + +namespace Private { + + +class ValidateChecksumJob : public Job { + typedef Job inherited; + +public: + ValidateChecksumJob( + const Context& context, + const BString& title, + ChecksumAccessor* expectedChecksumAccessor, + ChecksumAccessor* realChecksumAccessor, + bool failIfChecksumsDontMatch = true); + virtual ~ValidateChecksumJob(); + + bool ChecksumsMatch() const; + +protected: + virtual status_t Execute(); + +private: + ChecksumAccessor* fExpectedChecksumAccessor; + ChecksumAccessor* fRealChecksumAccessor; + bool fFailIfChecksumsDontMatch; + + bool fChecksumsMatch; +}; + + +} // namespace Private + +} // namespace Package + +} // namespace Haiku + + +#endif // _HAIKU__PACKAGE__PRIVATE__VALIDATE_CHECKSUM_JOB_H_ diff --git a/src/bin/pkgman/Jamfile b/src/bin/pkgman/Jamfile index 74791bbc9b..ee20e6d4a6 100644 --- a/src/bin/pkgman/Jamfile +++ b/src/bin/pkgman/Jamfile @@ -1,10 +1,11 @@ SubDir HAIKU_TOP src bin pkgman ; -UsePrivateHeaders shared support ; +UsePrivateHeaders support ; BinCommand pkgman : command_add_repo.cpp command_list_repos.cpp + command_refresh.cpp MyDecisionProvider.cpp MyJobStateListener.cpp pkgman.cpp diff --git a/src/bin/pkgman/MyJobStateListener.cpp b/src/bin/pkgman/MyJobStateListener.cpp index 1b9c925841..d62b2bb497 100644 --- a/src/bin/pkgman/MyJobStateListener.cpp +++ b/src/bin/pkgman/MyJobStateListener.cpp @@ -29,6 +29,11 @@ MyJobStateListener::JobSucceeded(Job* job) void MyJobStateListener::JobFailed(Job* job) { + BString error = job->ErrorString(); + if (error.Length() > 0) { + error.ReplaceAll("\n", "\n*** "); + fprintf(stderr, "%s", error.String()); + } DIE(job->Result(), "failed!"); } diff --git a/src/bin/pkgman/command_add_repo.cpp b/src/bin/pkgman/command_add_repo.cpp index 0c9c871ac1..7e2c2662d0 100644 --- a/src/bin/pkgman/command_add_repo.cpp +++ b/src/bin/pkgman/command_add_repo.cpp @@ -13,7 +13,8 @@ #include #include -#include +#include +#include #include "MyDecisionProvider.h" #include "MyJobStateListener.h" @@ -87,17 +88,32 @@ command_add_repo(int argc, const char* const* argv) status_t result; for (int i = 0; i < urlCount; ++i) { - AddRepositoryRequest request(context, repoURLs[i], asUserRepository); - JobQueue jobQueue; - result = request.CreateJobsToRun(jobQueue); + AddRepositoryRequest addRequest(context, repoURLs[i], asUserRepository); + result = addRequest.CreateInitialJobs(); if (result != B_OK) DIE(result, "unable to create necessary jobs"); - while (Job* job = jobQueue.Pop()) { + while (Job* job = addRequest.PopRunnableJob()) { result = job->Run(); delete job; if (result == B_CANCELED) - break; + return 1; + } + + BString repoName = addRequest.RepositoryName(); + Roster roster; + RepositoryConfig repoConfig; + roster.GetRepositoryConfig(repoName, &repoConfig); + RefreshRepositoryRequest refreshRequest(context, repoConfig); + result = refreshRequest.CreateInitialJobs(); + if (result != B_OK) + DIE(result, "unable to create necessary jobs"); + + while (Job* job = refreshRequest.PopRunnableJob()) { + result = job->Run(); + delete job; + if (result == B_CANCELED) + return 1; } } diff --git a/src/bin/pkgman/command_list_repos.cpp b/src/bin/pkgman/command_list_repos.cpp index 71ba4a37ce..f1af938fbb 100644 --- a/src/bin/pkgman/command_list_repos.cpp +++ b/src/bin/pkgman/command_list_repos.cpp @@ -43,48 +43,6 @@ print_command_usage_and_exit(bool error) } -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) { @@ -121,24 +79,25 @@ command_list_repos(int argc, const char* const* argv) if (argc != optind) print_command_usage_and_exit(true); + BObjectList repositoryNames(20, 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"); + status_t result = roster.GetRepositoryNames(repositoryNames); + if (result != B_OK) + DIE(result, "can't collect repository names"); - 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); + for (int i = 0; i < repositoryNames.CountItems(); ++i) { + const BString& repoName = *(repositoryNames.ItemAt(i)); + RepositoryConfig repoConfig; + result = roster.GetRepositoryConfig(repoName, &repoConfig); + if (result != B_OK) { + BPath path; + repoConfig.Entry().GetPath(&path); + WARN(result, "skipping repository-config '%s'", path.Path()); + continue; + } printf(" %s %s\n", - repoConfig->IsUserSpecific() ? "[User]" : " ", - repoConfig->Name().String()); + repoConfig.IsUserSpecific() ? "[User]" : " ", + repoConfig.Name().String()); } return 0; diff --git a/src/bin/pkgman/command_refresh.cpp b/src/bin/pkgman/command_refresh.cpp new file mode 100644 index 0000000000..30e1cfa5d8 --- /dev/null +++ b/src/bin/pkgman/command_refresh.cpp @@ -0,0 +1,119 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ + + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "MyDecisionProvider.h" +#include "MyJobStateListener.h" +#include "pkgman.h" + + +using namespace Haiku::Package; + + +// TODO: internationalization! + + +static const char* kCommandUsage = + "Usage: %s refresh [ ...]\n" + "Refreshes all or just the given repositories.\n" + "\n" +; + + +static void +print_command_usage_and_exit(bool error) +{ + fprintf(error ? stderr : stdout, kCommandUsage, kProgramName); + exit(error ? 1 : 0); +} + + +int +command_refresh(int argc, const char* const* argv) +{ + while (true) { + static struct option sLongOptions[] = { + { "help", no_argument, 0, 'h' }, + { 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; + + default: + print_command_usage_and_exit(true); + break; + } + } + + // The remaining arguments are repo names. + const char* const* repoArgs = argv + optind; + int nameCount = argc - optind; + + MyDecisionProvider decisionProvider; + Context context(decisionProvider); + MyJobStateListener listener; + context.SetJobStateListener(&listener); + + BObjectList repositoryNames(20, true); + + Roster roster; + if (nameCount == 0) { + status_t result = roster.GetRepositoryNames(repositoryNames); + if (result != B_OK) + DIE(result, "can't collect repository names"); + } else { + for (int i = 0; i < nameCount; ++i) { + BString* repoName = new (std::nothrow) BString(repoArgs[i]); + if (repoName == NULL) + DIE(B_NO_MEMORY, "can't allocate repository name"); + repositoryNames.AddItem(repoName); + } + } + + status_t result; + for (int i = 0; i < repositoryNames.CountItems(); ++i) { + const BString& repoName = *(repositoryNames.ItemAt(i)); + RepositoryConfig repoConfig; + result = roster.GetRepositoryConfig(repoName, &repoConfig); + if (result != B_OK) { + BPath path; + repoConfig.Entry().GetPath(&path); + WARN(result, "skipping repository-config '%s'", path.Path()); + continue; + } + RefreshRepositoryRequest refreshRequest(context, repoConfig); + result = refreshRequest.CreateInitialJobs(); + if (result != B_OK) + DIE(result, "unable to create necessary jobs"); + + while (Job* job = refreshRequest.PopRunnableJob()) { + result = job->Run(); + delete job; + if (result != B_OK) + return 1; + } + } + + return 0; +} diff --git a/src/bin/pkgman/pkgman.cpp b/src/bin/pkgman/pkgman.cpp index 55a6acb939..9d927f7d80 100644 --- a/src/bin/pkgman/pkgman.cpp +++ b/src/bin/pkgman/pkgman.cpp @@ -24,11 +24,14 @@ static const char* kUsage = " add-repo \n" " Adds the repository with the given .\n" "\n" + " drop-repo \n" + " Drops 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" + " refresh [ ...]\n" + " Refreshes all or just the given repositories.\n" "\n" "Common Options:\n" " -h, --help - Print this usage info.\n" @@ -50,15 +53,18 @@ main(int argc, const char* const* argv) print_usage_and_exit(true); const char* command = argv[1]; - if (strcmp(command, "add-repo") == 0) + if (strcmp(command, "add-repo") == 0 || strcmp(command, "ar") == 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) + if (strcmp(command, "list-repos") == 0 || strcmp(command, "lr") == 0) return command_list_repos(argc - 1, argv + 1); + if (strcmp(command, "refresh") == 0) + return command_refresh(argc - 1, argv + 1); + // if (strcmp(command, "search") == 0) // return command_search(argc - 1, argv + 1); diff --git a/src/bin/pkgman/pkgman.h b/src/bin/pkgman/pkgman.h index 1c95643413..c5641d2586 100644 --- a/src/bin/pkgman/pkgman.h +++ b/src/bin/pkgman/pkgman.h @@ -38,6 +38,7 @@ 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); +int command_refresh(int argc, const char* const* argv); #endif // PKGMAN_H diff --git a/src/kits/package/ActivateRepositoryCacheJob.cpp b/src/kits/package/ActivateRepositoryCacheJob.cpp new file mode 100644 index 0000000000..ab13cf4671 --- /dev/null +++ b/src/kits/package/ActivateRepositoryCacheJob.cpp @@ -0,0 +1,59 @@ +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Oliver Tappe + */ + + +#include + +#include + +#include + + +namespace Haiku { + +namespace Package { + +namespace Private { + + +ActivateRepositoryCacheJob::ActivateRepositoryCacheJob(const Context& context, + const BString& title, const BEntry& fetchedRepoCacheEntry, + const BString& repositoryName, const BDirectory& targetDirectory) + : + inherited(context, title), + fFetchedRepoCacheEntry(fetchedRepoCacheEntry), + fRepositoryName(repositoryName), + fTargetDirectory(targetDirectory) +{ +} + + +ActivateRepositoryCacheJob::~ActivateRepositoryCacheJob() +{ +} + + +status_t +ActivateRepositoryCacheJob::Execute() +{ + status_t result = fFetchedRepoCacheEntry.MoveTo(&fTargetDirectory, + fRepositoryName.String(), true); + if (result != B_OK) + return result; + + // TODO: propagate some repository attributes to file attributes + + return B_OK; +} + + +} // namespace Private + +} // namespace Package + +} // namespace Haiku diff --git a/src/kits/package/ActivateRepositoryConfigJob.cpp b/src/kits/package/ActivateRepositoryConfigJob.cpp index 274fb6b12e..322e405ceb 100644 --- a/src/kits/package/ActivateRepositoryConfigJob.cpp +++ b/src/kits/package/ActivateRepositoryConfigJob.cpp @@ -9,8 +9,6 @@ #include -#include - #include #include @@ -21,13 +19,16 @@ namespace Haiku { namespace Package { +namespace Private { + ActivateRepositoryConfigJob::ActivateRepositoryConfigJob(const Context& context, const BString& title, const BEntry& archivedRepoConfigEntry, - const BDirectory& targetDirectory) + const BString& repositoryBaseURL, const BDirectory& targetDirectory) : inherited(context, title), fArchivedRepoConfigEntry(archivedRepoConfigEntry), + fRepositoryBaseURL(repositoryBaseURL), fTargetDirectory(targetDirectory) { } @@ -69,9 +70,14 @@ ActivateRepositoryConfigJob::Execute() } } + // inject the URL that was actually used and write the config file + repoConfig->SetURL(fRepositoryBaseURL); if ((result = repoConfig->StoreAsConfigFile(fTargetEntry)) != B_OK) return result; + // store name of activated repository as result + fRepositoryName = repoConfig->Name(); + return B_OK; } @@ -85,6 +91,15 @@ ActivateRepositoryConfigJob::Cleanup(status_t jobResult) } +const BString& +ActivateRepositoryConfigJob::RepositoryName() const +{ + return fRepositoryName; +} + + +} // namespace Private + } // namespace Package } // namespace Haiku diff --git a/src/kits/package/AddRepositoryRequest.cpp b/src/kits/package/AddRepositoryRequest.cpp index 4da28a393f..eea51048b5 100644 --- a/src/kits/package/AddRepositoryRequest.cpp +++ b/src/kits/package/AddRepositoryRequest.cpp @@ -23,12 +23,16 @@ namespace Haiku { namespace Package { +using namespace Private; + + AddRepositoryRequest::AddRepositoryRequest(const Context& context, - const BString& repositoryURL, bool asUserRepository) + const BString& repositoryBaseURL, bool asUserRepository) : inherited(context), - fRepositoryURL(repositoryURL), - fAsUserRepository(asUserRepository) + fRepositoryBaseURL(repositoryBaseURL), + fAsUserRepository(asUserRepository), + fActivateJob(NULL) { } @@ -39,16 +43,16 @@ AddRepositoryRequest::~AddRepositoryRequest() status_t -AddRepositoryRequest::CreateJobsToRun(JobQueue& jobQueue) +AddRepositoryRequest::CreateInitialJobs() { - BEntry tempEntry - = GetContext().GetTempEntryManager().Create("repoconfig-"); - FetchFileJob* fetchJob = new (std::nothrow) FetchFileJob(GetContext(), - BString("Fetching repository-config from ") << fRepositoryURL, - fRepositoryURL, tempEntry); + BEntry tempEntry = fContext.GetTempfileManager().Create("repoheader-"); + BString repoHeaderURL = BString(fRepositoryBaseURL) << "/" << "repo.header"; + FetchFileJob* fetchJob = new (std::nothrow) FetchFileJob(fContext, + BString("Fetching repository header from ") << fRepositoryBaseURL, + repoHeaderURL, tempEntry); if (fetchJob == NULL) return B_NO_MEMORY; - status_t result = QueueJob(fetchJob, jobQueue); + status_t result = QueueJob(fetchJob); if (result != B_OK) { delete fetchJob; return result; @@ -63,21 +67,37 @@ AddRepositoryRequest::CreateJobsToRun(JobQueue& jobQueue) return result; BDirectory targetDirectory(targetRepoConfigPath.Path()); ActivateRepositoryConfigJob* activateJob - = new (std::nothrow) ActivateRepositoryConfigJob(GetContext(), - BString("Activating repository-config from ") << fRepositoryURL, - tempEntry, targetDirectory); + = new (std::nothrow) ActivateRepositoryConfigJob(fContext, + BString("Activating repository config from ") << fRepositoryBaseURL, + tempEntry, fRepositoryBaseURL, targetDirectory); if (activateJob == NULL) return B_NO_MEMORY; activateJob->AddDependency(fetchJob); - if ((result = QueueJob(activateJob, jobQueue)) != B_OK) { + if ((result = QueueJob(activateJob)) != B_OK) { delete activateJob; return result; } + fActivateJob = activateJob; return B_OK; } +void +AddRepositoryRequest::JobSucceeded(Job* job) +{ + if (job == fActivateJob) + fRepositoryName = fActivateJob->RepositoryName(); +} + + +const BString& +AddRepositoryRequest::RepositoryName() const +{ + return fRepositoryName; +} + + } // namespace Package } // namespace Haiku diff --git a/src/kits/package/Attributes.cpp b/src/kits/package/Attributes.cpp new file mode 100644 index 0000000000..02ee18dc57 --- /dev/null +++ b/src/kits/package/Attributes.cpp @@ -0,0 +1,33 @@ +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Oliver Tappe + */ + + +#include + + +namespace Haiku { + +namespace Package { + + +// attributes used in package and as file attribute, too +const char* kNameAttribute = "PKG:name"; +const char* kPlatformAttribute = "PKG:platform"; +const char* kVendorAttribute = "PKG:vendor"; +const char* kVersionAttribute = "PKG:version"; + +// attributes kept local to packages +const char* kCopyrightAttribute = "PKG:copyright"; +const char* kLicenseAttribute = "PKG:license"; +const char* kProvidesAttribute = "PKG:provides"; +const char* kRequiresAttribute = "PKG:requires"; + + +} // namespace Package + +} // namespace Haiku diff --git a/src/kits/package/ChecksumAccessors.cpp b/src/kits/package/ChecksumAccessors.cpp new file mode 100644 index 0000000000..6abc6e3c30 --- /dev/null +++ b/src/kits/package/ChecksumAccessors.cpp @@ -0,0 +1,136 @@ +/* + * 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 { + +namespace Private { + + +#define NIBBLE_AS_HEX(nibble) \ + (nibble >= 10 ? 'a' + nibble - 10 : '0' + nibble) + + +ChecksumAccessor::~ChecksumAccessor() +{ +} + + +ChecksumFileChecksumAccessor::ChecksumFileChecksumAccessor( + const BEntry& checksumFileEntry) + : + fChecksumFileEntry(checksumFileEntry) +{ +} + + +status_t +ChecksumFileChecksumAccessor::GetChecksum(BString& checksum) const +{ + BFile checksumFile(&fChecksumFileEntry, B_READ_ONLY); + status_t result = checksumFile.InitCheck(); + if (result != B_OK) + return result; + + const int kSHA256ChecksumHexDumpSize = 64; + char* buffer = checksum.LockBuffer(kSHA256ChecksumHexDumpSize); + if (buffer == NULL) + return B_NO_MEMORY; + + ssize_t bytesRead = checksumFile.Read(buffer, kSHA256ChecksumHexDumpSize); + buffer[kSHA256ChecksumHexDumpSize] = '\0'; + checksum.UnlockBuffer(kSHA256ChecksumHexDumpSize); + if (bytesRead < 0) + return bytesRead; + if (bytesRead != kSHA256ChecksumHexDumpSize) + return B_IO_ERROR; + + return B_OK; +} + + +GeneralFileChecksumAccessor::GeneralFileChecksumAccessor( + const BEntry& fileEntry, bool skipMissingFile) + : + fFileEntry(fileEntry), + fSkipMissingFile(skipMissingFile) +{ +} + + +status_t +GeneralFileChecksumAccessor::GetChecksum(BString& checksum) const +{ + SHA256 sha; + + checksum.Truncate(0); + + { + BFile file(&fFileEntry, B_READ_ONLY); + status_t result = file.InitCheck(); + if (result != B_OK) { + if (result == B_ENTRY_NOT_FOUND && fSkipMissingFile) + return B_OK; + return result; + } + + off_t fileSize; + if ((result = file.GetSize(&fileSize)) != B_OK) + return result; + + const int kBlockSize = 64 * 1024; + void* buffer = malloc(kBlockSize); + if (buffer == NULL) + return B_NO_MEMORY; + MemoryDeleter memoryDeleter(buffer); + + off_t handledSize = 0; + while (handledSize < fileSize) { + ssize_t bytesRead = file.Read(buffer, kBlockSize); + if (bytesRead < 0) + return bytesRead; + + sha.Update(buffer, bytesRead); + + handledSize += bytesRead; + } + } + + const int kSHA256ChecksumSize = sha.DigestLength(); + char* buffer = checksum.LockBuffer(2 * kSHA256ChecksumSize); + if (buffer == NULL) + return B_NO_MEMORY; + const uint8* digest = sha.Digest(); + for (int i = 0; i < kSHA256ChecksumSize; ++i) { + uint8 highNibble = (digest[i] & 0xF0) >> 4; + buffer[i * 2] = NIBBLE_AS_HEX(highNibble); + uint8 lowNibble = digest[i] & 0x0F; + buffer[1 + i * 2] = NIBBLE_AS_HEX(lowNibble); + } + buffer[2 * kSHA256ChecksumSize] = '\0'; + checksum.UnlockBuffer(2 * kSHA256ChecksumSize); + + return B_OK; +} + + +} // namespace Private + +} // namespace Package + +} // namespace Haiku diff --git a/src/kits/package/Context.cpp b/src/kits/package/Context.cpp index c04400baa2..792b5ef25e 100644 --- a/src/kits/package/Context.cpp +++ b/src/kits/package/Context.cpp @@ -38,7 +38,7 @@ Context::Context(DecisionProvider& decisionProvider) BString contextName = BString("pkgkit-context-") << find_thread(NULL); BDirectory baseDirectory; tempDirectory.CreateDirectory(contextName.String(), &baseDirectory); - fTempEntryManager.SetBaseDirectory(baseDirectory); + fTempfileManager.SetBaseDirectory(baseDirectory); } @@ -47,10 +47,10 @@ Context::~Context() } -TempEntryManager& -Context::GetTempEntryManager() const +TempfileManager& +Context::GetTempfileManager() const { - return fTempEntryManager; + return fTempfileManager; } diff --git a/src/kits/package/FetchFileJob.cpp b/src/kits/package/FetchFileJob.cpp index e60b64855b..b79c465ab6 100644 --- a/src/kits/package/FetchFileJob.cpp +++ b/src/kits/package/FetchFileJob.cpp @@ -19,6 +19,8 @@ namespace Haiku { namespace Package { +namespace Private { + FetchFileJob::FetchFileJob(const Context& context, const BString& title, const BString& fileURL, const BEntry& targetEntry) @@ -65,6 +67,8 @@ FetchFileJob::Cleanup(status_t jobResult) } +} // namespace Private + } // namespace Package } // namespace Haiku diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile index 5b5ff4c09e..4e3243c848 100644 --- a/src/kits/package/Jamfile +++ b/src/kits/package/Jamfile @@ -1,19 +1,26 @@ SubDir HAIKU_TOP src kits package ; -UsePrivateHeaders package ; +UsePrivateHeaders package shared ; SharedLibrary libpackage.so : + ActivateRepositoryCacheJob.cpp ActivateRepositoryConfigJob.cpp AddRepositoryRequest.cpp + Attributes.cpp + ChecksumAccessors.cpp Context.cpp FetchFileJob.cpp Job.cpp JobQueue.cpp + RefreshRepositoryRequest.cpp + RepositoryCache.cpp RepositoryConfig.cpp +# RepositoryHeader.cpp Request.cpp Roster.cpp - TempEntryManager.cpp + TempfileManager.cpp + ValidateChecksumJob.cpp : - be $(TARGET_LIBSTDC++) + libshared.a be $(TARGET_LIBSTDC++) ; diff --git a/src/kits/package/Job.cpp b/src/kits/package/Job.cpp index 02a7f99187..eb03f0c667 100644 --- a/src/kits/package/Job.cpp +++ b/src/kits/package/Job.cpp @@ -94,6 +94,20 @@ Job::Result() const } +const BString& +Job::ErrorString() const +{ + return fErrorString; +} + + +void +Job::SetErrorString(const BString& error) +{ + fErrorString = error; +} + + status_t Job::Run() { diff --git a/src/kits/package/JobQueue.cpp b/src/kits/package/JobQueue.cpp index 7f0f378db0..687ce5da26 100644 --- a/src/kits/package/JobQueue.cpp +++ b/src/kits/package/JobQueue.cpp @@ -20,6 +20,8 @@ namespace Haiku { namespace Package { +namespace Private { + struct JobQueue::JobPriorityLess { bool operator()(const Job* left, const Job* right) const; @@ -150,6 +152,8 @@ JobQueue::_UpdateDependantJobsOf(Job* job) } +} // namespace Private + } // namespace Package } // namespace Haiku diff --git a/src/kits/package/RefreshRepositoryRequest.cpp b/src/kits/package/RefreshRepositoryRequest.cpp new file mode 100644 index 0000000000..bf09d4b8bd --- /dev/null +++ b/src/kits/package/RefreshRepositoryRequest.cpp @@ -0,0 +1,171 @@ +/* + * 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 +#include +#include + + +namespace Haiku { + +namespace Package { + + +using namespace Private; + + +RefreshRepositoryRequest::RefreshRepositoryRequest(const Context& context, + const RepositoryConfig& repoConfig) + : + inherited(context), + fRepoConfig(repoConfig) +{ +} + + +RefreshRepositoryRequest::~RefreshRepositoryRequest() +{ +} + + +status_t +RefreshRepositoryRequest::CreateInitialJobs() +{ + Roster roster; + status_t result = fRepoConfig.InitCheck(); + if (result != B_OK) + return result; + + // fetch the current checksum and compare with our cache's checksum, + // if they differ, fetch the updated cache + fFetchedChecksumFile + = fContext.GetTempfileManager().Create("repochecksum-"); + BString repoChecksumURL + = BString(fRepoConfig.URL()) << "/" << "repo.sha256"; + FetchFileJob* fetchChecksumJob = new (std::nothrow) FetchFileJob( + fContext, + BString("Fetching repository checksum from ") << fRepoConfig.URL(), + repoChecksumURL, fFetchedChecksumFile); + if (fetchChecksumJob == NULL) + return B_NO_MEMORY; + if ((result = QueueJob(fetchChecksumJob)) != B_OK) { + delete fetchChecksumJob; + return result; + } + + RepositoryCache repoCache; + roster.GetRepositoryCache(fRepoConfig.Name(), &repoCache); + + ValidateChecksumJob* validateChecksumJob + = new (std::nothrow) ValidateChecksumJob(fContext, + BString("Validating checksum for ") << fRepoConfig.Name(), + new (std::nothrow) ChecksumFileChecksumAccessor( + fFetchedChecksumFile), + new (std::nothrow) GeneralFileChecksumAccessor(repoCache.Entry(), + true), + false); + if (validateChecksumJob == NULL) + return B_NO_MEMORY; + validateChecksumJob->AddDependency(fetchChecksumJob); + if ((result = QueueJob(validateChecksumJob)) != B_OK) { + delete validateChecksumJob; + return result; + } + fValidateChecksumJob = validateChecksumJob; + + return B_OK; +} + + +void +RefreshRepositoryRequest::JobSucceeded(Job* job) +{ + if (job == fValidateChecksumJob + && !fValidateChecksumJob->ChecksumsMatch()) { + // the remote repo cache has a different checksum, we fetch it + fValidateChecksumJob = NULL; + // don't re-trigger fetching if anything goes wrong, fail instead + _FetchRepositoryCache(); + } +} + + +status_t +RefreshRepositoryRequest::_FetchRepositoryCache() +{ + // download repository cache and put it in either the common/user cache + // path, depending on where the corresponding repo-config lives + + // job fetching the cache + BEntry tempRepoCache = fContext.GetTempfileManager().Create("repocache-"); + BString repoCacheURL = BString(fRepoConfig.URL()) << "/" << "repo"; + FetchFileJob* fetchCacheJob = new (std::nothrow) FetchFileJob(fContext, + BString("Fetching repository-cache from ") << fRepoConfig.URL(), + repoCacheURL, tempRepoCache); + if (fetchCacheJob == NULL) + return B_NO_MEMORY; + status_t result = QueueJob(fetchCacheJob); + if (result != B_OK) { + delete fetchCacheJob; + return result; + } + + // job validating the cache's checksum + ValidateChecksumJob* validateChecksumJob + = new (std::nothrow) ValidateChecksumJob(fContext, + BString("Validating checksum for ") << fRepoConfig.Name(), + new (std::nothrow) ChecksumFileChecksumAccessor( + fFetchedChecksumFile), + new (std::nothrow) GeneralFileChecksumAccessor(tempRepoCache)); + if (validateChecksumJob == NULL) + return B_NO_MEMORY; + validateChecksumJob->AddDependency(fetchCacheJob); + if ((result = QueueJob(validateChecksumJob)) != B_OK) { + delete validateChecksumJob; + return result; + } + + // job activating the cache + BPath targetRepoCachePath; + Roster roster; + result = fRepoConfig.IsUserSpecific() + ? roster.GetUserRepositoryCachePath(&targetRepoCachePath, true) + : roster.GetCommonRepositoryCachePath(&targetRepoCachePath, true); + if (result != B_OK) + return result; + BDirectory targetDirectory(targetRepoCachePath.Path()); + ActivateRepositoryCacheJob* activateJob + = new (std::nothrow) ActivateRepositoryCacheJob(fContext, + BString("Activating repository cache for ") << fRepoConfig.Name(), + tempRepoCache, fRepoConfig.Name(), targetDirectory); + if (activateJob == NULL) + return B_NO_MEMORY; + activateJob->AddDependency(validateChecksumJob); + if ((result = QueueJob(activateJob)) != B_OK) { + delete activateJob; + return result; + } + + return B_OK; +} + + +} // namespace Package + +} // namespace Haiku diff --git a/src/kits/package/RepositoryCache.cpp b/src/kits/package/RepositoryCache.cpp new file mode 100644 index 0000000000..ce1bf475c9 --- /dev/null +++ b/src/kits/package/RepositoryCache.cpp @@ -0,0 +1,106 @@ +/* + * 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 { + + +RepositoryCache::RepositoryCache() + : + fInitStatus(B_NO_INIT), + fIsUserSpecific(false) +{ +} + + +RepositoryCache::RepositoryCache(const BEntry& entry) +{ + SetTo(entry); +} + + +RepositoryCache::~RepositoryCache() +{ +} + + +status_t +RepositoryCache::InitCheck() const +{ + return fInitStatus; +} + + +const BEntry& +RepositoryCache::Entry() const +{ + return fEntry; +} + + +bool +RepositoryCache::IsUserSpecific() const +{ + return fIsUserSpecific; +} + + +void +RepositoryCache::SetIsUserSpecific(bool isUserSpecific) +{ + fIsUserSpecific = isUserSpecific; +} + + +status_t +RepositoryCache::SetTo(const BEntry& entry) +{ + fEntry = entry; + fInitStatus = B_NO_INIT; + + BFile file(&entry, B_READ_ONLY); + status_t result = file.InitCheck(); + if (result != B_OK) + return result; + + BMessage headerMsg; + if ((result = headerMsg.Unflatten(&file)) != B_OK) + return result; + + // TODO: unarchive header and read packages + + BPath userSettingsPath; + if (find_directory(B_USER_SETTINGS_DIRECTORY, &userSettingsPath) == B_OK) { + BDirectory userSettingsDir(userSettingsPath.Path()); + fIsUserSpecific = userSettingsDir.Contains(&entry); + } else + fIsUserSpecific = false; + + fInitStatus = B_OK; + + return B_OK; +} + + +} // namespace Package + +} // namespace Haiku diff --git a/src/kits/package/RepositoryConfig.cpp b/src/kits/package/RepositoryConfig.cpp index 73abb6cdc9..0271aca988 100644 --- a/src/kits/package/RepositoryConfig.cpp +++ b/src/kits/package/RepositoryConfig.cpp @@ -15,7 +15,6 @@ #include #include -#include #include #include #include @@ -26,6 +25,7 @@ namespace Haiku { namespace Package { +const uint8 RepositoryConfig::kDefaultPriority = 50; const char* RepositoryConfig::kNameField = "name"; const char* RepositoryConfig::kURLField = "url"; const char* RepositoryConfig::kPriorityField = "priority"; @@ -42,7 +42,7 @@ RepositoryConfig::RepositoryConfig() RepositoryConfig::RepositoryConfig(const BEntry& entry) { - fInitStatus = _InitFrom(entry); + SetTo(entry); } @@ -50,7 +50,7 @@ RepositoryConfig::RepositoryConfig(BMessage* data) : inherited(data) { - fInitStatus = _InitFrom(data); + SetTo(data); } @@ -109,7 +109,6 @@ RepositoryConfig::StoreAsConfigFile(const BEntry& entry) const BString configString; configString - << "name=" << fName << "\n" << "url=" << fURL << "\n" << "priority=" << fPriority << "\n"; @@ -128,6 +127,91 @@ RepositoryConfig::InitCheck() const } +status_t +RepositoryConfig::SetTo(const BEntry& entry) +{ + fEntry = entry; + fInitStatus = B_NO_INIT; + + 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_IO_ERROR : result; + + buffer[size] = '\0'; + configString.UnlockBuffer(size); + + void* settingsHandle = parse_driver_settings_string(configString.String()); + if (settingsHandle == NULL) + return B_BAD_DATA; + + 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 (url == NULL || *url == '\0') + return B_BAD_DATA; + + char name[B_FILE_NAME_LENGTH]; + if ((result = entry.GetName(name)) != B_OK) + return result; + + 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; + + fInitStatus = B_OK; + + return B_OK; +} + + +status_t +RepositoryConfig::SetTo(const BMessage* data) +{ + fInitStatus = B_NO_INIT; + + 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; + + fInitStatus = B_OK; + + return B_OK; +} + + const BString& RepositoryConfig::Name() const { @@ -156,6 +240,13 @@ RepositoryConfig::IsUserSpecific() const } +const BEntry& +RepositoryConfig::Entry() const +{ + return fEntry; +} + + void RepositoryConfig::SetName(const BString& name) { @@ -184,78 +275,6 @@ RepositoryConfig::SetIsUserSpecific(bool 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 index c9dbf8b46a..eb4f1a6a6d 100644 --- a/src/kits/package/Request.cpp +++ b/src/kits/package/Request.cpp @@ -11,7 +11,6 @@ #include #include -#include namespace Haiku { @@ -21,7 +20,8 @@ namespace Package { Request::Request(const Context& context) : - fContext(context) + fContext(context), + fJobQueue() { } @@ -31,21 +31,23 @@ Request::~Request() } -const Context& -Request::GetContext() const +Job* +Request::PopRunnableJob() { - return fContext; + return fJobQueue.Pop(); } status_t -Request::QueueJob(Job* job, JobQueue& jobQueue) const +Request::QueueJob(Job* job) { + job->AddStateListener(this); + JobStateListener* listener = fContext.GetJobStateListener(); if (listener != NULL) job->AddStateListener(listener); - return jobQueue.AddJob(job); + return fJobQueue.AddJob(job); } diff --git a/src/kits/package/Roster.cpp b/src/kits/package/Roster.cpp index 7a77397079..4b63f934e6 100644 --- a/src/kits/package/Roster.cpp +++ b/src/kits/package/Roster.cpp @@ -14,8 +14,12 @@ #include #include +#include #include -#include +#include + +#include +#include namespace Haiku { @@ -36,48 +40,28 @@ 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; + return _GetRepositoryPath(path, create, B_COMMON_SETTINGS_DIRECTORY); } status_t Roster::GetUserRepositoryConfigPath(BPath* path, bool create) const { - if (path == NULL) - return B_BAD_VALUE; + return _GetRepositoryPath(path, create, B_USER_SETTINGS_DIRECTORY); +} - 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; - } - } +status_t +Roster::GetCommonRepositoryCachePath(BPath* path, bool create) const +{ + return _GetRepositoryPath(path, create, B_COMMON_CACHE_DIRECTORY); +} - return B_OK; + +status_t +Roster::GetUserRepositoryCachePath(BPath* path, bool create) const +{ + return _GetRepositoryPath(path, create, B_USER_CACHE_DIRECTORY); } @@ -87,10 +71,10 @@ Roster::VisitCommonRepositoryConfigs(RepositoryConfigVisitor& visitor) BPath commonRepositoryConfigPath; status_t result = GetCommonRepositoryConfigPath(&commonRepositoryConfigPath); - if (result == B_OK) - result = _VisitRepositoryConfigs(commonRepositoryConfigPath, visitor); + if (result != B_OK) + return result; - return result; + return _VisitRepositoryConfigs(commonRepositoryConfigPath, visitor); } @@ -99,10 +83,122 @@ Roster::VisitUserRepositoryConfigs(RepositoryConfigVisitor& visitor) { BPath userRepositoryConfigPath; status_t result = GetUserRepositoryConfigPath(&userRepositoryConfigPath); - if (result == B_OK) - result = _VisitRepositoryConfigs(userRepositoryConfigPath, visitor); + if (result != B_OK) + return result; - return result; + return _VisitRepositoryConfigs(userRepositoryConfigPath, visitor); +} + + +status_t +Roster::GetRepositoryNames(BObjectList& names) +{ + struct RepositoryNameCollector : public RepositoryConfigVisitor { + RepositoryNameCollector(BObjectList& _names) + : names(_names) + { + } + status_t operator()(const BEntry& entry) + { + char name[B_FILE_NAME_LENGTH]; + status_t result = entry.GetName(name); + if (result != B_OK) + return result; + int32 count = names.CountItems(); + for (int i = 0; i < count; ++i) { + if (names.ItemAt(i)->Compare(name) == 0) + return B_OK; + } + names.AddItem(new (std::nothrow) BString(name)); + return B_OK; + } + BObjectList& names; + }; + RepositoryNameCollector repositoryNameCollector(names); + status_t result = VisitUserRepositoryConfigs(repositoryNameCollector); + if (result != B_OK) + return result; + + return VisitCommonRepositoryConfigs(repositoryNameCollector); +} + + +status_t +Roster::GetRepositoryCache(const BString& name, + RepositoryCache* repositoryCache) +{ + if (repositoryCache == NULL) + return B_BAD_VALUE; + + // user path has higher precedence than common path + BPath path; + status_t result = GetUserRepositoryCachePath(&path); + if (result != B_OK) + return result; + path.Append(name.String()); + + BEntry repoCacheEntry(path.Path()); + if (repoCacheEntry.Exists()) + return repositoryCache->SetTo(repoCacheEntry); + + if ((result = GetCommonRepositoryCachePath(&path)) != B_OK) + return result; + path.Append(name.String()); + + repoCacheEntry.SetTo(path.Path()); + return repositoryCache->SetTo(repoCacheEntry); +} + + +status_t +Roster::GetRepositoryConfig(const BString& name, + RepositoryConfig* repositoryConfig) +{ + if (repositoryConfig == NULL) + return B_BAD_VALUE; + + // user path has higher precedence than common path + BPath path; + status_t result = GetUserRepositoryConfigPath(&path); + if (result != B_OK) + return result; + path.Append(name.String()); + + BEntry repoConfigEntry(path.Path()); + if (repoConfigEntry.Exists()) + return repositoryConfig->SetTo(repoConfigEntry); + + if ((result = GetCommonRepositoryConfigPath(&path)) != B_OK) + return result; + path.Append(name.String()); + + repoConfigEntry.SetTo(path.Path()); + return repositoryConfig->SetTo(repoConfigEntry); +} + + +status_t +Roster::_GetRepositoryPath(BPath* path, bool create, + directory_which whichDir) const +{ + if (path == NULL) + return B_BAD_VALUE; + + status_t result = find_directory(whichDir, 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; } @@ -112,6 +208,8 @@ Roster::_VisitRepositoryConfigs(const BPath& path, { BDirectory directory(path.Path()); status_t result = directory.InitCheck(); + if (result == B_ENTRY_NOT_FOUND) + return B_OK; if (result != B_OK) return result; diff --git a/src/kits/package/TempEntryManager.cpp b/src/kits/package/TempfileManager.cpp similarity index 66% rename from src/kits/package/TempEntryManager.cpp rename to src/kits/package/TempfileManager.cpp index 96baedb8ee..0e0f91e3f7 100644 --- a/src/kits/package/TempEntryManager.cpp +++ b/src/kits/package/TempfileManager.cpp @@ -7,25 +7,27 @@ */ -#include +#include namespace Haiku { namespace Package { - -const BString TempEntryManager::kDefaultName = "tmp-pkgkit-file-"; +namespace Private { -TempEntryManager::TempEntryManager() +const BString TempfileManager::kDefaultName = "tmp-pkgkit-file-"; + + +TempfileManager::TempfileManager() : fNextNumber(1) { } -TempEntryManager::~TempEntryManager() +TempfileManager::~TempfileManager() { if (fBaseDirectory.InitCheck() != B_OK) return; @@ -41,14 +43,14 @@ TempEntryManager::~TempEntryManager() void -TempEntryManager::SetBaseDirectory(const BDirectory& baseDirectory) +TempfileManager::SetBaseDirectory(const BDirectory& baseDirectory) { fBaseDirectory = baseDirectory; } BEntry -TempEntryManager::Create(const BString& baseName) +TempfileManager::Create(const BString& baseName) { BString name = BString(baseName) << atomic_add(&fNextNumber, 1); @@ -56,6 +58,8 @@ TempEntryManager::Create(const BString& baseName) } +} // namespace Private + } // namespace Package } // namespace Haiku diff --git a/src/kits/package/ValidateChecksumJob.cpp b/src/kits/package/ValidateChecksumJob.cpp new file mode 100644 index 0000000000..f2f051b6da --- /dev/null +++ b/src/kits/package/ValidateChecksumJob.cpp @@ -0,0 +1,86 @@ +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Oliver Tappe + */ + + +#include + +#include + +#include + + +namespace Haiku { + +namespace Package { + +namespace Private { + + +ValidateChecksumJob::ValidateChecksumJob(const Context& context, + const BString& title, ChecksumAccessor* expectedChecksumAccessor, + ChecksumAccessor* realChecksumAccessor, bool failIfChecksumsDontMatch) + : + inherited(context, title), + fExpectedChecksumAccessor(expectedChecksumAccessor), + fRealChecksumAccessor(realChecksumAccessor), + fFailIfChecksumsDontMatch(failIfChecksumsDontMatch), + fChecksumsMatch(false) +{ +} + + +ValidateChecksumJob::~ValidateChecksumJob() +{ + delete fRealChecksumAccessor; + delete fExpectedChecksumAccessor; +} + + +status_t +ValidateChecksumJob::Execute() +{ + if (fExpectedChecksumAccessor == NULL || fRealChecksumAccessor == NULL) + return B_BAD_VALUE; + + BString expectedChecksum; + BString realChecksum; + + status_t result = fExpectedChecksumAccessor->GetChecksum(expectedChecksum); + if (result != B_OK) + return result; + + result = fRealChecksumAccessor->GetChecksum(realChecksum); + if (result != B_OK) + return result; + + fChecksumsMatch = expectedChecksum.ICompare(realChecksum) == 0; + + if (fFailIfChecksumsDontMatch && !fChecksumsMatch) { + BString error = BString("Checksum error:\n") + << "expected '" << expectedChecksum << "'\n" + << "got '" << realChecksum << "'"; + SetErrorString(error); + return B_BAD_DATA; + } + + return B_OK; +} + + +bool +ValidateChecksumJob::ChecksumsMatch() const +{ + return fChecksumsMatch; +} + + +} // namespace Private + +} // namespace Package + +} // namespace Haiku