From 2c3790f20c175f14972fce69752ad22b6a67f43d Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Mon, 11 May 2020 23:23:30 +0200 Subject: [PATCH] common/ImageType: move to the store package This is now only used for marshalling in the store, so keep the logic where it is used. Signed-off-by: Tom Gundersen --- internal/common/states.go | 20 +++ internal/common/types.go | 141 ------------------ internal/store/json.go | 97 +++++++++++- .../types_test.go => store/json_test.go} | 4 +- 4 files changed, 116 insertions(+), 146 deletions(-) delete mode 100644 internal/common/types.go rename internal/{common/types_test.go => store/json_test.go} (88%) diff --git a/internal/common/states.go b/internal/common/states.go index ddc5e4dd2..0de0387d3 100644 --- a/internal/common/states.go +++ b/internal/common/states.go @@ -17,6 +17,26 @@ const ( IBFailed ) +// CustomJsonConversionError is thrown when parsing strings into enumerations +type CustomJsonConversionError struct { + reason string +} + +// Error returns the error as a string +func (err *CustomJsonConversionError) Error() string { + return err.reason +} + +// CustomTypeError is thrown when parsing strings into enumerations +type CustomTypeError struct { + reason string +} + +// Error returns the error as a string +func (err *CustomTypeError) Error() string { + return err.reason +} + // ToString converts ImageBuildState into a human readable string func (ibs ImageBuildState) ToString() string { return getStateMapping()[int(ibs)] diff --git a/internal/common/types.go b/internal/common/types.go deleted file mode 100644 index 1f6ce8f26..000000000 --- a/internal/common/types.go +++ /dev/null @@ -1,141 +0,0 @@ -package common - -import ( - "encoding/json" - "fmt" -) - -// CustomJsonConversionError is thrown when parsing strings into enumerations -type CustomJsonConversionError struct { - reason string -} - -// Error returns the error as a string -func (err *CustomJsonConversionError) Error() string { - return err.reason -} - -// CustomTypeError is thrown when parsing strings into enumerations -type CustomTypeError struct { - reason string -} - -// Error returns the error as a string -func (err *CustomTypeError) Error() string { - return err.reason -} - -// Since Go has no generics, this is the only way to write common code for all the types present in this package. -// It uses weakly typed maps to convert between strings and integers which are then wrapped into type aliases. -// Specific implementations are bellow each type. -func unmarshalHelper(data []byte, jsonError, typeConversionError string, mapping map[string]int) (int, error) { - var stringInput string - err := json.Unmarshal(data, &stringInput) - if err != nil { - return 0, &CustomJsonConversionError{string(data) + jsonError} - } - value, exists := mapping[stringInput] - if !exists { - return 0, &CustomJsonConversionError{stringInput + typeConversionError} - } - return value, nil -} - -// See unmarshalHelper for explanation -func marshalHelper(input int, mapping map[string]int, errorMessage string) ([]byte, error) { - for k, v := range mapping { - if v == input { - return json.Marshal(k) - } - } - return nil, &CustomJsonConversionError{fmt.Sprintf("%d %s", input, errorMessage)} -} - -// See unmarshalHelper for introduction. Converts between TypeAlias(int) and string -func toStringHelper(mapping map[string]int, tag int) (string, bool) { - for k, v := range mapping { - if v == tag { - return k, true - } - } - return "", false -} - -type ImageType int - -// NOTE: If you want to add more constants here, don't forget to add a mapping below -const ( - Azure ImageType = iota - Aws - LiveISO - OpenStack - Qcow2Generic - Vmware - RawFilesystem - PartitionedDisk - TarArchive -) - -// getArchMapping is a helper function that defines the conversion from JSON string value -// to ImageType. -func getImageTypeMapping() map[string]int { - mapping := map[string]int{ - "Azure": int(Azure), - "AWS": int(Aws), - "LiveISO": int(LiveISO), - "OpenStack": int(OpenStack), - "qcow2": int(Qcow2Generic), - "VMWare": int(Vmware), - "Raw-filesystem": int(RawFilesystem), - "Partitioned-disk": int(PartitionedDisk), - "Tar": int(TarArchive), - } - return mapping -} - -// TODO: check the mapping here: -func getCompatImageTypeMapping() map[int]string { - mapping := map[int]string{ - int(Azure): "vhd", - int(Aws): "ami", - int(LiveISO): "liveiso", - int(OpenStack): "openstack", - int(Qcow2Generic): "qcow2", - int(Vmware): "vmdk", - int(RawFilesystem): "ext4-filesystem", - int(PartitionedDisk): "partitioned-disk", - int(TarArchive): "tar", - } - return mapping -} - -func (imgType *ImageType) UnmarshalJSON(data []byte) error { - value, err := unmarshalHelper(data, " is not a valid JSON value", " is not a valid image type", getImageTypeMapping()) - if err != nil { - return err - } - *imgType = ImageType(value) - return nil -} - -func (imgType ImageType) MarshalJSON() ([]byte, error) { - return marshalHelper(int(imgType), getImageTypeMapping(), "is not a valid image type tag") -} - -func (imgType ImageType) ToCompatString() (string, bool) { - str, exists := getCompatImageTypeMapping()[int(imgType)] - return str, exists -} - -func ImageTypeFromCompatString(input string) (ImageType, bool) { - for k, v := range getCompatImageTypeMapping() { - if v == input { - return ImageType(k), true - } - } - return ImageType(999), false -} - -func (imgType ImageType) ToString() (string, bool) { - return toStringHelper(getImageTypeMapping(), int(imgType)) -} diff --git a/internal/store/json.go b/internal/store/json.go index 9f8b80745..7c378ef58 100644 --- a/internal/store/json.go +++ b/internal/store/json.go @@ -1,6 +1,9 @@ package store import ( + "encoding/json" + "errors" + "fmt" "sort" "time" @@ -38,7 +41,7 @@ type composesV0 map[uuid.UUID]composeV0 // ImageBuild represents a single image build inside a compose type imageBuildV0 struct { ID int `json:"id"` - ImageType common.ImageType `json:"image_type"` + ImageType imageType `json:"image_type"` Manifest *osbuild.Manifest `json:"manifest"` Targets []*target.Target `json:"targets"` JobCreated time.Time `json:"job_created"` @@ -99,7 +102,7 @@ func newComposesFromV0(composesStruct composesV0, arch distro.Arch) map[uuid.UUI Blueprint: composeStruct.Blueprint, } for _, imgBuild := range composeStruct.ImageBuilds { - imgTypeString, valid := imgBuild.ImageType.ToCompatString() + imgTypeString, valid := imgBuild.ImageType.toCompatString() if !valid { // Invalid type strings in serialization format, this may happen // on upgrades. Ignore the image build. @@ -251,7 +254,7 @@ func newComposesV0(composes map[uuid.UUID]Compose) composesV0 { panic("the was a compose with zero image builds, that is forbidden") } for _, imgBuild := range compose.ImageBuilds { - imgType, valid := common.ImageTypeFromCompatString(imgBuild.ImageType.Name()) + imgType, valid := imageTypeFromCompatString(imgBuild.ImageType.Name()) if !valid { panic("invalid image type") } @@ -317,3 +320,91 @@ func (store *Store) toStoreV0() *storeV0 { Commits: newCommitsV0(store.blueprintsCommits), } } + +type imageType int + +// NOTE: If you want to add more constants here, don't forget to add a mapping below +const ( + Azure imageType = iota + Aws + LiveISO + OpenStack + Qcow2Generic + Vmware + RawFilesystem + PartitionedDisk + TarArchive +) + +// getArchMapping is a helper function that defines the conversion from JSON string value +// to ImageType. +func getImageTypeMapping() map[string]int { + mapping := map[string]int{ + "Azure": int(Azure), + "AWS": int(Aws), + "LiveISO": int(LiveISO), + "OpenStack": int(OpenStack), + "qcow2": int(Qcow2Generic), + "VMWare": int(Vmware), + "Raw-filesystem": int(RawFilesystem), + "Partitioned-disk": int(PartitionedDisk), + "Tar": int(TarArchive), + } + return mapping +} + +// TODO: check the mapping here: +func getCompatImageTypeMapping() map[int]string { + mapping := map[int]string{ + int(Azure): "vhd", + int(Aws): "ami", + int(LiveISO): "liveiso", + int(OpenStack): "openstack", + int(Qcow2Generic): "qcow2", + int(Vmware): "vmdk", + int(RawFilesystem): "ext4-filesystem", + int(PartitionedDisk): "partitioned-disk", + int(TarArchive): "tar", + } + return mapping +} + +func (imgType imageType) toCompatString() (string, bool) { + str, exists := getCompatImageTypeMapping()[int(imgType)] + return str, exists +} + +func imageTypeFromCompatString(input string) (imageType, bool) { + for k, v := range getCompatImageTypeMapping() { + if v == input { + return imageType(k), true + } + } + return imageType(999), false +} + +func (imgType *imageType) UnmarshalJSON(data []byte) error { + mapping := getImageTypeMapping() + var stringInput string + err := json.Unmarshal(data, &stringInput) + if err != nil { + return err + } + value, exists := mapping[stringInput] + if !exists { + return errors.New(stringInput + " is not a valid image type") + } + *imgType = imageType(value) + return nil +} + +func (imgType imageType) MarshalJSON() ([]byte, error) { + mapping := getImageTypeMapping() + input := int(imgType) + for k, v := range mapping { + if v == input { + return json.Marshal(k) + } + } + return nil, fmt.Errorf("%d is not a valid image type tag", input) +} diff --git a/internal/common/types_test.go b/internal/store/json_test.go similarity index 88% rename from internal/common/types_test.go rename to internal/store/json_test.go index b9b8e2e11..985c1fd41 100644 --- a/internal/common/types_test.go +++ b/internal/store/json_test.go @@ -1,4 +1,4 @@ -package common +package store import ( "encoding/json" @@ -7,7 +7,7 @@ import ( func TestImageType_UnmarshalJSON(t *testing.T) { dict := struct { - ImageTypes []ImageType `json:"image_types"` + ImageTypes []imageType `json:"image_types"` }{} input := `{"image_types":["qcow2", "Azure"]}` err := json.Unmarshal([]byte(input), &dict)