package common import ( "os" "os/exec" "path/filepath" "runtime" "strconv" "strings" ) func PathExists(path string) bool { _, err := os.Stat(path) return err == nil } func ExecCmd(cmd string) (string, error) { var c *exec.Cmd c = exec.Command("/bin/sh", "-c", cmd) out, err := c.CombinedOutput() return string(out), err } func RunCmd(cmd string, shell bool) ([]byte, error) { if shell { out, err := exec.Command("bash", "-c", cmd).CombinedOutput() return out, err } else { out, err := exec.Command(cmd).CombinedOutput() return out, err } } func GetCurrentFileDir() string { _, file, _, _ := runtime.Caller(1) return filepath.Dir(file) } func ReadLink(path string) string { info, err := os.Lstat(path) if err != nil { return path } if strings.HasPrefix(info.Mode().String(), "L") { dstPath, err := os.Readlink(path) if err != nil { return path } if strings.HasPrefix(dstPath, "/") { return dstPath } absDstPath := filepath.Join(filepath.Dir(path), dstPath) return absDstPath } return path } // return whether s exists in sList func InStringList(s string, sList []string) bool { for _, str := range sList { if len(s) == len(str) && s == str { return true } } return false } func InIntList(i int, iList []int) bool { for _, num := range iList { if i == num { return true } } return false } func InUintList(i uint, iList []uint) bool { for _, num := range iList { if i == num { return true } } return false } func CreateIfNotExistDir(dir string) error { if PathExists(dir) { return nil } return os.MkdirAll(dir, 0700) } // version_compare() // The possible operators are: <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne respectively. // special version strings these are handled in the following order, // (any string not found) < dev < alpha = a < beta = b < RC = rc < # < pl = p // Usage: // VersionCompare("1.2.3-alpha", "1.2.3RC7", '>=') // VersionCompare("1.2.3-beta", "1.2.3pl", 'lt') // VersionCompare("1.1_dev", "1.2any", 'eq') func VersionCompare(version1, version2, operator string) bool { var vcompare func(string, string) int var canonicalize func(string) string var special func(string, string) int // version compare vcompare = func(origV1, origV2 string) int { if origV1 == "" || origV2 == "" { if origV1 == "" && origV2 == "" { return 0 } else { if origV1 == "" { return -1 } else { return 1 } } } if (origV1 == "*" || origV2 == "*") && (operator == "eq" || operator == "=" || operator == "==") { return 0 } ver1, ver2, compare := "", "", 0 if origV1[0] == '#' { ver1 = origV1 } else { ver1 = canonicalize(origV1) } if origV2[0] == '#' { ver2 = origV2 } else { ver2 = canonicalize(origV2) } n1, n2 := 0, 0 for { p1, p2 := "", "" n1 = strings.IndexByte(ver1, '.') if n1 == -1 { p1, ver1 = ver1, "" } else { p1, ver1 = ver1[:n1], ver1[n1+1:] } n2 = strings.IndexByte(ver2, '.') if n2 == -1 { p2, ver2 = ver2, "" } else { p2, ver2 = ver2[:n2], ver2[n2+1:] } if (p1[0] >= '0' && p1[0] <= '9') && (p2[0] >= '0' && p2[0] <= '9') { // all isdigit l1, _ := strconv.Atoi(p1) l2, _ := strconv.Atoi(p2) if l1 > l2 { compare = 1 } else if l1 == l2 { compare = 0 } else { compare = -1 } } else if !(p1[0] >= '0' && p1[0] <= '9') && !(p2[0] >= '0' && p2[0] <= '9') { // all isndigit compare = special(p1, p2) } else { // part isdigit if p1[0] >= '0' && p1[0] <= '9' { // isdigit compare = special("#N#", p2) } else { compare = special(p1, "#N#") } } if compare != 0 || n1 == -1 || n2 == -1 { break } } if compare == 0 { if ver1 != "" { if ver1[0] >= '0' && ver1[0] <= '9' { compare = 1 } else { compare = vcompare(ver1, "#N#") } } else if ver2 != "" { if ver2[0] >= '0' && ver2[0] <= '9' { compare = -1 } else { compare = vcompare("#N#", ver2) } } } return compare } // canonicalize canonicalize = func(version string) string { ver := []byte(version) l := len(ver) if l == 0 { return "" } var buf = make([]byte, l*2) j := 0 for i, v := range ver { next := uint8(0) if i+1 < l { // Have the next one next = ver[i+1] } if v == '-' || v == '_' || v == '+' { // repalce "-","_","+" to "." if j > 0 && buf[j-1] != '.' { buf[j] = '.' j++ } } else if (next > 0) && (!(next >= '0' && next <= '9') && (v >= '0' && v <= '9')) || (!(v >= '0' && v <= '9') && (next >= '0' && next <= '9')) { // Insert '.' before and after a non-digit buf[j] = v j++ if v != '.' && next != '.' { buf[j] = '.' j++ } continue } else if !((v >= '0' && v <= '9') || (v >= 'a' && v <= 'z') || (v >= 'A' && v <= 'Z')) { // Non-letters and numbers if j > 0 && buf[j-1] != '.' { buf[j] = '.' j++ } } else { buf[j] = v j++ } } return string(buf[:j]) } //compare special version forms special = func(form1, form2 string) int { found1, found2, len1, len2 := -1, -1, len(form1), len(form2) // (Any string not found) < dev < alpha = a < beta = b < RC = rc < # < pl = p forms := map[string]int{ "dev": 0, "alpha": 1, "a": 1, "beta": 2, "b": 2, "RC": 3, "rc": 3, "#": 4, "pl": 5, "p": 5, } for name, order := range forms { if len1 < len(name) { continue } if strings.Compare(form1[:len(name)], name) == 0 { found1 = order break } } for name, order := range forms { if len2 < len(name) { continue } if strings.Compare(form2[:len(name)], name) == 0 { found2 = order break } } if found1 == found2 { return 0 } else if found1 > found2 { return 1 } else { return -1 } } var compare int // <> means between, version2 is a comma seperated version, eg: 1.2,2.0 means // vesion1 > 1.2 and version1 < 2.0 if operator == "<>" { splits := strings.Split(version2, ",") if len(splits) != 2 { return false } return VersionCompare(version1, splits[0], ">") && VersionCompare(version1, splits[1], "<") } else { compare = vcompare(version1, version2) } switch operator { case "<", "lt": return compare == -1 case "<=", "le": return compare != 1 case ">", "gt": return compare == 1 case ">=", "ge": return compare != -1 case "==", "=", "eq": return compare == 0 case "!=", "ne": return compare != 0 default: //panic("operator: invalid") return false } }