From 0d68f6afb34d8e01421123b216e34771d1c7fbfe Mon Sep 17 00:00:00 2001 From: Oliver Tappe Date: Wed, 9 Feb 2011 19:11:23 +0000 Subject: [PATCH] Implemented repository writing: * fleshed out RepositoryWriterImpl * renamed BRepositoryHeader to BRepositoryInfo (in accordance with BPackageInfo) * adjusted BRepositoryInfo to be able to parse itself from a driver_settings file * added package_repo binary (only 'create' works as of yet) git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40405 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/package/PackageInfo.h | 7 + headers/os/package/PackageInfoAttributes.h | 1 + headers/os/package/PackageResolvable.h | 8 + .../os/package/PackageResolvableExpression.h | 9 + headers/os/package/PackageVersion.h | 8 + headers/os/package/RepositoryCache.h | 9 +- .../{RepositoryHeader.h => RepositoryInfo.h} | 37 +- .../os/package/hpkg/PackageContentHandler.h | 1 + headers/os/package/hpkg/RepositoryWriter.h | 6 +- .../package/ActivateRepositoryConfigJob.h | 4 +- .../package/hpkg/RepositoryWriterImpl.h | 42 ++- headers/private/package/hpkg/haiku_package.h | 3 + .../kernel/file_systems/packagefs/Volume.cpp | 6 + src/bin/Jamfile | 1 + src/bin/package/command_create.cpp | 2 +- src/bin/package/command_extract.cpp | 5 + src/bin/package/command_list.cpp | 7 +- src/bin/package/package.cpp | 8 +- src/bin/package_repo/Jamfile | 20 ++ src/bin/package_repo/command_create.cpp | 218 ++++++++++++ src/bin/package_repo/command_list.cpp | 323 ++++++++++++++++++ src/bin/package_repo/package_repo.cpp | 70 ++++ src/bin/package_repo/package_repo.h | 15 + .../package/ActivateRepositoryConfigJob.cpp | 34 +- src/kits/package/AddRepositoryRequest.cpp | 8 +- src/kits/package/Jamfile | 3 +- src/kits/package/PackageInfo.cpp | 32 +- src/kits/package/PackageResolvable.cpp | 11 + .../package/PackageResolvableExpression.cpp | 18 +- src/kits/package/PackageVersion.cpp | 12 + src/kits/package/RepositoryCache.cpp | 8 +- src/kits/package/RepositoryHeader.cpp | 202 ----------- src/kits/package/RepositoryInfo.cpp | 284 +++++++++++++++ src/kits/package/hpkg/PackageReaderImpl.cpp | 6 +- src/kits/package/hpkg/RepositoryWriter.cpp | 6 +- .../package/hpkg/RepositoryWriterImpl.cpp | 276 ++++++++++++++- src/tests/kits/package/make_repo.cpp | 16 +- 37 files changed, 1425 insertions(+), 301 deletions(-) rename headers/os/package/{RepositoryHeader.h => RepositoryInfo.h} (56%) create mode 100644 src/bin/package_repo/Jamfile create mode 100644 src/bin/package_repo/command_create.cpp create mode 100644 src/bin/package_repo/command_list.cpp create mode 100644 src/bin/package_repo/package_repo.cpp create mode 100644 src/bin/package_repo/package_repo.h delete mode 100644 src/kits/package/RepositoryHeader.cpp create mode 100644 src/kits/package/RepositoryInfo.cpp diff --git a/headers/os/package/PackageInfo.h b/headers/os/package/PackageInfo.h index 67fa376acd..b130d175a9 100644 --- a/headers/os/package/PackageInfo.h +++ b/headers/os/package/PackageInfo.h @@ -55,6 +55,7 @@ public: const BString& Description() const; const BString& Vendor() const; const BString& Packager() const; + const BString& Checksum() const; uint32 Flags() const; @@ -81,6 +82,7 @@ public: void SetDescription(const BString& description); void SetVendor(const BString& vendor); void SetPackager(const BString& packager); + void SetChecksum(const BString& checksum); void SetFlags(uint32 flags); @@ -120,6 +122,9 @@ public: void Clear(); public: + static status_t GetArchitectureByName(const BString& name, + BPackageArchitecture& _architecture); + static const char* kElementNames[]; static const char* kArchitectureNames[]; @@ -152,6 +157,8 @@ private: BObjectList fFreshensList; BObjectList fReplacesList; + + BString fChecksum; }; diff --git a/headers/os/package/PackageInfoAttributes.h b/headers/os/package/PackageInfoAttributes.h index 3128414ecd..9ca5120e6a 100644 --- a/headers/os/package/PackageInfoAttributes.h +++ b/headers/os/package/PackageInfoAttributes.h @@ -34,6 +34,7 @@ enum BPackageInfoAttributeIndex { B_PACKAGE_INFO_REPLACES, // list of resolvables that this package // will replace (upon update) B_PACKAGE_INFO_FLAGS, + B_PACKAGE_INFO_CHECKSUM, // sha256-checksum // B_PACKAGE_INFO_ENUM_COUNT, }; diff --git a/headers/os/package/PackageResolvable.h b/headers/os/package/PackageResolvable.h index e054121bdc..18cf29e102 100644 --- a/headers/os/package/PackageResolvable.h +++ b/headers/os/package/PackageResolvable.h @@ -15,6 +15,12 @@ namespace BPackageKit { +namespace BHPKG { + class BPackageResolvableData; +} +using BHPKG::BPackageResolvableData; + + /* * Defines a resolvable (something other packages can depend upon). * Each resolvable is defined as a name (with an optional type prefix) @@ -39,6 +45,8 @@ namespace BPackageKit { class BPackageResolvable { public: BPackageResolvable(); + BPackageResolvable( + const BPackageResolvableData& data); BPackageResolvable(const BString& name, BPackageResolvableType type = B_PACKAGE_RESOLVABLE_TYPE_DEFAULT, diff --git a/headers/os/package/PackageResolvableExpression.h b/headers/os/package/PackageResolvableExpression.h index 1f03eb65dc..6eb7b0b8af 100644 --- a/headers/os/package/PackageResolvableExpression.h +++ b/headers/os/package/PackageResolvableExpression.h @@ -15,6 +15,12 @@ namespace BPackageKit { +namespace BHPKG { + class BPackageResolvableExpressionData; +} +using BHPKG::BPackageResolvableExpressionData; + + /* * Expresses a constraint on a specific resolvable, either just a name * or a name plus a relational operator and a version. @@ -33,6 +39,9 @@ namespace BPackageKit { class BPackageResolvableExpression { public: BPackageResolvableExpression(); + BPackageResolvableExpression( + const BPackageResolvableExpressionData& data + ); BPackageResolvableExpression( const BString& name, BPackageResolvableOperator _op diff --git a/headers/os/package/PackageVersion.h b/headers/os/package/PackageVersion.h index cb2667ef33..376d315197 100644 --- a/headers/os/package/PackageVersion.h +++ b/headers/os/package/PackageVersion.h @@ -12,9 +12,17 @@ namespace BPackageKit { +namespace BHPKG { + class BPackageVersionData; +} +using BHPKG::BPackageVersionData; + + class BPackageVersion { public: BPackageVersion(); + BPackageVersion( + const BPackageVersionData& data); BPackageVersion(const BString& major, const BString& minor, const BString& micro, uint8 release); diff --git a/headers/os/package/RepositoryCache.h b/headers/os/package/RepositoryCache.h index 6fc96efb92..881f6a660b 100644 --- a/headers/os/package/RepositoryCache.h +++ b/headers/os/package/RepositoryCache.h @@ -9,15 +9,12 @@ #include #include -#include +#include namespace BPackageKit { -//class RepositoryHeader; - - class BRepositoryCache { public: BRepositoryCache(); @@ -27,7 +24,7 @@ public: status_t SetTo(const BEntry& entry); status_t InitCheck() const; - const BRepositoryHeader& Header() const; + const BRepositoryInfo& Info() const; const BEntry& Entry() const; bool IsUserSpecific() const; @@ -37,7 +34,7 @@ private: status_t fInitStatus; BEntry fEntry; - BRepositoryHeader fHeader; + BRepositoryInfo fInfo; bool fIsUserSpecific; }; diff --git a/headers/os/package/RepositoryHeader.h b/headers/os/package/RepositoryInfo.h similarity index 56% rename from headers/os/package/RepositoryHeader.h rename to headers/os/package/RepositoryInfo.h index 7c6834c63e..db59d0f8bc 100644 --- a/headers/os/package/RepositoryHeader.h +++ b/headers/os/package/RepositoryInfo.h @@ -2,55 +2,60 @@ * Copyright 2011, Haiku, Inc. * Distributed under the terms of the MIT License. */ -#ifndef _PACKAGE__REPOSITORY_HEADER_H_ -#define _PACKAGE__REPOSITORY_HEADER_H_ +#ifndef _PACKAGE__REPOSITORY_INFO_H_ +#define _PACKAGE__REPOSITORY_INFO_H_ #include +#include #include +#include + namespace BPackageKit { -class BRepositoryHeader : public BArchivable { +class BRepositoryInfo : public BArchivable { typedef BArchivable inherited; public: - BRepositoryHeader(); - BRepositoryHeader(BMessage* data); - virtual ~BRepositoryHeader(); + BRepositoryInfo(); + BRepositoryInfo(BMessage* data); + BRepositoryInfo(const BEntry& entry); + virtual ~BRepositoryInfo(); virtual status_t Archive(BMessage* data, bool deep = true) const; status_t SetTo(const BMessage* data); + status_t SetTo(const BEntry& entry); status_t InitCheck() const; const BString& Name() const; const BString& OriginalBaseURL() const; const BString& Vendor() const; - const BString& ShortDescription() const; - const BString& LongDescription() const; + const BString& Summary() const; uint8 Priority() const; + BPackageArchitecture Architecture() const; void SetName(const BString& name); void SetOriginalBaseURL(const BString& url); void SetVendor(const BString& vendor); - void SetShortDescription(const BString& description); - void SetLongDescription(const BString& description); + void SetSummary(const BString& summary); void SetPriority(uint8 priority); + void SetArchitecture(BPackageArchitecture arch); public: - static BRepositoryHeader* Instantiate(BMessage* data); + static BRepositoryInfo* Instantiate(BMessage* data); static const uint8 kDefaultPriority; static const char* kNameField; static const char* kURLField; static const char* kVendorField; - static const char* kShortDescriptionField; - static const char* kLongDescriptionField; + static const char* kSummaryField; static const char* kPriorityField; + static const char* kArchitectureField; private: status_t fInitStatus; @@ -58,13 +63,13 @@ private: BString fName; BString fOriginalBaseURL; BString fVendor; - BString fShortDescription; - BString fLongDescription; + BString fSummary; uint8 fPriority; + BPackageArchitecture fArchitecture; }; } // namespace BPackageKit -#endif // _PACKAGE__REPOSITORY_HEADER_H_ +#endif // _PACKAGE__REPOSITORY_INFO_H_ diff --git a/headers/os/package/hpkg/PackageContentHandler.h b/headers/os/package/hpkg/PackageContentHandler.h index 21c64da4f8..db629c6e34 100644 --- a/headers/os/package/hpkg/PackageContentHandler.h +++ b/headers/os/package/hpkg/PackageContentHandler.h @@ -47,6 +47,7 @@ public: virtual status_t HandlePackageAttribute( const BPackageInfoAttributeValue& value ) = 0; + virtual status_t HandlePackageAttributesDone() = 0; virtual void HandleErrorOccurred() = 0; }; diff --git a/headers/os/package/hpkg/RepositoryWriter.h b/headers/os/package/hpkg/RepositoryWriter.h index 91906fb20a..102a44978b 100644 --- a/headers/os/package/hpkg/RepositoryWriter.h +++ b/headers/os/package/hpkg/RepositoryWriter.h @@ -16,6 +16,7 @@ namespace BPackageKit { class BPackageInfo; +class BRepositoryInfo; namespace BHPKG { @@ -38,6 +39,8 @@ public: virtual void OnPackageAttributesSizeInfo(uint32 stringCount, uint32 uncompressedSize) = 0; virtual void OnRepositorySizeInfo(uint32 headerSize, + uint32 repositoryInfoLength, + uint32 packageCount, uint32 packageAttributesSize, uint64 totalSize) = 0; }; @@ -47,7 +50,8 @@ class BRepositoryWriter { public: public: BRepositoryWriter( - BRepositoryWriterListener* listener); + BRepositoryWriterListener* listener, + const BRepositoryInfo* repositoryInfo); ~BRepositoryWriter(); status_t Init(const char* fileName); diff --git a/headers/private/package/ActivateRepositoryConfigJob.h b/headers/private/package/ActivateRepositoryConfigJob.h index c211b04a51..b48583b75b 100644 --- a/headers/private/package/ActivateRepositoryConfigJob.h +++ b/headers/private/package/ActivateRepositoryConfigJob.h @@ -25,7 +25,7 @@ public: ActivateRepositoryConfigJob( const BContext& context, const BString& title, - const BEntry& archivedRepoHeaderEntry, + const BEntry& archivedRepoInfoEntry, const BString& repositoryBaseURL, const BDirectory& targetDirectory); virtual ~ActivateRepositoryConfigJob(); @@ -37,7 +37,7 @@ protected: virtual void Cleanup(status_t jobResult); private: - BEntry fArchivedRepoHeaderEntry; + BEntry fArchivedRepoInfoEntry; BString fRepositoryBaseURL; BDirectory fTargetDirectory; BEntry fTargetEntry; diff --git a/headers/private/package/hpkg/RepositoryWriterImpl.h b/headers/private/package/hpkg/RepositoryWriterImpl.h index 3b82bbb09e..37c993469c 100644 --- a/headers/private/package/hpkg/RepositoryWriterImpl.h +++ b/headers/private/package/hpkg/RepositoryWriterImpl.h @@ -8,17 +8,21 @@ #include +#include #include #include +#include namespace BPackageKit { + namespace BHPKG { -class BDataReader; -class BErrorOutput; +class BPackageEntry; +class BPackageEntryAttribute; +class BPackageInfoAttributeValue; namespace BPrivate { @@ -26,26 +30,54 @@ namespace BPrivate { struct hpkg_header; -class RepositoryWriterImpl : public WriterImplBase { +class RepositoryWriterImpl + : public WriterImplBase, private BPackageContentHandler { public: RepositoryWriterImpl( - BRepositoryWriterListener* listener); + BRepositoryWriterListener* listener, + const BRepositoryInfo* repositoryInfo); ~RepositoryWriterImpl(); status_t Init(const char* fileName); status_t AddPackage(const BEntry& packageEntry); status_t Finish(); +private: + // BPackageContentHandler + virtual status_t HandleEntry(BPackageEntry* entry); + virtual status_t HandleEntryAttribute(BPackageEntry* entry, + BPackageEntryAttribute* attribute); + virtual status_t HandleEntryDone(BPackageEntry* entry); + + virtual status_t HandlePackageAttribute( + const BPackageInfoAttributeValue& value + ); + virtual status_t HandlePackageAttributesDone(); + + virtual void HandleErrorOccurred(); + private: status_t _Init(const char* fileName); status_t _AddPackage(const BEntry& packageEntry); status_t _Finish(); + status_t _RegisterCurrentPackageInfo(); + status_t _WriteRepositoryInfo( + ssize_t& _repositoryInfoLength); off_t _WritePackageAttributes( - hpkg_repo_header& header); + hpkg_repo_header& header, + off_t startOffset); + + struct PackageNameSet; private: BRepositoryWriterListener* fListener; + + const BRepositoryInfo* fRepositoryInfo; + + BPackageInfo fPackageInfo; + uint32 fPackageCount; + PackageNameSet* fPackageNames; }; diff --git a/headers/private/package/hpkg/haiku_package.h b/headers/private/package/hpkg/haiku_package.h index 92eb37e663..e111634248 100644 --- a/headers/private/package/hpkg/haiku_package.h +++ b/headers/private/package/hpkg/haiku_package.h @@ -51,6 +51,9 @@ struct hpkg_repo_header { uint16 version; uint64 total_size; + // repository header + uint32 repository_header_length; + // package attributes section uint32 attributes_compression; uint32 attributes_length_compressed; diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index c6b1fe01eb..44ed72e46b 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -264,6 +264,12 @@ struct Volume::PackageLoaderContentHandler : BPackageContentHandler { return B_OK; } + virtual status_t HandlePackageAttributesDone() + { + // TODO! + return B_OK; + } + virtual void HandleErrorOccurred() { fErrorOccurred = true; diff --git a/src/bin/Jamfile b/src/bin/Jamfile index 56abcf9745..eb76db98b4 100644 --- a/src/bin/Jamfile +++ b/src/bin/Jamfile @@ -255,6 +255,7 @@ SubInclude HAIKU_TOP src bin mkdos ; SubInclude HAIKU_TOP src bin mkfs ; SubInclude HAIKU_TOP src bin multiuser ; SubInclude HAIKU_TOP src bin package ; +SubInclude HAIKU_TOP src bin package_repo ; SubInclude HAIKU_TOP src bin patch ; SubInclude HAIKU_TOP src bin pc ; SubInclude HAIKU_TOP src bin pcmcia-cs ; diff --git a/src/bin/package/command_create.cpp b/src/bin/package/command_create.cpp index 1d1d4deb97..8932902a89 100644 --- a/src/bin/package/command_create.cpp +++ b/src/bin/package/command_create.cpp @@ -88,7 +88,7 @@ public: printf("TOC size: %10llu\n", tocSize); printf("package attributes size: %10lu\n", packageAttributesSize); printf("total size: %10llu\n", totalSize); - + printf("-----------------------------------\n"); } private: diff --git a/src/bin/package/command_extract.cpp b/src/bin/package/command_extract.cpp index d3b3a86a45..df6f38ab9b 100644 --- a/src/bin/package/command_extract.cpp +++ b/src/bin/package/command_extract.cpp @@ -229,6 +229,11 @@ struct PackageContentExtractHandler : BPackageContentHandler { return B_OK; } + virtual status_t HandlePackageAttributesDone() + { + return B_OK; + } + virtual void HandleErrorOccurred() { fErrorOccurred = true; diff --git a/src/bin/package/command_list.cpp b/src/bin/package/command_list.cpp index ac6a081503..31b5023dc9 100644 --- a/src/bin/package/command_list.cpp +++ b/src/bin/package/command_list.cpp @@ -144,7 +144,7 @@ struct PackageContentListHandler : BPackageContentHandler { break; case B_PACKAGE_INFO_ARCHITECTURE: - printf("\tarchitecure: %s\n", + printf("\tarchitecture: %s\n", BPackageInfo::kArchitectureNames[value.unsignedInt]); break; @@ -226,6 +226,11 @@ struct PackageContentListHandler : BPackageContentHandler { return B_OK; } + virtual status_t HandlePackageAttributesDone() + { + return B_OK; + } + virtual void HandleErrorOccurred() { } diff --git a/src/bin/package/package.cpp b/src/bin/package/package.cpp index ce3fe5e3f0..7d192caff1 100644 --- a/src/bin/package/package.cpp +++ b/src/bin/package/package.cpp @@ -13,8 +13,6 @@ #include #include -#include - extern const char* __progname; const char* kCommandName = __progname; @@ -28,7 +26,9 @@ static const char* kUsage = " create [ ] \n" " Creates package file from contents of current directory.\n" "\n" - " -C - Change to directory before starting.\n" + " -C - Change to directory before starting.\n" + " -q - be quiet (don't show any output except for errors).\n" + " -v - be verbose (show more info about created package).\n" "\n" " dump [ ] \n" " Dumps the TOC section of package file . For debugging only.\n" @@ -36,7 +36,7 @@ static const char* kUsage = " extract [ ] \n" " Extracts the contents of package file .\n" "\n" - " -C - Change to directory before extracting the " + " -C - Change to directory before extracting the " "contents\n" " of the archive.\n" "\n" diff --git a/src/bin/package_repo/Jamfile b/src/bin/package_repo/Jamfile new file mode 100644 index 0000000000..4c4999a4b8 --- /dev/null +++ b/src/bin/package_repo/Jamfile @@ -0,0 +1,20 @@ +SubDir HAIKU_TOP src bin package_repo ; + +UsePrivateHeaders kernel shared ; + +DEFINES += B_ENABLE_INCOMPLETE_POSIX_AT_SUPPORT ; + # TODO: Remove when it is complete! + +SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src bin package ] ; + +BinCommand package_repo : + BlockBufferCacheNoLock.cpp + command_create.cpp + command_list.cpp + package_repo.cpp + StandardErrorOutput.cpp + : + package be + $(TARGET_LIBSUPC++) +; + diff --git a/src/bin/package_repo/command_create.cpp b/src/bin/package_repo/command_create.cpp new file mode 100644 index 0000000000..a5eeca4cce --- /dev/null +++ b/src/bin/package_repo/command_create.cpp @@ -0,0 +1,218 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ + + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "package.h" +#include "StandardErrorOutput.h" + + +using BPackageKit::BHPKG::BRepositoryWriterListener; +using BPackageKit::BHPKG::BRepositoryWriter; +using namespace BPackageKit; + + +class RepositoryWriterListener : public BRepositoryWriterListener { +public: + RepositoryWriterListener(bool verbose, bool quiet) + : fVerbose(verbose), fQuiet(quiet) + { + } + + virtual void PrintErrorVarArgs(const char* format, va_list args) + { + vfprintf(stderr, format, args); + } + + virtual void OnPackageAdded(const BPackageInfo& packageInfo) + { + if (fQuiet) + return; + + printf("%s (%s)\n", packageInfo.Name().String(), + packageInfo.Version().ToString().String()); + if (fVerbose) { + printf("\tsummary: %s\n", packageInfo.Summary().String()); + printf("\tvendor: %s\n", packageInfo.Vendor().String()); + printf("\tpackager: %s\n", packageInfo.Packager().String()); + if (uint32 flags = packageInfo.Flags()) { + printf("\tflags:\n"); + if ((flags & B_PACKAGE_FLAG_APPROVE_LICENSE) != 0) + printf("\t\tapprove_license\n"); + if ((flags & B_PACKAGE_FLAG_SYSTEM_PACKAGE) != 0) + printf("\t\tsystem_package\n"); + } + } + } + + virtual void OnPackageAttributesSizeInfo(uint32 stringCount, + uint32 uncompressedSize) + { + if (fQuiet || !fVerbose) + return; + + printf("----- Package Attribute Info ---------------------\n"); + printf("string count: %10lu\n", stringCount); + printf("package attributes size: %10lu (uncompressed)\n", + uncompressedSize); + } + + virtual void OnRepositorySizeInfo(uint32 headerSize, + uint32 repositoryInfoSize, uint32 packageCount, + uint32 packageAttributesSize, uint64 totalSize) + { + if (fQuiet) + return; + + printf("----- Package Repository Info -----\n"); + printf("package count %10lu\n", packageCount); + printf("-----------------------------------\n"); + printf("header size: %10lu\n", headerSize); + printf("repository header size: %10lu\n", repositoryInfoSize); + printf("package attributes size: %10lu\n", packageAttributesSize); + printf("total size: %10llu\n", totalSize); + printf("-----------------------------------\n"); + } + +private: + bool fVerbose; + bool fQuiet; +}; + + +int +command_create(int argc, const char* const* argv) +{ + const char* changeToDirectory = NULL; + bool quiet = false; + bool verbose = false; + + while (true) { + static struct option sLongOptions[] = { + { "help", no_argument, 0, 'h' }, + { "quiet", no_argument, 0, 'q' }, + { "verbose", no_argument, 0, 'v' }, + { 0, 0, 0, 0 } + }; + + opterr = 0; // don't print errors + int c = getopt_long(argc, (char**)argv, "+C:hqv", sLongOptions, NULL); + if (c == -1) + break; + + switch (c) { + case 'C': + changeToDirectory = optarg; + break; + + case 'h': + print_usage_and_exit(false); + break; + + case 'q': + quiet = true; + break; + + case 'v': + verbose = true; + break; + + default: + print_usage_and_exit(true); + break; + } + } + + // The remaining arguments are the repository info file plus one or more + // package files, i.e. at least two more arguments. + if (optind + 2 >= argc) + print_usage_and_exit(true); + + const char* repositoryInfoFileName = argv[optind++]; + const char* const* packageFileNames = argv + optind; + + RepositoryWriterListener listener(verbose, quiet); + + BEntry repositoryInfoEntry(repositoryInfoFileName); + if (!repositoryInfoEntry.Exists()) { + listener.PrintError( + "Error: given repository-info file '%s' doesn't exist!\n", + repositoryInfoFileName); + return 1; + } + + // determine path for 'repo' file from given info file + BEntry repositoryParentEntry; + repositoryInfoEntry.GetParent(&repositoryParentEntry); + BPath repositoryPath; + if (repositoryParentEntry.GetPath(&repositoryPath) != B_OK) { + listener.PrintError( + "Error: can't determine path of given repository-info file!\n"); + return 1; + } + repositoryPath.Append("repo"); + + // create repository + BRepositoryInfo repositoryInfo(repositoryInfoEntry); + status_t result = repositoryInfo.InitCheck(); + if (result != B_OK) { + listener.PrintError( + "Error: can't parse given repository-info file : %s\n", + strerror(result)); + return 1; + } + BRepositoryWriter repositoryWriter(&listener, &repositoryInfo); + if ((result = repositoryWriter.Init(repositoryPath.Path())) != B_OK) { + listener.PrintError("Error: can't initialize repository-writer : %s\n", + strerror(result)); + return 1; + } + + // change directory, if requested + if (changeToDirectory != NULL) { + if (chdir(changeToDirectory) != 0) { + listener.PrintError( + "Error: Failed to change the current working directory to " + "\"%s\": %s\n", changeToDirectory, strerror(errno)); + return 1; + } + } + + // add all given package files + for (int i = 0; i < argc - optind; ++i) { + if (verbose) + printf("reading package '%s' ...\n", packageFileNames[i]); + BEntry entry(packageFileNames[i]); + result = repositoryWriter.AddPackage(entry); + if (result != B_OK) + return 1; + } + + // write the repository + result = repositoryWriter.Finish(); + if (result != B_OK) + return 1; + + if (verbose) { + printf("\nsuccessfully created repository '%s'\n", + repositoryPath.Path()); + } + + return 0; +} diff --git a/src/bin/package_repo/command_list.cpp b/src/bin/package_repo/command_list.cpp new file mode 100644 index 0000000000..31b5023dc9 --- /dev/null +++ b/src/bin/package_repo/command_list.cpp @@ -0,0 +1,323 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "package.h" +#include "StandardErrorOutput.h" + + +using namespace BPackageKit::BHPKG; +using namespace BPackageKit; + + +struct PackageContentListHandler : BPackageContentHandler { + PackageContentListHandler(bool listAttributes) + : + fLevel(0), + fListAttribute(listAttributes) + { + } + + virtual status_t HandleEntry(BPackageEntry* entry) + { + fLevel++; + + int indentation = (fLevel - 1) * 2; + printf("%*s", indentation, ""); + + // name and size + printf("%-*s", indentation < 32 ? 32 - indentation : 0, entry->Name()); + printf(" %8llu", entry->Data().UncompressedSize()); + + // time + struct tm* time = localtime(&entry->ModifiedTime().tv_sec); + printf(" %04d-%02d-%02d %02d:%02d:%02d", + 1900 + time->tm_year, time->tm_mon + 1, time->tm_mday, + time->tm_hour, time->tm_min, time->tm_sec); + + // file type + mode_t mode = entry->Mode(); + if (S_ISREG(mode)) + printf(" -"); + else if (S_ISDIR(mode)) + printf(" d"); + else if (S_ISLNK(mode)) + printf(" l"); + else + printf(" ?"); + + // permissions + char buffer[4]; + printf("%s", _PermissionString(buffer, mode >> 6, + (mode & S_ISUID) != 0)); + printf("%s", _PermissionString(buffer, mode >> 3, + (mode & S_ISGID) != 0)); + printf("%s", _PermissionString(buffer, mode, false)); + + // print the symlink path + if (S_ISLNK(mode)) + printf(" -> %s", entry->SymlinkPath()); + + printf("\n"); + return B_OK; + } + + virtual status_t HandleEntryAttribute(BPackageEntry* entry, + BPackageEntryAttribute* attribute) + { + if (!fListAttribute) + return B_OK; + + int indentation = fLevel * 2; + printf("%*s<", indentation, ""); + printf("%-*s %8llu", indentation < 31 ? 31 - indentation : 0, + attribute->Name(), attribute->Data().UncompressedSize()); + + uint32 type = attribute->Type(); + if (isprint(type & 0xff) && isprint((type >> 8) & 0xff) + && isprint((type >> 16) & 0xff) && isprint(type >> 24)) { + printf(" '%c%c%c%c'", int(type >> 24), int((type >> 16) & 0xff), + int((type >> 8) & 0xff), int(type & 0xff)); + } else + printf(" %#lx", type); + + printf(">\n"); + return B_OK; + } + + virtual status_t HandleEntryDone(BPackageEntry* entry) + { + fLevel--; + return B_OK; + } + + virtual status_t HandlePackageAttribute( + const BPackageInfoAttributeValue& value) + { + switch (value.attributeIndex) { + case B_PACKAGE_INFO_NAME: + printf("package-attributes:\n"); + printf("\tname: %s\n", value.string); + break; + + case B_PACKAGE_INFO_SUMMARY: + printf("\tsummary: %s\n", value.string); + break; + + case B_PACKAGE_INFO_DESCRIPTION: + printf("\tdescription: %s\n", value.string); + break; + + case B_PACKAGE_INFO_VENDOR: + printf("\tvendor: %s\n", value.string); + break; + + case B_PACKAGE_INFO_PACKAGER: + printf("\tpackager: %s\n", value.string); + break; + + case B_PACKAGE_INFO_FLAGS: + if (value.unsignedInt == 0) + break; + printf("\tflags:\n"); + if ((value.unsignedInt & B_PACKAGE_FLAG_APPROVE_LICENSE) != 0) + printf("\t\tapprove_license\n"); + if ((value.unsignedInt & B_PACKAGE_FLAG_SYSTEM_PACKAGE) != 0) + printf("\t\tsystem_package\n"); + break; + + case B_PACKAGE_INFO_ARCHITECTURE: + printf("\tarchitecture: %s\n", + BPackageInfo::kArchitectureNames[value.unsignedInt]); + break; + + case B_PACKAGE_INFO_VERSION: + printf("\tversion: %s.%s.%s-%d\n", value.version.major, + value.version.minor, value.version.micro, + value.version.release); + break; + + case B_PACKAGE_INFO_COPYRIGHTS: + printf("\tcopyright: %s\n", value.string); + break; + + case B_PACKAGE_INFO_LICENSES: + printf("\tlicense: %s\n", value.string); + break; + + case B_PACKAGE_INFO_PROVIDES: + printf("\tprovides: %s", value.resolvable.name); + if (value.resolvable.haveVersion) { + printf(" = "); + _PrintPackageVersion(value.resolvable.version); + } + printf("\n"); + break; + + case B_PACKAGE_INFO_REQUIRES: + printf("\trequires: %s", value.resolvableExpression.name); + if (value.resolvableExpression.haveOpAndVersion) { + printf(" %s ", BPackageResolvableExpression::kOperatorNames[ + value.resolvableExpression.op]); + _PrintPackageVersion(value.resolvableExpression.version); + } + printf("\n"); + break; + + case B_PACKAGE_INFO_SUPPLEMENTS: + printf("\tsupplements: %s", value.resolvableExpression.name); + if (value.resolvableExpression.haveOpAndVersion) { + printf(" %s ", BPackageResolvableExpression::kOperatorNames[ + value.resolvableExpression.op]); + _PrintPackageVersion(value.resolvableExpression.version); + } + printf("\n"); + break; + + case B_PACKAGE_INFO_CONFLICTS: + printf("\tconflicts: %s", value.resolvableExpression.name); + if (value.resolvableExpression.haveOpAndVersion) { + printf(" %s ", BPackageResolvableExpression::kOperatorNames[ + value.resolvableExpression.op]); + _PrintPackageVersion(value.resolvableExpression.version); + } + printf("\n"); + break; + + case B_PACKAGE_INFO_FRESHENS: + printf("\tfreshens: %s", value.resolvableExpression.name); + if (value.resolvableExpression.haveOpAndVersion) { + printf(" %s ", BPackageResolvableExpression::kOperatorNames[ + value.resolvableExpression.op]); + _PrintPackageVersion(value.resolvableExpression.version); + } + printf("\n"); + break; + + case B_PACKAGE_INFO_REPLACES: + printf("\treplaces: %s\n", value.string); + break; + + default: + printf( + "*** Invalid package attribute section: unexpected " + "package attribute index %d encountered\n", + value.attributeIndex); + return B_BAD_DATA; + } + + return B_OK; + } + + virtual status_t HandlePackageAttributesDone() + { + return B_OK; + } + + virtual void HandleErrorOccurred() + { + } + +private: + static const char* _PermissionString(char* buffer, uint32 mode, bool sticky) + { + buffer[0] = (mode & 0x4) != 0 ? 'r' : '-'; + buffer[1] = (mode & 0x2) != 0 ? 'w' : '-'; + + if ((mode & 0x1) != 0) + buffer[2] = sticky ? 's' : 'x'; + else + buffer[2] = '-'; + + buffer[3] = '\0'; + return buffer; + } + + static void _PrintPackageVersion(const BPackageVersionData& version) + { + printf("%s", version.major); + if (version.minor != NULL && version.minor[0] != '\0') + printf(".%s", version.minor); + if (version.micro != NULL && version.micro[0] != '\0') + printf(".%s", version.micro); + if (version.release > 0) + printf("-%d", version.release); + } + +private: + int fLevel; + bool fListAttribute; +}; + + +int +command_list(int argc, const char* const* argv) +{ + bool listAttributes = false; + + 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, "+ha", sLongOptions, NULL); + if (c == -1) + break; + + switch (c) { + case 'a': + listAttributes = true; + break; + + case 'h': + print_usage_and_exit(false); + break; + + default: + print_usage_and_exit(true); + break; + } + } + + // One argument should remain -- the package file name. + if (optind + 1 != argc) + print_usage_and_exit(true); + + const char* packageFileName = argv[optind++]; + + // open package + StandardErrorOutput errorOutput; + BPackageReader packageReader(&errorOutput); + status_t error = packageReader.Init(packageFileName); +printf("Init(): %s\n", strerror(error)); + if (error != B_OK) + return 1; + + // list + PackageContentListHandler handler(listAttributes); + error = packageReader.ParseContent(&handler); +printf("ParseContent(): %s\n", strerror(error)); + if (error != B_OK) + return 1; + + return 0; +} diff --git a/src/bin/package_repo/package_repo.cpp b/src/bin/package_repo/package_repo.cpp new file mode 100644 index 0000000000..b2811ab2da --- /dev/null +++ b/src/bin/package_repo/package_repo.cpp @@ -0,0 +1,70 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ + + +#include "package_repo.h" + +#include +#include +#include +#include +#include + +extern const char* __progname; +const char* kCommandName = __progname; + + +static const char* kUsage = + "Usage: %s \n" + "Creates or inspects a Haiku package repository file.\n" + "\n" + "Commands:\n" + " create [ ] \n" + " Creates package repository file from the given\n" + " package files.\n" + "\n" + " -C - Change to directory before starting.\n" + " -q - be quiet (don't show any output except for errors).\n" + " -v - be verbose (list package attributes as encountered).\n" + "\n" + " list [ ] \n" + " Lists the contents of package repository file .\n" + "\n" + " -v - be verbose (list attributes of all packages found).\n" + "\n" + "Common Options:\n" + " -h, --help - Print this usage info.\n" +; + + +void +print_usage_and_exit(bool error) +{ + fprintf(error ? stderr : stdout, kUsage, kCommandName); + 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, "create") == 0) + return command_create(argc - 1, argv + 1); + + if (strcmp(command, "list") == 0) + return command_list(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/package_repo/package_repo.h b/src/bin/package_repo/package_repo.h new file mode 100644 index 0000000000..2f24a15df0 --- /dev/null +++ b/src/bin/package_repo/package_repo.h @@ -0,0 +1,15 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ +#ifndef PACKAGE_REPO_H +#define PACKAGE_REPO_H + + +void print_usage_and_exit(bool error); + +int command_create(int argc, const char* const* argv); +int command_list(int argc, const char* const* argv); + + +#endif // PACKAGE_REPO_H diff --git a/src/kits/package/ActivateRepositoryConfigJob.cpp b/src/kits/package/ActivateRepositoryConfigJob.cpp index 59d9c0d149..07cdbabe0e 100644 --- a/src/kits/package/ActivateRepositoryConfigJob.cpp +++ b/src/kits/package/ActivateRepositoryConfigJob.cpp @@ -9,14 +9,9 @@ #include -#include -#include - -#include - #include #include -#include +#include namespace BPackageKit { @@ -26,11 +21,11 @@ namespace BPrivate { ActivateRepositoryConfigJob::ActivateRepositoryConfigJob( const BContext& context, const BString& title, - const BEntry& archivedRepoHeaderEntry, const BString& repositoryBaseURL, + const BEntry& archivedRepoInfoEntry, const BString& repositoryBaseURL, const BDirectory& targetDirectory) : inherited(context, title), - fArchivedRepoHeaderEntry(archivedRepoHeaderEntry), + fArchivedRepoInfoEntry(archivedRepoInfoEntry), fRepositoryBaseURL(repositoryBaseURL), fTargetDirectory(targetDirectory) { @@ -45,26 +40,15 @@ ActivateRepositoryConfigJob::~ActivateRepositoryConfigJob() status_t ActivateRepositoryConfigJob::Execute() { - BFile archiveFile(&fArchivedRepoHeaderEntry, B_READ_ONLY); - status_t result = archiveFile.InitCheck(); + BRepositoryInfo repoInfo(fArchivedRepoInfoEntry); + status_t result = repoInfo.InitCheck(); if (result != B_OK) return result; - BMessage archive; - if ((result = archive.Unflatten(&archiveFile)) != B_OK) - return result; - - BRepositoryHeader* repoHeader = BRepositoryHeader::Instantiate(&archive); - if (repoHeader == NULL) - return B_BAD_DATA; - ObjectDeleter repoHeaderDeleter(repoHeader); - if ((result = repoHeader->InitCheck()) != B_OK) - return result; - - fTargetEntry.SetTo(&fTargetDirectory, repoHeader->Name().String()); + fTargetEntry.SetTo(&fTargetDirectory, repoInfo.Name().String()); if (fTargetEntry.Exists()) { BString description = BString("A repository configuration for ") - << repoHeader->Name() << " already exists."; + << repoInfo.Name() << " already exists."; BString question("overwrite?"); bool yes = fContext.DecisionProvider().YesNoDecisionNeeded( description, question, "yes", "no", "no"); @@ -77,9 +61,9 @@ ActivateRepositoryConfigJob::Execute() // create and store the configuration (injecting the BaseURL that was // actually used) BRepositoryConfig repoConfig; - repoConfig.SetName(repoHeader->Name()); + repoConfig.SetName(repoInfo.Name()); repoConfig.SetBaseURL(fRepositoryBaseURL); - repoConfig.SetPriority(repoHeader->Priority()); + repoConfig.SetPriority(repoInfo.Priority()); if ((result = repoConfig.Store(fTargetEntry)) != B_OK) return result; diff --git a/src/kits/package/AddRepositoryRequest.cpp b/src/kits/package/AddRepositoryRequest.cpp index 509fdcb933..8c30d6c75b 100644 --- a/src/kits/package/AddRepositoryRequest.cpp +++ b/src/kits/package/AddRepositoryRequest.cpp @@ -48,13 +48,13 @@ AddRepositoryRequest::CreateInitialJobs() return B_NO_INIT; BEntry tempEntry; - result = fContext.GetNewTempfile("repoheader-", &tempEntry); + result = fContext.GetNewTempfile("repoinfo-", &tempEntry); if (result != B_OK) return result; - BString repoHeaderURL = BString(fRepositoryBaseURL) << "/" << "repo.header"; + BString repoInfoURL = BString(fRepositoryBaseURL) << "/" << "repo.info"; FetchFileJob* fetchJob = new (std::nothrow) FetchFileJob(fContext, - BString("Fetching repository header from ") << fRepositoryBaseURL, - repoHeaderURL, tempEntry); + BString("Fetching repository info from ") << fRepositoryBaseURL, + repoInfoURL, tempEntry); if (fetchJob == NULL) return B_NO_MEMORY; if ((result = QueueJob(fetchJob)) != B_OK) { diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile index ee0d9eccee..f480a20ac0 100644 --- a/src/kits/package/Jamfile +++ b/src/kits/package/Jamfile @@ -25,6 +25,7 @@ HPKG_SOURCES = PackageReaderImpl.cpp PackageWriter.cpp PackageWriterImpl.cpp + RepositoryWriter.cpp RepositoryWriterImpl.cpp Strings.cpp WriterImplBase.cpp @@ -56,7 +57,7 @@ SharedLibrary libpackage.so RemoveRepositoryJob.cpp RepositoryCache.cpp RepositoryConfig.cpp - RepositoryHeader.cpp + RepositoryInfo.cpp Request.cpp TempfileManager.cpp ValidateChecksumJob.cpp diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp index a4236c3c4b..117ada8066 100644 --- a/src/kits/package/PackageInfo.cpp +++ b/src/kits/package/PackageInfo.cpp @@ -809,6 +809,7 @@ const char* BPackageInfo::kElementNames[B_PACKAGE_INFO_ENUM_COUNT] = { "freshens", "replaces", "flags", + "checksum", // not being parsed, computed externally }; @@ -936,6 +937,13 @@ BPackageInfo::Packager() const } +const BString& +BPackageInfo::Checksum() const +{ + return fChecksum; +} + + uint32 BPackageInfo::Flags() const { @@ -1048,6 +1056,13 @@ BPackageInfo::SetPackager(const BString& packager) } +void +BPackageInfo::SetChecksum(const BString& checksum) +{ + fChecksum = checksum; +} + + void BPackageInfo::SetVersion(const BPackageVersion& version) { @@ -1226,8 +1241,10 @@ BPackageInfo::Clear() fDescription.Truncate(0); fVendor.Truncate(0); fPackager.Truncate(0); - fVersion.Clear(); + fChecksum.Truncate(0); + fFlags = 0; fArchitecture = B_PACKAGE_ARCHITECTURE_ENUM_COUNT; + fVersion.Clear(); fCopyrightList.MakeEmpty(); fLicenseList.MakeEmpty(); fRequiresList.MakeEmpty(); @@ -1239,4 +1256,17 @@ BPackageInfo::Clear() } +/*static*/ status_t +BPackageInfo::GetArchitectureByName(const BString& name, + BPackageArchitecture& _architecture) +{ + for (int i = 0; i < B_PACKAGE_ARCHITECTURE_ENUM_COUNT; ++i) { + if (name.ICompare(kArchitectureNames[i]) == 0) { + _architecture = (BPackageArchitecture)i; + return B_OK; + } + } + return B_NAME_NOT_FOUND; +} + } // namespace BPackageKit diff --git a/src/kits/package/PackageResolvable.cpp b/src/kits/package/PackageResolvable.cpp index e6eba8cbe2..e04915c2cf 100644 --- a/src/kits/package/PackageResolvable.cpp +++ b/src/kits/package/PackageResolvable.cpp @@ -6,6 +6,8 @@ #include +#include + namespace BPackageKit { @@ -27,6 +29,15 @@ BPackageResolvable::BPackageResolvable() } +BPackageResolvable::BPackageResolvable(const BPackageResolvableData& data) + : + fName(data.name), + fType(data.type), + fVersion(data.version) +{ +} + + BPackageResolvable::BPackageResolvable(const BString& name, BPackageResolvableType type, const BPackageVersion& version) : diff --git a/src/kits/package/PackageResolvableExpression.cpp b/src/kits/package/PackageResolvableExpression.cpp index 32513d8527..3e79ca015f 100644 --- a/src/kits/package/PackageResolvableExpression.cpp +++ b/src/kits/package/PackageResolvableExpression.cpp @@ -6,6 +6,8 @@ #include +#include + namespace BPackageKit { @@ -29,6 +31,16 @@ BPackageResolvableExpression::BPackageResolvableExpression() } +BPackageResolvableExpression::BPackageResolvableExpression( + const BPackageResolvableExpressionData& data) + : + fName(data.name), + fOperator(data.op), + fVersion(data.version) +{ +} + + BPackageResolvableExpression::BPackageResolvableExpression(const BString& name, BPackageResolvableOperator _operator, const BPackageVersion& version) : @@ -46,10 +58,8 @@ BPackageResolvableExpression::InitCheck() const return B_NO_INIT; // either both or none of operator and version must be set - if ((fOperator == B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT - && fVersion.InitCheck() == B_OK) - || (fOperator >= 0 && fOperator < B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT - && fVersion.InitCheck() != B_OK)) + if ((fOperator >= 0 && fOperator < B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT) + != (fVersion.InitCheck() == B_OK)) return B_NO_INIT; return B_OK; diff --git a/src/kits/package/PackageVersion.cpp b/src/kits/package/PackageVersion.cpp index 570c9b7e30..611f715f7e 100644 --- a/src/kits/package/PackageVersion.cpp +++ b/src/kits/package/PackageVersion.cpp @@ -8,6 +8,8 @@ #include +#include + using BPrivate::NaturalCompare; @@ -20,6 +22,16 @@ BPackageVersion::BPackageVersion() } +BPackageVersion::BPackageVersion(const BPackageVersionData& data) + : + fMajor(data.major), + fMinor(data.minor), + fMicro(data.micro), + fRelease(data.release) +{ +} + + BPackageVersion::BPackageVersion(const BString& major, const BString& minor, const BString& micro, uint8 release) : diff --git a/src/kits/package/RepositoryCache.cpp b/src/kits/package/RepositoryCache.cpp index f04a208c37..21baa6cf05 100644 --- a/src/kits/package/RepositoryCache.cpp +++ b/src/kits/package/RepositoryCache.cpp @@ -55,10 +55,10 @@ BRepositoryCache::Entry() const } -const BRepositoryHeader& -BRepositoryCache::Header() const +const BRepositoryInfo& +BRepositoryCache::Info() const { - return fHeader; + return fInfo; } @@ -90,7 +90,7 @@ BRepositoryCache::SetTo(const BEntry& entry) if ((result = headerMsg.Unflatten(&file)) != B_OK) return result; - if ((result = fHeader.SetTo(&headerMsg)) != B_OK) + if ((result = fInfo.SetTo(&headerMsg)) != B_OK) return result; BPath userSettingsPath; diff --git a/src/kits/package/RepositoryHeader.cpp b/src/kits/package/RepositoryHeader.cpp deleted file mode 100644 index 3694c876dc..0000000000 --- a/src/kits/package/RepositoryHeader.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright 2011, Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Oliver Tappe - */ - - -#include - -#include - - -namespace BPackageKit { - - -const uint8 BRepositoryHeader::kDefaultPriority = 50; - -const char* BRepositoryHeader::kNameField = "name"; -const char* BRepositoryHeader::kURLField = "url"; -const char* BRepositoryHeader::kVendorField = "vendor"; -const char* BRepositoryHeader::kShortDescriptionField = "shortDescr"; -const char* BRepositoryHeader::kLongDescriptionField = "longDescr"; -const char* BRepositoryHeader::kPriorityField = "priority"; - - -BRepositoryHeader::BRepositoryHeader() - : - fInitStatus(B_NO_INIT), - fPriority(kDefaultPriority) -{ -} - - -BRepositoryHeader::BRepositoryHeader(BMessage* data) - : - inherited(data) -{ - fInitStatus = SetTo(data); -} - - -BRepositoryHeader::~BRepositoryHeader() -{ -} - - -/*static*/ BRepositoryHeader* -BRepositoryHeader::Instantiate(BMessage* data) -{ - if (validate_instantiation(data, "BPackageKit::BRepositoryHeader")) - return new (std::nothrow) BRepositoryHeader(data); - - return NULL; -} - - -status_t -BRepositoryHeader::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, fOriginalBaseURL)) != B_OK) - return result; - if ((result = data->AddString(kVendorField, fVendor)) != B_OK) - return result; - result = data->AddString(kShortDescriptionField, fShortDescription); - if (result != B_OK) - return result; - result = data->AddString(kLongDescriptionField, fLongDescription); - if (result != B_OK) - return result; - if ((result = data->AddUInt8(kPriorityField, fPriority)) != B_OK) - return result; - - return B_OK; -} - - -status_t -BRepositoryHeader::InitCheck() const -{ - return fInitStatus; -} - - -status_t -BRepositoryHeader::SetTo(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, &fOriginalBaseURL)) != B_OK) - return result; - if ((result = data->FindString(kVendorField, &fVendor)) != B_OK) - return result; - result = data->FindString(kShortDescriptionField, &fShortDescription); - if (result != B_OK) - return result; - result = data->FindString(kLongDescriptionField, &fLongDescription); - if (result != B_OK) - return result; - if ((result = data->FindUInt8(kPriorityField, &fPriority)) != B_OK) - return result; - - return B_OK; -} - - -const BString& -BRepositoryHeader::Name() const -{ - return fName; -} - - -const BString& -BRepositoryHeader::OriginalBaseURL() const -{ - return fOriginalBaseURL; -} - - -const BString& -BRepositoryHeader::Vendor() const -{ - return fVendor; -} - - -const BString& -BRepositoryHeader::ShortDescription() const -{ - return fShortDescription; -} - - -const BString& -BRepositoryHeader::LongDescription() const -{ - return fLongDescription; -} - - -uint8 -BRepositoryHeader::Priority() const -{ - return fPriority; -} - - -void -BRepositoryHeader::SetName(const BString& name) -{ - fName = name; -} - - -void -BRepositoryHeader::SetOriginalBaseURL(const BString& url) -{ - fOriginalBaseURL = url; -} - - -void -BRepositoryHeader::SetVendor(const BString& vendor) -{ - fVendor = vendor; -} - - -void -BRepositoryHeader::SetShortDescription(const BString& description) -{ - fShortDescription = description; -} - - -void -BRepositoryHeader::SetLongDescription(const BString& description) -{ - fLongDescription = description; -} - - -void -BRepositoryHeader::SetPriority(uint8 priority) -{ - fPriority = priority; -} - - -} // namespace BPackageKit diff --git a/src/kits/package/RepositoryInfo.cpp b/src/kits/package/RepositoryInfo.cpp new file mode 100644 index 0000000000..cbb2bf896d --- /dev/null +++ b/src/kits/package/RepositoryInfo.cpp @@ -0,0 +1,284 @@ +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Oliver Tappe + */ + + +#include + +#include + +#include + +#include +#include + +#include + + +namespace BPackageKit { + + +const uint8 BRepositoryInfo::kDefaultPriority = 50; + +const char* BRepositoryInfo::kNameField = "name"; +const char* BRepositoryInfo::kURLField = "url"; +const char* BRepositoryInfo::kVendorField = "vendor"; +const char* BRepositoryInfo::kSummaryField = "summary"; +const char* BRepositoryInfo::kPriorityField = "priority"; +const char* BRepositoryInfo::kArchitectureField = "architecture"; + + +BRepositoryInfo::BRepositoryInfo() + : + fInitStatus(B_NO_INIT), + fPriority(kDefaultPriority), + fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT) +{ +} + + +BRepositoryInfo::BRepositoryInfo(BMessage* data) + : + inherited(data) +{ + fInitStatus = SetTo(data); +} + + +BRepositoryInfo::BRepositoryInfo(const BEntry& entry) +{ + SetTo(entry); +} + + +BRepositoryInfo::~BRepositoryInfo() +{ +} + + +/*static*/ BRepositoryInfo* +BRepositoryInfo::Instantiate(BMessage* data) +{ + if (validate_instantiation(data, "BPackageKit::BRepositoryInfo")) + return new (std::nothrow) BRepositoryInfo(data); + + return NULL; +} + + +status_t +BRepositoryInfo::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, fOriginalBaseURL)) != B_OK) + return result; + if ((result = data->AddString(kVendorField, fVendor)) != B_OK) + return result; + result = data->AddString(kSummaryField, fSummary); + if (result != B_OK) + return result; + if ((result = data->AddUInt8(kPriorityField, fPriority)) != B_OK) + return result; + if ((result = data->AddUInt8(kArchitectureField, fArchitecture)) != B_OK) + return result; + + return B_OK; +} + + +status_t +BRepositoryInfo::InitCheck() const +{ + return fInitStatus; +} + + +status_t +BRepositoryInfo::SetTo(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, &fOriginalBaseURL)) != B_OK) + return result; + if ((result = data->FindString(kVendorField, &fVendor)) != B_OK) + return result; + result = data->FindString(kSummaryField, &fSummary); + if (result != B_OK) + return result; + if ((result = data->FindUInt8(kPriorityField, &fPriority)) != B_OK) + return result; + result = data->FindUInt8(kArchitectureField, (uint8*)&fArchitecture); + if (result != B_OK) + return result; + + return B_OK; +} + + +status_t +BRepositoryInfo::SetTo(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) { + configString.UnlockBuffer(0); + 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* name = get_driver_parameter(settingsHandle, "name", NULL, NULL); + const char* url = get_driver_parameter(settingsHandle, "url", NULL, NULL); + const char* vendor + = get_driver_parameter(settingsHandle, "vendor", NULL, NULL); + const char* summary + = get_driver_parameter(settingsHandle, "summary", NULL, NULL); + const char* priorityString + = get_driver_parameter(settingsHandle, "priority", NULL, NULL); + const char* architectureString + = get_driver_parameter(settingsHandle, "architecture", NULL, NULL); + + unload_driver_settings(settingsHandle); + + if (name == NULL || *name == '\0' || url == NULL || *url == '\0' + || vendor == NULL || *vendor == '\0' + || summary == NULL || *summary == '\0' + || priorityString == NULL || *priorityString == '\0' + || architectureString == NULL || *architectureString == '\0') { + return B_BAD_DATA; + } + + BPackageArchitecture architecture; + if (BPackageInfo::GetArchitectureByName(architectureString, architecture) + != B_OK) { + return B_BAD_DATA; + } + + fName = name; + fOriginalBaseURL = url; + fVendor = vendor; + fSummary = summary; + fPriority = atoi(priorityString); + fArchitecture = architecture; + + fInitStatus = B_OK; + + return B_OK; +} + + +const BString& +BRepositoryInfo::Name() const +{ + return fName; +} + + +const BString& +BRepositoryInfo::OriginalBaseURL() const +{ + return fOriginalBaseURL; +} + + +const BString& +BRepositoryInfo::Vendor() const +{ + return fVendor; +} + + +const BString& +BRepositoryInfo::Summary() const +{ + return fSummary; +} + + +uint8 +BRepositoryInfo::Priority() const +{ + return fPriority; +} + + +BPackageArchitecture +BRepositoryInfo::Architecture() const +{ + return fArchitecture; +} + + +void +BRepositoryInfo::SetName(const BString& name) +{ + fName = name; +} + + +void +BRepositoryInfo::SetOriginalBaseURL(const BString& url) +{ + fOriginalBaseURL = url; +} + + +void +BRepositoryInfo::SetVendor(const BString& vendor) +{ + fVendor = vendor; +} + + +void +BRepositoryInfo::SetSummary(const BString& summary) +{ + fSummary = summary; +} + + +void +BRepositoryInfo::SetPriority(uint8 priority) +{ + fPriority = priority; +} + + +void +BRepositoryInfo::SetArchitecture(BPackageArchitecture architecture) +{ + fArchitecture = architecture; +} + + +} // namespace BPackageKit diff --git a/src/kits/package/hpkg/PackageReaderImpl.cpp b/src/kits/package/hpkg/PackageReaderImpl.cpp index 54bcfaa0a3..7b65655faf 100644 --- a/src/kits/package/hpkg/PackageReaderImpl.cpp +++ b/src/kits/package/hpkg/PackageReaderImpl.cpp @@ -1134,8 +1134,10 @@ PackageReaderImpl::_ParsePackageAttributes(AttributeHandlerContext* context) if (error != B_OK) return error; - if (tag == 0) - return B_OK; + if (tag == 0) { + return + context->packageContentHandler->HandlePackageAttributesDone(); + } switch (id) { case HPKG_PACKAGE_ATTRIBUTE_NAME: diff --git a/src/kits/package/hpkg/RepositoryWriter.cpp b/src/kits/package/hpkg/RepositoryWriter.cpp index 4712ac7854..34353b2eac 100644 --- a/src/kits/package/hpkg/RepositoryWriter.cpp +++ b/src/kits/package/hpkg/RepositoryWriter.cpp @@ -9,6 +9,7 @@ #include #include +#include namespace BPackageKit { @@ -16,9 +17,10 @@ namespace BPackageKit { namespace BHPKG { -BRepositoryWriter::BRepositoryWriter(BRepositoryWriterListener* listener) +BRepositoryWriter::BRepositoryWriter(BRepositoryWriterListener* listener, + const BRepositoryInfo* repositoryInfo) : - fImpl(new (std::nothrow) RepositoryWriterImpl(listener)) + fImpl(new (std::nothrow) RepositoryWriterImpl(listener, repositoryInfo)) { } diff --git a/src/kits/package/hpkg/RepositoryWriterImpl.cpp b/src/kits/package/hpkg/RepositoryWriterImpl.cpp index 0124097f97..846e95ba3f 100644 --- a/src/kits/package/hpkg/RepositoryWriterImpl.cpp +++ b/src/kits/package/hpkg/RepositoryWriterImpl.cpp @@ -8,12 +8,17 @@ #include #include +#include #include +#include +#include #include - -#include +#include +#include +#include +#include namespace BPackageKit { @@ -23,16 +28,28 @@ namespace BHPKG { namespace BPrivate { -RepositoryWriterImpl::RepositoryWriterImpl(BRepositoryWriterListener* listener) +using BPackageKit::BPrivate::GeneralFileChecksumAccessor; + + +struct RepositoryWriterImpl::PackageNameSet : public std::set { +}; + + +RepositoryWriterImpl::RepositoryWriterImpl(BRepositoryWriterListener* listener, + const BRepositoryInfo* repositoryInfo) : WriterImplBase(listener), - fListener(listener) + fListener(listener), + fRepositoryInfo(repositoryInfo), + fPackageCount(0), + fPackageNames(NULL) { } RepositoryWriterImpl::~RepositoryWriterImpl() { + delete fPackageNames; } @@ -40,6 +57,7 @@ status_t RepositoryWriterImpl::Init(const char* fileName) { try { + fPackageNames = new PackageNameSet(); return _Init(fileName); } catch (status_t error) { return error; @@ -78,6 +96,129 @@ RepositoryWriterImpl::Finish() } +status_t +RepositoryWriterImpl::HandleEntry(BPackageEntry* entry) +{ + return B_OK; +} + + +status_t +RepositoryWriterImpl::HandleEntryAttribute(BPackageEntry* entry, + BPackageEntryAttribute* attribute) +{ + return B_OK; +} + + +status_t +RepositoryWriterImpl::HandleEntryDone(BPackageEntry* entry) +{ + return B_OK; +} + + +status_t +RepositoryWriterImpl::HandlePackageAttribute( + const BPackageInfoAttributeValue& value) +{ + switch (value.attributeIndex) { + case B_PACKAGE_INFO_NAME: + fPackageInfo.SetName(value.string); + break; + + case B_PACKAGE_INFO_SUMMARY: + fPackageInfo.SetSummary(value.string); + break; + + case B_PACKAGE_INFO_DESCRIPTION: + fPackageInfo.SetDescription(value.string); + break; + + case B_PACKAGE_INFO_VENDOR: + { + fPackageInfo.SetVendor(value.string); + break; + } + + case B_PACKAGE_INFO_PACKAGER: + fPackageInfo.SetPackager(value.string); + break; + + case B_PACKAGE_INFO_FLAGS: + fPackageInfo.SetFlags(value.unsignedInt); + break; + + case B_PACKAGE_INFO_ARCHITECTURE: + { + fPackageInfo.SetArchitecture( + (BPackageArchitecture)value.unsignedInt); + break; + } + + case B_PACKAGE_INFO_VERSION: + fPackageInfo.SetVersion(value.version); + break; + + case B_PACKAGE_INFO_COPYRIGHTS: + fPackageInfo.AddCopyright(value.string); + break; + + case B_PACKAGE_INFO_LICENSES: + fPackageInfo.AddLicense(value.string); + break; + + case B_PACKAGE_INFO_PROVIDES: + fPackageInfo.AddProvides(value.resolvable); + break; + + case B_PACKAGE_INFO_REQUIRES: + fPackageInfo.AddRequires(value.resolvableExpression); + break; + + case B_PACKAGE_INFO_SUPPLEMENTS: + fPackageInfo.AddSupplements(value.resolvableExpression); + break; + + case B_PACKAGE_INFO_CONFLICTS: + fPackageInfo.AddConflicts(value.resolvableExpression); + break; + + case B_PACKAGE_INFO_FRESHENS: + fPackageInfo.AddFreshens(value.resolvableExpression); + break; + + case B_PACKAGE_INFO_REPLACES: + fPackageInfo.AddReplaces(value.string); + break; + + default: + fListener->PrintError( + "Invalid package attribute section: unexpected package " + "attribute index %d encountered\n", value.attributeIndex); + return B_BAD_DATA; + } + + return B_OK; +} + + +status_t +RepositoryWriterImpl::HandlePackageAttributesDone() +{ + status_t result = _RegisterCurrentPackageInfo(); + fPackageInfo.Clear(); + + return result; +} + + +void +RepositoryWriterImpl::HandleErrorOccurred() +{ +} + + status_t RepositoryWriterImpl::_Init(const char* fileName) { @@ -90,15 +231,24 @@ RepositoryWriterImpl::_Finish() { hpkg_repo_header header; - // write package attributes - off_t totalSize = _WritePackageAttributes(header); + // write repository header + ssize_t repositoryInfoLength; + status_t result = _WriteRepositoryInfo(repositoryInfoLength); + if (result != B_OK) + return result; - fListener->OnRepositorySizeInfo(sizeof(header), + header.repository_header_length + = B_HOST_TO_BENDIAN_INT32(repositoryInfoLength); + + // write package attributes + off_t totalSize = _WritePackageAttributes(header, + sizeof(header) + repositoryInfoLength); + + fListener->OnRepositorySizeInfo(sizeof(header), repositoryInfoLength, + fPackageCount, B_BENDIAN_TO_HOST_INT32(header.attributes_length_compressed), totalSize); - // prepare the header - // general header.magic = B_HOST_TO_BENDIAN_INT32(B_HPKG_REPO_MAGIC); header.header_size = B_HOST_TO_BENDIAN_INT16((uint16)sizeof(header)); @@ -116,17 +266,119 @@ RepositoryWriterImpl::_Finish() status_t RepositoryWriterImpl::_AddPackage(const BEntry& packageEntry) { -// TODO! + status_t result = packageEntry.InitCheck(); + if (result != B_OK) { + fListener->PrintError("entry not initialized!\n"); + return result; + } + + BPath packagePath; + if ((result = packageEntry.GetPath(&packagePath)) != B_OK) { + fListener->PrintError("can't get path for entry!\n"); + return result; + } + + BPackageReader packageReader(fListener); + if ((result = packageReader.Init(packagePath.Path())) != B_OK) { + fListener->PrintError("can't create package reader!\n"); + return result; + } + + fPackageInfo.Clear(); + + GeneralFileChecksumAccessor checksumAccessor(packageEntry); + BString checksum; + if ((result = checksumAccessor.GetChecksum(checksum)) != B_OK) { + fListener->PrintError("can't compute checksum!\n"); + return result; + } + fPackageInfo.SetChecksum(checksum); + + return packageReader.ParseContent(this); +} + + +status_t +RepositoryWriterImpl::_RegisterCurrentPackageInfo() +{ + status_t result = fPackageInfo.InitCheck(); + if (result != B_OK) { + fListener->PrintError("package %s has incomplete package-info!\n", + fPackageInfo.Name().String()); + return result; + } + + // reject package with a name that we've seen already + PackageNameSet::const_iterator namePos + = fPackageNames->find(fPackageInfo.Name()); + if (namePos != fPackageNames->end()) { + fListener->PrintError("package %s has already been added!\n", + fPackageInfo.Name().String()); + return B_NAME_IN_USE; + } + + // all packages must have the same vendor as the repository + const BString& expectedVendor = fRepositoryInfo->Vendor(); + if (fPackageInfo.Vendor().ICompare(expectedVendor) != 0) { + fListener->PrintError("package '%s' has unexpected vendor '%s' " + "(expected '%s')!\n", fPackageInfo.Name().String(), + fPackageInfo.Vendor().String(), expectedVendor.String()); + return B_BAD_DATA; + } + + // all packages must have an architecture that's compatible with the one + // used by the repository + BPackageArchitecture expectedArchitecture = fRepositoryInfo->Architecture(); + if (fPackageInfo.Architecture() != expectedArchitecture + && fPackageInfo.Architecture() != B_PACKAGE_ARCHITECTURE_ANY) { + fListener->PrintError( + "package '%s' has non-matching architecture '%s' " + "(expected '%s' or '%s')!\n", fPackageInfo.Name().String(), + BPackageInfo::kArchitectureNames[fPackageInfo.Architecture()], + BPackageInfo::kArchitectureNames[expectedArchitecture], + BPackageInfo::kArchitectureNames[B_PACKAGE_ARCHITECTURE_ANY] + ); + return B_BAD_DATA; + } + + fPackageNames->insert(fPackageInfo.Name()); + + RegisterPackageInfo(PackageAttributes(), fPackageInfo); + fPackageCount++; + fListener->OnPackageAdded(fPackageInfo); return B_OK; } +status_t +RepositoryWriterImpl::_WriteRepositoryInfo(ssize_t& _repositoryInfoLength) +{ + BMessage archive; + status_t result = fRepositoryInfo->Archive(&archive); + if (result != B_OK) { + fListener->PrintError("can't archive repository header!\n"); + return result; + } + + _repositoryInfoLength = archive.FlattenedSize(); + char buffer[_repositoryInfoLength]; + if ((result = archive.Flatten(buffer, _repositoryInfoLength)) != B_OK) { + fListener->PrintError("can't flatten repository header!\n"); + return result; + } + + off_t startOffset = sizeof(hpkg_repo_header); + WriteBuffer(buffer, _repositoryInfoLength, startOffset); + + return B_OK; +} + off_t -RepositoryWriterImpl::_WritePackageAttributes(hpkg_repo_header& header) +RepositoryWriterImpl::_WritePackageAttributes(hpkg_repo_header& header, + off_t startOffset) { // write the package attributes (zlib writer on top of a file writer) - off_t startOffset = sizeof(header); FDDataWriter realWriter(FD(), startOffset, fListener); ZlibDataWriter zlibWriter(&realWriter); SetDataWriter(&zlibWriter); diff --git a/src/tests/kits/package/make_repo.cpp b/src/tests/kits/package/make_repo.cpp index 896f3bca2f..4b0f442929 100644 --- a/src/tests/kits/package/make_repo.cpp +++ b/src/tests/kits/package/make_repo.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include using namespace BPackageKit; @@ -20,20 +20,20 @@ main(int argc, const char** argv) return 1; } - BRepositoryHeader repoHeader; - repoHeader.SetName(argv[1]); - repoHeader.SetOriginalBaseURL(argv[2]); - repoHeader.SetPriority(atoi(argv[3])); + BRepositoryInfo repoInfo; + repoInfo.SetName(argv[1]); + repoInfo.SetOriginalBaseURL(argv[2]); + repoInfo.SetPriority(atoi(argv[3])); - BMessage repoHeaderArchive; - status_t result = repoHeader.Archive(&repoHeaderArchive); + BMessage repoInfoArchive; + status_t result = repoInfo.Archive(&repoInfoArchive); if (result != B_OK) { fprintf(stderr, "couldn't archive repository-header\n"); return 1; } BFile output(argv[1], B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); - if ((result = repoHeaderArchive.Flatten(&output)) != B_OK) { + if ((result = repoInfoArchive.Flatten(&output)) != B_OK) { fprintf(stderr, "couldn't flatten repository-header archive\n"); return 1; }