github.com/graemephi/kahugo@v0.62.3-0.20211121071557-d78c0423784d/common/hugo/version.go (about) 1 // Copyright 2018 The Hugo Authors. All rights reserved. 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 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package hugo 15 16 import ( 17 "fmt" 18 "io" 19 "runtime" 20 "strings" 21 22 "github.com/gohugoio/hugo/compare" 23 "github.com/spf13/cast" 24 ) 25 26 // Version represents the Hugo build version. 27 type Version struct { 28 // Major and minor version. 29 Number float32 30 31 // Increment this for bug releases 32 PatchLevel int 33 34 // HugoVersionSuffix is the suffix used in the Hugo version string. 35 // It will be blank for release versions. 36 Suffix string 37 } 38 39 var ( 40 _ compare.Eqer = (*VersionString)(nil) 41 _ compare.Comparer = (*VersionString)(nil) 42 ) 43 44 func (v Version) String() string { 45 return version(v.Number, v.PatchLevel, v.Suffix) 46 } 47 48 // Version returns the Hugo version. 49 func (v Version) Version() VersionString { 50 return VersionString(v.String()) 51 } 52 53 // VersionString represents a Hugo version string. 54 type VersionString string 55 56 func (h VersionString) String() string { 57 return string(h) 58 } 59 60 // Compare implements the compare.Comparer interface. 61 func (h VersionString) Compare(other interface{}) int { 62 v := MustParseVersion(h.String()) 63 return compareVersionsWithSuffix(v.Number, v.PatchLevel, v.Suffix, other) 64 } 65 66 // Eq implements the compare.Eqer interface. 67 func (h VersionString) Eq(other interface{}) bool { 68 s, err := cast.ToStringE(other) 69 if err != nil { 70 return false 71 } 72 return s == h.String() 73 } 74 75 var versionSuffixes = []string{"-test", "-DEV"} 76 77 // ParseVersion parses a version string. 78 func ParseVersion(s string) (Version, error) { 79 var vv Version 80 for _, suffix := range versionSuffixes { 81 if strings.HasSuffix(s, suffix) { 82 vv.Suffix = suffix 83 s = strings.TrimSuffix(s, suffix) 84 } 85 } 86 87 v, p := parseVersion(s) 88 89 vv.Number = v 90 vv.PatchLevel = p 91 92 return vv, nil 93 } 94 95 // MustParseVersion parses a version string 96 // and panics if any error occurs. 97 func MustParseVersion(s string) Version { 98 vv, err := ParseVersion(s) 99 if err != nil { 100 panic(err) 101 } 102 return vv 103 } 104 105 // ReleaseVersion represents the release version. 106 func (v Version) ReleaseVersion() Version { 107 v.Suffix = "" 108 return v 109 } 110 111 // Next returns the next Hugo release version. 112 func (v Version) Next() Version { 113 return Version{Number: v.Number + 0.01} 114 } 115 116 // Prev returns the previous Hugo release version. 117 func (v Version) Prev() Version { 118 return Version{Number: v.Number - 0.01} 119 } 120 121 // NextPatchLevel returns the next patch/bugfix Hugo version. 122 // This will be a patch increment on the previous Hugo version. 123 func (v Version) NextPatchLevel(level int) Version { 124 return Version{Number: v.Number - 0.01, PatchLevel: level} 125 } 126 127 // BuildVersionString creates a version string. This is what you see when 128 // running "hugo version". 129 func BuildVersionString() string { 130 // program := "Hugo Static Site Generator" 131 program := "hugo" 132 133 version := "v" + CurrentVersion.String() 134 if commitHash != "" { 135 version += "-" + strings.ToUpper(commitHash) 136 } 137 if IsExtended { 138 version += "+extended" 139 } 140 141 osArch := runtime.GOOS + "/" + runtime.GOARCH 142 143 date := buildDate 144 if date == "" { 145 date = "unknown" 146 } 147 148 versionString := fmt.Sprintf("%s %s %s BuildDate=%s", 149 program, version, osArch, date) 150 151 if vendorInfo != "" { 152 versionString += " VendorInfo=" + vendorInfo 153 } 154 155 return versionString 156 } 157 158 func version(version float32, patchVersion int, suffix string) string { 159 if patchVersion > 0 || version > 0.53 { 160 return fmt.Sprintf("%.2f.%d%s", version, patchVersion, suffix) 161 } 162 return fmt.Sprintf("%.2f%s", version, suffix) 163 } 164 165 // CompareVersion compares the given version string or number against the 166 // running Hugo version. 167 // It returns -1 if the given version is less than, 0 if equal and 1 if greater than 168 // the running version. 169 func CompareVersion(version interface{}) int { 170 return compareVersionsWithSuffix(CurrentVersion.Number, CurrentVersion.PatchLevel, CurrentVersion.Suffix, version) 171 } 172 173 func compareVersions(inVersion float32, inPatchVersion int, in interface{}) int { 174 return compareVersionsWithSuffix(inVersion, inPatchVersion, "", in) 175 } 176 177 func compareVersionsWithSuffix(inVersion float32, inPatchVersion int, suffix string, in interface{}) int { 178 var c int 179 switch d := in.(type) { 180 case float64: 181 c = compareFloatVersions(inVersion, float32(d)) 182 case float32: 183 c = compareFloatVersions(inVersion, d) 184 case int: 185 c = compareFloatVersions(inVersion, float32(d)) 186 case int32: 187 c = compareFloatVersions(inVersion, float32(d)) 188 case int64: 189 c = compareFloatVersions(inVersion, float32(d)) 190 default: 191 s, err := cast.ToStringE(in) 192 if err != nil { 193 return -1 194 } 195 196 v, err := ParseVersion(s) 197 if err != nil { 198 return -1 199 } 200 201 if v.Number == inVersion && v.PatchLevel == inPatchVersion { 202 return strings.Compare(suffix, v.Suffix) 203 } 204 205 if v.Number < inVersion || (v.Number == inVersion && v.PatchLevel < inPatchVersion) { 206 return -1 207 } 208 209 return 1 210 } 211 212 if c == 0 && suffix != "" { 213 return 1 214 } 215 216 return c 217 } 218 219 func parseVersion(s string) (float32, int) { 220 var ( 221 v float32 222 p int 223 ) 224 225 if strings.Count(s, ".") == 2 { 226 li := strings.LastIndex(s, ".") 227 p = cast.ToInt(s[li+1:]) 228 s = s[:li] 229 } 230 231 v = float32(cast.ToFloat64(s)) 232 233 return v, p 234 } 235 236 func compareFloatVersions(version float32, v float32) int { 237 if v == version { 238 return 0 239 } 240 if v < version { 241 return -1 242 } 243 return 1 244 } 245 246 func GoMinorVersion() int { 247 return goMinorVersion(runtime.Version()) 248 } 249 250 func goMinorVersion(version string) int { 251 if strings.HasPrefix(version, "devel") { 252 return 9999 // magic 253 } 254 var major, minor int 255 var trailing string 256 n, err := fmt.Sscanf(version, "go%d.%d%s", &major, &minor, &trailing) 257 if n == 2 && err == io.EOF { 258 // Means there were no trailing characters (i.e., not an alpha/beta) 259 err = nil 260 } 261 if err != nil { 262 return 0 263 } 264 return minor 265 }