HaikuDepot: code-generation improvements
The HaikuDepot server's schemas are surfaced into HaikuDepot and then code-generated so that they can easily stay at parity with the server and any issues will be caught at build-time. Changes included; - improves the Jam build files' readability - changes the generated models to be immutable - changes the generated models to use `BReferenceable` - changes the creation of the models to use a builder pattern - changes string fields to use BString instead of BString* - outputs the model to a single file with ordered classes - makes corresponding changes to the listener for the model changes - changes the listener to use references instead of object pointers Purpose; - improve / tidy the as-built code generation system - prepare the system for potential use with REST APIs later - prepare the system for potential use for internal models Notable file modifications; - the file `HdsSchemaGenRules` has been renamed to `JsonSchemaGenRules` and edited - the file `hdsjsonschemacommon.py` has been renamed to `jsonschemacommon.py` and edited - the templates from `jsonschema2cppmodel.py` have been externalized into `modelheader.mustache` and `modelimplementation.mustache` - the templates from `jsonschema2cppparser.py` have been externalized into `parserheader.mustache` and `parserimplementation.mustache` Change-Id: I809efd2e40d9227939ab83f18f1deda27873f03f Reviewed-on: https://review.haiku-os.org/c/haiku/+/10612 Tested-by: Commit checker robot <[email protected]> Reviewed-by: Jérôme Duval <[email protected]>
This commit is contained in:
+119
-133
@@ -3,56 +3,59 @@ SubDir HAIKU_TOP src apps haikudepot ;
|
||||
# disable -Werror for this directory only
|
||||
SubDirC++Flags -Wno-error ;
|
||||
|
||||
include [ FDirName $(SUBDIR) build jam HdsSchemaGenRules ] ;
|
||||
include [ FDirName $(SUBDIR) build jam JsonSchemaGenRules ] ;
|
||||
|
||||
UsePrivateHeaders interface net netservices package shared storage ;
|
||||
UsePrivateHeaders support locale ;
|
||||
|
||||
HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY = $(TARGET_COMMON_DEBUG_LOCATE_TARGET) ;
|
||||
|
||||
# Generated sources JSON Schemas
|
||||
|
||||
local genServerDumpExportPkgSchema =
|
||||
[ FDirName $(SUBDIR) server schema dumpexportpkg.json ] ;
|
||||
local genServerDumpExportRepositorySchema =
|
||||
[ FDirName $(SUBDIR) server schema dumpexportrepository.json ] ;
|
||||
local genServerDumpExportReferenceSchema =
|
||||
[ FDirName $(SUBDIR) server schema dumpexportreference.json ] ;
|
||||
|
||||
# During the build process, some sources are generated into directories. These
|
||||
# are the directories.
|
||||
|
||||
local dumpExportRepositoryBulkListenerTargetDirectory =
|
||||
[ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY)
|
||||
dumpexportrepositorybulklistener ] ;
|
||||
local dumpExportPkgBulkListenerTargetDirectory =
|
||||
[ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY)
|
||||
dumpexportpkgbulklistener ] ;
|
||||
local dumpExportReferenceListenerTargetDirectory =
|
||||
[ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY)
|
||||
dumpexportreferencelistener ] ;
|
||||
local genServerDumpExportRepositoryBulkListenerTargetDirectory =
|
||||
[ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY) dumpexportrepositorybulklistener ] ;
|
||||
local genServerDumpExportPkgBulkListenerTargetDirectory =
|
||||
[ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY) dumpexportpkgbulklistener ] ;
|
||||
local genServerDumpExportReferenceListenerTargetDirectory =
|
||||
[ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY) dumpexportreferencelistener ] ;
|
||||
|
||||
local dumpExportPkgModelTargetDirectory =
|
||||
[ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY)
|
||||
dumpexportpkgmodel ] ;
|
||||
local dumpExportRepositoryModelTargetDirectory =
|
||||
[ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY)
|
||||
dumpexportrepositorymodel ] ;
|
||||
local dumpExportReferenceModelTargetDirectory =
|
||||
[ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY)
|
||||
dumpexportreferencemodel ] ;
|
||||
local genServerDumpExportPkgModelTargetDirectory =
|
||||
[ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY) dumpexportpkgmodel ] ;
|
||||
local genServerDumpExportRepositoryModelTargetDirectory =
|
||||
[ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY) dumpexportrepositorymodel ] ;
|
||||
local genServerDumpExportReferenceModelTargetDirectory =
|
||||
[ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY) dumpexportreferencemodel ] ;
|
||||
|
||||
# During the build process, some sources are generated into a directory. In
|
||||
# order to maintain a timestamp on that generation process, a dummy file is
|
||||
# used to signify the target of the generation. The leafname of this dummy file
|
||||
# is defined here.
|
||||
|
||||
local dummyFile = "dummy.dat" ;
|
||||
local genDummyFile = "dummy.dat" ;
|
||||
|
||||
local dumpExportRepositoryBulkListenerTargetFile =
|
||||
[ FDirName $(dumpExportRepositoryBulkListenerTargetDirectory) $(dummyFile) ] ;
|
||||
local dumpExportPkgBulkListenerTargetFile =
|
||||
[ FDirName $(dumpExportPkgBulkListenerTargetDirectory) $(dummyFile) ] ;
|
||||
local dumpExportReferenceListenerTargetFile =
|
||||
[ FDirName $(dumpExportReferenceListenerTargetDirectory) $(dummyFile) ] ;
|
||||
local genServerDumpExportRepositoryBulkListenerTargetFile =
|
||||
[ FDirName $(genServerDumpExportRepositoryBulkListenerTargetDirectory) $(genDummyFile) ] ;
|
||||
local genServerDumpExportPkgBulkListenerTargetFile =
|
||||
[ FDirName $(genServerDumpExportPkgBulkListenerTargetDirectory) $(genDummyFile) ] ;
|
||||
local genServerDumpExportReferenceListenerTargetFile =
|
||||
[ FDirName $(genServerDumpExportReferenceListenerTargetDirectory) $(genDummyFile) ] ;
|
||||
|
||||
local dumpExportPkgModelTargetFile =
|
||||
[ FDirName $(dumpExportPkgModelTargetDirectory) $(dummyFile) ] ;
|
||||
local dumpExportRepositoryModelTargetFile =
|
||||
[ FDirName $(dumpExportRepositoryModelTargetDirectory) $(dummyFile) ] ;
|
||||
local dumpExportReferenceModelTargetFile =
|
||||
[ FDirName $(dumpExportReferenceModelTargetDirectory) $(dummyFile) ] ;
|
||||
local genServerDumpExportPkgModelTargetFile =
|
||||
[ FDirName $(genServerDumpExportPkgModelTargetDirectory) $(genDummyFile) ] ;
|
||||
local genServerDumpExportRepositoryModelTargetFile =
|
||||
[ FDirName $(genServerDumpExportRepositoryModelTargetDirectory) $(genDummyFile) ] ;
|
||||
local genServerDumpExportReferenceModelTargetFile =
|
||||
[ FDirName $(genServerDumpExportReferenceModelTargetDirectory) $(genDummyFile) ] ;
|
||||
|
||||
# source directories
|
||||
local sourceDirs =
|
||||
@@ -77,13 +80,13 @@ for sourceDir in $(sourceDirs) {
|
||||
|
||||
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src servers package ] ;
|
||||
|
||||
SEARCH_SOURCE += $(dumpExportRepositoryBulkListenerTargetDirectory) ;
|
||||
SEARCH_SOURCE += $(dumpExportPkgBulkListenerTargetDirectory) ;
|
||||
SEARCH_SOURCE += $(dumpExportReferenceListenerTargetDirectory) ;
|
||||
SEARCH_SOURCE += $(genServerDumpExportRepositoryBulkListenerTargetDirectory) ;
|
||||
SEARCH_SOURCE += $(genServerDumpExportPkgBulkListenerTargetDirectory) ;
|
||||
SEARCH_SOURCE += $(genServerDumpExportReferenceListenerTargetDirectory) ;
|
||||
|
||||
SEARCH_SOURCE += $(dumpExportPkgModelTargetDirectory) ;
|
||||
SEARCH_SOURCE += $(dumpExportRepositoryModelTargetDirectory) ;
|
||||
SEARCH_SOURCE += $(dumpExportReferenceModelTargetDirectory) ;
|
||||
SEARCH_SOURCE += $(genServerDumpExportPkgModelTargetDirectory) ;
|
||||
SEARCH_SOURCE += $(genServerDumpExportRepositoryModelTargetDirectory) ;
|
||||
SEARCH_SOURCE += $(genServerDumpExportReferenceModelTargetDirectory) ;
|
||||
|
||||
local textDocumentSources =
|
||||
# edits_generic
|
||||
@@ -242,49 +245,30 @@ local applicationSources =
|
||||
ResultWindow.cpp
|
||||
;
|
||||
|
||||
local generatedPkgModelSourceFiles =
|
||||
DumpExportPkg.cpp
|
||||
DumpExportPkgCategory.cpp
|
||||
DumpExportPkgScreenshot.cpp
|
||||
DumpExportPkgVersion.cpp
|
||||
;
|
||||
local genServerPkgModelSourceFiles =
|
||||
DumpExportPkgModel.cpp ;
|
||||
local genServerRepositoryModelSourceFiles =
|
||||
DumpExportRepositoryModel.cpp ;
|
||||
local genServerReferenceModelSourceFiles =
|
||||
DumpExportReferenceModel.cpp ;
|
||||
|
||||
local generatedRepositoryModelSourceFiles =
|
||||
DumpExportRepository.cpp
|
||||
DumpExportRepositorySource.cpp
|
||||
DumpExportRepositorySourceMirror.cpp
|
||||
;
|
||||
|
||||
local generatedReferenceModelSourceFiles =
|
||||
DumpExportReference.cpp
|
||||
DumpExportReferenceNaturalLanguage.cpp
|
||||
DumpExportReferencePkgCategory.cpp
|
||||
DumpExportReferenceUserRatingStability.cpp
|
||||
DumpExportReferenceCountry.cpp
|
||||
;
|
||||
|
||||
local generatedPkgParserSourceFiles =
|
||||
DumpExportPkgJsonListener.cpp
|
||||
;
|
||||
|
||||
local generatedRepositoryParserSourceFiles =
|
||||
DumpExportRepositoryJsonListener.cpp
|
||||
;
|
||||
|
||||
local generatedReferenceParserSourceFiles =
|
||||
DumpExportReferenceJsonListener.cpp
|
||||
;
|
||||
local genServerPkgParserSourceFiles =
|
||||
DumpExportPkgJsonListener.cpp ;
|
||||
local genServerRepositoryParserSourceFiles =
|
||||
DumpExportRepositoryJsonListener.cpp ;
|
||||
local genServerReferenceParserSourceFiles =
|
||||
DumpExportReferenceJsonListener.cpp ;
|
||||
|
||||
Application HaikuDepot
|
||||
:
|
||||
$(applicationSources)
|
||||
$(textDocumentSources)
|
||||
$(generatedPkgModelSourceFiles)
|
||||
$(generatedRepositoryModelSourceFiles)
|
||||
$(generatedReferenceModelSourceFiles)
|
||||
$(generatedPkgParserSourceFiles)
|
||||
$(generatedRepositoryParserSourceFiles)
|
||||
$(generatedReferenceParserSourceFiles)
|
||||
$(genServerPkgModelSourceFiles)
|
||||
$(genServerRepositoryModelSourceFiles)
|
||||
$(genServerReferenceModelSourceFiles)
|
||||
$(genServerPkgParserSourceFiles)
|
||||
$(genServerRepositoryParserSourceFiles)
|
||||
$(genServerReferenceParserSourceFiles)
|
||||
:
|
||||
be package bnetapi translation libnetservices.a libcolumnlistview.a shared
|
||||
[ TargetLibstdc++ ] [ TargetLibsupc++ ] localestub
|
||||
@@ -302,79 +286,81 @@ DoCatalogs HaikuDepot :
|
||||
# JSON schemas that are defined in the HaikuDepotServer system. See the
|
||||
# included Jam rules and actions for the definitions.
|
||||
|
||||
HdsSchemaGenModel $(dumpExportPkgModelTargetFile)
|
||||
: dumpexportpkg.json : jsonschema2cppmodel.py ;
|
||||
JsonSchemaGenModel $(genServerDumpExportPkgModelTargetFile)
|
||||
: $(genServerDumpExportPkgSchema) ;
|
||||
JsonSchemaGenModel $(genServerDumpExportRepositoryModelTargetFile)
|
||||
: $(genServerDumpExportRepositorySchema) ;
|
||||
JsonSchemaGenModel $(genServerDumpExportReferenceModelTargetFile)
|
||||
: $(genServerDumpExportReferenceSchema) ;
|
||||
|
||||
HdsSchemaGenModel $(dumpExportRepositoryModelTargetFile)
|
||||
: dumpexportrepository.json : jsonschema2cppmodel.py ;
|
||||
JsonSchemaGenParser $(genServerDumpExportRepositoryBulkListenerTargetFile)
|
||||
: $(genServerDumpExportRepositorySchema) ;
|
||||
JsonSchemaGenParser $(genServerDumpExportPkgBulkListenerTargetFile)
|
||||
: $(genServerDumpExportPkgSchema) ;
|
||||
JsonSchemaGenParser $(genServerDumpExportReferenceListenerTargetFile)
|
||||
: $(genServerDumpExportReferenceSchema) ;
|
||||
|
||||
HdsSchemaGenModel $(dumpExportReferenceModelTargetFile)
|
||||
: dumpexportreference.json : jsonschema2cppmodel.py ;
|
||||
JsonSchemaGenAppSrcDependsOnGeneration
|
||||
[ FGristFiles $(genServerPkgParserSourceFiles) ]
|
||||
[ FGristFiles $(genServerPkgParserSourceFiles:S=.h) ]
|
||||
: $(genServerDumpExportPkgBulkListenerTargetDirectory)
|
||||
: $(genServerDumpExportPkgBulkListenerTargetFile)
|
||||
;
|
||||
|
||||
HdsSchemaGenBulkParser $(dumpExportRepositoryBulkListenerTargetFile)
|
||||
: dumpexportrepository.json : jsonschema2cppparser.py ;
|
||||
JsonSchemaGenAppSrcDependsOnGeneration
|
||||
[ FGristFiles $(genServerRepositoryParserSourceFiles) ]
|
||||
[ FGristFiles $(genServerRepositoryParserSourceFiles:S=.h) ]
|
||||
: $(genServerDumpExportRepositoryBulkListenerTargetDirectory)
|
||||
: $(genServerDumpExportRepositoryBulkListenerTargetFile)
|
||||
;
|
||||
|
||||
HdsSchemaGenBulkParser $(dumpExportPkgBulkListenerTargetFile)
|
||||
: dumpexportpkg.json : jsonschema2cppparser.py ;
|
||||
JsonSchemaGenAppSrcDependsOnGeneration
|
||||
[ FGristFiles $(genServerReferenceParserSourceFiles) ]
|
||||
[ FGristFiles $(genServerReferenceParserSourceFiles:S=.h) ]
|
||||
: $(genServerDumpExportReferenceListenerTargetDirectory)
|
||||
: $(genServerDumpExportReferenceListenerTargetFile)
|
||||
;
|
||||
|
||||
HdsSchemaGenParser $(dumpExportReferenceListenerTargetFile)
|
||||
: dumpexportreference.json : jsonschema2cppparser.py ;
|
||||
JsonSchemaGenAppSrcDependsOnGeneration
|
||||
[ FGristFiles $(genServerRepositoryModelSourceFiles) ]
|
||||
[ FGristFiles $(genServerRepositoryModelSourceFiles:S=.h) ]
|
||||
: $(genServerDumpExportRepositoryModelTargetDirectory)
|
||||
: $(genServerDumpExportRepositoryModelTargetFile)
|
||||
;
|
||||
|
||||
HdsSchemaGenAppSrcDependsOnGeneration
|
||||
[ FGristFiles $(generatedPkgParserSourceFiles) ]
|
||||
[ FGristFiles $(generatedPkgParserSourceFiles:S=.h) ]
|
||||
: $(dumpExportPkgBulkListenerTargetDirectory)
|
||||
: $(dumpExportPkgBulkListenerTargetFile) ;
|
||||
JsonSchemaGenAppSrcDependsOnGeneration
|
||||
[ FGristFiles $(genServerPkgModelSourceFiles) ]
|
||||
[ FGristFiles $(genServerPkgModelSourceFiles:S=.h) ]
|
||||
: $(genServerDumpExportPkgModelTargetDirectory)
|
||||
: $(genServerDumpExportPkgModelTargetFile)
|
||||
;
|
||||
|
||||
HdsSchemaGenAppSrcDependsOnGeneration
|
||||
[ FGristFiles $(generatedRepositoryParserSourceFiles) ]
|
||||
[ FGristFiles $(generatedRepositoryParserSourceFiles:S=.h) ]
|
||||
: $(dumpExportRepositoryBulkListenerTargetDirectory)
|
||||
: $(dumpExportRepositoryBulkListenerTargetFile) ;
|
||||
|
||||
HdsSchemaGenAppSrcDependsOnGeneration
|
||||
[ FGristFiles $(generatedReferenceParserSourceFiles) ]
|
||||
[ FGristFiles $(generatedReferenceParserSourceFiles:S=.h) ]
|
||||
: $(dumpExportReferenceListenerTargetDirectory)
|
||||
: $(dumpExportReferenceListenerTargetFile) ;
|
||||
|
||||
HdsSchemaGenAppSrcDependsOnGeneration
|
||||
[ FGristFiles $(generatedRepositoryModelSourceFiles) ]
|
||||
[ FGristFiles $(generatedRepositoryModelSourceFiles:S=.h) ]
|
||||
: $(dumpExportRepositoryModelTargetDirectory)
|
||||
: $(dumpExportRepositoryModelTargetFile) ;
|
||||
|
||||
HdsSchemaGenAppSrcDependsOnGeneration
|
||||
[ FGristFiles $(generatedPkgModelSourceFiles) ]
|
||||
[ FGristFiles $(generatedPkgModelSourceFiles:S=.h) ]
|
||||
: $(dumpExportPkgModelTargetDirectory)
|
||||
: $(dumpExportPkgModelTargetFile) ;
|
||||
|
||||
HdsSchemaGenAppSrcDependsOnGeneration
|
||||
[ FGristFiles $(generatedReferenceModelSourceFiles) ]
|
||||
[ FGristFiles $(generatedReferenceModelSourceFiles:S=.h) ]
|
||||
: $(dumpExportReferenceModelTargetDirectory)
|
||||
: $(dumpExportReferenceModelTargetFile) ;
|
||||
JsonSchemaGenAppSrcDependsOnGeneration
|
||||
[ FGristFiles $(genServerReferenceModelSourceFiles) ]
|
||||
[ FGristFiles $(genServerReferenceModelSourceFiles:S=.h) ]
|
||||
: $(genServerDumpExportReferenceModelTargetDirectory)
|
||||
: $(genServerDumpExportReferenceModelTargetFile)
|
||||
;
|
||||
|
||||
# This will ensure that if any of the generated files' header files change, then
|
||||
# the application should be re-built.
|
||||
|
||||
Includes [ FGristFiles $(applicationSources) ]
|
||||
:
|
||||
$(dumpExportRepositoryBulkListenerTargetDirectory)
|
||||
$(dumpExportPkgBulkListenerTargetDirectory)
|
||||
$(dumpExportReferenceListenerTargetDirectory)
|
||||
$(dumpExportPkgModelTargetDirectory)
|
||||
$(dumpExportRepositoryModelTargetDirectory)
|
||||
$(dumpExportReferenceModelTargetDirectory)
|
||||
$(genServerDumpExportRepositoryBulkListenerTargetDirectory)
|
||||
$(genServerDumpExportPkgBulkListenerTargetDirectory)
|
||||
$(genServerDumpExportReferenceListenerTargetDirectory)
|
||||
$(genServerDumpExportPkgModelTargetDirectory)
|
||||
$(genServerDumpExportRepositoryModelTargetDirectory)
|
||||
$(genServerDumpExportReferenceModelTargetDirectory)
|
||||
;
|
||||
|
||||
Depends [ FGristFiles $(applicationSources:S=.o) ]
|
||||
:
|
||||
[ FGristFiles $(generatedPkgParserSourceFiles:S=.h) ]
|
||||
[ FGristFiles $(generatedPkgModelSourceFiles:S=.h) ]
|
||||
[ FGristFiles $(generatedRepositoryParserSourceFiles:S=.h) ]
|
||||
[ FGristFiles $(generatedRepositoryModelSourceFiles:S=.h) ]
|
||||
[ FGristFiles $(generatedReferenceParserSourceFiles:S=.h) ]
|
||||
[ FGristFiles $(generatedReferenceModelSourceFiles:S=.h) ]
|
||||
[ FGristFiles $(genServerPkgParserSourceFiles:S=.h) ]
|
||||
[ FGristFiles $(genServerPkgModelSourceFiles:S=.h) ]
|
||||
[ FGristFiles $(genServerRepositoryParserSourceFiles:S=.h) ]
|
||||
[ FGristFiles $(genServerRepositoryModelSourceFiles:S=.h) ]
|
||||
[ FGristFiles $(genServerReferenceParserSourceFiles:S=.h) ]
|
||||
[ FGristFiles $(genServerReferenceModelSourceFiles:S=.h) ]
|
||||
;
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
# =====================================
|
||||
# Copyright 2019-2023, Andrew Lindesay
|
||||
# Distributed under the terms of the MIT License.
|
||||
# =====================================
|
||||
|
||||
# HaikuDepotServer has a number of data-transfer-objects (DTO) that are defined
|
||||
# by JSON schemas. The server uses these schemas to produce the objects at
|
||||
# compile time. Likewise, the schema files also generate C++ side DTO model
|
||||
# objects in the form of .cpp and .h files as well. This way the
|
||||
# HaikuDepotServer server and HaikuDepot desktop application are able to
|
||||
# communicate more 'safely'. The schema files still need to be copied from
|
||||
# the server source to the Haiku source, but the generation process will ensure
|
||||
# that the data-structures are consistent.
|
||||
#
|
||||
# The C++ side classes are generated with python scripts that are included in
|
||||
# the Haiku source. These rules and actions take care of making sure that the
|
||||
# python scripts are run when necessary to generate the C++ side classes. Note
|
||||
# that there are two sorts of classes generated here; the model DTO objects and
|
||||
# also the supporting classes that parse the DTO objects. The parsing classes
|
||||
# are intended to be used with Haiku JSON parsing systems.
|
||||
|
||||
# pragma mark - Generic
|
||||
|
||||
actions HdsSchemaGenTouch
|
||||
{
|
||||
touch $(1)
|
||||
}
|
||||
|
||||
# pragma mark - Model Class Generation
|
||||
|
||||
# 1 : the dummy file in the class generation directory (target)
|
||||
# 2 : the JSON schema file
|
||||
# 3 : the Python script to use
|
||||
|
||||
rule HdsSchemaGenModel
|
||||
{
|
||||
SEARCH on $(2) = [ FDirName $(SUBDIR) server schema ] ;
|
||||
SEARCH on $(3) = [ FDirName $(SUBDIR) build scripts ] ;
|
||||
|
||||
MkDir1 $(1:D) ;
|
||||
CleanDir clean : $(1:D) ;
|
||||
Depends $(1) : $(2) $(3) $(1:D) ;
|
||||
HdsSchemaGenModel1 $(1) : $(2) $(3) $(1:D) ;
|
||||
}
|
||||
|
||||
actions HdsSchemaGenModel1
|
||||
{
|
||||
$(HOST_PYTHON) $(2[2]) -i $(2[1]) --outputdirectory $(2[3])
|
||||
touch $(1)
|
||||
}
|
||||
|
||||
# pragma mark - Bulk Parsing Class Generation
|
||||
|
||||
# 1 : the dummy file in the class generation directory (target)
|
||||
# 2 : the JSON schema file
|
||||
# 3 : the Python script to use
|
||||
|
||||
rule HdsSchemaGenBulkParser
|
||||
{
|
||||
SEARCH on $(2) = [ FDirName $(SUBDIR) server schema ] ;
|
||||
SEARCH on $(3) = [ FDirName $(SUBDIR) build scripts ] ;
|
||||
|
||||
MkDir1 $(1:D) ;
|
||||
CleanDir clean : $(1:D) ;
|
||||
Depends $(1) : $(2) $(3) $(1:D) ;
|
||||
HdsSchemaGenBulkParser1 $(1) : $(2) $(3) $(1:D) ;
|
||||
}
|
||||
|
||||
actions HdsSchemaGenBulkParser1
|
||||
{
|
||||
$(HOST_PYTHON) $(2[2]) -i $(2[1]) --outputdirectory $(2[3])
|
||||
touch $(1)
|
||||
}
|
||||
|
||||
# pragma mark - Non-Bulk Parsing Class Generation
|
||||
|
||||
# 1 : the dummy file in the class generation directory (target)
|
||||
# 2 : the JSON schema file
|
||||
# 3 : the Python script to use
|
||||
|
||||
rule HdsSchemaGenParser
|
||||
{
|
||||
SEARCH on $(2) = [ FDirName $(SUBDIR) server schema ] ;
|
||||
SEARCH on $(3) = [ FDirName $(SUBDIR) build scripts ] ;
|
||||
|
||||
MkDir1 $(1:D) ;
|
||||
CleanDir clean : $(1:D) ;
|
||||
Depends $(1) : $(2) $(3) $(1:D) ;
|
||||
HdsSchemaGenParser1 $(1) : $(2) $(3) $(1:D) ;
|
||||
}
|
||||
|
||||
actions HdsSchemaGenParser1
|
||||
{
|
||||
$(HOST_PYTHON) $(2[2]) -i $(2[1]) --outputdirectory $(2[3])
|
||||
touch $(1)
|
||||
}
|
||||
|
||||
# pragma mark - Registering Generated Classes
|
||||
|
||||
# Because a number of .cpp and .h files will be generated from a single python
|
||||
# script's run, it is necessary to introduce a dependency between the known
|
||||
# output files and the target for a given python script run.
|
||||
|
||||
# 1 : generated files (.h and .cpp)
|
||||
# 2 : target directory generated files will be placed in
|
||||
# 3 : target that will generate the generated files (dummy file)
|
||||
|
||||
rule HdsSchemaGenAppSrcDependsOnGeneration {
|
||||
MakeLocate $(1) : $(2) ;
|
||||
MkDir1 $(2) ;
|
||||
Depends $(1) : $(2) $(3) ;
|
||||
Clean clean : $(1) ;
|
||||
|
||||
# just in case the dummy file ends up being newer than the generated
|
||||
# sources, update the modified timestamp on the generated files.
|
||||
HdsSchemaGenTouch $(1) ;
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
# =====================================
|
||||
# Copyright 2019-2026, Andrew Lindesay
|
||||
# Distributed under the terms of the MIT License.
|
||||
# =====================================
|
||||
|
||||
# HaikuDepotServer has a number of data-transfer-objects (DTO) that are defined
|
||||
# by JSON schemas. The server uses these schemas to produce the objects at
|
||||
# compile time. Likewise, the schema files also generate C++ side DTO model
|
||||
# objects in the form of .cpp and .h files as well. This way the
|
||||
# HaikuDepotServer server and HaikuDepot desktop application are able to
|
||||
# communicate more 'safely'. The schema files still need to be copied from
|
||||
# the server source to the Haiku source, but the generation process will ensure
|
||||
# that the data-structures are consistent.
|
||||
#
|
||||
# The C++ side classes are generated with python scripts that are included in
|
||||
# the Haiku source. These rules and actions take care of making sure that the
|
||||
# python scripts are run when necessary to generate the C++ side classes. Note
|
||||
# that there are two sorts of classes generated here; the model DTO objects and
|
||||
# also the supporting classes that parse the DTO objects. The parsing classes
|
||||
# are intended to be used with Haiku JSON parsing systems.
|
||||
|
||||
# =====================================
|
||||
# pragma mark - Generic
|
||||
|
||||
actions JsonSchemaGenTouch
|
||||
{
|
||||
touch $(1)
|
||||
}
|
||||
|
||||
# Because a number of .cpp and .h files will be generated from a single python
|
||||
# script's run, it is necessary to introduce a dependency between the known
|
||||
# output files and the target for a given python script run.
|
||||
|
||||
# 1 : generated files (.h and .cpp)
|
||||
# 2 : target directory generated files will be placed in
|
||||
# 3 : target that will generate the generated files (dummy file)
|
||||
|
||||
rule JsonSchemaGenAppSrcDependsOnGeneration {
|
||||
local generatedFiles = $(1) ;
|
||||
local targetDirectory = $(2) ;
|
||||
local dummy = $(3) ;
|
||||
|
||||
MakeLocate $(generatedFiles) : $(targetDirectory) ;
|
||||
MkDir1 $(targetDirectory) ;
|
||||
Depends $(generatedFiles) : $(targetDirectory) $(dummy) ;
|
||||
Clean clean : $(generatedFiles) ;
|
||||
|
||||
# just in case the dummy file ends up being newer than the generated
|
||||
# sources, update the modified timestamp on the generated files.
|
||||
JsonSchemaGenTouch $(generatedFiles) ;
|
||||
}
|
||||
|
||||
# =====================================
|
||||
# pragma mark - Model Class Generation
|
||||
|
||||
# This section is responsible for generation of .h and .cpp files which
|
||||
# represent the data model described in the supplied JSON schema file. These
|
||||
# files do not include parsers.
|
||||
#
|
||||
# A dummy file is used as a dependency item which then has the two generated
|
||||
# file as it's dependency. This approach avoids complications around the
|
||||
# generated target being two files rather than one.
|
||||
|
||||
# 1 : the dummy file in the class generation directory (target)
|
||||
# 2 : the JSON schema file
|
||||
|
||||
rule JsonSchemaGenModel
|
||||
{
|
||||
local dummy = $(1) ;
|
||||
local schema = $(2) ;
|
||||
|
||||
local script = [ FDirName $(HAIKU_TOP) src apps haikudepot build scripts jsonschema2cppmodel.py ] ;
|
||||
local commonScript = [ FDirName $(HAIKU_TOP) src apps haikudepot build scripts jsonschemacommon.py ] ;
|
||||
local headerTemplate = [ FDirName $(HAIKU_TOP) src apps haikudepot build scripts template modelheader.mustache ] ;
|
||||
local implementationTemplate = [ FDirName $(HAIKU_TOP) src apps haikudepot build scripts template modelimplementation.mustache ] ;
|
||||
|
||||
MkDir1 $(dummy:D) ;
|
||||
CleanDir clean : $(dummy:D) ;
|
||||
Depends $(dummy) : $(schema) $(script) $(commonScript) $(headerTemplate) $(implementationTemplate) $(dummy:D) ;
|
||||
JsonSchemaGenModel1 $(dummy) : $(schema) $(script) $(dummy:D) ;
|
||||
}
|
||||
|
||||
actions JsonSchemaGenModel1
|
||||
{
|
||||
$(HOST_PYTHON) $(2[2]) --jsonschemafile $(2[1]) --outputdirectory $(2[3])
|
||||
touch $(1)
|
||||
}
|
||||
|
||||
# =====================================
|
||||
# pragma mark - Parsing Class Generation
|
||||
|
||||
# This section is responsible for generation of .h and .cpp files which
|
||||
# represent a listener that is intended for use with the `BJson` class to
|
||||
# parse JSON data according to a supplied JSON Schema model. The C++
|
||||
# representation of the schema as a model must be also generated with
|
||||
# `JsonSchemaGenModel`.
|
||||
#
|
||||
# A dummy file is used as a dependency item which then has the two generated
|
||||
# file as it's dependency. This approach avoids complications around the
|
||||
# generated target being two files rather than one.
|
||||
|
||||
# 1 : the dummy file in the class generation directory (target)
|
||||
# 2 : the JSON schema file
|
||||
|
||||
rule JsonSchemaGenParser
|
||||
{
|
||||
local dummy = $(1) ;
|
||||
local schema = $(2) ;
|
||||
|
||||
local script = [ FDirName $(HAIKU_TOP) src apps haikudepot build scripts jsonschema2cppparser.py ] ;
|
||||
local commonScript = [ FDirName $(HAIKU_TOP) src apps haikudepot build scripts jsonschemacommon.py ] ;
|
||||
local headerTemplate = [ FDirName $(HAIKU_TOP) src apps haikudepot build scripts template modelheader.mustache ] ;
|
||||
local implementationTemplate = [ FDirName $(HAIKU_TOP) src apps haikudepot build scripts template modelimplementation.mustache ] ;
|
||||
|
||||
MkDir1 $(dummy:D) ;
|
||||
CleanDir clean : $(dummy:D) ;
|
||||
Depends $(dummy) : $(schema) $(script) $(commonScript) $(headerTemplate) $(implementationTemplate) $(dummy:D) ;
|
||||
JsonSchemaGenParser1 $(dummy) : $(schema) $(script) $(dummy:D) ;
|
||||
}
|
||||
|
||||
actions JsonSchemaGenParser1
|
||||
{
|
||||
$(HOST_PYTHON) $(2[2]) --jsonschemafile $(2[1]) --outputdirectory $(2[3])
|
||||
touch $(1)
|
||||
}
|
||||
@@ -1,267 +0,0 @@
|
||||
|
||||
# =====================================
|
||||
# Copyright 2017-2023, Andrew Lindesay
|
||||
# Distributed under the terms of the MIT License.
|
||||
# =====================================
|
||||
|
||||
# common material related to generation of schema-generated artifacts.
|
||||
|
||||
import datetime
|
||||
|
||||
|
||||
# The possible JSON types
|
||||
JSON_TYPE_STRING = "string"
|
||||
JSON_TYPE_OBJECT = "object"
|
||||
JSON_TYPE_ARRAY = "array"
|
||||
JSON_TYPE_BOOLEAN = "boolean"
|
||||
JSON_TYPE_INTEGER = "integer"
|
||||
JSON_TYPE_NUMBER = "number"
|
||||
|
||||
|
||||
# The possible C++ types
|
||||
CPP_TYPE_STRING = "BString"
|
||||
CPP_TYPE_ARRAY = "BObjectList"
|
||||
CPP_TYPE_BOOLEAN = "bool"
|
||||
CPP_TYPE_INTEGER = "int64"
|
||||
CPP_TYPE_NUMBER = "double"
|
||||
|
||||
|
||||
# The possible C++ default values
|
||||
CPP_DEFAULT_STRING = "NULL"
|
||||
CPP_DEFAULT_OBJECT = "NULL"
|
||||
CPP_DEFAULT_ARRAY = "NULL"
|
||||
CPP_DEFAULT_BOOLEAN = "false"
|
||||
CPP_DEFAULT_INTEGER = "0"
|
||||
CPP_DEFAULT_NUMBER = "0.0"
|
||||
|
||||
|
||||
def uniondicts(d1, d2):
|
||||
d = dict(d1)
|
||||
d.update(d2)
|
||||
return d
|
||||
|
||||
|
||||
def javatypetocppname(javaname):
|
||||
return javaname[javaname.rindex('.')+1:]
|
||||
|
||||
|
||||
def propnametocppname(propname):
|
||||
return propname[0:1].upper() + propname[1:]
|
||||
|
||||
|
||||
def propnametocppmembername(propname):
|
||||
return "f" + propnametocppname(propname)
|
||||
|
||||
def propmetadatatocppdefaultvalue(propmetadata):
|
||||
type = propmetadata['type']
|
||||
|
||||
if type == JSON_TYPE_STRING:
|
||||
return CPP_DEFAULT_STRING
|
||||
if type == JSON_TYPE_BOOLEAN:
|
||||
return CPP_DEFAULT_BOOLEAN
|
||||
if type == JSON_TYPE_INTEGER:
|
||||
return CPP_DEFAULT_INTEGER
|
||||
if type == JSON_TYPE_NUMBER:
|
||||
return CPP_DEFAULT_NUMBER
|
||||
if type == JSON_TYPE_OBJECT:
|
||||
return CPP_DEFAULT_OBJECT
|
||||
if type == JSON_TYPE_ARRAY:
|
||||
return CPP_DEFAULT_ARRAY
|
||||
|
||||
raise Exception('unknown json-schema type [' + type + ']')
|
||||
|
||||
def propmetadatatocpptypename(propmetadata):
|
||||
type = propmetadata['type']
|
||||
|
||||
if type == JSON_TYPE_STRING:
|
||||
return CPP_TYPE_STRING
|
||||
if type == JSON_TYPE_BOOLEAN:
|
||||
return CPP_TYPE_BOOLEAN
|
||||
if type == JSON_TYPE_INTEGER:
|
||||
return CPP_TYPE_INTEGER
|
||||
if type == JSON_TYPE_NUMBER:
|
||||
return CPP_TYPE_NUMBER
|
||||
if type == JSON_TYPE_OBJECT:
|
||||
javatype = propmetadata['javaType']
|
||||
|
||||
if not javatype or 0 == len(javatype):
|
||||
raise Exception('missing "javaType" field')
|
||||
|
||||
return javatypetocppname(javatype)
|
||||
|
||||
if type == JSON_TYPE_ARRAY:
|
||||
itemsmetadata = propmetadata['items']
|
||||
itemstype = itemsmetadata['type']
|
||||
|
||||
if not itemstype or 0 == len(itemstype):
|
||||
raise Exception('missing "type" field')
|
||||
|
||||
if itemstype == JSON_TYPE_OBJECT:
|
||||
itemsjavatype = itemsmetadata['javaType']
|
||||
if not itemsjavatype or 0 == len(itemsjavatype):
|
||||
raise Exception('missing "javaType" field')
|
||||
return "%s<%s>" % (CPP_TYPE_ARRAY, javatypetocppname(itemsjavatype))
|
||||
|
||||
if itemstype == JSON_TYPE_STRING:
|
||||
return "%s<%s>" % (CPP_TYPE_ARRAY, CPP_TYPE_STRING)
|
||||
|
||||
raise Exception('unsupported type [%s]' % itemstype)
|
||||
|
||||
raise Exception('unknown json-schema type [' + type + ']')
|
||||
|
||||
|
||||
def propmetadatatypeisscalar(propmetadata):
|
||||
type = propmetadata['type']
|
||||
return type == JSON_TYPE_BOOLEAN or type == JSON_TYPE_INTEGER or type == JSON_TYPE_NUMBER
|
||||
|
||||
|
||||
def writetopcomment(f, inputfilename, variant):
|
||||
f.write((
|
||||
'/*\n'
|
||||
' * Generated %s Object\n'
|
||||
' * source json-schema : %s\n'
|
||||
' * generated at : %s\n'
|
||||
' */\n'
|
||||
) % (variant, inputfilename, datetime.datetime.now().isoformat()))
|
||||
|
||||
def collect_all_objects(schema: dict[str, any]) -> list[dict[str, any]]:
|
||||
assembly = dict[str, dict[str, any]]()
|
||||
|
||||
def accumulate_all_objects(obj: dict[str, any]) -> None:
|
||||
assembly[obj["cppname"]] = obj
|
||||
|
||||
for prop_name, prop in obj['properties'].items():
|
||||
if JSON_TYPE_ARRAY == prop["type"]:
|
||||
array_items = prop['items']
|
||||
|
||||
if JSON_TYPE_OBJECT == array_items["type"] and not array_items["cppname"] in assembly:
|
||||
accumulate_all_objects(array_items)
|
||||
|
||||
if JSON_TYPE_OBJECT == prop["type"] and not prop["cppname"] in assembly:
|
||||
accumulate_all_objects(prop)
|
||||
|
||||
accumulate_all_objects(schema)
|
||||
result = list(assembly.values())
|
||||
result.sort(key= lambda v: v["cppname"])
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def augment_schema(schema: dict[str, any]) -> None:
|
||||
"""This function will take the data from the JSON schema and will overlay any
|
||||
specific information required for rendering the templates.
|
||||
"""
|
||||
|
||||
def derive_cpp_classname(obj: dict[str, any]) -> str:
|
||||
obj_type = obj['type']
|
||||
|
||||
if obj_type != JSON_TYPE_OBJECT:
|
||||
raise Exception('expecting object, but was [' + obj_type + ']')
|
||||
|
||||
java_type = obj['javaType']
|
||||
|
||||
return javatypetocppname(java_type)
|
||||
|
||||
def augment_property(prop: dict[str, any]) -> None:
|
||||
prop_type = prop['type']
|
||||
|
||||
prop["cpptype"] = propmetadatatocpptypename(prop)
|
||||
|
||||
is_scalar_type = propmetadatatypeisscalar(prop)
|
||||
is_array_type = (prop_type == JSON_TYPE_ARRAY)
|
||||
|
||||
prop["iscppscalartype"] = is_scalar_type
|
||||
prop["isarray"] = is_array_type
|
||||
prop["isstring"] = JSON_TYPE_STRING == prop_type
|
||||
prop["isboolean"] = JSON_TYPE_BOOLEAN == prop_type
|
||||
prop["isnumber"] = JSON_TYPE_NUMBER == prop_type
|
||||
prop["isinteger"] = JSON_TYPE_INTEGER == prop_type
|
||||
prop["isobject"] = JSON_TYPE_OBJECT == prop_type
|
||||
prop["iscppnonscalarnoncollectiontype"] = not is_scalar_type and not is_array_type
|
||||
prop["toplevelcppname"] = top_level_cpp_name
|
||||
prop["cppdefaultvalue"] = propmetadatatocppdefaultvalue(prop)
|
||||
|
||||
if not prop_type or 0 == len(prop_type):
|
||||
raise Exception('missing "type" field')
|
||||
|
||||
if JSON_TYPE_ARRAY == prop_type:
|
||||
array_items = prop['items']
|
||||
array_items_type = array_items["type"]
|
||||
|
||||
if array_items_type == JSON_TYPE_OBJECT:
|
||||
augment_object(array_items)
|
||||
else:
|
||||
augment_property(array_items)
|
||||
|
||||
if JSON_TYPE_OBJECT == prop_type:
|
||||
augment_object(prop)
|
||||
|
||||
def augment_object(obj: dict[str, any]) -> None:
|
||||
|
||||
def collect_referenced_class_names() -> list[str]:
|
||||
result = set()
|
||||
properties = obj['properties'].items()
|
||||
|
||||
if len(properties) > 15:
|
||||
raise RuntimeError("an object has more than 15 properties"
|
||||
" which is not allowed")
|
||||
|
||||
for _, prop in obj['properties'].items():
|
||||
if prop['type'] == JSON_TYPE_ARRAY:
|
||||
array_items = prop['items']
|
||||
if array_items['type'] == JSON_TYPE_OBJECT:
|
||||
result.add(array_items['cppname'])
|
||||
if prop['type'] == JSON_TYPE_OBJECT:
|
||||
result.add(prop['cppname'])
|
||||
|
||||
result_ordered = list(result)
|
||||
result_ordered.sort()
|
||||
return result_ordered
|
||||
|
||||
def has_any_list_properties() -> bool:
|
||||
for _, prop in obj['properties'].items():
|
||||
if prop['type'] == JSON_TYPE_ARRAY:
|
||||
return True
|
||||
return False
|
||||
|
||||
obj_cpp_classname = derive_cpp_classname(obj)
|
||||
obj["cppname"] = obj_cpp_classname
|
||||
obj["cppnameupper"] = obj_cpp_classname.upper()
|
||||
obj["cpptype"] = obj_cpp_classname
|
||||
obj["hasanylistproperties"] = has_any_list_properties()
|
||||
|
||||
# allows the object to know the top level object that contains it
|
||||
obj["toplevelcppname"] = top_level_cpp_name
|
||||
|
||||
properties = obj['properties'].items()
|
||||
|
||||
for prop_name, prop in properties:
|
||||
prop["cppname"] = propnametocppname(prop_name)
|
||||
prop["cppmembername"] = propnametocppmembername(prop_name)
|
||||
augment_property(prop)
|
||||
|
||||
# mustache is not able to iterate over a dictionary; it can only
|
||||
# iterate over a list where each item in the list has some properties.
|
||||
|
||||
property_array = sorted(
|
||||
[{
|
||||
"name": k,
|
||||
"property": v,
|
||||
"cppobjectname": obj_cpp_classname
|
||||
# ^ this is the name of the containing object
|
||||
} for k,v in properties],
|
||||
key= lambda item: item["name"]
|
||||
)
|
||||
|
||||
for i in range(len(property_array)):
|
||||
property_array[i]["cppbitmaskexpression"] = "(1 << %d)" % i
|
||||
|
||||
if 0 != len(property_array):
|
||||
property_array[0]["isfirst"] = True
|
||||
property_array[len(property_array) - 1]["islast"] = True
|
||||
|
||||
obj["propertyarray"] = property_array
|
||||
obj["referencedclasscpptypes"] = collect_referenced_class_names()
|
||||
|
||||
top_level_cpp_name = derive_cpp_classname(schema)
|
||||
augment_object(schema)
|
||||
@@ -1,266 +1,76 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# =====================================
|
||||
# Copyright 2017-2025, Andrew Lindesay
|
||||
# Copyright 2017-2026, Andrew Lindesay
|
||||
# Distributed under the terms of the MIT License.
|
||||
# =====================================
|
||||
|
||||
# This simple tool will read a JSON schema and will then generate
|
||||
# some model objects that can be used to hold the data-structure
|
||||
# in the C++ environment.
|
||||
"""\
|
||||
This is a command line tool which is able to take a JSON Schema file as input
|
||||
and will generate the `.h` and `.cpp` C++ source files for model classes that
|
||||
represent the schema. The classes will appear in the output file in the correct
|
||||
order according to their relationship in the schema.
|
||||
"""
|
||||
|
||||
import json
|
||||
import argparse
|
||||
import os
|
||||
import hdsjsonschemacommon
|
||||
import json
|
||||
import pathlib
|
||||
from pathlib import Path
|
||||
|
||||
import jsonschemacommon
|
||||
import ustache
|
||||
|
||||
|
||||
HEADER_TEMPLATE = """
|
||||
/*
|
||||
* Generated Model Object for {{cppname}}
|
||||
*/
|
||||
|
||||
#ifndef GEN_JSON_SCHEMA_MODEL__{{cppnameupper}}_H
|
||||
#define GEN_JSON_SCHEMA_MODEL__{{cppnameupper}}_H
|
||||
|
||||
#include <ObjectList.h>
|
||||
#include <String.h>
|
||||
|
||||
{{#referencedclasscpptypes}}#include "{{.}}.h"
|
||||
{{/referencedclasscpptypes}}
|
||||
|
||||
|
||||
class {{cppname}} {
|
||||
public:
|
||||
{{cppname}}();
|
||||
virtual ~{{cppname}}();
|
||||
|
||||
void Reset();
|
||||
{{#propertyarray}}{{#property.iscppscalartype}}
|
||||
{{property.cpptype}} {{property.cppname}}() const;
|
||||
void Set{{property.cppname}}({{property.cpptype}} value);
|
||||
void Set{{property.cppname}}Null();
|
||||
bool {{property.cppname}}IsNull() const;
|
||||
{{/property.iscppscalartype}}{{#property.isarray}}
|
||||
void AddTo{{property.cppname}}({{property.items.cpptype}}* value);
|
||||
void Set{{property.cppname}}({{property.cpptype}}* value);
|
||||
int32 Count{{property.cppname}}() const;
|
||||
{{property.items.cpptype}}* {{property.cppname}}ItemAt(int32 index) const;
|
||||
bool {{property.cppname}}IsNull() const;
|
||||
{{/property.isarray}}{{#property.iscppnonscalarnoncollectiontype}}
|
||||
{{property.cpptype}}* {{property.cppname}}() const;
|
||||
void Set{{property.cppname}}({{property.cpptype}}* value);
|
||||
void Set{{property.cppname}}Null();
|
||||
bool {{property.cppname}}IsNull() const;
|
||||
{{/property.iscppnonscalarnoncollectiontype}}
|
||||
{{/propertyarray}}
|
||||
|
||||
public:
|
||||
{{#propertyarray}} static const uint16 k{{property.cppname}}Bitmask;
|
||||
{{/propertyarray}}
|
||||
|
||||
private:
|
||||
uint16 fHasValueBitmask;
|
||||
{{#propertyarray}} {{property.cpptype}}{{^property.iscppscalartype}}*{{/property.iscppscalartype}} {{property.cppmembername}};
|
||||
{{/propertyarray}}
|
||||
};
|
||||
|
||||
#endif // GEN_JSON_SCHEMA_MODEL__{{cppnameupper}}_H
|
||||
"""
|
||||
|
||||
IMPLEMENTATION_TEMPLATE = """
|
||||
/*
|
||||
* Generated Model Object for {{cppname}}
|
||||
*/
|
||||
|
||||
#include "{{cppname}}.h"
|
||||
|
||||
|
||||
{{#propertyarray}}/*static*/ const uint16 {{cppname}}::k{{property.cppname}}Bitmask = {{cppbitmaskexpression}};
|
||||
{{/propertyarray}}
|
||||
|
||||
|
||||
{{cppname}}::{{cppname}}()
|
||||
:
|
||||
fHasValueBitmask(0),
|
||||
{{#propertyarray}} {{property.cppmembername}}({{property.cppdefaultvalue}}){{^islast}},{{/islast}}
|
||||
{{/propertyarray}}{
|
||||
}
|
||||
|
||||
|
||||
{{cppname}}::~{{cppname}}()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
{{cppname}}::Reset()
|
||||
{
|
||||
{{#propertyarray}}{{#property.isstring}} delete {{property.cppmembername}};
|
||||
{{/property.isstring}}{{#property.isobject}} delete {{property.cppmembername}};
|
||||
{{/property.isobject}}{{#property.isarray}}
|
||||
if ({{property.cppmembername}} != NULL) {
|
||||
for (int i = {{property.cppmembername}}->CountItems() - 1; i >= 0; i--)
|
||||
delete {{property.cppmembername}}->ItemAt(i);
|
||||
delete {{property.cppmembername}};
|
||||
}
|
||||
{{/property.isarray}} {{property.cppmembername}} = {{property.cppdefaultvalue}};
|
||||
{{/propertyarray}}
|
||||
fHasValueBitmask = 0;
|
||||
}
|
||||
|
||||
{{#propertyarray}}{{#property.iscppscalartype}}{{property.cpptype}}
|
||||
{{cppobjectname}}::{{property.cppname}}() const
|
||||
{
|
||||
return {{property.cppmembername}};
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
{{cppobjectname}}::Set{{property.cppname}}({{property.cpptype}} value)
|
||||
{
|
||||
fHasValueBitmask |= k{{property.cppname}}Bitmask;
|
||||
{{property.cppmembername}} = value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
{{cppobjectname}}::Set{{property.cppname}}Null()
|
||||
{
|
||||
fHasValueBitmask &= ~k{{property.cppname}}Bitmask;
|
||||
{{property.cppmembername}} = {{property.cppdefaultvalue}};
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
{{cppobjectname}}::{{property.cppname}}IsNull() const
|
||||
{
|
||||
return 0 == (fHasValueBitmask & k{{property.cppname}}Bitmask);
|
||||
}
|
||||
|
||||
{{/property.iscppscalartype}}{{#property.isarray}}void
|
||||
{{cppobjectname}}::AddTo{{property.cppname}}({{property.items.cpptype}}* value)
|
||||
{
|
||||
if ({{property.cppmembername}} == NULL)
|
||||
{{property.cppmembername}} = new {{property.cpptype}}();
|
||||
{{property.cppmembername}}->AddItem(value);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
{{cppobjectname}}::Set{{property.cppname}}({{property.cpptype}}* value)
|
||||
{
|
||||
if ({{property.cppmembername}} != NULL) {
|
||||
delete {{property.cppmembername}};
|
||||
}
|
||||
{{property.cppmembername}} = value;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
{{cppobjectname}}::Count{{property.cppname}}() const
|
||||
{
|
||||
if ({{property.cppmembername}} == NULL)
|
||||
return 0;
|
||||
return {{property.cppmembername}}->CountItems();
|
||||
}
|
||||
|
||||
|
||||
{{property.items.cpptype}}*
|
||||
{{cppobjectname}}::{{property.cppname}}ItemAt(int32 index) const
|
||||
{
|
||||
return {{property.cppmembername}}->ItemAt(index);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
{{cppobjectname}}::{{property.cppname}}IsNull() const
|
||||
{
|
||||
return {{property.cppmembername}} == NULL;
|
||||
}
|
||||
|
||||
{{/property.isarray}}{{#property.iscppnonscalarnoncollectiontype}}{{property.cpptype}}*
|
||||
{{cppobjectname}}::{{property.cppname}}() const
|
||||
{
|
||||
return {{property.cppmembername}};
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
{{cppobjectname}}::Set{{property.cppname}}({{property.cpptype}}* value)
|
||||
{
|
||||
{{property.cppmembername}} = value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
{{cppobjectname}}::Set{{property.cppname}}Null()
|
||||
{
|
||||
if (!{{property.cppname}}IsNull()) {
|
||||
delete {{property.cppmembername}};
|
||||
{{property.cppmembername}} = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
{{cppobjectname}}::{{property.cppname}}IsNull() const
|
||||
{
|
||||
return {{property.cppmembername}} == NULL;
|
||||
}
|
||||
|
||||
{{/property.iscppnonscalarnoncollectiontype}}
|
||||
{{/propertyarray}}
|
||||
"""
|
||||
|
||||
|
||||
def write_models_for_schema(schema: dict[str, any], output_directory: str) -> None:
|
||||
|
||||
def write_model_object(obj: dict[str, any]) -> None:
|
||||
cpp_name = obj["cppname"]
|
||||
cpp_header_filename = os.path.join(output_directory, cpp_name + '.h')
|
||||
cpp_implementation_filename = os.path.join(output_directory, cpp_name + '.cpp')
|
||||
|
||||
with open(cpp_header_filename, 'w') as cpp_h_file:
|
||||
cpp_h_file.write(ustache.render(
|
||||
HEADER_TEMPLATE,
|
||||
obj,
|
||||
escape= lambda x: x))
|
||||
|
||||
with open(cpp_implementation_filename, 'w') as cpp_i_file:
|
||||
cpp_i_file.write(ustache.render(
|
||||
IMPLEMENTATION_TEMPLATE,
|
||||
obj,
|
||||
escape= lambda x: x))
|
||||
|
||||
for obj in hdsjsonschemacommon.collect_all_objects(schema):
|
||||
write_model_object(obj)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Convert JSON schema to Haiku C++ Models')
|
||||
description="Convert JSON schema to Haiku C++ Models")
|
||||
|
||||
parser.add_argument(
|
||||
'-i', '--inputfile',
|
||||
"--jsonschemafile",
|
||||
dest = "jsonschemafile",
|
||||
required=True,
|
||||
help='The input filename containing the JSON schema')
|
||||
help="The input filename containing the JSON schema")
|
||||
|
||||
parser.add_argument(
|
||||
'--outputdirectory',
|
||||
help='The output directory where the C++ files should be written')
|
||||
"--outputdirectory",
|
||||
dest = "outputdirectory",
|
||||
required=True,
|
||||
help="The output filename where the C++ header and implementation file should be written")
|
||||
|
||||
args = parser.parse_args()
|
||||
schema_path = Path(args.jsonschemafile).absolute()
|
||||
|
||||
output_directory = args.outputdirectory
|
||||
if not schema_path.is_file():
|
||||
raise RuntimeError(f"The input file [{schema_path}] does not exist")
|
||||
|
||||
if not output_directory:
|
||||
output_directory = '.'
|
||||
output_directory_path = Path(args.outputdirectory).absolute()
|
||||
output_directory_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with open(args.inputfile) as inputfile:
|
||||
schema = json.load(inputfile)
|
||||
hdsjsonschemacommon.augment_schema(schema)
|
||||
write_models_for_schema(schema, output_directory)
|
||||
with open(schema_path) as input_file:
|
||||
schema = json.load(input_file)
|
||||
|
||||
jsonschemacommon.augment_schema(schema)
|
||||
object_schemas = jsonschemacommon.collect_all_objects(schema)
|
||||
|
||||
def output_to_path(output_path: pathlib.Path):
|
||||
template_type = jsonschemacommon.path_to_extension_type(output_path)
|
||||
template = jsonschemacommon.load_template("model", template_type)
|
||||
template_model = {
|
||||
"objects": object_schemas,
|
||||
"outputfilename": output_path.name,
|
||||
"outputheaderfile": output_path.stem + ".h",
|
||||
"outputfilestemupper": output_path.stem.upper()
|
||||
}
|
||||
|
||||
with open(output_path, 'w') as out_file:
|
||||
out_file.write(ustache.render(
|
||||
template,
|
||||
template_model,
|
||||
escape= lambda x: x))
|
||||
|
||||
cpp_name = schema["cppname"]
|
||||
output_to_path(output_directory_path / f"{cpp_name}Model.h")
|
||||
output_to_path(output_directory_path / f"{cpp_name}Model.cpp")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,335 @@
|
||||
# =====================================
|
||||
# Copyright 2017-2026, Andrew Lindesay
|
||||
# Distributed under the terms of the MIT License.
|
||||
# =====================================
|
||||
|
||||
"""\
|
||||
This file contains classes and helper functions that are used in the generation
|
||||
of `.h` and `.cpp` C++ files based on a JSON Schema. The schemas are intended
|
||||
for use in a Java setting, but are adapted by this logic for use with C++ and
|
||||
types that are typical for the Haiku environment.
|
||||
"""
|
||||
|
||||
import datetime
|
||||
import pathlib
|
||||
from typing import Any
|
||||
from enum import Enum, auto
|
||||
|
||||
# The possible JSON types
|
||||
JSON_TYPE_STRING = "string"
|
||||
JSON_TYPE_OBJECT = "object"
|
||||
JSON_TYPE_ARRAY = "array"
|
||||
JSON_TYPE_BOOLEAN = "boolean"
|
||||
JSON_TYPE_INTEGER = "integer"
|
||||
JSON_TYPE_NUMBER = "number"
|
||||
|
||||
|
||||
# The possible C++ types
|
||||
CPP_TYPE_STRING = "BString"
|
||||
CPP_TYPE_ARRAY = "std::vector"
|
||||
CPP_TYPE_BOOLEAN = "bool"
|
||||
CPP_TYPE_INTEGER = "int64"
|
||||
CPP_TYPE_NUMBER = "double"
|
||||
|
||||
|
||||
# The possible C++ default values
|
||||
CPP_DEFAULT_STRING = "\"\""
|
||||
CPP_DEFAULT_BOOLEAN = "false"
|
||||
CPP_DEFAULT_INTEGER = "0"
|
||||
CPP_DEFAULT_NUMBER = "0.0"
|
||||
|
||||
|
||||
class TemplateType(Enum):
|
||||
"""Type of template to load."""
|
||||
HEADER = auto()
|
||||
IMPLEMENTATION = auto()
|
||||
|
||||
|
||||
class CppClassNode:
|
||||
"""An object representing a C++ class for establishing a dependency graph."""
|
||||
def __init__(self, cpp_name: str, schema: dict[str, Any], dependencies: set):
|
||||
self.cpp_name = cpp_name
|
||||
self.schema = schema
|
||||
self.dependencies = dependencies
|
||||
|
||||
|
||||
def java_type_to_cpp_name(java_name: str) -> str:
|
||||
return java_name[java_name.rindex('.') + 1:]
|
||||
|
||||
|
||||
def prop_name_to_cpp_name(prop_name: str) -> str:
|
||||
return prop_name[0:1].upper() + prop_name[1:]
|
||||
|
||||
|
||||
def prop_name_to_cpp_member_name(prop_name: str) -> str:
|
||||
return "f" + prop_name_to_cpp_name(prop_name)
|
||||
|
||||
|
||||
def prop_metadata_to_cpp_default_value(prop_metadata: dict[str, Any]) -> str:
|
||||
"""Converts the property data into a C++ default for the field.
|
||||
|
||||
This function will look at the metadata for the property and decide what a
|
||||
generic default value for that type might be.
|
||||
|
||||
Returns: The function will return a string representation of the C++ value.
|
||||
"""
|
||||
type = prop_metadata['type']
|
||||
|
||||
if type == JSON_TYPE_STRING:
|
||||
return CPP_DEFAULT_STRING
|
||||
if type == JSON_TYPE_BOOLEAN:
|
||||
return CPP_DEFAULT_BOOLEAN
|
||||
if type == JSON_TYPE_INTEGER:
|
||||
return CPP_DEFAULT_INTEGER
|
||||
if type == JSON_TYPE_NUMBER:
|
||||
return CPP_DEFAULT_NUMBER
|
||||
if type == JSON_TYPE_OBJECT:
|
||||
cpp_type = prop_metadata["cpptype"]
|
||||
return f"{cpp_type}Ref()"
|
||||
if type == JSON_TYPE_ARRAY:
|
||||
items_cpptype = prop_metadata["items"]["cpptype"]
|
||||
return f"{CPP_TYPE_ARRAY}<{items_cpptype}>()"
|
||||
|
||||
raise Exception(f"unknown json-schema type [{type}]")
|
||||
|
||||
def prop_metadata_to_cpp_type_name(prop_metadata: dict[str, Any]) -> str:
|
||||
"""Introspects data metadata for a property and returns its type in C++"""
|
||||
type_ = prop_metadata['type']
|
||||
|
||||
if type_ == JSON_TYPE_STRING:
|
||||
return CPP_TYPE_STRING
|
||||
if type_ == JSON_TYPE_BOOLEAN:
|
||||
return CPP_TYPE_BOOLEAN
|
||||
if type_ == JSON_TYPE_INTEGER:
|
||||
return CPP_TYPE_INTEGER
|
||||
if type_ == JSON_TYPE_NUMBER:
|
||||
return CPP_TYPE_NUMBER
|
||||
if type_ == JSON_TYPE_OBJECT:
|
||||
java_type = prop_metadata['javaType']
|
||||
|
||||
if not java_type or 0 == len(java_type):
|
||||
raise Exception('missing "javaType" field')
|
||||
|
||||
return java_type_to_cpp_name(java_type)
|
||||
|
||||
if type_ == JSON_TYPE_ARRAY:
|
||||
items_cpptype = prop_metadata["items"]["cpptype"]
|
||||
return f"{CPP_TYPE_ARRAY}<{items_cpptype}>"
|
||||
|
||||
raise Exception(f"unknown json-schema type [{type_}]")
|
||||
|
||||
|
||||
def prop_metadata_type_is_scalar(prop_metadata: dict[str, Any]) -> bool:
|
||||
type_ = prop_metadata['type']
|
||||
return type_ == JSON_TYPE_BOOLEAN or type_ == JSON_TYPE_INTEGER or type_ == JSON_TYPE_NUMBER
|
||||
|
||||
|
||||
def write_top_comment(f, input_filename: str, variant: str) -> None:
|
||||
f.write((
|
||||
'/*\n'
|
||||
' * Generated %s Object\n'
|
||||
' * source json-schema : %s\n'
|
||||
' * generated at : %s\n'
|
||||
' */\n'
|
||||
) % (variant, input_filename, datetime.datetime.now().isoformat()))
|
||||
|
||||
|
||||
def _to_cpp_class_dependency_tree(schema: dict[str, Any]) -> CppClassNode | None:
|
||||
"""Builds up a dependency tree of to-be C++ classes
|
||||
|
||||
The output of this is a dependency tree of C++ classes from which it is
|
||||
possible to get the order that the classes need to be written into the
|
||||
header and implementation files.
|
||||
"""
|
||||
|
||||
all_nodes: list[CppClassNode] = []
|
||||
|
||||
def to_node(sub_schema: dict[str, Any]):
|
||||
if sub_schema["type"] == JSON_TYPE_ARRAY:
|
||||
return to_node(sub_schema["items"])
|
||||
if sub_schema["type"] == JSON_TYPE_OBJECT:
|
||||
cpp_name = sub_schema["cppname"]
|
||||
|
||||
existing_class = next((c for c in all_nodes if c.cpp_name == cpp_name), None)
|
||||
if existing_class:
|
||||
return existing_class
|
||||
|
||||
node = CppClassNode(cpp_name=cpp_name, schema=sub_schema, dependencies=set())
|
||||
all_nodes.append(node)
|
||||
|
||||
dependencies = [to_node(property_schema) for property_schema in sub_schema["properties"].values()]
|
||||
node.dependencies = sorted([d for d in dependencies if d], key = lambda d: d.cpp_name)
|
||||
|
||||
return node
|
||||
return None
|
||||
|
||||
return to_node(schema)
|
||||
|
||||
|
||||
def _to_object_sub_schemas_in_dependency_order(root_node: CppClassNode) -> list[dict[str, Any]]:
|
||||
"""Returns a list of the schemas representing objects such that any dependencies appear first."""
|
||||
|
||||
result: list[dict[str, Any]] = []
|
||||
|
||||
def walk(node: CppClassNode):
|
||||
for d in node.dependencies:
|
||||
walk(d)
|
||||
result.append(node.schema)
|
||||
|
||||
walk(root_node)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def collect_all_objects(schema: dict[str, Any]) -> list[dict[str, Any]]:
|
||||
"""Walks the schema and extracts all definitions of objects.
|
||||
|
||||
Returns:
|
||||
A list of schema structure which defines the class. The list will be in
|
||||
order so that latter classes are able to have dependency on earlier
|
||||
classes.
|
||||
"""
|
||||
|
||||
root_node = _to_cpp_class_dependency_tree(schema)
|
||||
|
||||
if not root_node:
|
||||
raise RuntimeError("it was not possible to extract a tree from the schema data")
|
||||
|
||||
return _to_object_sub_schemas_in_dependency_order(root_node)
|
||||
|
||||
|
||||
def augment_schema(schema: dict[str, Any]) -> None:
|
||||
"""This function will take the data from the JSON schema and will overlay any
|
||||
specific information required for rendering the templates.
|
||||
"""
|
||||
|
||||
def augment_property_type(prop: dict[str, Any]) -> None:
|
||||
prop_type = prop['type']
|
||||
|
||||
if not prop_type or 0 == len(prop_type):
|
||||
raise Exception('missing "type" field')
|
||||
|
||||
# For the object type, a `BReference` is used as the member variable
|
||||
# type but the actual wrapped type is still required for constructors.
|
||||
|
||||
if prop_type == JSON_TYPE_OBJECT:
|
||||
prop["cpptyperaw"] = prop_metadata_to_cpp_type_name(prop)
|
||||
prop["cpptype"] = prop_metadata_to_cpp_type_name(prop) + "Ref"
|
||||
else:
|
||||
prop["cpptype"] = prop_metadata_to_cpp_type_name(prop)
|
||||
|
||||
is_scalar_type = prop_metadata_type_is_scalar(prop)
|
||||
is_array_type = (prop_type == JSON_TYPE_ARRAY)
|
||||
|
||||
prop["iscppscalartype"] = is_scalar_type
|
||||
prop["isarray"] = is_array_type
|
||||
prop["isstring"] = JSON_TYPE_STRING == prop_type
|
||||
prop["isboolean"] = JSON_TYPE_BOOLEAN == prop_type
|
||||
prop["isnumber"] = JSON_TYPE_NUMBER == prop_type
|
||||
prop["isinteger"] = JSON_TYPE_INTEGER == prop_type
|
||||
prop["isobject"] = JSON_TYPE_OBJECT == prop_type
|
||||
prop["isobjectorarray"] = prop_type in [JSON_TYPE_OBJECT, JSON_TYPE_ARRAY]
|
||||
prop["iscppnonscalarnoncollectiontype"] = not is_scalar_type and not is_array_type
|
||||
|
||||
def derive_cpp_classname(obj: dict[str, Any]) -> str:
|
||||
obj_type = obj['type']
|
||||
|
||||
if obj_type != JSON_TYPE_OBJECT:
|
||||
raise Exception('expecting object, but was [' + obj_type + ']')
|
||||
|
||||
java_type = obj['javaType']
|
||||
|
||||
return java_type_to_cpp_name(java_type)
|
||||
|
||||
def augment_property(prop: dict[str, Any]) -> None:
|
||||
|
||||
if JSON_TYPE_ARRAY == prop["type"]:
|
||||
array_items = prop['items']
|
||||
array_items_type = array_items["type"]
|
||||
|
||||
if array_items_type == JSON_TYPE_OBJECT:
|
||||
augment_object(array_items)
|
||||
elif array_items_type == JSON_TYPE_STRING:
|
||||
augment_property(array_items)
|
||||
else:
|
||||
raise Exception(f"bad type for array items [{array_items_type}]")
|
||||
|
||||
augment_property_type(prop)
|
||||
prop["cppdefaultvalue"] = prop_metadata_to_cpp_default_value(prop)
|
||||
|
||||
if JSON_TYPE_OBJECT == prop["type"]:
|
||||
augment_object(prop)
|
||||
|
||||
def augment_object(obj: dict[str, Any]) -> None:
|
||||
def has_any_list_properties() -> bool:
|
||||
for _, prop in obj['properties'].items():
|
||||
if prop['type'] == JSON_TYPE_ARRAY:
|
||||
return True
|
||||
return False
|
||||
|
||||
augment_property_type(obj)
|
||||
|
||||
obj_cpp_classname = derive_cpp_classname(obj)
|
||||
obj["cppname"] = obj_cpp_classname
|
||||
obj["cppnameupper"] = obj_cpp_classname.upper()
|
||||
obj["hasanylistproperties"] = has_any_list_properties()
|
||||
|
||||
# allows the object to know the top level object that contains it
|
||||
obj["toplevelcppname"] = top_level_cpp_name
|
||||
|
||||
properties = obj['properties'].items()
|
||||
|
||||
for prop_name, prop in properties:
|
||||
prop["cppname"] = prop_name_to_cpp_name(prop_name)
|
||||
prop["cppmembername"] = prop_name_to_cpp_member_name(prop_name)
|
||||
augment_property(prop)
|
||||
|
||||
# mustache is not able to iterate over a dictionary; it can only
|
||||
# iterate over a list where each item in the list has some properties.
|
||||
|
||||
property_array = sorted(
|
||||
[{
|
||||
"name": k,
|
||||
"property": v,
|
||||
"cppobjectname": obj_cpp_classname
|
||||
# ^ this is the name of the containing object
|
||||
} for k,v in properties],
|
||||
key= lambda item: item["name"]
|
||||
)
|
||||
|
||||
for i in range(len(property_array)):
|
||||
property_array[i]["cppbitmaskexpression"] = "(1 << %d)" % i
|
||||
|
||||
if 0 != len(property_array):
|
||||
property_array[0]["isfirst"] = True
|
||||
property_array[len(property_array) - 1]["islast"] = True
|
||||
|
||||
obj["propertyarray"] = property_array
|
||||
|
||||
top_level_cpp_name = derive_cpp_classname(schema)
|
||||
augment_object(schema)
|
||||
|
||||
|
||||
def path_to_extension_type(file_path: pathlib.Path) -> TemplateType:
|
||||
if ".h" == file_path.suffix:
|
||||
return TemplateType.HEADER
|
||||
if ".cpp" == file_path.suffix:
|
||||
return TemplateType.IMPLEMENTATION
|
||||
raise RuntimeError(f"unknown extension [{file_path.suffix}]")
|
||||
|
||||
|
||||
def load_template(template_name: str, template_type: TemplateType) -> str:
|
||||
"""Loads the template from the `./template` directory."""
|
||||
|
||||
def template_type_path_component() -> str:
|
||||
if template_type == TemplateType.HEADER:
|
||||
return "header"
|
||||
if template_type == TemplateType.IMPLEMENTATION:
|
||||
return "implementation"
|
||||
raise RuntimeError(f"unknown template type [{str(template_type)}")
|
||||
|
||||
script_directory = pathlib.Path(__file__).parent.resolve()
|
||||
template_path = script_directory / "template" / f"{template_name}{template_type_path_component()}.mustache"
|
||||
|
||||
with open(template_path, "r") as f:
|
||||
return f.read()
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Generated Model Object for {{outputfilename}}
|
||||
*/
|
||||
|
||||
#ifndef GEN_JSON_SCHEMA_MODEL__{{outputfilestemupper}}_H
|
||||
#define GEN_JSON_SCHEMA_MODEL__{{outputfilestemupper}}_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <Archivable.h>
|
||||
#include <Referenceable.h>
|
||||
#include <String.h>{{#objects}}
|
||||
|
||||
|
||||
class {{cppname}} : public BArchivable, public BReferenceable
|
||||
{
|
||||
friend class {{cppname}}Builder;
|
||||
|
||||
public:
|
||||
{{cppname}}();
|
||||
{{cppname}}(const BMessage* message);
|
||||
virtual ~{{cppname}}();
|
||||
|
||||
bool operator==(const {{cppname}}& other) const;
|
||||
bool operator!=(const {{cppname}}& other) const;
|
||||
|
||||
{{#propertyarray}}{{#property.isarray}}
|
||||
const {{property.cpptype}} {{property.cppname}}() const;
|
||||
int32 Count{{property.cppname}}() const;
|
||||
const {{property.items.cpptype}}& {{property.cppname}}ItemAt(int32 index) const;
|
||||
bool IsSet{{property.cppname}}() const;
|
||||
{{/property.isarray}}{{^property.isarray}}
|
||||
{{#property.iscppscalartype}} {{property.cpptype}} {{property.cppname}}() const;
|
||||
{{/property.iscppscalartype}}{{^property.iscppscalartype}} const {{property.cpptype}}& {{property.cppname}}() const;
|
||||
{{/property.iscppscalartype}}
|
||||
bool IsSet{{property.cppname}}() const;
|
||||
{{/property.isarray}}
|
||||
{{/propertyarray}}
|
||||
|
||||
status_t Archive(BMessage* into, bool deep = true) const;
|
||||
|
||||
private:
|
||||
{{#propertyarray}}{{#property.isarray}} void _Set{{property.cppname}}(const {{property.cpptype}}& value);
|
||||
void _AddTo{{property.cppname}}(const {{property.items.cpptype}}& value);
|
||||
void _Unset{{property.cppname}}();
|
||||
{{/property.isarray}}{{^property.isarray}}
|
||||
{{#property.iscppscalartype}} void _Set{{property.cppname}}({{property.cpptype}} value);
|
||||
{{/property.iscppscalartype}}{{^property.iscppscalartype}} void _Set{{property.cppname}}(const {{property.cpptype}}& value);
|
||||
{{/property.iscppscalartype}}
|
||||
void _Unset{{property.cppname}}();
|
||||
{{/property.isarray}}
|
||||
{{/propertyarray}}
|
||||
|
||||
public:
|
||||
{{#propertyarray}} static const uint16 k{{property.cppname}}Bitmask;
|
||||
{{/propertyarray}}
|
||||
|
||||
private:
|
||||
uint16 fHasValueBitmask;
|
||||
{{#propertyarray}} {{property.cpptype}} {{property.cppmembername}};
|
||||
{{/propertyarray}}
|
||||
};
|
||||
|
||||
|
||||
typedef BReference<{{cppname}}> {{cppname}}Ref;
|
||||
|
||||
|
||||
class {{cppname}}Builder
|
||||
{
|
||||
public:
|
||||
{{cppname}}Builder();
|
||||
{{cppname}}Builder(const {{cppname}}Ref& source);
|
||||
{{cppname}}Builder(const {{cppname}}* source);
|
||||
virtual ~{{cppname}}Builder();
|
||||
|
||||
{{cppname}}Builder& Clear();
|
||||
{{cppname}}Ref BuildRef();
|
||||
|
||||
{{#propertyarray}}{{#property.isarray}}
|
||||
{{cppname}}Builder& With{{property.cppname}}({{property.cpptype}} value);
|
||||
{{cppname}}Builder& Without{{property.cppname}}();
|
||||
{{cppname}}Builder& AddTo{{property.cppname}}({{property.items.cpptype}} value);
|
||||
{{/property.isarray}}{{^property.isarray}}
|
||||
{{cppname}}Builder& With{{property.cppname}}({{property.cpptype}} value);
|
||||
{{cppname}}Builder& Without{{property.cppname}}();
|
||||
{{/property.isarray}}
|
||||
{{/propertyarray}}
|
||||
|
||||
private:
|
||||
void _InitFromSource();
|
||||
void _Init(const {{cppname}}* source);
|
||||
|
||||
private:
|
||||
uint16 fHasValueBitmask;
|
||||
{{cppname}}Ref fSourceRef;
|
||||
|
||||
{{#propertyarray}} {{property.cpptype}} {{property.cppmembername}};
|
||||
{{/propertyarray}}
|
||||
};{{/objects}}
|
||||
|
||||
#endif // GEN_JSON_SCHEMA_MODEL__{{outputfilestemupper}}_H
|
||||
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* Generated Model Object for {{outputfilename}}
|
||||
*/
|
||||
|
||||
#include "{{outputheaderfile}}"{{#objects}}
|
||||
|
||||
|
||||
{{#propertyarray}}/*static*/ const uint16 {{cppname}}::k{{property.cppname}}Bitmask = {{cppbitmaskexpression}};
|
||||
{{/propertyarray}}
|
||||
|
||||
|
||||
{{cppname}}::{{cppname}}()
|
||||
:
|
||||
fHasValueBitmask(0),
|
||||
{{#propertyarray}} {{property.cppmembername}}({{property.cppdefaultvalue}}){{^islast}},{{/islast}}
|
||||
{{/propertyarray}}{
|
||||
}
|
||||
|
||||
|
||||
{{cppname}}::{{cppname}}(const BMessage* from)
|
||||
:
|
||||
fHasValueBitmask(0)
|
||||
{
|
||||
{{#hasanylistproperties}} bool arrayIsSet;
|
||||
BString arrayItemKey;
|
||||
{{/hasanylistproperties}}
|
||||
{{#propertyarray}}{{#property.isstring}} if (from->FindString("{{property.cppname}}", &{{property.cppmembername}}) == B_OK)
|
||||
fHasValueBitmask |= k{{property.cppname}}Bitmask;
|
||||
{{/property.isstring}}{{#property.isboolean}} if (from->FindBool("{{property.cppname}}", &{{property.cppmembername}}) == B_OK)
|
||||
fHasValueBitmask |= k{{property.cppname}}Bitmask;
|
||||
{{/property.isboolean}}{{#property.isnumber}} if (from->FindDouble("{{property.cppname}}", &{{property.cppmembername}}) == B_OK)
|
||||
fHasValueBitmask |= k{{property.cppname}}Bitmask;
|
||||
{{/property.isnumber}}{{#property.isinteger}} if (from->FindInt64("{{property.cppname}}", &{{property.cppmembername}}) == B_OK)
|
||||
fHasValueBitmask |= k{{property.cppname}}Bitmask;
|
||||
{{/property.isinteger}}{{#property.isobject}} {
|
||||
BMessage objectMessage;
|
||||
if (from->FindMessage("{{property.cppname}}", &objectMessage) == B_OK) {
|
||||
{{property.cpptyperaw}}* object = new {{property.cpptyperaw}}(&objectMessage);
|
||||
{{property.cppmembername}} = {{property.cpptyperaw}}(object, true);
|
||||
fHasValueBitmask |= k{{property.cppname}}Bitmask;
|
||||
}
|
||||
}
|
||||
{{/property.isobject}}{{#property.isarray}} if (from->FindBool("{{property.cppname}}_isSet", &arrayIsSet) == B_OK && arrayIsSet) {
|
||||
status_t arrayItemFindResult = B_OK;
|
||||
|
||||
for (int32 i = 0; arrayItemFindResult == B_OK; i++) {
|
||||
arrayItemKey.SetToFormat("{{property.cppname}}_%" B_PRId32, i);
|
||||
{{#property.items.isstring}} BString arrayItemString;
|
||||
arrayItemFindResult = from->FindString(arrayItemKey, &arrayItemString);
|
||||
if (arrayItemFindResult == B_OK)
|
||||
{{property.cppmembername}}.push_back(arrayItemString);
|
||||
{{/property.items.isstring}}{{^property.items.isstring}} BMessage arrayItemMessage;
|
||||
arrayItemFindResult = from->FindMessage(arrayItemKey, &arrayItemMessage);
|
||||
if (arrayItemFindResult == B_OK) {
|
||||
{{property.items.cpptyperaw}}* arrayItemObject = new {{property.items.cpptyperaw}}(&arrayItemMessage);
|
||||
{{property.cppmembername}}.push_back({{property.items.cpptype}}(arrayItemObject, true));
|
||||
}
|
||||
{{/property.items.isstring}} }
|
||||
}
|
||||
{{/property.isarray}}{{/propertyarray}}
|
||||
}
|
||||
|
||||
|
||||
{{cppname}}::~{{cppname}}()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
{{cppname}}::operator==(const {{cppname}}& other) const
|
||||
{
|
||||
if (fHasValueBitmask != other.fHasValueBitmask)
|
||||
return false;
|
||||
{{#propertyarray}}{{#property.iscppscalartype}} if (0 != (fHasValueBitmask & k{{property.cppname}}Bitmask) && {{property.cppmembername}} != other.{{property.cppmembername}})
|
||||
return false;
|
||||
{{/property.iscppscalartype}}{{/propertyarray}}{{#propertyarray}}{{#property.isstring}} if (0 != (fHasValueBitmask & k{{property.cppname}}Bitmask) && {{property.cppmembername}} != other.{{property.cppmembername}})
|
||||
return false;
|
||||
{{/property.isstring}}{{/propertyarray}}{{#propertyarray}}{{#property.isobject}} if (0 != (fHasValueBitmask & k{{property.cppname}}Bitmask) && *({{property.cppmembername}}.Get()) != *(other.{{property.cppmembername}}.Get())
|
||||
return false;
|
||||
{{/property.isobject}}{{/propertyarray}}{{#propertyarray}}{{#property.isarray}} if (0 != (fHasValueBitmask & k{{property.cppname}}Bitmask)) {
|
||||
if ({{property.cppmembername}}.size() != other.{{property.cppmembername}}.size())
|
||||
return false;
|
||||
for (int32 i = {{property.cppmembername}}.size() - 1; i >= 0; i--) {
|
||||
{{#property.items.isobject}} if (*({{property.cppmembername}}[i].Get()) != *(other.{{property.cppmembername}}[i].Get()))
|
||||
return false;
|
||||
{{/property.items.isobject}}{{^property.items.isobject}} if ({{property.cppmembername}}[i] != other.{{property.cppmembername}}[i])
|
||||
return false;
|
||||
{{/property.items.isobject}}
|
||||
}
|
||||
}
|
||||
{{/property.isarray}}{{/propertyarray}}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
{{cppname}}::operator!=(const {{cppname}}& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
|
||||
{{#propertyarray}}void
|
||||
{{#property.iscppscalartype}}{{cppname}}::_Set{{property.cppname}}({{property.cpptype}} value)
|
||||
{{/property.iscppscalartype}}{{^property.iscppscalartype}}{{cppname}}::_Set{{property.cppname}}(const {{property.cpptype}}& value)
|
||||
{{/property.iscppscalartype}}{
|
||||
{{#property.isobject}} if (!{{property.cpptype}}.IsSet())
|
||||
fHasValueBitmask &= ~k{{property.cppname}}Bitmask;
|
||||
else
|
||||
fHasValueBitmask |= k{{property.cppname}}Bitmask;
|
||||
{{/property.isobject}}{{^property.isobject}} fHasValueBitmask |= k{{property.cppname}}Bitmask;
|
||||
{{/property.isobject}} {{property.cppmembername}} = value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
{{cppname}}::_Unset{{property.cppname}}()
|
||||
{
|
||||
fHasValueBitmask &= ~k{{property.cppname}}Bitmask;
|
||||
{{property.cppmembername}} = {{property.cppdefaultvalue}};
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
{{cppname}}::IsSet{{property.cppname}}() const
|
||||
{
|
||||
return 0 != (fHasValueBitmask & k{{property.cppname}}Bitmask);
|
||||
}
|
||||
|
||||
|
||||
{{#property.isarray}}void
|
||||
{{cppname}}::_AddTo{{property.cppname}}(const {{property.items.cpptype}}& value)
|
||||
{
|
||||
{{#property.items.isobject}} if (!value.IsSet()) {
|
||||
debugger("attempt to inset an unset object into an array field [{{property.cppmembername}}] of [{{cppobjectname}}]");
|
||||
return;
|
||||
}
|
||||
{{/property.items.isobject}} fHasValueBitmask |= k{{property.cppname}}Bitmask;
|
||||
{{property.cppmembername}}.push_back(value);
|
||||
}
|
||||
|
||||
|
||||
const {{property.cpptype}}
|
||||
{{cppname}}::{{property.cppname}}() const
|
||||
{
|
||||
return {{property.cppmembername}};
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
{{cppname}}::Count{{property.cppname}}() const
|
||||
{
|
||||
return {{property.cppmembername}}.size();
|
||||
}
|
||||
|
||||
|
||||
const {{property.items.cpptype}}&
|
||||
{{cppname}}::{{property.cppname}}ItemAt(int32 index) const
|
||||
{
|
||||
return {{property.cppmembername}}[index];
|
||||
}
|
||||
|
||||
|
||||
{{/property.isarray}}{{^property.isarray}}{{#property.iscppscalartype}}{{property.cpptype}}
|
||||
{{cppname}}::{{property.cppname}}() const
|
||||
{{/property.iscppscalartype}}{{^property.iscppscalartype}}const {{property.cpptype}}&
|
||||
{{cppname}}::{{property.cppname}}() const
|
||||
{{/property.iscppscalartype}}{
|
||||
return {{property.cppmembername}};
|
||||
}
|
||||
|
||||
|
||||
{{/property.isarray}}{{/propertyarray}}
|
||||
status_t
|
||||
{{cppname}}::Archive(BMessage* into, bool deep) const
|
||||
{
|
||||
{{#hasanylistproperties}} BString arrayItemKey;{{/hasanylistproperties}}
|
||||
status_t result = B_OK;
|
||||
|
||||
{{#propertyarray}}{{#property.isstring}} if (result == B_OK && 0 != (fHasValueBitmask & k{{property.cppname}}Bitmask))
|
||||
result = into->AddString("{{property.cppname}}", {{property.cppmembername}});
|
||||
{{/property.isstring}}{{#property.isboolean}} if (result == B_OK && 0 != (fHasValueBitmask & k{{property.cppname}}Bitmask))
|
||||
result = into->AddBool("{{property.cppname}}", {{property.cppmembername}});
|
||||
{{/property.isboolean}}{{#property.isnumber}} if (result == B_OK && 0 != (fHasValueBitmask & k{{property.cppname}}Bitmask))
|
||||
result = into->AddDouble("{{property.cppname}}", {{property.cppmembername}});
|
||||
{{/property.isnumber}}{{#property.isinteger}} if (result == B_OK && 0 != (fHasValueBitmask & k{{property.cppname}}Bitmask))
|
||||
result = into->AddInt64("{{property.cppname}}", {{property.cppmembername}});
|
||||
{{/property.isinteger}}{{#property.isobject}} if (deep && result == B_OK && 0 != (fHasValueBitmask & k{{property.cppname}}Bitmask && {{property.cppmembername}}.IsSet())) {
|
||||
BMessage objectMessage;
|
||||
result = {{property.cppmembername}}->Archive(&objectMessage, deep);
|
||||
if (result == B_OK)
|
||||
result = into->AddMessage("{{property.cppname}}", &objectMessage);
|
||||
}
|
||||
{{/property.isobject}}{{#property.isarray}} if (deep && result == B_OK && 0 != (fHasValueBitmask & k{{property.cppname}}Bitmask)) {
|
||||
for (int32 i = Count{{property.cppname}}() - 1; result == B_OK && i >= 0; i--) {
|
||||
arrayItemKey.SetToFormat("%s_%" B_PRId32, "{{property.cppname}}", i);
|
||||
{{#property.items.isstring}} result = into->AddString(arrayItemKey, {{property.cppname}}ItemAt(i));
|
||||
{{/property.items.isstring}}{{#property.items.isobject}} BMessage arrayItemMessage;
|
||||
result = {{property.cppname}}ItemAt(i)->Archive(&arrayItemMessage, deep);
|
||||
if (result == B_OK)
|
||||
result = into->AddMessage(arrayItemKey, &arrayItemMessage);
|
||||
{{/property.items.isobject}} }
|
||||
if (result == B_OK)
|
||||
result = into->AddBool("{{property.cppname}}_isSet", true);
|
||||
}
|
||||
{{/property.isarray}}
|
||||
{{/propertyarray}} return result;
|
||||
}
|
||||
|
||||
|
||||
{{cppname}}Builder::{{cppname}}Builder()
|
||||
:
|
||||
fHasValueBitmask(0),
|
||||
fSourceRef(),
|
||||
{{#propertyarray}} {{property.cppmembername}}({{property.cppdefaultvalue}}){{^islast}},
|
||||
{{/islast}}{{/propertyarray}}
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
{{cppname}}Builder::{{cppname}}Builder(const {{cppname}}Ref& source)
|
||||
:
|
||||
fHasValueBitmask(0),
|
||||
fSourceRef(source),
|
||||
{{#propertyarray}} {{property.cppmembername}}({{property.cppdefaultvalue}}){{^islast}},
|
||||
{{/islast}}{{/propertyarray}}
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
{{cppname}}Builder::~{{cppname}}Builder()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
{{cppname}}Builder::_InitFromSource()
|
||||
{
|
||||
if (fSourceRef.IsSet()) {
|
||||
_Init(fSourceRef.Get());
|
||||
fSourceRef.Unset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
{{cppname}}Builder::_Init(const {{cppname}}* source)
|
||||
{
|
||||
{{#propertyarray}} if (source->IsSet{{property.cppname}}()) {
|
||||
fHasValueBitmask |= {{cppobjectname}}::k{{property.cppname}}Bitmask;
|
||||
{{property.cppmembername}} = source->{{property.cppname}}();
|
||||
}
|
||||
{{/propertyarray}}
|
||||
}
|
||||
|
||||
|
||||
{{#propertyarray}}{{#property.isarray}}{{cppname}}Builder&
|
||||
{{cppname}}Builder::AddTo{{property.cppname}}({{property.items.cpptype}} value)
|
||||
{
|
||||
{{#property.items.isstring}} _InitFromSource();
|
||||
fHasValueBitmask |= {{cppobjectname}}::k{{property.cppname}}Bitmask;
|
||||
{{property.cppmembername}}.push_back(value);
|
||||
{{/property.items.isstring}}{{#property.items.isobject}} if (!value.IsSet()) {
|
||||
debugger("value for [{{property.cppname}}] in class [{{cppname}}Builder}}] is unset");
|
||||
} else {
|
||||
_InitFromSource();
|
||||
fHasValueBitmask |= {{cppobjectname}}::k{{property.cppname}}Bitmask;
|
||||
{{property.cppmembername}}.push_back(value);
|
||||
}
|
||||
{{/property.items.isobject}}
|
||||
return *this;
|
||||
}
|
||||
{{/property.isarray}}
|
||||
|
||||
{{cppname}}Builder&
|
||||
{{cppname}}Builder::With{{property.cppname}}({{property.cpptype}} value)
|
||||
{
|
||||
{{#property.isobject}} if (!value->IsSet())
|
||||
return Without{{property.cppname}}();
|
||||
{{/property.isobject}} if (!fSourceRef.IsSet() || !fSourceRef->IsSet{{property.cppname}}() || fSourceRef->{{property.cppname}}() != value) {
|
||||
_InitFromSource();
|
||||
fHasValueBitmask |= {{cppobjectname}}::k{{property.cppname}}Bitmask;
|
||||
{{property.cppmembername}} = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
{{cppname}}Builder&
|
||||
{{cppname}}Builder::Without{{property.cppname}}()
|
||||
{
|
||||
if (!fSourceRef.IsSet() || fSourceRef->IsSet{{property.cppname}}()) {
|
||||
_InitFromSource();
|
||||
fHasValueBitmask &= ~{{cppobjectname}}::k{{property.cppname}}Bitmask;
|
||||
{{property.cppmembername}} = {{property.cppdefaultvalue}};
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
{{/propertyarray}}
|
||||
|
||||
{{cppname}}Ref
|
||||
{{cppname}}Builder::BuildRef()
|
||||
{
|
||||
if (fSourceRef.IsSet())
|
||||
return fSourceRef;
|
||||
|
||||
{{cppname}}* result = new {{cppname}}();
|
||||
|
||||
{{#propertyarray}} if (0 != (fHasValueBitmask & {{cppobjectname}}::k{{property.cppname}}Bitmask))
|
||||
result->_Set{{property.cppname}}({{property.cppmembername}});
|
||||
{{/propertyarray}}
|
||||
return {{cppname}}Ref(result, true);
|
||||
}
|
||||
|
||||
|
||||
/*! Sets the builder as if it had no values set. Even if it was initialized
|
||||
with an existing object, it will be reset with no values.
|
||||
*/
|
||||
{{cppname}}Builder&
|
||||
{{cppname}}Builder::Clear()
|
||||
{
|
||||
fHasValueBitmask = 0;
|
||||
fSourceRef.Unset();
|
||||
return *this;
|
||||
}{{/objects}}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Generated Listener Object for {{outputfilename}}
|
||||
*/
|
||||
|
||||
#ifndef GEN_JSON_SCHEMA_PARSER__{{outputfilestemupper}}_H
|
||||
#define GEN_JSON_SCHEMA_PARSER__{{outputfilestemupper}}_H
|
||||
|
||||
#include <JsonEventListener.h>
|
||||
|
||||
#include "{{toplevel.cppname}}Model.h"
|
||||
|
||||
|
||||
class _AbstractStacked{{toplevel.cppname}}JsonListener;
|
||||
|
||||
|
||||
class AbstractMain{{toplevel.cppname}}JsonListener : public BJsonEventListener {
|
||||
friend class _AbstractStacked{{toplevel.cppname}}JsonListener;
|
||||
public:
|
||||
AbstractMain{{toplevel.cppname}}JsonListener();
|
||||
virtual ~AbstractMain{{toplevel.cppname}}JsonListener();
|
||||
|
||||
void HandleError(status_t status, int32 line, const char* message);
|
||||
void Complete();
|
||||
status_t ErrorStatus();
|
||||
|
||||
protected:
|
||||
void SetStackedListener(
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener* listener);
|
||||
|
||||
protected:
|
||||
status_t fErrorStatus;
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener* fStackedListener;
|
||||
};
|
||||
|
||||
|
||||
/*! Use this listener when you want to parse some JSON data that contains
|
||||
just a single instance of {{toplevel.cppname}}.
|
||||
*/
|
||||
class Single{{toplevel.cppname}}JsonListener
|
||||
: public AbstractMain{{toplevel.cppname}}JsonListener {
|
||||
friend class AbstractStacked{{toplevel.cppname}}JsonListener;
|
||||
public:
|
||||
Single{{toplevel.cppname}}JsonListener();
|
||||
virtual ~Single{{toplevel.cppname}}JsonListener();
|
||||
|
||||
bool Handle(const BJsonEvent& event);
|
||||
{{toplevel.cppname}}Ref Result();
|
||||
|
||||
static bool WithResultCallback(void*, const {{toplevel.cppname}}Ref value);
|
||||
|
||||
private:
|
||||
{{toplevel.cppname}}Ref fResult;
|
||||
};
|
||||
|
||||
|
||||
/*! Concrete sub-classes of this class are able to respond to each
|
||||
{{toplevel.cppname}} instance as
|
||||
it is parsed from the bulk container. When the stream is
|
||||
finished, the Complete() method is invoked.
|
||||
*/
|
||||
class {{toplevel.cppname}}Listener {
|
||||
public:
|
||||
virtual bool Handle({{toplevel.cppname}}Ref item) = 0;
|
||||
virtual void Complete() = 0;
|
||||
};
|
||||
|
||||
|
||||
/*! Use this listener, together with an instance of a concrete
|
||||
subclass of {{toplevel.cppname}}Listener
|
||||
in order to parse the JSON data in a specific "bulk
|
||||
container" format. Each time that an instance of
|
||||
{{toplevel.cppname}}
|
||||
is parsed, the instance item listener will be invoked.
|
||||
*/
|
||||
class BulkContainer{{toplevel.cppname}}JsonListener
|
||||
: public AbstractMain{{toplevel.cppname}}JsonListener {
|
||||
friend class AbstractStacked{{toplevel.cppname}}JsonListener;
|
||||
public:
|
||||
BulkContainer{{toplevel.cppname}}JsonListener(
|
||||
{{toplevel.cppname}}Listener* itemListener);
|
||||
~BulkContainer{{toplevel.cppname}}JsonListener();
|
||||
|
||||
bool Handle(const BJsonEvent& event);
|
||||
|
||||
private:
|
||||
{{toplevel.cppname}}Listener* fItemListener;
|
||||
};
|
||||
|
||||
#endif // GEN_JSON_SCHEMA_PARSER__{{outputfilestemupper}}_H
|
||||
@@ -0,0 +1,916 @@
|
||||
/*
|
||||
* Generated Listener Object for {{outputfilename}}
|
||||
*/
|
||||
|
||||
#include "{{toplevel.cppname}}JsonListener.h"
|
||||
|
||||
#include <ObjectList.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 _AbstractStacked{{toplevel.cppname}}JsonListener : public BJsonEventListener {
|
||||
public:
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener(
|
||||
AbstractMain{{toplevel.cppname}}JsonListener* mainListener,
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener* parent);
|
||||
~_AbstractStacked{{toplevel.cppname}}JsonListener();
|
||||
|
||||
void HandleError(status_t status, int32 line, const char* message);
|
||||
void Complete();
|
||||
|
||||
status_t ErrorStatus();
|
||||
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener* Parent();
|
||||
|
||||
virtual bool WillPop();
|
||||
|
||||
virtual void Clear();
|
||||
|
||||
protected:
|
||||
AbstractMain{{toplevel.cppname}}JsonListener* fMainListener;
|
||||
|
||||
virtual bool Pop();
|
||||
|
||||
void Push(_AbstractStacked{{toplevel.cppname}}JsonListener* stackedListener);
|
||||
|
||||
private:
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener* fParent;
|
||||
};
|
||||
|
||||
|
||||
/*! This implementation of the listener will consume data from the array and
|
||||
discard it.
|
||||
*/
|
||||
class _GeneralNoOpArrayStacked{{toplevel.cppname}}JsonListener : public _AbstractStacked{{toplevel.cppname}}JsonListener {
|
||||
public:
|
||||
_GeneralNoOpArrayStacked{{toplevel.cppname}}JsonListener(
|
||||
AbstractMain{{toplevel.cppname}}JsonListener* mainListener,
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener* parent);
|
||||
~_GeneralNoOpArrayStacked{{toplevel.cppname}}JsonListener();
|
||||
|
||||
bool Handle(const BJsonEvent& event);
|
||||
};
|
||||
|
||||
|
||||
class _GeneralNoOpObjectStacked{{toplevel.cppname}}JsonListener : public _AbstractStacked{{toplevel.cppname}}JsonListener {
|
||||
public:
|
||||
_GeneralNoOpObjectStacked{{toplevel.cppname}}JsonListener(
|
||||
AbstractMain{{toplevel.cppname}}JsonListener* mainListener,
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener* parent);
|
||||
~_GeneralNoOpObjectStacked{{toplevel.cppname}}JsonListener();
|
||||
|
||||
bool Handle(const BJsonEvent& event);
|
||||
};
|
||||
|
||||
|
||||
/*! Sometimes attributes of objects are able to be arrays of strings. This
|
||||
listener will parse and return the array of strings.
|
||||
*/
|
||||
|
||||
class _StringListStacked{{toplevel.cppname}}JsonListener : public _AbstractStacked{{toplevel.cppname}}JsonListener {
|
||||
public:
|
||||
_StringListStacked{{toplevel.cppname}}JsonListener(
|
||||
bool (*callback)(void* context, const std::vector<BString>& values),
|
||||
void* callbackContext,
|
||||
AbstractMain{{toplevel.cppname}}JsonListener* mainListener,
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener* parent);
|
||||
~_StringListStacked{{toplevel.cppname}}JsonListener();
|
||||
|
||||
bool Handle(const BJsonEvent& event);
|
||||
|
||||
void Clear();
|
||||
|
||||
protected:
|
||||
bool Pop();
|
||||
|
||||
protected:
|
||||
std::vector<BString> fAccumulator;
|
||||
bool (*fCallback)(void* context, const std::vector<BString>& values);
|
||||
void* fCallbackContext;
|
||||
};
|
||||
{{#allobjs}}
|
||||
|
||||
class _{{cppname}}Stacked{{toplevelcppname}}JsonListener : public _AbstractStacked{{toplevelcppname}}JsonListener {
|
||||
public:
|
||||
_{{cppname}}Stacked{{toplevelcppname}}JsonListener(
|
||||
bool (*callback)(void* context, const {{cppname}}Ref ref),
|
||||
void* callbackContext,
|
||||
AbstractMain{{toplevelcppname}}JsonListener* mainListener,
|
||||
_AbstractStacked{{toplevelcppname}}JsonListener* parent);
|
||||
~_{{cppname}}Stacked{{toplevelcppname}}JsonListener();
|
||||
|
||||
bool Handle(const BJsonEvent& event);
|
||||
|
||||
void Clear();
|
||||
|
||||
{{#propertyarray}}{{#property.isobject}} static bool With{{property.cppname}}Callback(void* context, const {{property.cpptype}} value);
|
||||
{{/property.isobject}}{{#property.isarray}} static bool With{{property.cppname}}Callback(void* context, const {{property.cpptype}}& value);
|
||||
{{/property.isarray}}{{/propertyarray}}
|
||||
|
||||
protected:
|
||||
bool Pop();
|
||||
|
||||
protected:
|
||||
{{cppname}}Builder fBuilder;
|
||||
uint16 fNextItemBitmask;
|
||||
bool (*fCallback)(void* context, const {{cppname}}Ref ref);
|
||||
void* fCallbackContext;
|
||||
};
|
||||
|
||||
class _{{cppname}}ListStacked{{toplevelcppname}}JsonListener : public _AbstractStacked{{toplevelcppname}}JsonListener {
|
||||
public:
|
||||
_{{cppname}}ListStacked{{toplevelcppname}}JsonListener(
|
||||
bool (*callback)(void* context, const std::vector<{{cppname}}Ref>& values),
|
||||
void* callbackContext,
|
||||
AbstractMain{{toplevelcppname}}JsonListener* mainListener,
|
||||
_AbstractStacked{{toplevelcppname}}JsonListener* parent);
|
||||
~_{{cppname}}ListStacked{{toplevelcppname}}JsonListener();
|
||||
|
||||
bool Handle(const BJsonEvent& event);
|
||||
|
||||
void Clear();
|
||||
|
||||
static bool AddItemCallback(void* target, const {{cppname}}Ref value);
|
||||
|
||||
protected:
|
||||
bool Pop();
|
||||
|
||||
private:
|
||||
std::vector<{{cppname}}Ref> fAccumulator;
|
||||
bool (*fCallback)(void* context, const std::vector<{{cppname}}Ref>& values);
|
||||
void* fCallbackContext;
|
||||
};
|
||||
{{/allobjs}}
|
||||
|
||||
|
||||
class _BulkContainerStacked{{toplevel.cppname}}JsonListener : public _AbstractStacked{{toplevel.cppname}}JsonListener {
|
||||
public:
|
||||
_BulkContainerStacked{{toplevel.cppname}}JsonListener(
|
||||
AbstractMain{{toplevel.cppname}}JsonListener* mainListener,
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener* parent,
|
||||
{{toplevel.cppname}}Listener* itemListener);
|
||||
~_BulkContainerStacked{{toplevel.cppname}}JsonListener();
|
||||
|
||||
bool Handle(const BJsonEvent& event);
|
||||
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
bool fNextItemIsItems;
|
||||
{{toplevel.cppname}}Listener* fItemListener;
|
||||
};
|
||||
|
||||
|
||||
class _BulkContainerItemsStacked{{toplevel.cppname}}JsonListener : public _AbstractStacked{{toplevel.cppname}}JsonListener {
|
||||
public:
|
||||
_BulkContainerItemsStacked{{toplevel.cppname}}JsonListener(
|
||||
AbstractMain{{toplevel.cppname}}JsonListener* mainListener,
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener* parent,
|
||||
{{toplevel.cppname}}Listener* itemListener);
|
||||
~_BulkContainerItemsStacked{{toplevel.cppname}}JsonListener();
|
||||
|
||||
bool Handle(const BJsonEvent& event);
|
||||
bool WillPop();
|
||||
|
||||
static bool NotifyListenerCallback(void* context, const {{toplevel.cppname}}Ref value);
|
||||
|
||||
private:
|
||||
{{toplevel.cppname}}Listener* fItemListener;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - implementations for the stacked listeners
|
||||
|
||||
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener::_AbstractStacked{{toplevel.cppname}}JsonListener (
|
||||
AbstractMain{{toplevel.cppname}}JsonListener* mainListener,
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener* parent)
|
||||
{
|
||||
fMainListener = mainListener;
|
||||
fParent = parent;
|
||||
}
|
||||
|
||||
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener::~_AbstractStacked{{toplevel.cppname}}JsonListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener::HandleError(status_t status, int32 line, const char* message)
|
||||
{
|
||||
fMainListener->HandleError(status, line, message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener::Complete()
|
||||
{
|
||||
fMainListener->Complete();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener::ErrorStatus()
|
||||
{
|
||||
return fMainListener->ErrorStatus();
|
||||
}
|
||||
|
||||
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener*
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener::Parent()
|
||||
{
|
||||
return fParent;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener::Push(_AbstractStacked{{toplevel.cppname}}JsonListener* stackedListener)
|
||||
{
|
||||
fMainListener->SetStackedListener(stackedListener);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener::WillPop()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener::Pop()
|
||||
{
|
||||
bool result = WillPop();
|
||||
fMainListener->SetStackedListener(fParent);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener::Clear()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
_GeneralNoOpObjectStacked{{toplevel.cppname}}JsonListener::_GeneralNoOpObjectStacked{{toplevel.cppname}}JsonListener(
|
||||
AbstractMain{{toplevel.cppname}}JsonListener* mainListener,
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener* parent)
|
||||
:
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener(mainListener, parent)
|
||||
{
|
||||
}
|
||||
|
||||
_GeneralNoOpObjectStacked{{toplevel.cppname}}JsonListener::~_GeneralNoOpObjectStacked{{toplevel.cppname}}JsonListener()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
_GeneralNoOpObjectStacked{{toplevel.cppname}}JsonListener::Handle(const BJsonEvent& event)
|
||||
{
|
||||
switch (event.EventType()) {
|
||||
case B_JSON_OBJECT_NAME:
|
||||
case B_JSON_NUMBER:
|
||||
case B_JSON_STRING:
|
||||
case B_JSON_TRUE:
|
||||
case B_JSON_FALSE:
|
||||
case B_JSON_NULL:
|
||||
// ignore
|
||||
break;
|
||||
case B_JSON_OBJECT_START:
|
||||
Push(new _GeneralNoOpObjectStacked{{toplevel.cppname}}JsonListener(fMainListener, this));
|
||||
break;
|
||||
case B_JSON_ARRAY_START:
|
||||
Push(new _GeneralNoOpArrayStacked{{toplevel.cppname}}JsonListener(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:
|
||||
{
|
||||
bool status = Pop() && (ErrorStatus() == B_OK);
|
||||
delete this;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
return ErrorStatus() == B_OK;
|
||||
}
|
||||
|
||||
_GeneralNoOpArrayStacked{{toplevel.cppname}}JsonListener::_GeneralNoOpArrayStacked{{toplevel.cppname}}JsonListener(
|
||||
AbstractMain{{toplevel.cppname}}JsonListener* mainListener,
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener* parent)
|
||||
:
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener(mainListener, parent)
|
||||
{
|
||||
}
|
||||
|
||||
_GeneralNoOpArrayStacked{{toplevel.cppname}}JsonListener::~_GeneralNoOpArrayStacked{{toplevel.cppname}}JsonListener()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
_GeneralNoOpArrayStacked{{toplevel.cppname}}JsonListener::Handle(const BJsonEvent& event)
|
||||
{
|
||||
switch (event.EventType()) {
|
||||
case B_JSON_OBJECT_NAME:
|
||||
case B_JSON_NUMBER:
|
||||
case B_JSON_STRING:
|
||||
case B_JSON_TRUE:
|
||||
case B_JSON_FALSE:
|
||||
case B_JSON_NULL:
|
||||
// ignore
|
||||
break;
|
||||
case B_JSON_OBJECT_START:
|
||||
Push(new _GeneralNoOpObjectStacked{{toplevel.cppname}}JsonListener(fMainListener, this));
|
||||
break;
|
||||
case B_JSON_ARRAY_START:
|
||||
Push(new _GeneralNoOpArrayStacked{{toplevel.cppname}}JsonListener(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:
|
||||
{
|
||||
bool status = Pop() && (ErrorStatus() == B_OK);
|
||||
delete this;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ErrorStatus() == B_OK;
|
||||
}
|
||||
|
||||
_StringListStacked{{toplevel.cppname}}JsonListener::_StringListStacked{{toplevel.cppname}}JsonListener(
|
||||
bool (*callback)(void* context, const std::vector<BString>& values),
|
||||
void* callbackContext,
|
||||
AbstractMain{{toplevel.cppname}}JsonListener* mainListener,
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener* parent)
|
||||
:
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener(mainListener, parent),
|
||||
fAccumulator(),
|
||||
fCallback(callback),
|
||||
fCallbackContext(callbackContext)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
_StringListStacked{{toplevel.cppname}}JsonListener::~_StringListStacked{{toplevel.cppname}}JsonListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
_StringListStacked{{toplevel.cppname}}JsonListener::Pop()
|
||||
{
|
||||
bool callbackResult = fCallback(fCallbackContext, fAccumulator);
|
||||
return _AbstractStacked{{toplevel.cppname}}JsonListener::Pop() && callbackResult;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_StringListStacked{{toplevel.cppname}}JsonListener::Clear()
|
||||
{
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener::Clear();
|
||||
fAccumulator.clear();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
_StringListStacked{{toplevel.cppname}}JsonListener::Handle(const BJsonEvent& event)
|
||||
{
|
||||
switch (event.EventType()) {
|
||||
case B_JSON_ARRAY_END:
|
||||
{
|
||||
bool status = Pop() && (ErrorStatus() == B_OK);
|
||||
delete this;
|
||||
return status;
|
||||
}
|
||||
case B_JSON_STRING:
|
||||
{
|
||||
fAccumulator.push_back(event.Content());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
|
||||
"illegal state - unexpected json event parsing a string array");
|
||||
break;
|
||||
}
|
||||
|
||||
return ErrorStatus() == B_OK;
|
||||
}
|
||||
|
||||
{{#allobjs}}
|
||||
_{{cppname}}Stacked{{toplevelcppname}}JsonListener::_{{cppname}}Stacked{{toplevelcppname}}JsonListener(
|
||||
bool (*callback)(void* context, const {{cppname}}Ref ref),
|
||||
void* callbackContext,
|
||||
AbstractMain{{toplevelcppname}}JsonListener* mainListener,
|
||||
_AbstractStacked{{toplevelcppname}}JsonListener* parent)
|
||||
:
|
||||
_AbstractStacked{{toplevelcppname}}JsonListener(mainListener, parent),
|
||||
fBuilder(),
|
||||
fCallback(callback),
|
||||
fCallbackContext(callbackContext)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
_{{cppname}}Stacked{{toplevelcppname}}JsonListener::~_{{cppname}}Stacked{{toplevelcppname}}JsonListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
_{{cppname}}Stacked{{toplevelcppname}}JsonListener::Pop()
|
||||
{
|
||||
bool callbackResult = fCallback(fCallbackContext, fBuilder.BuildRef());
|
||||
return _AbstractStacked{{toplevelcppname}}JsonListener::Pop() && callbackResult;
|
||||
}
|
||||
{{#propertyarray}}{{#property.isobject}}
|
||||
/*static*/ bool
|
||||
_{{cppname}}Stacked{{toplevelcppname}}JsonListener::With{{property.cppname}}Callback(void* context, const {{property.cpptype}} value)
|
||||
{{/property.isobject}}{{#property.isarray}}/*static*/ bool
|
||||
_{{cppname}}Stacked{{toplevelcppname}}JsonListener::With{{property.cppname}}Callback(void* context, const {{property.cpptype}}& value)
|
||||
{{/property.isarray}}{{#property.isobjectorarray}}{
|
||||
{{cppname}}Builder* builder = static_cast<{{cppname}}Builder*>(context);
|
||||
builder->With{{property.cppname}}(value);
|
||||
return true;
|
||||
}
|
||||
{{/property.isobjectorarray}}{{/propertyarray}}
|
||||
|
||||
|
||||
void
|
||||
_{{cppname}}Stacked{{toplevelcppname}}JsonListener::Clear()
|
||||
{
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener::Clear();
|
||||
fBuilder.Clear();
|
||||
fNextItemBitmask = 0;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
_{{cppname}}Stacked{{toplevelcppname}}JsonListener::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:
|
||||
fNextItemBitmask = 0;
|
||||
{{#propertyarray}} if (0 == strcmp(event.Content(), "{{name}}"))
|
||||
fNextItemBitmask = {{cppobjectname}}::k{{property.cppname}}Bitmask;
|
||||
{{/propertyarray}}
|
||||
break;
|
||||
case B_JSON_OBJECT_END:
|
||||
{
|
||||
bool status = Pop() && (ErrorStatus() == B_OK);
|
||||
delete this;
|
||||
return status;
|
||||
}
|
||||
case B_JSON_STRING:
|
||||
{
|
||||
{{#propertyarray}}{{#property.isstring}} if (fNextItemBitmask == {{cppobjectname}}::k{{property.cppname}}Bitmask)
|
||||
fBuilder.With{{property.cppname}}(event.Content());
|
||||
{{/property.isstring}}{{/propertyarray}}
|
||||
fNextItemBitmask = 0;
|
||||
break;
|
||||
}
|
||||
case B_JSON_TRUE:
|
||||
{{#propertyarray}}{{#property.isboolean}} if (fNextItemBitmask == {{cppobjectname}}::k{{property.cppname}}Bitmask)
|
||||
fBuilder.With{{property.cppname}}(true);
|
||||
{{/property.isboolean}}{{/propertyarray}}
|
||||
fNextItemBitmask = 0;
|
||||
break;
|
||||
case B_JSON_FALSE:
|
||||
{{#propertyarray}}{{#property.isboolean}} if (fNextItemBitmask == {{cppobjectname}}::k{{property.cppname}}Bitmask)
|
||||
fBuilder.With{{property.cppname}}(false);
|
||||
{{/property.isboolean}}
|
||||
{{/propertyarray}}
|
||||
fNextItemBitmask = 0;
|
||||
break;
|
||||
case B_JSON_NULL:
|
||||
{
|
||||
{{#propertyarray}}{{^property.isarray}} if (fNextItemBitmask == {{cppobjectname}}::k{{property.cppname}}Bitmask)
|
||||
fBuilder.Without{{property.cppname}}();
|
||||
{{/property.isarray}}{{/propertyarray}}
|
||||
fNextItemBitmask = 0;
|
||||
break;
|
||||
}
|
||||
case B_JSON_NUMBER:
|
||||
{
|
||||
{{#propertyarray}}{{#property.isinteger}} if (fNextItemBitmask == {{cppobjectname}}::k{{property.cppname}}Bitmask)
|
||||
fBuilder.With{{property.cppname}}(event.ContentInteger());
|
||||
{{/property.isinteger}}
|
||||
{{#property.isnumber}} if (fNextItemBitmask == {{cppobjectname}}::k{{property.cppname}}Bitmask)
|
||||
fBuilder.With{{property.cppname}}(event.ContentDouble());
|
||||
{{/property.isnumber}}
|
||||
{{/propertyarray}}
|
||||
fNextItemBitmask = 0;
|
||||
break;
|
||||
}
|
||||
case B_JSON_OBJECT_START:
|
||||
{
|
||||
{{#propertyarray}}{{#property.isobject}} if (fNextItemBitmask == {{cppobjectname}}::k{{property.cppname}}Bitmask) {
|
||||
_GeneralNoOpObjectStacked{{toplevelcppname}}JsonListener* nextListener
|
||||
= new _GeneralNoOpObjectStacked{{toplevelcppname}}JsonListener(
|
||||
_{{cppname}}Stacked{{toplevelcppname}}JsonListener::With{{property.cppname}},
|
||||
&fBuilder,
|
||||
fMainListener,
|
||||
this);
|
||||
Push(nextListener);
|
||||
fNextItemBitmask = 0;
|
||||
break;
|
||||
}
|
||||
{{/property.isobject}}{{/propertyarray}}
|
||||
// a general consumer that will clear any spurious data that was not
|
||||
// part of the schema. This is important for schema evolution.
|
||||
_GeneralNoOpObjectStacked{{toplevelcppname}}JsonListener* nextListener
|
||||
= new _GeneralNoOpObjectStacked{{toplevelcppname}}JsonListener(fMainListener, this);
|
||||
Push(nextListener);
|
||||
fNextItemBitmask = 0;
|
||||
break;
|
||||
}
|
||||
case B_JSON_ARRAY_START:
|
||||
{
|
||||
{{#propertyarray}}{{#property.isarray}} if (fNextItemBitmask == {{cppobjectname}}::k{{property.cppname}}Bitmask) {
|
||||
{{#property.items.isstring}}
|
||||
_StringListStacked{{toplevelcppname}}JsonListener* nextListener = new _StringListStacked{{toplevelcppname}}JsonListener(
|
||||
_{{cppname}}Stacked{{toplevelcppname}}JsonListener::With{{property.cppname}}Callback,
|
||||
&fBuilder,
|
||||
fMainListener,
|
||||
this);
|
||||
{{/property.items.isstring}}{{^property.items.isstring}}
|
||||
_{{property.items.cppname}}ListStacked{{toplevelcppname}}JsonListener* nextListener =
|
||||
new _{{property.items.cppname}}ListStacked{{toplevelcppname}}JsonListener(
|
||||
_{{cppname}}Stacked{{toplevelcppname}}JsonListener::With{{property.cppname}}Callback,
|
||||
&fBuilder,
|
||||
fMainListener,
|
||||
this);
|
||||
{{/property.items.isstring}}
|
||||
Push(nextListener);
|
||||
fNextItemBitmask = 0;
|
||||
break;
|
||||
}
|
||||
{{/property.isarray}}{{/propertyarray}}
|
||||
// a general consumer that will clear any spurious data that was not
|
||||
// part of the schema. This is important for schema evolution.
|
||||
_AbstractStacked{{toplevelcppname}}JsonListener* nextListener
|
||||
= new _GeneralNoOpArrayStacked{{toplevelcppname}}JsonListener(fMainListener, this);
|
||||
Push(nextListener);
|
||||
fNextItemBitmask = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ErrorStatus() == B_OK;
|
||||
}
|
||||
|
||||
|
||||
_{{cppname}}ListStacked{{toplevelcppname}}JsonListener::_{{cppname}}ListStacked{{toplevelcppname}}JsonListener(
|
||||
bool (*callback)(void* context, const std::vector<{{cppname}}Ref>& values),
|
||||
void* callbackContext,
|
||||
AbstractMain{{toplevelcppname}}JsonListener* mainListener,
|
||||
_AbstractStacked{{toplevelcppname}}JsonListener* parent)
|
||||
:
|
||||
_AbstractStacked{{toplevelcppname}}JsonListener(mainListener, parent),
|
||||
fAccumulator(),
|
||||
fCallback(callback),
|
||||
fCallbackContext(callbackContext)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
_{{cppname}}ListStacked{{toplevelcppname}}JsonListener::~_{{cppname}}ListStacked{{toplevelcppname}}JsonListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
_{{cppname}}ListStacked{{toplevelcppname}}JsonListener::Pop()
|
||||
{
|
||||
bool callbackResult = fCallback(fCallbackContext, fAccumulator);
|
||||
return _AbstractStacked{{toplevelcppname}}JsonListener::Pop() && callbackResult;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ bool
|
||||
_{{cppname}}ListStacked{{toplevelcppname}}JsonListener::AddItemCallback(void* context, const {{cppname}}Ref value)
|
||||
{
|
||||
std::vector<{{cppname}}Ref>* accumulator = static_cast<std::vector<{{cppname}}Ref>*>(context);
|
||||
accumulator->push_back(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
_{{cppname}}ListStacked{{toplevelcppname}}JsonListener::Handle(const BJsonEvent& event)
|
||||
{
|
||||
switch (event.EventType()) {
|
||||
case B_JSON_ARRAY_END:
|
||||
{
|
||||
bool status = Pop() && (ErrorStatus() == B_OK);
|
||||
delete this;
|
||||
return status;
|
||||
}
|
||||
case B_JSON_OBJECT_START:
|
||||
{
|
||||
_{{cppname}}Stacked{{toplevelcppname}}JsonListener* nextListener =
|
||||
new _{{cppname}}Stacked{{toplevelcppname}}JsonListener(
|
||||
AddItemCallback,
|
||||
&fAccumulator,
|
||||
fMainListener,
|
||||
this);
|
||||
Push(nextListener);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
|
||||
"illegal state - unexpected json event parsing an array of {{cppname}}");
|
||||
break;
|
||||
}
|
||||
|
||||
return ErrorStatus() == B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_{{cppname}}ListStacked{{toplevelcppname}}JsonListener::Clear()
|
||||
{
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener::Clear();
|
||||
fAccumulator.clear();
|
||||
}
|
||||
{{/allobjs}}
|
||||
|
||||
_BulkContainerStacked{{toplevel.cppname}}JsonListener::_BulkContainerStacked{{toplevel.cppname}}JsonListener(
|
||||
AbstractMain{{toplevel.cppname}}JsonListener* mainListener, _AbstractStacked{{toplevel.cppname}}JsonListener* parent,
|
||||
{{toplevel.cppname}}Listener* itemListener)
|
||||
:
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener(mainListener, parent)
|
||||
{
|
||||
fItemListener = itemListener;
|
||||
}
|
||||
|
||||
|
||||
_BulkContainerStacked{{toplevel.cppname}}JsonListener::~_BulkContainerStacked{{toplevel.cppname}}JsonListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
_BulkContainerStacked{{toplevel.cppname}}JsonListener::Handle(const BJsonEvent& event)
|
||||
{
|
||||
switch (event.EventType()) {
|
||||
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_NAME:
|
||||
fNextItemIsItems = (0 == strcmp(event.Content(), "items"));
|
||||
break;
|
||||
case B_JSON_OBJECT_START:
|
||||
Push(new _GeneralNoOpObjectStacked{{toplevel.cppname}}JsonListener(fMainListener, this));
|
||||
fNextItemIsItems = false;
|
||||
break;
|
||||
case B_JSON_ARRAY_START:
|
||||
if (fNextItemIsItems)
|
||||
Push(new _BulkContainerItemsStacked{{toplevel.cppname}}JsonListener(fMainListener, this, fItemListener));
|
||||
else
|
||||
Push(new _GeneralNoOpArrayStacked{{toplevel.cppname}}JsonListener(fMainListener, this));
|
||||
break;
|
||||
case B_JSON_OBJECT_END:
|
||||
{
|
||||
bool status = Pop() && (ErrorStatus() == B_OK);
|
||||
delete this;
|
||||
return status;
|
||||
}
|
||||
default:
|
||||
// ignore any other fields
|
||||
fNextItemIsItems = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return ErrorStatus() == B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_BulkContainerStacked{{toplevel.cppname}}JsonListener::Clear()
|
||||
{
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener::Clear();
|
||||
fNextItemIsItems = false;
|
||||
}
|
||||
|
||||
|
||||
_BulkContainerItemsStacked{{toplevel.cppname}}JsonListener::_BulkContainerItemsStacked{{toplevel.cppname}}JsonListener(
|
||||
AbstractMain{{toplevel.cppname}}JsonListener* mainListener, _AbstractStacked{{toplevel.cppname}}JsonListener* parent,
|
||||
{{toplevel.cppname}}Listener* itemListener)
|
||||
:
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener(mainListener, parent),
|
||||
fItemListener(itemListener)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
_BulkContainerItemsStacked{{toplevel.cppname}}JsonListener::~_BulkContainerItemsStacked{{toplevel.cppname}}JsonListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
_BulkContainerItemsStacked{{toplevel.cppname}}JsonListener::Handle(const BJsonEvent& event)
|
||||
{
|
||||
switch (event.EventType()) {
|
||||
case B_JSON_OBJECT_START:
|
||||
Push(new _{{toplevel.cppname}}Stacked{{toplevel.cppname}}JsonListener(
|
||||
_BulkContainerItemsStacked{{toplevel.cppname}}JsonListener::NotifyListenerCallback,
|
||||
fItemListener,
|
||||
fMainListener,
|
||||
this
|
||||
));
|
||||
break;
|
||||
case B_JSON_ARRAY_END:
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ bool
|
||||
_BulkContainerItemsStacked{{toplevel.cppname}}JsonListener::NotifyListenerCallback(void* context, const {{toplevel.cppname}}Ref value)
|
||||
{
|
||||
{{toplevel.cppname}}Listener* listener = static_cast<{{toplevel.cppname}}Listener*>(context);
|
||||
return listener->Handle(value);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
_BulkContainerItemsStacked{{toplevel.cppname}}JsonListener::WillPop()
|
||||
{
|
||||
fItemListener->Complete();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - implementations for the main listeners
|
||||
|
||||
|
||||
AbstractMain{{toplevel.cppname}}JsonListener::AbstractMain{{toplevel.cppname}}JsonListener()
|
||||
{
|
||||
fStackedListener = NULL;
|
||||
fErrorStatus = B_OK;
|
||||
}
|
||||
|
||||
|
||||
AbstractMain{{toplevel.cppname}}JsonListener::~AbstractMain{{toplevel.cppname}}JsonListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AbstractMain{{toplevel.cppname}}JsonListener::HandleError(status_t status, int32 line, const char* message)
|
||||
{
|
||||
if (message != NULL) {
|
||||
fprintf(stderr, "an error has arisen processing json for '{{toplevel.cppname}}'; %s\\n", message);
|
||||
} else {
|
||||
fprintf(stderr, "an error has arisen processing json for '{{toplevel.cppname}}'\\n");
|
||||
}
|
||||
fErrorStatus = status;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AbstractMain{{toplevel.cppname}}JsonListener::Complete()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AbstractMain{{toplevel.cppname}}JsonListener::ErrorStatus()
|
||||
{
|
||||
return fErrorStatus;
|
||||
}
|
||||
|
||||
void
|
||||
AbstractMain{{toplevel.cppname}}JsonListener::SetStackedListener(
|
||||
_AbstractStacked{{toplevel.cppname}}JsonListener* stackedListener)
|
||||
{
|
||||
fStackedListener = stackedListener;
|
||||
}
|
||||
|
||||
|
||||
Single{{toplevel.cppname}}JsonListener::Single{{toplevel.cppname}}JsonListener()
|
||||
:
|
||||
AbstractMain{{toplevel.cppname}}JsonListener(),
|
||||
fResult()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Single{{toplevel.cppname}}JsonListener::~Single{{toplevel.cppname}}JsonListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Single{{toplevel.cppname}}JsonListener::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:
|
||||
{
|
||||
_{{toplevel.cppname}}Stacked{{toplevel.cppname}}JsonListener* nextListener
|
||||
= new _{{toplevel.cppname}}Stacked{{toplevel.cppname}}JsonListener(
|
||||
Single{{toplevel.cppname}}JsonListener::WithResultCallback,
|
||||
&fResult,
|
||||
this,
|
||||
NULL);
|
||||
SetStackedListener(nextListener);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
|
||||
"illegal state - unexpected json event parsing top level for {{toplevel.cppname}}");
|
||||
break;
|
||||
}
|
||||
|
||||
return ErrorStatus() == B_OK;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ bool
|
||||
Single{{toplevel.cppname}}JsonListener::WithResultCallback(void* context, const {{toplevel.cppname}}Ref value)
|
||||
{
|
||||
{{toplevel.cppname}}Ref* ref = static_cast<{{toplevel.cppname}}Ref*>(context);
|
||||
if (value.IsSet())
|
||||
ref->SetTo(value.Get(), false);
|
||||
else
|
||||
ref->Unset();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
{{toplevel.cppname}}Ref
|
||||
Single{{toplevel.cppname}}JsonListener::Result()
|
||||
{
|
||||
return fResult;
|
||||
}
|
||||
|
||||
|
||||
BulkContainer{{toplevel.cppname}}JsonListener::BulkContainer{{toplevel.cppname}}JsonListener(
|
||||
{{toplevel.cppname}}Listener* itemListener) : AbstractMain{{toplevel.cppname}}JsonListener()
|
||||
{
|
||||
fItemListener = itemListener;
|
||||
}
|
||||
|
||||
|
||||
BulkContainer{{toplevel.cppname}}JsonListener::~BulkContainer{{toplevel.cppname}}JsonListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BulkContainer{{toplevel.cppname}}JsonListener::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:
|
||||
{
|
||||
_BulkContainerStacked{{toplevel.cppname}}JsonListener* nextListener =
|
||||
new _BulkContainerStacked{{toplevel.cppname}}JsonListener(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 _BulkContainerStacked{{toplevel.cppname}}JsonListener");
|
||||
break;
|
||||
}
|
||||
|
||||
return ErrorStatus() == B_OK;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2020, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2018-2026, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -132,6 +132,8 @@ LocalRepositoryUpdateProcess::_RunForRepositoryName(const BString& repoName,
|
||||
BPackageKit::BContext& context, BPackageKit::BPackageRoster& roster,
|
||||
BPackageKit::BRepositoryCache* cache)
|
||||
{
|
||||
HDINFO("[%s] will update local repo [%s] cache", Name(), repoName.String());
|
||||
|
||||
status_t result = B_ERROR;
|
||||
BRepositoryConfig repoConfig;
|
||||
result = roster.GetRepositoryConfig(repoName, &repoConfig);
|
||||
@@ -140,8 +142,7 @@ LocalRepositoryUpdateProcess::_RunForRepositoryName(const BString& repoName,
|
||||
try {
|
||||
BRefreshRepositoryRequest refreshRequest(context, repoConfig);
|
||||
result = refreshRequest.Process();
|
||||
HDINFO("[%s] did update local repo [%s] cache", Name(),
|
||||
repoName.String());
|
||||
HDINFO("[%s] did update local repo [%s] cache", Name(), repoName.String());
|
||||
result = B_OK;
|
||||
} catch (BFatalErrorException& ex) {
|
||||
_NotifyError(ex.Message(), ex.Details());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2025, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2017-2026, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef SERVER_ICON_EXPORT_UPDATE_PROCESS_H
|
||||
@@ -15,9 +15,6 @@
|
||||
#include "Model.h"
|
||||
|
||||
|
||||
class DumpExportPkg;
|
||||
|
||||
|
||||
class ServerIconExportUpdateProcess : public AbstractSingleFileServerProcess {
|
||||
public:
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2025, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2017-2026, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -17,11 +17,8 @@
|
||||
#include <StopWatch.h>
|
||||
#include <Url.h>
|
||||
|
||||
#include "DumpExportPkg.h"
|
||||
#include "DumpExportPkgCategory.h"
|
||||
#include "DumpExportPkgJsonListener.h"
|
||||
#include "DumpExportPkgScreenshot.h"
|
||||
#include "DumpExportPkgVersion.h"
|
||||
#include "DumpExportPkgModel.h"
|
||||
#include "HaikuDepotConstants.h"
|
||||
#include "Logger.h"
|
||||
#include "PackageUtils.h"
|
||||
@@ -49,7 +46,7 @@ public:
|
||||
PackageFillingPkgListener(Model *model, Stoppable* stoppable);
|
||||
virtual ~PackageFillingPkgListener();
|
||||
|
||||
virtual bool Handle(DumpExportPkg* item);
|
||||
virtual bool Handle(DumpExportPkgRef item);
|
||||
virtual void Complete();
|
||||
|
||||
uint32 Count();
|
||||
@@ -153,19 +150,19 @@ PackageFillingPkgListener::_CreateUpdatePackage(const PackageInfoRef& package,
|
||||
|
||||
DumpExportPkgVersion* pkgVersion = pkg->PkgVersionsItemAt(0);
|
||||
|
||||
if (!pkgVersion->TitleIsNull())
|
||||
localizedTextBuilder.WithTitle(*(pkgVersion->Title()));
|
||||
if (pkgVersion->IsSetTitle())
|
||||
localizedTextBuilder.WithTitle(pkgVersion->Title());
|
||||
|
||||
if (!pkgVersion->SummaryIsNull())
|
||||
localizedTextBuilder.WithSummary(*(pkgVersion->Summary()));
|
||||
if (pkgVersion->IsSetSummary())
|
||||
localizedTextBuilder.WithSummary(pkgVersion->Summary());
|
||||
|
||||
if (!pkgVersion->DescriptionIsNull())
|
||||
localizedTextBuilder.WithDescription(*(pkgVersion->Description()));
|
||||
if (pkgVersion->IsSetDescription())
|
||||
localizedTextBuilder.WithDescription(pkgVersion->Description());
|
||||
|
||||
if (!pkgVersion->PayloadLengthIsNull())
|
||||
if (pkgVersion->IsSetPayloadLength())
|
||||
localInfoBuilder.WithSize(static_cast<off_t>(pkgVersion->PayloadLength()));
|
||||
|
||||
if (!pkgVersion->CreateTimestampIsNull()) {
|
||||
if (pkgVersion->IsSetCreateTimestamp()) {
|
||||
PackageVersionRef versionRef = PackageUtils::Version(package);
|
||||
|
||||
if (versionRef.IsSet()) {
|
||||
@@ -181,7 +178,7 @@ PackageFillingPkgListener::_CreateUpdatePackage(const PackageInfoRef& package,
|
||||
}
|
||||
}
|
||||
|
||||
if (!pkg->DerivedRatingIsNull()) {
|
||||
if (pkg->IsSetDerivedRating()) {
|
||||
// TODO; unify the naming here!
|
||||
userRatingBuilder.WithSummary(UserRatingSummaryBuilder()
|
||||
.WithAverageRating(pkg->DerivedRating())
|
||||
@@ -192,22 +189,22 @@ PackageFillingPkgListener::_CreateUpdatePackage(const PackageInfoRef& package,
|
||||
int32 countPkgCategories = pkg->CountPkgCategories();
|
||||
|
||||
for (i = 0; i < countPkgCategories; i++) {
|
||||
BString* categoryCode = pkg->PkgCategoriesItemAt(i)->Code();
|
||||
CategoryRef category = fCategories[*categoryCode];
|
||||
BString categoryCode = pkg->PkgCategoriesItemAt(i)->Code();
|
||||
CategoryRef category = fCategories[categoryCode];
|
||||
|
||||
if (!category.IsSet())
|
||||
HDERROR("unable to find the category for [%s]", categoryCode->String());
|
||||
HDERROR("unable to find the category for [%s]", categoryCode.String());
|
||||
else
|
||||
classificationInfoBuilder.AddCategory(category);
|
||||
}
|
||||
|
||||
if (!pkg->ProminenceOrderingIsNull())
|
||||
if (pkg->IsSetProminenceOrdering())
|
||||
classificationInfoBuilder.WithProminence(static_cast<uint32>(pkg->ProminenceOrdering()));
|
||||
|
||||
if (!pkg->IsDesktopIsNull())
|
||||
if (pkg->IsSetIsDesktop())
|
||||
classificationInfoBuilder.WithIsDesktop(pkg->IsDesktop());
|
||||
|
||||
if (!pkg->IsNativeDesktopIsNull())
|
||||
if (pkg->IsSetIsNativeDesktop())
|
||||
classificationInfoBuilder.WithIsNativeDesktop(pkg->IsNativeDesktop());
|
||||
|
||||
int32 countPkgScreenshots = pkg->CountPkgScreenshots();
|
||||
@@ -232,7 +229,7 @@ PackageFillingPkgListener::_CreateUpdatePackage(const PackageInfoRef& package,
|
||||
PackageFillingPkgListener::_CreateScreenshot(DumpExportPkgScreenshot* screenshot)
|
||||
{
|
||||
return ScreenshotInfoRef(
|
||||
new ScreenshotInfo(*(screenshot->Code()), static_cast<int32>(screenshot->Width()),
|
||||
new ScreenshotInfo(screenshot->Code(), static_cast<int32>(screenshot->Width()),
|
||||
static_cast<int32>(screenshot->Height()), static_cast<int32>(screenshot->Length())),
|
||||
true);
|
||||
}
|
||||
@@ -246,14 +243,14 @@ PackageFillingPkgListener::Count()
|
||||
|
||||
|
||||
bool
|
||||
PackageFillingPkgListener::Handle(DumpExportPkg* pkg)
|
||||
PackageFillingPkgListener::Handle(DumpExportPkgRef pkg)
|
||||
{
|
||||
const BString packageName = *(pkg->Name());
|
||||
const BString packageName = pkg->Name();
|
||||
PackageInfoRef package = _PackageForName(packageName);
|
||||
|
||||
if (package.IsSet()) {
|
||||
fUpdatedPackages.push_back(_CreateUpdatePackage(package, pkg));
|
||||
HDTRACE("did populate data for [%s]", pkg->Name()->String());
|
||||
HDTRACE("did populate data for [%s]", packageName.String());
|
||||
fCount++;
|
||||
} else {
|
||||
HDINFO("[PackageFillingPkgListener] unable to find the pkg [%s]", packageName.String());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2025, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2019-2026, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -11,17 +11,12 @@
|
||||
#include <time.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <AutoLocker.h>
|
||||
#include <Catalog.h>
|
||||
#include <FileIO.h>
|
||||
#include <Url.h>
|
||||
|
||||
#include "DumpExportReference.h"
|
||||
#include "DumpExportReferenceCountry.h"
|
||||
#include "DumpExportReferenceJsonListener.h"
|
||||
#include "DumpExportReferenceNaturalLanguage.h"
|
||||
#include "DumpExportReferencePkgCategory.h"
|
||||
#include "DumpExportReferenceUserRatingStability.h"
|
||||
#include "DumpExportReferenceModel.h"
|
||||
#include "LocaleUtils.h"
|
||||
#include "Logger.h"
|
||||
#include "ServerSettings.h"
|
||||
@@ -80,6 +75,7 @@ status_t
|
||||
ServerReferenceDataUpdateProcess::ProcessLocalData()
|
||||
{
|
||||
SingleDumpExportReferenceJsonListener* listener = new SingleDumpExportReferenceJsonListener();
|
||||
ObjectDeleter<SingleDumpExportReferenceJsonListener> listenerDeleter(listener);
|
||||
|
||||
BPath localPath;
|
||||
status_t result = GetLocalPath(localPath);
|
||||
@@ -97,12 +93,12 @@ ServerReferenceDataUpdateProcess::ProcessLocalData()
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
return _ProcessData(listener->Target());
|
||||
return _ProcessData(listener->Result());
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ServerReferenceDataUpdateProcess::_ProcessData(DumpExportReference* data)
|
||||
ServerReferenceDataUpdateProcess::_ProcessData(DumpExportReferenceRef data)
|
||||
{
|
||||
status_t result = B_OK;
|
||||
if (result == B_OK)
|
||||
@@ -116,7 +112,7 @@ ServerReferenceDataUpdateProcess::_ProcessData(DumpExportReference* data)
|
||||
|
||||
|
||||
status_t
|
||||
ServerReferenceDataUpdateProcess::_ProcessNaturalLanguages(DumpExportReference* data)
|
||||
ServerReferenceDataUpdateProcess::_ProcessNaturalLanguages(DumpExportReferenceRef data)
|
||||
{
|
||||
HDINFO("[%s] will populate from %" B_PRId32 " possible natural languages", Name(),
|
||||
data->CountNaturalLanguages());
|
||||
@@ -126,7 +122,7 @@ ServerReferenceDataUpdateProcess::_ProcessNaturalLanguages(DumpExportReference*
|
||||
|
||||
for (int32 i = data->CountNaturalLanguages() - 1; i > 0; i--) {
|
||||
DumpExportReferenceNaturalLanguage* naturalLanguage = data->NaturalLanguagesItemAt(i);
|
||||
Language* language = new Language(*(naturalLanguage->Code()), *(naturalLanguage->Name()),
|
||||
Language* language = new Language(naturalLanguage->Code(), naturalLanguage->Name(),
|
||||
naturalLanguage->IsPopular());
|
||||
languages.push_back(LanguageRef(language, true));
|
||||
count++;
|
||||
@@ -142,7 +138,7 @@ ServerReferenceDataUpdateProcess::_ProcessNaturalLanguages(DumpExportReference*
|
||||
|
||||
|
||||
status_t
|
||||
ServerReferenceDataUpdateProcess::_ProcessPkgCategories(DumpExportReference* data)
|
||||
ServerReferenceDataUpdateProcess::_ProcessPkgCategories(DumpExportReferenceRef data)
|
||||
{
|
||||
HDINFO("[%s] will populate %" B_PRId32 " pkg categories", Name(), data->CountPkgCategories());
|
||||
|
||||
@@ -151,7 +147,7 @@ ServerReferenceDataUpdateProcess::_ProcessPkgCategories(DumpExportReference* dat
|
||||
for (int32 i = 0; i < data->CountPkgCategories(); i++) {
|
||||
DumpExportReferencePkgCategory* pkgCategory = data->PkgCategoriesItemAt(i);
|
||||
assembledCategories.push_back(
|
||||
CategoryRef(new PackageCategory(*(pkgCategory->Code()), *(pkgCategory->Name())), true));
|
||||
CategoryRef(new PackageCategory(pkgCategory->Code(), pkgCategory->Name()), true));
|
||||
}
|
||||
|
||||
fModel->SetCategories(assembledCategories);
|
||||
@@ -161,7 +157,7 @@ ServerReferenceDataUpdateProcess::_ProcessPkgCategories(DumpExportReference* dat
|
||||
|
||||
|
||||
status_t
|
||||
ServerReferenceDataUpdateProcess::_ProcessRatingStabilities(DumpExportReference* data)
|
||||
ServerReferenceDataUpdateProcess::_ProcessRatingStabilities(DumpExportReferenceRef data)
|
||||
{
|
||||
HDINFO("[%s] will populate %" B_PRId32 " rating stabilities", Name(),
|
||||
data->CountUserRatingStabilities());
|
||||
@@ -172,8 +168,8 @@ ServerReferenceDataUpdateProcess::_ProcessRatingStabilities(DumpExportReference*
|
||||
DumpExportReferenceUserRatingStability* ratingStability
|
||||
= data->UserRatingStabilitiesItemAt(i);
|
||||
assembledRatingStabilities.push_back(
|
||||
RatingStabilityRef(new RatingStability(*(ratingStability->Code()),
|
||||
*(ratingStability->Name()), ratingStability->Ordering()),
|
||||
RatingStabilityRef(new RatingStability(ratingStability->Code(), ratingStability->Name(),
|
||||
ratingStability->Ordering()),
|
||||
true));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2019-2026, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef SERVER_REFERENCE_DATA_UPDATE_PROCESS_H
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <String.h>
|
||||
#include <Url.h>
|
||||
|
||||
#include "DumpExportReferenceModel.h"
|
||||
#include "Model.h"
|
||||
#include "PackageInfo.h"
|
||||
|
||||
@@ -20,7 +21,6 @@
|
||||
#undef B_TRANSLATION_CONTEXT
|
||||
#define B_TRANSLATION_CONTEXT "ServerReferenceDataUpdateProcess"
|
||||
|
||||
class DumpExportReference;
|
||||
|
||||
class ServerReferenceDataUpdateProcess : public AbstractSingleFileServerProcess
|
||||
{
|
||||
@@ -43,13 +43,10 @@ protected:
|
||||
status_t GetLocalPath(BPath& path) const;
|
||||
|
||||
private:
|
||||
status_t _ProcessData(DumpExportReference* data);
|
||||
status_t _ProcessNaturalLanguages(
|
||||
DumpExportReference* data);
|
||||
status_t _ProcessPkgCategories(
|
||||
DumpExportReference* data);
|
||||
status_t _ProcessRatingStabilities(
|
||||
DumpExportReference* data);
|
||||
status_t _ProcessData(DumpExportReferenceRef data);
|
||||
status_t _ProcessNaturalLanguages(DumpExportReferenceRef data);
|
||||
status_t _ProcessPkgCategories(DumpExportReferenceRef data);
|
||||
status_t _ProcessRatingStabilities(DumpExportReferenceRef data);
|
||||
|
||||
private:
|
||||
Model* fModel;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2025, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2017-2026, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "ServerRepositoryDataUpdateProcess.h"
|
||||
@@ -9,14 +9,12 @@
|
||||
#include <time.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <Autolock.h>
|
||||
#include <Catalog.h>
|
||||
#include <FileIO.h>
|
||||
#include <Url.h>
|
||||
|
||||
#include "DumpExportRepository.h"
|
||||
#include "DumpExportRepositoryJsonListener.h"
|
||||
#include "DumpExportRepositorySource.h"
|
||||
#include "DumpExportRepositoryModel.h"
|
||||
#include "Logger.h"
|
||||
#include "PackageInfo.h"
|
||||
#include "ServerSettings.h"
|
||||
@@ -35,26 +33,22 @@
|
||||
|
||||
class DepotMatchingRepositoryListener : public DumpExportRepositoryListener {
|
||||
public:
|
||||
DepotMatchingRepositoryListener(Model* model,
|
||||
Stoppable* stoppable);
|
||||
DepotMatchingRepositoryListener(Model* model, Stoppable* stoppable);
|
||||
virtual ~DepotMatchingRepositoryListener();
|
||||
|
||||
virtual bool Handle(DumpExportRepository* item);
|
||||
void Handle(DumpExportRepository* repository,
|
||||
DumpExportRepositorySource*
|
||||
repositorySource);
|
||||
virtual bool Handle(DumpExportRepositoryRef item);
|
||||
void Handle(DumpExportRepositoryRef repository,
|
||||
DumpExportRepositorySourceRef repositorySource);
|
||||
void Handle(const BString& identifier,
|
||||
DumpExportRepository* repository,
|
||||
DumpExportRepositorySource*
|
||||
repositorySource);
|
||||
DumpExportRepositoryRef repository,
|
||||
DumpExportRepositorySourceRef repositorySource);
|
||||
virtual void Complete();
|
||||
|
||||
private:
|
||||
void _SetupRepositoryData(
|
||||
DepotInfoRef& depot,
|
||||
DumpExportRepository* repository,
|
||||
DumpExportRepositorySource*
|
||||
repositorySource);
|
||||
DumpExportRepositoryRef repository,
|
||||
DumpExportRepositorySourceRef repositorySource);
|
||||
|
||||
private:
|
||||
Model* fModel;
|
||||
@@ -80,15 +74,15 @@ DepotMatchingRepositoryListener::~DepotMatchingRepositoryListener()
|
||||
|
||||
void
|
||||
DepotMatchingRepositoryListener::_SetupRepositoryData(DepotInfoRef& depot,
|
||||
DumpExportRepository* repository, DumpExportRepositorySource* repositorySource)
|
||||
DumpExportRepositoryRef repository, DumpExportRepositorySourceRef repositorySource)
|
||||
{
|
||||
BString* repositoryCode = repository->Code();
|
||||
BString* repositorySourceCode = repositorySource->Code();
|
||||
BString repositoryCode = repository->Code();
|
||||
BString repositorySourceCode = repositorySource->Code();
|
||||
|
||||
DepotInfoBuilder depotBuilder(depot);
|
||||
|
||||
depotBuilder.WithWebAppRepositoryCode(*repositoryCode);
|
||||
depotBuilder.WithWebAppRepositorySourceCode(*repositorySourceCode);
|
||||
depotBuilder.WithWebAppRepositoryCode(repositoryCode);
|
||||
depotBuilder.WithWebAppRepositorySourceCode(repositorySourceCode);
|
||||
|
||||
DepotInfoRef depotInfo = depotBuilder.BuildRef();
|
||||
fDepots.push_back(depotInfo);
|
||||
@@ -96,19 +90,19 @@ DepotMatchingRepositoryListener::_SetupRepositoryData(DepotInfoRef& depot,
|
||||
if (Logger::IsDebugEnabled()) {
|
||||
HDDEBUG("[DepotMatchingRepositoryListener] associated depot [%s] (%s) "
|
||||
"with server repository source [%s] (%s)",
|
||||
depot->Name().String(), depot->Identifier().String(), repositorySourceCode->String(),
|
||||
repositorySource->Identifier()->String());
|
||||
depot->Name().String(), depot->Identifier().String(), repositorySourceCode.String(),
|
||||
repositorySource->Identifier().String());
|
||||
} else {
|
||||
HDINFO("[DepotMatchingRepositoryListener] associated depot [%s] with "
|
||||
"server repository source [%s]",
|
||||
depot->Name().String(), repositorySourceCode->String());
|
||||
depot->Name().String(), repositorySourceCode.String());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DepotMatchingRepositoryListener::Handle(const BString& identifier, DumpExportRepository* repository,
|
||||
DumpExportRepositorySource* repositorySource)
|
||||
DepotMatchingRepositoryListener::Handle(const BString& identifier,
|
||||
DumpExportRepositoryRef repository, DumpExportRepositorySourceRef repositorySource)
|
||||
{
|
||||
if (!identifier.IsEmpty()) {
|
||||
DepotInfoRef depotForIdentifier = fModel->DepotForIdentifier(identifier);
|
||||
@@ -120,22 +114,22 @@ DepotMatchingRepositoryListener::Handle(const BString& identifier, DumpExportRep
|
||||
|
||||
|
||||
void
|
||||
DepotMatchingRepositoryListener::Handle(DumpExportRepository* repository,
|
||||
DumpExportRepositorySource* repositorySource)
|
||||
DepotMatchingRepositoryListener::Handle(DumpExportRepositoryRef repository,
|
||||
DumpExportRepositorySourceRef repositorySource)
|
||||
{
|
||||
if (!repositorySource->IdentifierIsNull())
|
||||
Handle(*(repositorySource->Identifier()), repository, repositorySource);
|
||||
if (repositorySource->IsSetIdentifier())
|
||||
Handle(repositorySource->Identifier(), repository, repositorySource);
|
||||
|
||||
// there may be additional identifiers for the remote repository and
|
||||
// these should also be taken into consideration.
|
||||
|
||||
for (int32 i = 0; i < repositorySource->CountExtraIdentifiers(); i++)
|
||||
Handle(*(repositorySource->ExtraIdentifiersItemAt(i)), repository, repositorySource);
|
||||
Handle(repositorySource->ExtraIdentifiersItemAt(i), repository, repositorySource);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
DepotMatchingRepositoryListener::Handle(DumpExportRepository* repository)
|
||||
DepotMatchingRepositoryListener::Handle(DumpExportRepositoryRef repository)
|
||||
{
|
||||
int32 i;
|
||||
for (i = 0; i < repository->CountRepositorySources(); i++)
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
/*
|
||||
* Copyright 2017-2020, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2017-2026, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "DumpExportRepositorySource.h"
|
||||
#include "DumpExportRepository.h"
|
||||
#include "DumpExportRepositoryJsonListener.h"
|
||||
#include "DumpExportRepositoryJsonListenerTest.h"
|
||||
#include "DumpExportRepositoryModel.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -124,7 +123,7 @@ public:
|
||||
TestBulkContainerItemListener();
|
||||
virtual ~TestBulkContainerItemListener();
|
||||
|
||||
bool Handle(DumpExportRepository* item);
|
||||
bool Handle(DumpExportRepositoryRef item);
|
||||
void Complete();
|
||||
|
||||
BString ConcatenatedCodes();
|
||||
@@ -200,21 +199,15 @@ DumpExportRepositoryJsonListenerTest::TestSingle()
|
||||
BPrivate::BJson::Parse(inputData, listener);
|
||||
// ----------------------
|
||||
|
||||
DumpExportRepository *repository = listener->Target();
|
||||
ObjectDeleter<DumpExportRepository> repositoryDeleter(repository);
|
||||
DumpExportRepositoryRef repository = listener->Result();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, listener->ErrorStatus());
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(
|
||||
BString("haikuports"), *(repository->Code()));
|
||||
CPPUNIT_ASSERT_EQUAL(
|
||||
BString("HaikuPorts"), *(repository->Name()));
|
||||
CPPUNIT_ASSERT_EQUAL(
|
||||
BString("HaikuPorts is a centralized collection..."),
|
||||
*(repository->Description()));
|
||||
CPPUNIT_ASSERT_EQUAL(
|
||||
BString("https://example.com"),
|
||||
*(repository->InformationUrl()));
|
||||
CPPUNIT_ASSERT_EQUAL(BString("haikuports"), repository->Code());
|
||||
CPPUNIT_ASSERT_EQUAL(BString("HaikuPorts"), repository->Name());
|
||||
CPPUNIT_ASSERT_EQUAL(BString("HaikuPorts is a centralized collection..."),
|
||||
repository->Description());
|
||||
CPPUNIT_ASSERT_EQUAL(BString("https://example.com"), repository->InformationUrl());
|
||||
CPPUNIT_ASSERT_EQUAL(2, repository->CountRepositorySources());
|
||||
|
||||
DumpExportRepositorySource *source0 =
|
||||
@@ -222,12 +215,12 @@ DumpExportRepositoryJsonListenerTest::TestSingle()
|
||||
DumpExportRepositorySource *source1 =
|
||||
repository->RepositorySourcesItemAt(1);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(BString("haikuports_x86_64"), *(source0->Code()));
|
||||
CPPUNIT_ASSERT_EQUAL(BString("haiku:hpkr:haikuports_x86_64"), *(source0->Identifier()));
|
||||
CPPUNIT_ASSERT_EQUAL(BString("zing"), *(source0->ExtraIdentifiersItemAt(0)));
|
||||
CPPUNIT_ASSERT_EQUAL(BString("haikuports_x86_64"), source0->Code());
|
||||
CPPUNIT_ASSERT_EQUAL(BString("haiku:hpkr:haikuports_x86_64"), source0->Identifier());
|
||||
CPPUNIT_ASSERT_EQUAL(BString("zing"), source0->ExtraIdentifiersItemAt(0));
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(BString("haikuports_x86_gcc2"), *(source1->Code()));
|
||||
CPPUNIT_ASSERT_EQUAL(BString("haiku:hpkr:haikuports_x86_gcc2"), *(source1->Identifier()));
|
||||
CPPUNIT_ASSERT_EQUAL(BString("haikuports_x86_gcc2"), source1->Code());
|
||||
CPPUNIT_ASSERT_EQUAL(BString("haiku:hpkr:haikuports_x86_gcc2"), source1->Identifier());
|
||||
}
|
||||
|
||||
|
||||
@@ -267,21 +260,20 @@ TestBulkContainerItemListener::~TestBulkContainerItemListener()
|
||||
*/
|
||||
|
||||
bool
|
||||
TestBulkContainerItemListener::Handle(DumpExportRepository* item)
|
||||
TestBulkContainerItemListener::Handle(DumpExportRepositoryRef item)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
if (!fConcatenatedCodes.IsEmpty())
|
||||
fConcatenatedCodes.Append(" ");
|
||||
|
||||
fConcatenatedCodes.Append(item->Code()->String());
|
||||
fConcatenatedCodes.Append(item->Code().String());
|
||||
|
||||
for (i = 0; i < item->CountRepositorySources(); i++) {
|
||||
if (!fConcatenatedSourcesUrl.IsEmpty())
|
||||
fConcatenatedSourcesUrl.Append(" ");
|
||||
|
||||
fConcatenatedSourcesUrl.Append(
|
||||
item->RepositorySourcesItemAt(i)->Identifier()->String());
|
||||
fConcatenatedSourcesUrl.Append(item->RepositorySourcesItemAt(i)->Identifier().String());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
* Copyright 2026, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "DumpExportRepositoryTest.h"
|
||||
|
||||
#include <cppunit/TestCaller.h>
|
||||
#include <cppunit/TestSuite.h>
|
||||
|
||||
#include "DumpExportRepositoryModel.h"
|
||||
|
||||
|
||||
DumpExportRepositoryTest::DumpExportRepositoryTest()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
DumpExportRepositoryTest::~DumpExportRepositoryTest()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DumpExportRepositoryTest::TestEqualityTrue()
|
||||
{
|
||||
DumpExportRepositoryRef repositoryRef1 = _CreateAny();
|
||||
DumpExportRepositoryRef repositoryRef2 = _CreateAny();
|
||||
|
||||
// ----------------------
|
||||
bool result = (*(repositoryRef1.Get()) == *(repositoryRef2.Get()));
|
||||
// ----------------------
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("==", true, result);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DumpExportRepositoryTest::TestEqualityFalse()
|
||||
{
|
||||
DumpExportRepositoryRef repositoryRef1 = _CreateAny();
|
||||
DumpExportRepositoryRef repositoryRef2
|
||||
= DumpExportRepositoryBuilder(repositoryRef1).WithCode("craters").BuildRef();
|
||||
|
||||
// ----------------------
|
||||
bool result = (*(repositoryRef1.Get()) != *(repositoryRef2.Get()));
|
||||
// ----------------------
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("!=", true, result);
|
||||
}
|
||||
|
||||
|
||||
/*! This test case checks what happens when data changes down the hierarchy of
|
||||
objects. It should still see this as part of the equality.
|
||||
*/
|
||||
void
|
||||
DumpExportRepositoryTest::TestEqualityTransientFalse()
|
||||
{
|
||||
DumpExportRepositoryRef repositoryRef1 = _CreateAny();
|
||||
DumpExportRepositorySourceRef repositorySourceRef1 = repositoryRef1->RepositorySourcesItemAt(0);
|
||||
|
||||
DumpExportRepositoryRef repositoryRef2
|
||||
= DumpExportRepositoryBuilder(repositoryRef1)
|
||||
.WithoutRepositorySources()
|
||||
.AddToRepositorySources(DumpExportRepositorySourceBuilder(repositorySourceRef1)
|
||||
.WithCode("pigeon")
|
||||
.BuildRef())
|
||||
.BuildRef();
|
||||
|
||||
// ----------------------
|
||||
bool result = (*(repositoryRef1.Get()) == *(repositoryRef2.Get()));
|
||||
// ----------------------
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("R1 CountRepositorySources", 1,
|
||||
repositoryRef1->CountRepositorySources());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("R2 CountRepositorySources", 1,
|
||||
repositoryRef2->CountRepositorySources());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("==", false, result);
|
||||
}
|
||||
|
||||
|
||||
/*! Check to make sure that the Clear method works. */
|
||||
void
|
||||
DumpExportRepositoryTest::TestBuilderClear()
|
||||
{
|
||||
DumpExportRepositoryBuilder builder
|
||||
= DumpExportRepositoryBuilder().WithCode("oak").WithName("Oak Tree");
|
||||
|
||||
DumpExportRepositoryRef repositoryBeforeRef = builder.BuildRef();
|
||||
|
||||
// ----------------------
|
||||
builder.Clear();
|
||||
// ----------------------
|
||||
|
||||
DumpExportRepositoryRef repositoryAfterRef = builder.WithCode("birch").BuildRef();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("CodeBefore", BString("oak"), repositoryBeforeRef->Code());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("NameBefore", BString("Oak Tree"), repositoryBeforeRef->Name());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("CodeAfter", BString("birch"), repositoryAfterRef->Code());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("IsSetNameAfter", false, repositoryAfterRef->IsSetName());
|
||||
}
|
||||
|
||||
|
||||
/*! Checks use of the builder without any prior object. */
|
||||
void
|
||||
DumpExportRepositoryTest::TestBuilderFromCold()
|
||||
{
|
||||
|
||||
// ----------------------
|
||||
DumpExportRepositoryRef repositoryRef = _CreateAny();
|
||||
// ----------------------
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Code", BString("flamingo"), repositoryRef->Code());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("IsSetCode", true, repositoryRef->IsSetCode());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Description", BString("Flamingo is a bird"),
|
||||
repositoryRef->Description());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Name", BString("Flamingo"), repositoryRef->Name());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("InformationUrl", BString("http://example.com"),
|
||||
repositoryRef->InformationUrl());
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("SourcesCount", 1, repositoryRef->CountRepositorySources());
|
||||
DumpExportRepositorySourceRef repositorySourceRef = repositoryRef->RepositorySourcesItemAt(0);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Sources0Code", BString("flamingo_x86_64"),
|
||||
repositorySourceRef->Code());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Sources0Identifier", BString("repo:flamingo"),
|
||||
repositorySourceRef->Identifier());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Sources0IsSetArchitectureCode", false,
|
||||
repositorySourceRef->IsSetArchitectureCode());
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("CountRepositorySourceMirrors", 1,
|
||||
repositorySourceRef->CountRepositorySourceMirrors());
|
||||
DumpExportRepositorySourceMirrorRef repositorySourceMirrorRef
|
||||
= repositorySourceRef->RepositorySourceMirrorsItemAt(0);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("CountryCode", BString("de"),
|
||||
repositorySourceMirrorRef->CountryCode());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DumpExportRepositoryTest::TestBuilderFromExisting()
|
||||
{
|
||||
DumpExportRepositoryRef originRepositoryRef = _CreateAny();
|
||||
DumpExportRepositoryBuilder builder
|
||||
= DumpExportRepositoryBuilder(originRepositoryRef).WithCode("flamingo2");
|
||||
|
||||
// ----------------------
|
||||
DumpExportRepositoryRef repositoryRef = builder.BuildRef();
|
||||
// ----------------------
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Code", BString("flamingo2"), repositoryRef->Code());
|
||||
// check that the changed field has come through
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Name", BString("Flamingo"), repositoryRef->Name());
|
||||
// check that the unchanged field has come through
|
||||
|
||||
// check that unmodified subordinate objects are coming through
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("SourcesCount", 1, repositoryRef->CountRepositorySources());
|
||||
DumpExportRepositorySourceRef repositorySourceRef = repositoryRef->RepositorySourcesItemAt(0);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Sources0Code", BString("flamingo_x86_64"),
|
||||
repositorySourceRef->Code());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DumpExportRepositoryTest::TestBuilderFromExistingNoChange()
|
||||
{
|
||||
DumpExportRepositoryRef originRepositoryRef = _CreateAny();
|
||||
DumpExportRepositoryBuilder builder = DumpExportRepositoryBuilder(originRepositoryRef);
|
||||
|
||||
// ----------------------
|
||||
DumpExportRepositoryRef repositoryRef = builder.BuildRef();
|
||||
// ----------------------
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Code", BString("flamingo"), repositoryRef->Code());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DumpExportRepositoryTest::TestFromMessage()
|
||||
{
|
||||
BMessage message = _CreateAnyMessage();
|
||||
|
||||
// ----------------------
|
||||
DumpExportRepositoryRef repository(new DumpExportRepository(&message), true);
|
||||
// ----------------------
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("R Code", BString("myrepo"), repository->Code());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("IsSetCode", true, repository->IsSetCode());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("IsSetInformationUrl", false, repository->IsSetInformationUrl());
|
||||
// ^ specifically check that one of the missing fields is showing as missing.
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("CountRepositorySources", 1, repository->CountRepositorySources());
|
||||
|
||||
DumpExportRepositorySourceRef source0 = repository->RepositorySourcesItemAt(0);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("RS Code", BString("myrepo_x86_64"), source0->Code());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("IsSetCode", true, source0->IsSetCode());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("CountExtraIdentifiers", 2, source0->CountExtraIdentifiers());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("ExtraIdentifier_0", BString("extra_ident:myrepo_x86_64_0"),
|
||||
source0->ExtraIdentifiersItemAt(0));
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("ExtraIdentifier_1", BString("extra_ident:myrepo_x86_64_1"),
|
||||
source0->ExtraIdentifiersItemAt(1));
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("CountRepositorySourceMirrors", 1,
|
||||
source0->CountRepositorySourceMirrors());
|
||||
|
||||
DumpExportRepositorySourceMirrorRef mirror0 = source0->RepositorySourceMirrorsItemAt(0);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("CountryCode", BString("nz"), mirror0->CountryCode());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("IsPrimary", true, mirror0->IsPrimary());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("IsSetIsPrimary", true, mirror0->IsSetIsPrimary());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DumpExportRepositoryTest::TestToMessage()
|
||||
{
|
||||
DumpExportRepositoryRef repositoryRef = _CreateAny();
|
||||
BMessage repositoryMessage;
|
||||
|
||||
// ----------------------
|
||||
status_t result = repositoryRef->Archive(&repositoryMessage, true);
|
||||
// ----------------------
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Result", B_OK, result);
|
||||
|
||||
// quick checks as this could get quite laborious.
|
||||
status_t status;
|
||||
BString anyString;
|
||||
bool anyBool;
|
||||
|
||||
status = repositoryMessage.FindString("Code", &anyString);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Code Status", B_OK, status);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Code", BString("flamingo"), anyString);
|
||||
|
||||
status = repositoryMessage.FindBool("RepositorySources_isSet", &anyBool);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("RepositorySources_isSet Status", B_OK, status);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("RepositorySources_isSet", true, anyBool);
|
||||
|
||||
BMessage repositorySource0Message;
|
||||
status = repositoryMessage.FindMessage("RepositorySources_0", &repositorySource0Message);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("RepositorySources_0 Status", B_OK, status);
|
||||
|
||||
status = repositorySource0Message.FindString("Code", &anyString);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Code Status", B_OK, status);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("Code", BString("flamingo_x86_64"), anyString);
|
||||
|
||||
status = repositorySource0Message.FindBool("ExtraIdentifiers_isSet", &anyBool);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("ExtraIdentifiers_isSet Status", B_OK, status);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("ExtraIdentifiers_isSet", true, anyBool);
|
||||
|
||||
status = repositorySource0Message.FindString("ExtraIdentifiers_0", &anyString);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("ExtraIdentifiers_0 Status", B_OK, status);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("ExtraIdentifiers_0", BString("repo:flamingo2"), anyString);
|
||||
|
||||
status = repositorySource0Message.FindBool("RepositorySourceMirrors_isSet", &anyBool);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("RepositorySourceMirrors_isSet Status", B_OK, status);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("RepositorySourceMirrors_isSet", true, anyBool);
|
||||
|
||||
BMessage repositorySourceMirror0Message;
|
||||
status = repositorySource0Message.FindMessage("RepositorySourceMirrors_0",
|
||||
&repositorySourceMirror0Message);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("RepositorySourceMirrors_0 Status", B_OK, status);
|
||||
|
||||
status = repositorySourceMirror0Message.FindString("CountryCode", &anyString);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("CountryCode Status", B_OK, status);
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("CountryCode", BString("de"), anyString);
|
||||
}
|
||||
|
||||
|
||||
/*static*/ void
|
||||
DumpExportRepositoryTest::AddTests(BTestSuite& parent)
|
||||
{
|
||||
CppUnit::TestSuite& suite = *new CppUnit::TestSuite("DumpExportRepositoryTest");
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<DumpExportRepositoryTest>(
|
||||
"DumpExportRepositoryTest::TestEqualityTrue", &DumpExportRepositoryTest::TestEqualityTrue));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<DumpExportRepositoryTest>(
|
||||
"DumpExportRepositoryTest::TestEqualityFalse",
|
||||
&DumpExportRepositoryTest::TestEqualityFalse));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<DumpExportRepositoryTest>(
|
||||
"DumpExportRepositoryTest::TestEqualityTransientFalse",
|
||||
&DumpExportRepositoryTest::TestEqualityTransientFalse));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<DumpExportRepositoryTest>(
|
||||
"DumpExportRepositoryTest::TestBuilderFromCold",
|
||||
&DumpExportRepositoryTest::TestBuilderFromCold));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<DumpExportRepositoryTest>(
|
||||
"DumpExportRepositoryTest::TestBuilderFromExisting",
|
||||
&DumpExportRepositoryTest::TestBuilderFromExisting));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<DumpExportRepositoryTest>(
|
||||
"DumpExportRepositoryTest::TestBuilderFromExistingNoChange",
|
||||
&DumpExportRepositoryTest::TestBuilderFromExistingNoChange));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<DumpExportRepositoryTest>(
|
||||
"DumpExportRepositoryTest::TestBuilderClear", &DumpExportRepositoryTest::TestBuilderClear));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<DumpExportRepositoryTest>(
|
||||
"DumpExportRepositoryTest::TestFromMessage", &DumpExportRepositoryTest::TestFromMessage));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<DumpExportRepositoryTest>(
|
||||
"DumpExportRepositoryTest::TestToMessage", &DumpExportRepositoryTest::TestToMessage));
|
||||
|
||||
parent.addTest("DumpExportRepositoryTest", &suite);
|
||||
}
|
||||
|
||||
|
||||
/*! This is a `BMessage` that is an archive of an `DumpExportRepository` object. */
|
||||
BMessage
|
||||
DumpExportRepositoryTest::_CreateAnyMessage()
|
||||
{
|
||||
BMessage repositorySourceMirrorMessage;
|
||||
|
||||
if (repositorySourceMirrorMessage.AddString("BaseUrl", "http://www.example.com/mirror_baseurl")
|
||||
!= B_OK) {
|
||||
CPPUNIT_FAIL("unable to add the key [BaseUrl]");
|
||||
}
|
||||
if (repositorySourceMirrorMessage.AddString("CountryCode", "nz") != B_OK)
|
||||
CPPUNIT_FAIL("unable to add the key [CountryCode]");
|
||||
if (repositorySourceMirrorMessage.AddString("Description", "New Zealand mirror") != B_OK)
|
||||
CPPUNIT_FAIL("unable to add the key [Description]");
|
||||
if (repositorySourceMirrorMessage.AddBool("IsPrimary", true) != B_OK)
|
||||
CPPUNIT_FAIL("unable to add the key [IsPrimary]");
|
||||
|
||||
BMessage repositorySourceMessage;
|
||||
|
||||
if (repositorySourceMessage.AddString("ArchitectureCode", "x86_64") != B_OK)
|
||||
CPPUNIT_FAIL("unable to add the key [ArchitectureCode]");
|
||||
if (repositorySourceMessage.AddString("Code", "myrepo_x86_64") != B_OK)
|
||||
CPPUNIT_FAIL("unable to add the key [Code]");
|
||||
if (repositorySourceMessage.AddBool("ExtraIdentifiers_isSet", true) != B_OK)
|
||||
CPPUNIT_FAIL("unable to add the key [ExtraIdentifiers_isSet]");
|
||||
if (repositorySourceMessage.AddString("ExtraIdentifiers_0", "extra_ident:myrepo_x86_64_0")
|
||||
!= B_OK) {
|
||||
CPPUNIT_FAIL("unable to add the key [ExtraIdentifiers_0]");
|
||||
}
|
||||
if (repositorySourceMessage.AddString("ExtraIdentifiers_1", "extra_ident:myrepo_x86_64_1")
|
||||
!= B_OK) {
|
||||
CPPUNIT_FAIL("unable to add the key [ExtraIdentifiers_1]");
|
||||
}
|
||||
if (repositorySourceMessage.AddString("Identifier", "ident:myrepo_x86_64") != B_OK)
|
||||
CPPUNIT_FAIL("unable to add the key [Identifier]");
|
||||
if (repositorySourceMessage.AddString("RepoInfoUrl", "http://www.example.com/myrepo_x86_64")
|
||||
!= B_OK) {
|
||||
CPPUNIT_FAIL("unable to add the key [RepoInfoUrl]");
|
||||
}
|
||||
if (repositorySourceMessage.AddBool("RepositorySourceMirrors_isSet", true) != B_OK)
|
||||
CPPUNIT_FAIL("unable to add the key [RepositorySourceMirrors_isSet]");
|
||||
if (repositorySourceMessage.AddMessage("RepositorySourceMirrors_0",
|
||||
&repositorySourceMirrorMessage)
|
||||
!= B_OK) {
|
||||
CPPUNIT_FAIL("unable to add the key [RepositorySourceMirrors_0]");
|
||||
}
|
||||
|
||||
BMessage repositoryMessage;
|
||||
|
||||
if (repositoryMessage.AddString("Code", "myrepo") != B_OK)
|
||||
CPPUNIT_FAIL("unable to add the key [Code]");
|
||||
if (repositoryMessage.AddString("Description", "This is my repo") != B_OK)
|
||||
CPPUNIT_FAIL("unable to add the key [Description]");
|
||||
// note; missing the informational url intentionally
|
||||
if (repositoryMessage.AddString("Name", "My Repo") != B_OK)
|
||||
CPPUNIT_FAIL("unable to add the key [Name]");
|
||||
if (repositoryMessage.AddBool("RepositorySources_isSet", true) != B_OK)
|
||||
CPPUNIT_FAIL("unable to add the key [RepositorySources_isSet]");
|
||||
if (repositoryMessage.AddMessage("RepositorySources_0", &repositorySourceMessage) != B_OK)
|
||||
CPPUNIT_FAIL("unable to add the key [RepositorySources_0]");
|
||||
|
||||
return repositoryMessage;
|
||||
}
|
||||
|
||||
|
||||
DumpExportRepositoryRef
|
||||
DumpExportRepositoryTest::_CreateAny()
|
||||
{
|
||||
return DumpExportRepositoryBuilder()
|
||||
.WithCode("flamingo")
|
||||
.WithDescription("Flamingo is a bird")
|
||||
.WithInformationUrl("http://example.com")
|
||||
.WithName("Flamingo")
|
||||
.AddToRepositorySources(DumpExportRepositorySourceBuilder()
|
||||
.WithCode("flamingo_x86_64")
|
||||
.WithIdentifier("repo:flamingo")
|
||||
.AddToExtraIdentifiers("repo:flamingo2")
|
||||
.AddToRepositorySourceMirrors(DumpExportRepositorySourceMirrorBuilder()
|
||||
.WithCountryCode("de")
|
||||
.WithBaseUrl("http://www.example.com/base_url")
|
||||
.BuildRef())
|
||||
.BuildRef())
|
||||
.BuildRef();
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2026, Andrew Lindesay <[email protected]>
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef DUMP_EXPORT_REPOSITORY_TEST_H
|
||||
#define DUMP_EXPORT_REPOSITORY_TEST_H
|
||||
|
||||
#include <Message.h>
|
||||
|
||||
#include <TestCase.h>
|
||||
#include <TestSuite.h>
|
||||
|
||||
#include "DumpExportRepositoryModel.h"
|
||||
|
||||
|
||||
/*! Tests the model in insolation from the listener. */
|
||||
class DumpExportRepositoryTest : public CppUnit::TestCase {
|
||||
public:
|
||||
DumpExportRepositoryTest();
|
||||
virtual ~DumpExportRepositoryTest();
|
||||
|
||||
void TestEqualityTrue();
|
||||
void TestEqualityFalse();
|
||||
void TestEqualityTransientFalse();
|
||||
|
||||
void TestBuilderFromCold();
|
||||
void TestBuilderFromExisting();
|
||||
void TestBuilderFromExistingNoChange();
|
||||
void TestBuilderClear();
|
||||
|
||||
void TestFromMessage();
|
||||
void TestToMessage();
|
||||
|
||||
static void AddTests(BTestSuite& suite);
|
||||
|
||||
private:
|
||||
DumpExportRepositoryRef
|
||||
_CreateAny();
|
||||
BMessage _CreateAnyMessage();
|
||||
};
|
||||
|
||||
|
||||
#endif // DUMP_EXPORT_REPOSITORY_TEST_H
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2024, Andrew Lindesay, [email protected]
|
||||
* Copyright 2017-2026, Andrew Lindesay, [email protected]
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "DataIOUtilsTest.h"
|
||||
#include "DumpExportRepositoryJsonListenerTest.h"
|
||||
#include "DumpExportRepositoryTest.h"
|
||||
#include "JwtTokenHelperTest.h"
|
||||
#include "LocaleUtilsTest.h"
|
||||
#include "StandardMetaDataJsonEventListenerTest.h"
|
||||
@@ -27,7 +28,7 @@ getTestSuite()
|
||||
StandardMetaDataJsonEventListenerTest::AddTests(*suite);
|
||||
DataIOUtilsTest::AddTests(*suite);
|
||||
DumpExportRepositoryJsonListenerTest::AddTests(*suite);
|
||||
DumpExportRepositoryJsonListenerTest::AddTests(*suite);
|
||||
DumpExportRepositoryTest::AddTests(*suite);
|
||||
LocaleUtilsTest::AddTests(*suite);
|
||||
JwtTokenHelperTest::AddTests(*suite);
|
||||
ValidationFailureTest::AddTests(*suite);
|
||||
|
||||
@@ -2,7 +2,7 @@ SubDir HAIKU_TOP src tests apps haikudepot ;
|
||||
|
||||
AddSubDirSupportedPlatforms libbe_test ;
|
||||
|
||||
include [ FDirName $(HAIKU_TOP) src apps haikudepot build jam HdsSchemaGenRules ] ;
|
||||
include [ FDirName $(HAIKU_TOP) src apps haikudepot build jam JsonSchemaGenRules ] ;
|
||||
|
||||
SubDirHdrs [ FDirName $(HAIKU_TOP) src apps haikudepot ] ;
|
||||
SubDirHdrs [ FDirName $(HAIKU_TOP) src apps haikudepot model ] ;
|
||||
@@ -27,52 +27,50 @@ local sourceDir ;
|
||||
for sourceDir in $(sourceDirs) {
|
||||
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src apps haikudepot $(sourceDir) ] ;
|
||||
}
|
||||
local dumpExportRepositoryBulkListenerTargetDirectory =
|
||||
[ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY)
|
||||
dumpexportrepositorybulklistener ] ;
|
||||
local dumpExportRepositoryModelTargetDirectory =
|
||||
[ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY)
|
||||
dumpexportrepositorymodel ] ;
|
||||
SEARCH_SOURCE += $(dumpExportRepositoryBulkListenerTargetDirectory) ;
|
||||
SEARCH_SOURCE += $(dumpExportRepositoryModelTargetDirectory) ;
|
||||
|
||||
local generatedRepositoryModelSourceFiles =
|
||||
DumpExportRepository.cpp
|
||||
DumpExportRepositorySource.cpp
|
||||
DumpExportRepositorySourceMirror.cpp
|
||||
local genServerDumpExportRepositoryListenerTargetDirectory =
|
||||
[ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY) dumpexportrepositorylistener ] ;
|
||||
local genServerDumpExportRepositoryModelTargetDirectory =
|
||||
[ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY) dumpexportrepositorymodel ] ;
|
||||
|
||||
SEARCH_SOURCE += $(genServerDumpExportRepositoryListenerTargetDirectory) ;
|
||||
SEARCH_SOURCE += $(genServerDumpExportRepositoryModelTargetDirectory) ;
|
||||
|
||||
local genServerDumpExportRepositorySchema =
|
||||
[ FDirName $(HAIKU_TOP) src apps haikudepot server schema dumpexportrepository.json ] ;
|
||||
|
||||
local genServerRepositoryModelSourceFiles =
|
||||
DumpExportRepositoryModel.cpp
|
||||
;
|
||||
local generatedRepositoryParserSourceFiles =
|
||||
local genServerRepositoryParserSourceFiles =
|
||||
DumpExportRepositoryJsonListener.cpp
|
||||
;
|
||||
|
||||
LOCATE on dumpexportrepository.json = [ FDirName $(HAIKU_TOP) src apps haikudepot server schema ] ;
|
||||
LOCATE on jsonschema2cppmodel.py = [ FDirName $(HAIKU_TOP) src apps haikudepot build scripts ] ;
|
||||
LOCATE on jsonschema2cppparser.py = [ FDirName $(HAIKU_TOP) src apps haikudepot build scripts ] ;
|
||||
local genDummyFile = "dummy.dat" ;
|
||||
|
||||
local dummyFile = "dummy.dat" ;
|
||||
local genServerDumpExportRepositoryListenerTargetFile =
|
||||
[ FDirName $(genServerDumpExportRepositoryListenerTargetDirectory) $(genDummyFile) ] ;
|
||||
local genServerDumpExportRepositoryModelTargetFile =
|
||||
[ FDirName $(genServerDumpExportRepositoryModelTargetDirectory) $(genDummyFile) ] ;
|
||||
|
||||
local dumpExportRepositoryBulkListenerTargetFile =
|
||||
[ FDirName $(dumpExportRepositoryBulkListenerTargetDirectory) $(dummyFile) ] ;
|
||||
local dumpExportRepositoryModelTargetFile =
|
||||
[ FDirName $(dumpExportRepositoryModelTargetDirectory) $(dummyFile) ] ;
|
||||
JsonSchemaGenModel $(genServerDumpExportRepositoryModelTargetFile)
|
||||
: $(genServerDumpExportRepositorySchema) ;
|
||||
|
||||
HdsSchemaGenModel $(dumpExportRepositoryModelTargetFile)
|
||||
: dumpexportrepository.json : jsonschema2cppmodel.py ;
|
||||
JsonSchemaGenParser $(genServerDumpExportRepositoryListenerTargetFile)
|
||||
: $(genServerDumpExportRepositorySchema) ;
|
||||
|
||||
HdsSchemaGenBulkParser $(dumpExportRepositoryBulkListenerTargetFile)
|
||||
: dumpexportrepository.json : jsonschema2cppparser.py ;
|
||||
|
||||
HdsSchemaGenAppSrcDependsOnGeneration
|
||||
[ FGristFiles $(generatedRepositoryParserSourceFiles) ]
|
||||
[ FGristFiles $(generatedRepositoryParserSourceFiles:S=.h) ]
|
||||
: $(dumpExportRepositoryBulkListenerTargetDirectory)
|
||||
: $(dumpExportRepositoryBulkListenerTargetFile) ;
|
||||
JsonSchemaGenAppSrcDependsOnGeneration
|
||||
[ FGristFiles $(genServerRepositoryParserSourceFiles) ]
|
||||
[ FGristFiles $(genServerRepositoryParserSourceFiles:S=.h) ]
|
||||
: $(genServerDumpExportRepositoryListenerTargetDirectory)
|
||||
: $(genServerDumpExportRepositoryListenerTargetFile)
|
||||
;
|
||||
|
||||
HdsSchemaGenAppSrcDependsOnGeneration
|
||||
[ FGristFiles $(generatedRepositoryModelSourceFiles) ]
|
||||
[ FGristFiles $(generatedRepositoryModelSourceFiles:S=.h) ]
|
||||
: $(dumpExportRepositoryModelTargetDirectory)
|
||||
: $(dumpExportRepositoryModelTargetFile) ;
|
||||
JsonSchemaGenAppSrcDependsOnGeneration
|
||||
[ FGristFiles $(genServerRepositoryModelSourceFiles) ]
|
||||
[ FGristFiles $(genServerRepositoryModelSourceFiles:S=.h) ]
|
||||
: $(genServerDumpExportRepositoryModelTargetDirectory)
|
||||
: $(genServerDumpExportRepositoryModelTargetFile)
|
||||
;
|
||||
|
||||
UnitTestLib haikudepottest.so :
|
||||
HaikuDepotTestAddon.cpp
|
||||
@@ -80,9 +78,10 @@ UnitTestLib haikudepottest.so :
|
||||
DataIOUtils.cpp
|
||||
DataIOUtilsTest.cpp
|
||||
|
||||
$(generatedRepositoryModelSourceFiles)
|
||||
$(generatedRepositoryParserSourceFiles)
|
||||
$(genServerRepositoryModelSourceFiles)
|
||||
$(genServerRepositoryParserSourceFiles)
|
||||
DumpExportRepositoryJsonListenerTest.cpp
|
||||
DumpExportRepositoryTest.cpp
|
||||
|
||||
JwtTokenHelper.cpp
|
||||
JwtTokenHelperTest.cpp
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024, Andrew Lindesay <[email protected]>.
|
||||
* Copyright 2024-2026, Andrew Lindesay <[email protected]>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -35,7 +35,7 @@ LocaleUtilsTest::TestLanguageIsBeforeFalseAfter()
|
||||
LanguageRef languageDeCh = LanguageRef(new Language("de_CH", "German (Swiss)", true), true);
|
||||
|
||||
// ----------------------
|
||||
bool actual = languageZh < languageDeCh;
|
||||
bool actual = (*(languageZh.Get()) < *(languageDeCh.Get()));
|
||||
// ----------------------
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(false, actual);
|
||||
@@ -48,7 +48,7 @@ LocaleUtilsTest::TestLanguageIsBeforeFalseEqual()
|
||||
LanguageRef languageDeCh = LanguageRef(new Language("de_CH", "German (Swiss)", true), true);
|
||||
|
||||
// ----------------------
|
||||
bool actual = languageDeCh < languageDeCh;
|
||||
bool actual = (*(languageDeCh.Get()) < *(languageDeCh.Get()));
|
||||
// ----------------------
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(false, actual);
|
||||
@@ -62,7 +62,7 @@ LocaleUtilsTest::TestLanguageIsBeforeTrueBefore()
|
||||
LanguageRef languageDeCh = LanguageRef(new Language("de_CH", "German (Swiss)", true), true);
|
||||
|
||||
// ----------------------
|
||||
bool actual = languageDeCh < languageZh;
|
||||
bool actual = (*(languageDeCh.Get()) < *(languageZh.Get()));
|
||||
// ----------------------
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(true, actual);
|
||||
|
||||
Reference in New Issue
Block a user