common: extend common types with helper functions

It is very common that a string is required in the rest of our code and
also for user input/output. These helper functions will make this easy.
This commit is contained in:
Martin Sehnoutka 2020-02-10 09:20:53 +01:00 committed by Ondřej Budai
parent 7f66147888
commit cffa74f0a1

View file

@ -11,10 +11,14 @@ type CustomJsonConversionError struct {
reason string
}
// Error returns the error as a string
func (err *CustomJsonConversionError) 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)
@ -28,6 +32,7 @@ func unmarshalHelper(data []byte, jsonError, typeConversionError string, mapping
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 {
@ -37,14 +42,16 @@ func marshalHelper(input int, mapping map[string]int, errorMessage string) ([]by
return nil, &CustomJsonConversionError{fmt.Sprintf("%d %s", input, errorMessage)}
}
// See unmarshalHelper for introduction. This helper can create a list of possible values of a single type.
func listHelper(mapping map[string]int) []string {
ret := make([]string, 0)
for k,_ := range mapping {
for k, _ := range mapping {
ret = append(ret, k)
}
return ret
}
// See unmarshalHelper for introduction. With this helper one can make sure a value exists in a set of existing values.
func existsHelper(mapping map[string]int, testedValue string) bool {
for k, _ := range mapping {
if k == testedValue {
@ -54,6 +61,22 @@ func existsHelper(mapping map[string]int, testedValue string) bool {
return false
}
// 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
}
// See unmarshalHelper for introduction. Converts between string and TypeAlias(int)
func fromStringHelper(mapping map[string]int, stringInput string) (int, bool) {
value, exists := mapping[stringInput]
return value, exists
}
// Architecture represents one of the supported CPU architectures available for images
// produced by osbuild-composer. It is represented as an integer because if it
// was a string it would unmarshal from JSON just fine even in case that the architecture
@ -113,6 +136,10 @@ func (arch Architecture) MarshalJSON() ([]byte, error) {
return marshalHelper(int(arch), getArchMapping(), "is not a valid architecture tag")
}
func (arch Architecture) ToString() (string, bool) {
return toStringHelper(getDistributionMapping(), int(arch))
}
type ImageType int
// NOTE: If you want to add more constants here, don't forget to add a mapping below
@ -126,21 +153,46 @@ const (
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{
"Alibaba": int(Alibaba),
"Azure": int(Azure),
"AWS": int(Aws),
"Google Cloud": int(GoogleCloud),
"Hyper-V": int(HyperV),
"LiveISO": int(LiveISO),
"OpenStack": int(OpenStack),
"qcow2": int(Qcow2Generic),
"VMWare": int(Vmware),
"Alibaba": int(Alibaba),
"Azure": int(Azure),
"AWS": int(Aws),
"Google-Cloud": int(GoogleCloud),
"Hyper-V": int(HyperV),
"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(Alibaba): "ami",
int(Azure): "vhd",
int(Aws): "ami",
int(GoogleCloud): "ami",
int(HyperV): "vhd",
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
}
@ -158,6 +210,24 @@ 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))
}
type Distribution int
// NOTE: If you want to add more constants here, don't forget to add a mapping below
@ -178,7 +248,6 @@ func getDistributionMapping() map[string]int {
return mapping
}
func ListDistributions() []string {
return listHelper(getDistributionMapping())
}
@ -200,6 +269,15 @@ func (distro Distribution) MarshalJSON() ([]byte, error) {
return marshalHelper(int(distro), getDistributionMapping(), "is not a valid distribution tag")
}
func (distro Distribution) ToString() (string, bool) {
return toStringHelper(getDistributionMapping(), int(distro))
}
func DistributionFromString(distro string) (Distribution, bool) {
tag, exists := fromStringHelper(getDistributionMapping(), distro)
return Distribution(tag), exists
}
type UploadTarget int
// NOTE: If you want to add more constants here, don't forget to add a mapping below