github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/utils/version/version.go (about)

     1  // Copyright 2022 Dolthub, Inc.
     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  
    23  // Encode encodes a version string in the format "X.Y.Z" into a uint32 (X represents the major version and must be
    24  // numeric and in the range 0-255, Y represents the minor version and must be in the range 0-255, and Z represents the
    25  // build which is in the range 0-65535). The encoded uint32 version uses the highest 8 bits for the major version,
    26  // the next 8 bits for the minor version, and the last 16 used for the build number. Encoded versions are numerically
    27  // comparable (as in the encoded value of the version 1.2.3 will be less than the encoded value of the version 1.11.0)
    28  func Encode(version string) (uint32, error) {
    29  	parts := strings.Split(version, ".")
    30  
    31  	if len(parts) != 3 {
    32  		return 0, fmt.Errorf("version '%s' is not in the format X.X.X", version)
    33  	}
    34  
    35  	partVals := make([]uint64, 3)
    36  	for i := 0; i < 3; i++ {
    37  		var err error
    38  		partVals[i], err = strconv.ParseUint(parts[i], 10, 32)
    39  		if err != nil {
    40  			return 0, fmt.Errorf("failed to parse version '%s'. error at '%s': %w", version, parts[i], err)
    41  		}
    42  	}
    43  
    44  	if partVals[0] > 255 || partVals[1] > 255 || partVals[2] > 65535 {
    45  		return 0, fmt.Errorf("version '%s' cannot be encoded with 8 bits for major, 8 bits for minor, 16 bits for build", version)
    46  	}
    47  
    48  	versionUint32 := (uint32(partVals[0]&0xFF) << 24) | (uint32(partVals[1]&0xFF) << 16) | uint32(partVals[2]&0xFFFF)
    49  	return versionUint32, nil
    50  }
    51  
    52  // Decode converts the uint32 encoding of the version (described by the Encode method) back to its string representation.
    53  func Decode(version uint32) string {
    54  	major := (version & 0xFF000000) >> 24
    55  	minor := (version & 0x00FF0000) >> 16
    56  	build := version & 0x0000FFFF
    57  
    58  	majorStr := strconv.FormatUint(uint64(major), 10)
    59  	minorStr := strconv.FormatUint(uint64(minor), 10)
    60  	buildStr := strconv.FormatUint(uint64(build), 10)
    61  
    62  	return majorStr + "." + minorStr + "." + buildStr
    63  }