mirror of
https://github.com/containers/podman.git
synced 2026-03-09 18:27:55 -04:00
As the title says, vendor Buildah v1.10.1 Signed-off-by: TomSweeneyRedHat <tsweeney@redhat.com>
324 lines
8.0 KiB
Go
324 lines
8.0 KiB
Go
/**
|
|
* Copyright 2014 Paul Querna
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
package ffjsoninception
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
|
|
"github.com/pquerna/ffjson/shared"
|
|
)
|
|
|
|
var validValues []string = []string{
|
|
"FFTok_left_brace",
|
|
"FFTok_left_bracket",
|
|
"FFTok_integer",
|
|
"FFTok_double",
|
|
"FFTok_string",
|
|
"FFTok_bool",
|
|
"FFTok_null",
|
|
}
|
|
|
|
func CreateUnmarshalJSON(ic *Inception, si *StructInfo) error {
|
|
out := ""
|
|
ic.OutputImports[`fflib "github.com/pquerna/ffjson/fflib/v1"`] = true
|
|
if len(si.Fields) > 0 {
|
|
ic.OutputImports[`"bytes"`] = true
|
|
}
|
|
ic.OutputImports[`"fmt"`] = true
|
|
|
|
out += tplStr(decodeTpl["header"], header{
|
|
IC: ic,
|
|
SI: si,
|
|
})
|
|
|
|
out += tplStr(decodeTpl["ujFunc"], ujFunc{
|
|
SI: si,
|
|
IC: ic,
|
|
ValidValues: validValues,
|
|
ResetFields: ic.ResetFields,
|
|
})
|
|
|
|
ic.OutputFuncs = append(ic.OutputFuncs, out)
|
|
|
|
return nil
|
|
}
|
|
|
|
func handleField(ic *Inception, name string, typ reflect.Type, ptr bool, quoted bool) string {
|
|
return handleFieldAddr(ic, name, false, typ, ptr, quoted)
|
|
}
|
|
|
|
func handleFieldAddr(ic *Inception, name string, takeAddr bool, typ reflect.Type, ptr bool, quoted bool) string {
|
|
out := fmt.Sprintf("/* handler: %s type=%v kind=%v quoted=%t*/\n", name, typ, typ.Kind(), quoted)
|
|
|
|
umlx := typ.Implements(unmarshalFasterType) || typeInInception(ic, typ, shared.MustDecoder)
|
|
umlx = umlx || reflect.PtrTo(typ).Implements(unmarshalFasterType)
|
|
|
|
umlstd := typ.Implements(unmarshalerType) || reflect.PtrTo(typ).Implements(unmarshalerType)
|
|
|
|
out += tplStr(decodeTpl["handleUnmarshaler"], handleUnmarshaler{
|
|
IC: ic,
|
|
Name: name,
|
|
Typ: typ,
|
|
Ptr: reflect.Ptr,
|
|
TakeAddr: takeAddr || ptr,
|
|
UnmarshalJSONFFLexer: umlx,
|
|
Unmarshaler: umlstd,
|
|
})
|
|
|
|
if umlx || umlstd {
|
|
return out
|
|
}
|
|
|
|
// TODO(pquerna): generic handling of token type mismatching struct type
|
|
switch typ.Kind() {
|
|
case reflect.Int,
|
|
reflect.Int8,
|
|
reflect.Int16,
|
|
reflect.Int32,
|
|
reflect.Int64:
|
|
|
|
allowed := buildTokens(quoted, "FFTok_string", "FFTok_integer", "FFTok_null")
|
|
out += getAllowTokens(typ.Name(), allowed...)
|
|
|
|
out += getNumberHandler(ic, name, takeAddr || ptr, typ, "ParseInt")
|
|
|
|
case reflect.Uint,
|
|
reflect.Uint8,
|
|
reflect.Uint16,
|
|
reflect.Uint32,
|
|
reflect.Uint64:
|
|
|
|
allowed := buildTokens(quoted, "FFTok_string", "FFTok_integer", "FFTok_null")
|
|
out += getAllowTokens(typ.Name(), allowed...)
|
|
|
|
out += getNumberHandler(ic, name, takeAddr || ptr, typ, "ParseUint")
|
|
|
|
case reflect.Float32,
|
|
reflect.Float64:
|
|
|
|
allowed := buildTokens(quoted, "FFTok_string", "FFTok_double", "FFTok_integer", "FFTok_null")
|
|
out += getAllowTokens(typ.Name(), allowed...)
|
|
|
|
out += getNumberHandler(ic, name, takeAddr || ptr, typ, "ParseFloat")
|
|
|
|
case reflect.Bool:
|
|
ic.OutputImports[`"bytes"`] = true
|
|
ic.OutputImports[`"errors"`] = true
|
|
|
|
allowed := buildTokens(quoted, "FFTok_string", "FFTok_bool", "FFTok_null")
|
|
out += getAllowTokens(typ.Name(), allowed...)
|
|
|
|
out += tplStr(decodeTpl["handleBool"], handleBool{
|
|
Name: name,
|
|
Typ: typ,
|
|
TakeAddr: takeAddr || ptr,
|
|
})
|
|
|
|
case reflect.Ptr:
|
|
out += tplStr(decodeTpl["handlePtr"], handlePtr{
|
|
IC: ic,
|
|
Name: name,
|
|
Typ: typ,
|
|
Quoted: quoted,
|
|
})
|
|
|
|
case reflect.Array,
|
|
reflect.Slice:
|
|
out += getArrayHandler(ic, name, typ, ptr)
|
|
|
|
case reflect.String:
|
|
// Is it a json.Number?
|
|
if typ.PkgPath() == "encoding/json" && typ.Name() == "Number" {
|
|
// Fall back to json package to rely on the valid number check.
|
|
// See: https://github.com/golang/go/blob/f05c3aa24d815cd3869153750c9875e35fc48a6e/src/encoding/json/decode.go#L897
|
|
ic.OutputImports[`"encoding/json"`] = true
|
|
out += tplStr(decodeTpl["handleFallback"], handleFallback{
|
|
Name: name,
|
|
Typ: typ,
|
|
Kind: typ.Kind(),
|
|
})
|
|
} else {
|
|
out += tplStr(decodeTpl["handleString"], handleString{
|
|
IC: ic,
|
|
Name: name,
|
|
Typ: typ,
|
|
TakeAddr: takeAddr || ptr,
|
|
Quoted: quoted,
|
|
})
|
|
}
|
|
case reflect.Interface:
|
|
ic.OutputImports[`"encoding/json"`] = true
|
|
out += tplStr(decodeTpl["handleFallback"], handleFallback{
|
|
Name: name,
|
|
Typ: typ,
|
|
Kind: typ.Kind(),
|
|
})
|
|
case reflect.Map:
|
|
out += tplStr(decodeTpl["handleObject"], handleObject{
|
|
IC: ic,
|
|
Name: name,
|
|
Typ: typ,
|
|
Ptr: reflect.Ptr,
|
|
TakeAddr: takeAddr || ptr,
|
|
})
|
|
default:
|
|
ic.OutputImports[`"encoding/json"`] = true
|
|
out += tplStr(decodeTpl["handleFallback"], handleFallback{
|
|
Name: name,
|
|
Typ: typ,
|
|
Kind: typ.Kind(),
|
|
})
|
|
}
|
|
|
|
return out
|
|
}
|
|
|
|
func getArrayHandler(ic *Inception, name string, typ reflect.Type, ptr bool) string {
|
|
if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 {
|
|
ic.OutputImports[`"encoding/base64"`] = true
|
|
useReflectToSet := false
|
|
if typ.Elem().Name() != "byte" {
|
|
ic.OutputImports[`"reflect"`] = true
|
|
useReflectToSet = true
|
|
}
|
|
|
|
return tplStr(decodeTpl["handleByteSlice"], handleArray{
|
|
IC: ic,
|
|
Name: name,
|
|
Typ: typ,
|
|
Ptr: reflect.Ptr,
|
|
UseReflectToSet: useReflectToSet,
|
|
})
|
|
}
|
|
|
|
if typ.Elem().Kind() == reflect.Struct && typ.Elem().Name() != "" {
|
|
goto sliceOrArray
|
|
}
|
|
|
|
if (typ.Elem().Kind() == reflect.Struct || typ.Elem().Kind() == reflect.Map) ||
|
|
typ.Elem().Kind() == reflect.Array || typ.Elem().Kind() == reflect.Slice &&
|
|
typ.Elem().Name() == "" {
|
|
ic.OutputImports[`"encoding/json"`] = true
|
|
|
|
return tplStr(decodeTpl["handleFallback"], handleFallback{
|
|
Name: name,
|
|
Typ: typ,
|
|
Kind: typ.Kind(),
|
|
})
|
|
}
|
|
|
|
sliceOrArray:
|
|
|
|
if typ.Kind() == reflect.Array {
|
|
return tplStr(decodeTpl["handleArray"], handleArray{
|
|
IC: ic,
|
|
Name: name,
|
|
Typ: typ,
|
|
IsPtr: ptr,
|
|
Ptr: reflect.Ptr,
|
|
})
|
|
}
|
|
|
|
return tplStr(decodeTpl["handleSlice"], handleArray{
|
|
IC: ic,
|
|
Name: name,
|
|
Typ: typ,
|
|
IsPtr: ptr,
|
|
Ptr: reflect.Ptr,
|
|
})
|
|
}
|
|
|
|
func getAllowTokens(name string, tokens ...string) string {
|
|
return tplStr(decodeTpl["allowTokens"], allowTokens{
|
|
Name: name,
|
|
Tokens: tokens,
|
|
})
|
|
}
|
|
|
|
func getNumberHandler(ic *Inception, name string, takeAddr bool, typ reflect.Type, parsefunc string) string {
|
|
return tplStr(decodeTpl["handlerNumeric"], handlerNumeric{
|
|
IC: ic,
|
|
Name: name,
|
|
ParseFunc: parsefunc,
|
|
TakeAddr: takeAddr,
|
|
Typ: typ,
|
|
})
|
|
}
|
|
|
|
func getNumberSize(typ reflect.Type) string {
|
|
return fmt.Sprintf("%d", typ.Bits())
|
|
}
|
|
|
|
func getType(ic *Inception, name string, typ reflect.Type) string {
|
|
s := typ.Name()
|
|
|
|
if typ.PkgPath() != "" && typ.PkgPath() != ic.PackagePath {
|
|
path := removeVendor(typ.PkgPath())
|
|
ic.OutputImports[`"`+path+`"`] = true
|
|
s = typ.String()
|
|
}
|
|
|
|
if s == "" {
|
|
return typ.String()
|
|
}
|
|
|
|
return s
|
|
}
|
|
|
|
// removeVendor removes everything before and including a '/vendor/'
|
|
// substring in the package path.
|
|
// This is needed becuase that full path can't be used in the
|
|
// import statement.
|
|
func removeVendor(path string) string {
|
|
i := strings.Index(path, "/vendor/")
|
|
if i == -1 {
|
|
return path
|
|
}
|
|
return path[i+8:]
|
|
}
|
|
|
|
func buildTokens(containsOptional bool, optional string, required ...string) []string {
|
|
if containsOptional {
|
|
return append(required, optional)
|
|
}
|
|
|
|
return required
|
|
}
|
|
|
|
func unquoteField(quoted bool) string {
|
|
// The outer quote of a string is already stripped out by
|
|
// the lexer. We need to check if the inner string is also
|
|
// quoted. If so, we will decode it as json string. If decoding
|
|
// fails, we will use the original string
|
|
if quoted {
|
|
return `
|
|
unquoted, ok := fflib.UnquoteBytes(outBuf)
|
|
if ok {
|
|
outBuf = unquoted
|
|
}
|
|
`
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func getTmpVarFor(name string) string {
|
|
return "tmp" + strings.Replace(strings.Title(name), ".", "", -1)
|
|
}
|