github.hscsec.cn/openshift/source-to-image@v1.2.0/pkg/util/user/range.go (about)

     1  package user
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strconv"
     7  	"strings"
     8  )
     9  
    10  // Range errors
    11  var (
    12  	ErrInvalidRange = errors.New("invalid range; a range must consist of positive integers and the upper bound must be greater than or equal to the lower bound")
    13  )
    14  
    15  // ErrParseRange is an error encountered while parsing a Range
    16  type ErrParseRange struct {
    17  	cause error
    18  }
    19  
    20  func (e *ErrParseRange) Error() string {
    21  	msg := "error parsing range; a range must be of one of the following formats: [n], [-n], [n-], [n:m] where n and m are positive numbers and m is greater than or equal to n"
    22  	if e.cause != nil {
    23  		msg = fmt.Sprintf("%s: %v", msg, e.cause)
    24  	}
    25  	return msg
    26  }
    27  
    28  // Range represents a range of user ids. It can be unbound at either end with a nil value
    29  // I both From and To are present, To must be greater than or equal to From. Bounds are inclusive
    30  type Range struct {
    31  	from *int
    32  	to   *int
    33  }
    34  
    35  // NewRange creates a new range with lower and upper bound
    36  func NewRange(from int, to int) (*Range, error) {
    37  	return (&rangeBuilder{}).from(from, nil).to(to, nil).Range()
    38  }
    39  
    40  // NewRangeTo creates a new range with only the upper bound
    41  func NewRangeTo(to int) (*Range, error) {
    42  	return (&rangeBuilder{}).to(to, nil).Range()
    43  }
    44  
    45  // NewRangeFrom creates a new range with only the lower bound
    46  func NewRangeFrom(from int) (*Range, error) {
    47  	return (&rangeBuilder{}).from(from, nil).Range()
    48  }
    49  
    50  func parseInt(str string) (int, error) {
    51  	num, err := strconv.Atoi(str)
    52  	if err != nil {
    53  		return 0, &ErrParseRange{cause: err}
    54  	}
    55  	return num, nil
    56  }
    57  
    58  type rangeBuilder struct {
    59  	r   Range
    60  	err error
    61  }
    62  
    63  func (b *rangeBuilder) from(num int, err error) *rangeBuilder {
    64  	return b.setBound(num, err, &b.r.from)
    65  }
    66  
    67  func (b *rangeBuilder) to(num int, err error) *rangeBuilder {
    68  	return b.setBound(num, err, &b.r.to)
    69  }
    70  
    71  func (b *rangeBuilder) setBound(num int, err error, bound **int) *rangeBuilder {
    72  	if b.err != nil {
    73  		return b
    74  	}
    75  	if b.err = err; b.err != nil {
    76  		return b
    77  	}
    78  	if num < 0 {
    79  		b.err = ErrInvalidRange
    80  		return b
    81  	}
    82  	*bound = &num
    83  	return b
    84  }
    85  
    86  // Range returns the completed Range from the rangeBuilder.
    87  func (b *rangeBuilder) Range() (*Range, error) {
    88  	if b.err != nil {
    89  		return nil, b.err
    90  	}
    91  	if b.r.from != nil && b.r.to != nil && *b.r.to < *b.r.from {
    92  		return nil, ErrInvalidRange
    93  	}
    94  	return &b.r, nil
    95  }
    96  
    97  // ParseRange creates a Range from a given string
    98  func ParseRange(value string) (*Range, error) {
    99  	value = strings.TrimSpace(value)
   100  	b := &rangeBuilder{}
   101  	if value == "" {
   102  		return b.Range()
   103  	}
   104  	parts := strings.Split(value, "-")
   105  	switch len(parts) {
   106  	case 1:
   107  		num, err := parseInt(parts[0])
   108  		return b.from(num, err).to(num, err).Range()
   109  	case 2:
   110  		if parts[0] != "" {
   111  			b.from(parseInt(parts[0]))
   112  		}
   113  		if parts[1] != "" {
   114  			b.to(parseInt(parts[1]))
   115  		}
   116  		return b.Range()
   117  	default:
   118  		return nil, &ErrParseRange{}
   119  	}
   120  }
   121  
   122  // Contains returns true if the argument falls inside the Range
   123  func (r *Range) Contains(value int) bool {
   124  	if r.from == nil && r.to == nil {
   125  		return false
   126  	}
   127  	if r.from != nil && value < *r.from {
   128  		return false
   129  	}
   130  	if r.to != nil && value > *r.to {
   131  		return false
   132  	}
   133  	return true
   134  }
   135  
   136  // String returns a parse-able string representation of a Range
   137  func (r *Range) String() string {
   138  	switch {
   139  	case r.from == nil && r.to == nil:
   140  		return ""
   141  	case r.from == nil:
   142  		return fmt.Sprintf("-%d", *r.to)
   143  	case r.to == nil:
   144  		return fmt.Sprintf("%d-", *r.from)
   145  	case *r.from == *r.to:
   146  		return fmt.Sprintf("%d", *r.to)
   147  	default:
   148  		return fmt.Sprintf("%d-%d", *r.from, *r.to)
   149  	}
   150  }
   151  
   152  // Type returns the type of a Range object
   153  func (r *Range) Type() string {
   154  	return "user.Range"
   155  }
   156  
   157  // Set sets the value of a Range object
   158  func (r *Range) Set(value string) error {
   159  	newRange, err := ParseRange(value)
   160  	if err != nil {
   161  		return err
   162  	}
   163  	*r = *newRange
   164  	return nil
   165  }
   166  
   167  // Empty returns true if the range has no bounds
   168  func (r *Range) Empty() bool {
   169  	return r.from == nil && r.to == nil
   170  }