diff --git a/helpers/listhelpers.go b/helpers/listhelpers.go index 61e7b52..a9a8030 100644 --- a/helpers/listhelpers.go +++ b/helpers/listhelpers.go @@ -8,3 +8,81 @@ func SliceContains(list []string, a string) bool { } return false } + +func IsPlainMap(mp map[string]interface{}) bool { + // First we check is it more complex. If so - it is worth investigating and we should stop checking. + for _, m := range mp { + if _, ok := m.(map[string]interface{}); ok { + return false + } else if _, ok := m.([]interface{}); ok { + return false + } + } + // Ok, it isn't. So is there any ? + if mapContainsNil(mp) { // Yes, it is - so it is a map worth investigating. This is not the map we're looking for. + return false + } + + return true // There is no and no complexity - it is a plain, non-nil map. +} + +func IsPlainSlice(slc []interface{}) bool { + // The same flow as in `isPlainMap` function. + for _, s := range slc { + if _, ok := s.(map[string]interface{}); ok { + return false + } else if _, ok := s.([]interface{}); ok { + return false + } + } + + if sliceContainsNil(slc) { + return false + } + + return true +} + +func Discard(slice []interface{}, n interface{}) []interface{} { + result := []interface{}{} + for _, s := range slice { + if s != n { + result = append(result, s) + } + } + return result +} + +// We check if the element is non-string, non-float64, non-boolean. Then it is another node or . There is no other option. +func IsNonStringFloatBool(v interface{}) bool { + var isString, isFloat, isBool bool + if _, ok := v.(string); ok { + isString = true + } else if _, ok := v.(float64); ok { + isFloat = true + } else if _, ok := v.(bool); ok { + isBool = true + } + if !isString && !isFloat && !isBool { + return true + } + return false +} + +func mapContainsNil(mp map[string]interface{}) bool { + for _, m := range mp { + if m == nil { + return true + } + } + return false +} + +func sliceContainsNil(slice []interface{}) bool { + for _, s := range slice { + if s == nil { + return true + } + } + return false +} diff --git a/offlinevalidator/offlinevalidator.go b/offlinevalidator/offlinevalidator.go index 49976bc..5502688 100644 --- a/offlinevalidator/offlinevalidator.go +++ b/offlinevalidator/offlinevalidator.go @@ -26,6 +26,7 @@ import ( "strings" "errors" + "github.com/Appliscale/perun/context" "github.com/Appliscale/perun/helpers" "github.com/Appliscale/perun/logger" @@ -351,118 +352,6 @@ func getNilResources(resources map[string]template.Resource) []string { return list } -func sliceContains(slice []string, match string) bool { - for _, s := range slice { - if s == match { - return true - } - } - return false -} - -func mapContainsNil(mp map[string]interface{}) bool { - for _, m := range mp { - if m == nil { - return true - } - } - return false -} - -func sliceContainsNil(slice []interface{}) bool { - for _, s := range slice { - if s == nil { - return true - } - } - return false -} - -// We check if the element is non-string, non-float64, non-boolean. Then it is another node or . There is no other option. -func isNonStringFloatBool(v interface{}) bool { - var isString, isFloat, isBool bool - if _, ok := v.(string); ok { - isString = true - } else if _, ok := v.(float64); ok { - isFloat = true - } else if _, ok := v.(bool); ok { - isBool = true - } - if !isString && !isFloat && !isBool { - return true - } - return false -} - -func isPlainMap(mp map[string]interface{}) bool { - // First we check is it more complex. If so - it is worth investigating and we should stop checking. - for _, m := range mp { - if _, ok := m.(map[string]interface{}); ok { - return false - } else if _, ok := m.([]interface{}); ok { - return false - } - } - // Ok, it isn't. So is there any ? - if mapContainsNil(mp) { // Yes, it is - so it is a map worth investigating. This is not the map we're looking for. - return false - } - - return true // There is no and no complexity - it is a plain, non-nil map. -} - -func isPlainSlice(slc []interface{}) bool { - // The same flow as in `isPlainMap` function. - for _, s := range slc { - if _, ok := s.(map[string]interface{}); ok { - return false - } else if _, ok := s.([]interface{}); ok { - return false - } - } - - if sliceContainsNil(slc) { - return false - } - - return true -} - -func discard(slice []interface{}, n interface{}) []interface{} { - result := []interface{}{} - for _, s := range slice { - if s != n { - result = append(result, s) - } - } - return result -} - -func lineAndCharacter(input string, offset int) (line int, character int) { - lf := rune(0x0A) - - if offset > len(input) || offset < 0 { - return 0, 0 - } - - line = 1 - - for i, b := range input { - if b == lf { - if i < offset { - line++ - character = 0 - } - } else { - character++ - } - if i == offset { - break - } - } - return line, character -} - func checkWhereIsNil(n interface{}, v interface{}, baseLevel string, logger *logger.Logger, fullPath []interface{}, dsc *interface{}) { if v == nil { // Value we encountered is nil - this is the end of investigation. where := "" @@ -479,26 +368,26 @@ func checkWhereIsNil(n interface{}, v interface{}, baseLevel string, logger *log } logger.Warning(baseLevel + ": " + where + " <--- is nil.") } else if mp, ok := v.(map[string]interface{}); ok { // Value we encountered is a map. - if isPlainMap(mp) { // Check is it plain, non-nil map. + if helpers.IsPlainMap(mp) { // Check is it plain, non-nil map. // It is - we shouldn't dive into. *dsc = n // The name is stored in the `discarded` container as the name of the blind alley. } else { for kmp, vmp := range mp { - if isNonStringFloatBool(vmp) { + if helpers.IsNonStringFloatBool(vmp) { fullPath = append(fullPath, kmp) - fullPath = discard(fullPath, *dsc) // If the output path would be different, it seems that we've encountered some node which is not on the way to the . It will be discarded from the path. Otherwise the paths are the same and we hit the point. + fullPath = helpers.Discard(fullPath, *dsc) // If the output path would be different, it seems that we've encountered some node which is not on the way to the . It will be discarded from the path. Otherwise the paths are the same and we hit the point. checkWhereIsNil(kmp, vmp, baseLevel, logger, fullPath, dsc) } } } } else if slc, ok := v.([]interface{}); ok { // The same flow as above. - if isPlainSlice(slc) { + if helpers.IsPlainSlice(slc) { *dsc = n } else { for islc, vslc := range slc { - if isNonStringFloatBool(vslc) { + if helpers.IsNonStringFloatBool(vslc) { fullPath = append(fullPath, islc) - fullPath = discard(fullPath, *dsc) + fullPath = helpers.Discard(fullPath, *dsc) checkWhereIsNil(islc, vslc, baseLevel, logger, fullPath, dsc) } }