From 8dea7442369ed9e54c9d56ed8f9027e4e57f2726 Mon Sep 17 00:00:00 2001 From: Jimmy Zelinskie Date: Fri, 13 Jan 2017 01:37:18 -0500 Subject: [PATCH] delete unused types.Version --- utils/types/version.go | 296 ------------------------------------ utils/types/version_test.go | 243 ----------------------------- 2 files changed, 539 deletions(-) delete mode 100644 utils/types/version.go delete mode 100644 utils/types/version_test.go diff --git a/utils/types/version.go b/utils/types/version.go deleted file mode 100644 index 4c241f24..00000000 --- a/utils/types/version.go +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright 2015 clair authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package types - -import ( - "database/sql/driver" - "encoding/json" - "errors" - "strconv" - "strings" - "unicode" -) - -// Version represents a package version -type Version struct { - epoch int - version string - revision string -} - -var ( - // MinVersion is a special package version which is always sorted first - MinVersion = Version{version: "#MINV#"} - // MaxVersion is a special package version which is always sorted last - MaxVersion = Version{version: "#MAXV#"} - - versionAllowedSymbols = []rune{'.', '-', '+', '~', ':', '_'} - revisionAllowedSymbols = []rune{'.', '+', '~', '_'} -) - -// NewVersion function parses a string into a Version struct which can be compared -// -// The implementation is based on http://man.he.net/man5/deb-version -// on https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version -// -// It uses the dpkg-1.17.25's algorithm (lib/parsehelp.c) -func NewVersion(str string) (Version, error) { - var version Version - - // Trim leading and trailing space - str = strings.TrimSpace(str) - - if len(str) == 0 { - return Version{}, errors.New("Version string is empty") - } - - // Max/Min versions - if str == MaxVersion.String() { - return MaxVersion, nil - } - if str == MinVersion.String() { - return MinVersion, nil - } - - // Find epoch - sepepoch := strings.Index(str, ":") - if sepepoch > -1 { - intepoch, err := strconv.Atoi(str[:sepepoch]) - if err == nil { - version.epoch = intepoch - } else { - return Version{}, errors.New("epoch in version is not a number") - } - if intepoch < 0 { - return Version{}, errors.New("epoch in version is negative") - } - } else { - version.epoch = 0 - } - - // Find version / revision - seprevision := strings.LastIndex(str, "-") - if seprevision > -1 { - version.version = str[sepepoch+1 : seprevision] - version.revision = str[seprevision+1:] - } else { - version.version = str[sepepoch+1:] - version.revision = "" - } - // Verify format - if len(version.version) == 0 { - return Version{}, errors.New("No version") - } - - if !unicode.IsDigit(rune(version.version[0])) { - return Version{}, errors.New("version does not start with digit") - } - - for i := 0; i < len(version.version); i = i + 1 { - r := rune(version.version[i]) - if !unicode.IsDigit(r) && !unicode.IsLetter(r) && !containsRune(versionAllowedSymbols, r) { - return Version{}, errors.New("invalid character in version") - } - } - - for i := 0; i < len(version.revision); i = i + 1 { - r := rune(version.revision[i]) - if !unicode.IsDigit(r) && !unicode.IsLetter(r) && !containsRune(revisionAllowedSymbols, r) { - return Version{}, errors.New("invalid character in revision") - } - } - - return version, nil -} - -// NewVersionUnsafe is just a wrapper around NewVersion that ignore potentiel -// parsing error. Useful for test purposes -func NewVersionUnsafe(str string) Version { - v, _ := NewVersion(str) - return v -} - -// Compare function compares two Debian-like package version -// -// The implementation is based on http://man.he.net/man5/deb-version -// on https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version -// -// It uses the dpkg-1.17.25's algorithm (lib/version.c) -func (a Version) Compare(b Version) int { - // Quick check - if a == b { - return 0 - } - - // Max/Min comparison - if a == MinVersion || b == MaxVersion { - return -1 - } - if b == MinVersion || a == MaxVersion { - return 1 - } - - // Compare epochs - if a.epoch > b.epoch { - return 1 - } - if a.epoch < b.epoch { - return -1 - } - - // Compare version - rc := verrevcmp(a.version, b.version) - if rc != 0 { - return signum(rc) - } - - // Compare revision - return signum(verrevcmp(a.revision, b.revision)) -} - -// String returns the string representation of a Version -func (v Version) String() (s string) { - if v.epoch != 0 { - s = strconv.Itoa(v.epoch) + ":" - } - s += v.version - if v.revision != "" { - s += "-" + v.revision - } - return -} - -func (v Version) MarshalJSON() ([]byte, error) { - return json.Marshal(v.String()) -} - -func (v *Version) UnmarshalJSON(b []byte) (err error) { - var str string - json.Unmarshal(b, &str) - vp := NewVersionUnsafe(str) - *v = vp - return -} - -func (v *Version) Scan(value interface{}) (err error) { - val, ok := value.([]byte) - if !ok { - return errors.New("could not scan a Version from a non-string input") - } - *v, err = NewVersion(string(val)) - return -} - -func (v *Version) Value() (driver.Value, error) { - return v.String(), nil -} - -func verrevcmp(t1, t2 string) int { - t1, rt1 := nextRune(t1) - t2, rt2 := nextRune(t2) - - for rt1 != nil || rt2 != nil { - firstDiff := 0 - - for (rt1 != nil && !unicode.IsDigit(*rt1)) || (rt2 != nil && !unicode.IsDigit(*rt2)) { - ac := 0 - bc := 0 - if rt1 != nil { - ac = order(*rt1) - } - if rt2 != nil { - bc = order(*rt2) - } - - if ac != bc { - return ac - bc - } - - t1, rt1 = nextRune(t1) - t2, rt2 = nextRune(t2) - } - for rt1 != nil && *rt1 == '0' { - t1, rt1 = nextRune(t1) - } - for rt2 != nil && *rt2 == '0' { - t2, rt2 = nextRune(t2) - } - for rt1 != nil && unicode.IsDigit(*rt1) && rt2 != nil && unicode.IsDigit(*rt2) { - if firstDiff == 0 { - firstDiff = int(*rt1) - int(*rt2) - } - t1, rt1 = nextRune(t1) - t2, rt2 = nextRune(t2) - } - if rt1 != nil && unicode.IsDigit(*rt1) { - return 1 - } - if rt2 != nil && unicode.IsDigit(*rt2) { - return -1 - } - if firstDiff != 0 { - return firstDiff - } - } - - return 0 -} - -// order compares runes using a modified ASCII table -// so that letters are sorted earlier than non-letters -// and so that tildes sorts before anything -func order(r rune) int { - if unicode.IsDigit(r) { - return 0 - } - - if unicode.IsLetter(r) { - return int(r) - } - - if r == '~' { - return -1 - } - - return int(r) + 256 -} - -func nextRune(str string) (string, *rune) { - if len(str) >= 1 { - r := rune(str[0]) - return str[1:], &r - } - return str, nil -} - -func containsRune(s []rune, e rune) bool { - for _, a := range s { - if a == e { - return true - } - } - return false -} - -func signum(a int) int { - switch { - case a < 0: - return -1 - case a > 0: - return +1 - } - - return 0 -} diff --git a/utils/types/version_test.go b/utils/types/version_test.go deleted file mode 100644 index 4796ceb9..00000000 --- a/utils/types/version_test.go +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright 2015 clair authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package types - -import ( - "strings" - "testing" - - "github.com/stretchr/testify/assert" -) - -const ( - LESS = -1 - EQUAL = 0 - GREATER = 1 -) - -func TestCompareSimpleVersion(t *testing.T) { - cases := []struct { - v1 Version - expected int - v2 Version - }{ - {Version{}, EQUAL, Version{}}, - {Version{epoch: 1}, LESS, Version{epoch: 2}}, - {Version{epoch: 0, version: "1", revision: "1"}, LESS, Version{epoch: 0, version: "2", revision: "1"}}, - {Version{epoch: 0, version: "a", revision: "0"}, LESS, Version{epoch: 0, version: "b", revision: "0"}}, - {Version{epoch: 0, version: "1", revision: "1"}, LESS, Version{epoch: 0, version: "1", revision: "2"}}, - {Version{epoch: 0, version: "0", revision: "0"}, EQUAL, Version{epoch: 0, version: "0", revision: "0"}}, - {Version{epoch: 0, version: "0", revision: "00"}, EQUAL, Version{epoch: 0, version: "00", revision: "0"}}, - {Version{epoch: 1, version: "2", revision: "3"}, EQUAL, Version{epoch: 1, version: "2", revision: "3"}}, - {Version{epoch: 0, version: "0", revision: "a"}, LESS, Version{epoch: 0, version: "0", revision: "b"}}, - {MinVersion, LESS, MaxVersion}, - {MinVersion, LESS, Version{}}, - {MinVersion, LESS, Version{version: "0"}}, - {MaxVersion, GREATER, Version{}}, - {MaxVersion, GREATER, Version{epoch: 9999999, version: "9999999", revision: "9999999"}}, - } - - for _, c := range cases { - cmp := c.v1.Compare(c.v2) - assert.Equal(t, c.expected, cmp, "%s vs. %s, = %d, expected %d", c.v1, c.v2, cmp, c.expected) - - cmp = c.v2.Compare(c.v1) - assert.Equal(t, -c.expected, cmp, "%s vs. %s, = %d, expected %d", c.v2, c.v1, cmp, -c.expected) - } -} - -func TestParse(t *testing.T) { - cases := []struct { - str string - ver Version - err bool - }{ - // Test 0 - {"0", Version{epoch: 0, version: "0", revision: ""}, false}, - {"0:0", Version{epoch: 0, version: "0", revision: ""}, false}, - {"0:0-", Version{epoch: 0, version: "0", revision: ""}, false}, - {"0:0-0", Version{epoch: 0, version: "0", revision: "0"}, false}, - {"0:0.0-0.0", Version{epoch: 0, version: "0.0", revision: "0.0"}, false}, - // Test epoched - {"1:0", Version{epoch: 1, version: "0", revision: ""}, false}, - {"5:1", Version{epoch: 5, version: "1", revision: ""}, false}, - // Test multiple hypens - {"0:0-0-0", Version{epoch: 0, version: "0-0", revision: "0"}, false}, - {"0:0-0-0-0", Version{epoch: 0, version: "0-0-0", revision: "0"}, false}, - // Test multiple colons - {"0:0:0-0", Version{epoch: 0, version: "0:0", revision: "0"}, false}, - {"0:0:0:0-0", Version{epoch: 0, version: "0:0:0", revision: "0"}, false}, - // Test multiple hyphens and colons - {"0:0:0-0-0", Version{epoch: 0, version: "0:0-0", revision: "0"}, false}, - {"0:0-0:0-0", Version{epoch: 0, version: "0-0:0", revision: "0"}, false}, - // Test valid characters in version - {"0:09azAZ.-+~:_-0", Version{epoch: 0, version: "09azAZ.-+~:_", revision: "0"}, false}, - // Test valid characters in debian revision - {"0:0-azAZ09.+~_", Version{epoch: 0, version: "0", revision: "azAZ09.+~_"}, false}, - // Test version with leading and trailing spaces - {" 0:0-1", Version{epoch: 0, version: "0", revision: "1"}, false}, - {"0:0-1 ", Version{epoch: 0, version: "0", revision: "1"}, false}, - {" 0:0-1 ", Version{epoch: 0, version: "0", revision: "1"}, false}, - // Test empty version - {"", Version{}, true}, - {" ", Version{}, true}, - {"0:", Version{}, true}, - // Test version with embedded spaces - {"0:0 0-1", Version{}, true}, - // Test version with negative epoch - {"-1:0-1", Version{}, true}, - // Test invalid characters in epoch - {"a:0-0", Version{}, true}, - {"A:0-0", Version{}, true}, - // Test version not starting with a digit - {"0:abc3-0", Version{}, true}, - } - for _, c := range cases { - v, err := NewVersion(c.str) - - if c.err { - assert.Error(t, err, "When parsing '%s'", c.str) - } else { - assert.Nil(t, err, "When parsing '%s'", c.str) - } - assert.Equal(t, c.ver, v, "When parsing '%s'", c.str) - } - - // Test invalid characters in version - versym := []rune{'!', '#', '@', '$', '%', '&', '/', '|', '\\', '<', '>', '(', ')', '[', ']', '{', '}', ';', ',', '=', '*', '^', '\''} - for _, r := range versym { - _, err := NewVersion(strings.Join([]string{"0:0", string(r), "-0"}, "")) - assert.Error(t, err, "Parsing with invalid character '%s' in version should have failed", string(r)) - } - - // Test invalid characters in revision - versym = []rune{'!', '#', '@', '$', '%', '&', '/', '|', '\\', '<', '>', '(', ')', '[', ']', '{', '}', ':', ';', ',', '=', '*', '^', '\''} - for _, r := range versym { - _, err := NewVersion(strings.Join([]string{"0:0-", string(r)}, "")) - assert.Error(t, err, "Parsing with invalid character '%s' in revision should have failed", string(r)) - } -} - -func TestParseAndCompare(t *testing.T) { - const LESS = -1 - const EQUAL = 0 - const GREATER = 1 - - cases := []struct { - v1 string - expected int - v2 string - }{ - {"7.6p2-4", GREATER, "7.6-0"}, - {"1.0.3-3", GREATER, "1.0-1"}, - {"1.3", GREATER, "1.2.2-2"}, - {"1.3", GREATER, "1.2.2"}, - // Some properties of text strings - {"0-pre", EQUAL, "0-pre"}, - {"0-pre", LESS, "0-pree"}, - {"1.1.6r2-2", GREATER, "1.1.6r-1"}, - {"2.6b2-1", GREATER, "2.6b-2"}, - {"98.1p5-1", LESS, "98.1-pre2-b6-2"}, - {"0.4a6-2", GREATER, "0.4-1"}, - {"1:3.0.5-2", LESS, "1:3.0.5.1"}, - // epochs - {"1:0.4", GREATER, "10.3"}, - {"1:1.25-4", LESS, "1:1.25-8"}, - {"0:1.18.36", EQUAL, "1.18.36"}, - {"1.18.36", GREATER, "1.18.35"}, - {"0:1.18.36", GREATER, "1.18.35"}, - // Funky, but allowed, characters in upstream version - {"9:1.18.36:5.4-20", LESS, "10:0.5.1-22"}, - {"9:1.18.36:5.4-20", LESS, "9:1.18.36:5.5-1"}, - {"9:1.18.36:5.4-20", LESS, " 9:1.18.37:4.3-22"}, - {"1.18.36-0.17.35-18", GREATER, "1.18.36-19"}, - // Junk - {"1:1.2.13-3", LESS, "1:1.2.13-3.1"}, - {"2.0.7pre1-4", LESS, "2.0.7r-1"}, - // if a version includes a dash, it should be the debrev dash - policy says so - {"0:0-0-0", GREATER, "0-0"}, - // do we like strange versions? Yes we like strange versions… - {"0", EQUAL, "0"}, - {"0", EQUAL, "00"}, - // #205960 - {"3.0~rc1-1", LESS, "3.0-1"}, - // #573592 - debian policy 5.6.12 - {"1.0", EQUAL, "1.0-0"}, - {"0.2", LESS, "1.0-0"}, - {"1.0", LESS, "1.0-0+b1"}, - {"1.0", GREATER, "1.0-0~"}, - // "steal" the testcases from (old perl) cupt - {"1.2.3", EQUAL, "1.2.3"}, // identical - {"4.4.3-2", EQUAL, "4.4.3-2"}, // identical - {"1:2ab:5", EQUAL, "1:2ab:5"}, // this is correct... - {"7:1-a:b-5", EQUAL, "7:1-a:b-5"}, // and this - {"57:1.2.3abYZ+~-4-5", EQUAL, "57:1.2.3abYZ+~-4-5"}, // and those too - {"1.2.3", EQUAL, "0:1.2.3"}, // zero epoch - {"1.2.3", EQUAL, "1.2.3-0"}, // zero revision - {"009", EQUAL, "9"}, // zeroes… - {"009ab5", EQUAL, "9ab5"}, // there as well - {"1.2.3", LESS, "1.2.3-1"}, // added non-zero revision - {"1.2.3", LESS, "1.2.4"}, // just bigger - {"1.2.4", GREATER, "1.2.3"}, // order doesn't matter - {"1.2.24", GREATER, "1.2.3"}, // bigger, eh? - {"0.10.0", GREATER, "0.8.7"}, // bigger, eh? - {"3.2", GREATER, "2.3"}, // major number rocks - {"1.3.2a", GREATER, "1.3.2"}, // letters rock - {"0.5.0~git", LESS, "0.5.0~git2"}, // numbers rock - {"2a", LESS, "21"}, // but not in all places - {"1.3.2a", LESS, "1.3.2b"}, // but there is another letter - {"1:1.2.3", GREATER, "1.2.4"}, // epoch rocks - {"1:1.2.3", LESS, "1:1.2.4"}, // bigger anyway - {"1.2a+~bCd3", LESS, "1.2a++"}, // tilde doesn't rock - {"1.2a+~bCd3", GREATER, "1.2a+~"}, // but first is longer! - {"5:2", GREATER, "304-2"}, // epoch rocks - {"5:2", LESS, "304:2"}, // so big epoch? - {"25:2", GREATER, "3:2"}, // 25 > 3, obviously - {"1:2:123", LESS, "1:12:3"}, // 12 > 2 - {"1.2-5", LESS, "1.2-3-5"}, // 1.2 < 1.2-3 - {"5.10.0", GREATER, "5.005"}, // preceding zeroes don't matters - {"3a9.8", LESS, "3.10.2"}, // letters are before all letter symbols - {"3a9.8", GREATER, "3~10"}, // but after the tilde - {"1.4+OOo3.0.0~", LESS, "1.4+OOo3.0.0-4"}, // another tilde check - {"2.4.7-1", LESS, "2.4.7-z"}, // revision comparing - {"1.002-1+b2", GREATER, "1.00"}, // whatever... - } - - for _, c := range cases { - v1, err1 := NewVersion(c.v1) - v2, err2 := NewVersion(c.v2) - if assert.Nil(t, err1) && assert.Nil(t, err2) { - cmp := v1.Compare(v2) - assert.Equal(t, c.expected, cmp, "%s vs. %s, = %d, expected %d", c.v1, c.v2, cmp, c.expected) - - cmp = v2.Compare(v1) - assert.Equal(t, -c.expected, cmp, "%s vs. %s, = %d, expected %d", c.v2, c.v1, cmp, -c.expected) - } - } -} - -func TestVersionJson(t *testing.T) { - v, _ := NewVersion("57:1.2.3abYZ+~-4-5") - - // Marshal - json, err := v.MarshalJSON() - assert.Nil(t, err) - assert.Equal(t, "\""+v.String()+"\"", string(json)) - - // Unmarshal - var v2 Version - v2.UnmarshalJSON(json) - assert.Equal(t, v, v2) -}