mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-10-31 16:13:45 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			163 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			163 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package apicaps
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"sort"
 | |
| 	"strings"
 | |
| 
 | |
| 	pb "github.com/moby/buildkit/util/apicaps/pb"
 | |
| 	"github.com/pkg/errors"
 | |
| )
 | |
| 
 | |
| type PBCap = pb.APICap
 | |
| 
 | |
| // ExportedProduct is the name of the product using this package.
 | |
| // Users vendoring this library may override it to provide better versioning hints
 | |
| // for their users (or set it with a flag to buildkitd).
 | |
| var ExportedProduct string
 | |
| 
 | |
| // CapStatus defines the stability properties of a capability
 | |
| type CapStatus int
 | |
| 
 | |
| const (
 | |
| 	// CapStatusStable refers to a capability that should never be changed in
 | |
| 	// backwards incompatible manner unless there is a serious security issue.
 | |
| 	CapStatusStable CapStatus = iota
 | |
| 	// CapStatusExperimental refers to a capability that may be removed in the future.
 | |
| 	// If incompatible changes are made the previous ID is disabled and new is added.
 | |
| 	CapStatusExperimental
 | |
| 	// CapStatusPrerelease is same as CapStatusExperimental that can be used for new
 | |
| 	// features before they move to stable.
 | |
| 	CapStatusPrerelease
 | |
| )
 | |
| 
 | |
| // CapID is type for capability identifier
 | |
| type CapID string
 | |
| 
 | |
| // Cap describes an API feature
 | |
| type Cap struct {
 | |
| 	ID                  CapID
 | |
| 	Name                string // readable name, may contain spaces but keep in one sentence
 | |
| 	Status              CapStatus
 | |
| 	Enabled             bool
 | |
| 	Deprecated          bool
 | |
| 	SupportedHint       map[string]string
 | |
| 	DisabledReason      string
 | |
| 	DisabledReasonMsg   string
 | |
| 	DisabledAlternative string
 | |
| }
 | |
| 
 | |
| // CapList is a collection of capability definitions
 | |
| type CapList struct {
 | |
| 	m map[CapID]Cap
 | |
| }
 | |
| 
 | |
| // Init initializes definition for a new capability.
 | |
| // Not safe to be called concurrently with other methods.
 | |
| func (l *CapList) Init(cc ...Cap) {
 | |
| 	if l.m == nil {
 | |
| 		l.m = make(map[CapID]Cap, len(cc))
 | |
| 	}
 | |
| 	for _, c := range cc {
 | |
| 		l.m[c.ID] = c
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // All reports the configuration of all known capabilities
 | |
| func (l *CapList) All() []pb.APICap {
 | |
| 	out := make([]pb.APICap, 0, len(l.m))
 | |
| 	for _, c := range l.m {
 | |
| 		out = append(out, pb.APICap{
 | |
| 			ID:                  string(c.ID),
 | |
| 			Enabled:             c.Enabled,
 | |
| 			Deprecated:          c.Deprecated,
 | |
| 			DisabledReason:      c.DisabledReason,
 | |
| 			DisabledReasonMsg:   c.DisabledReasonMsg,
 | |
| 			DisabledAlternative: c.DisabledAlternative,
 | |
| 		})
 | |
| 	}
 | |
| 	sort.Slice(out, func(i, j int) bool {
 | |
| 		return out[i].ID < out[j].ID
 | |
| 	})
 | |
| 	return out
 | |
| }
 | |
| 
 | |
| // CapSet returns a CapSet for an capability configuration
 | |
| func (l *CapList) CapSet(caps []pb.APICap) CapSet {
 | |
| 	m := make(map[string]*pb.APICap, len(caps))
 | |
| 	for _, c := range caps {
 | |
| 		if c.ID != "" {
 | |
| 			c := c // capture loop iterator
 | |
| 			m[c.ID] = &c
 | |
| 		}
 | |
| 	}
 | |
| 	return CapSet{
 | |
| 		list: l,
 | |
| 		set:  m,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // CapSet is a configuration for detecting supported capabilities
 | |
| type CapSet struct {
 | |
| 	list *CapList
 | |
| 	set  map[string]*pb.APICap
 | |
| }
 | |
| 
 | |
| // Supports returns an error if capability is not supported
 | |
| func (s *CapSet) Supports(id CapID) error {
 | |
| 	err := &CapError{ID: id}
 | |
| 	c, ok := s.list.m[id]
 | |
| 	if !ok {
 | |
| 		return errors.WithStack(err)
 | |
| 	}
 | |
| 	err.Definition = &c
 | |
| 	state, ok := s.set[string(id)]
 | |
| 	if !ok {
 | |
| 		return errors.WithStack(err)
 | |
| 	}
 | |
| 	err.State = state
 | |
| 	if !state.Enabled {
 | |
| 		return errors.WithStack(err)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // CapError is an error for unsupported capability
 | |
| type CapError struct {
 | |
| 	ID         CapID
 | |
| 	Definition *Cap
 | |
| 	State      *pb.APICap
 | |
| }
 | |
| 
 | |
| func (e CapError) Error() string {
 | |
| 	if e.Definition == nil {
 | |
| 		return fmt.Sprintf("unknown API capability %s", e.ID)
 | |
| 	}
 | |
| 	typ := ""
 | |
| 	if e.Definition.Status == CapStatusExperimental {
 | |
| 		typ = "experimental "
 | |
| 	}
 | |
| 	if e.Definition.Status == CapStatusPrerelease {
 | |
| 		typ = "prerelease "
 | |
| 	}
 | |
| 	name := ""
 | |
| 	if e.Definition.Name != "" {
 | |
| 		name = "(" + e.Definition.Name + ")"
 | |
| 	}
 | |
| 	b := &strings.Builder{}
 | |
| 	fmt.Fprintf(b, "requested %sfeature %s %s", typ, e.ID, name)
 | |
| 	if e.State == nil {
 | |
| 		fmt.Fprint(b, " is not supported by build server")
 | |
| 		if hint, ok := e.Definition.SupportedHint[ExportedProduct]; ok {
 | |
| 			fmt.Fprintf(b, " (added in %s)", hint)
 | |
| 		}
 | |
| 		fmt.Fprintf(b, ", please update %s", ExportedProduct)
 | |
| 	} else {
 | |
| 		fmt.Fprint(b, " has been disabled on the build server")
 | |
| 		if e.State.DisabledReasonMsg != "" {
 | |
| 			fmt.Fprintf(b, ": %s", e.State.DisabledReasonMsg)
 | |
| 		}
 | |
| 	}
 | |
| 	return b.String()
 | |
| }
 | 
