mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 18:13:42 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			186 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			186 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2014 The Kubernetes Authors.
 | 
						|
 | 
						|
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 intstr
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"math"
 | 
						|
	"runtime/debug"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"github.com/google/gofuzz"
 | 
						|
	"k8s.io/klog/v2"
 | 
						|
)
 | 
						|
 | 
						|
// IntOrString is a type that can hold an int32 or a string.  When used in
 | 
						|
// JSON or YAML marshalling and unmarshalling, it produces or consumes the
 | 
						|
// inner type.  This allows you to have, for example, a JSON field that can
 | 
						|
// accept a name or number.
 | 
						|
// TODO: Rename to Int32OrString
 | 
						|
//
 | 
						|
// +protobuf=true
 | 
						|
// +protobuf.options.(gogoproto.goproto_stringer)=false
 | 
						|
// +k8s:openapi-gen=true
 | 
						|
type IntOrString struct {
 | 
						|
	Type   Type   `protobuf:"varint,1,opt,name=type,casttype=Type"`
 | 
						|
	IntVal int32  `protobuf:"varint,2,opt,name=intVal"`
 | 
						|
	StrVal string `protobuf:"bytes,3,opt,name=strVal"`
 | 
						|
}
 | 
						|
 | 
						|
// Type represents the stored type of IntOrString.
 | 
						|
type Type int64
 | 
						|
 | 
						|
const (
 | 
						|
	Int    Type = iota // The IntOrString holds an int.
 | 
						|
	String             // The IntOrString holds a string.
 | 
						|
)
 | 
						|
 | 
						|
// FromInt creates an IntOrString object with an int32 value. It is
 | 
						|
// your responsibility not to call this method with a value greater
 | 
						|
// than int32.
 | 
						|
// TODO: convert to (val int32)
 | 
						|
func FromInt(val int) IntOrString {
 | 
						|
	if val > math.MaxInt32 || val < math.MinInt32 {
 | 
						|
		klog.Errorf("value: %d overflows int32\n%s\n", val, debug.Stack())
 | 
						|
	}
 | 
						|
	return IntOrString{Type: Int, IntVal: int32(val)}
 | 
						|
}
 | 
						|
 | 
						|
// FromString creates an IntOrString object with a string value.
 | 
						|
func FromString(val string) IntOrString {
 | 
						|
	return IntOrString{Type: String, StrVal: val}
 | 
						|
}
 | 
						|
 | 
						|
// Parse the given string and try to convert it to an integer before
 | 
						|
// setting it as a string value.
 | 
						|
func Parse(val string) IntOrString {
 | 
						|
	i, err := strconv.Atoi(val)
 | 
						|
	if err != nil {
 | 
						|
		return FromString(val)
 | 
						|
	}
 | 
						|
	return FromInt(i)
 | 
						|
}
 | 
						|
 | 
						|
// UnmarshalJSON implements the json.Unmarshaller interface.
 | 
						|
func (intstr *IntOrString) UnmarshalJSON(value []byte) error {
 | 
						|
	if value[0] == '"' {
 | 
						|
		intstr.Type = String
 | 
						|
		return json.Unmarshal(value, &intstr.StrVal)
 | 
						|
	}
 | 
						|
	intstr.Type = Int
 | 
						|
	return json.Unmarshal(value, &intstr.IntVal)
 | 
						|
}
 | 
						|
 | 
						|
// String returns the string value, or the Itoa of the int value.
 | 
						|
func (intstr *IntOrString) String() string {
 | 
						|
	if intstr.Type == String {
 | 
						|
		return intstr.StrVal
 | 
						|
	}
 | 
						|
	return strconv.Itoa(intstr.IntValue())
 | 
						|
}
 | 
						|
 | 
						|
// IntValue returns the IntVal if type Int, or if
 | 
						|
// it is a String, will attempt a conversion to int,
 | 
						|
// returning 0 if a parsing error occurs.
 | 
						|
func (intstr *IntOrString) IntValue() int {
 | 
						|
	if intstr.Type == String {
 | 
						|
		i, _ := strconv.Atoi(intstr.StrVal)
 | 
						|
		return i
 | 
						|
	}
 | 
						|
	return int(intstr.IntVal)
 | 
						|
}
 | 
						|
 | 
						|
// MarshalJSON implements the json.Marshaller interface.
 | 
						|
func (intstr IntOrString) MarshalJSON() ([]byte, error) {
 | 
						|
	switch intstr.Type {
 | 
						|
	case Int:
 | 
						|
		return json.Marshal(intstr.IntVal)
 | 
						|
	case String:
 | 
						|
		return json.Marshal(intstr.StrVal)
 | 
						|
	default:
 | 
						|
		return []byte{}, fmt.Errorf("impossible IntOrString.Type")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// OpenAPISchemaType is used by the kube-openapi generator when constructing
 | 
						|
// the OpenAPI spec of this type.
 | 
						|
//
 | 
						|
// See: https://github.com/kubernetes/kube-openapi/tree/master/pkg/generators
 | 
						|
func (IntOrString) OpenAPISchemaType() []string { return []string{"string"} }
 | 
						|
 | 
						|
// OpenAPISchemaFormat is used by the kube-openapi generator when constructing
 | 
						|
// the OpenAPI spec of this type.
 | 
						|
func (IntOrString) OpenAPISchemaFormat() string { return "int-or-string" }
 | 
						|
 | 
						|
func (intstr *IntOrString) Fuzz(c fuzz.Continue) {
 | 
						|
	if intstr == nil {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	if c.RandBool() {
 | 
						|
		intstr.Type = Int
 | 
						|
		c.Fuzz(&intstr.IntVal)
 | 
						|
		intstr.StrVal = ""
 | 
						|
	} else {
 | 
						|
		intstr.Type = String
 | 
						|
		intstr.IntVal = 0
 | 
						|
		c.Fuzz(&intstr.StrVal)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func ValueOrDefault(intOrPercent *IntOrString, defaultValue IntOrString) *IntOrString {
 | 
						|
	if intOrPercent == nil {
 | 
						|
		return &defaultValue
 | 
						|
	}
 | 
						|
	return intOrPercent
 | 
						|
}
 | 
						|
 | 
						|
func GetValueFromIntOrPercent(intOrPercent *IntOrString, total int, roundUp bool) (int, error) {
 | 
						|
	if intOrPercent == nil {
 | 
						|
		return 0, errors.New("nil value for IntOrString")
 | 
						|
	}
 | 
						|
	value, isPercent, err := getIntOrPercentValue(intOrPercent)
 | 
						|
	if err != nil {
 | 
						|
		return 0, fmt.Errorf("invalid value for IntOrString: %v", err)
 | 
						|
	}
 | 
						|
	if isPercent {
 | 
						|
		if roundUp {
 | 
						|
			value = int(math.Ceil(float64(value) * (float64(total)) / 100))
 | 
						|
		} else {
 | 
						|
			value = int(math.Floor(float64(value) * (float64(total)) / 100))
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return value, nil
 | 
						|
}
 | 
						|
 | 
						|
func getIntOrPercentValue(intOrStr *IntOrString) (int, bool, error) {
 | 
						|
	switch intOrStr.Type {
 | 
						|
	case Int:
 | 
						|
		return intOrStr.IntValue(), false, nil
 | 
						|
	case String:
 | 
						|
		s := strings.Replace(intOrStr.StrVal, "%", "", -1)
 | 
						|
		v, err := strconv.Atoi(s)
 | 
						|
		if err != nil {
 | 
						|
			return 0, false, fmt.Errorf("invalid value %q: %v", intOrStr.StrVal, err)
 | 
						|
		}
 | 
						|
		return int(v), true, nil
 | 
						|
	}
 | 
						|
	return 0, false, fmt.Errorf("invalid type: neither int nor percentage")
 | 
						|
}
 |