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  }