mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 05:22:24 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			594 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			594 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package semver
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"regexp"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| // Constraints is one or more constraint that a semantic version can be
 | |
| // checked against.
 | |
| type Constraints struct {
 | |
| 	constraints [][]*constraint
 | |
| }
 | |
| 
 | |
| // NewConstraint returns a Constraints instance that a Version instance can
 | |
| // be checked against. If there is a parse error it will be returned.
 | |
| func NewConstraint(c string) (*Constraints, error) {
 | |
| 
 | |
| 	// Rewrite - ranges into a comparison operation.
 | |
| 	c = rewriteRange(c)
 | |
| 
 | |
| 	ors := strings.Split(c, "||")
 | |
| 	or := make([][]*constraint, len(ors))
 | |
| 	for k, v := range ors {
 | |
| 
 | |
| 		// TODO: Find a way to validate and fetch all the constraints in a simpler form
 | |
| 
 | |
| 		// Validate the segment
 | |
| 		if !validConstraintRegex.MatchString(v) {
 | |
| 			return nil, fmt.Errorf("improper constraint: %s", v)
 | |
| 		}
 | |
| 
 | |
| 		cs := findConstraintRegex.FindAllString(v, -1)
 | |
| 		if cs == nil {
 | |
| 			cs = append(cs, v)
 | |
| 		}
 | |
| 		result := make([]*constraint, len(cs))
 | |
| 		for i, s := range cs {
 | |
| 			pc, err := parseConstraint(s)
 | |
| 			if err != nil {
 | |
| 				return nil, err
 | |
| 			}
 | |
| 
 | |
| 			result[i] = pc
 | |
| 		}
 | |
| 		or[k] = result
 | |
| 	}
 | |
| 
 | |
| 	o := &Constraints{constraints: or}
 | |
| 	return o, nil
 | |
| }
 | |
| 
 | |
| // Check tests if a version satisfies the constraints.
 | |
| func (cs Constraints) Check(v *Version) bool {
 | |
| 	// TODO(mattfarina): For v4 of this library consolidate the Check and Validate
 | |
| 	// functions as the underlying functions make that possible now.
 | |
| 	// loop over the ORs and check the inner ANDs
 | |
| 	for _, o := range cs.constraints {
 | |
| 		joy := true
 | |
| 		for _, c := range o {
 | |
| 			if check, _ := c.check(v); !check {
 | |
| 				joy = false
 | |
| 				break
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if joy {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| // Validate checks if a version satisfies a constraint. If not a slice of
 | |
| // reasons for the failure are returned in addition to a bool.
 | |
| func (cs Constraints) Validate(v *Version) (bool, []error) {
 | |
| 	// loop over the ORs and check the inner ANDs
 | |
| 	var e []error
 | |
| 
 | |
| 	// Capture the prerelease message only once. When it happens the first time
 | |
| 	// this var is marked
 | |
| 	var prerelesase bool
 | |
| 	for _, o := range cs.constraints {
 | |
| 		joy := true
 | |
| 		for _, c := range o {
 | |
| 			// Before running the check handle the case there the version is
 | |
| 			// a prerelease and the check is not searching for prereleases.
 | |
| 			if c.con.pre == "" && v.pre != "" {
 | |
| 				if !prerelesase {
 | |
| 					em := fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
 | |
| 					e = append(e, em)
 | |
| 					prerelesase = true
 | |
| 				}
 | |
| 				joy = false
 | |
| 
 | |
| 			} else {
 | |
| 
 | |
| 				if _, err := c.check(v); err != nil {
 | |
| 					e = append(e, err)
 | |
| 					joy = false
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if joy {
 | |
| 			return true, []error{}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return false, e
 | |
| }
 | |
| 
 | |
| func (cs Constraints) String() string {
 | |
| 	buf := make([]string, len(cs.constraints))
 | |
| 	var tmp bytes.Buffer
 | |
| 
 | |
| 	for k, v := range cs.constraints {
 | |
| 		tmp.Reset()
 | |
| 		vlen := len(v)
 | |
| 		for kk, c := range v {
 | |
| 			tmp.WriteString(c.string())
 | |
| 
 | |
| 			// Space separate the AND conditions
 | |
| 			if vlen > 1 && kk < vlen-1 {
 | |
| 				tmp.WriteString(" ")
 | |
| 			}
 | |
| 		}
 | |
| 		buf[k] = tmp.String()
 | |
| 	}
 | |
| 
 | |
| 	return strings.Join(buf, " || ")
 | |
| }
 | |
| 
 | |
| // UnmarshalText implements the encoding.TextUnmarshaler interface.
 | |
| func (cs *Constraints) UnmarshalText(text []byte) error {
 | |
| 	temp, err := NewConstraint(string(text))
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	*cs = *temp
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // MarshalText implements the encoding.TextMarshaler interface.
 | |
| func (cs Constraints) MarshalText() ([]byte, error) {
 | |
| 	return []byte(cs.String()), nil
 | |
| }
 | |
| 
 | |
| var constraintOps map[string]cfunc
 | |
| var constraintRegex *regexp.Regexp
 | |
| var constraintRangeRegex *regexp.Regexp
 | |
| 
 | |
| // Used to find individual constraints within a multi-constraint string
 | |
| var findConstraintRegex *regexp.Regexp
 | |
| 
 | |
| // Used to validate an segment of ANDs is valid
 | |
| var validConstraintRegex *regexp.Regexp
 | |
| 
 | |
| const cvRegex string = `v?([0-9|x|X|\*]+)(\.[0-9|x|X|\*]+)?(\.[0-9|x|X|\*]+)?` +
 | |
| 	`(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` +
 | |
| 	`(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?`
 | |
| 
 | |
| func init() {
 | |
| 	constraintOps = map[string]cfunc{
 | |
| 		"":   constraintTildeOrEqual,
 | |
| 		"=":  constraintTildeOrEqual,
 | |
| 		"!=": constraintNotEqual,
 | |
| 		">":  constraintGreaterThan,
 | |
| 		"<":  constraintLessThan,
 | |
| 		">=": constraintGreaterThanEqual,
 | |
| 		"=>": constraintGreaterThanEqual,
 | |
| 		"<=": constraintLessThanEqual,
 | |
| 		"=<": constraintLessThanEqual,
 | |
| 		"~":  constraintTilde,
 | |
| 		"~>": constraintTilde,
 | |
| 		"^":  constraintCaret,
 | |
| 	}
 | |
| 
 | |
| 	ops := `=||!=|>|<|>=|=>|<=|=<|~|~>|\^`
 | |
| 
 | |
| 	constraintRegex = regexp.MustCompile(fmt.Sprintf(
 | |
| 		`^\s*(%s)\s*(%s)\s*$`,
 | |
| 		ops,
 | |
| 		cvRegex))
 | |
| 
 | |
| 	constraintRangeRegex = regexp.MustCompile(fmt.Sprintf(
 | |
| 		`\s*(%s)\s+-\s+(%s)\s*`,
 | |
| 		cvRegex, cvRegex))
 | |
| 
 | |
| 	findConstraintRegex = regexp.MustCompile(fmt.Sprintf(
 | |
| 		`(%s)\s*(%s)`,
 | |
| 		ops,
 | |
| 		cvRegex))
 | |
| 
 | |
| 	// The first time a constraint shows up will look slightly different from
 | |
| 	// future times it shows up due to a leading space or comma in a given
 | |
| 	// string.
 | |
| 	validConstraintRegex = regexp.MustCompile(fmt.Sprintf(
 | |
| 		`^(\s*(%s)\s*(%s)\s*)((?:\s+|,\s*)(%s)\s*(%s)\s*)*$`,
 | |
| 		ops,
 | |
| 		cvRegex,
 | |
| 		ops,
 | |
| 		cvRegex))
 | |
| }
 | |
| 
 | |
| // An individual constraint
 | |
| type constraint struct {
 | |
| 	// The version used in the constraint check. For example, if a constraint
 | |
| 	// is '<= 2.0.0' the con a version instance representing 2.0.0.
 | |
| 	con *Version
 | |
| 
 | |
| 	// The original parsed version (e.g., 4.x from != 4.x)
 | |
| 	orig string
 | |
| 
 | |
| 	// The original operator for the constraint
 | |
| 	origfunc string
 | |
| 
 | |
| 	// When an x is used as part of the version (e.g., 1.x)
 | |
| 	minorDirty bool
 | |
| 	dirty      bool
 | |
| 	patchDirty bool
 | |
| }
 | |
| 
 | |
| // Check if a version meets the constraint
 | |
| func (c *constraint) check(v *Version) (bool, error) {
 | |
| 	return constraintOps[c.origfunc](v, c)
 | |
| }
 | |
| 
 | |
| // String prints an individual constraint into a string
 | |
| func (c *constraint) string() string {
 | |
| 	return c.origfunc + c.orig
 | |
| }
 | |
| 
 | |
| type cfunc func(v *Version, c *constraint) (bool, error)
 | |
| 
 | |
| func parseConstraint(c string) (*constraint, error) {
 | |
| 	if len(c) > 0 {
 | |
| 		m := constraintRegex.FindStringSubmatch(c)
 | |
| 		if m == nil {
 | |
| 			return nil, fmt.Errorf("improper constraint: %s", c)
 | |
| 		}
 | |
| 
 | |
| 		cs := &constraint{
 | |
| 			orig:     m[2],
 | |
| 			origfunc: m[1],
 | |
| 		}
 | |
| 
 | |
| 		ver := m[2]
 | |
| 		minorDirty := false
 | |
| 		patchDirty := false
 | |
| 		dirty := false
 | |
| 		if isX(m[3]) || m[3] == "" {
 | |
| 			ver = fmt.Sprintf("0.0.0%s", m[6])
 | |
| 			dirty = true
 | |
| 		} else if isX(strings.TrimPrefix(m[4], ".")) || m[4] == "" {
 | |
| 			minorDirty = true
 | |
| 			dirty = true
 | |
| 			ver = fmt.Sprintf("%s.0.0%s", m[3], m[6])
 | |
| 		} else if isX(strings.TrimPrefix(m[5], ".")) || m[5] == "" {
 | |
| 			dirty = true
 | |
| 			patchDirty = true
 | |
| 			ver = fmt.Sprintf("%s%s.0%s", m[3], m[4], m[6])
 | |
| 		}
 | |
| 
 | |
| 		con, err := NewVersion(ver)
 | |
| 		if err != nil {
 | |
| 
 | |
| 			// The constraintRegex should catch any regex parsing errors. So,
 | |
| 			// we should never get here.
 | |
| 			return nil, errors.New("constraint Parser Error")
 | |
| 		}
 | |
| 
 | |
| 		cs.con = con
 | |
| 		cs.minorDirty = minorDirty
 | |
| 		cs.patchDirty = patchDirty
 | |
| 		cs.dirty = dirty
 | |
| 
 | |
| 		return cs, nil
 | |
| 	}
 | |
| 
 | |
| 	// The rest is the special case where an empty string was passed in which
 | |
| 	// is equivalent to * or >=0.0.0
 | |
| 	con, err := StrictNewVersion("0.0.0")
 | |
| 	if err != nil {
 | |
| 
 | |
| 		// The constraintRegex should catch any regex parsing errors. So,
 | |
| 		// we should never get here.
 | |
| 		return nil, errors.New("constraint Parser Error")
 | |
| 	}
 | |
| 
 | |
| 	cs := &constraint{
 | |
| 		con:        con,
 | |
| 		orig:       c,
 | |
| 		origfunc:   "",
 | |
| 		minorDirty: false,
 | |
| 		patchDirty: false,
 | |
| 		dirty:      true,
 | |
| 	}
 | |
| 	return cs, nil
 | |
| }
 | |
| 
 | |
| // Constraint functions
 | |
| func constraintNotEqual(v *Version, c *constraint) (bool, error) {
 | |
| 	if c.dirty {
 | |
| 
 | |
| 		// If there is a pre-release on the version but the constraint isn't looking
 | |
| 		// for them assume that pre-releases are not compatible. See issue 21 for
 | |
| 		// more details.
 | |
| 		if v.Prerelease() != "" && c.con.Prerelease() == "" {
 | |
| 			return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
 | |
| 		}
 | |
| 
 | |
| 		if c.con.Major() != v.Major() {
 | |
| 			return true, nil
 | |
| 		}
 | |
| 		if c.con.Minor() != v.Minor() && !c.minorDirty {
 | |
| 			return true, nil
 | |
| 		} else if c.minorDirty {
 | |
| 			return false, fmt.Errorf("%s is equal to %s", v, c.orig)
 | |
| 		} else if c.con.Patch() != v.Patch() && !c.patchDirty {
 | |
| 			return true, nil
 | |
| 		} else if c.patchDirty {
 | |
| 			// Need to handle prereleases if present
 | |
| 			if v.Prerelease() != "" || c.con.Prerelease() != "" {
 | |
| 				eq := comparePrerelease(v.Prerelease(), c.con.Prerelease()) != 0
 | |
| 				if eq {
 | |
| 					return true, nil
 | |
| 				}
 | |
| 				return false, fmt.Errorf("%s is equal to %s", v, c.orig)
 | |
| 			}
 | |
| 			return false, fmt.Errorf("%s is equal to %s", v, c.orig)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	eq := v.Equal(c.con)
 | |
| 	if eq {
 | |
| 		return false, fmt.Errorf("%s is equal to %s", v, c.orig)
 | |
| 	}
 | |
| 
 | |
| 	return true, nil
 | |
| }
 | |
| 
 | |
| func constraintGreaterThan(v *Version, c *constraint) (bool, error) {
 | |
| 
 | |
| 	// If there is a pre-release on the version but the constraint isn't looking
 | |
| 	// for them assume that pre-releases are not compatible. See issue 21 for
 | |
| 	// more details.
 | |
| 	if v.Prerelease() != "" && c.con.Prerelease() == "" {
 | |
| 		return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
 | |
| 	}
 | |
| 
 | |
| 	var eq bool
 | |
| 
 | |
| 	if !c.dirty {
 | |
| 		eq = v.Compare(c.con) == 1
 | |
| 		if eq {
 | |
| 			return true, nil
 | |
| 		}
 | |
| 		return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
 | |
| 	}
 | |
| 
 | |
| 	if v.Major() > c.con.Major() {
 | |
| 		return true, nil
 | |
| 	} else if v.Major() < c.con.Major() {
 | |
| 		return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
 | |
| 	} else if c.minorDirty {
 | |
| 		// This is a range case such as >11. When the version is something like
 | |
| 		// 11.1.0 is it not > 11. For that we would need 12 or higher
 | |
| 		return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
 | |
| 	} else if c.patchDirty {
 | |
| 		// This is for ranges such as >11.1. A version of 11.1.1 is not greater
 | |
| 		// which one of 11.2.1 is greater
 | |
| 		eq = v.Minor() > c.con.Minor()
 | |
| 		if eq {
 | |
| 			return true, nil
 | |
| 		}
 | |
| 		return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
 | |
| 	}
 | |
| 
 | |
| 	// If we have gotten here we are not comparing pre-preleases and can use the
 | |
| 	// Compare function to accomplish that.
 | |
| 	eq = v.Compare(c.con) == 1
 | |
| 	if eq {
 | |
| 		return true, nil
 | |
| 	}
 | |
| 	return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
 | |
| }
 | |
| 
 | |
| func constraintLessThan(v *Version, c *constraint) (bool, error) {
 | |
| 	// If there is a pre-release on the version but the constraint isn't looking
 | |
| 	// for them assume that pre-releases are not compatible. See issue 21 for
 | |
| 	// more details.
 | |
| 	if v.Prerelease() != "" && c.con.Prerelease() == "" {
 | |
| 		return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
 | |
| 	}
 | |
| 
 | |
| 	eq := v.Compare(c.con) < 0
 | |
| 	if eq {
 | |
| 		return true, nil
 | |
| 	}
 | |
| 	return false, fmt.Errorf("%s is greater than or equal to %s", v, c.orig)
 | |
| }
 | |
| 
 | |
| func constraintGreaterThanEqual(v *Version, c *constraint) (bool, error) {
 | |
| 
 | |
| 	// If there is a pre-release on the version but the constraint isn't looking
 | |
| 	// for them assume that pre-releases are not compatible. See issue 21 for
 | |
| 	// more details.
 | |
| 	if v.Prerelease() != "" && c.con.Prerelease() == "" {
 | |
| 		return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
 | |
| 	}
 | |
| 
 | |
| 	eq := v.Compare(c.con) >= 0
 | |
| 	if eq {
 | |
| 		return true, nil
 | |
| 	}
 | |
| 	return false, fmt.Errorf("%s is less than %s", v, c.orig)
 | |
| }
 | |
| 
 | |
| func constraintLessThanEqual(v *Version, c *constraint) (bool, error) {
 | |
| 	// If there is a pre-release on the version but the constraint isn't looking
 | |
| 	// for them assume that pre-releases are not compatible. See issue 21 for
 | |
| 	// more details.
 | |
| 	if v.Prerelease() != "" && c.con.Prerelease() == "" {
 | |
| 		return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
 | |
| 	}
 | |
| 
 | |
| 	var eq bool
 | |
| 
 | |
| 	if !c.dirty {
 | |
| 		eq = v.Compare(c.con) <= 0
 | |
| 		if eq {
 | |
| 			return true, nil
 | |
| 		}
 | |
| 		return false, fmt.Errorf("%s is greater than %s", v, c.orig)
 | |
| 	}
 | |
| 
 | |
| 	if v.Major() > c.con.Major() {
 | |
| 		return false, fmt.Errorf("%s is greater than %s", v, c.orig)
 | |
| 	} else if v.Major() == c.con.Major() && v.Minor() > c.con.Minor() && !c.minorDirty {
 | |
| 		return false, fmt.Errorf("%s is greater than %s", v, c.orig)
 | |
| 	}
 | |
| 
 | |
| 	return true, nil
 | |
| }
 | |
| 
 | |
| // ~*, ~>* --> >= 0.0.0 (any)
 | |
| // ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0, <3.0.0
 | |
| // ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0, <2.1.0
 | |
| // ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0, <1.3.0
 | |
| // ~1.2.3, ~>1.2.3 --> >=1.2.3, <1.3.0
 | |
| // ~1.2.0, ~>1.2.0 --> >=1.2.0, <1.3.0
 | |
| func constraintTilde(v *Version, c *constraint) (bool, error) {
 | |
| 	// If there is a pre-release on the version but the constraint isn't looking
 | |
| 	// for them assume that pre-releases are not compatible. See issue 21 for
 | |
| 	// more details.
 | |
| 	if v.Prerelease() != "" && c.con.Prerelease() == "" {
 | |
| 		return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
 | |
| 	}
 | |
| 
 | |
| 	if v.LessThan(c.con) {
 | |
| 		return false, fmt.Errorf("%s is less than %s", v, c.orig)
 | |
| 	}
 | |
| 
 | |
| 	// ~0.0.0 is a special case where all constraints are accepted. It's
 | |
| 	// equivalent to >= 0.0.0.
 | |
| 	if c.con.Major() == 0 && c.con.Minor() == 0 && c.con.Patch() == 0 &&
 | |
| 		!c.minorDirty && !c.patchDirty {
 | |
| 		return true, nil
 | |
| 	}
 | |
| 
 | |
| 	if v.Major() != c.con.Major() {
 | |
| 		return false, fmt.Errorf("%s does not have same major version as %s", v, c.orig)
 | |
| 	}
 | |
| 
 | |
| 	if v.Minor() != c.con.Minor() && !c.minorDirty {
 | |
| 		return false, fmt.Errorf("%s does not have same major and minor version as %s", v, c.orig)
 | |
| 	}
 | |
| 
 | |
| 	return true, nil
 | |
| }
 | |
| 
 | |
| // When there is a .x (dirty) status it automatically opts in to ~. Otherwise
 | |
| // it's a straight =
 | |
| func constraintTildeOrEqual(v *Version, c *constraint) (bool, error) {
 | |
| 	// If there is a pre-release on the version but the constraint isn't looking
 | |
| 	// for them assume that pre-releases are not compatible. See issue 21 for
 | |
| 	// more details.
 | |
| 	if v.Prerelease() != "" && c.con.Prerelease() == "" {
 | |
| 		return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
 | |
| 	}
 | |
| 
 | |
| 	if c.dirty {
 | |
| 		return constraintTilde(v, c)
 | |
| 	}
 | |
| 
 | |
| 	eq := v.Equal(c.con)
 | |
| 	if eq {
 | |
| 		return true, nil
 | |
| 	}
 | |
| 
 | |
| 	return false, fmt.Errorf("%s is not equal to %s", v, c.orig)
 | |
| }
 | |
| 
 | |
| // ^*      -->  (any)
 | |
| // ^1.2.3  -->  >=1.2.3 <2.0.0
 | |
| // ^1.2    -->  >=1.2.0 <2.0.0
 | |
| // ^1      -->  >=1.0.0 <2.0.0
 | |
| // ^0.2.3  -->  >=0.2.3 <0.3.0
 | |
| // ^0.2    -->  >=0.2.0 <0.3.0
 | |
| // ^0.0.3  -->  >=0.0.3 <0.0.4
 | |
| // ^0.0    -->  >=0.0.0 <0.1.0
 | |
| // ^0      -->  >=0.0.0 <1.0.0
 | |
| func constraintCaret(v *Version, c *constraint) (bool, error) {
 | |
| 	// If there is a pre-release on the version but the constraint isn't looking
 | |
| 	// for them assume that pre-releases are not compatible. See issue 21 for
 | |
| 	// more details.
 | |
| 	if v.Prerelease() != "" && c.con.Prerelease() == "" {
 | |
| 		return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
 | |
| 	}
 | |
| 
 | |
| 	// This less than handles prereleases
 | |
| 	if v.LessThan(c.con) {
 | |
| 		return false, fmt.Errorf("%s is less than %s", v, c.orig)
 | |
| 	}
 | |
| 
 | |
| 	var eq bool
 | |
| 
 | |
| 	// ^ when the major > 0 is >=x.y.z < x+1
 | |
| 	if c.con.Major() > 0 || c.minorDirty {
 | |
| 
 | |
| 		// ^ has to be within a major range for > 0. Everything less than was
 | |
| 		// filtered out with the LessThan call above. This filters out those
 | |
| 		// that greater but not within the same major range.
 | |
| 		eq = v.Major() == c.con.Major()
 | |
| 		if eq {
 | |
| 			return true, nil
 | |
| 		}
 | |
| 		return false, fmt.Errorf("%s does not have same major version as %s", v, c.orig)
 | |
| 	}
 | |
| 
 | |
| 	// ^ when the major is 0 and minor > 0 is >=0.y.z < 0.y+1
 | |
| 	if c.con.Major() == 0 && v.Major() > 0 {
 | |
| 		return false, fmt.Errorf("%s does not have same major version as %s", v, c.orig)
 | |
| 	}
 | |
| 	// If the con Minor is > 0 it is not dirty
 | |
| 	if c.con.Minor() > 0 || c.patchDirty {
 | |
| 		eq = v.Minor() == c.con.Minor()
 | |
| 		if eq {
 | |
| 			return true, nil
 | |
| 		}
 | |
| 		return false, fmt.Errorf("%s does not have same minor version as %s. Expected minor versions to match when constraint major version is 0", v, c.orig)
 | |
| 	}
 | |
| 	// ^ when the minor is 0 and minor > 0 is =0.0.z
 | |
| 	if c.con.Minor() == 0 && v.Minor() > 0 {
 | |
| 		return false, fmt.Errorf("%s does not have same minor version as %s", v, c.orig)
 | |
| 	}
 | |
| 
 | |
| 	// At this point the major is 0 and the minor is 0 and not dirty. The patch
 | |
| 	// is not dirty so we need to check if they are equal. If they are not equal
 | |
| 	eq = c.con.Patch() == v.Patch()
 | |
| 	if eq {
 | |
| 		return true, nil
 | |
| 	}
 | |
| 	return false, fmt.Errorf("%s does not equal %s. Expect version and constraint to equal when major and minor versions are 0", v, c.orig)
 | |
| }
 | |
| 
 | |
| func isX(x string) bool {
 | |
| 	switch x {
 | |
| 	case "x", "*", "X":
 | |
| 		return true
 | |
| 	default:
 | |
| 		return false
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func rewriteRange(i string) string {
 | |
| 	m := constraintRangeRegex.FindAllStringSubmatch(i, -1)
 | |
| 	if m == nil {
 | |
| 		return i
 | |
| 	}
 | |
| 	o := i
 | |
| 	for _, v := range m {
 | |
| 		t := fmt.Sprintf(">= %s, <= %s ", v[1], v[11])
 | |
| 		o = strings.Replace(o, v[0], t, 1)
 | |
| 	}
 | |
| 
 | |
| 	return o
 | |
| }
 |