istio.io/istio@v0.0.0-20240520182934-d79c90f27776/operator/pkg/version/version.go (about) 1 // Copyright Istio Authors 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 version 16 17 import ( 18 "fmt" 19 "strconv" 20 "strings" 21 22 goversion "github.com/hashicorp/go-version" 23 "gopkg.in/yaml.v2" 24 ) 25 26 const ( 27 // releasePrefix is the prefix we used in http://gcr.io/istio-release for releases 28 releasePrefix = "release-" 29 ) 30 31 // NewVersionFromString creates a new Version from the provided SemVer formatted string and returns a pointer to it. 32 func NewVersionFromString(s string) (*Version, error) { 33 ver, err := goversion.NewVersion(s) 34 if err != nil { 35 return nil, err 36 } 37 38 newVer := &Version{} 39 vv := ver.Segments() 40 if len(vv) > 0 { 41 newVer.Major = uint32(vv[0]) 42 } 43 if len(vv) > 1 { 44 newVer.Minor = uint32(vv[1]) 45 } 46 if len(vv) > 2 { 47 newVer.Patch = uint32(vv[2]) 48 } 49 50 sv := strings.Split(s, "-") 51 if len(sv) > 0 { 52 newVer.Suffix = strings.Join(sv[1:], "-") 53 } 54 55 return newVer, nil 56 } 57 58 // IsVersionString checks whether the given string is a version string 59 func IsVersionString(path string) bool { 60 _, err := goversion.NewSemver(path) 61 if err != nil { 62 return false 63 } 64 vs := Version{} 65 return yaml.Unmarshal([]byte(path), &vs) == nil 66 } 67 68 // TagToVersionString converts an istio container tag into a version string 69 func TagToVersionString(path string) (string, error) { 70 path = strings.TrimPrefix(path, releasePrefix) 71 ver, err := goversion.NewSemver(path) 72 if err != nil { 73 return "", err 74 } 75 segments := ver.Segments() 76 fmtParts := make([]string, len(segments)) 77 for i, s := range segments { 78 str := strconv.Itoa(s) 79 fmtParts[i] = str 80 } 81 return strings.Join(fmtParts, "."), nil 82 } 83 84 // TagToVersionStringGrace converts an Istio container tag into a version string, 85 // if any error, fallback to use the original tag. 86 func TagToVersionStringGrace(path string) string { 87 v, err := TagToVersionString(path) 88 if err != nil { 89 return path 90 } 91 return v 92 } 93 94 // MajorVersion represents a major version. 95 type MajorVersion struct { 96 Major uint32 97 } 98 99 // MinorVersion represents a minor version. 100 type MinorVersion struct { 101 MajorVersion 102 Minor uint32 103 } 104 105 // PatchVersion represents a patch version. 106 type PatchVersion struct { 107 MinorVersion 108 Patch uint32 109 } 110 111 // Version represents a version with an optional suffix. 112 type Version struct { 113 PatchVersion 114 Suffix string 115 } 116 117 // NewMajorVersion creates an initialized MajorVersion struct. 118 func NewMajorVersion(major uint32) MajorVersion { 119 return MajorVersion{ 120 Major: major, 121 } 122 } 123 124 // NewMinorVersion creates an initialized MinorVersion struct. 125 func NewMinorVersion(major, minor uint32) MinorVersion { 126 return MinorVersion{ 127 MajorVersion: NewMajorVersion(major), 128 Minor: minor, 129 } 130 } 131 132 // NewPatchVersion creates an initialized PatchVersion struct. 133 func NewPatchVersion(major, minor, patch uint32) PatchVersion { 134 return PatchVersion{ 135 MinorVersion: NewMinorVersion(major, minor), 136 Patch: patch, 137 } 138 } 139 140 // NewVersion creates an initialized Version struct. 141 func NewVersion(major, minor, patch uint32, suffix string) Version { 142 return Version{ 143 PatchVersion: NewPatchVersion(major, minor, patch), 144 Suffix: suffix, 145 } 146 } 147 148 // String implements the Stringer interface. 149 func (v MajorVersion) String() string { 150 return fmt.Sprintf("%d", v.Major) 151 } 152 153 // String implements the Stringer interface. 154 func (v MinorVersion) String() string { 155 return fmt.Sprintf("%s.%d", v.MajorVersion, v.Minor) 156 } 157 158 // String implements the Stringer interface. 159 func (v PatchVersion) String() string { 160 return fmt.Sprintf("%s.%d", v.MinorVersion, v.Patch) 161 } 162 163 // String implements the Stringer interface. 164 func (v *Version) String() string { 165 if v.Suffix == "" { 166 return v.PatchVersion.String() 167 } 168 return fmt.Sprintf("%s-%s", v.PatchVersion, v.Suffix) 169 } 170 171 // UnmarshalYAML implements the Unmarshaler interface. 172 func (v *Version) UnmarshalYAML(unmarshal func(any) error) error { 173 s := "" 174 if err := unmarshal(&s); err != nil { 175 return err 176 } 177 out, err := NewVersionFromString(s) 178 if err != nil { 179 return err 180 } 181 *v = *out 182 return nil 183 }