diff --git a/.golangci.yml b/.golangci.yml index 38ac40f70..cf2fe615c 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -72,6 +72,10 @@ issues: linters-settings: depguard: rules: + go-version: + deny: + # Use "github.com/Masterminds/semver/v3" instead. + - pkg: github.com/hashicorp/go-version ioutil: deny: - pkg: "io/ioutil" diff --git a/LICENSES/github.com/Masterminds/semver/v3/LICENSE.txt b/LICENSES/github.com/Masterminds/semver/v3/LICENSE.txt new file mode 100644 index 000000000..9ff7da9c4 --- /dev/null +++ b/LICENSES/github.com/Masterminds/semver/v3/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (C) 2014-2019, Matt Butcher and Matt Farina + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/LICENSES/github.com/hashicorp/go-version/.github/dependabot.yml b/LICENSES/github.com/hashicorp/go-version/.github/dependabot.yml deleted file mode 100644 index f401df1ef..000000000 --- a/LICENSES/github.com/hashicorp/go-version/.github/dependabot.yml +++ /dev/null @@ -1,25 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "gomod" - directory: "/" - schedule: - interval: "daily" - labels: ["dependencies"] - - - package-ecosystem: github-actions - directory: / - schedule: - interval: monthly - labels: - - dependencies - # only update HashiCorp actions, external actions managed by TSCCR - allow: - - dependency-name: hashicorp/* - groups: - github-actions-breaking: - update-types: - - major - github-actions-backward-compatible: - update-types: - - minor - - patch diff --git a/LICENSES/github.com/hashicorp/go-version/.github/workflows/go-tests.yml b/LICENSES/github.com/hashicorp/go-version/.github/workflows/go-tests.yml deleted file mode 100644 index ca6882a70..000000000 --- a/LICENSES/github.com/hashicorp/go-version/.github/workflows/go-tests.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: go-tests - -on: [push] - -env: - TEST_RESULTS: /tmp/test-results - -jobs: - - go-tests: - runs-on: ubuntu-latest - strategy: - matrix: - go-version: [ 1.15.3, 1.19 ] - - steps: - - name: Setup go - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 - with: - go-version: ${{ matrix.go-version }} - - - name: Checkout code - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 - - - name: Create test directory - run: | - mkdir -p ${{ env.TEST_RESULTS }} - - - name: Download go modules - run: go mod download - - - name: Cache / restore go modules - uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0 # v3.2.6 - with: - path: | - ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - - # Check go fmt output because it does not report non-zero when there are fmt changes - - name: Run gofmt - run: | - go fmt ./... - files=$(go fmt ./...) - if [ -n "$files" ]; then - echo "The following file(s) do not conform to go fmt:" - echo "$files" - exit 1 - fi - - # Install gotestsum with go get for 1.15.3; otherwise default to go install - - name: Install gotestsum - run: | - GTS="gotest.tools/gotestsum@v1.8.2" - # We use the same error message prefix in either failure case, so just define it once here. - ERROR="Failed to install $GTS" - # First try to 'go install', if that fails try 'go get'... - go install "$GTS" || go get "$GTS" || { echo "$ERROR: both 'go install' and 'go get' failed"; exit 1; } - # Check that the gotestsum command was actually installed in the path... - command -v gotestsum > /dev/null 2>&1 || { echo "$ERROR: gotestsum command not installed"; exit 1; } - echo "OK: Command 'gotestsum' installed ($GTS)" - - - name: Run go tests - run: | - PACKAGE_NAMES=$(go list ./...) - gotestsum --format=short-verbose --junitfile $TEST_RESULTS/gotestsum-report.xml -- $PACKAGE_NAMES - - # Save coverage report parts - - name: Upload and save artifacts - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 - with: - name: Test Results - path: ${{ env.TEST_RESULTS }} \ No newline at end of file diff --git a/LICENSES/github.com/hashicorp/go-version/CHANGELOG.md b/LICENSES/github.com/hashicorp/go-version/CHANGELOG.md deleted file mode 100644 index 6d48174bf..000000000 --- a/LICENSES/github.com/hashicorp/go-version/CHANGELOG.md +++ /dev/null @@ -1,64 +0,0 @@ -# 1.7.0 (May 24, 2024) - -ENHANCEMENTS: - -- Remove `reflect` dependency ([#91](https://github.com/hashicorp/go-version/pull/91)) -- Implement the `database/sql.Scanner` and `database/sql/driver.Value` interfaces for `Version` ([#133](https://github.com/hashicorp/go-version/pull/133)) - -INTERNAL: - -- [COMPLIANCE] Add Copyright and License Headers ([#115](https://github.com/hashicorp/go-version/pull/115)) -- [COMPLIANCE] Update MPL-2.0 LICENSE ([#105](https://github.com/hashicorp/go-version/pull/105)) -- Bump actions/cache from 3.0.11 to 3.2.5 ([#116](https://github.com/hashicorp/go-version/pull/116)) -- Bump actions/checkout from 3.2.0 to 3.3.0 ([#111](https://github.com/hashicorp/go-version/pull/111)) -- Bump actions/upload-artifact from 3.1.1 to 3.1.2 ([#112](https://github.com/hashicorp/go-version/pull/112)) -- GHA Migration ([#103](https://github.com/hashicorp/go-version/pull/103)) -- github: Pin external GitHub Actions to hashes ([#107](https://github.com/hashicorp/go-version/pull/107)) -- SEC-090: Automated trusted workflow pinning (2023-04-05) ([#124](https://github.com/hashicorp/go-version/pull/124)) -- update readme ([#104](https://github.com/hashicorp/go-version/pull/104)) - -# 1.6.0 (June 28, 2022) - -FEATURES: - -- Add `Prerelease` function to `Constraint` to return true if the version includes a prerelease field ([#100](https://github.com/hashicorp/go-version/pull/100)) - -# 1.5.0 (May 18, 2022) - -FEATURES: - -- Use `encoding` `TextMarshaler` & `TextUnmarshaler` instead of JSON equivalents ([#95](https://github.com/hashicorp/go-version/pull/95)) -- Add JSON handlers to allow parsing from/to JSON ([#93](https://github.com/hashicorp/go-version/pull/93)) - -# 1.4.0 (January 5, 2022) - -FEATURES: - - - Introduce `MustConstraints()` ([#87](https://github.com/hashicorp/go-version/pull/87)) - - `Constraints`: Introduce `Equals()` and `sort.Interface` methods ([#88](https://github.com/hashicorp/go-version/pull/88)) - -# 1.3.0 (March 31, 2021) - -Please note that CHANGELOG.md does not exist in the source code prior to this release. - -FEATURES: - - Add `Core` function to return a version without prerelease or metadata ([#85](https://github.com/hashicorp/go-version/pull/85)) - -# 1.2.1 (June 17, 2020) - -BUG FIXES: - - Prevent `Version.Equal` method from panicking on `nil` encounter ([#73](https://github.com/hashicorp/go-version/pull/73)) - -# 1.2.0 (April 23, 2019) - -FEATURES: - - Add `GreaterThanOrEqual` and `LessThanOrEqual` helper methods ([#53](https://github.com/hashicorp/go-version/pull/53)) - -# 1.1.0 (Jan 07, 2019) - -FEATURES: - - Add `NewSemver` constructor ([#45](https://github.com/hashicorp/go-version/pull/45)) - -# 1.0.0 (August 24, 2018) - -Initial release. diff --git a/LICENSES/github.com/hashicorp/go-version/LICENSE b/LICENSES/github.com/hashicorp/go-version/LICENSE deleted file mode 100644 index 1409d6ab9..000000000 --- a/LICENSES/github.com/hashicorp/go-version/LICENSE +++ /dev/null @@ -1,356 +0,0 @@ -Copyright (c) 2014 HashiCorp, Inc. - -Mozilla Public License, version 2.0 - -1. Definitions - -1.1. “Contributor” - - means each individual or legal entity that creates, contributes to the - creation of, or owns Covered Software. - -1.2. “Contributor Version” - - means the combination of the Contributions of others (if any) used by a - Contributor and that particular Contributor’s Contribution. - -1.3. “Contribution” - - means Covered Software of a particular Contributor. - -1.4. “Covered Software” - - means Source Code Form to which the initial Contributor has attached the - notice in Exhibit A, the Executable Form of such Source Code Form, and - Modifications of such Source Code Form, in each case including portions - thereof. - -1.5. “Incompatible With Secondary Licenses” - means - - a. that the initial Contributor has attached the notice described in - Exhibit B to the Covered Software; or - - b. that the Covered Software was made available under the terms of version - 1.1 or earlier of the License, but not also under the terms of a - Secondary License. - -1.6. “Executable Form” - - means any form of the work other than Source Code Form. - -1.7. “Larger Work” - - means a work that combines Covered Software with other material, in a separate - file or files, that is not Covered Software. - -1.8. “License” - - means this document. - -1.9. “Licensable” - - means having the right to grant, to the maximum extent possible, whether at the - time of the initial grant or subsequently, any and all of the rights conveyed by - this License. - -1.10. “Modifications” - - means any of the following: - - a. any file in Source Code Form that results from an addition to, deletion - from, or modification of the contents of Covered Software; or - - b. any new file in Source Code Form that contains any Covered Software. - -1.11. “Patent Claims” of a Contributor - - means any patent claim(s), including without limitation, method, process, - and apparatus claims, in any patent Licensable by such Contributor that - would be infringed, but for the grant of the License, by the making, - using, selling, offering for sale, having made, import, or transfer of - either its Contributions or its Contributor Version. - -1.12. “Secondary License” - - means either the GNU General Public License, Version 2.0, the GNU Lesser - General Public License, Version 2.1, the GNU Affero General Public - License, Version 3.0, or any later versions of those licenses. - -1.13. “Source Code Form” - - means the form of the work preferred for making modifications. - -1.14. “You” (or “Your”) - - means an individual or a legal entity exercising rights under this - License. For legal entities, “You” includes any entity that controls, is - controlled by, or is under common control with You. For purposes of this - definition, “control” means (a) the power, direct or indirect, to cause - the direction or management of such entity, whether by contract or - otherwise, or (b) ownership of more than fifty percent (50%) of the - outstanding shares or beneficial ownership of such entity. - - -2. License Grants and Conditions - -2.1. Grants - - Each Contributor hereby grants You a world-wide, royalty-free, - non-exclusive license: - - a. under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or as - part of a Larger Work; and - - b. under Patent Claims of such Contributor to make, use, sell, offer for - sale, have made, import, and otherwise transfer either its Contributions - or its Contributor Version. - -2.2. Effective Date - - The licenses granted in Section 2.1 with respect to any Contribution become - effective for each Contribution on the date the Contributor first distributes - such Contribution. - -2.3. Limitations on Grant Scope - - The licenses granted in this Section 2 are the only rights granted under this - License. No additional rights or licenses will be implied from the distribution - or licensing of Covered Software under this License. Notwithstanding Section - 2.1(b) above, no patent license is granted by a Contributor: - - a. for any code that a Contributor has removed from Covered Software; or - - b. for infringements caused by: (i) Your and any other third party’s - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - - c. under Patent Claims infringed by Covered Software in the absence of its - Contributions. - - This License does not grant any rights in the trademarks, service marks, or - logos of any Contributor (except as may be necessary to comply with the - notice requirements in Section 3.4). - -2.4. Subsequent Licenses - - No Contributor makes additional grants as a result of Your choice to - distribute the Covered Software under a subsequent version of this License - (see Section 10.2) or under the terms of a Secondary License (if permitted - under the terms of Section 3.3). - -2.5. Representation - - Each Contributor represents that the Contributor believes its Contributions - are its original creation(s) or it has sufficient rights to grant the - rights to its Contributions conveyed by this License. - -2.6. Fair Use - - This License is not intended to limit any rights You have under applicable - copyright doctrines of fair use, fair dealing, or other equivalents. - -2.7. Conditions - - Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in - Section 2.1. - - -3. Responsibilities - -3.1. Distribution of Source Form - - All distribution of Covered Software in Source Code Form, including any - Modifications that You create or to which You contribute, must be under the - terms of this License. You must inform recipients that the Source Code Form - of the Covered Software is governed by the terms of this License, and how - they can obtain a copy of this License. You may not attempt to alter or - restrict the recipients’ rights in the Source Code Form. - -3.2. Distribution of Executable Form - - If You distribute Covered Software in Executable Form then: - - a. such Covered Software must also be made available in Source Code Form, - as described in Section 3.1, and You must inform recipients of the - Executable Form how they can obtain a copy of such Source Code Form by - reasonable means in a timely manner, at a charge no more than the cost - of distribution to the recipient; and - - b. You may distribute such Executable Form under the terms of this License, - or sublicense it under different terms, provided that the license for - the Executable Form does not attempt to limit or alter the recipients’ - rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - - You may create and distribute a Larger Work under terms of Your choice, - provided that You also comply with the requirements of this License for the - Covered Software. If the Larger Work is a combination of Covered Software - with a work governed by one or more Secondary Licenses, and the Covered - Software is not Incompatible With Secondary Licenses, this License permits - You to additionally distribute such Covered Software under the terms of - such Secondary License(s), so that the recipient of the Larger Work may, at - their option, further distribute the Covered Software under the terms of - either this License or such Secondary License(s). - -3.4. Notices - - You may not remove or alter the substance of any license notices (including - copyright notices, patent notices, disclaimers of warranty, or limitations - of liability) contained within the Source Code Form of the Covered - Software, except that You may alter any license notices to the extent - required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - - You may choose to offer, and to charge a fee for, warranty, support, - indemnity or liability obligations to one or more recipients of Covered - Software. However, You may do so only on Your own behalf, and not on behalf - of any Contributor. You must make it absolutely clear that any such - warranty, support, indemnity, or liability obligation is offered by You - alone, and You hereby agree to indemnify every Contributor for any - liability incurred by such Contributor as a result of warranty, support, - indemnity or liability terms You offer. You may include additional - disclaimers of warranty and limitations of liability specific to any - jurisdiction. - -4. Inability to Comply Due to Statute or Regulation - - If it is impossible for You to comply with any of the terms of this License - with respect to some or all of the Covered Software due to statute, judicial - order, or regulation then You must: (a) comply with the terms of this License - to the maximum extent possible; and (b) describe the limitations and the code - they affect. Such description must be placed in a text file included with all - distributions of the Covered Software under this License. Except to the - extent prohibited by statute or regulation, such description must be - sufficiently detailed for a recipient of ordinary skill to be able to - understand it. - -5. Termination - -5.1. The rights granted under this License will terminate automatically if You - fail to comply with any of its terms. However, if You become compliant, - then the rights granted under this License from a particular Contributor - are reinstated (a) provisionally, unless and until such Contributor - explicitly and finally terminates Your grants, and (b) on an ongoing basis, - if such Contributor fails to notify You of the non-compliance by some - reasonable means prior to 60 days after You have come back into compliance. - Moreover, Your grants from a particular Contributor are reinstated on an - ongoing basis if such Contributor notifies You of the non-compliance by - some reasonable means, this is the first time You have received notice of - non-compliance with this License from such Contributor, and You become - compliant prior to 30 days after Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent - infringement claim (excluding declaratory judgment actions, counter-claims, - and cross-claims) alleging that a Contributor Version directly or - indirectly infringes any patent, then the rights granted to You by any and - all Contributors for the Covered Software under Section 2.1 of this License - shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user - license agreements (excluding distributors and resellers) which have been - validly granted by You or Your distributors under this License prior to - termination shall survive termination. - -6. Disclaimer of Warranty - - Covered Software is provided under this License on an “as is” basis, without - warranty of any kind, either expressed, implied, or statutory, including, - without limitation, warranties that the Covered Software is free of defects, - merchantable, fit for a particular purpose or non-infringing. The entire - risk as to the quality and performance of the Covered Software is with You. - Should any Covered Software prove defective in any respect, You (not any - Contributor) assume the cost of any necessary servicing, repair, or - correction. This disclaimer of warranty constitutes an essential part of this - License. No use of any Covered Software is authorized under this License - except under this disclaimer. - -7. Limitation of Liability - - Under no circumstances and under no legal theory, whether tort (including - negligence), contract, or otherwise, shall any Contributor, or anyone who - distributes Covered Software as permitted above, be liable to You for any - direct, indirect, special, incidental, or consequential damages of any - character including, without limitation, damages for lost profits, loss of - goodwill, work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses, even if such party shall have been - informed of the possibility of such damages. This limitation of liability - shall not apply to liability for death or personal injury resulting from such - party’s negligence to the extent applicable law prohibits such limitation. - Some jurisdictions do not allow the exclusion or limitation of incidental or - consequential damages, so this exclusion and limitation may not apply to You. - -8. Litigation - - Any litigation relating to this License may be brought only in the courts of - a jurisdiction where the defendant maintains its principal place of business - and such litigation shall be governed by laws of that jurisdiction, without - reference to its conflict-of-law provisions. Nothing in this Section shall - prevent a party’s ability to bring cross-claims or counter-claims. - -9. Miscellaneous - - This License represents the complete agreement concerning the subject matter - hereof. If any provision of this License is held to be unenforceable, such - provision shall be reformed only to the extent necessary to make it - enforceable. Any law or regulation which provides that the language of a - contract shall be construed against the drafter shall not be used to construe - this License against a Contributor. - - -10. Versions of the License - -10.1. New Versions - - Mozilla Foundation is the license steward. Except as provided in Section - 10.3, no one other than the license steward has the right to modify or - publish new versions of this License. Each version will be given a - distinguishing version number. - -10.2. Effect of New Versions - - You may distribute the Covered Software under the terms of the version of - the License under which You originally received the Covered Software, or - under the terms of any subsequent version published by the license - steward. - -10.3. Modified Versions - - If you create software not governed by this License, and you want to - create a new license for such software, you may create and use a modified - version of this License if you rename the license and remove any - references to the name of the license steward (except to note that such - modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses - If You choose to distribute Source Code Form that is Incompatible With - Secondary Licenses under the terms of this version of the License, the - notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice - - This Source Code Form is subject to the - terms of the Mozilla Public License, v. - 2.0. If a copy of the MPL was not - distributed with this file, You can - obtain one at - http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular file, then -You may include the notice in a location (such as a LICENSE file in a relevant -directory) where a recipient would be likely to look for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - “Incompatible With Secondary Licenses” Notice - - This Source Code Form is “Incompatible - With Secondary Licenses”, as defined by - the Mozilla Public License, v. 2.0. - diff --git a/LICENSES/github.com/hashicorp/go-version/README.md b/LICENSES/github.com/hashicorp/go-version/README.md deleted file mode 100644 index 4b7806cd9..000000000 --- a/LICENSES/github.com/hashicorp/go-version/README.md +++ /dev/null @@ -1,66 +0,0 @@ -# Versioning Library for Go -![Build Status](https://github.com/hashicorp/go-version/actions/workflows/go-tests.yml/badge.svg) -[![GoDoc](https://godoc.org/github.com/hashicorp/go-version?status.svg)](https://godoc.org/github.com/hashicorp/go-version) - -go-version is a library for parsing versions and version constraints, -and verifying versions against a set of constraints. go-version -can sort a collection of versions properly, handles prerelease/beta -versions, can increment versions, etc. - -Versions used with go-version must follow [SemVer](http://semver.org/). - -## Installation and Usage - -Package documentation can be found on -[GoDoc](http://godoc.org/github.com/hashicorp/go-version). - -Installation can be done with a normal `go get`: - -``` -$ go get github.com/hashicorp/go-version -``` - -#### Version Parsing and Comparison - -```go -v1, err := version.NewVersion("1.2") -v2, err := version.NewVersion("1.5+metadata") - -// Comparison example. There is also GreaterThan, Equal, and just -// a simple Compare that returns an int allowing easy >=, <=, etc. -if v1.LessThan(v2) { - fmt.Printf("%s is less than %s", v1, v2) -} -``` - -#### Version Constraints - -```go -v1, err := version.NewVersion("1.2") - -// Constraints example. -constraints, err := version.NewConstraint(">= 1.0, < 1.4") -if constraints.Check(v1) { - fmt.Printf("%s satisfies constraints %s", v1, constraints) -} -``` - -#### Version Sorting - -```go -versionsRaw := []string{"1.1", "0.7.1", "1.4-beta", "1.4", "2"} -versions := make([]*version.Version, len(versionsRaw)) -for i, raw := range versionsRaw { - v, _ := version.NewVersion(raw) - versions[i] = v -} - -// After this, the versions are properly sorted -sort.Sort(version.Collection(versions)) -``` - -## Issues and Contributing - -If you find an issue with this library, please report an issue. If you'd -like, we welcome any contributions. Fork this library and submit a pull -request. diff --git a/LICENSES/github.com/hashicorp/go-version/constraint.go b/LICENSES/github.com/hashicorp/go-version/constraint.go deleted file mode 100644 index 29bdc4d2b..000000000 --- a/LICENSES/github.com/hashicorp/go-version/constraint.go +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package version - -import ( - "fmt" - "regexp" - "sort" - "strings" -) - -// Constraint represents a single constraint for a version, such as -// ">= 1.0". -type Constraint struct { - f constraintFunc - op operator - check *Version - original string -} - -func (c *Constraint) Equals(con *Constraint) bool { - return c.op == con.op && c.check.Equal(con.check) -} - -// Constraints is a slice of constraints. We make a custom type so that -// we can add methods to it. -type Constraints []*Constraint - -type constraintFunc func(v, c *Version) bool - -var constraintOperators map[string]constraintOperation - -type constraintOperation struct { - op operator - f constraintFunc -} - -var constraintRegexp *regexp.Regexp - -func init() { - constraintOperators = map[string]constraintOperation{ - "": {op: equal, f: constraintEqual}, - "=": {op: equal, f: constraintEqual}, - "!=": {op: notEqual, f: constraintNotEqual}, - ">": {op: greaterThan, f: constraintGreaterThan}, - "<": {op: lessThan, f: constraintLessThan}, - ">=": {op: greaterThanEqual, f: constraintGreaterThanEqual}, - "<=": {op: lessThanEqual, f: constraintLessThanEqual}, - "~>": {op: pessimistic, f: constraintPessimistic}, - } - - ops := make([]string, 0, len(constraintOperators)) - for k := range constraintOperators { - ops = append(ops, regexp.QuoteMeta(k)) - } - - constraintRegexp = regexp.MustCompile(fmt.Sprintf( - `^\s*(%s)\s*(%s)\s*$`, - strings.Join(ops, "|"), - VersionRegexpRaw)) -} - -// NewConstraint will parse one or more constraints from the given -// constraint string. The string must be a comma-separated list of -// constraints. -func NewConstraint(v string) (Constraints, error) { - vs := strings.Split(v, ",") - result := make([]*Constraint, len(vs)) - for i, single := range vs { - c, err := parseSingle(single) - if err != nil { - return nil, err - } - - result[i] = c - } - - return Constraints(result), nil -} - -// MustConstraints is a helper that wraps a call to a function -// returning (Constraints, error) and panics if error is non-nil. -func MustConstraints(c Constraints, err error) Constraints { - if err != nil { - panic(err) - } - - return c -} - -// Check tests if a version satisfies all the constraints. -func (cs Constraints) Check(v *Version) bool { - for _, c := range cs { - if !c.Check(v) { - return false - } - } - - return true -} - -// Equals compares Constraints with other Constraints -// for equality. This may not represent logical equivalence -// of compared constraints. -// e.g. even though '>0.1,>0.2' is logically equivalent -// to '>0.2' it is *NOT* treated as equal. -// -// Missing operator is treated as equal to '=', whitespaces -// are ignored and constraints are sorted before comaparison. -func (cs Constraints) Equals(c Constraints) bool { - if len(cs) != len(c) { - return false - } - - // make copies to retain order of the original slices - left := make(Constraints, len(cs)) - copy(left, cs) - sort.Stable(left) - right := make(Constraints, len(c)) - copy(right, c) - sort.Stable(right) - - // compare sorted slices - for i, con := range left { - if !con.Equals(right[i]) { - return false - } - } - - return true -} - -func (cs Constraints) Len() int { - return len(cs) -} - -func (cs Constraints) Less(i, j int) bool { - if cs[i].op < cs[j].op { - return true - } - if cs[i].op > cs[j].op { - return false - } - - return cs[i].check.LessThan(cs[j].check) -} - -func (cs Constraints) Swap(i, j int) { - cs[i], cs[j] = cs[j], cs[i] -} - -// Returns the string format of the constraints -func (cs Constraints) String() string { - csStr := make([]string, len(cs)) - for i, c := range cs { - csStr[i] = c.String() - } - - return strings.Join(csStr, ",") -} - -// Check tests if a constraint is validated by the given version. -func (c *Constraint) Check(v *Version) bool { - return c.f(v, c.check) -} - -// Prerelease returns true if the version underlying this constraint -// contains a prerelease field. -func (c *Constraint) Prerelease() bool { - return len(c.check.Prerelease()) > 0 -} - -func (c *Constraint) String() string { - return c.original -} - -func parseSingle(v string) (*Constraint, error) { - matches := constraintRegexp.FindStringSubmatch(v) - if matches == nil { - return nil, fmt.Errorf("Malformed constraint: %s", v) - } - - check, err := NewVersion(matches[2]) - if err != nil { - return nil, err - } - - cop := constraintOperators[matches[1]] - - return &Constraint{ - f: cop.f, - op: cop.op, - check: check, - original: v, - }, nil -} - -func prereleaseCheck(v, c *Version) bool { - switch vPre, cPre := v.Prerelease() != "", c.Prerelease() != ""; { - case cPre && vPre: - // A constraint with a pre-release can only match a pre-release version - // with the same base segments. - return v.equalSegments(c) - - case !cPre && vPre: - // A constraint without a pre-release can only match a version without a - // pre-release. - return false - - case cPre && !vPre: - // OK, except with the pessimistic operator - case !cPre && !vPre: - // OK - } - return true -} - -//------------------------------------------------------------------- -// Constraint functions -//------------------------------------------------------------------- - -type operator rune - -const ( - equal operator = '=' - notEqual operator = '≠' - greaterThan operator = '>' - lessThan operator = '<' - greaterThanEqual operator = '≥' - lessThanEqual operator = '≤' - pessimistic operator = '~' -) - -func constraintEqual(v, c *Version) bool { - return v.Equal(c) -} - -func constraintNotEqual(v, c *Version) bool { - return !v.Equal(c) -} - -func constraintGreaterThan(v, c *Version) bool { - return prereleaseCheck(v, c) && v.Compare(c) == 1 -} - -func constraintLessThan(v, c *Version) bool { - return prereleaseCheck(v, c) && v.Compare(c) == -1 -} - -func constraintGreaterThanEqual(v, c *Version) bool { - return prereleaseCheck(v, c) && v.Compare(c) >= 0 -} - -func constraintLessThanEqual(v, c *Version) bool { - return prereleaseCheck(v, c) && v.Compare(c) <= 0 -} - -func constraintPessimistic(v, c *Version) bool { - // Using a pessimistic constraint with a pre-release, restricts versions to pre-releases - if !prereleaseCheck(v, c) || (c.Prerelease() != "" && v.Prerelease() == "") { - return false - } - - // If the version being checked is naturally less than the constraint, then there - // is no way for the version to be valid against the constraint - if v.LessThan(c) { - return false - } - // We'll use this more than once, so grab the length now so it's a little cleaner - // to write the later checks - cs := len(c.segments) - - // If the version being checked has less specificity than the constraint, then there - // is no way for the version to be valid against the constraint - if cs > len(v.segments) { - return false - } - - // Check the segments in the constraint against those in the version. If the version - // being checked, at any point, does not have the same values in each index of the - // constraints segments, then it cannot be valid against the constraint. - for i := 0; i < c.si-1; i++ { - if v.segments[i] != c.segments[i] { - return false - } - } - - // Check the last part of the segment in the constraint. If the version segment at - // this index is less than the constraints segment at this index, then it cannot - // be valid against the constraint - if c.segments[cs-1] > v.segments[cs-1] { - return false - } - - // If nothing has rejected the version by now, it's valid - return true -} diff --git a/LICENSES/github.com/hashicorp/go-version/constraint_test.go b/LICENSES/github.com/hashicorp/go-version/constraint_test.go deleted file mode 100644 index e76d3b0d5..000000000 --- a/LICENSES/github.com/hashicorp/go-version/constraint_test.go +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package version - -import ( - "fmt" - "reflect" - "sort" - "testing" -) - -func TestNewConstraint(t *testing.T) { - cases := []struct { - input string - count int - err bool - }{ - {">= 1.2", 1, false}, - {"1.0", 1, false}, - {">= 1.x", 0, true}, - {">= 1.2, < 1.0", 2, false}, - - // Out of bounds - {"11387778780781445675529500000000000000000", 0, true}, - } - - for _, tc := range cases { - v, err := NewConstraint(tc.input) - if tc.err && err == nil { - t.Fatalf("expected error for input: %s", tc.input) - } else if !tc.err && err != nil { - t.Fatalf("error for input %s: %s", tc.input, err) - } - - if len(v) != tc.count { - t.Fatalf("input: %s\nexpected len: %d\nactual: %d", - tc.input, tc.count, len(v)) - } - } -} - -func TestConstraintCheck(t *testing.T) { - cases := []struct { - constraint string - version string - check bool - }{ - {">= 1.0, < 1.2", "1.1.5", true}, - {"< 1.0, < 1.2", "1.1.5", false}, - {"= 1.0", "1.1.5", false}, - {"= 1.0", "1.0.0", true}, - {"1.0", "1.0.0", true}, - {"~> 1.0", "2.0", false}, - {"~> 1.0", "1.1", true}, - {"~> 1.0", "1.2.3", true}, - {"~> 1.0.0", "1.2.3", false}, - {"~> 1.0.0", "1.0.7", true}, - {"~> 1.0.0", "1.1.0", false}, - {"~> 1.0.7", "1.0.4", false}, - {"~> 1.0.7", "1.0.7", true}, - {"~> 1.0.7", "1.0.8", true}, - {"~> 1.0.7", "1.0.7.5", true}, - {"~> 1.0.7", "1.0.6.99", false}, - {"~> 1.0.7", "1.0.8.0", true}, - {"~> 1.0.9.5", "1.0.9.5", true}, - {"~> 1.0.9.5", "1.0.9.4", false}, - {"~> 1.0.9.5", "1.0.9.6", true}, - {"~> 1.0.9.5", "1.0.9.5.0", true}, - {"~> 1.0.9.5", "1.0.9.5.1", true}, - {"~> 2.0", "2.1.0-beta", false}, - {"~> 2.1.0-a", "2.2.0", false}, - {"~> 2.1.0-a", "2.1.0", false}, - {"~> 2.1.0-a", "2.1.0-beta", true}, - {"~> 2.1.0-a", "2.2.0-alpha", false}, - {"> 2.0", "2.1.0-beta", false}, - {">= 2.1.0-a", "2.1.0-beta", true}, - {">= 2.1.0-a", "2.1.1-beta", false}, - {">= 2.0.0", "2.1.0-beta", false}, - {">= 2.1.0-a", "2.1.1", true}, - {">= 2.1.0-a", "2.1.1-beta", false}, - {">= 2.1.0-a", "2.1.0", true}, - {"<= 2.1.0-a", "2.0.0", true}, - } - - for _, tc := range cases { - c, err := NewConstraint(tc.constraint) - if err != nil { - t.Fatalf("err: %s", err) - } - - v, err := NewVersion(tc.version) - if err != nil { - t.Fatalf("err: %s", err) - } - - actual := c.Check(v) - expected := tc.check - if actual != expected { - t.Fatalf("Version: %s\nConstraint: %s\nExpected: %#v", - tc.version, tc.constraint, expected) - } - } -} - -func TestConstraintPrerelease(t *testing.T) { - cases := []struct { - constraint string - prerelease bool - }{ - {"= 1.0", false}, - {"= 1.0-beta", true}, - {"~> 2.1.0", false}, - {"~> 2.1.0-dev", true}, - {"> 2.0", false}, - {">= 2.1.0-a", true}, - } - - for _, tc := range cases { - c, err := parseSingle(tc.constraint) - if err != nil { - t.Fatalf("err: %s", err) - } - - actual := c.Prerelease() - expected := tc.prerelease - if actual != expected { - t.Fatalf("Constraint: %s\nExpected: %#v", - tc.constraint, expected) - } - } -} - -func TestConstraintEqual(t *testing.T) { - cases := []struct { - leftConstraint string - rightConstraint string - expectedEqual bool - }{ - { - "0.0.1", - "0.0.1", - true, - }, - { // whitespaces - " 0.0.1 ", - "0.0.1", - true, - }, - { // equal op implied - "=0.0.1 ", - "0.0.1", - true, - }, - { // version difference - "=0.0.1", - "=0.0.2", - false, - }, - { // operator difference - ">0.0.1", - "=0.0.1", - false, - }, - { // different order - ">0.1.0, <=1.0.0", - "<=1.0.0, >0.1.0", - true, - }, - } - - for _, tc := range cases { - leftCon, err := NewConstraint(tc.leftConstraint) - if err != nil { - t.Fatalf("err: %s", err) - } - rightCon, err := NewConstraint(tc.rightConstraint) - if err != nil { - t.Fatalf("err: %s", err) - } - - actual := leftCon.Equals(rightCon) - if actual != tc.expectedEqual { - t.Fatalf("Constraints: %s vs %s\nExpected: %t\nActual: %t", - tc.leftConstraint, tc.rightConstraint, tc.expectedEqual, actual) - } - } -} - -func TestConstraint_sort(t *testing.T) { - cases := []struct { - constraint string - expectedConstraints string - }{ - { - ">= 0.1.0,< 1.12", - "< 1.12,>= 0.1.0", - }, - { - "< 1.12,>= 0.1.0", - "< 1.12,>= 0.1.0", - }, - { - "< 1.12,>= 0.1.0,0.2.0", - "< 1.12,0.2.0,>= 0.1.0", - }, - { - ">1.0,>0.1.0,>0.3.0,>0.2.0", - ">0.1.0,>0.2.0,>0.3.0,>1.0", - }, - } - - for i, tc := range cases { - t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { - c, err := NewConstraint(tc.constraint) - if err != nil { - t.Fatalf("err: %s", err) - } - - sort.Sort(c) - - actual := c.String() - - if !reflect.DeepEqual(actual, tc.expectedConstraints) { - t.Fatalf("unexpected order\nexpected: %#v\nactual: %#v", - tc.expectedConstraints, actual) - } - }) - } -} - -func TestConstraintsString(t *testing.T) { - cases := []struct { - constraint string - result string - }{ - {">= 1.0, < 1.2", ""}, - {"~> 1.0.7", ""}, - } - - for _, tc := range cases { - c, err := NewConstraint(tc.constraint) - if err != nil { - t.Fatalf("err: %s", err) - } - - actual := c.String() - expected := tc.result - if expected == "" { - expected = tc.constraint - } - - if actual != expected { - t.Fatalf("Constraint: %s\nExpected: %#v\nActual: %s", - tc.constraint, expected, actual) - } - } -} diff --git a/LICENSES/github.com/hashicorp/go-version/go.mod b/LICENSES/github.com/hashicorp/go-version/go.mod deleted file mode 100644 index f5285555f..000000000 --- a/LICENSES/github.com/hashicorp/go-version/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/hashicorp/go-version diff --git a/LICENSES/github.com/hashicorp/go-version/version.go b/LICENSES/github.com/hashicorp/go-version/version.go deleted file mode 100644 index 7c683c281..000000000 --- a/LICENSES/github.com/hashicorp/go-version/version.go +++ /dev/null @@ -1,441 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package version - -import ( - "bytes" - "database/sql/driver" - "fmt" - "regexp" - "strconv" - "strings" -) - -// The compiled regular expression used to test the validity of a version. -var ( - versionRegexp *regexp.Regexp - semverRegexp *regexp.Regexp -) - -// The raw regular expression string used for testing the validity -// of a version. -const ( - VersionRegexpRaw string = `v?([0-9]+(\.[0-9]+)*?)` + - `(-([0-9]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)|(-?([A-Za-z\-~]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)))?` + - `(\+([0-9A-Za-z\-~]+(\.[0-9A-Za-z\-~]+)*))?` + - `?` - - // SemverRegexpRaw requires a separator between version and prerelease - SemverRegexpRaw string = `v?([0-9]+(\.[0-9]+)*?)` + - `(-([0-9]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)|(-([A-Za-z\-~]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)))?` + - `(\+([0-9A-Za-z\-~]+(\.[0-9A-Za-z\-~]+)*))?` + - `?` -) - -// Version represents a single version. -type Version struct { - metadata string - pre string - segments []int64 - si int - original string -} - -func init() { - versionRegexp = regexp.MustCompile("^" + VersionRegexpRaw + "$") - semverRegexp = regexp.MustCompile("^" + SemverRegexpRaw + "$") -} - -// NewVersion parses the given version and returns a new -// Version. -func NewVersion(v string) (*Version, error) { - return newVersion(v, versionRegexp) -} - -// NewSemver parses the given version and returns a new -// Version that adheres strictly to SemVer specs -// https://semver.org/ -func NewSemver(v string) (*Version, error) { - return newVersion(v, semverRegexp) -} - -func newVersion(v string, pattern *regexp.Regexp) (*Version, error) { - matches := pattern.FindStringSubmatch(v) - if matches == nil { - return nil, fmt.Errorf("Malformed version: %s", v) - } - segmentsStr := strings.Split(matches[1], ".") - segments := make([]int64, len(segmentsStr)) - for i, str := range segmentsStr { - val, err := strconv.ParseInt(str, 10, 64) - if err != nil { - return nil, fmt.Errorf( - "Error parsing version: %s", err) - } - - segments[i] = val - } - - // Even though we could support more than three segments, if we - // got less than three, pad it with 0s. This is to cover the basic - // default usecase of semver, which is MAJOR.MINOR.PATCH at the minimum - for i := len(segments); i < 3; i++ { - segments = append(segments, 0) - } - - pre := matches[7] - if pre == "" { - pre = matches[4] - } - - return &Version{ - metadata: matches[10], - pre: pre, - segments: segments, - si: len(segmentsStr), - original: v, - }, nil -} - -// Must is a helper that wraps a call to a function returning (*Version, error) -// and panics if error is non-nil. -func Must(v *Version, err error) *Version { - if err != nil { - panic(err) - } - - return v -} - -// Compare compares this version to another version. This -// returns -1, 0, or 1 if this version is smaller, equal, -// or larger than the other version, respectively. -// -// If you want boolean results, use the LessThan, Equal, -// GreaterThan, GreaterThanOrEqual or LessThanOrEqual methods. -func (v *Version) Compare(other *Version) int { - // A quick, efficient equality check - if v.String() == other.String() { - return 0 - } - - // If the segments are the same, we must compare on prerelease info - if v.equalSegments(other) { - preSelf := v.Prerelease() - preOther := other.Prerelease() - if preSelf == "" && preOther == "" { - return 0 - } - if preSelf == "" { - return 1 - } - if preOther == "" { - return -1 - } - - return comparePrereleases(preSelf, preOther) - } - - segmentsSelf := v.Segments64() - segmentsOther := other.Segments64() - // Get the highest specificity (hS), or if they're equal, just use segmentSelf length - lenSelf := len(segmentsSelf) - lenOther := len(segmentsOther) - hS := lenSelf - if lenSelf < lenOther { - hS = lenOther - } - // Compare the segments - // Because a constraint could have more/less specificity than the version it's - // checking, we need to account for a lopsided or jagged comparison - for i := 0; i < hS; i++ { - if i > lenSelf-1 { - // This means Self had the lower specificity - // Check to see if the remaining segments in Other are all zeros - if !allZero(segmentsOther[i:]) { - // if not, it means that Other has to be greater than Self - return -1 - } - break - } else if i > lenOther-1 { - // this means Other had the lower specificity - // Check to see if the remaining segments in Self are all zeros - - if !allZero(segmentsSelf[i:]) { - // if not, it means that Self has to be greater than Other - return 1 - } - break - } - lhs := segmentsSelf[i] - rhs := segmentsOther[i] - if lhs == rhs { - continue - } else if lhs < rhs { - return -1 - } - // Otherwis, rhs was > lhs, they're not equal - return 1 - } - - // if we got this far, they're equal - return 0 -} - -func (v *Version) equalSegments(other *Version) bool { - segmentsSelf := v.Segments64() - segmentsOther := other.Segments64() - - if len(segmentsSelf) != len(segmentsOther) { - return false - } - for i, v := range segmentsSelf { - if v != segmentsOther[i] { - return false - } - } - return true -} - -func allZero(segs []int64) bool { - for _, s := range segs { - if s != 0 { - return false - } - } - return true -} - -func comparePart(preSelf string, preOther string) int { - if preSelf == preOther { - return 0 - } - - var selfInt int64 - selfNumeric := true - selfInt, err := strconv.ParseInt(preSelf, 10, 64) - if err != nil { - selfNumeric = false - } - - var otherInt int64 - otherNumeric := true - otherInt, err = strconv.ParseInt(preOther, 10, 64) - if err != nil { - otherNumeric = false - } - - // if a part is empty, we use the other to decide - if preSelf == "" { - if otherNumeric { - return -1 - } - return 1 - } - - if preOther == "" { - if selfNumeric { - return 1 - } - return -1 - } - - if selfNumeric && !otherNumeric { - return -1 - } else if !selfNumeric && otherNumeric { - return 1 - } else if !selfNumeric && !otherNumeric && preSelf > preOther { - return 1 - } else if selfInt > otherInt { - return 1 - } - - return -1 -} - -func comparePrereleases(v string, other string) int { - // the same pre release! - if v == other { - return 0 - } - - // split both pre releases for analyse their parts - selfPreReleaseMeta := strings.Split(v, ".") - otherPreReleaseMeta := strings.Split(other, ".") - - selfPreReleaseLen := len(selfPreReleaseMeta) - otherPreReleaseLen := len(otherPreReleaseMeta) - - biggestLen := otherPreReleaseLen - if selfPreReleaseLen > otherPreReleaseLen { - biggestLen = selfPreReleaseLen - } - - // loop for parts to find the first difference - for i := 0; i < biggestLen; i = i + 1 { - partSelfPre := "" - if i < selfPreReleaseLen { - partSelfPre = selfPreReleaseMeta[i] - } - - partOtherPre := "" - if i < otherPreReleaseLen { - partOtherPre = otherPreReleaseMeta[i] - } - - compare := comparePart(partSelfPre, partOtherPre) - // if parts are equals, continue the loop - if compare != 0 { - return compare - } - } - - return 0 -} - -// Core returns a new version constructed from only the MAJOR.MINOR.PATCH -// segments of the version, without prerelease or metadata. -func (v *Version) Core() *Version { - segments := v.Segments64() - segmentsOnly := fmt.Sprintf("%d.%d.%d", segments[0], segments[1], segments[2]) - return Must(NewVersion(segmentsOnly)) -} - -// Equal tests if two versions are equal. -func (v *Version) Equal(o *Version) bool { - if v == nil || o == nil { - return v == o - } - - return v.Compare(o) == 0 -} - -// GreaterThan tests if this version is greater than another version. -func (v *Version) GreaterThan(o *Version) bool { - return v.Compare(o) > 0 -} - -// GreaterThanOrEqual tests if this version is greater than or equal to another version. -func (v *Version) GreaterThanOrEqual(o *Version) bool { - return v.Compare(o) >= 0 -} - -// LessThan tests if this version is less than another version. -func (v *Version) LessThan(o *Version) bool { - return v.Compare(o) < 0 -} - -// LessThanOrEqual tests if this version is less than or equal to another version. -func (v *Version) LessThanOrEqual(o *Version) bool { - return v.Compare(o) <= 0 -} - -// Metadata returns any metadata that was part of the version -// string. -// -// Metadata is anything that comes after the "+" in the version. -// For example, with "1.2.3+beta", the metadata is "beta". -func (v *Version) Metadata() string { - return v.metadata -} - -// Prerelease returns any prerelease data that is part of the version, -// or blank if there is no prerelease data. -// -// Prerelease information is anything that comes after the "-" in the -// version (but before any metadata). For example, with "1.2.3-beta", -// the prerelease information is "beta". -func (v *Version) Prerelease() string { - return v.pre -} - -// Segments returns the numeric segments of the version as a slice of ints. -// -// This excludes any metadata or pre-release information. For example, -// for a version "1.2.3-beta", segments will return a slice of -// 1, 2, 3. -func (v *Version) Segments() []int { - segmentSlice := make([]int, len(v.segments)) - for i, v := range v.segments { - segmentSlice[i] = int(v) - } - return segmentSlice -} - -// Segments64 returns the numeric segments of the version as a slice of int64s. -// -// This excludes any metadata or pre-release information. For example, -// for a version "1.2.3-beta", segments will return a slice of -// 1, 2, 3. -func (v *Version) Segments64() []int64 { - result := make([]int64, len(v.segments)) - copy(result, v.segments) - return result -} - -// String returns the full version string included pre-release -// and metadata information. -// -// This value is rebuilt according to the parsed segments and other -// information. Therefore, ambiguities in the version string such as -// prefixed zeroes (1.04.0 => 1.4.0), `v` prefix (v1.0.0 => 1.0.0), and -// missing parts (1.0 => 1.0.0) will be made into a canonicalized form -// as shown in the parenthesized examples. -func (v *Version) String() string { - var buf bytes.Buffer - fmtParts := make([]string, len(v.segments)) - for i, s := range v.segments { - // We can ignore err here since we've pre-parsed the values in segments - str := strconv.FormatInt(s, 10) - fmtParts[i] = str - } - fmt.Fprintf(&buf, strings.Join(fmtParts, ".")) - if v.pre != "" { - fmt.Fprintf(&buf, "-%s", v.pre) - } - if v.metadata != "" { - fmt.Fprintf(&buf, "+%s", v.metadata) - } - - return buf.String() -} - -// Original returns the original parsed version as-is, including any -// potential whitespace, `v` prefix, etc. -func (v *Version) Original() string { - return v.original -} - -// UnmarshalText implements encoding.TextUnmarshaler interface. -func (v *Version) UnmarshalText(b []byte) error { - temp, err := NewVersion(string(b)) - if err != nil { - return err - } - - *v = *temp - - return nil -} - -// MarshalText implements encoding.TextMarshaler interface. -func (v *Version) MarshalText() ([]byte, error) { - return []byte(v.String()), nil -} - -// Scan implements the sql.Scanner interface. -func (v *Version) Scan(src interface{}) error { - switch src := src.(type) { - case string: - return v.UnmarshalText([]byte(src)) - case nil: - return nil - default: - return fmt.Errorf("cannot scan %T as Version", src) - } -} - -// Value implements the driver.Valuer interface. -func (v *Version) Value() (driver.Value, error) { - return v.String(), nil -} diff --git a/LICENSES/github.com/hashicorp/go-version/version_collection.go b/LICENSES/github.com/hashicorp/go-version/version_collection.go deleted file mode 100644 index 83547fe13..000000000 --- a/LICENSES/github.com/hashicorp/go-version/version_collection.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package version - -// Collection is a type that implements the sort.Interface interface -// so that versions can be sorted. -type Collection []*Version - -func (v Collection) Len() int { - return len(v) -} - -func (v Collection) Less(i, j int) bool { - return v[i].LessThan(v[j]) -} - -func (v Collection) Swap(i, j int) { - v[i], v[j] = v[j], v[i] -} diff --git a/LICENSES/github.com/hashicorp/go-version/version_collection_test.go b/LICENSES/github.com/hashicorp/go-version/version_collection_test.go deleted file mode 100644 index b6298a85f..000000000 --- a/LICENSES/github.com/hashicorp/go-version/version_collection_test.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package version - -import ( - "reflect" - "sort" - "testing" -) - -func TestCollection(t *testing.T) { - versionsRaw := []string{ - "1.1.1", - "1.0", - "1.2", - "2", - "0.7.1", - } - - versions := make([]*Version, len(versionsRaw)) - for i, raw := range versionsRaw { - v, err := NewVersion(raw) - if err != nil { - t.Fatalf("err: %s", err) - } - - versions[i] = v - } - - sort.Sort(Collection(versions)) - - actual := make([]string, len(versions)) - for i, v := range versions { - actual[i] = v.String() - } - - expected := []string{ - "0.7.1", - "1.0.0", - "1.1.1", - "1.2.0", - "2.0.0", - } - - if !reflect.DeepEqual(actual, expected) { - t.Fatalf("bad: %#v", actual) - } -} diff --git a/LICENSES/github.com/hashicorp/go-version/version_test.go b/LICENSES/github.com/hashicorp/go-version/version_test.go deleted file mode 100644 index 8256794f3..000000000 --- a/LICENSES/github.com/hashicorp/go-version/version_test.go +++ /dev/null @@ -1,730 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package version - -import ( - "encoding/json" - "fmt" - "reflect" - "testing" -) - -func TestNewVersion(t *testing.T) { - cases := []struct { - version string - err bool - }{ - {"", true}, - {"1.2.3", false}, - {"1.0", false}, - {"1", false}, - {"1.2.beta", true}, - {"1.21.beta", true}, - {"foo", true}, - {"1.2-5", false}, - {"1.2-beta.5", false}, - {"\n1.2", true}, - {"1.2.0-x.Y.0+metadata", false}, - {"1.2.0-x.Y.0+metadata-width-hyphen", false}, - {"1.2.3-rc1-with-hyphen", false}, - {"1.2.3.4", false}, - {"1.2.0.4-x.Y.0+metadata", false}, - {"1.2.0.4-x.Y.0+metadata-width-hyphen", false}, - {"1.2.0-X-1.2.0+metadata~dist", false}, - {"1.2.3.4-rc1-with-hyphen", false}, - {"1.2.3.4", false}, - {"v1.2.3", false}, - {"foo1.2.3", true}, - {"1.7rc2", false}, - {"v1.7rc2", false}, - {"1.0-", false}, - } - - for _, tc := range cases { - _, err := NewVersion(tc.version) - if tc.err && err == nil { - t.Fatalf("expected error for version: %q", tc.version) - } else if !tc.err && err != nil { - t.Fatalf("error for version %q: %s", tc.version, err) - } - } -} - -func TestNewSemver(t *testing.T) { - cases := []struct { - version string - err bool - }{ - {"", true}, - {"1.2.3", false}, - {"1.0", false}, - {"1", false}, - {"1.2.beta", true}, - {"1.21.beta", true}, - {"foo", true}, - {"1.2-5", false}, - {"1.2-beta.5", false}, - {"\n1.2", true}, - {"1.2.0-x.Y.0+metadata", false}, - {"1.2.0-x.Y.0+metadata-width-hyphen", false}, - {"1.2.3-rc1-with-hyphen", false}, - {"1.2.3.4", false}, - {"1.2.0.4-x.Y.0+metadata", false}, - {"1.2.0.4-x.Y.0+metadata-width-hyphen", false}, - {"1.2.0-X-1.2.0+metadata~dist", false}, - {"1.2.3.4-rc1-with-hyphen", false}, - {"1.2.3.4", false}, - {"v1.2.3", false}, - {"foo1.2.3", true}, - {"1.7rc2", true}, - {"v1.7rc2", true}, - {"1.0-", true}, - } - - for _, tc := range cases { - _, err := NewSemver(tc.version) - if tc.err && err == nil { - t.Fatalf("expected error for version: %q", tc.version) - } else if !tc.err && err != nil { - t.Fatalf("error for version %q: %s", tc.version, err) - } - } -} - -func TestCore(t *testing.T) { - cases := []struct { - v1 string - v2 string - }{ - {"1.2.3", "1.2.3"}, - {"2.3.4-alpha1", "2.3.4"}, - {"3.4.5alpha1", "3.4.5"}, - {"1.2.3-2", "1.2.3"}, - {"4.5.6-beta1+meta", "4.5.6"}, - {"5.6.7.1.2.3", "5.6.7"}, - } - - for _, tc := range cases { - v1, err := NewVersion(tc.v1) - if err != nil { - t.Fatalf("error for version %q: %s", tc.v1, err) - } - v2, err := NewVersion(tc.v2) - if err != nil { - t.Fatalf("error for version %q: %s", tc.v2, err) - } - - actual := v1.Core() - expected := v2 - - if !reflect.DeepEqual(actual, expected) { - t.Fatalf("expected: %s\nactual: %s", expected, actual) - } - } -} - -func TestVersionCompare(t *testing.T) { - cases := []struct { - v1 string - v2 string - expected int - }{ - {"1.2.3", "1.4.5", -1}, - {"1.2-beta", "1.2-beta", 0}, - {"1.2", "1.1.4", 1}, - {"1.2", "1.2-beta", 1}, - {"1.2+foo", "1.2+beta", 0}, - {"v1.2", "v1.2-beta", 1}, - {"v1.2+foo", "v1.2+beta", 0}, - {"v1.2.3.4", "v1.2.3.4", 0}, - {"v1.2.0.0", "v1.2", 0}, - {"v1.2.0.0.1", "v1.2", 1}, - {"v1.2", "v1.2.0.0", 0}, - {"v1.2", "v1.2.0.0.1", -1}, - {"v1.2.0.0", "v1.2.0.0.1", -1}, - {"v1.2.3.0", "v1.2.3.4", -1}, - {"1.7rc2", "1.7rc1", 1}, - {"1.7rc2", "1.7", -1}, - {"1.2.0", "1.2.0-X-1.2.0+metadata~dist", 1}, - } - - for _, tc := range cases { - v1, err := NewVersion(tc.v1) - if err != nil { - t.Fatalf("err: %s", err) - } - - v2, err := NewVersion(tc.v2) - if err != nil { - t.Fatalf("err: %s", err) - } - - actual := v1.Compare(v2) - expected := tc.expected - if actual != expected { - t.Fatalf( - "%s <=> %s\nexpected: %d\nactual: %d", - tc.v1, tc.v2, - expected, actual) - } - } -} - -func TestVersionCompare_versionAndSemver(t *testing.T) { - cases := []struct { - versionRaw string - semverRaw string - expected int - }{ - {"0.0.2", "0.0.2", 0}, - {"1.0.2alpha", "1.0.2-alpha", 0}, - {"v1.2+foo", "v1.2+beta", 0}, - {"v1.2", "v1.2+meta", 0}, - {"1.2", "1.2-beta", 1}, - {"v1.2", "v1.2-beta", 1}, - {"1.2.3", "1.4.5", -1}, - {"v1.2", "v1.2.0.0.1", -1}, - {"v1.0.3-", "v1.0.3", -1}, - } - - for _, tc := range cases { - ver, err := NewVersion(tc.versionRaw) - if err != nil { - t.Fatalf("err: %s", err) - } - - semver, err := NewSemver(tc.semverRaw) - if err != nil { - t.Fatalf("err: %s", err) - } - - actual := ver.Compare(semver) - if actual != tc.expected { - t.Fatalf( - "%s <=> %s\nexpected: %d\n actual: %d", - tc.versionRaw, tc.semverRaw, tc.expected, actual, - ) - } - } -} - -func TestVersionEqual_nil(t *testing.T) { - mustVersion := func(v string) *Version { - ver, err := NewVersion(v) - if err != nil { - t.Fatal(err) - } - return ver - } - cases := []struct { - leftVersion *Version - rightVersion *Version - expected bool - }{ - {mustVersion("1.0.0"), nil, false}, - {nil, mustVersion("1.0.0"), false}, - {nil, nil, true}, - } - - for _, tc := range cases { - given := tc.leftVersion.Equal(tc.rightVersion) - if given != tc.expected { - t.Fatalf("expected Equal to nil to be %t", tc.expected) - } - } -} - -func TestComparePreReleases(t *testing.T) { - cases := []struct { - v1 string - v2 string - expected int - }{ - {"1.2-beta.2", "1.2-beta.2", 0}, - {"1.2-beta.1", "1.2-beta.2", -1}, - {"1.2-beta.2", "1.2-beta.11", -1}, - {"3.2-alpha.1", "3.2-alpha", 1}, - {"1.2-beta.2", "1.2-beta.1", 1}, - {"1.2-beta.11", "1.2-beta.2", 1}, - {"1.2-beta", "1.2-beta.3", -1}, - {"1.2-alpha", "1.2-beta.3", -1}, - {"1.2-beta", "1.2-alpha.3", 1}, - {"3.0-alpha.3", "3.0-rc.1", -1}, - {"3.0-alpha3", "3.0-rc1", -1}, - {"3.0-alpha.1", "3.0-alpha.beta", -1}, - {"5.4-alpha", "5.4-alpha.beta", 1}, - {"v1.2-beta.2", "v1.2-beta.2", 0}, - {"v1.2-beta.1", "v1.2-beta.2", -1}, - {"v3.2-alpha.1", "v3.2-alpha", 1}, - {"v3.2-rc.1-1-g123", "v3.2-rc.2", 1}, - } - - for _, tc := range cases { - v1, err := NewVersion(tc.v1) - if err != nil { - t.Fatalf("err: %s", err) - } - - v2, err := NewVersion(tc.v2) - if err != nil { - t.Fatalf("err: %s", err) - } - - actual := v1.Compare(v2) - expected := tc.expected - if actual != expected { - t.Fatalf( - "%s <=> %s\nexpected: %d\nactual: %d", - tc.v1, tc.v2, - expected, actual) - } - } -} - -func TestVersionMetadata(t *testing.T) { - cases := []struct { - version string - expected string - }{ - {"1.2.3", ""}, - {"1.2-beta", ""}, - {"1.2.0-x.Y.0", ""}, - {"1.2.0-x.Y.0+metadata", "metadata"}, - {"1.2.0-metadata-1.2.0+metadata~dist", "metadata~dist"}, - } - - for _, tc := range cases { - v, err := NewVersion(tc.version) - if err != nil { - t.Fatalf("err: %s", err) - } - - actual := v.Metadata() - expected := tc.expected - if actual != expected { - t.Fatalf("expected: %s\nactual: %s", expected, actual) - } - } -} - -func TestVersionPrerelease(t *testing.T) { - cases := []struct { - version string - expected string - }{ - {"1.2.3", ""}, - {"1.2-beta", "beta"}, - {"1.2.0-x.Y.0", "x.Y.0"}, - {"1.2.0-7.Y.0", "7.Y.0"}, - {"1.2.0-x.Y.0+metadata", "x.Y.0"}, - {"1.2.0-metadata-1.2.0+metadata~dist", "metadata-1.2.0"}, - {"17.03.0-ce", "ce"}, // zero-padded fields - } - - for _, tc := range cases { - v, err := NewVersion(tc.version) - if err != nil { - t.Fatalf("err: %s", err) - } - - actual := v.Prerelease() - expected := tc.expected - if actual != expected { - t.Fatalf("expected: %s\nactual: %s", expected, actual) - } - } -} - -func TestVersionSegments(t *testing.T) { - cases := []struct { - version string - expected []int - }{ - {"1.2.3", []int{1, 2, 3}}, - {"1.2-beta", []int{1, 2, 0}}, - {"1-x.Y.0", []int{1, 0, 0}}, - {"1.2.0-x.Y.0+metadata", []int{1, 2, 0}}, - {"1.2.0-metadata-1.2.0+metadata~dist", []int{1, 2, 0}}, - {"17.03.0-ce", []int{17, 3, 0}}, // zero-padded fields - } - - for _, tc := range cases { - v, err := NewVersion(tc.version) - if err != nil { - t.Fatalf("err: %s", err) - } - - actual := v.Segments() - expected := tc.expected - if !reflect.DeepEqual(actual, expected) { - t.Fatalf("expected: %#v\nactual: %#v", expected, actual) - } - } -} - -func TestVersionSegments64(t *testing.T) { - cases := []struct { - version string - expected []int64 - }{ - {"1.2.3", []int64{1, 2, 3}}, - {"1.2-beta", []int64{1, 2, 0}}, - {"1-x.Y.0", []int64{1, 0, 0}}, - {"1.2.0-x.Y.0+metadata", []int64{1, 2, 0}}, - {"1.4.9223372036854775807", []int64{1, 4, 9223372036854775807}}, - } - - for _, tc := range cases { - v, err := NewVersion(tc.version) - if err != nil { - t.Fatalf("err: %s", err) - } - - actual := v.Segments64() - expected := tc.expected - if !reflect.DeepEqual(actual, expected) { - t.Fatalf("expected: %#v\nactual: %#v", expected, actual) - } - - { - expected := actual[0] - actual[0]++ - actual = v.Segments64() - if actual[0] != expected { - t.Fatalf("Segments64 is mutable") - } - } - } -} - -func TestJsonMarshal(t *testing.T) { - cases := []struct { - version string - err bool - }{ - {"1.2.3", false}, - {"1.2.0-x.Y.0+metadata", false}, - {"1.2.0-x.Y.0+metadata-width-hyphen", false}, - {"1.2.3-rc1-with-hyphen", false}, - {"1.2.3.4", false}, - {"1.2.0.4-x.Y.0+metadata", false}, - {"1.2.0.4-x.Y.0+metadata-width-hyphen", false}, - {"1.2.0-X-1.2.0+metadata~dist", false}, - {"1.2.3.4-rc1-with-hyphen", false}, - {"1.2.3.4", false}, - } - - for _, tc := range cases { - v, err1 := NewVersion(tc.version) - if err1 != nil { - t.Fatalf("error for version %q: %s", tc.version, err1) - } - - parsed, err2 := json.Marshal(v) - if err2 != nil { - t.Fatalf("error marshaling version %q: %s", tc.version, err2) - } - result := string(parsed) - expected := fmt.Sprintf("%q", tc.version) - if result != expected && !tc.err { - t.Fatalf("Error marshaling unexpected marshaled content: result=%q expected=%q", result, expected) - } - } -} - -func TestJsonUnmarshal(t *testing.T) { - cases := []struct { - version string - err bool - }{ - {"1.2.3", false}, - {"1.2.0-x.Y.0+metadata", false}, - {"1.2.0-x.Y.0+metadata-width-hyphen", false}, - {"1.2.3-rc1-with-hyphen", false}, - {"1.2.3.4", false}, - {"1.2.0.4-x.Y.0+metadata", false}, - {"1.2.0.4-x.Y.0+metadata-width-hyphen", false}, - {"1.2.0-X-1.2.0+metadata~dist", false}, - {"1.2.3.4-rc1-with-hyphen", false}, - {"1.2.3.4", false}, - } - - for _, tc := range cases { - expected, err1 := NewVersion(tc.version) - if err1 != nil { - t.Fatalf("err: %s", err1) - } - - actual := &Version{} - err2 := json.Unmarshal([]byte(fmt.Sprintf("%q", tc.version)), actual) - if err2 != nil { - t.Fatalf("error unmarshaling version: %s", err2) - } - if !reflect.DeepEqual(actual, expected) { - t.Fatalf("error unmarshaling, unexpected object content: actual=%q expected=%q", actual, expected) - } - } -} - -func TestVersionString(t *testing.T) { - cases := [][]string{ - {"1.2.3", "1.2.3"}, - {"1.2-beta", "1.2.0-beta"}, - {"1.2.0-x.Y.0", "1.2.0-x.Y.0"}, - {"1.2.0-x.Y.0+metadata", "1.2.0-x.Y.0+metadata"}, - {"1.2.0-metadata-1.2.0+metadata~dist", "1.2.0-metadata-1.2.0+metadata~dist"}, - {"17.03.0-ce", "17.3.0-ce"}, // zero-padded fields - } - - for _, tc := range cases { - v, err := NewVersion(tc[0]) - if err != nil { - t.Fatalf("err: %s", err) - } - - actual := v.String() - expected := tc[1] - if actual != expected { - t.Fatalf("expected: %s\nactual: %s", expected, actual) - } - if actual := v.Original(); actual != tc[0] { - t.Fatalf("expected original: %q\nactual: %q", tc[0], actual) - } - } -} - -func TestEqual(t *testing.T) { - cases := []struct { - v1 string - v2 string - expected bool - }{ - {"1.2.3", "1.4.5", false}, - {"1.2-beta", "1.2-beta", true}, - {"1.2", "1.1.4", false}, - {"1.2", "1.2-beta", false}, - {"1.2+foo", "1.2+beta", true}, - {"v1.2", "v1.2-beta", false}, - {"v1.2+foo", "v1.2+beta", true}, - {"v1.2.3.4", "v1.2.3.4", true}, - {"v1.2.0.0", "v1.2", true}, - {"v1.2.0.0.1", "v1.2", false}, - {"v1.2", "v1.2.0.0", true}, - {"v1.2", "v1.2.0.0.1", false}, - {"v1.2.0.0", "v1.2.0.0.1", false}, - {"v1.2.3.0", "v1.2.3.4", false}, - {"1.7rc2", "1.7rc1", false}, - {"1.7rc2", "1.7", false}, - {"1.2.0", "1.2.0-X-1.2.0+metadata~dist", false}, - } - - for _, tc := range cases { - v1, err := NewVersion(tc.v1) - if err != nil { - t.Fatalf("err: %s", err) - } - - v2, err := NewVersion(tc.v2) - if err != nil { - t.Fatalf("err: %s", err) - } - - actual := v1.Equal(v2) - expected := tc.expected - if actual != expected { - t.Fatalf( - "%s <=> %s\nexpected: %t\nactual: %t", - tc.v1, tc.v2, - expected, actual) - } - } -} - -func TestGreaterThan(t *testing.T) { - cases := []struct { - v1 string - v2 string - expected bool - }{ - {"1.2.3", "1.4.5", false}, - {"1.2-beta", "1.2-beta", false}, - {"1.2", "1.1.4", true}, - {"1.2", "1.2-beta", true}, - {"1.2+foo", "1.2+beta", false}, - {"v1.2", "v1.2-beta", true}, - {"v1.2+foo", "v1.2+beta", false}, - {"v1.2.3.4", "v1.2.3.4", false}, - {"v1.2.0.0", "v1.2", false}, - {"v1.2.0.0.1", "v1.2", true}, - {"v1.2", "v1.2.0.0", false}, - {"v1.2", "v1.2.0.0.1", false}, - {"v1.2.0.0", "v1.2.0.0.1", false}, - {"v1.2.3.0", "v1.2.3.4", false}, - {"1.7rc2", "1.7rc1", true}, - {"1.7rc2", "1.7", false}, - {"1.2.0", "1.2.0-X-1.2.0+metadata~dist", true}, - } - - for _, tc := range cases { - v1, err := NewVersion(tc.v1) - if err != nil { - t.Fatalf("err: %s", err) - } - - v2, err := NewVersion(tc.v2) - if err != nil { - t.Fatalf("err: %s", err) - } - - actual := v1.GreaterThan(v2) - expected := tc.expected - if actual != expected { - t.Fatalf( - "%s > %s\nexpected: %t\nactual: %t", - tc.v1, tc.v2, - expected, actual) - } - } -} - -func TestLessThan(t *testing.T) { - cases := []struct { - v1 string - v2 string - expected bool - }{ - {"1.2.3", "1.4.5", true}, - {"1.2-beta", "1.2-beta", false}, - {"1.2", "1.1.4", false}, - {"1.2", "1.2-beta", false}, - {"1.2+foo", "1.2+beta", false}, - {"v1.2", "v1.2-beta", false}, - {"v1.2+foo", "v1.2+beta", false}, - {"v1.2.3.4", "v1.2.3.4", false}, - {"v1.2.0.0", "v1.2", false}, - {"v1.2.0.0.1", "v1.2", false}, - {"v1.2", "v1.2.0.0", false}, - {"v1.2", "v1.2.0.0.1", true}, - {"v1.2.0.0", "v1.2.0.0.1", true}, - {"v1.2.3.0", "v1.2.3.4", true}, - {"1.7rc2", "1.7rc1", false}, - {"1.7rc2", "1.7", true}, - {"1.2.0", "1.2.0-X-1.2.0+metadata~dist", false}, - } - - for _, tc := range cases { - v1, err := NewVersion(tc.v1) - if err != nil { - t.Fatalf("err: %s", err) - } - - v2, err := NewVersion(tc.v2) - if err != nil { - t.Fatalf("err: %s", err) - } - - actual := v1.LessThan(v2) - expected := tc.expected - if actual != expected { - t.Fatalf( - "%s < %s\nexpected: %t\nactual: %t", - tc.v1, tc.v2, - expected, actual) - } - } -} - -func TestGreaterThanOrEqual(t *testing.T) { - cases := []struct { - v1 string - v2 string - expected bool - }{ - {"1.2.3", "1.4.5", false}, - {"1.2-beta", "1.2-beta", true}, - {"1.2", "1.1.4", true}, - {"1.2", "1.2-beta", true}, - {"1.2+foo", "1.2+beta", true}, - {"v1.2", "v1.2-beta", true}, - {"v1.2+foo", "v1.2+beta", true}, - {"v1.2.3.4", "v1.2.3.4", true}, - {"v1.2.0.0", "v1.2", true}, - {"v1.2.0.0.1", "v1.2", true}, - {"v1.2", "v1.2.0.0", true}, - {"v1.2", "v1.2.0.0.1", false}, - {"v1.2.0.0", "v1.2.0.0.1", false}, - {"v1.2.3.0", "v1.2.3.4", false}, - {"1.7rc2", "1.7rc1", true}, - {"1.7rc2", "1.7", false}, - {"1.2.0", "1.2.0-X-1.2.0+metadata~dist", true}, - } - - for _, tc := range cases { - v1, err := NewVersion(tc.v1) - if err != nil { - t.Fatalf("err: %s", err) - } - - v2, err := NewVersion(tc.v2) - if err != nil { - t.Fatalf("err: %s", err) - } - - actual := v1.GreaterThanOrEqual(v2) - expected := tc.expected - if actual != expected { - t.Fatalf( - "%s >= %s\nexpected: %t\nactual: %t", - tc.v1, tc.v2, - expected, actual) - } - } -} - -func TestLessThanOrEqual(t *testing.T) { - cases := []struct { - v1 string - v2 string - expected bool - }{ - {"1.2.3", "1.4.5", true}, - {"1.2-beta", "1.2-beta", true}, - {"1.2", "1.1.4", false}, - {"1.2", "1.2-beta", false}, - {"1.2+foo", "1.2+beta", true}, - {"v1.2", "v1.2-beta", false}, - {"v1.2+foo", "v1.2+beta", true}, - {"v1.2.3.4", "v1.2.3.4", true}, - {"v1.2.0.0", "v1.2", true}, - {"v1.2.0.0.1", "v1.2", false}, - {"v1.2", "v1.2.0.0", true}, - {"v1.2", "v1.2.0.0.1", true}, - {"v1.2.0.0", "v1.2.0.0.1", true}, - {"v1.2.3.0", "v1.2.3.4", true}, - {"1.7rc2", "1.7rc1", false}, - {"1.7rc2", "1.7", true}, - {"1.2.0", "1.2.0-X-1.2.0+metadata~dist", false}, - } - - for _, tc := range cases { - v1, err := NewVersion(tc.v1) - if err != nil { - t.Fatalf("err: %s", err) - } - - v2, err := NewVersion(tc.v2) - if err != nil { - t.Fatalf("err: %s", err) - } - - actual := v1.LessThanOrEqual(v2) - expected := tc.expected - if actual != expected { - t.Fatalf( - "%s <= %s\nexpected: %t\nactual: %t", - tc.v1, tc.v2, - expected, actual) - } - } -} diff --git a/go.mod b/go.mod index 77c68a42a..09d3112dc 100644 --- a/go.mod +++ b/go.mod @@ -18,9 +18,9 @@ retract ( ) require ( + github.com/Masterminds/semver/v3 v3.3.1 github.com/cilium/ebpf v0.17.3 github.com/go-logr/stdr v1.2.2 - github.com/hashicorp/go-version v1.7.0 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.10.0 github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 diff --git a/go.sum b/go.sum index 9bc02f406..2472394c3 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= +github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= @@ -27,8 +29,6 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA= github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M= -github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= -github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/jsimonetti/rtnetlink/v2 v2.0.1 h1:xda7qaHDSVOsADNouv7ukSuicKZO7GgVUCXxpaIEIlM= diff --git a/internal/pkg/inject/consts.go b/internal/pkg/inject/consts.go index b1471f6c0..f744e7283 100644 --- a/internal/pkg/inject/consts.go +++ b/internal/pkg/inject/consts.go @@ -10,8 +10,8 @@ import ( "errors" "fmt" + "github.com/Masterminds/semver/v3" "github.com/cilium/ebpf" - "github.com/hashicorp/go-version" "go.opentelemetry.io/auto/internal/pkg/process" "go.opentelemetry.io/auto/internal/pkg/structfield" @@ -139,7 +139,7 @@ func WithKeyValue(key string, value interface{}) Option { // // If the offset value is not known, an error is returned when the returned // Option is used. -func WithOffset(key string, id structfield.ID, ver *version.Version) Option { +func WithOffset(key string, id structfield.ID, ver *semver.Version) Option { if ver == nil { return errOpt{ err: fmt.Errorf("missing version: %s", id), @@ -187,10 +187,10 @@ func FindOffset(id structfield.ID, td *process.TargetDetails) (structfield.Offse return structfield.OffsetKey{Offset: uint64(v), Valid: true}, err // nolint: gosec // Bounded. } -func GetOffset(id structfield.ID, ver *version.Version) (structfield.OffsetKey, bool) { +func GetOffset(id structfield.ID, ver *semver.Version) (structfield.OffsetKey, bool) { return offsets.GetOffset(id, ver) } -func GetLatestOffset(id structfield.ID) (structfield.OffsetKey, *version.Version) { +func GetLatestOffset(id structfield.ID) (structfield.OffsetKey, *semver.Version) { return offsets.GetLatestOffset(id) } diff --git a/internal/pkg/inject/consts_test.go b/internal/pkg/inject/consts_test.go index c762c41cf..5ca2404cf 100644 --- a/internal/pkg/inject/consts_test.go +++ b/internal/pkg/inject/consts_test.go @@ -6,7 +6,7 @@ package inject import ( "testing" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -54,10 +54,8 @@ func TestWithAllocationDetails(t *testing.T) { } func TestWithOffset(t *testing.T) { - v10, err := version.NewVersion("1.0") - require.NoError(t, err) - v18, err := version.NewVersion("1.8") - require.NoError(t, err) + v10 := semver.New(1, 0, 0, "", "") + v18 := semver.New(1, 8, 0, "", "") const off uint64 = 1 id := structfield.NewID("std", "net/http", "Request", "Method") diff --git a/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/probe.go b/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/probe.go index 0fcfa2ed0..f7373b18e 100644 --- a/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/probe.go +++ b/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/probe.go @@ -19,8 +19,8 @@ import ( "go.opentelemetry.io/auto/internal/pkg/process" "go.opentelemetry.io/auto/internal/pkg/structfield" + "github.com/Masterminds/semver/v3" "github.com/cilium/ebpf/perf" - "github.com/hashicorp/go-version" "golang.org/x/sys/unix" "go.opentelemetry.io/otel/attribute" @@ -39,34 +39,34 @@ const ( // Minimum version of go.opentelemetry.io/otel that supports using the // go.opentelemetry.io/auto/sdk in the global API. minAutoSDK = "1.33.0" - minGoMaps = "1.24.0" ) +func must(c *semver.Constraints, err error) *semver.Constraints { + if err != nil { + panic(err) + } + return c +} + var ( + goMapsVersion = semver.New(1, 24, 0, "", "") + otelWithAutoSDK = probe.PackageConstraints{ - Package: "go.opentelemetry.io/otel", - Constraints: version.MustConstraints( - version.NewConstraint(">= " + minAutoSDK), - ), + Package: "go.opentelemetry.io/otel", + Constraints: must(semver.NewConstraint(">= " + minAutoSDK)), FailureMode: probe.FailureModeIgnore, } otelWithoutAutoSDK = probe.PackageConstraints{ - Package: "go.opentelemetry.io/otel", - Constraints: version.MustConstraints( - version.NewConstraint("< " + minAutoSDK), - ), + Package: "go.opentelemetry.io/otel", + Constraints: must(semver.NewConstraint("< " + minAutoSDK)), FailureMode: probe.FailureModeIgnore, } goWithoutSwissMaps = probe.PackageConstraints{ - Package: "std", - Constraints: version.MustConstraints( - version.NewConstraint("< " + minGoMaps), - ), + Package: "std", + Constraints: must(semver.NewConstraint("< " + goMapsVersion.String())), // Warn in logs that this is not supported. FailureMode: probe.FailureModeWarn, } - - goMapsVersion = version.Must(version.NewVersion(minGoMaps)) ) // New returns a new [probe.Probe]. @@ -256,7 +256,7 @@ type tracerIDContainsSchemaURL struct{} // Prior to v1.28 the tracer key did not contain schemaURL. However, in that version a // change was made to include it. // https://github.com/open-telemetry/opentelemetry-go/pull/5426/files -var schemaAddedToTracerKeyVer = version.Must(version.NewVersion("1.28.0")) +var schemaAddedToTracerKeyVer = semver.New(1, 28, 0, "", "") func (c tracerIDContainsSchemaURL) InjectOption(td *process.TargetDetails) (inject.Option, error) { ver, ok := td.Modules["go.opentelemetry.io/otel"] @@ -264,12 +264,12 @@ func (c tracerIDContainsSchemaURL) InjectOption(td *process.TargetDetails) (inje return nil, fmt.Errorf("unknown module version: %s", pkg) } - return inject.WithKeyValue("tracer_id_contains_schemaURL", ver.GreaterThanOrEqual(schemaAddedToTracerKeyVer)), nil + return inject.WithKeyValue("tracer_id_contains_schemaURL", ver.GreaterThanEqual(schemaAddedToTracerKeyVer)), nil } // In v1.32.0 the tracer key was updated to include the scope attributes. // https://github.com/open-telemetry/opentelemetry-go/pull/5924/files -var scopeAttributesAddedToTracerKeyVer = version.Must(version.NewVersion("1.32.0")) +var scopeAttributesAddedToTracerKeyVer = semver.New(1, 32, 0, "", "") // tracerIDContainsScopeAttributes is a Probe Const defining whether the tracer key contains scope attributes. type tracerIDContainsScopeAttributes struct{} @@ -280,7 +280,7 @@ func (c tracerIDContainsScopeAttributes) InjectOption(td *process.TargetDetails) return nil, fmt.Errorf("unknown module version: %s", pkg) } - return inject.WithKeyValue("tracer_id_contains_scope_attributes", ver.GreaterThanOrEqual(scopeAttributesAddedToTracerKeyVer)), nil + return inject.WithKeyValue("tracer_id_contains_scope_attributes", ver.GreaterThanEqual(scopeAttributesAddedToTracerKeyVer)), nil } type attributeKeyVal struct { diff --git a/internal/pkg/instrumentation/bpf/google.golang.org/grpc/client/probe.go b/internal/pkg/instrumentation/bpf/google.golang.org/grpc/client/probe.go index 54f311a00..8e4702e26 100644 --- a/internal/pkg/instrumentation/bpf/google.golang.org/grpc/client/probe.go +++ b/internal/pkg/instrumentation/bpf/google.golang.org/grpc/client/probe.go @@ -10,8 +10,8 @@ import ( "net" "strconv" + "github.com/Masterminds/semver/v3" "github.com/cilium/ebpf" - "github.com/hashicorp/go-version" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/otel/attribute" @@ -36,7 +36,7 @@ const ( var ( writeStatus = false - writeStatusMinVersion = version.Must(version.NewVersion("1.40.0")) + writeStatusMinVersion = semver.New(1, 40, 0, "", "") ) type writeStatusConst struct{} @@ -46,7 +46,7 @@ func (w writeStatusConst) InjectOption(td *process.TargetDetails) (inject.Option if !ok { return nil, fmt.Errorf("unknown module version: %s", pkg) } - if ver.GreaterThanOrEqual(writeStatusMinVersion) { + if ver.GreaterThanEqual(writeStatusMinVersion) { writeStatus = true } return inject.WithKeyValue("write_status_supported", writeStatus), nil diff --git a/internal/pkg/instrumentation/bpf/google.golang.org/grpc/server/probe.go b/internal/pkg/instrumentation/bpf/google.golang.org/grpc/server/probe.go index 784f65ef6..d2f3bbc02 100644 --- a/internal/pkg/instrumentation/bpf/google.golang.org/grpc/server/probe.go +++ b/internal/pkg/instrumentation/bpf/google.golang.org/grpc/server/probe.go @@ -8,7 +8,7 @@ import ( "log/slog" "net" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/otel/attribute" @@ -27,23 +27,17 @@ import ( //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target amd64,arm64 bpf ./bpf/probe.bpf.c -const ( - // pkg is the package being instrumented. - pkg = "google.golang.org/grpc" - - // writeStatusMin is the minimum version of grpc that supports status - // parsing. - writeStatusMin = "1.40.0" - - // serverStream is the version the both the writeStatus and handleStream - // methods changed to accept a *transport.ServerStream instead of a - // *transport.Stream. - serverStream = "1.69.0" -) +// pkg is the package being instrumented. +const pkg = "google.golang.org/grpc" var ( - writeStatusMinVersion = version.Must(version.NewVersion(writeStatusMin)) - serverStreamVersion = version.Must(version.NewVersion(serverStream)) + // writeStatusMinVersion is the minimum version of grpc that supports + // status parsing. + writeStatusMinVersion = semver.New(1, 40, 0, "", "") + // serverStreamVersion is the version the both the writeStatus and + // handleStream methods changed to accept a *transport.ServerStream instead + // of a *transport.Stream. + serverStreamVersion = semver.New(1, 69, 0, "", "") ) // New returns a new [probe.Probe]. @@ -133,10 +127,8 @@ func New(logger *slog.Logger, ver string) probe.Probe { ReturnProbe: "uprobe_server_handleStream_Returns", PackageConstraints: []probe.PackageConstraints{ { - Package: "google.golang.org/grpc", - Constraints: version.MustConstraints( - version.NewConstraint("< " + serverStream), - ), + Package: "google.golang.org/grpc", + Constraints: must(semver.NewConstraint("< " + serverStreamVersion.String())), FailureMode: probe.FailureModeIgnore, }, }, @@ -147,10 +139,8 @@ func New(logger *slog.Logger, ver string) probe.Probe { ReturnProbe: "uprobe_server_handleStream2_Returns", PackageConstraints: []probe.PackageConstraints{ { - Package: "google.golang.org/grpc", - Constraints: version.MustConstraints( - version.NewConstraint(">= " + serverStream), - ), + Package: "google.golang.org/grpc", + Constraints: must(semver.NewConstraint(">= " + serverStreamVersion.String())), FailureMode: probe.FailureModeIgnore, }, }, @@ -165,11 +155,9 @@ func New(logger *slog.Logger, ver string) probe.Probe { PackageConstraints: []probe.PackageConstraints{ { Package: "google.golang.org/grpc", - Constraints: version.MustConstraints( - version.NewConstraint( - fmt.Sprintf("> %s, < %s", writeStatusMin, serverStream), - ), - ), + Constraints: must(semver.NewConstraint( + fmt.Sprintf("> %s, < %s", writeStatusMinVersion, serverStreamVersion), + )), FailureMode: probe.FailureModeIgnore, }, }, @@ -179,10 +167,8 @@ func New(logger *slog.Logger, ver string) probe.Probe { EntryProbe: "uprobe_http2Server_WriteStatus2", PackageConstraints: []probe.PackageConstraints{ { - Package: "google.golang.org/grpc", - Constraints: version.MustConstraints( - version.NewConstraint(">= " + serverStream), - ), + Package: "google.golang.org/grpc", + Constraints: must(semver.NewConstraint(">= " + serverStreamVersion.String())), FailureMode: probe.FailureModeIgnore, }, }, @@ -196,6 +182,13 @@ func New(logger *slog.Logger, ver string) probe.Probe { } } +func must(c *semver.Constraints, err error) *semver.Constraints { + if err != nil { + panic(err) + } + return c +} + // framePosConst is a Probe Const defining the position of the // http.MetaHeadersFrame parameter of the http2Server.operateHeaders method. type framePosConst struct{} @@ -204,7 +197,7 @@ type framePosConst struct{} // context was added as the first parameter. The frame became the second // parameter: // https://github.com/grpc/grpc-go/pull/6716/files#diff-4058722211b8d52e2d5b0c0b7542059ed447a04017b69520d767e94a9493409eR334 -var paramChangeVer = version.Must(version.NewVersion("1.60.0")) +var paramChangeVer = semver.New(1, 60, 0, "", "") func (c framePosConst) InjectOption(td *process.TargetDetails) (inject.Option, error) { ver, ok := td.Modules[pkg] @@ -212,13 +205,13 @@ func (c framePosConst) InjectOption(td *process.TargetDetails) (inject.Option, e return nil, fmt.Errorf("unknown module version: %s", pkg) } - return inject.WithKeyValue("is_new_frame_pos", ver.GreaterThanOrEqual(paramChangeVer)), nil + return inject.WithKeyValue("is_new_frame_pos", ver.GreaterThanEqual(paramChangeVer)), nil } type serverAddrConst struct{} var ( - serverAddrMinVersion = version.Must(version.NewVersion("1.60.0")) + serverAddrMinVersion = semver.New(1, 60, 0, "", "") serverAddr = false ) @@ -227,7 +220,7 @@ func (w serverAddrConst) InjectOption(td *process.TargetDetails) (inject.Option, if !ok { return nil, fmt.Errorf("unknown module version: %s", pkg) } - if ver.GreaterThanOrEqual(serverAddrMinVersion) { + if ver.GreaterThanEqual(serverAddrMinVersion) { serverAddr = true } return inject.WithKeyValue("server_addr_supported", serverAddr), nil diff --git a/internal/pkg/instrumentation/bpf/net/http/server/probe.go b/internal/pkg/instrumentation/bpf/net/http/server/probe.go index 5761ec9aa..c641d6bf8 100644 --- a/internal/pkg/instrumentation/bpf/net/http/server/probe.go +++ b/internal/pkg/instrumentation/bpf/net/http/server/probe.go @@ -7,7 +7,7 @@ import ( "log/slog" "strings" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/otel/attribute" @@ -26,23 +26,24 @@ import ( //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target amd64,arm64 bpf ./bpf/probe.bpf.c -const ( - // pkg is the package being instrumented. - pkg = "net/http" - minGoSwissMaps = "1.24.0" -) +// pkg is the package being instrumented. +const pkg = "net/http" var ( + goMapsVersion = semver.New(1, 24, 0, "", "") + goWithSwissMaps = probe.PackageConstraints{ Package: "std", - Constraints: version.MustConstraints( - version.NewConstraint(">= " + minGoSwissMaps), - ), + Constraints: func() *semver.Constraints { + c, err := semver.NewConstraint(">= " + goMapsVersion.String()) + if err != nil { + panic(err) + } + return c + }(), // Don't warn, we have a backup path. FailureMode: probe.FailureModeIgnore, } - - goMapsVersion = version.Must(version.NewVersion(minGoSwissMaps)) ) // New returns a new [probe.Probe]. @@ -147,20 +148,19 @@ func New(logger *slog.Logger, version string) probe.Probe { type patternPathSupportedConst struct{} var ( - patternPathMinVersion = version.Must(version.NewVersion("1.22.0")) + patternPathMinVersion = semver.New(1, 22, 0, "", "") isPatternPathSupported = false ) func (c patternPathSupportedConst) InjectOption(td *process.TargetDetails) (inject.Option, error) { - isPatternPathSupported = td.GoVersion.GreaterThanOrEqual(patternPathMinVersion) + isPatternPathSupported = td.GoVersion.GreaterThanEqual(patternPathMinVersion) return inject.WithKeyValue("pattern_path_supported", isPatternPathSupported), nil } type swissMapsUsedConst struct{} func (c swissMapsUsedConst) InjectOption(td *process.TargetDetails) (inject.Option, error) { - minGoSwissMapsVersion := version.Must(version.NewVersion(minGoSwissMaps)) - isUsingGoSwissMaps := td.GoVersion.GreaterThanOrEqual(minGoSwissMapsVersion) + isUsingGoSwissMaps := td.GoVersion.GreaterThanEqual(goMapsVersion) return inject.WithKeyValue("swiss_maps_used", isUsingGoSwissMaps), nil } diff --git a/internal/pkg/instrumentation/manager_load_test.go b/internal/pkg/instrumentation/manager_load_test.go index 764f9e8b6..deb78728d 100644 --- a/internal/pkg/instrumentation/manager_load_test.go +++ b/internal/pkg/instrumentation/manager_load_test.go @@ -9,15 +9,17 @@ import ( "log/slog" "testing" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "go.opentelemetry.io/auto/internal/pkg/inject" "go.opentelemetry.io/auto/internal/pkg/instrumentation/testutils" "go.opentelemetry.io/auto/internal/pkg/instrumentation/utils" ) func TestLoadProbes(t *testing.T) { - ver, _ := utils.GetLinuxKernelVersion() + ver := utils.GetLinuxKernelVersion() + require.NotNil(t, ver) t.Logf("Running on kernel %s", ver.String()) m := fakeManager(t) @@ -27,7 +29,7 @@ func TestLoadProbes(t *testing.T) { for _, p := range probes { manifest := p.Manifest() fields := manifest.StructFields - offsets := map[string]*version.Version{} + offsets := map[string]*semver.Version{} for _, f := range fields { _, ver := inject.GetLatestOffset(f) if ver != nil { diff --git a/internal/pkg/instrumentation/manager_test.go b/internal/pkg/instrumentation/manager_test.go index 56983706e..afb4d31af 100644 --- a/internal/pkg/instrumentation/manager_test.go +++ b/internal/pkg/instrumentation/manager_test.go @@ -13,8 +13,8 @@ import ( "testing" "time" + "github.com/Masterminds/semver/v3" "github.com/cilium/ebpf/link" - "github.com/hashicorp/go-version" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -30,8 +30,7 @@ import ( ) func TestProbeFiltering(t *testing.T) { - ver, err := version.NewVersion("1.20.0") - assert.NoError(t, err) + ver := semver.New(1, 20, 0, "", "") t.Run("empty target details", func(t *testing.T) { m := fakeManager(t) @@ -40,7 +39,7 @@ func TestProbeFiltering(t *testing.T) { PID: 1, Functions: []*binary.Func{}, GoVersion: ver, - Modules: map[string]*version.Version{}, + Modules: map[string]*semver.Version{}, AllocationDetails: nil, } m.FilterUnusedProbes(&td) @@ -58,7 +57,7 @@ func TestProbeFiltering(t *testing.T) { PID: 1, Functions: httpFuncs, GoVersion: ver, - Modules: map[string]*version.Version{}, + Modules: map[string]*semver.Version{}, AllocationDetails: nil, } m.FilterUnusedProbes(&td) @@ -77,7 +76,7 @@ func TestProbeFiltering(t *testing.T) { PID: 1, Functions: httpFuncs, GoVersion: ver, - Modules: map[string]*version.Version{}, + Modules: map[string]*semver.Version{}, AllocationDetails: nil, } m.FilterUnusedProbes(&td) @@ -97,7 +96,7 @@ func TestProbeFiltering(t *testing.T) { PID: 1, Functions: httpFuncs, GoVersion: ver, - Modules: map[string]*version.Version{}, + Modules: map[string]*semver.Version{}, AllocationDetails: nil, } m.FilterUnusedProbes(&td) diff --git a/internal/pkg/instrumentation/probe/constraint.go b/internal/pkg/instrumentation/probe/constraint.go index 557dd1042..028463358 100644 --- a/internal/pkg/instrumentation/probe/constraint.go +++ b/internal/pkg/instrumentation/probe/constraint.go @@ -3,7 +3,9 @@ package probe -import "github.com/hashicorp/go-version" +import ( + "github.com/Masterminds/semver/v3" +) // FailureMode defines the behavior that is performed when a failure occurs. type FailureMode int @@ -26,7 +28,7 @@ type PackageConstraints struct { // Constraints is the version constraint that is evaluated. If the // constraint is not satisfied, the FailureMode defines the behavior of how // the failure is handled. - Constraints version.Constraints + Constraints *semver.Constraints // FailureMode defines the behavior that is performed when the Constraint // is not satisfied. FailureMode FailureMode diff --git a/internal/pkg/instrumentation/probe/probe.go b/internal/pkg/instrumentation/probe/probe.go index d0a7cb776..c03ac675f 100644 --- a/internal/pkg/instrumentation/probe/probe.go +++ b/internal/pkg/instrumentation/probe/probe.go @@ -14,10 +14,10 @@ import ( "os" "sync/atomic" + "github.com/Masterminds/semver/v3" "github.com/cilium/ebpf" "github.com/cilium/ebpf/link" "github.com/cilium/ebpf/perf" - "github.com/hashicorp/go-version" "go.opentelemetry.io/collector/pdata/ptrace" @@ -521,7 +521,7 @@ type StructFieldConstMaxVersion struct { StructField StructFieldConst // MaxVersion is the exclusive maximum version (it will only match versions // less than this). - MaxVersion *version.Version + MaxVersion *semver.Version } // InjectOption returns the appropriately configured [inject.WithOffset] if the @@ -548,7 +548,7 @@ func (c StructFieldConstMaxVersion) InjectOption(td *process.TargetDetails) (inj // injected if the module version is greater than or equal to the MinVersion. type StructFieldConstMinVersion struct { StructField StructFieldConst - MinVersion *version.Version + MinVersion *semver.Version } // InjectOption returns the appropriately configured [inject.WithOffset] if the @@ -563,7 +563,7 @@ func (c StructFieldConstMinVersion) InjectOption(td *process.TargetDetails) (inj return nil, fmt.Errorf("unknown module version: %s", sf.ID.ModPath) } - if !ver.GreaterThanOrEqual(c.MinVersion) { + if !ver.GreaterThanEqual(c.MinVersion) { return nil, nil } diff --git a/internal/pkg/instrumentation/testutils/testutils.go b/internal/pkg/instrumentation/testutils/testutils.go index af24e6ad5..c64c26d8c 100644 --- a/internal/pkg/instrumentation/testutils/testutils.go +++ b/internal/pkg/instrumentation/testutils/testutils.go @@ -7,9 +7,9 @@ import ( "errors" "testing" + "github.com/Masterminds/semver/v3" "github.com/cilium/ebpf" "github.com/cilium/ebpf/rlimit" - "github.com/hashicorp/go-version" "github.com/stretchr/testify/assert" "go.opentelemetry.io/auto/internal/pkg/instrumentation/bpffs" @@ -17,14 +17,14 @@ import ( "go.opentelemetry.io/auto/internal/pkg/process" ) -var testGoVersion = version.Must(version.NewVersion("1.22.1")) +var testGoVersion = semver.New(1, 22, 1, "", "") type TestProbe interface { Spec() (*ebpf.CollectionSpec, error) InjectConsts(td *process.TargetDetails, spec *ebpf.CollectionSpec) error } -func ProbesLoad(t *testing.T, p TestProbe, libs map[string]*version.Version) { +func ProbesLoad(t *testing.T, p TestProbe, libs map[string]*semver.Version) { err := rlimit.RemoveMemlock() if !assert.NoError(t, err) { return @@ -36,7 +36,7 @@ func ProbesLoad(t *testing.T, p TestProbe, libs map[string]*version.Version) { StartAddr: 140434497441792, EndAddr: 140434497507328, }, - Modules: map[string]*version.Version{ + Modules: map[string]*semver.Version{ "std": testGoVersion, }, GoVersion: testGoVersion, diff --git a/internal/pkg/instrumentation/utils/ebpf.go b/internal/pkg/instrumentation/utils/ebpf.go index b74f62bef..0bb90ad6b 100644 --- a/internal/pkg/instrumentation/utils/ebpf.go +++ b/internal/pkg/instrumentation/utils/ebpf.go @@ -9,8 +9,8 @@ import ( "os" "strconv" + "github.com/Masterminds/semver/v3" "github.com/cilium/ebpf" - "github.com/hashicorp/go-version" ) const ( @@ -53,16 +53,12 @@ func ShouldShowVerifierLogs() bool { // Does kernel version check and /sys/kernel/security/lockdown inspection to determine if it's // safe to use bpf_probe_write_user. func SupportsContextPropagation() bool { - ver, err := GetLinuxKernelVersion() - if err != nil { + ver := GetLinuxKernelVersion() + if ver == nil { return false } - noLockKernel, err := version.NewVersion("5.14") - if err != nil { - fmt.Printf("Error creating version 5.14 - %v\n", err) - } - + noLockKernel := semver.New(5, 14, 0, "", "") if ver.LessThan(noLockKernel) { return true } diff --git a/internal/pkg/instrumentation/utils/kernel_linux.go b/internal/pkg/instrumentation/utils/kernel_linux.go index 831962bb5..f7e908f69 100644 --- a/internal/pkg/instrumentation/utils/kernel_linux.go +++ b/internal/pkg/instrumentation/utils/kernel_linux.go @@ -9,32 +9,35 @@ import ( "fmt" "os" "runtime" - "strconv" "strings" "syscall" "time" "golang.org/x/sys/unix" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" ) var unameFn = syscall.Uname -// parse logic adapted from https://github.com/golang/go/blob/go1.21.3/src/internal/syscall/unix/kernel_version_linux.go -func GetLinuxKernelVersion() (*version.Version, error) { +// GetLinuxKernelVersion returns the current version of the Linux kernel. If +// unable to determine the function, nil is returned. +// +// Adapted from https://github.com/golang/go/blob/go1.21.3/src/internal/syscall/unix/kernel_version_linux.go +func GetLinuxKernelVersion() *semver.Version { var uname syscall.Utsname if err := unameFn(&uname); err != nil { - return nil, err + return nil } var ( - values [2]int - value, vi int + values [2]uint64 + value uint64 + vi int ) for _, c := range uname.Release { if '0' <= c && c <= '9' { - value = (value * 10) + int(c-'0') + value = (value * 10) + uint64(c-'0') // nolint:gosec // c >= '0' } else { // Note that we're assuming N.N.N here. // If we see anything else, we are likely to mis-parse it. @@ -46,9 +49,7 @@ func GetLinuxKernelVersion() (*version.Version, error) { value = 0 } } - ver := fmt.Sprintf("%s.%s", strconv.Itoa(values[0]), strconv.Itoa(values[1])) - - return version.NewVersion(ver) + return semver.New(values[0], values[1], 0, "", "") } // KernelLockdown is the lockdown state of the Linux kernel. diff --git a/internal/pkg/instrumentation/utils/kernel_linux_test.go b/internal/pkg/instrumentation/utils/kernel_linux_test.go index 4dd7634ca..47a63cc30 100644 --- a/internal/pkg/instrumentation/utils/kernel_linux_test.go +++ b/internal/pkg/instrumentation/utils/kernel_linux_test.go @@ -9,28 +9,29 @@ import ( "syscall" "testing" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestGetLinuxKernelVersion(t *testing.T) { tests := map[string]struct { unameFn func(buf *syscall.Utsname) error - want *version.Version + want *semver.Version }{ "ubuntu-23.10": { unameFn: func(buf *syscall.Utsname) error { buf.Release = [65]int8{54, 46, 53, 46, 48, 45, 57, 45, 103, 101, 110, 101, 114, 105, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} return nil }, - want: version.Must(version.NewVersion("6.5")), + want: semver.New(6, 5, 0, "", ""), }, "debian-12": { unameFn: func(buf *syscall.Utsname) error { buf.Release = [65]int8{54, 46, 49, 46, 48, 45, 49, 50, 45, 99, 108, 111, 117, 100, 45, 97, 109, 100, 54, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} return nil }, - want: version.Must(version.NewVersion("6.1")), + want: semver.New(6, 1, 0, "", ""), }, } for name, tt := range tests { @@ -41,11 +42,8 @@ func TestGetLinuxKernelVersion(t *testing.T) { t.Cleanup(func() { unameFn = oldUnameFn }) - got, err := GetLinuxKernelVersion() - if err != nil { - t.Errorf("GetLinuxKernelVersion() error = %v", err) - return - } + got := GetLinuxKernelVersion() + require.NotNil(t, got) assert.Equal(t, tt.want, got) }) diff --git a/internal/pkg/instrumentation/utils/kernel_other.go b/internal/pkg/instrumentation/utils/kernel_other.go index f9da90dcb..7daa7a0cb 100644 --- a/internal/pkg/instrumentation/utils/kernel_other.go +++ b/internal/pkg/instrumentation/utils/kernel_other.go @@ -5,13 +5,13 @@ package utils -import "github.com/hashicorp/go-version" +import ( + "github.com/Masterminds/semver/v3" +) // Stubs for non-linux systems -func GetLinuxKernelVersion() (*version.Version, error) { - return &version.Version{}, nil -} +func GetLinuxKernelVersion() *semver.Version { return nil } type KernelLockdown uint8 diff --git a/internal/pkg/process/analyze.go b/internal/pkg/process/analyze.go index ad6781fc1..866e16039 100644 --- a/internal/pkg/process/analyze.go +++ b/internal/pkg/process/analyze.go @@ -11,7 +11,7 @@ import ( "os" "strings" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "go.opentelemetry.io/auto/internal/pkg/process/binary" ) @@ -20,15 +20,15 @@ import ( type TargetDetails struct { PID int Functions []*binary.Func - GoVersion *version.Version - Modules map[string]*version.Version + GoVersion *semver.Version + Modules map[string]*semver.Version AllocationDetails *AllocationDetails } // IsRegistersABI returns if t is supported. func (t *TargetDetails) IsRegistersABI() bool { - regAbiMinVersion, _ := version.NewVersion("1.17") - return t.GoVersion.GreaterThanOrEqual(regAbiMinVersion) + regAbiMinVersion := semver.New(1, 17, 0, "", "") + return t.GoVersion.GreaterThanEqual(regAbiMinVersion) } // GetFunctionOffset returns the offset for of the function with name. @@ -75,14 +75,14 @@ func (a *Analyzer) Analyze(pid int, relevantFuncs map[string]interface{}) (*Targ return nil, err } - goVersion, err := version.NewVersion(a.BuildInfo.GoVersion) + goVersion, err := semver.NewVersion(a.BuildInfo.GoVersion) if err != nil { return nil, err } result.GoVersion = goVersion - result.Modules = make(map[string]*version.Version, len(a.BuildInfo.Deps)+1) + result.Modules = make(map[string]*semver.Version, len(a.BuildInfo.Deps)+1) for _, dep := range a.BuildInfo.Deps { - depVersion, err := version.NewVersion(dep.Version) + depVersion, err := semver.NewVersion(dep.Version) if err != nil { a.logger.Error("parsing dependency version", "error", err, "dependency", dep) continue diff --git a/internal/pkg/process/ptrace_linux.go b/internal/pkg/process/ptrace_linux.go index d1300afe7..535067a49 100644 --- a/internal/pkg/process/ptrace_linux.go +++ b/internal/pkg/process/ptrace_linux.go @@ -13,7 +13,7 @@ import ( "golang.org/x/sys/unix" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "github.com/pkg/errors" "go.opentelemetry.io/auto/internal/pkg/instrumentation/utils" @@ -228,18 +228,18 @@ func (p *tracedProgram) Mmap(length uint64, fd uint64) (uint64, error) { // Madvise runs madvise syscall. func (p *tracedProgram) Madvise(addr uint64, length uint64) error { advice := uint64(syscall.MADV_WILLNEED) - ver, err := utils.GetLinuxKernelVersion() - if err != nil { - return errors.WithStack(err) + ver := utils.GetLinuxKernelVersion() + if ver == nil { + return errors.WithStack(errors.New("unknown Linux version")) } - minVersion := version.Must(version.NewVersion("5.14")) + minVersion := semver.New(5, 14, 0, "", "") p.logger.Debug("Detected linux kernel version", "version", ver) - if ver.GreaterThanOrEqual(minVersion) { + if ver.GreaterThanEqual(minVersion) { advice = syscall.MADV_WILLNEED | MadvisePopulateRead | MadvisePopulateWrite } - _, err = p.Syscall(syscall.SYS_MADVISE, addr, length, advice, 0, 0, 0) + _, err := p.Syscall(syscall.SYS_MADVISE, addr, length, advice, 0, 0, 0) return err } diff --git a/internal/pkg/structfield/json.go b/internal/pkg/structfield/json.go index 0ea669193..daf2d0c3b 100644 --- a/internal/pkg/structfield/json.go +++ b/internal/pkg/structfield/json.go @@ -3,11 +3,11 @@ package structfield -import "github.com/hashicorp/go-version" +import "github.com/Masterminds/semver/v3" type jsonOffset struct { - Offset *uint64 `json:"offset"` - Versions []*version.Version `json:"versions"` + Offset *uint64 `json:"offset"` + Versions []*semver.Version `json:"versions"` } type jsonField struct { @@ -31,7 +31,7 @@ func (jf *jsonField) addOffsets(off *Offsets) { jOff.Offset = &offTmp.Offset } - jOff.Versions = mergeSorted(jOff.Versions, vers, func(a, b *version.Version) int { + jOff.Versions = mergeSorted(jOff.Versions, vers, func(a, b *semver.Version) int { return a.Compare(b) }) } diff --git a/internal/pkg/structfield/structfield.go b/internal/pkg/structfield/structfield.go index 30a4fb1bf..b6ad2815b 100644 --- a/internal/pkg/structfield/structfield.go +++ b/internal/pkg/structfield/structfield.go @@ -11,7 +11,7 @@ import ( "strings" "sync" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" ) // Index holds all struct field offsets. @@ -42,7 +42,7 @@ func (i *Index) get(id ID) (*Offsets, bool) { // GetOffset returns the offset value and true for the version ver of id // contained in the Index i. It will return zero and false for any id not // contained in i. -func (i *Index) GetOffset(id ID, ver *version.Version) (OffsetKey, bool) { +func (i *Index) GetOffset(id ID, ver *semver.Version) (OffsetKey, bool) { i.dataMu.RLock() defer i.dataMu.RUnlock() @@ -51,7 +51,7 @@ func (i *Index) GetOffset(id ID, ver *version.Version) (OffsetKey, bool) { // GetLatestOffset returns the latest known offset value and version for id // contained in the Index i. -func (i *Index) GetLatestOffset(id ID) (OffsetKey, *version.Version) { +func (i *Index) GetLatestOffset(id ID) (OffsetKey, *semver.Version) { i.dataMu.RLock() defer i.dataMu.RUnlock() @@ -60,10 +60,10 @@ func (i *Index) GetLatestOffset(id ID) (OffsetKey, *version.Version) { return OffsetKey{}, nil } off, ver := offs.getLatest() - return off, ver.ToVersion() + return off, &ver.Version } -func (i *Index) getOffset(id ID, ver *version.Version) (OffsetKey, bool) { +func (i *Index) getOffset(id ID, ver *semver.Version) (OffsetKey, bool) { offs, ok := i.get(id) if !ok { return OffsetKey{}, false @@ -91,14 +91,14 @@ func (i *Index) put(id ID, offsets *Offsets) { // // This will update any existing offsets stored for id with offset. If ver // already exists within those offsets it will overwrite that value. -func (i *Index) PutOffset(id ID, ver *version.Version, offset uint64, valid bool) { +func (i *Index) PutOffset(id ID, ver *semver.Version, offset uint64, valid bool) { i.dataMu.Lock() defer i.dataMu.Unlock() i.putOffset(id, ver, offset, valid) } -func (i *Index) putOffset(id ID, ver *version.Version, offset uint64, valid bool) { +func (i *Index) putOffset(id ID, ver *semver.Version, offset uint64, valid bool) { off, ok := i.get(id) if !ok { off = NewOffsets() @@ -254,7 +254,7 @@ func NewOffsets() *Offsets { // Get returns the offset in bytes and true if known. Otherwise, 0 and false // are returned. -func (o *Offsets) Get(ver *version.Version) (OffsetKey, bool) { +func (o *Offsets) Get(ver *semver.Version) (OffsetKey, bool) { if o == nil { return OffsetKey{}, false } @@ -292,7 +292,7 @@ func (o *Offsets) getLatest() (OffsetKey, verKey) { // Put sets the offset value for ver. If an offset for ver is already known // (i.e. ver.Equal(other) == true), this will overwrite that value. -func (o *Offsets) Put(ver *version.Version, offset OffsetKey) { +func (o *Offsets) Put(ver *semver.Version, offset OffsetKey) { ov := offsetVersion{offset: offset, version: ver} o.mu.Lock() @@ -313,37 +313,19 @@ func (o *Offsets) Put(ver *version.Version, offset OffsetKey) { } func (v verKey) GreaterThan(other verKey) bool { - if v.major != other.major { - return v.major > other.major - } - if v.minor != other.minor { - return v.minor > other.minor - } - if v.patch != other.patch { - return v.patch > other.patch - } - return false + return v.Version.GreaterThan(&other.Version) } -func (v verKey) ToVersion() *version.Version { - vs := fmt.Sprintf("%d.%d.%d", v.major, v.minor, v.patch) - if v.prerelease != "" { - vs += "-" + v.prerelease - } - ver, _ := version.NewVersion(vs) - return ver -} - -func (o *Offsets) index() map[OffsetKey][]*version.Version { +func (o *Offsets) index() map[OffsetKey][]*semver.Version { o.mu.RLock() defer o.mu.RUnlock() - out := make(map[OffsetKey][]*version.Version) + out := make(map[OffsetKey][]*semver.Version) for _, ov := range o.values { vers, ok := out[ov.offset] if ok { i := sort.Search(len(vers), func(i int) bool { - return vers[i].GreaterThanOrEqual(ov.version) + return vers[i].GreaterThanEqual(ov.version) }) vers = append(vers, nil) copy(vers[i+1:], vers[i:]) @@ -357,9 +339,7 @@ func (o *Offsets) index() map[OffsetKey][]*version.Version { } type verKey struct { - major, minor, patch uint64 - prerelease string - metadata string + semver.Version } // OffsetKey is the offset of a specific struct field in a specific version. @@ -370,19 +350,19 @@ type OffsetKey struct { Valid bool } -func newVerKey(v *version.Version) verKey { - var segs [3]int - copy(segs[:], v.Segments()) - return verKey{ - major: uint64(max(segs[0], 0)), // nolint: gosec // Bounded. - minor: uint64(max(segs[1], 0)), // nolint: gosec // Bounded. - patch: uint64(max(segs[2], 0)), // nolint: gosec // Bounded. - prerelease: v.Prerelease(), - metadata: v.Metadata(), - } +func newVerKey(v *semver.Version) verKey { + // Strip out v.original to prevent ambiguity. + stripped := semver.New( + v.Major(), + v.Minor(), + v.Patch(), + v.Prerelease(), + v.Metadata(), + ) + return verKey{Version: *stripped} } type offsetVersion struct { offset OffsetKey - version *version.Version + version *semver.Version } diff --git a/internal/pkg/structfield/structfield_test.go b/internal/pkg/structfield/structfield_test.go index 4b36e78b0..da0e8faf5 100644 --- a/internal/pkg/structfield/structfield_test.go +++ b/internal/pkg/structfield/structfield_test.go @@ -10,17 +10,17 @@ import ( "strings" "testing" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) var ( - v110 = version.Must(version.NewVersion("1.1.0")) - v12 = version.Must(version.NewVersion("1.2")) - v120 = version.Must(version.NewVersion("1.2.0")) - v121 = version.Must(version.NewVersion("1.2.1")) - v130 = version.Must(version.NewVersion("1.3.0")) + v110 = semver.New(1, 1, 0, "", "") + v12 = semver.New(1, 2, 0, "", "") + v120 = semver.New(1, 2, 0, "", "") + v121 = semver.New(1, 2, 1, "", "") + v130 = semver.New(1, 3, 0, "", "") ) func TestOffsets(t *testing.T) { @@ -54,7 +54,7 @@ func TestOffsets(t *testing.T) { assert.Equal(t, OffsetKey{Offset: 2, Valid: true}, off, "invalid value for 1.2.1") off, ver := o.getLatest() - assert.Equal(t, v121, ver.ToVersion(), "invalid version for latest") + assert.Equal(t, v121, &ver.Version, "invalid version for latest") assert.Equal(t, OffsetKey{Offset: 2, Valid: true}, off, "invalid value for latest") o.Put(v120, OffsetKey{Offset: 1, Valid: true}) diff --git a/internal/tools/go.mod b/internal/tools/go.mod index 201834e93..e883491d6 100644 --- a/internal/tools/go.mod +++ b/internal/tools/go.mod @@ -3,10 +3,10 @@ module go.opentelemetry.io/auto/internal/tools go 1.23.0 require ( + github.com/Masterminds/semver/v3 v3.3.1 github.com/docker/docker v27.5.1+incompatible github.com/golangci/golangci-lint v1.64.4 github.com/google/go-licenses/v2 v2.0.0-alpha.1 - github.com/hashicorp/go-version v1.7.0 go.opentelemetry.io/auto v0.20.0 go.opentelemetry.io/build-tools/dbotconf v0.18.0 go.opentelemetry.io/build-tools/multimod v0.18.0 @@ -26,7 +26,6 @@ require ( github.com/Crocmagnon/fatcontext v0.7.1 // indirect github.com/Djarvur/go-err113 v0.1.0 // indirect github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 // indirect - github.com/Masterminds/semver/v3 v3.3.1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/OpenPeeDeeP/depguard/v2 v2.2.0 // indirect github.com/ProtonMail/go-crypto v1.1.5 // indirect @@ -105,6 +104,7 @@ require ( github.com/gostaticanalysis/forcetypeassert v0.2.0 // indirect github.com/gostaticanalysis/nilerr v0.1.1 // indirect github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect + github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect diff --git a/internal/tools/inspect/app.go b/internal/tools/inspect/app.go index 92c0a772d..3f273cf7a 100644 --- a/internal/tools/inspect/app.go +++ b/internal/tools/inspect/app.go @@ -11,7 +11,7 @@ import ( "log/slog" "os" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "go.opentelemetry.io/auto/internal/pkg/process" "go.opentelemetry.io/auto/internal/pkg/structfield" @@ -21,7 +21,7 @@ import ( type app struct { Renderer Renderer Builder *builder - AppVer *version.Version + AppVer *semver.Version Fields []structfield.ID log *slog.Logger diff --git a/internal/tools/inspect/builder.go b/internal/tools/inspect/builder.go index 2fdab16ab..b545b1c9a 100644 --- a/internal/tools/inspect/builder.go +++ b/internal/tools/inspect/builder.go @@ -14,6 +14,7 @@ import ( "os" "path/filepath" + "github.com/Masterminds/semver/v3" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/image" @@ -21,18 +22,17 @@ import ( "github.com/docker/docker/api/types/registry" "github.com/docker/docker/client" "github.com/docker/docker/pkg/stdcopy" - "github.com/hashicorp/go-version" ) // minCompatVer is the min "go mod" version that includes the "compat" option. -var minCompatVer = version.Must(version.NewVersion("1.17.0")) +var minCompatVer = semver.New(1, 17, 0, "", "") // builder builds a Go application into a binary using Docker. type builder struct { log *slog.Logger cli *client.Client - goVer *version.Version + goVer *semver.Version GoImage string } @@ -42,7 +42,7 @@ type builder struct { // // If goVer is nil, the latest version of the Go docker container will be used // to build applications. -func newBuilder(l *slog.Logger, cli *client.Client, goVer *version.Version) *builder { +func newBuilder(l *slog.Logger, cli *client.Client, goVer *semver.Version) *builder { img := "golang:latest" if goVer != nil { // Use goVer.String here so 1.12 means 1.12.0. If Original is used, it @@ -59,7 +59,7 @@ func newBuilder(l *slog.Logger, cli *client.Client, goVer *version.Version) *bui } // Build builds the appV version of a Go application located in dir. -func (b *builder) Build(ctx context.Context, dir string, appV *version.Version, modName string) (string, error) { +func (b *builder) Build(ctx context.Context, dir string, appV *semver.Version, modName string) (string, error) { b.log.Debug("building application...", "version", appV, "dir", dir, "image", b.GoImage) app := "app" + appV.Original() diff --git a/internal/tools/inspect/cache.go b/internal/tools/inspect/cache.go index 5a91b279e..8a1b9d08d 100644 --- a/internal/tools/inspect/cache.go +++ b/internal/tools/inspect/cache.go @@ -8,7 +8,7 @@ import ( "log/slog" "os" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "go.opentelemetry.io/auto/internal/pkg/structfield" ) @@ -42,7 +42,7 @@ func newCache(l *slog.Logger) *Cache { // GetOffset returns the cached offset key and true for the id at the specified // version is found in the cache. If the cache does not contain a valid offset for the provided // values, 0 and false are returned. -func (c *Cache) GetOffset(ver *version.Version, id structfield.ID) (structfield.OffsetKey, bool) { +func (c *Cache) GetOffset(ver *semver.Version, id structfield.ID) (structfield.OffsetKey, bool) { if c.data == nil { return structfield.OffsetKey{}, false } diff --git a/internal/tools/inspect/cmd/offsetgen/versions.go b/internal/tools/inspect/cmd/offsetgen/versions.go index ca7cd9541..bea6a4b5e 100644 --- a/internal/tools/inspect/cmd/offsetgen/versions.go +++ b/internal/tools/inspect/cmd/offsetgen/versions.go @@ -12,7 +12,7 @@ import ( "sort" "strings" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" ) const jsonURL = "https://go.dev/dl/?mode=json&include=all" @@ -24,7 +24,7 @@ type goListResponse struct { // PkgVersions returns all locally known version of module with // moduleName. -func PkgVersions(name string) ([]*version.Version, error) { +func PkgVersions(name string) ([]*semver.Version, error) { command := "go list -m -json -versions " + name cmd := exec.Command("bash", "-c", command) @@ -40,9 +40,9 @@ func PkgVersions(name string) ([]*version.Version, error) { return nil, err } - out := make([]*version.Version, len(resp.Versions)) + out := make([]*semver.Version, len(resp.Versions)) for i, v := range resp.Versions { - conv, err := version.NewVersion(v) + conv, err := semver.NewVersion(v) if err != nil { return nil, err } @@ -58,7 +58,7 @@ type goDevResponse struct { // GoVersions returns all known GoVersions versions from the GoVersions package mirror at // https://go.dev/dl/. -func GoVersions(constraints ...string) ([]*version.Version, error) { +func GoVersions(constraints ...string) ([]*semver.Version, error) { res, err := http.Get(jsonURL) if err != nil { return nil, err @@ -76,11 +76,11 @@ func GoVersions(constraints ...string) ([]*version.Version, error) { return nil, err } - var versions []*version.Version + var versions []*semver.Version for _, v := range resp { if v.Stable { stripepdV := strings.ReplaceAll(v.Version, "go", "") - v, err := version.NewVersion(stripepdV) + v, err := semver.NewVersion(stripepdV) if err != nil { return nil, err } @@ -95,17 +95,17 @@ func GoVersions(constraints ...string) ([]*version.Version, error) { return constrained, err } -func constrain(vers []*version.Version, constrains []string) ([]*version.Version, error) { - var cnsts []version.Constraints +func constrain(vers []*semver.Version, constrains []string) ([]*semver.Version, error) { + var cnsts []*semver.Constraints for _, c := range constrains { - parsed, err := version.NewConstraint(c) + parsed, err := semver.NewConstraint(c) if err != nil { return nil, err } cnsts = append(cnsts, parsed) } - valid := func(v *version.Version) bool { + valid := func(v *semver.Version) bool { for _, c := range cnsts { if !c.Check(v) { return false @@ -114,7 +114,7 @@ func constrain(vers []*version.Version, constrains []string) ([]*version.Version return true } - var fltr []*version.Version + var fltr []*semver.Version for _, ver := range vers { if valid(ver) { fltr = append(fltr, ver) diff --git a/internal/tools/inspect/inspector.go b/internal/tools/inspect/inspector.go index a712120f3..c6417fa07 100644 --- a/internal/tools/inspect/inspector.go +++ b/internal/tools/inspect/inspector.go @@ -8,8 +8,8 @@ import ( "errors" "log/slog" + "github.com/Masterminds/semver/v3" "github.com/docker/docker/client" - "github.com/hashicorp/go-version" "golang.org/x/sync/errgroup" "go.opentelemetry.io/auto/internal/pkg/structfield" @@ -120,7 +120,7 @@ func (i *Inspector) AddManifest(manifest Manifest) error { type job struct { Renderer Renderer Builder *builder - AppVer *version.Version + AppVer *semver.Version Fields []structfield.ID } @@ -181,7 +181,7 @@ func (i *Inspector) Do(ctx context.Context) (*structfield.Index, error) { type result struct { StructField structfield.ID - Version *version.Version + Version *semver.Version Offset uint64 // Valid is true if the offset is valid for the struct field at the specified version. Valid bool diff --git a/internal/tools/inspect/manifest.go b/internal/tools/inspect/manifest.go index 2b81d7706..0d58ca1fe 100644 --- a/internal/tools/inspect/manifest.go +++ b/internal/tools/inspect/manifest.go @@ -6,7 +6,7 @@ package inspect import ( "errors" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" "go.opentelemetry.io/auto/internal/pkg/structfield" ) @@ -38,9 +38,9 @@ type Application struct { // // If this is nil, the GoVerions will also be used as the application // versions that are passed to the template. - Versions []*version.Version + Versions []*semver.Version // GoVerions are the versions of Go to build the application with. // // If this is nil, the latest version of Go will be used. - GoVerions []*version.Version + GoVerions []*semver.Version } diff --git a/internal/tools/synclibbpf/main.go b/internal/tools/synclibbpf/main.go index f7676a667..381b0c31e 100644 --- a/internal/tools/synclibbpf/main.go +++ b/internal/tools/synclibbpf/main.go @@ -18,7 +18,7 @@ import ( "sort" "strings" - "github.com/hashicorp/go-version" + "github.com/Masterminds/semver/v3" ) const ( @@ -41,7 +41,7 @@ func main() { dest := flag.String("dest", "./libbpf", "Destination directory for extracted files") flag.Parse() - constraint, err := version.NewConstraint(*ver) + constraint, err := semver.NewConstraint(*ver) if err != nil { log.Fatalf("Invalid version %q: %s", *ver, err) } @@ -67,11 +67,11 @@ func main() { // Release is a partial set of GitHub release info. type Release struct { - TagName *version.Version `json:"tag_name"` - TarballURL string `json:"tarball_url"` + TagName *semver.Version `json:"tag_name"` + TarballURL string `json:"tarball_url"` } -func latestRelease(constraint version.Constraints) (*Release, error) { +func latestRelease(constraint *semver.Constraints) (*Release, error) { resp, err := http.Get(repoAPI) if err != nil { return nil, err diff --git a/versions.yaml b/versions.yaml index 4b9d4c8f3..a9e0f78b6 100644 --- a/versions.yaml +++ b/versions.yaml @@ -11,7 +11,6 @@ module-sets: modules: - go.opentelemetry.io/auto/sdk excluded-modules: - - github.com/hashicorp/go-version - go.opentelemetry.io/auto/examples - go.opentelemetry.io/auto/examples/httpPlusdb - go.opentelemetry.io/auto/examples/kafka-go/producer