Chromium Code Reviews| 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 | |
|
iannucci
2017/02/21 10:08:16
named return values would simplify this code I thi
dnj
2017/02/21 23:21:35
I dunno, i don't really mind it as-is.
| |
| 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 |