github.phpd.cn/cilium/cilium@v1.6.12/pkg/labels/array.go (about)

     1  // Copyright 2016-2017 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package labels
    16  
    17  import (
    18  	"sort"
    19  	"strings"
    20  )
    21  
    22  // LabelArray is an array of labels forming a set
    23  type LabelArray []Label
    24  
    25  // Sort is an internal utility to return all LabelArrays in sorted
    26  // order, when the source material may be unsorted.  'ls' is sorted
    27  // in-place, but also returns the sorted array for convenience.
    28  func (ls LabelArray) Sort() LabelArray {
    29  	sort.Slice(ls, func(i, j int) bool {
    30  		return ls[i].Key < ls[j].Key
    31  	})
    32  	return ls
    33  }
    34  
    35  // ParseLabelArray parses a list of labels and returns a LabelArray
    36  func ParseLabelArray(labels ...string) LabelArray {
    37  	array := make(LabelArray, len(labels))
    38  	for i := range labels {
    39  		array[i] = ParseLabel(labels[i])
    40  	}
    41  	return array.Sort()
    42  }
    43  
    44  // ParseSelectLabelArray parses a list of select labels and returns a LabelArray
    45  func ParseSelectLabelArray(labels ...string) LabelArray {
    46  	array := make(LabelArray, len(labels))
    47  	for i := range labels {
    48  		array[i] = ParseSelectLabel(labels[i])
    49  	}
    50  	return array.Sort()
    51  }
    52  
    53  // ParseLabelArrayFromArray converts an array of strings as labels and returns a LabelArray
    54  func ParseLabelArrayFromArray(base []string) LabelArray {
    55  	array := make(LabelArray, len(base))
    56  	for i := range base {
    57  		array[i] = ParseLabel(base[i])
    58  	}
    59  	return array.Sort()
    60  }
    61  
    62  // NewLabelArrayFromSortedList returns labels based on the output of SortedList()
    63  // Trailing ';' will result in an empty key that must be filtered out.
    64  func NewLabelArrayFromSortedList(list string) LabelArray {
    65  	base := strings.Split(list, ";")
    66  	array := make(LabelArray, 0, len(base))
    67  	for _, v := range base {
    68  		if lbl := ParseLabel(v); lbl.Key != "" {
    69  			array = append(array, lbl)
    70  		}
    71  	}
    72  	return array
    73  }
    74  
    75  // ParseSelectLabelArrayFromArray converts an array of strings as select labels and returns a LabelArray
    76  func ParseSelectLabelArrayFromArray(base []string) LabelArray {
    77  	array := make(LabelArray, len(base))
    78  	for i := range base {
    79  		array[i] = ParseSelectLabel(base[i])
    80  	}
    81  	return array.Sort()
    82  }
    83  
    84  // Labels returns the LabelArray as Labels
    85  func (ls LabelArray) Labels() Labels {
    86  	lbls := Labels{}
    87  	for _, l := range ls {
    88  		lbls[l.Key] = l
    89  	}
    90  	return lbls
    91  }
    92  
    93  // Contains returns true if all ls contains all the labels in needed. If
    94  // needed contains no labels, Contains() will always return true
    95  func (ls LabelArray) Contains(needed LabelArray) bool {
    96  nextLabel:
    97  	for i := range needed {
    98  		for l := range ls {
    99  			if needed[i].matches(&ls[l]) {
   100  				continue nextLabel
   101  			}
   102  		}
   103  
   104  		return false
   105  	}
   106  
   107  	return true
   108  }
   109  
   110  // Lacks is identical to Contains but returns all missing labels
   111  func (ls LabelArray) Lacks(needed LabelArray) LabelArray {
   112  	missing := LabelArray{}
   113  nextLabel:
   114  	for i := range needed {
   115  		for l := range ls {
   116  			if needed[i].matches(&ls[l]) {
   117  				continue nextLabel
   118  			}
   119  		}
   120  
   121  		missing = append(missing, needed[i])
   122  	}
   123  
   124  	return missing
   125  }
   126  
   127  // Has returns whether the provided key exists.
   128  // Implementation of the k8s.io/apimachinery/pkg/labels.Labels interface.
   129  func (ls LabelArray) Has(key string) bool {
   130  	// The key is submitted in the form of `source.key=value`
   131  	keyLabel := parseSelectLabel(key, '.')
   132  	if keyLabel.IsAnySource() {
   133  		for l := range ls {
   134  			if ls[l].Key == keyLabel.Key {
   135  				return true
   136  			}
   137  		}
   138  	} else {
   139  		for _, lsl := range ls {
   140  			// Note that if '=value' is part of 'key' it is ignored here
   141  			if lsl.Source == keyLabel.Source && lsl.Key == keyLabel.Key {
   142  				return true
   143  			}
   144  		}
   145  	}
   146  	return false
   147  }
   148  
   149  // Get returns the value for the provided key.
   150  // Implementation of the k8s.io/apimachinery/pkg/labels.Labels interface.
   151  func (ls LabelArray) Get(key string) string {
   152  	keyLabel := parseSelectLabel(key, '.')
   153  	if keyLabel.IsAnySource() {
   154  		for l := range ls {
   155  			if ls[l].Key == keyLabel.Key {
   156  				return ls[l].Value
   157  			}
   158  		}
   159  	} else {
   160  		for _, lsl := range ls {
   161  			if lsl.Source == keyLabel.Source && lsl.Key == keyLabel.Key {
   162  				return lsl.Value
   163  			}
   164  		}
   165  	}
   166  	return ""
   167  }
   168  
   169  // DeepCopy returns a deep copy of the labels.
   170  func (ls LabelArray) DeepCopy() LabelArray {
   171  	if ls == nil {
   172  		return nil
   173  	}
   174  
   175  	o := make(LabelArray, len(ls))
   176  	copy(o, ls)
   177  	return o
   178  }
   179  
   180  // GetModel returns the LabelArray as a string array with fully-qualified labels.
   181  // The output is parseable by ParseLabelArrayFromArray
   182  func (ls LabelArray) GetModel() []string {
   183  	res := []string{}
   184  	for l := range ls {
   185  		res = append(res, ls[l].String())
   186  	}
   187  	return res
   188  }
   189  
   190  func (ls LabelArray) String() string {
   191  	res := "["
   192  	for l := range ls {
   193  		if l > 0 {
   194  			res += " "
   195  		}
   196  		res += ls[l].String()
   197  	}
   198  	res += "]"
   199  	return res
   200  }
   201  
   202  // StringMap converts LabelArray into map[string]string
   203  // Note: The source is included in the keys with a ':' separator.
   204  // Note: LabelArray does not deduplicate entries, as it is an array. It is
   205  // possible for the output to contain fewer entries when the source and key are
   206  // repeated in a LabelArray, as that is the key of the output. This scenario is
   207  // not expected.
   208  func (ls LabelArray) StringMap() map[string]string {
   209  	o := map[string]string{}
   210  	for _, v := range ls {
   211  		o[v.Source+":"+v.Key] = v.Value
   212  	}
   213  	return o
   214  }
   215  
   216  // Same returns true if the label arrays are the same, i.e., have the same labels in the same order.
   217  func (ls LabelArray) Same(b LabelArray) bool {
   218  	if len(ls) != len(b) {
   219  		return false
   220  	}
   221  	for l := range ls {
   222  		if !ls[l].Equals(&b[l]) {
   223  			return false
   224  		}
   225  	}
   226  	return true
   227  }