mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 10:03:42 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			269 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			269 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package middleware
 | 
						|
 | 
						|
import "fmt"
 | 
						|
 | 
						|
// RelativePosition provides specifying the relative position of a middleware
 | 
						|
// in an ordered group.
 | 
						|
type RelativePosition int
 | 
						|
 | 
						|
// Relative position for middleware in steps.
 | 
						|
const (
 | 
						|
	After RelativePosition = iota
 | 
						|
	Before
 | 
						|
)
 | 
						|
 | 
						|
type ider interface {
 | 
						|
	ID() string
 | 
						|
}
 | 
						|
 | 
						|
// orderedIDs provides an ordered collection of items with relative ordering
 | 
						|
// by name.
 | 
						|
type orderedIDs struct {
 | 
						|
	order *relativeOrder
 | 
						|
	items map[string]ider
 | 
						|
}
 | 
						|
 | 
						|
const baseOrderedItems = 5
 | 
						|
 | 
						|
func newOrderedIDs() *orderedIDs {
 | 
						|
	return &orderedIDs{
 | 
						|
		order: newRelativeOrder(),
 | 
						|
		items: make(map[string]ider, baseOrderedItems),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Add injects the item to the relative position of the item group. Returns an
 | 
						|
// error if the item already exists.
 | 
						|
func (g *orderedIDs) Add(m ider, pos RelativePosition) error {
 | 
						|
	id := m.ID()
 | 
						|
	if len(id) == 0 {
 | 
						|
		return fmt.Errorf("empty ID, ID must not be empty")
 | 
						|
	}
 | 
						|
 | 
						|
	if err := g.order.Add(pos, id); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	g.items[id] = m
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// Insert injects the item relative to an existing item id. Returns an error if
 | 
						|
// the original item does not exist, or the item being added already exists.
 | 
						|
func (g *orderedIDs) Insert(m ider, relativeTo string, pos RelativePosition) error {
 | 
						|
	if len(m.ID()) == 0 {
 | 
						|
		return fmt.Errorf("insert ID must not be empty")
 | 
						|
	}
 | 
						|
	if len(relativeTo) == 0 {
 | 
						|
		return fmt.Errorf("relative to ID must not be empty")
 | 
						|
	}
 | 
						|
 | 
						|
	if err := g.order.Insert(relativeTo, pos, m.ID()); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	g.items[m.ID()] = m
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// Get returns the ider identified by id. If ider is not present, returns false.
 | 
						|
func (g *orderedIDs) Get(id string) (ider, bool) {
 | 
						|
	v, ok := g.items[id]
 | 
						|
	return v, ok
 | 
						|
}
 | 
						|
 | 
						|
// Swap removes the item by id, replacing it with the new item. Returns an error
 | 
						|
// if the original item doesn't exist.
 | 
						|
func (g *orderedIDs) Swap(id string, m ider) (ider, error) {
 | 
						|
	if len(id) == 0 {
 | 
						|
		return nil, fmt.Errorf("swap from ID must not be empty")
 | 
						|
	}
 | 
						|
 | 
						|
	iderID := m.ID()
 | 
						|
	if len(iderID) == 0 {
 | 
						|
		return nil, fmt.Errorf("swap to ID must not be empty")
 | 
						|
	}
 | 
						|
 | 
						|
	if err := g.order.Swap(id, iderID); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	removed := g.items[id]
 | 
						|
 | 
						|
	delete(g.items, id)
 | 
						|
	g.items[iderID] = m
 | 
						|
 | 
						|
	return removed, nil
 | 
						|
}
 | 
						|
 | 
						|
// Remove removes the item by id. Returns an error if the item
 | 
						|
// doesn't exist.
 | 
						|
func (g *orderedIDs) Remove(id string) (ider, error) {
 | 
						|
	if len(id) == 0 {
 | 
						|
		return nil, fmt.Errorf("remove ID must not be empty")
 | 
						|
	}
 | 
						|
 | 
						|
	if err := g.order.Remove(id); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	removed := g.items[id]
 | 
						|
	delete(g.items, id)
 | 
						|
	return removed, nil
 | 
						|
}
 | 
						|
 | 
						|
func (g *orderedIDs) List() []string {
 | 
						|
	items := g.order.List()
 | 
						|
	order := make([]string, len(items))
 | 
						|
	copy(order, items)
 | 
						|
	return order
 | 
						|
}
 | 
						|
 | 
						|
// Clear removes all entries and slots.
 | 
						|
func (g *orderedIDs) Clear() {
 | 
						|
	g.order.Clear()
 | 
						|
	g.items = map[string]ider{}
 | 
						|
}
 | 
						|
 | 
						|
// GetOrder returns the item in the order it should be invoked in.
 | 
						|
func (g *orderedIDs) GetOrder() []interface{} {
 | 
						|
	order := g.order.List()
 | 
						|
	ordered := make([]interface{}, len(order))
 | 
						|
	for i := 0; i < len(order); i++ {
 | 
						|
		ordered[i] = g.items[order[i]]
 | 
						|
	}
 | 
						|
 | 
						|
	return ordered
 | 
						|
}
 | 
						|
 | 
						|
// relativeOrder provides ordering of item
 | 
						|
type relativeOrder struct {
 | 
						|
	order []string
 | 
						|
}
 | 
						|
 | 
						|
func newRelativeOrder() *relativeOrder {
 | 
						|
	return &relativeOrder{
 | 
						|
		order: make([]string, 0, baseOrderedItems),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Add inserts an item into the order relative to the position provided.
 | 
						|
func (s *relativeOrder) Add(pos RelativePosition, ids ...string) error {
 | 
						|
	if len(ids) == 0 {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	for _, id := range ids {
 | 
						|
		if _, ok := s.has(id); ok {
 | 
						|
			return fmt.Errorf("already exists, %v", id)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	switch pos {
 | 
						|
	case Before:
 | 
						|
		return s.insert(0, Before, ids...)
 | 
						|
 | 
						|
	case After:
 | 
						|
		s.order = append(s.order, ids...)
 | 
						|
 | 
						|
	default:
 | 
						|
		return fmt.Errorf("invalid position, %v", int(pos))
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// Insert injects an item before or after the relative item. Returns
 | 
						|
// an error if the relative item does not exist.
 | 
						|
func (s *relativeOrder) Insert(relativeTo string, pos RelativePosition, ids ...string) error {
 | 
						|
	if len(ids) == 0 {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	for _, id := range ids {
 | 
						|
		if _, ok := s.has(id); ok {
 | 
						|
			return fmt.Errorf("already exists, %v", id)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	i, ok := s.has(relativeTo)
 | 
						|
	if !ok {
 | 
						|
		return fmt.Errorf("not found, %v", relativeTo)
 | 
						|
	}
 | 
						|
 | 
						|
	return s.insert(i, pos, ids...)
 | 
						|
}
 | 
						|
 | 
						|
// Swap will replace the item id with the to item. Returns an
 | 
						|
// error if the original item id does not exist. Allows swapping out an
 | 
						|
// item for another item with the same id.
 | 
						|
func (s *relativeOrder) Swap(id, to string) error {
 | 
						|
	i, ok := s.has(id)
 | 
						|
	if !ok {
 | 
						|
		return fmt.Errorf("not found, %v", id)
 | 
						|
	}
 | 
						|
 | 
						|
	if _, ok = s.has(to); ok && id != to {
 | 
						|
		return fmt.Errorf("already exists, %v", to)
 | 
						|
	}
 | 
						|
 | 
						|
	s.order[i] = to
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (s *relativeOrder) Remove(id string) error {
 | 
						|
	i, ok := s.has(id)
 | 
						|
	if !ok {
 | 
						|
		return fmt.Errorf("not found, %v", id)
 | 
						|
	}
 | 
						|
 | 
						|
	s.order = append(s.order[:i], s.order[i+1:]...)
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (s *relativeOrder) List() []string {
 | 
						|
	return s.order
 | 
						|
}
 | 
						|
 | 
						|
func (s *relativeOrder) Clear() {
 | 
						|
	s.order = s.order[0:0]
 | 
						|
}
 | 
						|
 | 
						|
func (s *relativeOrder) insert(i int, pos RelativePosition, ids ...string) error {
 | 
						|
	switch pos {
 | 
						|
	case Before:
 | 
						|
		n := len(ids)
 | 
						|
		var src []string
 | 
						|
		if n <= cap(s.order)-len(s.order) {
 | 
						|
			s.order = s.order[:len(s.order)+n]
 | 
						|
			src = s.order
 | 
						|
		} else {
 | 
						|
			src = s.order
 | 
						|
			s.order = make([]string, len(s.order)+n)
 | 
						|
			copy(s.order[:i], src[:i]) // only when allocating a new slice do we need to copy the front half
 | 
						|
		}
 | 
						|
		copy(s.order[i+n:], src[i:])
 | 
						|
		copy(s.order[i:], ids)
 | 
						|
	case After:
 | 
						|
		if i == len(s.order)-1 || len(s.order) == 0 {
 | 
						|
			s.order = append(s.order, ids...)
 | 
						|
		} else {
 | 
						|
			s.order = append(s.order[:i+1], append(ids, s.order[i+1:]...)...)
 | 
						|
		}
 | 
						|
 | 
						|
	default:
 | 
						|
		return fmt.Errorf("invalid position, %v", int(pos))
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (s *relativeOrder) has(id string) (i int, found bool) {
 | 
						|
	for i := 0; i < len(s.order); i++ {
 | 
						|
		if s.order[i] == id {
 | 
						|
			return i, true
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return 0, false
 | 
						|
}
 |