HaikuDepot : More Backend Communications Improvements

* Further improves the logging and provides some
  basic performance numbers.
* Moves the bulk-load logic out of the data-model
  class.
* Introduces a state-machine for the bulk-load
  process so that it will be more easily able to be
  shifted to non-blocking IO when the HTTP libraries
  can do that.
* Implements concurrent loading of the bulk-data to
  hopefully improve lead time for icons and meta-data.
* Loads data to a temporary file and then moves to the
  final location in order to avoid partially written
  data in the cache.
* Handles situations where no network is available;
  prevents attempt to access the network.
* Allows bulk-load processes to be cancelled when the
  application quits.
* Introduces command-line arguments to help simulate
  scenarios to help with testing performance and
  network absence.
* Implements ordered insert and binary search in the
  'List' class + basic unit test.
This commit is contained in:
Andrew Lindesay 2017-12-19 20:56:53 +01:00
parent 11b65332b4
commit 3094fef308
47 changed files with 1549 additions and 953 deletions

View File

@ -69,6 +69,8 @@ Application HaikuDepot :
MarkupTextView.cpp
MessagePackageListener.cpp
Model.cpp
BulkLoadContext.cpp
BulkLoadStateMachine.cpp
PackageAction.cpp
PackageActionHandler.cpp
PackageContentsView.cpp
@ -98,6 +100,7 @@ Application HaikuDepot :
# network + server
AbstractServerProcess.cpp
AbstractSingleFileServerProcess.cpp
ServerSettings.cpp
WebAppInterface.cpp
PkgDataUpdateProcess.cpp

View File

@ -13,6 +13,9 @@
#include <SupportDefs.h>
#define BINARY_SEARCH_LINEAR_THRESHOLD 4
template <typename ItemType, bool PlainOldData, uint32 BlockSize = 8>
class List {
typedef List<ItemType, PlainOldData, BlockSize> SelfType;
@ -110,6 +113,30 @@ public:
return fCount;
}
/*! Note that the use of this method will depend on the list being ordered.
*/
inline int32 BinarySearch(const void* context,
int32 (*compareFunc)(const void* context, const ItemType& item))
{
if (fCount == 0)
return -1;
return _BinarySearchBounded(context, compareFunc, 0, fCount - 1);
}
inline bool AddOrdered(const ItemType& copyFrom,
int32 (*compareFunc)(const ItemType& one, const ItemType& two))
{
// special case
if (fCount == 0
|| compareFunc(copyFrom, ItemAtFast(fCount - 1)) > 0) {
return Add(copyFrom);
}
return _AddOrderedBounded(copyFrom, compareFunc, 0, fCount - 1);
}
inline bool Add(const ItemType& copyFrom)
{
if (_Resize(fCount + 1)) {
@ -229,6 +256,71 @@ public:
}
private:
inline int32 _BinarySearchLinearBounded(
const void* context,
int32 (*compareFunc)(const void* context, const ItemType& item),
int32 start, int32 end)
{
for(int32 i = start; i <= end; i++) {
if (compareFunc(context, ItemAtFast(i)) == 0)
return i;
}
return -1;
}
inline int32 _BinarySearchBounded(
const void* context,
int32 (*compareFunc)(const void* context, const ItemType& item),
int32 start, int32 end)
{
if (end - start < BINARY_SEARCH_LINEAR_THRESHOLD)
return _BinarySearchLinearBounded(context, compareFunc, start, end);
int32 mid = start + (end - start);
if (compareFunc(context, ItemAtFast(mid)) >= 0)
return _BinarySearchBounded(context, compareFunc, mid, end);
return _BinarySearchBounded(context, compareFunc, start, mid - 1);
}
inline bool _AddOrderedLinearBounded(
const ItemType& copyFrom,
int32 (*compareFunc)(const ItemType& one, const ItemType& two),
int32 start, int32 end)
{
for(int32 i = start; i <= (end + 1); i++) {
bool greaterBefore = (i == start)
|| (compareFunc(copyFrom, ItemAtFast(i - 1)) > 0);
if (greaterBefore) {
bool lessAfter = (i == end + 1)
|| (compareFunc(copyFrom, ItemAtFast(i)) <= 0);
if (lessAfter)
return Add(copyFrom, i);
}
}
printf("illegal state; unable to insert item into list\n");
exit(EXIT_FAILURE);
}
inline bool _AddOrderedBounded(
const ItemType& copyFrom,
int32 (*compareFunc)(const ItemType& one, const ItemType& two),
int32 start, int32 end)
{
if(end - start < BINARY_SEARCH_LINEAR_THRESHOLD)
return _AddOrderedLinearBounded(copyFrom, compareFunc, start, end);
int32 mid = start + (end - start);
if (compareFunc(copyFrom, ItemAtFast(mid)) >= 0)
return _AddOrderedBounded(copyFrom, compareFunc, mid, end);
return _AddOrderedBounded(copyFrom, compareFunc, start, mid - 1);
}
inline bool _Resize(uint32 count)
{
if (count > fAllocatedCount) {

View File

@ -15,10 +15,9 @@
#include "StorageUtils.h"
LocalIconStore::LocalIconStore()
LocalIconStore::LocalIconStore(const BPath& path)
{
if (_EnsureIconStoragePath(fIconStoragePath) != B_OK)
fprintf(stdout, "unable to setup icon storage\n");
fIconStoragePath = path;
}
@ -42,62 +41,26 @@ LocalIconStore::_HasIconStoragePath() const
status_t
LocalIconStore::TryFindIconPath(const BString& pkgName, BPath& path) const
{
if (_HasIconStoragePath()) {
BPath bestIconPath;
BPath iconPkgPath(fIconStoragePath);
bool exists;
bool isDir;
BPath bestIconPath;
BPath iconPkgPath(fIconStoragePath);
bool exists;
bool isDir;
if ( (iconPkgPath.Append("hicn") == B_OK)
&& (iconPkgPath.Append(pkgName) == B_OK)
&& (StorageUtils::ExistsDirectory(iconPkgPath, &exists, &isDir)
== B_OK)
&& exists
&& isDir
&& (_IdentifyBestIconFileAtDirectory(iconPkgPath, bestIconPath)
== B_OK)
) {
path = bestIconPath;
return B_OK;
}
}
path.Unset();
return B_FILE_NOT_FOUND;
}
void
LocalIconStore::UpdateFromServerIfNecessary() const
{
if (_HasIconStoragePath()) {
BPath iconStoragePath(fIconStoragePath);
ServerIconExportUpdateProcess service(iconStoragePath);
service.Run();
if (Logger::IsDebugEnabled()) {
printf("did update the icons from server\n");
}
}
}
status_t
LocalIconStore::_EnsureIconStoragePath(BPath& path) const
{
BPath iconStoragePath;
if (find_directory(B_USER_CACHE_DIRECTORY, &iconStoragePath) == B_OK
&& iconStoragePath.Append("HaikuDepot") == B_OK
&& iconStoragePath.Append("__allicons") == B_OK
&& create_directory(iconStoragePath.Path(), 0777) == B_OK) {
path.SetTo(iconStoragePath.Path());
if ( (iconPkgPath.Append("hicn") == B_OK)
&& (iconPkgPath.Append(pkgName) == B_OK)
&& (StorageUtils::ExistsObject(iconPkgPath, &exists, &isDir, NULL)
== B_OK)
&& exists
&& isDir
&& (_IdentifyBestIconFileAtDirectory(iconPkgPath, bestIconPath)
== B_OK)
) {
path = bestIconPath;
return B_OK;
}
path.Unset();
fprintf(stdout, "unable to find the user cache directory for icons");
return B_ERROR;
return B_FILE_NOT_FOUND;
}
@ -121,8 +84,8 @@ LocalIconStore::_IdentifyBestIconFileAtDirectory(const BPath& directory,
bool isDir;
if ( (workingPath.Append(iconLeafname) == B_OK
&& StorageUtils::ExistsDirectory(
workingPath, &exists, &isDir) == B_OK)
&& StorageUtils::ExistsObject(
workingPath, &exists, &isDir, NULL) == B_OK)
&& exists
&& !isDir) {
bestIconPath.SetTo(workingPath.Path());

View File

@ -16,15 +16,13 @@
class LocalIconStore {
public:
LocalIconStore();
LocalIconStore(const BPath& path);
virtual ~LocalIconStore();
status_t TryFindIconPath(const BString& pkgName,
BPath& path) const;
void UpdateFromServerIfNecessary() const;
private:
bool _HasIconStoragePath() const;
status_t _EnsureIconStoragePath(BPath& path) const;
status_t _IdentifyBestIconFileAtDirectory(
const BPath& directory,
BPath& bestIconPath) const;

View File

@ -2,8 +2,6 @@
* Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef LOGGER_H
#define LOGGER_H

View File

@ -23,8 +23,6 @@
#include <Path.h>
#include "Logger.h"
#include "PkgDataUpdateProcess.h"
#include "RepositoryDataUpdateProcess.h"
#include "StorageUtils.h"
@ -359,10 +357,7 @@ Model::Model()
fShowAvailablePackages(true),
fShowInstalledPackages(true),
fShowSourcePackages(false),
fShowDevelopPackages(false),
fPopulateAllPackagesThread(-1),
fStopPopulatingAllPackages(false)
fShowDevelopPackages(false)
{
_UpdateIsFeaturedFilter();
@ -417,7 +412,6 @@ Model::Model()
Model::~Model()
{
StopPopulatingAllPackages();
}
@ -701,7 +695,6 @@ Model::PopulatePackage(const PackageInfoRef& package, uint32 flags)
BMessage item;
if (items.FindMessage(name, &item) != B_OK)
break;
// item.PrintToStream();
BString user;
BMessage userInfo;
@ -768,32 +761,6 @@ Model::PopulatePackage(const PackageInfoRef& package, uint32 flags)
}
void
Model::PopulateAllPackages()
{
StopPopulatingAllPackages();
fStopPopulatingAllPackages = false;
fPopulateAllPackagesThread = spawn_thread(&_PopulateAllPackagesEntry,
"Package populator", B_NORMAL_PRIORITY, this);
if (fPopulateAllPackagesThread >= 0)
resume_thread(fPopulateAllPackagesThread);
}
void
Model::StopPopulatingAllPackages()
{
if (fPopulateAllPackagesThread < 0)
return;
fStopPopulatingAllPackages = true;
wait_for_thread(fPopulateAllPackagesThread, NULL);
fPopulateAllPackagesThread = -1;
}
void
Model::SetUsername(BString username)
{
@ -837,8 +804,6 @@ Model::SetAuthorization(const BString& username, const BString& password,
}
// #pragma mark - private
/*! When bulk repository data comes down from the server, it will
arrive as a json.gz payload. This is stored locally as a cache
and this method will provide the on-disk storage location for
@ -846,7 +811,7 @@ Model::SetAuthorization(const BString& username, const BString& password,
*/
status_t
Model::_DumpExportRepositoryDataPath(BPath& path) const
Model::DumpExportRepositoryDataPath(BPath& path) const
{
BPath repoDataPath;
@ -866,7 +831,26 @@ Model::_DumpExportRepositoryDataPath(BPath& path) const
status_t
Model::_DumpExportPkgDataPath(BPath& path,
Model::IconStoragePath(BPath& path) const
{
BPath iconStoragePath;
if (find_directory(B_USER_CACHE_DIRECTORY, &iconStoragePath) == B_OK
&& iconStoragePath.Append("HaikuDepot") == B_OK
&& iconStoragePath.Append("__allicons") == B_OK
&& create_directory(iconStoragePath.Path(), 0777) == B_OK) {
path.SetTo(iconStoragePath.Path());
return B_OK;
}
path.Unset();
fprintf(stdout, "unable to find the user cache directory for icons");
return B_ERROR;
}
status_t
Model::DumpExportPkgDataPath(BPath& path,
const BString& repositorySourceCode) const
{
BPath repoDataPath;
@ -889,24 +873,6 @@ Model::_DumpExportPkgDataPath(BPath& path,
}
status_t
Model::PopulateWebAppRepositoryCodes()
{
status_t result = B_OK;
BPath dataPath;
result = _DumpExportRepositoryDataPath(dataPath);
if (result != B_OK)
return result;
RepositoryDataUpdateProcess process(dataPath, &fDepots);
result = process.Run();
return result;
}
void
Model::_UpdateIsFeaturedFilter()
{
@ -917,141 +883,6 @@ Model::_UpdateIsFeaturedFilter()
}
int32
Model::_PopulateAllPackagesEntry(void* cookie)
{
Model* model = static_cast<Model*>(cookie);
model->_PopulateAllPackagesThread();
model->_PopulateAllPackagesIcons();
return 0;
}
void
Model::_PopulateAllPackagesIcons()
{
fLocalIconStore.UpdateFromServerIfNecessary();
int32 depotIndex = 0;
int32 packageIndex = 0;
int32 countIconsSet = 0;
fprintf(stdout, "will populate all packages' icons\n");
while (true) {
PackageInfoRef package;
BAutolock locker(&fLock);
if (depotIndex > fDepots.CountItems()) {
fprintf(stdout, "did populate %" B_PRId32 " packages' icons\n",
countIconsSet);
return;
}
const DepotInfo& depot = fDepots.ItemAt(depotIndex);
const PackageList& packages = depot.Packages();
if (packageIndex >= packages.CountItems()) {
// Need the next depot
packageIndex = 0;
depotIndex++;
} else {
package = packages.ItemAt(packageIndex);
if (Logger::IsDebugEnabled()) {
fprintf(stdout, "will populate package icon for [%s]\n",
package->Name().String());
}
if (_PopulatePackageIcon(package) == B_OK)
countIconsSet++;
packageIndex++;
}
}
}
void
Model::_PopulatePackagesForDepot(const DepotInfo& depotInfo)
{
BString repositorySourceCode = depotInfo.WebAppRepositorySourceCode();
BPath repositorySourcePkgDataPath;
if (B_OK != _DumpExportPkgDataPath(repositorySourcePkgDataPath,
repositorySourceCode)) {
printf("unable to obtain the path for storing data for [%s]\n",
repositorySourceCode.String());
} else {
printf("will fetch and process data for repository source [%s]\n",
repositorySourceCode.String());
PkgDataUpdateProcess process(
repositorySourcePkgDataPath,
fLock, repositorySourceCode, fPreferredLanguage,
depotInfo.Packages(),
fCategories);
process.Run();
printf("did fetch and process data for repository source [%s]\n",
repositorySourceCode.String());
}
}
void
Model::_PopulateAllPackagesThread()
{
int32 depotIndex = 0;
int32 count = 0;
for (depotIndex = 0;
depotIndex < fDepots.CountItems() && !fStopPopulatingAllPackages;
depotIndex++) {
const DepotInfo& depot = fDepots.ItemAt(depotIndex);
if (depot.WebAppRepositorySourceCode().Length() > 0) {
_PopulatePackagesForDepot(depot);
count++;
}
}
printf("did populate package data for %" B_PRIi32 " depots\n", count);
}
status_t
Model::_PopulatePackageIcon(const PackageInfoRef& package)
{
BPath bestIconPath;
if ( fLocalIconStore.TryFindIconPath(
package->Name(), bestIconPath) == B_OK) {
BFile bestIconFile(bestIconPath.Path(), O_RDONLY);
BitmapRef bitmapRef(new(std::nothrow)SharedBitmap(bestIconFile), true);
BAutolock locker(&fLock);
package->SetIcon(bitmapRef);
if (Logger::IsDebugEnabled()) {
fprintf(stdout, "have set the package icon for [%s] from [%s]\n",
package->Name().String(), bestIconPath.Path());
}
return B_OK;
}
if (Logger::IsDebugEnabled()) {
fprintf(stdout, "did not set the package icon for [%s]; no data\n",
package->Name().String());
}
return B_FILE_NOT_FOUND;
}
void
Model::_PopulatePackageScreenshot(const PackageInfoRef& package,
const ScreenshotInfo& info, int32 scaledWidth, bool fromCacheOnly)
@ -1128,3 +959,119 @@ Model::_NotifyAuthorizationChanged()
listener->AuthorizationChanged();
}
}
// temporary - should not be required once the repo info url is used.
static void
normalize_repository_base_url(BUrl& url)
{
if (url.Protocol() == "https")
url.SetProtocol("http");
BString path(url.Path());
if (path.EndsWith("/"))
url.SetPath(path.Truncate(path.Length() - 1));
}
void
Model::ForAllDepots(void (*func)(const DepotInfo& depot, void* context),
void* context)
{
for (int32 i = 0; i < fDepots.CountItems(); i++) {
DepotInfo depotInfo = fDepots.ItemAtFast(i);
func(depotInfo, context);
}
}
// TODO; should use the repo.info url and not the base url.
void
Model::ReplaceDepotByUrl(const BString& url,
DepotMapper* depotMapper, void* context)
{
for (int32 i = 0; i < fDepots.CountItems(); i++) {
DepotInfo depotInfo = fDepots.ItemAtFast(i);
BUrl url(url);
BUrl depotUrlNormalized(depotInfo.BaseURL());
normalize_repository_base_url(url);
normalize_repository_base_url(depotUrlNormalized);
if (url == depotUrlNormalized) {
BAutolock locker(&fLock);
fDepots.Replace(i, depotMapper->MapDepot(depotInfo, context));
}
}
}
void
Model::ForAllPackages(PackageConsumer* packageConsumer, void* context)
{
for (int32 i = 0; i < fDepots.CountItems(); i++) {
DepotInfo depotInfo = fDepots.ItemAtFast(i);
PackageList packages = depotInfo.Packages();
for(int32 j = 0; j < packages.CountItems(); j++) {
const PackageInfoRef& packageInfoRef = packages.ItemAtFast(j);
if (packageInfoRef != NULL) {
BAutolock locker(&fLock);
if (!packageConsumer->ConsumePackage(packageInfoRef, context))
return;
}
}
}
}
void
Model::ForPackageByNameInDepot(const BString& depotName,
const BString& packageName, PackageConsumer* packageConsumer, void* context)
{
int32 depotCount = fDepots.CountItems();
for (int32 i = 0; i < depotCount; i++) {
DepotInfo depotInfo = fDepots.ItemAtFast(i);
if (depotInfo.Name() == depotName) {
int32 packageIndex = depotInfo.PackageIndexByName(packageName);
if (-1 != packageIndex) {
PackageList packages = depotInfo.Packages();
const PackageInfoRef& packageInfoRef =
packages.ItemAtFast(packageIndex);
BAutolock locker(&fLock);
packageConsumer->ConsumePackage(packageInfoRef,
context);
}
return;
}
}
}
void
Model::LogDepotsWithNoWebAppRepositoryCode() const
{
int32 i;
for (i = 0; i < fDepots.CountItems(); i++) {
const DepotInfo& depot = fDepots.ItemAt(i);
if (depot.WebAppRepositoryCode().Length() == 0) {
printf("depot [%s]", depot.Name().String());
if (depot.BaseURL().Length() > 0)
printf(" (%s)", depot.BaseURL().String());
printf(" correlates with no repository in the haiku"
"depot server system\n");
}
}
}

View File

@ -9,7 +9,9 @@
#include <FindDirectory.h>
#include <Locker.h>
#include "AbstractServerProcess.h"
#include "LocalIconStore.h"
#include "BulkLoadContext.h"
#include "PackageInfo.h"
#include "WebAppInterface.h"
@ -37,6 +39,22 @@ public:
virtual void AuthorizationChanged() = 0;
};
class DepotMapper {
public:
virtual DepotInfo MapDepot(const DepotInfo& depot,
void* context) = 0;
};
class PackageConsumer {
public:
virtual bool ConsumePackage(
const PackageInfoRef& packageInfoRef,
void* context) = 0;
};
typedef BReference<ModelListener> ModelListenerRef;
typedef List<ModelListenerRef, false> ModelListenerList;
@ -118,8 +136,6 @@ public:
bool ShowDevelopPackages() const
{ return fShowDevelopPackages; }
status_t PopulateWebAppRepositoryCodes();
// Retrieve package information
static const uint32 POPULATE_CACHED_RATING = 1 << 0;
static const uint32 POPULATE_CACHED_ICON = 1 << 1;
@ -131,8 +147,6 @@ public:
void PopulatePackage(const PackageInfoRef& package,
uint32 flags);
void PopulateAllPackages();
void StopPopulatingAllPackages();
const StringList& SupportedLanguages() const
{ return fSupportedLanguages; }
@ -149,20 +163,41 @@ public:
const WebAppInterface& GetWebAppInterface() const
{ return fWebAppInterface; }
void ReplaceDepotByUrl(
const BString& url,
DepotMapper* depotMapper,
void* context);
void ForAllDepots(
void (*func)(const DepotInfo& depot,
void* context),
void* context);
void ForAllPackages(PackageConsumer* packageConsumer,
void* context);
void ForPackageByNameInDepot(
const BString& depotName,
const BString& packageName,
PackageConsumer* packageConsumer,
void* context);
status_t IconStoragePath(BPath& path) const;
status_t DumpExportRepositoryDataPath(BPath& path) const;
status_t DumpExportPkgDataPath(BPath& path,
const BString& repositorySourceCode) const;
void LogDepotsWithNoWebAppRepositoryCode() const;
private:
status_t _DumpExportRepositoryDataPath(
BPath& path) const;
status_t _DumpExportPkgDataPath(BPath& path,
const BString& repositorySourceCode) const;
void _UpdateIsFeaturedFilter();
static int32 _PopulateAllPackagesEntry(void* cookie);
void _PopulateAllPackagesThread();
void _PopulatePackagesForDepot(
const DepotInfo& depotInfo);
void _PopulateAllPackagesIcons();
void _PopulatePackageScreenshot(
const PackageInfoRef& package,
const ScreenshotInfo& info,
int32 scaledWidth, bool fromCacheOnly);
bool _GetCacheFile(BPath& path, BFile& file,
directory_which directory,
@ -175,14 +210,6 @@ private:
const char* fileName,
bool ignoreAge, time_t maxAge) const;
status_t _PopulatePackageIcon(
const PackageInfoRef& package);
void _PopulatePackageScreenshot(
const PackageInfoRef& package,
const ScreenshotInfo& info,
int32 scaledWidth,
bool fromCacheOnly);
void _NotifyAuthorizationChanged();
private:
@ -190,8 +217,6 @@ private:
DepotList fDepots;
LocalIconStore fLocalIconStore;
CategoryRef fCategoryAudio;
CategoryRef fCategoryBusiness;
CategoryRef fCategoryDevelopment;
@ -225,9 +250,6 @@ private:
bool fShowSourcePackages;
bool fShowDevelopPackages;
thread_id fPopulateAllPackagesThread;
volatile bool fStopPopulatingAllPackages;
StringList fSupportedLanguages;
BString fPreferredLanguage;

View File

@ -1,7 +1,7 @@
/*
* Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2013, Rene Gollent <rene@gollent.com>.
* Copyright 2016, Andrew Lindesay <apl@lindesay.co.nz>.
* Copyright 2016-2017, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
@ -1047,10 +1047,35 @@ DepotInfo::operator!=(const DepotInfo& other) const
}
static int32 PackageCompare(const PackageInfoRef& p1, const PackageInfoRef& p2)
{
return p1->Name().Compare(p2->Name());
}
/*! This method will insert the package into the list of packages
in order so that the list of packages remains in order.
*/
bool
DepotInfo::AddPackage(const PackageInfoRef& package)
{
return fPackages.Add(package);
return fPackages.AddOrdered(package, &PackageCompare);
}
static int32 PackageFixedNameCompare(const void* context,
const PackageInfoRef& package)
{
const BString* packageName = static_cast<BString*>(context);
return packageName->Compare(package->Name());
}
int32
DepotInfo::PackageIndexByName(const BString& packageName)
{
return fPackages.BinarySearch(&packageName, &PackageFixedNameCompare);
}

View File

@ -1,6 +1,6 @@
/*
* Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2016, Andrew Lindesay <apl@lindesay.co.nz>.
* Copyright 2016-2017, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_INFO_H
@ -411,6 +411,8 @@ public:
bool AddPackage(const PackageInfoRef& package);
int32 PackageIndexByName(const BString& packageName);
void SyncPackages(const PackageList& packages);
void SetBaseURL(const BString& baseURL);

View File

@ -4,13 +4,15 @@
*/
#include "AbstractServerProcess.h"
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <AutoDeleter.h>
#include <Autolock.h>
#include <FileIO.h>
#include <HttpRequest.h>
#include <HttpTime.h>
#include <Locker.h>
#include <UrlProtocolRoster.h>
#include <support/ZlibCompressionAlgorithm.h>
@ -18,6 +20,7 @@
#include "Logger.h"
#include "ServerSettings.h"
#include "StandardMetaDataJsonEventListener.h"
#include "StorageUtils.h"
#include "ToFileUrlProtocolListener.h"
@ -31,6 +34,140 @@
#define TIMEOUT_MICROSECONDS 3e+7
AbstractServerProcess::AbstractServerProcess(
AbstractServerProcessListener* listener, uint32 options)
:
fLock(),
fListener(listener),
fWasStopped(false),
fProcessState(SERVER_PROCESS_INITIAL),
fErrorStatus(B_OK),
fOptions(options),
fRequest(NULL)
{
}
AbstractServerProcess::~AbstractServerProcess()
{
}
bool
AbstractServerProcess::HasOption(uint32 flag)
{
return (fOptions & flag) == flag;
}
bool
AbstractServerProcess::ShouldAttemptNetworkDownload(bool hasDataAlready)
{
return
!HasOption(SERVER_PROCESS_NO_NETWORKING)
&& !(HasOption(SERVER_PROCESS_PREFER_CACHE) && hasDataAlready);
}
status_t
AbstractServerProcess::Run()
{
{
BAutolock locker(&fLock);
if (ProcessState() != SERVER_PROCESS_INITIAL) {
printf("cannot start server process as it is not idle");
return B_NOT_ALLOWED;
}
fProcessState = SERVER_PROCESS_RUNNING;
}
SetErrorStatus(RunInternal());
SetProcessState(SERVER_PROCESS_COMPLETE);
// this process may be part of a larger bulk-load process and
// if so, the process orchestration needs to know when this
// process has completed.
if (fListener != NULL)
fListener->ServerProcessExited();
return ErrorStatus();
}
bool
AbstractServerProcess::WasStopped()
{
BAutolock locker(&fLock);
return fWasStopped;
}
status_t
AbstractServerProcess::ErrorStatus()
{
BAutolock locker(&fLock);
return fErrorStatus;
}
status_t
AbstractServerProcess::Stop()
{
BAutolock locker(&fLock);
fWasStopped = true;
return StopInternal();
}
status_t
AbstractServerProcess::StopInternal()
{
if (fRequest != NULL) {
return fRequest->Stop();
}
return B_NOT_ALLOWED;
}
bool
AbstractServerProcess::IsRunning()
{
return ProcessState() == SERVER_PROCESS_RUNNING;
}
void
AbstractServerProcess::SetErrorStatus(status_t value)
{
BAutolock locker(&fLock);
if (fErrorStatus == B_OK) {
fErrorStatus = value;
}
}
void
AbstractServerProcess::SetProcessState(process_state value)
{
BAutolock locker(&fLock);
fProcessState = value;
}
process_state
AbstractServerProcess::ProcessState()
{
BAutolock locker(&fLock);
return fProcessState;
}
status_t
AbstractServerProcess::IfModifiedSinceHeaderValue(BString& headerValue) const
{
@ -74,8 +211,9 @@ AbstractServerProcess::IfModifiedSinceHeaderValue(BString& headerValue,
headerValue.SetTo(modifiedHttpTime
.ToString(BPrivate::B_HTTP_TIME_FORMAT_COOKIE));
} else {
fprintf(stderr, "unable to parse the meta-data date and time -"
" cannot set the 'If-Modified-Since' header\n");
fprintf(stderr, "unable to parse the meta-data date and time from [%s]"
" - cannot set the 'If-Modified-Since' header\n",
metaDataPath.Path());
}
return result;
@ -163,10 +301,52 @@ AbstractServerProcess::ParseJsonFromFileWithListener(
}
/*! In order to reduce the chance of failure half way through downloading a
large file, this method will download the file to a temporary file and
then it can rename the file to the final target file.
*/
status_t
AbstractServerProcess::DownloadToLocalFileAtomically(
const BPath& targetFilePath,
const BUrl& url)
{
BPath temporaryFilePath(tmpnam(NULL), NULL, true);
status_t result = DownloadToLocalFile(
temporaryFilePath, url, 0, 0);
// not copying if the data has not changed because the data will be
// zero length. This is if the result is APP_ERR_NOT_MODIFIED.
if (result == B_OK) {
// if the file is zero length then assume that something has
// gone wrong.
off_t size;
bool hasFile;
result = StorageUtils::ExistsObject(temporaryFilePath, &hasFile, NULL,
&size);
if (result == B_OK && hasFile && size > 0) {
if (rename(temporaryFilePath.Path(), targetFilePath.Path()) != 0) {
printf("[%s] did rename [%s] --> [%s]\n",
Name(), temporaryFilePath.Path(), targetFilePath.Path());
result = B_IO_ERROR;
}
}
}
return result;
}
status_t
AbstractServerProcess::DownloadToLocalFile(const BPath& targetFilePath,
const BUrl& url, uint32 redirects, uint32 failures)
{
if (WasStopped())
return B_CANCELED;
if (redirects > MAX_REDIRECTS) {
fprintf(stdout, "exceeded %d redirects --> failure\n", MAX_REDIRECTS);
return B_IO_ERROR;
@ -177,10 +357,10 @@ AbstractServerProcess::DownloadToLocalFile(const BPath& targetFilePath,
return B_IO_ERROR;
}
fprintf(stdout, "will stream '%s' to [%s]\n", url.UrlString().String(),
targetFilePath.Path());
fprintf(stdout, "[%s] will stream '%s' to [%s]\n",
Name(), url.UrlString().String(), targetFilePath.Path());
ToFileUrlProtocolListener listener(targetFilePath, LoggingName(),
ToFileUrlProtocolListener listener(targetFilePath, Name(),
Logger::IsTraceEnabled());
BHttpHeaders headers;
@ -195,57 +375,77 @@ AbstractServerProcess::DownloadToLocalFile(const BPath& targetFilePath,
headers.AddHeader("If-Modified-Since", ifModifiedSinceHeader);
}
BHttpRequest *request = dynamic_cast<BHttpRequest *>(
BUrlProtocolRoster::MakeRequest(url, &listener));
ObjectDeleter<BHttpRequest> requestDeleter(request);
request->SetHeaders(headers);
request->SetMaxRedirections(0);
request->SetTimeout(TIMEOUT_MICROSECONDS);
thread_id thread;
{
fRequest = dynamic_cast<BHttpRequest *>(
BUrlProtocolRoster::MakeRequest(url, &listener));
fRequest->SetHeaders(headers);
fRequest->SetMaxRedirections(0);
fRequest->SetTimeout(TIMEOUT_MICROSECONDS);
thread = fRequest->Run();
}
thread_id thread = request->Run();
wait_for_thread(thread, NULL);
const BHttpResult& result = dynamic_cast<const BHttpResult&>(
request->Result());
fRequest->Result());
int32 statusCode = result.StatusCode();
const BHttpHeaders responseHeaders = result.Headers();
const char *locationC = responseHeaders["Location"];
BString location;
if (locationC != NULL)
location.SetTo(locationC);
delete fRequest;
fRequest = NULL;
if (BHttpRequest::IsSuccessStatusCode(statusCode)) {
fprintf(stdout, "did complete streaming data\n");
fprintf(stdout, "[%s] did complete streaming data [%"
B_PRIdSSIZE " bytes]\n", Name(), listener.ContentLength());
return B_OK;
} else if (statusCode == HTTP_STATUS_NOT_MODIFIED) {
fprintf(stdout, "remote data has not changed since [%s]\n",
ifModifiedSinceHeader.String());
fprintf(stdout, "[%s] remote data has not changed since [%s]\n",
Name(), ifModifiedSinceHeader.String());
return APP_ERR_NOT_MODIFIED;
} else if (BHttpRequest::IsRedirectionStatusCode(statusCode)) {
const BHttpHeaders responseHeaders = result.Headers();
const char *locationValue = responseHeaders["Location"];
if (locationValue != NULL && strlen(locationValue) != 0) {
BUrl location(result.Url(), locationValue);
fprintf(stdout, "will redirect to; %s\n",
location.UrlString().String());
return DownloadToLocalFile(targetFilePath, location,
redirects + 1, 0);
if (location.Length() != 0) {
BUrl location(result.Url(), location);
fprintf(stdout, "[%s] will redirect to; %s\n",
Name(), location.UrlString().String());
return DownloadToLocalFile(targetFilePath, location,
redirects + 1, 0);
}
fprintf(stdout, "unable to find 'Location' header for redirect\n");
fprintf(stdout, "[%s] unable to find 'Location' header for redirect\n",
Name());
return B_IO_ERROR;
} else {
if (statusCode == 0 || (statusCode / 100) == 5) {
fprintf(stdout, "error response from server; %" B_PRId32 " --> "
fprintf(stdout, "error response from server [%" B_PRId32 "] --> "
"retry...\n", statusCode);
return DownloadToLocalFile(targetFilePath, url, redirects,
failures + 1);
}
fprintf(stdout, "unexpected response from server; %" B_PRId32 "\n",
statusCode);
fprintf(stdout, "[%s] unexpected response from server [%" B_PRId32 "]\n",
Name(), statusCode);
return B_IO_ERROR;
}
}
status_t
AbstractServerProcess::DeleteLocalFile(const BPath& currentFilePath)
{
if (0 == remove(currentFilePath.Path()))
return B_OK;
return B_IO_ERROR;
}
/*! When a file is damaged or corrupted in some way, the file should be 'moved
aside' so that it is not involved in the next update. This method will
create such an alternative 'damaged' file location and move this file to
@ -263,13 +463,19 @@ AbstractServerProcess::MoveDamagedFileAside(const BPath& currentFilePath)
damagedFilePath.Append(damagedLeaf.String());
if (0 != rename(currentFilePath.Path(), damagedFilePath.Path())) {
printf("unable to move damaged file [%s] aside to [%s]\n",
currentFilePath.Path(), damagedFilePath.Path());
printf("[%s] unable to move damaged file [%s] aside to [%s]\n",
Name(), currentFilePath.Path(), damagedFilePath.Path());
return B_IO_ERROR;
}
printf("did move damaged file [%s] aside to [%s]\n",
currentFilePath.Path(), damagedFilePath.Path());
printf("[%s] did move damaged file [%s] aside to [%s]\n",
Name(), currentFilePath.Path(), damagedFilePath.Path());
return B_OK;
}
bool
AbstractServerProcess::IsSuccess(status_t e) {
return e == B_OK || e == APP_ERR_NOT_MODIFIED;
}

View File

@ -6,26 +6,66 @@
#ifndef ABSTRACT_SERVER_PROCESS_H
#define ABSTRACT_SERVER_PROCESS_H
#include <HttpRequest.h>
#include <Json.h>
#include <String.h>
#include <Url.h>
#include "StandardMetaData.h"
#include "Stoppable.h"
#define APP_ERR_NOT_MODIFIED (B_APP_ERROR_BASE + 452)
#define APP_ERR_NOT_MODIFIED (B_APP_ERROR_BASE + 452)
#define APP_ERR_NO_DATA (B_APP_ERROR_BASE + 453)
class AbstractServerProcess {
typedef enum process_options {
SERVER_PROCESS_NO_NETWORKING = 1 << 0,
SERVER_PROCESS_PREFER_CACHE = 1 << 1,
SERVER_PROCESS_DROP_CACHE = 1 << 2
} process_options;
typedef enum process_state {
SERVER_PROCESS_INITIAL = 1,
SERVER_PROCESS_RUNNING = 2,
SERVER_PROCESS_COMPLETE = 3
} process_state;
/*! Clients are able to subclass from this 'interface' in order to accept
call-backs when a process has exited; either through success or through
failure.
*/
class AbstractServerProcessListener {
public:
virtual status_t Run() = 0;
virtual void ServerProcessExited() = 0;
};
class AbstractServerProcess : public Stoppable {
public:
AbstractServerProcess(
AbstractServerProcessListener* listener,
uint32 options);
virtual ~AbstractServerProcess();
virtual const char* Name() = 0;
status_t Run();
status_t Stop();
status_t ErrorStatus();
bool IsRunning();
bool WasStopped();
protected:
virtual status_t RunInternal() = 0;
virtual status_t StopInternal();
virtual void GetStandardMetaDataPath(
BPath& path) const = 0;
virtual void GetStandardMetaDataJsonPath(
BString& jsonPath) const = 0;
virtual const char* LoggingName() const = 0;
status_t IfModifiedSinceHeaderValue(
BString& headerValue) const;
@ -43,15 +83,41 @@ protected:
BJsonEventListener *listener,
const BPath& path) const;
status_t DownloadToLocalFileAtomically(
const BPath& targetFilePath,
const BUrl& url);
status_t DeleteLocalFile(const BPath& currentFilePath);
status_t MoveDamagedFileAside(
const BPath& currentFilePath);
bool HasOption(uint32 flag);
bool ShouldAttemptNetworkDownload(
bool hasDataAlready);
static bool IsSuccess(status_t e);
private:
BLocker fLock;
AbstractServerProcessListener*
fListener;
bool fWasStopped;
process_state fProcessState;
status_t fErrorStatus;
uint32 fOptions;
BHttpRequest* fRequest;
process_state ProcessState();
void SetErrorStatus(status_t value);
void SetProcessState(process_state value);
status_t DownloadToLocalFile(
const BPath& targetFilePath,
const BUrl& url,
uint32 redirects, uint32 failures);
status_t MoveDamagedFileAside(
const BPath& currentFilePath);
private:
bool LooksLikeGzip(const char *pathStr) const;
};

View File

@ -11,6 +11,7 @@
#include <Autolock.h>
#include <FileIO.h>
#include <support/StopWatch.h>
#include <Url.h>
#include "Logger.h"
@ -27,39 +28,46 @@
packages as they are parsed and processing them.
*/
class PackageFillingPkgListener : public DumpExportPkgListener {
class PackageFillingPkgListener :
public DumpExportPkgListener, public PackageConsumer {
public:
PackageFillingPkgListener(
const PackageList& packages,
const CategoryList& categories,
BLocker& lock);
PackageFillingPkgListener(Model *model,
BString& depotName, Stoppable* stoppable);
virtual ~PackageFillingPkgListener();
virtual void Handle(DumpExportPkg* item);
virtual bool ConsumePackage(const PackageInfoRef& package,
void *context);
virtual bool Handle(DumpExportPkg* item);
virtual void Complete();
uint32 Count();
private:
int32 IndexOfPackageByName(const BString& name) const;
int32 IndexOfCategoryByName(
const BString& name) const;
int32 IndexOfCategoryByCode(
const BString& code) const;
const PackageList& fPackages;
const CategoryList& fCategories;
BLocker& fLock;
BString fDepotName;
Model* fModel;
CategoryList fCategories;
Stoppable* fStoppable;
uint32 fCount;
bool fDebugEnabled;
};
PackageFillingPkgListener::PackageFillingPkgListener(
const PackageList& packages, const CategoryList& categories,
BLocker& lock)
PackageFillingPkgListener::PackageFillingPkgListener(Model* model,
BString& depotName, Stoppable* stoppable)
:
fPackages(packages),
fCategories(categories),
fLock(lock)
fDepotName(depotName),
fModel(model),
fStoppable(stoppable),
fCount(0),
fDebugEnabled(Logger::IsDebugEnabled())
{
fCategories = model->Categories();
}
@ -70,32 +78,14 @@ PackageFillingPkgListener::~PackageFillingPkgListener()
// TODO; performance could be improved by not needing the linear search
int32
PackageFillingPkgListener::IndexOfPackageByName(
const BString& name) const
{
int32 i;
for (i = 0; i < fPackages.CountItems(); i++) {
const PackageInfoRef& packageInfo = fPackages.ItemAt(i);
if (packageInfo->Name() == name)
return i;
}
return -1;
}
// TODO; performance could be improved by not needing the linear search
int32
inline int32
PackageFillingPkgListener::IndexOfCategoryByName(
const BString& name) const
{
int32 i;
int32 categoryCount = fCategories.CountItems();
for (i = 0; i < fCategories.CountItems(); i++) {
for (i = 0; i < categoryCount; i++) {
const CategoryRef categoryRef = fCategories.ItemAtFast(i);
if (categoryRef->Name() == name)
@ -106,81 +96,95 @@ PackageFillingPkgListener::IndexOfCategoryByName(
}
void
PackageFillingPkgListener::Handle(DumpExportPkg* pkg)
bool
PackageFillingPkgListener::ConsumePackage(const PackageInfoRef& package,
void *context)
{
BAutolock locker(fLock); // lock from the model.
int32 packageIndex = IndexOfPackageByName(*(pkg->Name()));
DumpExportPkg* pkg = static_cast<DumpExportPkg*>(context);
int32 i;
if (packageIndex == -1) {
printf("unable to find package data for pkg name [%s]\n",
pkg->Name()->String());
} else {
int32 i;
const PackageInfoRef& packageInfo = fPackages.ItemAt(packageIndex);
if (0 != pkg->CountPkgVersions()) {
if (0 != pkg->CountPkgVersions()) {
// this makes the assumption that the only version will be the
// latest one.
// this makes the assumption that the only version will be the
// latest one.
DumpExportPkgVersion* pkgVersion = pkg->PkgVersionsItemAt(0);
DumpExportPkgVersion* pkgVersion = pkg->PkgVersionsItemAt(0);
if (!pkgVersion->TitleIsNull())
package->SetTitle(*(pkgVersion->Title()));
if (!pkgVersion->TitleIsNull())
packageInfo->SetTitle(*(pkgVersion->Title()));
if (!pkgVersion->SummaryIsNull())
package->SetShortDescription(*(pkgVersion->Summary()));
if (!pkgVersion->SummaryIsNull())
packageInfo->SetShortDescription(*(pkgVersion->Summary()));
if (!pkgVersion->DescriptionIsNull())
package->SetFullDescription(*(pkgVersion->Description()));
if (!pkgVersion->DescriptionIsNull()) {
packageInfo->SetFullDescription(*(pkgVersion->Description()));
}
if (!pkgVersion->PayloadLengthIsNull())
package->SetSize(pkgVersion->PayloadLength());
}
if (!pkgVersion->PayloadLengthIsNull())
packageInfo->SetSize(pkgVersion->PayloadLength());
}
int32 countPkgCategories = pkg->CountPkgCategories();
for (i = 0; i < pkg->CountPkgCategories(); i++) {
BString* categoryCode = pkg->PkgCategoriesItemAt(i)->Code();
int categoryIndex = IndexOfCategoryByName(*(categoryCode));
for (i = 0; i < countPkgCategories; i++) {
BString* categoryCode = pkg->PkgCategoriesItemAt(i)->Code();
int categoryIndex = IndexOfCategoryByName(*(categoryCode));
if (categoryIndex == -1) {
printf("unable to find the category for [%s]\n",
categoryCode->String());
} else {
packageInfo->AddCategory(
fCategories.ItemAtFast(categoryIndex));
}
}
if (!pkg->DerivedRatingIsNull()) {
RatingSummary summary;
summary.averageRating = pkg->DerivedRating();
packageInfo->SetRatingSummary(summary);
}
if (!pkg->ProminenceOrderingIsNull()) {
packageInfo->SetProminence(pkg->ProminenceOrdering());
}
if (!pkg->PkgChangelogContentIsNull()) {
packageInfo->SetChangelog(*(pkg->PkgChangelogContent()));
}
for (i = 0; i < pkg->CountPkgScreenshots(); i++) {
DumpExportPkgScreenshot* screenshot = pkg->PkgScreenshotsItemAt(i);
packageInfo->AddScreenshotInfo(ScreenshotInfo(
*(screenshot->Code()),
static_cast<int32>(screenshot->Width()),
static_cast<int32>(screenshot->Height()),
static_cast<int32>(screenshot->Length())
));
}
if (Logger::IsDebugEnabled()) {
printf("did populate data for [%s]\n", pkg->Name()->String());
if (categoryIndex == -1) {
printf("unable to find the category for [%s]\n",
categoryCode->String());
} else {
package->AddCategory(
fCategories.ItemAtFast(categoryIndex));
}
}
if (!pkg->DerivedRatingIsNull()) {
RatingSummary summary;
summary.averageRating = pkg->DerivedRating();
package->SetRatingSummary(summary);
}
if (!pkg->ProminenceOrderingIsNull())
package->SetProminence(pkg->ProminenceOrdering());
if (!pkg->PkgChangelogContentIsNull())
package->SetChangelog(*(pkg->PkgChangelogContent()));
int32 countPkgScreenshots = pkg->CountPkgScreenshots();
for (i = 0; i < countPkgScreenshots; i++) {
DumpExportPkgScreenshot* screenshot = pkg->PkgScreenshotsItemAt(i);
package->AddScreenshotInfo(ScreenshotInfo(
*(screenshot->Code()),
static_cast<int32>(screenshot->Width()),
static_cast<int32>(screenshot->Height()),
static_cast<int32>(screenshot->Length())
));
}
if (fDebugEnabled) {
printf("did populate data for [%s] (%s)\n", pkg->Name()->String(),
fDepotName.String());
}
fCount++;
return !fStoppable->WasStopped();
}
uint32
PackageFillingPkgListener::Count()
{
return fCount;
}
bool
PackageFillingPkgListener::Handle(DumpExportPkg* pkg)
{
fModel->ForPackageByNameInDepot(fDepotName, *(pkg->Name()), this, pkg);
return !fStoppable->WasStopped();
}
@ -191,20 +195,22 @@ PackageFillingPkgListener::Complete()
PkgDataUpdateProcess::PkgDataUpdateProcess(
AbstractServerProcessListener* listener,
const BPath& localFilePath,
BLocker& lock,
BString repositorySourceCode,
BString naturalLanguageCode,
const PackageList& packages,
const CategoryList& categories)
BString repositorySourceCode,
BString depotName,
Model *model,
uint32 options)
:
AbstractSingleFileServerProcess(listener, options),
fLocalFilePath(localFilePath),
fNaturalLanguageCode(naturalLanguageCode),
fRepositorySourceCode(repositorySourceCode),
fPackages(packages),
fCategories(categories),
fLock(lock)
fModel(model),
fDepotName(depotName)
{
fName.SetToFormat("PkgDataUpdateProcess<%s>", depotName.String());
}
@ -213,53 +219,50 @@ PkgDataUpdateProcess::~PkgDataUpdateProcess()
}
status_t
PkgDataUpdateProcess::Run()
const char*
PkgDataUpdateProcess::Name()
{
printf("will fetch packages' data\n");
return fName.String();
}
BString
PkgDataUpdateProcess::UrlPathComponent()
{
BString urlPath;
urlPath.SetToFormat("/__pkg/all-%s-%s.json.gz",
fRepositorySourceCode.String(),
fNaturalLanguageCode.String());
return urlPath;
}
status_t result = DownloadToLocalFile(fLocalFilePath,
ServerSettings::CreateFullUrl(urlPath),
0, 0);
if (result == B_OK || result == APP_ERR_NOT_MODIFIED) {
printf("did fetch packages' data\n");
// now load the data in and process it.
printf("will process packages' data\n");
result = PopulateDataToDepots();
switch (result) {
case B_OK:
printf("did process packages' data\n");
break;
default:
MoveDamagedFileAside(fLocalFilePath);
break;
}
}
return result;
BPath&
PkgDataUpdateProcess::LocalPath()
{
return fLocalFilePath;
}
status_t
PkgDataUpdateProcess::PopulateDataToDepots()
PkgDataUpdateProcess::ProcessLocalData()
{
BStopWatch watch("PkgDataUpdateProcess::ProcessLocalData", true);
PackageFillingPkgListener* itemListener =
new PackageFillingPkgListener(fPackages, fCategories, fLock);
new PackageFillingPkgListener(fModel, fDepotName, this);
BulkContainerDumpExportPkgJsonListener* listener =
new BulkContainerDumpExportPkgJsonListener(itemListener);
status_t result = ParseJsonFromFileWithListener(listener, fLocalFilePath);
if (Logger::IsInfoEnabled()) {
double secs = watch.ElapsedTime() / 1000000.0;
fprintf(stdout, "[%s] did process %" B_PRIi32 " packages' data "
"in (%6.3g secs)\n", Name(), itemListener->Count(), secs);
}
if (B_OK != result)
return result;
@ -280,10 +283,3 @@ PkgDataUpdateProcess::GetStandardMetaDataJsonPath(
{
jsonPath.SetTo("$.info");
}
const char*
PkgDataUpdateProcess::LoggingName() const
{
return "pkg-data-update";
}

View File

@ -7,8 +7,9 @@
#define PACKAGE_DATA_UPDATE_PROCESS_H
#include "AbstractServerProcess.h"
#include "AbstractSingleFileServerProcess.h"
#include "Model.h"
#include "PackageInfo.h"
#include <File.h>
@ -17,34 +18,37 @@
#include <Url.h>
class PkgDataUpdateProcess : public AbstractServerProcess {
class PkgDataUpdateProcess : public AbstractSingleFileServerProcess {
public:
PkgDataUpdateProcess(
AbstractServerProcessListener* listener,
const BPath& localFilePath,
BLocker& lock,
BString naturalLanguageCode,
BString repositorySourceCode,
const PackageList& packages,
const CategoryList& categories);
BString depotName,
Model *model,
uint32 options);
virtual ~PkgDataUpdateProcess();
status_t Run();
const char* Name();
protected:
void GetStandardMetaDataPath(BPath& path) const;
void GetStandardMetaDataJsonPath(
BString& jsonPath) const;
const char* LoggingName() const;
BString UrlPathComponent();
status_t ProcessLocalData();
BPath& LocalPath();
private:
status_t PopulateDataToDepots();
BPath fLocalFilePath;
BString fNaturalLanguageCode;
BString fRepositorySourceCode;
const PackageList& fPackages;
const CategoryList& fCategories;
BLocker& fLock;
Model* fModel;
BString fDepotName;
BString fName;
};

View File

@ -14,6 +14,7 @@
#include "ServerSettings.h"
#include "StorageUtils.h"
#include "Logger.h"
#include "DumpExportRepository.h"
#include "DumpExportRepositorySource.h"
#include "DumpExportRepositoryJsonListener.h"
@ -25,13 +26,15 @@
from the server with the data about the depot.
*/
class DepotMatchingRepositoryListener : public DumpExportRepositoryListener {
class DepotMatchingRepositoryListener :
public DumpExportRepositoryListener, public DepotMapper {
public:
DepotMatchingRepositoryListener(
DepotList* depotList);
DepotMatchingRepositoryListener(Model* model,
Stoppable* stoppable);
virtual ~DepotMatchingRepositoryListener();
virtual void Handle(DumpExportRepository* item);
virtual DepotInfo MapDepot(const DepotInfo& depot, void *context);
virtual bool Handle(DumpExportRepository* item);
virtual void Complete();
private:
@ -43,15 +46,17 @@ private:
int32 IndexOfUnassociatedDepotByUrl(
const BString& url) const;
DepotList* fDepotList;
Model* fModel;
Stoppable* fStoppable;
};
DepotMatchingRepositoryListener::DepotMatchingRepositoryListener(
DepotList* depotList)
Model* model, Stoppable* stoppable)
:
fModel(model),
fStoppable(stoppable)
{
fDepotList = depotList;
}
@ -60,110 +65,86 @@ DepotMatchingRepositoryListener::~DepotMatchingRepositoryListener()
}
void
DepotMatchingRepositoryListener::NormalizeUrl(BUrl& url) const
struct repository_and_repository_source {
DumpExportRepository* repository;
DumpExportRepositorySource* repositorySource;
};
/*! This is invoked as a result of logic in 'Handle(..)' that requests that the
model call this method with the requested DepotInfo instance.
*/
DepotInfo
DepotMatchingRepositoryListener::MapDepot(const DepotInfo& depot, void *context)
{
if (url.Protocol() == "https")
url.SetProtocol("http");
repository_and_repository_source* repositoryAndRepositorySource =
(repository_and_repository_source*) context;
BString* repositoryCode =
repositoryAndRepositorySource->repository->Code();
BString* repositorySourceCode =
repositoryAndRepositorySource->repositorySource->Code();
BString path(url.Path());
DepotInfo modifiedDepotInfo(depot);
modifiedDepotInfo.SetWebAppRepositoryCode(BString(*repositoryCode));
modifiedDepotInfo.SetWebAppRepositorySourceCode(
BString(*repositorySourceCode));
if (path.EndsWith("/"))
url.SetPath(path.Truncate(path.Length() - 1));
if (Logger::IsDebugEnabled()) {
printf("associated dept [%s] (%s) with server repository "
"source [%s] (%s)\n", modifiedDepotInfo.Name().String(),
modifiedDepotInfo.BaseURL().String(),
repositorySourceCode->String(),
repositoryAndRepositorySource->repositorySource->Url()->String());
} else {
printf("associated depot [%s] with server repository source [%s]\n",
modifiedDepotInfo.Name().String(), repositorySourceCode->String());
}
return modifiedDepotInfo;
}
bool
DepotMatchingRepositoryListener::IsUnassociatedDepotByUrl(
const DepotInfo& depotInfo, const BString& urlStr) const
{
if (depotInfo.BaseURL().Length() > 0
&& depotInfo.WebAppRepositorySourceCode().Length() == 0) {
BUrl depotInfoBaseUrl(depotInfo.BaseURL());
BUrl url(urlStr);
NormalizeUrl(depotInfoBaseUrl);
NormalizeUrl(url);
if (depotInfoBaseUrl == url)
return true;
}
return false;
}
int32
DepotMatchingRepositoryListener::IndexOfUnassociatedDepotByUrl(
const BString& url) const
{
int32 i;
for (i = 0; i < fDepotList->CountItems(); i++) {
const DepotInfo& depot = fDepotList->ItemAt(i);
if (IsUnassociatedDepotByUrl(depot, url))
return i;
}
return -1;
}
void
DepotMatchingRepositoryListener::Handle(DumpExportRepository* repository)
{
int32 i;
for (i = 0; i < repository->CountRepositorySources(); i++) {
DumpExportRepositorySource *repositorySource =
repository_and_repository_source repositoryAndRepositorySource;
repositoryAndRepositorySource.repository = repository;
repositoryAndRepositorySource.repositorySource =
repository->RepositorySourcesItemAt(i);
int32 depotIndex = IndexOfUnassociatedDepotByUrl(
*(repositorySource->Url()));
if (depotIndex >= 0) {
DepotInfo modifiedDepotInfo(fDepotList->ItemAt(depotIndex));
modifiedDepotInfo.SetWebAppRepositoryCode(
BString(*(repository->Code())));
modifiedDepotInfo.SetWebAppRepositorySourceCode(
BString(*(repositorySource->Code())));
fDepotList->Replace(depotIndex, modifiedDepotInfo);
// TODO; replace with the repo info url
BString* url = repositoryAndRepositorySource.repositorySource->Url();
printf("associated depot [%s] with server"
" repository source [%s]\n", modifiedDepotInfo.Name().String(),
repositorySource->Code()->String());
if (url->Length() > 0) {
fModel->ReplaceDepotByUrl(*url, this,
&repositoryAndRepositorySource);
}
}
return !fStoppable->WasStopped();
}
void
DepotMatchingRepositoryListener::Complete()
{
int32 i;
for (i = 0; i < fDepotList->CountItems(); i++) {
const DepotInfo& depot = fDepotList->ItemAt(i);
if (depot.WebAppRepositoryCode().Length() == 0) {
printf("depot [%s]", depot.Name().String());
if (depot.BaseURL().Length() > 0)
printf(" (%s)", depot.BaseURL().String());
printf(" correlates with no repository in the haiku"
"depot server system\n");
}
}
}
RepositoryDataUpdateProcess::RepositoryDataUpdateProcess(
AbstractServerProcessListener* listener,
const BPath& localFilePath,
DepotList* depotList)
Model* model,
uint32 options)
:
AbstractSingleFileServerProcess(listener, options),
fLocalFilePath(localFilePath),
fModel(model)
{
fLocalFilePath = localFilePath;
fDepotList = depotList;
}
@ -172,46 +153,32 @@ RepositoryDataUpdateProcess::~RepositoryDataUpdateProcess()
}
status_t
RepositoryDataUpdateProcess::Run()
const char*
RepositoryDataUpdateProcess::Name()
{
printf("will fetch repositories data\n");
return "RepositoryDataUpdateProcess";
}
// TODO: add language ISO code to the path; just 'en' for now.
status_t result = DownloadToLocalFile(fLocalFilePath,
ServerSettings::CreateFullUrl("/__repository/all-en.json.gz"),
0, 0);
if (result == B_OK || result == APP_ERR_NOT_MODIFIED) {
printf("did fetch repositories data\n");
BString
RepositoryDataUpdateProcess::UrlPathComponent()
{
return BString("/__repository/all-en.json.gz");
}
// now load the data in and process it.
printf("will process repository data and match to depots\n");
result = PopulateDataToDepots();
switch (result) {
case B_OK:
printf("did process repository data and match to depots\n");
break;
default:
MoveDamagedFileAside(fLocalFilePath);
break;
}
} else {
printf("an error has arisen downloading the repositories' data\n");
}
return result;
BPath&
RepositoryDataUpdateProcess::LocalPath()
{
return fLocalFilePath;
}
status_t
RepositoryDataUpdateProcess::PopulateDataToDepots()
RepositoryDataUpdateProcess::ProcessLocalData()
{
DepotMatchingRepositoryListener* itemListener =
new DepotMatchingRepositoryListener(fDepotList);
new DepotMatchingRepositoryListener(fModel, this);
BulkContainerDumpExportRepositoryJsonListener* listener =
new BulkContainerDumpExportRepositoryJsonListener(itemListener);
@ -238,10 +205,3 @@ RepositoryDataUpdateProcess::GetStandardMetaDataJsonPath(
{
jsonPath.SetTo("$.info");
}
const char*
RepositoryDataUpdateProcess::LoggingName() const
{
return "repo-data-update";
}

View File

@ -7,8 +7,9 @@
#define REPOSITORY_DATA_UPDATE_PROCESS_H
#include "AbstractServerProcess.h"
#include "AbstractSingleFileServerProcess.h"
#include "Model.h"
#include "PackageInfo.h"
#include <File.h>
@ -17,27 +18,29 @@
#include <Url.h>
class RepositoryDataUpdateProcess : public AbstractServerProcess {
class RepositoryDataUpdateProcess : public AbstractSingleFileServerProcess {
public:
RepositoryDataUpdateProcess(
AbstractServerProcessListener* listener,
const BPath& localFilePath,
DepotList* depotList);
Model* model, uint32 options);
virtual ~RepositoryDataUpdateProcess();
status_t Run();
const char* Name();
protected:
void GetStandardMetaDataPath(BPath& path) const;
void GetStandardMetaDataJsonPath(
BString& jsonPath) const;
const char* LoggingName() const;
BString UrlPathComponent();
status_t ProcessLocalData();
BPath& LocalPath();
private:
status_t PopulateDataToDepots();
BPath fLocalFilePath;
DepotList* fDepotList;
Model* fModel;
};

View File

@ -9,9 +9,12 @@
#include <sys/stat.h>
#include <time.h>
#include <Autolock.h>
#include <FileIO.h>
#include <support/StopWatch.h>
#include <support/ZlibCompressionAlgorithm.h>
#include "Logger.h"
#include "ServerSettings.h"
#include "StorageUtils.h"
#include "TarArchiveService.h"
@ -20,9 +23,17 @@
/*! This constructor will locate the cached data in a standardized location */
ServerIconExportUpdateProcess::ServerIconExportUpdateProcess(
const BPath& localStorageDirectoryPath)
AbstractServerProcessListener* listener,
const BPath& localStorageDirectoryPath,
Model* model,
uint32 options)
:
AbstractServerProcess(listener, options),
fLocalStorageDirectoryPath(localStorageDirectoryPath),
fModel(model),
fLocalIconStore(LocalIconStore(localStorageDirectoryPath)),
fCountIconsSet(0)
{
fLocalStorageDirectoryPath = localStorageDirectoryPath;
}
@ -31,8 +42,106 @@ ServerIconExportUpdateProcess::~ServerIconExportUpdateProcess()
}
const char*
ServerIconExportUpdateProcess::Name()
{
return "ServerIconExportUpdateProcess";
}
status_t
ServerIconExportUpdateProcess::Run()
ServerIconExportUpdateProcess::RunInternal()
{
status_t result = B_OK;
if (IsSuccess(result) && HasOption(SERVER_PROCESS_DROP_CACHE)) {
result = StorageUtils::RemoveDirectoryContents(
fLocalStorageDirectoryPath);
}
if (IsSuccess(result)) {
bool hasData;
result = HasLocalData(&hasData);
if (IsSuccess(result) && ShouldAttemptNetworkDownload(hasData))
result = DownloadAndUnpack();
if (IsSuccess(result)) {
status_t hasDataResult = HasLocalData(&hasData);
if (IsSuccess(hasDataResult) && !hasData)
result = APP_ERR_NO_DATA;
}
}
if (IsSuccess(result) && !WasStopped())
result = Populate();
return result;
}
status_t
ServerIconExportUpdateProcess::PopulateForPkg(const PackageInfoRef& package)
{
BPath bestIconPath;
if ( fLocalIconStore.TryFindIconPath(
package->Name(), bestIconPath) == B_OK) {
BFile bestIconFile(bestIconPath.Path(), O_RDONLY);
BitmapRef bitmapRef(new(std::nothrow)SharedBitmap(bestIconFile), true);
// TODO; somehow handle the locking!
//BAutolock locker(&fLock);
package->SetIcon(bitmapRef);
if (Logger::IsDebugEnabled()) {
fprintf(stdout, "have set the package icon for [%s] from [%s]\n",
package->Name().String(), bestIconPath.Path());
}
fCountIconsSet++;
return B_OK;
}
if (Logger::IsDebugEnabled()) {
fprintf(stdout, "did not set the package icon for [%s]; no data\n",
package->Name().String());
}
return B_FILE_NOT_FOUND;
}
bool
ServerIconExportUpdateProcess::ConsumePackage(
const PackageInfoRef& packageInfoRef, void* context)
{
PopulateForPkg(packageInfoRef);
return !WasStopped();
}
status_t
ServerIconExportUpdateProcess::Populate()
{
BStopWatch watch("ServerIconExportUpdateProcess::Populate", true);
fModel->ForAllPackages(this, NULL);
if (Logger::IsInfoEnabled()) {
double secs = watch.ElapsedTime() / 1000000.0;
fprintf(stdout, "did populate %" B_PRId32 " packages' icons"
" (%6.3g secs)\n", fCountIconsSet, secs);
}
return B_OK;
}
status_t
ServerIconExportUpdateProcess::DownloadAndUnpack()
{
BPath tarGzFilePath(tmpnam(NULL));
status_t result = B_OK;
@ -59,10 +168,15 @@ ServerIconExportUpdateProcess::Run()
zlibDecompressionParameters, tarIn);
if (result == B_OK) {
BStopWatch watch("ServerIconExportUpdateProcess::DownloadAndUnpack_Unpack", true);
result = TarArchiveService::Unpack(*tarIn,
fLocalStorageDirectoryPath);
fLocalStorageDirectoryPath, NULL);
if (result == B_OK) {
double secs = watch.ElapsedTime() / 1000000.0;
fprintf(stdout, "did unpack icon tgz in (%6.3g secs)\n", secs);
if (0 != remove(tarGzFilePath.Path())) {
fprintf(stdout, "unable to delete the temporary tgz path; "
"%s\n", tarGzFilePath.Path());
@ -79,6 +193,17 @@ ServerIconExportUpdateProcess::Run()
}
status_t
ServerIconExportUpdateProcess::HasLocalData(bool* result) const
{
BPath path;
off_t size;
GetStandardMetaDataPath(path);
return StorageUtils::ExistsObject(path, result, NULL, &size)
&& size > 0;
}
void
ServerIconExportUpdateProcess::GetStandardMetaDataPath(BPath& path) const
{
@ -96,16 +221,9 @@ ServerIconExportUpdateProcess::GetStandardMetaDataJsonPath(
}
const char*
ServerIconExportUpdateProcess::LoggingName() const
{
return "icon-export-update";
}
status_t
ServerIconExportUpdateProcess::Download(BPath& tarGzFilePath)
{
return DownloadToLocalFile(tarGzFilePath,
ServerSettings::CreateFullUrl("/__pkgicon/all.tar.gz"), 0, 0);
return DownloadToLocalFileAtomically(tarGzFilePath,
ServerSettings::CreateFullUrl("/__pkgicon/all.tar.gz"));
}

View File

@ -8,6 +8,8 @@
#include "AbstractServerProcess.h"
#include "LocalIconStore.h"
#include "Model.h"
#include <File.h>
#include <Path.h>
@ -15,26 +17,37 @@
#include <Url.h>
class ServerIconExportUpdateProcess : public AbstractServerProcess {
class ServerIconExportUpdateProcess :
public AbstractServerProcess, public PackageConsumer {
public:
ServerIconExportUpdateProcess(
const BPath& localStorageDirectoryPath);
AbstractServerProcessListener* listener,
const BPath& localStorageDirectoryPath,
Model* model, uint32 options);
virtual ~ServerIconExportUpdateProcess();
status_t Run();
const char* Name();
status_t RunInternal();
virtual bool ConsumePackage(
const PackageInfoRef& packageInfoRef,
void *context);
protected:
status_t PopulateForPkg(const PackageInfoRef& package);
status_t Populate();
status_t DownloadAndUnpack();
status_t HasLocalData(bool* result) const;
void GetStandardMetaDataPath(BPath& path) const;
void GetStandardMetaDataJsonPath(
BString& jsonPath) const;
const char* LoggingName() const;
private:
status_t Download(BPath& tarGzFilePath);
BPath fLocalStorageDirectoryPath;
Model* fModel;
LocalIconStore fLocalIconStore;
int32 fCountIconsSet;
};

View File

@ -21,6 +21,9 @@
BUrl ServerSettings::sBaseUrl = BUrl(BASEURL_DEFAULT);
BString ServerSettings::sUserAgent = BString();
pthread_once_t ServerSettings::sUserAgentInitOnce = PTHREAD_ONCE_INIT;
bool ServerSettings::sPreferCache = false;
bool ServerSettings::sDropCache = false;
bool ServerSettings::sForceNoNetwork = false;
status_t
@ -102,6 +105,7 @@ ServerSettings::_GetUserAgentVersionString()
return result;
}
void
ServerSettings::AugmentHeaders(BHttpHeaders& headers)
{
@ -109,3 +113,43 @@ ServerSettings::AugmentHeaders(BHttpHeaders& headers)
}
bool
ServerSettings::PreferCache()
{
return sPreferCache;
}
void
ServerSettings::SetPreferCache(bool value)
{
sPreferCache = value;
}
bool
ServerSettings::DropCache()
{
return sDropCache;
}
void
ServerSettings::SetDropCache(bool value)
{
sDropCache = value;
}
bool
ServerSettings::ForceNoNetwork()
{
return sForceNoNetwork;
}
void
ServerSettings::SetForceNoNetwork(bool value)
{
sForceNoNetwork = value;
}

View File

@ -20,6 +20,13 @@ public:
static BUrl CreateFullUrl(
const BString urlPathComponents);
static bool PreferCache();
static void SetPreferCache(bool value);
static bool DropCache();
static void SetDropCache(bool value);
static bool ForceNoNetwork();
static void SetForceNoNetwork(bool value);
private:
static void _InitUserAgent();
static const BString _GetUserAgentVersionString();
@ -27,6 +34,9 @@ private:
static BUrl sBaseUrl;
static BString sUserAgent;
static pthread_once_t sUserAgentInitOnce;
static bool sPreferCache;
static bool sDropCache;
static bool sForceNoNetwork;
};
#endif // SERVER_SETTINGS_H

View File

@ -1,7 +1,7 @@
/*
* Generated Model Object
* source json-schema : dumpexport.json
* generated at : 2017-11-05T22:30:10.254264
* generated at : 2017-12-07T23:22:17.116794
*/
#include "DumpExportPkg.h"

View File

@ -1,7 +1,7 @@
/*
* Generated Model Object
* source json-schema : dumpexport.json
* generated at : 2017-11-05T22:30:10.253178
* generated at : 2017-12-07T23:22:17.115160
*/
#ifndef GEN_JSON_SCHEMA_MODEL__DUMPEXPORTPKG_H

View File

@ -1,7 +1,7 @@
/*
* Generated Model Object
* source json-schema : dumpexport.json
* generated at : 2017-11-05T22:30:10.260503
* generated at : 2017-12-07T23:22:17.118616
*/
#include "DumpExportPkgCategory.h"

View File

@ -1,7 +1,7 @@
/*
* Generated Model Object
* source json-schema : dumpexport.json
* generated at : 2017-11-05T22:30:10.259170
* generated at : 2017-12-07T23:22:17.118521
*/
#ifndef GEN_JSON_SCHEMA_MODEL__DUMPEXPORTPKGCATEGORY_H

View File

@ -1,7 +1,7 @@
/*
* Generated Listener Object
* source json-schema : dumpexport.json
* generated at : 2017-11-11T14:09:03.498648
* generated at : 2017-12-17T20:45:25.516772
*/
#include "DumpExportPkgJsonListener.h"
#include "List.h"
@ -10,11 +10,11 @@
// #pragma mark - private interfaces for the stacked listeners
/*! This class is the top level of the stacked listeners. The stack structure
is maintained in a linked list and sub-classes implement specific behaviors
depending where in the parse tree the stacked listener is working at.
*/
*/
class AbstractStackedDumpExportPkgJsonListener : public BJsonEventListener {
public:
AbstractStackedDumpExportPkgJsonListener(
@ -29,14 +29,14 @@ public:
AbstractStackedDumpExportPkgJsonListener* Parent();
virtual void WillPop();
virtual bool WillPop();
protected:
AbstractMainDumpExportPkgJsonListener* fMainListener;
void Pop();
bool Pop();
void Push(AbstractStackedDumpExportPkgJsonListener* stackedListener);
private:
AbstractStackedDumpExportPkgJsonListener* fParent;
};
@ -47,7 +47,7 @@ public:
AbstractMainDumpExportPkgJsonListener* mainListener,
AbstractStackedDumpExportPkgJsonListener* parent);
~GeneralArrayStackedDumpExportPkgJsonListener();
bool Handle(const BJsonEvent& event);
};
@ -57,7 +57,7 @@ public:
AbstractMainDumpExportPkgJsonListener* mainListener,
AbstractStackedDumpExportPkgJsonListener* parent);
~GeneralObjectStackedDumpExportPkgJsonListener();
bool Handle(const BJsonEvent& event);
};
@ -67,11 +67,11 @@ public:
AbstractMainDumpExportPkgJsonListener* mainListener,
AbstractStackedDumpExportPkgJsonListener* parent);
~DumpExportPkg_StackedDumpExportPkgJsonListener();
bool Handle(const BJsonEvent& event);
DumpExportPkg* Target();
protected:
DumpExportPkg* fTarget;
BString fNextItemName;
@ -83,11 +83,11 @@ public:
AbstractMainDumpExportPkgJsonListener* mainListener,
AbstractStackedDumpExportPkgJsonListener* parent);
~DumpExportPkg_List_StackedDumpExportPkgJsonListener();
bool Handle(const BJsonEvent& event);
List<DumpExportPkg*, true>* Target(); // list of %s pointers
private:
List<DumpExportPkg*, true>* fTarget;
};
@ -98,11 +98,11 @@ public:
AbstractMainDumpExportPkgJsonListener* mainListener,
AbstractStackedDumpExportPkgJsonListener* parent);
~DumpExportPkgVersion_StackedDumpExportPkgJsonListener();
bool Handle(const BJsonEvent& event);
DumpExportPkgVersion* Target();
protected:
DumpExportPkgVersion* fTarget;
BString fNextItemName;
@ -114,11 +114,11 @@ public:
AbstractMainDumpExportPkgJsonListener* mainListener,
AbstractStackedDumpExportPkgJsonListener* parent);
~DumpExportPkgVersion_List_StackedDumpExportPkgJsonListener();
bool Handle(const BJsonEvent& event);
List<DumpExportPkgVersion*, true>* Target(); // list of %s pointers
private:
List<DumpExportPkgVersion*, true>* fTarget;
};
@ -129,11 +129,11 @@ public:
AbstractMainDumpExportPkgJsonListener* mainListener,
AbstractStackedDumpExportPkgJsonListener* parent);
~DumpExportPkgScreenshot_StackedDumpExportPkgJsonListener();
bool Handle(const BJsonEvent& event);
DumpExportPkgScreenshot* Target();
protected:
DumpExportPkgScreenshot* fTarget;
BString fNextItemName;
@ -145,11 +145,11 @@ public:
AbstractMainDumpExportPkgJsonListener* mainListener,
AbstractStackedDumpExportPkgJsonListener* parent);
~DumpExportPkgScreenshot_List_StackedDumpExportPkgJsonListener();
bool Handle(const BJsonEvent& event);
List<DumpExportPkgScreenshot*, true>* Target(); // list of %s pointers
private:
List<DumpExportPkgScreenshot*, true>* fTarget;
};
@ -160,11 +160,11 @@ public:
AbstractMainDumpExportPkgJsonListener* mainListener,
AbstractStackedDumpExportPkgJsonListener* parent);
~DumpExportPkgCategory_StackedDumpExportPkgJsonListener();
bool Handle(const BJsonEvent& event);
DumpExportPkgCategory* Target();
protected:
DumpExportPkgCategory* fTarget;
BString fNextItemName;
@ -176,11 +176,11 @@ public:
AbstractMainDumpExportPkgJsonListener* mainListener,
AbstractStackedDumpExportPkgJsonListener* parent);
~DumpExportPkgCategory_List_StackedDumpExportPkgJsonListener();
bool Handle(const BJsonEvent& event);
List<DumpExportPkgCategory*, true>* Target(); // list of %s pointers
private:
List<DumpExportPkgCategory*, true>* fTarget;
};
@ -192,9 +192,9 @@ public:
AbstractStackedDumpExportPkgJsonListener* parent,
DumpExportPkgListener* itemListener);
~ItemEmittingStackedDumpExportPkgJsonListener();
void WillPop();
bool WillPop();
private:
DumpExportPkgListener* fItemListener;
};
@ -207,9 +207,9 @@ public:
AbstractStackedDumpExportPkgJsonListener* parent,
DumpExportPkgListener* itemListener);
~BulkContainerStackedDumpExportPkgJsonListener();
bool Handle(const BJsonEvent& event);
private:
BString fNextItemName;
DumpExportPkgListener* fItemListener;
@ -223,10 +223,10 @@ public:
AbstractStackedDumpExportPkgJsonListener* parent,
DumpExportPkgListener* itemListener);
~BulkContainerItemsStackedDumpExportPkgJsonListener();
bool Handle(const BJsonEvent& event);
void WillPop();
bool WillPop();
private:
DumpExportPkgListener* fItemListener;
};
@ -275,16 +275,18 @@ AbstractStackedDumpExportPkgJsonListener::Push(AbstractStackedDumpExportPkgJsonL
fMainListener->SetStackedListener(stackedListener);
}
void
bool
AbstractStackedDumpExportPkgJsonListener::WillPop()
{
return true;
}
void
bool
AbstractStackedDumpExportPkgJsonListener::Pop()
{
WillPop();
bool result = WillPop();
fMainListener->SetStackedListener(fParent);
return result;
}
GeneralObjectStackedDumpExportPkgJsonListener::GeneralObjectStackedDumpExportPkgJsonListener(
@ -312,29 +314,28 @@ GeneralObjectStackedDumpExportPkgJsonListener::Handle(const BJsonEvent& event)
case B_JSON_NULL:
// ignore
break;
case B_JSON_OBJECT_START:
Push(new GeneralObjectStackedDumpExportPkgJsonListener(fMainListener, this));
break;
case B_JSON_ARRAY_START:
Push(new GeneralArrayStackedDumpExportPkgJsonListener(fMainListener, this));
break;
case B_JSON_ARRAY_END:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE, "illegal state - unexpected end of array");
break;
case B_JSON_OBJECT_END:
{
Pop();
bool status = (ErrorStatus() == B_OK);
bool status = Pop() && (ErrorStatus() == B_OK);
delete this;
return status;
}
}
return ErrorStatus() == B_OK;
}
@ -363,29 +364,28 @@ GeneralArrayStackedDumpExportPkgJsonListener::Handle(const BJsonEvent& event)
case B_JSON_NULL:
// ignore
break;
case B_JSON_OBJECT_START:
Push(new GeneralObjectStackedDumpExportPkgJsonListener(fMainListener, this));
break;
case B_JSON_ARRAY_START:
Push(new GeneralArrayStackedDumpExportPkgJsonListener(fMainListener, this));
break;
case B_JSON_OBJECT_END:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE, "illegal state - unexpected end of object");
break;
case B_JSON_ARRAY_END:
{
Pop();
bool status = (ErrorStatus() == B_OK);
bool status = Pop() && (ErrorStatus() == B_OK);
delete this;
return status;
}
}
return ErrorStatus() == B_OK;
}
@ -415,19 +415,18 @@ bool
DumpExportPkg_StackedDumpExportPkgJsonListener::Handle(const BJsonEvent& event)
{
switch (event.EventType()) {
case B_JSON_ARRAY_END:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE, "illegal state - unexpected start of array");
break;
case B_JSON_OBJECT_NAME:
fNextItemName = event.Content();
break;
case B_JSON_OBJECT_END:
{
Pop();
bool status = (ErrorStatus() == B_OK);
bool status = Pop() && (ErrorStatus() == B_OK);
delete this;
return status;
}
@ -436,7 +435,7 @@ DumpExportPkg_StackedDumpExportPkgJsonListener::Handle(const BJsonEvent& event)
if (fNextItemName == "pkgChangelogContent")
fTarget->SetPkgChangelogContent(new BString(event.Content()));
if (fNextItemName == "name")
fTarget->SetName(new BString(event.Content()));
fNextItemName.SetTo("");
@ -452,16 +451,16 @@ DumpExportPkg_StackedDumpExportPkgJsonListener::Handle(const BJsonEvent& event)
if (fNextItemName == "pkgChangelogContent")
fTarget->SetPkgChangelogContentNull();
if (fNextItemName == "name")
fTarget->SetNameNull();
if (fNextItemName == "derivedRating")
fTarget->SetDerivedRatingNull();
if (fNextItemName == "prominenceOrdering")
fTarget->SetProminenceOrderingNull();
if (fNextItemName == "modifyTimestamp")
fTarget->SetModifyTimestampNull();
fNextItemName.SetTo("");
@ -472,10 +471,10 @@ DumpExportPkg_StackedDumpExportPkgJsonListener::Handle(const BJsonEvent& event)
if (fNextItemName == "derivedRating")
fTarget->SetDerivedRating(event.ContentDouble());
if (fNextItemName == "prominenceOrdering")
fTarget->SetProminenceOrdering(event.ContentInteger());
if (fNextItemName == "modifyTimestamp")
fTarget->SetModifyTimestamp(event.ContentInteger());
fNextItemName.SetTo("");
@ -516,7 +515,7 @@ DumpExportPkg_StackedDumpExportPkgJsonListener::Handle(const BJsonEvent& event)
}
}
return ErrorStatus() == B_OK;
}
@ -546,15 +545,14 @@ bool
DumpExportPkg_List_StackedDumpExportPkgJsonListener::Handle(const BJsonEvent& event)
{
switch (event.EventType()) {
case B_JSON_ARRAY_END:
{
Pop();
bool status = (ErrorStatus() == B_OK);
bool status = Pop() && (ErrorStatus() == B_OK);
delete this;
return status;
}
case B_JSON_OBJECT_START:
{
DumpExportPkg_StackedDumpExportPkgJsonListener* nextListener =
@ -563,13 +561,13 @@ DumpExportPkg_List_StackedDumpExportPkgJsonListener::Handle(const BJsonEvent& ev
Push(nextListener);
break;
}
default:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
"illegal state - unexpected json event parsing an array of DumpExportPkg");
break;
}
return ErrorStatus() == B_OK;
}
@ -599,19 +597,18 @@ bool
DumpExportPkgVersion_StackedDumpExportPkgJsonListener::Handle(const BJsonEvent& event)
{
switch (event.EventType()) {
case B_JSON_ARRAY_END:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE, "illegal state - unexpected start of array");
break;
case B_JSON_OBJECT_NAME:
fNextItemName = event.Content();
break;
case B_JSON_OBJECT_END:
{
Pop();
bool status = (ErrorStatus() == B_OK);
bool status = Pop() && (ErrorStatus() == B_OK);
delete this;
return status;
}
@ -620,25 +617,25 @@ DumpExportPkgVersion_StackedDumpExportPkgJsonListener::Handle(const BJsonEvent&
if (fNextItemName == "major")
fTarget->SetMajor(new BString(event.Content()));
if (fNextItemName == "description")
fTarget->SetDescription(new BString(event.Content()));
if (fNextItemName == "title")
fTarget->SetTitle(new BString(event.Content()));
if (fNextItemName == "summary")
fTarget->SetSummary(new BString(event.Content()));
if (fNextItemName == "micro")
fTarget->SetMicro(new BString(event.Content()));
if (fNextItemName == "preRelease")
fTarget->SetPreRelease(new BString(event.Content()));
if (fNextItemName == "architectureCode")
fTarget->SetArchitectureCode(new BString(event.Content()));
if (fNextItemName == "minor")
fTarget->SetMinor(new BString(event.Content()));
fNextItemName.SetTo("");
@ -654,31 +651,31 @@ DumpExportPkgVersion_StackedDumpExportPkgJsonListener::Handle(const BJsonEvent&
if (fNextItemName == "major")
fTarget->SetMajorNull();
if (fNextItemName == "payloadLength")
fTarget->SetPayloadLengthNull();
if (fNextItemName == "description")
fTarget->SetDescriptionNull();
if (fNextItemName == "title")
fTarget->SetTitleNull();
if (fNextItemName == "summary")
fTarget->SetSummaryNull();
if (fNextItemName == "micro")
fTarget->SetMicroNull();
if (fNextItemName == "preRelease")
fTarget->SetPreReleaseNull();
if (fNextItemName == "architectureCode")
fTarget->SetArchitectureCodeNull();
if (fNextItemName == "minor")
fTarget->SetMinorNull();
if (fNextItemName == "revision")
fTarget->SetRevisionNull();
fNextItemName.SetTo("");
@ -689,7 +686,7 @@ DumpExportPkgVersion_StackedDumpExportPkgJsonListener::Handle(const BJsonEvent&
if (fNextItemName == "payloadLength")
fTarget->SetPayloadLength(event.ContentInteger());
if (fNextItemName == "revision")
fTarget->SetRevision(event.ContentInteger());
fNextItemName.SetTo("");
@ -715,7 +712,7 @@ DumpExportPkgVersion_StackedDumpExportPkgJsonListener::Handle(const BJsonEvent&
}
}
return ErrorStatus() == B_OK;
}
@ -745,15 +742,14 @@ bool
DumpExportPkgVersion_List_StackedDumpExportPkgJsonListener::Handle(const BJsonEvent& event)
{
switch (event.EventType()) {
case B_JSON_ARRAY_END:
{
Pop();
bool status = (ErrorStatus() == B_OK);
bool status = Pop() && (ErrorStatus() == B_OK);
delete this;
return status;
}
case B_JSON_OBJECT_START:
{
DumpExportPkgVersion_StackedDumpExportPkgJsonListener* nextListener =
@ -762,13 +758,13 @@ DumpExportPkgVersion_List_StackedDumpExportPkgJsonListener::Handle(const BJsonEv
Push(nextListener);
break;
}
default:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
"illegal state - unexpected json event parsing an array of DumpExportPkgVersion");
break;
}
return ErrorStatus() == B_OK;
}
@ -798,19 +794,18 @@ bool
DumpExportPkgScreenshot_StackedDumpExportPkgJsonListener::Handle(const BJsonEvent& event)
{
switch (event.EventType()) {
case B_JSON_ARRAY_END:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE, "illegal state - unexpected start of array");
break;
case B_JSON_OBJECT_NAME:
fNextItemName = event.Content();
break;
case B_JSON_OBJECT_END:
{
Pop();
bool status = (ErrorStatus() == B_OK);
bool status = Pop() && (ErrorStatus() == B_OK);
delete this;
return status;
}
@ -832,16 +827,16 @@ DumpExportPkgScreenshot_StackedDumpExportPkgJsonListener::Handle(const BJsonEven
if (fNextItemName == "ordering")
fTarget->SetOrderingNull();
if (fNextItemName == "width")
fTarget->SetWidthNull();
if (fNextItemName == "length")
fTarget->SetLengthNull();
if (fNextItemName == "code")
fTarget->SetCodeNull();
if (fNextItemName == "height")
fTarget->SetHeightNull();
fNextItemName.SetTo("");
@ -852,13 +847,13 @@ DumpExportPkgScreenshot_StackedDumpExportPkgJsonListener::Handle(const BJsonEven
if (fNextItemName == "ordering")
fTarget->SetOrdering(event.ContentInteger());
if (fNextItemName == "width")
fTarget->SetWidth(event.ContentInteger());
if (fNextItemName == "length")
fTarget->SetLength(event.ContentInteger());
if (fNextItemName == "height")
fTarget->SetHeight(event.ContentInteger());
fNextItemName.SetTo("");
@ -884,7 +879,7 @@ DumpExportPkgScreenshot_StackedDumpExportPkgJsonListener::Handle(const BJsonEven
}
}
return ErrorStatus() == B_OK;
}
@ -914,15 +909,14 @@ bool
DumpExportPkgScreenshot_List_StackedDumpExportPkgJsonListener::Handle(const BJsonEvent& event)
{
switch (event.EventType()) {
case B_JSON_ARRAY_END:
{
Pop();
bool status = (ErrorStatus() == B_OK);
bool status = Pop() && (ErrorStatus() == B_OK);
delete this;
return status;
}
case B_JSON_OBJECT_START:
{
DumpExportPkgScreenshot_StackedDumpExportPkgJsonListener* nextListener =
@ -931,13 +925,13 @@ DumpExportPkgScreenshot_List_StackedDumpExportPkgJsonListener::Handle(const BJso
Push(nextListener);
break;
}
default:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
"illegal state - unexpected json event parsing an array of DumpExportPkgScreenshot");
break;
}
return ErrorStatus() == B_OK;
}
@ -967,19 +961,18 @@ bool
DumpExportPkgCategory_StackedDumpExportPkgJsonListener::Handle(const BJsonEvent& event)
{
switch (event.EventType()) {
case B_JSON_ARRAY_END:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE, "illegal state - unexpected start of array");
break;
case B_JSON_OBJECT_NAME:
fNextItemName = event.Content();
break;
case B_JSON_OBJECT_END:
{
Pop();
bool status = (ErrorStatus() == B_OK);
bool status = Pop() && (ErrorStatus() == B_OK);
delete this;
return status;
}
@ -1029,7 +1022,7 @@ DumpExportPkgCategory_StackedDumpExportPkgJsonListener::Handle(const BJsonEvent&
}
}
return ErrorStatus() == B_OK;
}
@ -1059,15 +1052,14 @@ bool
DumpExportPkgCategory_List_StackedDumpExportPkgJsonListener::Handle(const BJsonEvent& event)
{
switch (event.EventType()) {
case B_JSON_ARRAY_END:
{
Pop();
bool status = (ErrorStatus() == B_OK);
bool status = Pop() && (ErrorStatus() == B_OK);
delete this;
return status;
}
case B_JSON_OBJECT_START:
{
DumpExportPkgCategory_StackedDumpExportPkgJsonListener* nextListener =
@ -1076,13 +1068,13 @@ DumpExportPkgCategory_List_StackedDumpExportPkgJsonListener::Handle(const BJsonE
Push(nextListener);
break;
}
default:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
"illegal state - unexpected json event parsing an array of DumpExportPkgCategory");
break;
}
return ErrorStatus() == B_OK;
}
@ -1101,11 +1093,13 @@ ItemEmittingStackedDumpExportPkgJsonListener::~ItemEmittingStackedDumpExportPkgJ
}
void
bool
ItemEmittingStackedDumpExportPkgJsonListener::WillPop()
{
fItemListener->Handle(fTarget);
bool result = fItemListener->Handle(fTarget);
delete fTarget;
fTarget = NULL;
return result;
}
@ -1128,39 +1122,38 @@ bool
BulkContainerStackedDumpExportPkgJsonListener::Handle(const BJsonEvent& event)
{
switch (event.EventType()) {
case B_JSON_ARRAY_END:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE, "illegal state - unexpected start of array");
break;
case B_JSON_OBJECT_NAME:
fNextItemName = event.Content();
break;
case B_JSON_OBJECT_START:
Push(new GeneralObjectStackedDumpExportPkgJsonListener(fMainListener, this));
break;
case B_JSON_ARRAY_START:
if (fNextItemName == "items")
Push(new BulkContainerItemsStackedDumpExportPkgJsonListener(fMainListener, this, fItemListener));
else
Push(new GeneralArrayStackedDumpExportPkgJsonListener(fMainListener, this));
break;
case B_JSON_OBJECT_END:
{
Pop();
bool status = (ErrorStatus() == B_OK);
bool status = Pop() && (ErrorStatus() == B_OK);
delete this;
return status;
}
default:
// ignore
break;
}
return ErrorStatus() == B_OK;
}
@ -1184,32 +1177,32 @@ bool
BulkContainerItemsStackedDumpExportPkgJsonListener::Handle(const BJsonEvent& event)
{
switch (event.EventType()) {
case B_JSON_OBJECT_START:
Push(new ItemEmittingStackedDumpExportPkgJsonListener(fMainListener, this, fItemListener));
break;
case B_JSON_ARRAY_END:
{
Pop();
bool status = (ErrorStatus() == B_OK);
bool status = Pop() && (ErrorStatus() == B_OK);
delete this;
return status;
}
default:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE, "illegal state - unexpected json event");
break;
}
return ErrorStatus() == B_OK;
}
void
bool
BulkContainerItemsStackedDumpExportPkgJsonListener::WillPop()
{
fItemListener->Complete();
return true;
}
@ -1278,12 +1271,12 @@ SingleDumpExportPkgJsonListener::Handle(const BJsonEvent& event)
{
if (fErrorStatus != B_OK)
return false;
if (fStackedListener != NULL)
return fStackedListener->Handle(event);
switch (event.EventType()) {
case B_JSON_OBJECT_START:
{
DumpExportPkg_StackedDumpExportPkgJsonListener* nextListener = new DumpExportPkg_StackedDumpExportPkgJsonListener(
@ -1292,13 +1285,13 @@ SingleDumpExportPkgJsonListener::Handle(const BJsonEvent& event)
SetStackedListener(nextListener);
break;
}
default:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
"illegal state - unexpected json event parsing top level for DumpExportPkg");
break;
}
return ErrorStatus() == B_OK;
}
@ -1327,12 +1320,12 @@ BulkContainerDumpExportPkgJsonListener::Handle(const BJsonEvent& event)
{
if (fErrorStatus != B_OK)
return false;
if (fStackedListener != NULL)
return fStackedListener->Handle(event);
switch (event.EventType()) {
case B_JSON_OBJECT_START:
{
BulkContainerStackedDumpExportPkgJsonListener* nextListener =
@ -1342,13 +1335,13 @@ BulkContainerDumpExportPkgJsonListener::Handle(const BJsonEvent& event)
return true;
break;
}
default:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
"illegal state - unexpected json event parsing top level for BulkContainerDumpExportPkgJsonListener");
break;
}
return ErrorStatus() == B_OK;
}

View File

@ -1,7 +1,7 @@
/*
* Generated Listener Object
* source json-schema : dumpexport.json
* generated at : 2017-11-11T14:09:03.498089
* generated at : 2017-12-17T20:45:25.514143
*/
#ifndef GEN_JSON_SCHEMA_PARSER__SINGLEDUMPEXPORTPKGJSONLISTENER_H
@ -60,7 +60,7 @@ private:
*/
class DumpExportPkgListener {
public:
virtual void Handle(DumpExportPkg* item) = 0;
virtual bool Handle(DumpExportPkg* item) = 0;
virtual void Complete() = 0;
};

View File

@ -1,7 +1,7 @@
/*
* Generated Model Object
* source json-schema : dumpexport.json
* generated at : 2017-11-05T22:30:10.257444
* generated at : 2017-12-07T23:22:17.118221
*/
#include "DumpExportPkgScreenshot.h"

View File

@ -1,7 +1,7 @@
/*
* Generated Model Object
* source json-schema : dumpexport.json
* generated at : 2017-11-05T22:30:10.256842
* generated at : 2017-12-07T23:22:17.118049
*/
#ifndef GEN_JSON_SCHEMA_MODEL__DUMPEXPORTPKGSCREENSHOT_H

View File

@ -1,7 +1,7 @@
/*
* Generated Model Object
* source json-schema : dumpexport.json
* generated at : 2017-11-05T22:30:10.255929
* generated at : 2017-12-07T23:22:17.117543
*/
#include "DumpExportPkgVersion.h"

View File

@ -1,7 +1,7 @@
/*
* Generated Model Object
* source json-schema : dumpexport.json
* generated at : 2017-11-05T22:30:10.255268
* generated at : 2017-12-07T23:22:17.117333
*/
#ifndef GEN_JSON_SCHEMA_MODEL__DUMPEXPORTPKGVERSION_H

View File

@ -1,7 +1,7 @@
/*
* Generated Model Object
* source json-schema : dumpexport.json
* generated at : 2017-11-11T13:59:22.553529
* generated at : 2017-12-07T23:22:33.021497
*/
#include "DumpExportRepository.h"

View File

@ -1,7 +1,7 @@
/*
* Generated Model Object
* source json-schema : dumpexport.json
* generated at : 2017-11-11T13:59:22.550365
* generated at : 2017-12-07T23:22:33.020747
*/
#ifndef GEN_JSON_SCHEMA_MODEL__DUMPEXPORTREPOSITORY_H

View File

@ -1,19 +1,20 @@
/*
* Generated Listener Object
* source json-schema : dumpexport.json
* generated at : 2017-11-11T14:08:39.276778
* generated at : 2017-12-18T23:07:02.401765
*/
#include "DumpExportRepositoryJsonListener.h"
#include "List.h"
#include <stdio.h>
// #pragma mark - private interfaces for the stacked listeners
/*! This class is the top level of the stacked listeners. The stack structure
is maintained in a linked list and sub-classes implement specific behaviors
depending where in the parse tree the stacked listener is working at.
*/
*/
class AbstractStackedDumpExportRepositoryJsonListener : public BJsonEventListener {
public:
AbstractStackedDumpExportRepositoryJsonListener(
@ -28,14 +29,14 @@ public:
AbstractStackedDumpExportRepositoryJsonListener* Parent();
virtual void WillPop();
virtual bool WillPop();
protected:
AbstractMainDumpExportRepositoryJsonListener* fMainListener;
void Pop();
bool Pop();
void Push(AbstractStackedDumpExportRepositoryJsonListener* stackedListener);
private:
AbstractStackedDumpExportRepositoryJsonListener* fParent;
};
@ -46,7 +47,7 @@ public:
AbstractMainDumpExportRepositoryJsonListener* mainListener,
AbstractStackedDumpExportRepositoryJsonListener* parent);
~GeneralArrayStackedDumpExportRepositoryJsonListener();
bool Handle(const BJsonEvent& event);
};
@ -56,7 +57,7 @@ public:
AbstractMainDumpExportRepositoryJsonListener* mainListener,
AbstractStackedDumpExportRepositoryJsonListener* parent);
~GeneralObjectStackedDumpExportRepositoryJsonListener();
bool Handle(const BJsonEvent& event);
};
@ -66,11 +67,11 @@ public:
AbstractMainDumpExportRepositoryJsonListener* mainListener,
AbstractStackedDumpExportRepositoryJsonListener* parent);
~DumpExportRepository_StackedDumpExportRepositoryJsonListener();
bool Handle(const BJsonEvent& event);
DumpExportRepository* Target();
protected:
DumpExportRepository* fTarget;
BString fNextItemName;
@ -82,11 +83,11 @@ public:
AbstractMainDumpExportRepositoryJsonListener* mainListener,
AbstractStackedDumpExportRepositoryJsonListener* parent);
~DumpExportRepository_List_StackedDumpExportRepositoryJsonListener();
bool Handle(const BJsonEvent& event);
List<DumpExportRepository*, true>* Target(); // list of %s pointers
private:
List<DumpExportRepository*, true>* fTarget;
};
@ -97,11 +98,11 @@ public:
AbstractMainDumpExportRepositoryJsonListener* mainListener,
AbstractStackedDumpExportRepositoryJsonListener* parent);
~DumpExportRepositorySource_StackedDumpExportRepositoryJsonListener();
bool Handle(const BJsonEvent& event);
DumpExportRepositorySource* Target();
protected:
DumpExportRepositorySource* fTarget;
BString fNextItemName;
@ -113,11 +114,11 @@ public:
AbstractMainDumpExportRepositoryJsonListener* mainListener,
AbstractStackedDumpExportRepositoryJsonListener* parent);
~DumpExportRepositorySource_List_StackedDumpExportRepositoryJsonListener();
bool Handle(const BJsonEvent& event);
List<DumpExportRepositorySource*, true>* Target(); // list of %s pointers
private:
List<DumpExportRepositorySource*, true>* fTarget;
};
@ -129,9 +130,9 @@ public:
AbstractStackedDumpExportRepositoryJsonListener* parent,
DumpExportRepositoryListener* itemListener);
~ItemEmittingStackedDumpExportRepositoryJsonListener();
void WillPop();
bool WillPop();
private:
DumpExportRepositoryListener* fItemListener;
};
@ -144,9 +145,9 @@ public:
AbstractStackedDumpExportRepositoryJsonListener* parent,
DumpExportRepositoryListener* itemListener);
~BulkContainerStackedDumpExportRepositoryJsonListener();
bool Handle(const BJsonEvent& event);
private:
BString fNextItemName;
DumpExportRepositoryListener* fItemListener;
@ -160,10 +161,10 @@ public:
AbstractStackedDumpExportRepositoryJsonListener* parent,
DumpExportRepositoryListener* itemListener);
~BulkContainerItemsStackedDumpExportRepositoryJsonListener();
bool Handle(const BJsonEvent& event);
void WillPop();
bool WillPop();
private:
DumpExportRepositoryListener* fItemListener;
};
@ -212,16 +213,18 @@ AbstractStackedDumpExportRepositoryJsonListener::Push(AbstractStackedDumpExportR
fMainListener->SetStackedListener(stackedListener);
}
void
bool
AbstractStackedDumpExportRepositoryJsonListener::WillPop()
{
return true;
}
void
bool
AbstractStackedDumpExportRepositoryJsonListener::Pop()
{
WillPop();
bool result = WillPop();
fMainListener->SetStackedListener(fParent);
return result;
}
GeneralObjectStackedDumpExportRepositoryJsonListener::GeneralObjectStackedDumpExportRepositoryJsonListener(
@ -249,28 +252,28 @@ GeneralObjectStackedDumpExportRepositoryJsonListener::Handle(const BJsonEvent& e
case B_JSON_NULL:
// ignore
break;
case B_JSON_OBJECT_START:
Push(new GeneralObjectStackedDumpExportRepositoryJsonListener(fMainListener, this));
break;
case B_JSON_ARRAY_START:
Push(new GeneralArrayStackedDumpExportRepositoryJsonListener(fMainListener, this));
break;
case B_JSON_ARRAY_END:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE, "illegal state - unexpected end of array");
break;
case B_JSON_OBJECT_END:
{
Pop();
bool status = (ErrorStatus() == B_OK);
bool status = Pop() && (ErrorStatus() == B_OK);
delete this;
return status;
}
}
return ErrorStatus() == B_OK;
}
@ -299,28 +302,28 @@ GeneralArrayStackedDumpExportRepositoryJsonListener::Handle(const BJsonEvent& ev
case B_JSON_NULL:
// ignore
break;
case B_JSON_OBJECT_START:
Push(new GeneralObjectStackedDumpExportRepositoryJsonListener(fMainListener, this));
break;
case B_JSON_ARRAY_START:
Push(new GeneralArrayStackedDumpExportRepositoryJsonListener(fMainListener, this));
break;
case B_JSON_OBJECT_END:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE, "illegal state - unexpected end of object");
break;
case B_JSON_ARRAY_END:
{
Pop();
bool status = (ErrorStatus() == B_OK);
bool status = Pop() && (ErrorStatus() == B_OK);
delete this;
return status;
}
}
return ErrorStatus() == B_OK;
}
@ -350,19 +353,18 @@ bool
DumpExportRepository_StackedDumpExportRepositoryJsonListener::Handle(const BJsonEvent& event)
{
switch (event.EventType()) {
case B_JSON_ARRAY_END:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE, "illegal state - unexpected start of array");
break;
case B_JSON_OBJECT_NAME:
fNextItemName = event.Content();
break;
case B_JSON_OBJECT_END:
{
Pop();
bool status = (ErrorStatus() == B_OK);
bool status = Pop() && (ErrorStatus() == B_OK);
delete this;
return status;
}
@ -371,13 +373,13 @@ DumpExportRepository_StackedDumpExportRepositoryJsonListener::Handle(const BJson
if (fNextItemName == "informationUrl")
fTarget->SetInformationUrl(new BString(event.Content()));
if (fNextItemName == "code")
fTarget->SetCode(new BString(event.Content()));
if (fNextItemName == "name")
fTarget->SetName(new BString(event.Content()));
if (fNextItemName == "description")
fTarget->SetDescription(new BString(event.Content()));
fNextItemName.SetTo("");
@ -393,13 +395,13 @@ DumpExportRepository_StackedDumpExportRepositoryJsonListener::Handle(const BJson
if (fNextItemName == "informationUrl")
fTarget->SetInformationUrlNull();
if (fNextItemName == "code")
fTarget->SetCodeNull();
if (fNextItemName == "name")
fTarget->SetNameNull();
if (fNextItemName == "description")
fTarget->SetDescriptionNull();
fNextItemName.SetTo("");
@ -435,7 +437,7 @@ DumpExportRepository_StackedDumpExportRepositoryJsonListener::Handle(const BJson
}
}
return ErrorStatus() == B_OK;
}
@ -465,15 +467,14 @@ bool
DumpExportRepository_List_StackedDumpExportRepositoryJsonListener::Handle(const BJsonEvent& event)
{
switch (event.EventType()) {
case B_JSON_ARRAY_END:
{
Pop();
bool status = (ErrorStatus() == B_OK);
bool status = Pop() && (ErrorStatus() == B_OK);
delete this;
return status;
}
case B_JSON_OBJECT_START:
{
DumpExportRepository_StackedDumpExportRepositoryJsonListener* nextListener =
@ -482,13 +483,13 @@ DumpExportRepository_List_StackedDumpExportRepositoryJsonListener::Handle(const
Push(nextListener);
break;
}
default:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
"illegal state - unexpected json event parsing an array of DumpExportRepository");
break;
}
return ErrorStatus() == B_OK;
}
@ -518,19 +519,18 @@ bool
DumpExportRepositorySource_StackedDumpExportRepositoryJsonListener::Handle(const BJsonEvent& event)
{
switch (event.EventType()) {
case B_JSON_ARRAY_END:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE, "illegal state - unexpected start of array");
break;
case B_JSON_OBJECT_NAME:
fNextItemName = event.Content();
break;
case B_JSON_OBJECT_END:
{
Pop();
bool status = (ErrorStatus() == B_OK);
bool status = Pop() && (ErrorStatus() == B_OK);
delete this;
return status;
}
@ -539,7 +539,10 @@ DumpExportRepositorySource_StackedDumpExportRepositoryJsonListener::Handle(const
if (fNextItemName == "url")
fTarget->SetUrl(new BString(event.Content()));
if (fNextItemName == "repoInfoUrl")
fTarget->SetRepoInfoUrl(new BString(event.Content()));
if (fNextItemName == "code")
fTarget->SetCode(new BString(event.Content()));
fNextItemName.SetTo("");
@ -555,7 +558,10 @@ DumpExportRepositorySource_StackedDumpExportRepositoryJsonListener::Handle(const
if (fNextItemName == "url")
fTarget->SetUrlNull();
if (fNextItemName == "repoInfoUrl")
fTarget->SetRepoInfoUrlNull();
if (fNextItemName == "code")
fTarget->SetCodeNull();
fNextItemName.SetTo("");
@ -586,7 +592,7 @@ DumpExportRepositorySource_StackedDumpExportRepositoryJsonListener::Handle(const
}
}
return ErrorStatus() == B_OK;
}
@ -616,15 +622,14 @@ bool
DumpExportRepositorySource_List_StackedDumpExportRepositoryJsonListener::Handle(const BJsonEvent& event)
{
switch (event.EventType()) {
case B_JSON_ARRAY_END:
{
Pop();
bool status = (ErrorStatus() == B_OK);
bool status = Pop() && (ErrorStatus() == B_OK);
delete this;
return status;
}
case B_JSON_OBJECT_START:
{
DumpExportRepositorySource_StackedDumpExportRepositoryJsonListener* nextListener =
@ -633,13 +638,13 @@ DumpExportRepositorySource_List_StackedDumpExportRepositoryJsonListener::Handle(
Push(nextListener);
break;
}
default:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
"illegal state - unexpected json event parsing an array of DumpExportRepositorySource");
break;
}
return ErrorStatus() == B_OK;
}
@ -658,11 +663,13 @@ ItemEmittingStackedDumpExportRepositoryJsonListener::~ItemEmittingStackedDumpExp
}
void
bool
ItemEmittingStackedDumpExportRepositoryJsonListener::WillPop()
{
fItemListener->Handle(fTarget);
bool result = fItemListener->Handle(fTarget);
delete fTarget;
fTarget = NULL;
return result;
}
@ -685,39 +692,38 @@ bool
BulkContainerStackedDumpExportRepositoryJsonListener::Handle(const BJsonEvent& event)
{
switch (event.EventType()) {
case B_JSON_ARRAY_END:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE, "illegal state - unexpected start of array");
break;
case B_JSON_OBJECT_NAME:
fNextItemName = event.Content();
break;
case B_JSON_OBJECT_START:
Push(new GeneralObjectStackedDumpExportRepositoryJsonListener(fMainListener, this));
break;
case B_JSON_ARRAY_START:
if (fNextItemName == "items")
Push(new BulkContainerItemsStackedDumpExportRepositoryJsonListener(fMainListener, this, fItemListener));
else
Push(new GeneralArrayStackedDumpExportRepositoryJsonListener(fMainListener, this));
break;
case B_JSON_OBJECT_END:
{
Pop();
bool status = (ErrorStatus() == B_OK);
bool status = Pop() && (ErrorStatus() == B_OK);
delete this;
return status;
}
default:
// ignore
break;
}
return ErrorStatus() == B_OK;
}
@ -741,32 +747,32 @@ bool
BulkContainerItemsStackedDumpExportRepositoryJsonListener::Handle(const BJsonEvent& event)
{
switch (event.EventType()) {
case B_JSON_OBJECT_START:
Push(new ItemEmittingStackedDumpExportRepositoryJsonListener(fMainListener, this, fItemListener));
break;
case B_JSON_ARRAY_END:
{
Pop();
bool status = (ErrorStatus() == B_OK);
bool status = Pop() && (ErrorStatus() == B_OK);
delete this;
return status;
}
default:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE, "illegal state - unexpected json event");
break;
}
return ErrorStatus() == B_OK;
}
void
bool
BulkContainerItemsStackedDumpExportRepositoryJsonListener::WillPop()
{
fItemListener->Complete();
return true;
}
@ -835,12 +841,12 @@ SingleDumpExportRepositoryJsonListener::Handle(const BJsonEvent& event)
{
if (fErrorStatus != B_OK)
return false;
if (fStackedListener != NULL)
return fStackedListener->Handle(event);
switch (event.EventType()) {
case B_JSON_OBJECT_START:
{
DumpExportRepository_StackedDumpExportRepositoryJsonListener* nextListener = new DumpExportRepository_StackedDumpExportRepositoryJsonListener(
@ -849,13 +855,13 @@ SingleDumpExportRepositoryJsonListener::Handle(const BJsonEvent& event)
SetStackedListener(nextListener);
break;
}
default:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
"illegal state - unexpected json event parsing top level for DumpExportRepository");
break;
}
return ErrorStatus() == B_OK;
}
@ -884,29 +890,28 @@ BulkContainerDumpExportRepositoryJsonListener::Handle(const BJsonEvent& event)
{
if (fErrorStatus != B_OK)
return false;
if (fStackedListener != NULL)
return fStackedListener->Handle(event);
switch (event.EventType()) {
case B_JSON_OBJECT_START:
{
BulkContainerStackedDumpExportRepositoryJsonListener* nextListener =
new BulkContainerStackedDumpExportRepositoryJsonListener(
this, NULL, fItemListener);
SetStackedListener(nextListener);
return true;
break;
}
default:
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
"illegal state - unexpected json event parsing top level for BulkContainerDumpExportRepositoryJsonListener");
break;
}
return ErrorStatus() == B_OK;
}

View File

@ -1,7 +1,7 @@
/*
* Generated Listener Object
* source json-schema : dumpexport.json
* generated at : 2017-11-11T14:08:39.274913
* generated at : 2017-12-18T23:07:02.399681
*/
#ifndef GEN_JSON_SCHEMA_PARSER__SINGLEDUMPEXPORTREPOSITORYJSONLISTENER_H
@ -60,7 +60,7 @@ private:
*/
class DumpExportRepositoryListener {
public:
virtual void Handle(DumpExportRepository* item) = 0;
virtual bool Handle(DumpExportRepository* item) = 0;
virtual void Complete() = 0;
};

View File

@ -1,7 +1,7 @@
/*
* Generated Model Object
* source json-schema : dumpexport.json
* generated at : 2017-11-11T13:59:22.559632
* generated at : 2017-12-07T23:22:33.022114
*/
#include "DumpExportRepositorySource.h"
@ -9,6 +9,7 @@
DumpExportRepositorySource::DumpExportRepositorySource()
{
fUrl = NULL;
fRepoInfoUrl = NULL;
fCode = NULL;
}
@ -19,6 +20,10 @@ DumpExportRepositorySource::~DumpExportRepositorySource()
delete fUrl;
}
if (fRepoInfoUrl != NULL) {
delete fRepoInfoUrl;
}
if (fCode != NULL) {
delete fCode;
}
@ -56,6 +61,37 @@ DumpExportRepositorySource::UrlIsNull()
}
BString*
DumpExportRepositorySource::RepoInfoUrl()
{
return fRepoInfoUrl;
}
void
DumpExportRepositorySource::SetRepoInfoUrl(BString* value)
{
fRepoInfoUrl = value;
}
void
DumpExportRepositorySource::SetRepoInfoUrlNull()
{
if (!RepoInfoUrlIsNull()) {
delete fRepoInfoUrl;
fRepoInfoUrl = NULL;
}
}
bool
DumpExportRepositorySource::RepoInfoUrlIsNull()
{
return fRepoInfoUrl == NULL;
}
BString*
DumpExportRepositorySource::Code()
{

View File

@ -1,7 +1,7 @@
/*
* Generated Model Object
* source json-schema : dumpexport.json
* generated at : 2017-11-11T13:59:22.559237
* generated at : 2017-12-07T23:22:33.021952
*/
#ifndef GEN_JSON_SCHEMA_MODEL__DUMPEXPORTREPOSITORYSOURCE_H
@ -21,6 +21,11 @@ public:
void SetUrlNull();
bool UrlIsNull();
BString* RepoInfoUrl();
void SetRepoInfoUrl(BString* value);
void SetRepoInfoUrlNull();
bool RepoInfoUrlIsNull();
BString* Code();
void SetCode(BString* value);
void SetCodeNull();
@ -28,6 +33,7 @@ public:
private:
BString* fUrl;
BString* fRepoInfoUrl;
BString* fCode;
};

View File

@ -19,7 +19,8 @@
status_t
TarArchiveService::Unpack(BDataIO& tarDataIo, BPath& targetDirectory)
TarArchiveService::Unpack(BDataIO& tarDataIo, BPath& targetDirectory,
Stoppable* stoppable)
{
uint8 buffer[LENGTH_BLOCK];
uint8 zero_buffer[LENGTH_BLOCK];
@ -30,8 +31,9 @@ TarArchiveService::Unpack(BDataIO& tarDataIo, BPath& targetDirectory)
memset(zero_buffer, 0, sizeof zero_buffer);
while (B_OK == result && B_OK == (result = tarDataIo.ReadExactly(buffer,
LENGTH_BLOCK))) {
while (B_OK == result
&& (NULL == stoppable || !stoppable->WasStopped())
&& B_OK == (result = tarDataIo.ReadExactly(buffer, LENGTH_BLOCK))) {
count_items_read++;

View File

@ -7,6 +7,7 @@
#define TAR_ARCHIVE_SERVICE_H
#include "AbstractServerProcess.h"
#include "Stoppable.h"
#include "TarArchiveHeader.h"
#include <String.h>
@ -16,7 +17,8 @@
class TarArchiveService {
public:
static status_t Unpack(BDataIO& tarDataIo,
BPath& targetDirectoryPath);
BPath& targetDirectoryPath,
Stoppable* stoppable);
private:
static status_t _EnsurePathToTarItemFile(

View File

@ -1,5 +1,6 @@
/*
* Copyright 2013, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
@ -127,6 +128,9 @@ enum arg_switch {
HELP_SWITCH,
WEB_APP_BASE_URL_SWITCH,
VERBOSITY_SWITCH,
FORCE_NO_NETWORKING_SWITCH,
PREFER_CACHE_SWITCH,
DROP_CACHE_SWITCH
};
@ -134,13 +138,24 @@ static void
app_print_help()
{
fprintf(stdout, "HaikuDepot ");
fprintf(stdout, "[-u|--webappbaseurl <web-app-base-url>] ");
fprintf(stdout, "[-v|--verbosity [off|info|debug|trace] ");
fprintf(stdout, "[-h|--help]\n\n");
fprintf(stdout, "[-u|--webappbaseurl <web-app-base-url>]\n");
fprintf(stdout, "[-v|--verbosity [off|info|debug|trace]\n");
fprintf(stdout, "[--nonetworking]\n");
fprintf(stdout, "[--prefercache]\n");
fprintf(stdout, "[--dropcache]\n");
fprintf(stdout, "[-h|--help]\n");
fprintf(stdout, "\n");
fprintf(stdout, "'-h' : causes this help text to be printed out.\n");
fprintf(stdout, "'-v' : allows for the verbosity level to be set.\n");
fprintf(stdout, "'-u' : allows for the haiku depot server to be\n");
fprintf(stdout, " configured.");
fprintf(stdout, "'-u' : allows for the haiku depot server url to be\n");
fprintf(stdout, " configured.\n");
fprintf(stdout, "'--nonetworking' : prevents network access.**\n");
fprintf(stdout, "'--prefercache' : prefer to get data from cache rather\n");
fprintf(stdout, " then obtain data from the network.**\n");
fprintf(stdout, "'--dropcache' : drop cached data before performing\n");
fprintf(stdout, " bulk operations.**\n");
fprintf(stdout, "\n");
fprintf(stdout, "** = only applies to bulk operations.\n");
}
@ -160,6 +175,15 @@ app_resolve_switch(char *arg)
if (0 == strcmp(&arg[2], "verbosity"))
return VERBOSITY_SWITCH;
if (0 == strcmp(&arg[2], "nonetworking"))
return FORCE_NO_NETWORKING_SWITCH;
if (0 == strcmp(&arg[2], "prefercache"))
return PREFER_CACHE_SWITCH;
if (0 == strcmp(&arg[2], "dropcache"))
return DROP_CACHE_SWITCH;
} else {
if (arglen == 2) { // short form
switch (arg[1]) {
@ -237,6 +261,18 @@ App::ArgvReceived(int32 argc, char* argv[])
break;
case FORCE_NO_NETWORKING_SWITCH:
ServerSettings::SetForceNoNetwork(true);
break;
case PREFER_CACHE_SWITCH:
ServerSettings::SetPreferCache(true);
break;
case DROP_CACHE_SWITCH:
ServerSettings::SetDropCache(true);
break;
case NOT_SWITCH:
{
BEntry entry(argv[i], true);

View File

@ -132,6 +132,7 @@ MainWindow::MainWindow(const BMessage& settings)
fLogInItem(NULL),
fLogOutItem(NULL),
fModelListener(new MessageModelListener(BMessenger(this)), true),
fBulkLoadStateMachine(&fModel),
fTerminating(false),
fSinglePackageMode(false),
fModelWorker(B_BAD_THREAD_ID)
@ -245,6 +246,7 @@ MainWindow::MainWindow(const BMessage& settings, const PackageInfoRef& package)
fLogInItem(NULL),
fLogOutItem(NULL),
fModelListener(new MessageModelListener(BMessenger(this)), true),
fBulkLoadStateMachine(&fModel),
fTerminating(false),
fSinglePackageMode(true),
fModelWorker(B_BAD_THREAD_ID)
@ -1062,7 +1064,7 @@ MainWindow::_RefreshPackageList(bool force)
bool wasEmpty = fModel.Depots().IsEmpty();
if (force || wasEmpty)
fModel.StopPopulatingAllPackages();
fBulkLoadStateMachine.Stop();
BAutolock lock(fModel.Lock());
@ -1094,11 +1096,10 @@ MainWindow::_RefreshPackageList(bool force)
fModel.AddDepot(it->second);
}
fModel.PopulateWebAppRepositoryCodes();
// start retrieving package icons and average ratings
if (force || wasEmpty)
fModel.PopulateAllPackages();
if (force || wasEmpty) {
fBulkLoadStateMachine.Start();
}
// compute the OS package dependencies
try {

View File

@ -2,6 +2,7 @@
* Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2013, Rene Gollent <rene@gollent.com>.
* Copyright 2017, Julian Harnath <julian.harnath@rwth-aachen.de>.
* Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef MAIN_WINDOW_H
@ -9,6 +10,7 @@
#include <Window.h>
#include "BulkLoadStateMachine.h"
#include "Model.h"
#include "PackageAction.h"
#include "PackageActionHandler.h"
@ -119,6 +121,8 @@ private:
Model fModel;
ModelListenerRef fModelListener;
PackageList fVisiblePackages;
BulkLoadStateMachine
fBulkLoadStateMachine;
bool fTerminating;
bool fSinglePackageMode;

View File

@ -5,13 +5,15 @@
#include "StorageUtils.h"
#include <stdio.h>
#include <errno.h>
#include <Directory.h>
#include <File.h>
#include <Entry.h>
#include <String.h>
#include <stdio.h>
#include <errno.h>
#include "Logger.h"
#define FILE_TO_STRING_BUFFER_LEN 64
@ -51,23 +53,27 @@ StorageUtils::RemoveDirectoryContents(BPath& path)
bool exists = false;
bool isDirectory = false;
BPath directroyEntryPath;
BPath directoryEntryPath;
result = directoryEntry.GetPath(&directroyEntryPath);
result = directoryEntry.GetPath(&directoryEntryPath);
if (result == B_OK)
result = ExistsDirectory(directroyEntryPath, &exists, &isDirectory);
if (result == B_OK) {
result = ExistsObject(directoryEntryPath, &exists, &isDirectory,
NULL);
}
if (result == B_OK) {
if (isDirectory)
RemoveDirectoryContents(directroyEntryPath);
RemoveDirectoryContents(directoryEntryPath);
if (remove(directroyEntryPath.Path()) == 0) {
fprintf(stdout, "did delete [%s]\n",
directroyEntryPath.Path());
if (remove(directoryEntryPath.Path()) == 0) {
if (Logger::IsDebugEnabled()) {
fprintf(stdout, "did delete [%s]\n",
directoryEntryPath.Path());
}
} else {
fprintf(stderr, "unable to delete [%s]\n",
directroyEntryPath.Path());
directoryEntryPath.Path());
result = B_ERROR;
}
}
@ -84,21 +90,34 @@ StorageUtils::RemoveDirectoryContents(BPath& path)
*/
status_t
StorageUtils::ExistsDirectory(BPath& directory,
StorageUtils::ExistsObject(BPath& path,
bool* exists,
bool* isDirectory)
bool* isDirectory,
off_t* size)
{
struct stat s;
*exists = false;
*isDirectory = false;
if (exists != NULL)
*exists = false;
if (-1 == stat(directory.Path(), &s)) {
if (isDirectory != NULL)
*isDirectory = false;
if (size != NULL)
*size = 0;
if (-1 == stat(path.Path(), &s)) {
if (ENOENT != errno)
return B_ERROR;
} else {
*exists = true;
*isDirectory = S_ISDIR(s.st_mode);
if (exists != NULL)
*exists = true;
if (isDirectory != NULL)
*isDirectory = S_ISDIR(s.st_mode);
if (size != NULL)
*size = s.st_size;
}
return B_OK;

View File

@ -2,7 +2,6 @@
* Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PATH_UTILS_H
#define PATH_UTILS_H
@ -13,9 +12,10 @@ class StorageUtils {
public:
static status_t RemoveDirectoryContents(BPath& path);
static status_t AppendToString(BPath& path, BString& result);
static status_t ExistsDirectory(BPath& directory,
static status_t ExistsObject(BPath& directory,
bool* exists,
bool* isDirectory);
bool* isDirectory,
off_t* size);
};
#endif // PATH_UTILS_H

View File

@ -18,6 +18,7 @@ ToFileUrlProtocolListener::ToFileUrlProtocolListener(BPath path,
fTraceLoggingIdentifier = traceLoggingIdentifier;
fTraceLogging = traceLogging;
fShouldDownload = true;
fContentLength = 0;
}
@ -70,6 +71,8 @@ void
ToFileUrlProtocolListener::DataReceived(BUrlRequest* caller, const char* data,
off_t position, ssize_t size)
{
fContentLength += size;
if (fShouldDownload && fDownloadIO != NULL && size > 0) {
size_t remaining = size;
size_t written = 0;
@ -116,3 +119,9 @@ ToFileUrlProtocolListener::DebugMessage(BUrlRequest* caller,
}
}
ssize_t
ToFileUrlProtocolListener::ContentLength()
{
return fContentLength;
}

View File

@ -13,6 +13,8 @@ public:
bool traceLogging);
virtual ~ToFileUrlProtocolListener();
ssize_t ContentLength();
void ConnectionOpened(BUrlRequest* caller);
void HostnameResolved(BUrlRequest* caller,
const char* ip);
@ -37,6 +39,7 @@ private:
bool fTraceLogging;
BString fTraceLoggingIdentifier;
BPositionIO* fDownloadIO;
ssize_t fContentLength;
};

View File

@ -122,7 +122,7 @@ public:
TestBulkContainerItemListener();
virtual ~TestBulkContainerItemListener();
void Handle(DumpExportRepository* item);
bool Handle(DumpExportRepository* item);
void Complete();
BString ConcatenatedCodes();
@ -261,7 +261,7 @@ TestBulkContainerItemListener::~TestBulkContainerItemListener()
for this.
*/
void
bool
TestBulkContainerItemListener::Handle(DumpExportRepository* item)
{
int32 i;
@ -278,6 +278,8 @@ TestBulkContainerItemListener::Handle(DumpExportRepository* item)
fConcatenatedSourcesUrl.Append(
item->RepositorySourcesItemAt(i)->Url()->String());
}
return true;
}

View File

@ -8,6 +8,7 @@
#include "StandardMetaDataJsonEventListenerTest.h"
#include "DumpExportRepositoryJsonListenerTest.h"
#include "ListTest.h"
BTestSuite*
getTestSuite()
@ -16,6 +17,7 @@ getTestSuite()
StandardMetaDataJsonEventListenerTest::AddTests(*suite);
DumpExportRepositoryJsonListenerTest::AddTests(*suite);
ListTest::AddTests(*suite);
return suite;
}

View File

@ -9,6 +9,16 @@ SubDirHdrs [ FDirName $(HAIKU_TOP) src apps haikudepot server dumpexportreposito
UsePrivateHeaders shared ;
local sourceDirs =
server
server/dumpexportrepository
;
local sourceDir ;
for sourceDir in $(sourceDirs) {
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src apps haikudepot $(sourceDir) ] ;
}
UnitTestLib haikudepottest.so :
HaikuDepotTestAddon.cpp
@ -17,15 +27,11 @@ UnitTestLib haikudepottest.so :
DumpExportRepositoryJsonListener.cpp
DumpExportRepositoryJsonListenerTest.cpp
ListTest.cpp
StandardMetaData.cpp
StandardMetaDataJsonEventListener.cpp
StandardMetaDataJsonEventListenerTest.cpp
: be shared bnetapi [ TargetLibstdc++ ] [ TargetLibsupc++ ]
;
SEARCH on [ FGristFiles StandardMetaData.cpp StandardMetaDataJsonEventListener.cpp ]
= [ FDirName $(HAIKU_TOP) src apps haikudepot server ] ;
SEARCH on [ FGristFiles DumpExportRepositorySource.cpp DumpExportRepository.cpp DumpExportRepositoryJsonListener.cpp ]
= [ FDirName $(HAIKU_TOP) src apps haikudepot server dumpexportrepository ] ;
: be shared bnetapi package [ TargetLibstdc++ ] [ TargetLibsupc++ ]
;