| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2017 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. |
| 4 |
| 5 package python |
| 6 |
| 7 import ( |
| 8 "fmt" |
| 9 "strconv" |
| 10 "strings" |
| 11 |
| 12 "github.com/luci/luci-go/common/errors" |
| 13 ) |
| 14 |
| 15 // Version is a Python interpreter version. |
| 16 type Version struct { |
| 17 Major int |
| 18 Minor int |
| 19 Patch int |
| 20 } |
| 21 |
| 22 // ParseVersion parses a Python version from a version string (e.g., "1.2.3"). |
| 23 func ParseVersion(s string) (Version, error) { |
| 24 if len(s) == 0 { |
| 25 return Version{}, nil |
| 26 } |
| 27 |
| 28 parseVersion := func(value string) (int, error) { |
| 29 version, err := strconv.Atoi(value) |
| 30 if err != nil { |
| 31 return 0, errors.Annotate(err).Reason("invalid number va
lue: %(value)q"). |
| 32 D("value", value). |
| 33 Err() |
| 34 } |
| 35 if version < 0 { |
| 36 return 0, errors.Reason("version (%(version)d) must not
be negative"). |
| 37 D("version", version). |
| 38 Err() |
| 39 } |
| 40 return version, nil |
| 41 } |
| 42 |
| 43 var v Version |
| 44 parts := strings.Split(s, ".") |
| 45 var err error |
| 46 switch l := len(parts); l { |
| 47 case 3: |
| 48 if v.Patch, err = parseVersion(parts[2]); err != nil { |
| 49 return v, errors.Annotate(err).Reason("invalid patch val
ue").Err() |
| 50 } |
| 51 fallthrough |
| 52 |
| 53 case 2: |
| 54 if v.Minor, err = parseVersion(parts[1]); err != nil { |
| 55 return v, errors.Annotate(err).Reason("invalid minor val
ue").Err() |
| 56 } |
| 57 fallthrough |
| 58 |
| 59 case 1: |
| 60 if v.Major, err = parseVersion(parts[0]); err != nil { |
| 61 return v, errors.Annotate(err).Reason("invalid major val
ue").Err() |
| 62 } |
| 63 if v.IsZero() { |
| 64 return v, errors.Reason("version is incomplete").Err() |
| 65 } |
| 66 return v, nil |
| 67 |
| 68 default: |
| 69 return v, errors.Reason("unsupported number of parts (%(count)d)
"). |
| 70 D("count", l). |
| 71 Err() |
| 72 } |
| 73 } |
| 74 |
| 75 func (v Version) String() string { |
| 76 if v.IsZero() { |
| 77 return "" |
| 78 } |
| 79 return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch) |
| 80 } |
| 81 |
| 82 // IsZero returns true if the Version is empty. This is true if the Major field, |
| 83 // which must be set, is empty. |
| 84 func (v *Version) IsZero() bool { return v.Major <= 0 } |
| 85 |
| 86 // PythonBase returns the base Python interpreter name for this version. |
| 87 func (v *Version) PythonBase() string { |
| 88 switch { |
| 89 case v.IsZero(): |
| 90 return "python" |
| 91 case v.Minor > 0: |
| 92 return fmt.Sprintf("python%d.%d", v.Major, v.Minor) |
| 93 default: |
| 94 return fmt.Sprintf("python%d", v.Major) |
| 95 } |
| 96 } |
| 97 |
| 98 // IsSatisfiedBy returns true if "other" is a suitable match for this version. A |
| 99 // suitable match: |
| 100 // |
| 101 // - MUST have a Major version. |
| 102 // - If v is zero, other is automatically suitable. |
| 103 // - If v is non-zero, other must have the same Major version as v, and a |
| 104 // minor/patch version that is >= v's. |
| 105 func (v *Version) IsSatisfiedBy(other Version) bool { |
| 106 switch { |
| 107 case other.Major <= 0: |
| 108 // "other" must have a Major version. |
| 109 return false |
| 110 case v.IsZero(): |
| 111 // "v" is zero (anything), so "other" satisfies it. |
| 112 return true |
| 113 case v.Major != other.Major: |
| 114 // "other" must match "v"'s Major version precisely. |
| 115 return false |
| 116 case v.Minor > other.Minor: |
| 117 // "v" requires a Minor version that is greater than "other"'s. |
| 118 return false |
| 119 case v.Minor < other.Minor: |
| 120 // "v" requires a Minor version that is less than "other"'s. |
| 121 return true |
| 122 case v.Patch > other.Patch: |
| 123 // "v" requires a Patch version that is greater than "other"'s. |
| 124 return false |
| 125 default: |
| 126 return true |
| 127 } |
| 128 } |
| 129 |
| 130 // Less returns true if "v"'s Version semantically precedes "other". |
| 131 func (v *Version) Less(other *Version) bool { |
| 132 switch { |
| 133 case v.Major < other.Major: |
| 134 return true |
| 135 case v.Major > other.Major: |
| 136 return false |
| 137 case v.Minor < other.Minor: |
| 138 return true |
| 139 case v.Minor > other.Minor: |
| 140 return false |
| 141 default: |
| 142 return (v.Patch < other.Patch) |
| 143 } |
| 144 } |
| OLD | NEW |