]> xenbits.xensource.com Git - people/gdunlap/xsatool/commitdiff
Implement xenversion ranges
authorGeorge Dunlap <george.dunlap@citrix.com>
Mon, 30 Jul 2018 17:05:47 +0000 (18:05 +0100)
committerGeorge Dunlap <george.dunlap@citrix.com>
Mon, 30 Jul 2018 17:05:47 +0000 (18:05 +0100)
Implement VersionsFromString(), which takes a XenVersionSlice and
filter function rather than a pointer to an xsa and a flag.

Parse `all`, `master`, and use `..` for ranges rather than `-` so that
we can do things like say `..4.8` (since `-4.8` might look like a
flag).

Also implement tests

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
systemtest.go
xenversion.go

index 033234e1e4eb9c83a49aca4a66c017b117713982..fdd44b92098e387d6ef9b0faafa2baa631d597f2 100644 (file)
@@ -523,7 +523,7 @@ func Story206Backport(st *SystemTest) bool {
        // the backports actually work. :-(
        
        fakeBackport := func(v XenVersion) (err error) {
-               fmt.Print(" xsatool 206 backport [to %v] [should fail]\n", v)
+               fmt.Printf(" xsatool 206 backport [to %v] [should fail]\n", v)
                if MainHarness("206", "backport") == 0 {
                        return fmt.Errorf("Expected %v backport to fail, but succeeded!",
                                v)
index f733bc6dadf060f6ff0147672d84d9e6b56023d6..36fd29b4a43a67973e5115ef25d7d9e304f368ab 100644 (file)
@@ -9,7 +9,9 @@ import (
 
 type XenVersion string
 
+// XenVersionMaster is always the 'maximum'
 const XenVersionMaster = XenVersion("master")
+const XenVersionMin = XenVersion("MIN")
 
 // This is a bit weird but it hides the implementation
 func (v XenVersion) String() string {
@@ -17,16 +19,19 @@ func (v XenVersion) String() string {
 }
 
 func (v XenVersion) parse() (major, minor int, err error) {
-       if v == "master" {
-               // NB if Xen's major ever exceeds 2 billion, we'll
+       switch v {
+       case XenVersionMaster:
+               // NB if Xen's major ever exceeds 2 billion-1, we'll
                // need to deprecate the 32-bit build of this tool.
                return math.MaxInt32, 0, nil
+       case XenVersionMin:
+               return -1, 0, nil
        }
 
        major = -1
        minor = -1
 
-       submatch := regexp.MustCompile("^([0-9]+).([0-9]+)$").FindStringSubmatch(string(v))
+       submatch := regexp.MustCompile("^([0-9]+)\\.([0-9]+)$").FindStringSubmatch(string(v))
 
        if len(submatch) != 3 {
                err = fmt.Errorf("Bad XenVersion: %s", string(v))
@@ -55,6 +60,15 @@ func (v XenVersion) Check() bool {
        return err == nil
 }
 
+func XenVersionFromString(s string) (v XenVersion, err error) {
+       v = XenVersion(s)
+       _, _, err = v.parse()
+       if err != nil {
+               v = ""
+       }
+       return
+}
+
 func (v XenVersion) gt(v2 XenVersion, orEqual bool) bool {
        majorA, minorA, err := v.parse()
        if err != nil {
@@ -139,6 +153,129 @@ func (vl XenVersionSlice) Swap(i, j int) {
        vl[i] = tmp
 }
 
+func (vl XenVersionSlice) Present(v XenVersion) (found bool) {
+       for _, cv := range vl {
+               if cv == v {
+                       found = true
+                       break
+               }
+       }
+       return
+}
+
+func (a XenVersionSlice) IsEqual(b XenVersionSlice) bool {
+       if a == nil && b == nil { 
+               return true; 
+       }
+
+       if a == nil || b == nil { 
+               return false; 
+       }
+
+       if len(a) != len(b) {
+               return false
+       }
+
+       for i := range a {
+               if a[i] != b[i] {
+                       return false
+               }
+       }
+
+       return true
+}
+
+// NB that this list goes high to low
+// all: All versions in the current xsa (or all with patches)
+// <v>: One particular version
+// <v1>..<v2>: All versions between <v1> and <v2>
+// <v>.. : All versions newer than <v>
+// ..<v> : All versions older than <v>
+// TODO: Maybe add ','?
+func VersionsFromString(s string, validVersions XenVersionSlice, filter func(v XenVersion) bool) (vl XenVersionSlice, err error) {
+       // If it parses as a single version, just pass that back.
+       if _, _, terr := XenVersion(s).parse(); terr == nil {
+               v := XenVersion(s)
+
+               if validVersions != nil && !validVersions.Present(v) {
+                       err = fmt.Errorf("Version %v not listed", v)
+                       return
+               }
+
+               if filter != nil && !filter(v) {
+                       err = fmt.Errorf("Only value filtered")
+                       return
+               }
+               
+               vl = XenVersionSlice{v}
+               return
+       }
+
+       vmin := XenVersionMin;
+       vmax := XenVersionMaster;
+
+       if s != "all" {
+               submatch := regexp.MustCompile("^([0-9.]*|master)\\.\\.([0-9.]*)$").FindStringSubmatch(s)
+               if len(submatch) != 3 {
+                       err = fmt.Errorf("Cannot parse version list")
+                       return
+               }
+               
+               if submatch[1] != "" {
+                       vmax = XenVersion(submatch[1])
+               }
+
+               if submatch[2] != "" {
+                       vmin = XenVersion(submatch[2])
+               }
+               
+               if !vmin.Check() {
+                       err = fmt.Errorf("Invalid version: %s", vmin)
+                       return
+               }
+               
+               if !vmax.Check() {
+                       err = fmt.Errorf("Invalid version: %s", vmax)
+                       return
+               }
+       }
+
+       if !vmax.IsGreaterEqualThan(vmin) {
+               err = fmt.Errorf("Range max %v less than min %v", vmax, vmin)
+               return
+       }
+
+       // We have a list of valid versions, so just go through the list picking
+       // out the valid ones
+       if validVersions != nil {
+               if vmin != XenVersionMin && !validVersions.Present(vmin) {
+                       err = fmt.Errorf("Version %v not listed", vmin)
+                       return
+               }
+               if vmax != XenVersionMaster && !validVersions.Present(vmax) {
+                       err = fmt.Errorf("Version %v not listed", vmax)
+                       return
+               }
+               
+               for _, cv := range validVersions {
+                       // FIXME: Should a filter failure cause a 'break' instead?
+                       if cv.IsGreaterEqualThan(vmin) &&
+                               vmax.IsGreaterEqualThan(cv) &&
+                               (filter == nil || filter(cv)) {
+                               vl = append(vl, cv)
+                       }
+               }
+               
+               return
+       }
+
+       // We don't have any users w/o valid versions yet; implement
+       // this when we need to
+       err = fmt.Errorf("INTERNAL ERROR: Parsing w/o valid versions not implemented")
+       
+       return
+}
+
 type XenVersionFull string
 
 func (v XenVersionFull) String() string {
@@ -169,6 +306,15 @@ func (v XenVersionFull) Check() bool {
        return (err == nil)
 }
 
+func XenVersionFullFromString(s string) (fv XenVersionFull, err error) {
+       fv = XenVersionFull(s)
+       _, _, err = fv.parse()
+       if err != nil {
+               fv = ""
+       }
+       return
+}
+
 func (v XenVersionFull) XenVersion() XenVersion {
        ver, _, err := v.parse()
        if err != nil {