mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-05-20 02:17:44 +08:00

Removes gogo/protobuf from buildx and updates to a version of moby/buildkit where gogo is removed. This also changes how the proto files are generated. This is because newer versions of protobuf are more strict about name conflicts. If two files have the same name (even if they are relative paths) and are used in different protoc commands, they'll conflict in the registry. Since protobuf file generation doesn't work very well with `paths=source_relative`, this removes the `go:generate` expression and just relies on the dockerfile to perform the generation. Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
415 lines
12 KiB
Go
415 lines
12 KiB
Go
// Copyright 2018 The Go Authors. All rights reserved.
|
||
// Use of this source code is governed by a BSD-style
|
||
// license that can be found in the LICENSE file.
|
||
|
||
// Package descfmt provides functionality to format descriptors.
|
||
package descfmt
|
||
|
||
import (
|
||
"fmt"
|
||
"io"
|
||
"reflect"
|
||
"strconv"
|
||
"strings"
|
||
|
||
"google.golang.org/protobuf/internal/detrand"
|
||
"google.golang.org/protobuf/internal/pragma"
|
||
"google.golang.org/protobuf/reflect/protoreflect"
|
||
)
|
||
|
||
type list interface {
|
||
Len() int
|
||
pragma.DoNotImplement
|
||
}
|
||
|
||
func FormatList(s fmt.State, r rune, vs list) {
|
||
io.WriteString(s, formatListOpt(vs, true, r == 'v' && (s.Flag('+') || s.Flag('#'))))
|
||
}
|
||
func formatListOpt(vs list, isRoot, allowMulti bool) string {
|
||
start, end := "[", "]"
|
||
if isRoot {
|
||
var name string
|
||
switch vs.(type) {
|
||
case protoreflect.Names:
|
||
name = "Names"
|
||
case protoreflect.FieldNumbers:
|
||
name = "FieldNumbers"
|
||
case protoreflect.FieldRanges:
|
||
name = "FieldRanges"
|
||
case protoreflect.EnumRanges:
|
||
name = "EnumRanges"
|
||
case protoreflect.FileImports:
|
||
name = "FileImports"
|
||
case protoreflect.Descriptor:
|
||
name = reflect.ValueOf(vs).MethodByName("Get").Type().Out(0).Name() + "s"
|
||
default:
|
||
name = reflect.ValueOf(vs).Elem().Type().Name()
|
||
}
|
||
start, end = name+"{", "}"
|
||
}
|
||
|
||
var ss []string
|
||
switch vs := vs.(type) {
|
||
case protoreflect.Names:
|
||
for i := 0; i < vs.Len(); i++ {
|
||
ss = append(ss, fmt.Sprint(vs.Get(i)))
|
||
}
|
||
return start + joinStrings(ss, false) + end
|
||
case protoreflect.FieldNumbers:
|
||
for i := 0; i < vs.Len(); i++ {
|
||
ss = append(ss, fmt.Sprint(vs.Get(i)))
|
||
}
|
||
return start + joinStrings(ss, false) + end
|
||
case protoreflect.FieldRanges:
|
||
for i := 0; i < vs.Len(); i++ {
|
||
r := vs.Get(i)
|
||
if r[0]+1 == r[1] {
|
||
ss = append(ss, fmt.Sprintf("%d", r[0]))
|
||
} else {
|
||
ss = append(ss, fmt.Sprintf("%d:%d", r[0], r[1])) // enum ranges are end exclusive
|
||
}
|
||
}
|
||
return start + joinStrings(ss, false) + end
|
||
case protoreflect.EnumRanges:
|
||
for i := 0; i < vs.Len(); i++ {
|
||
r := vs.Get(i)
|
||
if r[0] == r[1] {
|
||
ss = append(ss, fmt.Sprintf("%d", r[0]))
|
||
} else {
|
||
ss = append(ss, fmt.Sprintf("%d:%d", r[0], int64(r[1])+1)) // enum ranges are end inclusive
|
||
}
|
||
}
|
||
return start + joinStrings(ss, false) + end
|
||
case protoreflect.FileImports:
|
||
for i := 0; i < vs.Len(); i++ {
|
||
var rs records
|
||
rv := reflect.ValueOf(vs.Get(i))
|
||
rs.Append(rv, []methodAndName{
|
||
{rv.MethodByName("Path"), "Path"},
|
||
{rv.MethodByName("Package"), "Package"},
|
||
{rv.MethodByName("IsPublic"), "IsPublic"},
|
||
{rv.MethodByName("IsWeak"), "IsWeak"},
|
||
}...)
|
||
ss = append(ss, "{"+rs.Join()+"}")
|
||
}
|
||
return start + joinStrings(ss, allowMulti) + end
|
||
default:
|
||
_, isEnumValue := vs.(protoreflect.EnumValueDescriptors)
|
||
for i := 0; i < vs.Len(); i++ {
|
||
m := reflect.ValueOf(vs).MethodByName("Get")
|
||
v := m.Call([]reflect.Value{reflect.ValueOf(i)})[0].Interface()
|
||
ss = append(ss, formatDescOpt(v.(protoreflect.Descriptor), false, allowMulti && !isEnumValue, nil))
|
||
}
|
||
return start + joinStrings(ss, allowMulti && isEnumValue) + end
|
||
}
|
||
}
|
||
|
||
type methodAndName struct {
|
||
method reflect.Value
|
||
name string
|
||
}
|
||
|
||
func FormatDesc(s fmt.State, r rune, t protoreflect.Descriptor) {
|
||
io.WriteString(s, formatDescOpt(t, true, r == 'v' && (s.Flag('+') || s.Flag('#')), nil))
|
||
}
|
||
|
||
func InternalFormatDescOptForTesting(t protoreflect.Descriptor, isRoot, allowMulti bool, record func(string)) string {
|
||
return formatDescOpt(t, isRoot, allowMulti, record)
|
||
}
|
||
|
||
func formatDescOpt(t protoreflect.Descriptor, isRoot, allowMulti bool, record func(string)) string {
|
||
rv := reflect.ValueOf(t)
|
||
rt := rv.MethodByName("ProtoType").Type().In(0)
|
||
|
||
start, end := "{", "}"
|
||
if isRoot {
|
||
start = rt.Name() + "{"
|
||
}
|
||
|
||
_, isFile := t.(protoreflect.FileDescriptor)
|
||
rs := records{
|
||
allowMulti: allowMulti,
|
||
record: record,
|
||
}
|
||
if t.IsPlaceholder() {
|
||
if isFile {
|
||
rs.Append(rv, []methodAndName{
|
||
{rv.MethodByName("Path"), "Path"},
|
||
{rv.MethodByName("Package"), "Package"},
|
||
{rv.MethodByName("IsPlaceholder"), "IsPlaceholder"},
|
||
}...)
|
||
} else {
|
||
rs.Append(rv, []methodAndName{
|
||
{rv.MethodByName("FullName"), "FullName"},
|
||
{rv.MethodByName("IsPlaceholder"), "IsPlaceholder"},
|
||
}...)
|
||
}
|
||
} else {
|
||
switch {
|
||
case isFile:
|
||
rs.Append(rv, methodAndName{rv.MethodByName("Syntax"), "Syntax"})
|
||
case isRoot:
|
||
rs.Append(rv, []methodAndName{
|
||
{rv.MethodByName("Syntax"), "Syntax"},
|
||
{rv.MethodByName("FullName"), "FullName"},
|
||
}...)
|
||
default:
|
||
rs.Append(rv, methodAndName{rv.MethodByName("Name"), "Name"})
|
||
}
|
||
switch t := t.(type) {
|
||
case protoreflect.FieldDescriptor:
|
||
accessors := []methodAndName{
|
||
{rv.MethodByName("Number"), "Number"},
|
||
{rv.MethodByName("Cardinality"), "Cardinality"},
|
||
{rv.MethodByName("Kind"), "Kind"},
|
||
{rv.MethodByName("HasJSONName"), "HasJSONName"},
|
||
{rv.MethodByName("JSONName"), "JSONName"},
|
||
{rv.MethodByName("HasPresence"), "HasPresence"},
|
||
{rv.MethodByName("IsExtension"), "IsExtension"},
|
||
{rv.MethodByName("IsPacked"), "IsPacked"},
|
||
{rv.MethodByName("IsWeak"), "IsWeak"},
|
||
{rv.MethodByName("IsList"), "IsList"},
|
||
{rv.MethodByName("IsMap"), "IsMap"},
|
||
{rv.MethodByName("MapKey"), "MapKey"},
|
||
{rv.MethodByName("MapValue"), "MapValue"},
|
||
{rv.MethodByName("HasDefault"), "HasDefault"},
|
||
{rv.MethodByName("Default"), "Default"},
|
||
{rv.MethodByName("ContainingOneof"), "ContainingOneof"},
|
||
{rv.MethodByName("ContainingMessage"), "ContainingMessage"},
|
||
{rv.MethodByName("Message"), "Message"},
|
||
{rv.MethodByName("Enum"), "Enum"},
|
||
}
|
||
for _, s := range accessors {
|
||
switch s.name {
|
||
case "MapKey":
|
||
if k := t.MapKey(); k != nil {
|
||
rs.recs = append(rs.recs, [2]string{"MapKey", k.Kind().String()})
|
||
}
|
||
case "MapValue":
|
||
if v := t.MapValue(); v != nil {
|
||
switch v.Kind() {
|
||
case protoreflect.EnumKind:
|
||
rs.AppendRecs("MapValue", [2]string{"MapValue", string(v.Enum().FullName())})
|
||
case protoreflect.MessageKind, protoreflect.GroupKind:
|
||
rs.AppendRecs("MapValue", [2]string{"MapValue", string(v.Message().FullName())})
|
||
default:
|
||
rs.AppendRecs("MapValue", [2]string{"MapValue", v.Kind().String()})
|
||
}
|
||
}
|
||
case "ContainingOneof":
|
||
if od := t.ContainingOneof(); od != nil {
|
||
rs.AppendRecs("ContainingOneof", [2]string{"Oneof", string(od.Name())})
|
||
}
|
||
case "ContainingMessage":
|
||
if t.IsExtension() {
|
||
rs.AppendRecs("ContainingMessage", [2]string{"Extendee", string(t.ContainingMessage().FullName())})
|
||
}
|
||
case "Message":
|
||
if !t.IsMap() {
|
||
rs.Append(rv, s)
|
||
}
|
||
default:
|
||
rs.Append(rv, s)
|
||
}
|
||
}
|
||
case protoreflect.OneofDescriptor:
|
||
var ss []string
|
||
fs := t.Fields()
|
||
for i := 0; i < fs.Len(); i++ {
|
||
ss = append(ss, string(fs.Get(i).Name()))
|
||
}
|
||
if len(ss) > 0 {
|
||
rs.AppendRecs("Fields", [2]string{"Fields", "[" + joinStrings(ss, false) + "]"})
|
||
}
|
||
|
||
case protoreflect.FileDescriptor:
|
||
rs.Append(rv, []methodAndName{
|
||
{rv.MethodByName("Path"), "Path"},
|
||
{rv.MethodByName("Package"), "Package"},
|
||
{rv.MethodByName("Imports"), "Imports"},
|
||
{rv.MethodByName("Messages"), "Messages"},
|
||
{rv.MethodByName("Enums"), "Enums"},
|
||
{rv.MethodByName("Extensions"), "Extensions"},
|
||
{rv.MethodByName("Services"), "Services"},
|
||
}...)
|
||
|
||
case protoreflect.MessageDescriptor:
|
||
rs.Append(rv, []methodAndName{
|
||
{rv.MethodByName("IsMapEntry"), "IsMapEntry"},
|
||
{rv.MethodByName("Fields"), "Fields"},
|
||
{rv.MethodByName("Oneofs"), "Oneofs"},
|
||
{rv.MethodByName("ReservedNames"), "ReservedNames"},
|
||
{rv.MethodByName("ReservedRanges"), "ReservedRanges"},
|
||
{rv.MethodByName("RequiredNumbers"), "RequiredNumbers"},
|
||
{rv.MethodByName("ExtensionRanges"), "ExtensionRanges"},
|
||
{rv.MethodByName("Messages"), "Messages"},
|
||
{rv.MethodByName("Enums"), "Enums"},
|
||
{rv.MethodByName("Extensions"), "Extensions"},
|
||
}...)
|
||
|
||
case protoreflect.EnumDescriptor:
|
||
rs.Append(rv, []methodAndName{
|
||
{rv.MethodByName("Values"), "Values"},
|
||
{rv.MethodByName("ReservedNames"), "ReservedNames"},
|
||
{rv.MethodByName("ReservedRanges"), "ReservedRanges"},
|
||
{rv.MethodByName("IsClosed"), "IsClosed"},
|
||
}...)
|
||
|
||
case protoreflect.EnumValueDescriptor:
|
||
rs.Append(rv, []methodAndName{
|
||
{rv.MethodByName("Number"), "Number"},
|
||
}...)
|
||
|
||
case protoreflect.ServiceDescriptor:
|
||
rs.Append(rv, []methodAndName{
|
||
{rv.MethodByName("Methods"), "Methods"},
|
||
}...)
|
||
|
||
case protoreflect.MethodDescriptor:
|
||
rs.Append(rv, []methodAndName{
|
||
{rv.MethodByName("Input"), "Input"},
|
||
{rv.MethodByName("Output"), "Output"},
|
||
{rv.MethodByName("IsStreamingClient"), "IsStreamingClient"},
|
||
{rv.MethodByName("IsStreamingServer"), "IsStreamingServer"},
|
||
}...)
|
||
}
|
||
if m := rv.MethodByName("GoType"); m.IsValid() {
|
||
rs.Append(rv, methodAndName{m, "GoType"})
|
||
}
|
||
}
|
||
return start + rs.Join() + end
|
||
}
|
||
|
||
type records struct {
|
||
recs [][2]string
|
||
allowMulti bool
|
||
|
||
// record is a function that will be called for every Append() or
|
||
// AppendRecs() call, to be used for testing with the
|
||
// InternalFormatDescOptForTesting function.
|
||
record func(string)
|
||
}
|
||
|
||
func (rs *records) AppendRecs(fieldName string, newRecs [2]string) {
|
||
if rs.record != nil {
|
||
rs.record(fieldName)
|
||
}
|
||
rs.recs = append(rs.recs, newRecs)
|
||
}
|
||
|
||
func (rs *records) Append(v reflect.Value, accessors ...methodAndName) {
|
||
for _, a := range accessors {
|
||
if rs.record != nil {
|
||
rs.record(a.name)
|
||
}
|
||
var rv reflect.Value
|
||
if a.method.IsValid() {
|
||
rv = a.method.Call(nil)[0]
|
||
}
|
||
if v.Kind() == reflect.Struct && !rv.IsValid() {
|
||
rv = v.FieldByName(a.name)
|
||
}
|
||
if !rv.IsValid() {
|
||
panic(fmt.Sprintf("unknown accessor: %v.%s", v.Type(), a.name))
|
||
}
|
||
if _, ok := rv.Interface().(protoreflect.Value); ok {
|
||
rv = rv.MethodByName("Interface").Call(nil)[0]
|
||
if !rv.IsNil() {
|
||
rv = rv.Elem()
|
||
}
|
||
}
|
||
|
||
// Ignore zero values.
|
||
var isZero bool
|
||
switch rv.Kind() {
|
||
case reflect.Interface, reflect.Slice:
|
||
isZero = rv.IsNil()
|
||
case reflect.Bool:
|
||
isZero = rv.Bool() == false
|
||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||
isZero = rv.Int() == 0
|
||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||
isZero = rv.Uint() == 0
|
||
case reflect.String:
|
||
isZero = rv.String() == ""
|
||
}
|
||
if n, ok := rv.Interface().(list); ok {
|
||
isZero = n.Len() == 0
|
||
}
|
||
if isZero {
|
||
continue
|
||
}
|
||
|
||
// Format the value.
|
||
var s string
|
||
v := rv.Interface()
|
||
switch v := v.(type) {
|
||
case list:
|
||
s = formatListOpt(v, false, rs.allowMulti)
|
||
case protoreflect.FieldDescriptor, protoreflect.OneofDescriptor, protoreflect.EnumValueDescriptor, protoreflect.MethodDescriptor:
|
||
s = string(v.(protoreflect.Descriptor).Name())
|
||
case protoreflect.Descriptor:
|
||
s = string(v.FullName())
|
||
case string:
|
||
s = strconv.Quote(v)
|
||
case []byte:
|
||
s = fmt.Sprintf("%q", v)
|
||
default:
|
||
s = fmt.Sprint(v)
|
||
}
|
||
rs.recs = append(rs.recs, [2]string{a.name, s})
|
||
}
|
||
}
|
||
|
||
func (rs *records) Join() string {
|
||
var ss []string
|
||
|
||
// In single line mode, simply join all records with commas.
|
||
if !rs.allowMulti {
|
||
for _, r := range rs.recs {
|
||
ss = append(ss, r[0]+formatColon(0)+r[1])
|
||
}
|
||
return joinStrings(ss, false)
|
||
}
|
||
|
||
// In allowMulti line mode, align single line records for more readable output.
|
||
var maxLen int
|
||
flush := func(i int) {
|
||
for _, r := range rs.recs[len(ss):i] {
|
||
ss = append(ss, r[0]+formatColon(maxLen-len(r[0]))+r[1])
|
||
}
|
||
maxLen = 0
|
||
}
|
||
for i, r := range rs.recs {
|
||
if isMulti := strings.Contains(r[1], "\n"); isMulti {
|
||
flush(i)
|
||
ss = append(ss, r[0]+formatColon(0)+strings.Join(strings.Split(r[1], "\n"), "\n\t"))
|
||
} else if maxLen < len(r[0]) {
|
||
maxLen = len(r[0])
|
||
}
|
||
}
|
||
flush(len(rs.recs))
|
||
return joinStrings(ss, true)
|
||
}
|
||
|
||
func formatColon(padding int) string {
|
||
// Deliberately introduce instability into the debug output to
|
||
// discourage users from performing string comparisons.
|
||
// This provides us flexibility to change the output in the future.
|
||
if detrand.Bool() {
|
||
return ":" + strings.Repeat(" ", 1+padding) // use non-breaking spaces (U+00a0)
|
||
} else {
|
||
return ":" + strings.Repeat(" ", 1+padding) // use regular spaces (U+0020)
|
||
}
|
||
}
|
||
|
||
func joinStrings(ss []string, isMulti bool) string {
|
||
if len(ss) == 0 {
|
||
return ""
|
||
}
|
||
if isMulti {
|
||
return "\n\t" + strings.Join(ss, "\n\t") + "\n"
|
||
}
|
||
return strings.Join(ss, ", ")
|
||
}
|