SemVer working with new Masterminds/semver library
diff --git a/cmd/flatten.go b/cmd/flatten.go
index 746c083..51655af 100644
--- a/cmd/flatten.go
+++ b/cmd/flatten.go
@@ -3,8 +3,10 @@
 import (
 	"os"
 	"path"
+	"strings"
 
 	"github.com/Masterminds/cookoo"
+	"github.com/Masterminds/semver"
 	"github.com/kylelemons/go-gypsy/yaml"
 )
 
@@ -16,7 +18,7 @@
 // Params:
 //	- packages ([]string): The packages to read. If this is empty, it reads all
 //		packages.
-//	- force (bool): force git updates.
+//	- force (bool): force vcs updates.
 //	- conf (*Config): The configuration.
 //
 // Returns:
@@ -87,15 +89,15 @@
 		Debug("----> Scanning %s", imp)
 		base := path.Join(f.top, imp)
 		mod := []string{}
-		if m, ok := mergeGlide(base, imp, f.deps); ok {
+		if m, ok := mergeGlide(base, imp, f.deps, f.top); ok {
 			mod = m
-		} else if m, ok = mergeGodep(base, imp, f.deps); ok {
+		} else if m, ok = mergeGodep(base, imp, f.deps, f.top); ok {
 			mod = m
-		} else if m, ok = mergeGPM(base, imp, f.deps); ok {
+		} else if m, ok = mergeGPM(base, imp, f.deps, f.top); ok {
 			mod = m
-		} else if m, ok = mergeGb(base, imp, f.deps); ok {
+		} else if m, ok = mergeGb(base, imp, f.deps, f.top); ok {
 			mod = m
-		} else if m, ok = mergeGuess(base, imp, f.deps); ok {
+		} else if m, ok = mergeGuess(base, imp, f.deps, f.top); ok {
 			mod = m
 		}
 
@@ -164,7 +166,7 @@
 	}
 }
 
-func mergeGlide(dir, name string, deps map[string]*Dependency) ([]string, bool) {
+func mergeGlide(dir, name string, deps map[string]*Dependency, vend string) ([]string, bool) {
 	gp := path.Join(dir, "glide.yaml")
 	if _, err := os.Stat(gp); err != nil {
 		return []string{}, false
@@ -183,14 +185,14 @@
 
 	Info("Found glide.yaml in %s", gp)
 
-	return mergeDeps(deps, conf.Imports), true
+	return mergeDeps(deps, conf.Imports, vend), true
 }
 
 // listGodep appends Godeps entries to the deps.
 //
 // It returns true if any dependencies were found (even if not added because
 // they are duplicates).
-func mergeGodep(dir, name string, deps map[string]*Dependency) ([]string, bool) {
+func mergeGodep(dir, name string, deps map[string]*Dependency, vend string) ([]string, bool) {
 	Debug("Looking in %s/Godeps/ for a Godeps.json file.\n", dir)
 	d, err := parseGodepGodeps(dir)
 	if err != nil {
@@ -201,28 +203,28 @@
 	}
 
 	Info("Found Godeps.json file for %q", name)
-	return mergeDeps(deps, d), true
+	return mergeDeps(deps, d, vend), true
 }
 
 // listGb merges GB dependencies into the deps.
-func mergeGb(dir, pkg string, deps map[string]*Dependency) ([]string, bool) {
+func mergeGb(dir, pkg string, deps map[string]*Dependency, vend string) ([]string, bool) {
 	Debug("Looking in %s/vendor/ for a manifest file.\n", dir)
 	d, err := parseGbManifest(dir)
 	if err != nil || len(d) == 0 {
 		return []string{}, false
 	}
 	Info("Found gb manifest file for %q", pkg)
-	return mergeDeps(deps, d), true
+	return mergeDeps(deps, d, vend), true
 }
 
 // mergeGPM merges GPM Godeps files into deps.
-func mergeGPM(dir, pkg string, deps map[string]*Dependency) ([]string, bool) {
+func mergeGPM(dir, pkg string, deps map[string]*Dependency, vend string) ([]string, bool) {
 	d, err := parseGPMGodeps(dir)
 	if err != nil || len(d) == 0 {
 		return []string{}, false
 	}
 	Info("Found GPM file for %q", pkg)
-	return mergeDeps(deps, d), true
+	return mergeDeps(deps, d, vend), true
 }
 
 // mergeGuess guesses dependencies and merges.
@@ -230,7 +232,7 @@
 // This always returns true because it always handles the job of searching
 // for dependencies. So generally it should be the last merge strategy
 // that you try.
-func mergeGuess(dir, pkg string, deps map[string]*Dependency) ([]string, bool) {
+func mergeGuess(dir, pkg string, deps map[string]*Dependency, vend string) ([]string, bool) {
 	/*
 			Info("Scanning %s for dependencies.", pkg)
 			buildContext, err := GetBuildContext()
@@ -286,7 +288,7 @@
 }
 
 // mergeDeps merges any dependency array into deps.
-func mergeDeps(orig map[string]*Dependency, add []*Dependency) []string {
+func mergeDeps(orig map[string]*Dependency, add []*Dependency, vend string) []string {
 	mod := []string{}
 	for _, dd := range add {
 		// Add it unless it's already there.
@@ -300,11 +302,115 @@
 			existing.Reference = dd.Reference
 			mod = append(mod, dd.Name)
 		} else if dd.Reference != "" && existing.Reference != "" && dd.Reference != existing.Reference {
-			// We can detect version conflicts, but we can't really do
-			// anything to correct, since we don't know the intentions of the
-			// authors.
-			Warn("Conflict: %s ref is %s, but also asked for %s", existing.Name, existing.Reference, dd.Reference)
-			Info("Keeping %s %s", existing.Name, existing.Reference)
+			// Check if one is a version and the other is a constraint. If the
+			// version is in the constraint use that.
+			dest := path.Join(vend, dd.Name)
+			repo, err := existing.GetRepo(dest)
+			if err != nil {
+				Warn("Unable to access repo for %s\n", existing.Name)
+				Info("Keeping %s %s", existing.Name, existing.Reference)
+				continue
+			}
+
+			eIsRef := repo.IsReference(existing.Reference)
+			ddIsRef := repo.IsReference(dd.Reference)
+
+			// Both are references and different ones.
+			if eIsRef && ddIsRef {
+				Warn("Conflict: %s ref is %s, but also asked for %s\n", existing.Name, existing.Reference, dd.Reference)
+				Info("Keeping %s %s", existing.Name, existing.Reference)
+			} else if eIsRef {
+				// Test ddIsRef is a constraint and if eIsRef is a semver
+				// within that
+				con, err := semver.NewConstraint(dd.Reference)
+				if err != nil {
+					Warn("Version issue for %s: '%s' is neither a reference or semantic version constraint\n", dd.Name, dd.Reference)
+					Info("Keeping %s %s", existing.Name, existing.Reference)
+					continue
+				}
+
+				ver, err := semver.NewVersion(existing.Reference)
+				if err != nil {
+					// The existing version is not a semantic version.
+					Warn("Conflict: %s version is %s, but also asked for %s\n", existing.Name, existing.Reference, dd.Reference)
+					Info("Keeping %s %s", existing.Name, existing.Reference)
+					continue
+				}
+
+				if con.Check(ver) {
+					Info("Keeping %s %s because it fits constraint '%s'", existing.Name, existing.Reference, dd.Reference)
+				} else {
+					Warn("Conflict: %s version is %s but does not meet constraint '%s'\n", existing.Name, existing.Reference, dd.Reference)
+					Info("Keeping %s %s", existing.Name, existing.Reference)
+				}
+
+			} else if ddIsRef {
+				// Test eIsRef is a constraint and if ddIsRef is a semver
+				// within that
+				con, err := semver.NewConstraint(existing.Reference)
+				if err != nil {
+					Warn("Version issue for %s: '%s' is neither a reference or semantic version constraint\n", existing.Name, existing.Reference)
+					Info("Keeping %s %s", existing.Name, existing.Reference)
+					continue
+				}
+
+				ver, err := semver.NewVersion(dd.Reference)
+				if err != nil {
+					// The dd version is not a semantic version.
+					Warn("Conflict: %s version is %s, but also asked for %s\n", existing.Name, existing.Reference, dd.Reference)
+					Info("Keeping %s %s", existing.Name, existing.Reference)
+					continue
+				}
+
+				if con.Check(ver) {
+					// Use the specific version if noted instead of the existing
+					// constraint.
+					existing.Reference = dd.Reference
+					mod = append(mod, dd.Name)
+					Info("Using %s %s because it fits constraint '%s'", existing.Name, dd.Reference, existing.Reference)
+				} else {
+					Warn("Conflict: %s semantic version constraint is %s but '%s' does not meet the constraint\n", existing.Name, existing.Reference, dd.Reference)
+					Info("Keeping %s %s", existing.Name, existing.Reference)
+				}
+			} else {
+				// Neither is a vcs reference and both could be semantic version
+				// constraints that are different.
+
+				_, err := semver.NewConstraint(dd.Reference)
+				if err != nil {
+					// dd.Reference is not a reference or a valid constraint.
+					Warn("Version %s %s is not a reference or valid semantic version constraint\n", dd.Name, dd.Reference)
+					Info("Keeping %s %s", existing.Name, existing.Reference)
+					continue
+				}
+
+				_, err = semver.NewConstraint(existing.Reference)
+				if err != nil {
+					// existing.Reference is not a reference or a valid constraint.
+					// We really should never end up here.
+					Warn("Version %s %s is not a reference or valid semantic version constraint\n", existing.Name, existing.Reference)
+
+					existing.Reference = dd.Reference
+					mod = append(mod, dd.Name)
+					Info("Using %s %s because it is a valid version", existing.Name, existing.Reference)
+					continue
+				}
+
+				// Both versions are constraints. Try to merge them.
+				// If either comparison has an || skip merging. That's complicated.
+				ddor := strings.Index(dd.Reference, "||")
+				eor := strings.Index(existing.Reference, "||")
+				if ddor == -1 && eor == -1 {
+					// Add the comparisons together.
+					newRef := existing.Reference + ", " + dd.Reference
+					existing.Reference = newRef
+					mod = append(mod, dd.Name)
+					Info("Combining %s semantic version constraints %s and %s", existing.Name, existing.Reference, dd.Reference)
+				} else {
+					Warn("Conflict: %s version is %s, but also asked for %s\n", existing.Name, existing.Reference, dd.Reference)
+					Info("Keeping %s %s", existing.Name, existing.Reference)
+				}
+			}
 		}
 	}
 	return mod
diff --git a/cmd/get_imports.go b/cmd/get_imports.go
index b730877..538c2ca 100644
--- a/cmd/get_imports.go
+++ b/cmd/get_imports.go
@@ -3,6 +3,7 @@
 import (
 	"encoding/xml"
 	"fmt"
+	"sort"
 	//"log"
 	"io"
 	"net/http"
@@ -14,8 +15,8 @@
 	"strings"
 
 	"github.com/Masterminds/cookoo"
+	"github.com/Masterminds/semver"
 	v "github.com/Masterminds/vcs"
-	"github.com/hashicorp/go-version"
 )
 
 func init() {
@@ -370,7 +371,7 @@
 
 			// Create the constraing first to make sure it's valid before
 			// working on the repo.
-			constraint, err := version.NewConstraint(ver)
+			constraint, err := semver.NewConstraint(ver)
 
 			// Make sure the constriant is valid. At this point it's not a valid
 			// reference so if it's not a valid constrint we can exit early.
@@ -385,25 +386,25 @@
 				return err
 			}
 
-			// Filter the references to just the semantic versions.
-			semverMap := getSemVers(refs)
+			// Convert and filter the list to semver.Version instances
+			semvers := getSemVers(refs)
 
 			// Sort semver list
-			var sv []string
-			for k := range semverMap {
-				sv = append(sv, k)
-			}
-			sorted := getSortedSemVerList(sv)
-			for _, v := range sorted {
+			sort.Sort(sort.Reverse(semver.Collection(semvers)))
+			found := false
+			for _, v := range semvers {
 				if constraint.Check(v) {
-
+					found = true
 					// If the constrint passes get the original reference
-					ver = semverMap[v.String()]
+					ver = v.Original()
 					break
 				}
 			}
-
-			Info("Detected semantic version. Setting version for %s to %s.\n", dep.Name, ver)
+			if found {
+				Info("Detected semantic version. Setting version for %s to %s.\n", dep.Name, ver)
+			} else {
+				Warn("Unable to find semantic version for constraint %s %s\n", dep.Name, ver)
+			}
 		}
 		if err := repo.UpdateVersion(ver); err != nil {
 			Error("Failed to set version to %s: %s\n", dep.Reference, err)
diff --git a/cmd/semver.go b/cmd/semver.go
index 5be74aa..566f431 100644
--- a/cmd/semver.go
+++ b/cmd/semver.go
@@ -1,50 +1,18 @@
 package cmd
 
 import (
-	"errors"
-	"regexp"
-	"sort"
-
+	"github.com/Masterminds/semver"
 	"github.com/Masterminds/vcs"
-	"github.com/hashicorp/go-version"
 )
 
-// The SemVer handling by github.com/hashicorp/go-version provides the ability
-// to work with versions
-
-// The compiled regular expression used to test the validity of a version.
-var versionRegexp *regexp.Regexp
-
-const versionRegexpRaw string = `v?(([0-9]+(\.[0-9]+){0,2})` +
-	`(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` +
-	`(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?)` +
-	`?`
-
-func init() {
-	versionRegexp = regexp.MustCompile("^" + versionRegexpRaw + "$")
-}
-
-// Filter the leading v from the version. Returns an error if there
-// was an issue including if the version was not SemVer
-// returns:
-// - the semantic verions (stripping any leading v if present)
-// - error if there was one
-func filterVersion(v string) (string, error) {
-	matches := versionRegexp.FindStringSubmatch(v)
-	if matches == nil || matches[1] == "" {
-		return "", errors.New("No SemVer found.")
-	}
-	return matches[1], nil
-}
-
 // Filter a list of versions to only included semantic versions. The response
 // is a mapping of the original version to the semantic version.
-func getSemVers(refs []string) map[string]string {
-	sv := map[string]string{}
+func getSemVers(refs []string) []*semver.Version {
+	sv := []*semver.Version{}
 	for _, r := range refs {
-		nv, err := filterVersion(r)
+		v, err := semver.NewVersion(r)
 		if err == nil {
-			sv[nv] = r
+			sv = append(sv, v)
 		}
 	}
 
@@ -78,16 +46,3 @@
 	}
 	return false, nil
 }
-
-func getSortedSemVerList(v []string) []*version.Version {
-	versions := make([]*version.Version, len(v))
-	for i, raw := range v {
-		v, err := version.NewVersion(raw)
-		if err == nil {
-			versions[i] = v
-		}
-	}
-
-	sort.Sort(sort.Reverse(version.Collection(versions)))
-	return versions
-}
diff --git a/cmd/semver_test.go b/cmd/semver_test.go
deleted file mode 100644
index 5f9a15b..0000000
--- a/cmd/semver_test.go
+++ /dev/null
@@ -1,122 +0,0 @@
-package cmd
-
-import "testing"
-
-func TestFilterVersion(t *testing.T) {
-	cases := []struct {
-		version string
-		semver  string
-		err     bool
-	}{
-		{"1.2.3", "1.2.3", false},
-		{"1.0", "1.0", false},
-		{"1", "1", false},
-		{"1.2.beta", "", true},
-		{"foo", "", true},
-		{"1.2-5", "1.2-5", false},
-		{"1.2-beta.5", "1.2-beta.5", false},
-		{"\n1.2", "", true},
-		{"1.2.0-x.Y.0+metadata", "1.2.0-x.Y.0+metadata", false},
-		{"1.2.0-x.Y.0+metadata-width-hypen", "1.2.0-x.Y.0+metadata-width-hypen", false},
-		{"1.2.3-rc1-with-hypen", "1.2.3-rc1-with-hypen", false},
-		{"1.2.3.4", "", true},
-		{"v1.2.3", "1.2.3", false},
-		{"foo1.2.3", "", true},
-		{"v1.0", "1.0", false},
-		{"v1", "1", false},
-		{"v1.2.beta", "", true},
-		{"v1.2-5", "1.2-5", false},
-		{"v1.2-beta.5", "1.2-beta.5", false},
-	}
-
-	for _, tc := range cases {
-		fv, err := filterVersion(tc.version)
-		if tc.err && err == nil {
-			t.Errorf("expected error for version: %s", tc.version)
-		} else if !tc.err && err != nil {
-			t.Errorf("error for version %s: %s", tc.version, err)
-		}
-
-		if tc.semver != fv {
-			t.Errorf("expected version '%s' does not match actual version '%s'", tc.semver, fv)
-		}
-	}
-}
-
-func TestGetSemVers(t *testing.T) {
-	versions := []string{
-		"1.2.3",
-		"1.0",
-		"1",
-		"1.2.beta",
-		"foo",
-		"1.2-5",
-		"1.2-beta.5",
-		"\n1.2",
-		"1.2.0-x.Y.0+metadata",
-		"1.2.0-x.Y.0+metadata-width-hypen",
-		"1.2.3-rc1-with-hypen",
-		"1.2.3.4",
-		"v1.2.3",
-		"foo1.2.3",
-		"v1.0",
-		"v1",
-		"v1.2.beta",
-		"v1.2-5",
-		"v1.2-beta.5",
-	}
-
-	pass := map[string]string{
-		"1.2.3":                            "1.2.3",
-		"1.0":                              "1.0",
-		"1":                                "1",
-		"1.2-5":                            "1.2-5",
-		"1.2-beta.5":                       "1.2-beta.5",
-		"1.2.0-x.Y.0+metadata":             "1.2.0-x.Y.0+metadata",
-		"1.2.0-x.Y.0+metadata-width-hypen": "1.2.0-x.Y.0+metadata-width-hypen",
-		"1.2.3-rc1-with-hypen":             "1.2.3-rc1-with-hypen",
-		"v1.2.3":                           "1.2.3",
-		"v1.0":                             "1.0",
-		"v1":                               "1",
-		"v1.2-5":                           "1.2-5",
-		"v1.2-beta.5":                      "1.2-beta.5",
-	}
-
-	sv := getSemVers(versions)
-	for k, v := range sv {
-		temp, ok := pass[v]
-		if !ok {
-			t.Errorf("GetSemVers found %s in error", k)
-		}
-		if k != temp {
-			t.Errorf("GetSemVers found %s but expected %s", k, temp)
-		}
-	}
-}
-
-func TestGetSortedSemVerList(t *testing.T) {
-	versions := []string{
-		"1.2.3",
-		"2.1",
-		"2",
-		"1.2-beta.5",
-		"1.0",
-		"2.0.3",
-	}
-
-	pass := []string{
-		"2.1.0",
-		"2.0.3",
-		"2.0.0",
-		"1.2.3",
-		"1.2.0-beta.5",
-		"1.0.0",
-	}
-
-	sorted := getSortedSemVerList(versions)
-	for k, v := range sorted {
-		if pass[k] != v.String() {
-			t.Errorf("Sorting expected %s but got %s", pass[k], v)
-		}
-	}
-}
diff --git a/glide.yaml b/glide.yaml
index b11af42..d9a3721 100644
--- a/glide.yaml
+++ b/glide.yaml
@@ -11,5 +11,6 @@
     subpackages:
       - .
   - package: github.com/Masterminds/vcs
+    ref:     ^1.0.0
   - package: github.com/codegangsta/cli
-  - package: github.com/hashicorp/go-version
+  - package: github.com/Masterminds/semver