First steps towards refactoring config

This is very much not finished, but it's a solid first chunk that
focuses on changing the basic config structs and setting up the legacy
-> current autoupgrade.
diff --git a/cfg/config.go b/cfg/config.go
index 0bcfb18..3b46764 100644
--- a/cfg/config.go
+++ b/cfg/config.go
@@ -9,7 +9,6 @@
 	"sort"
 	"strings"
 
-	"github.com/Masterminds/glide/util"
 	"github.com/Masterminds/vcs"
 	"github.com/sdboyer/gps"
 	"gopkg.in/yaml.v2"
@@ -44,33 +43,14 @@
 	// those to skip.
 	Ignore []string `yaml:"ignore,omitempty"`
 
-	// Exclude contains a list of directories in the local application to
-	// exclude from scanning for dependencies.
-	Exclude []string `yaml:"excludeDirs,omitempty"`
-
-	// Imports contains a list of all non-development imports for a project. For
+	// Imports contains a list of all dependency constraints for a project. For
 	// more detail on how these are captured see the Dependency type.
-	Imports Dependencies `yaml:"import"`
+	Imports Dependencies `yaml:"dependencies"`
 
-	// DevImports contains the test or other development imports for a project.
-	// See the Dependency type for more details on how this is recorded.
-	DevImports Dependencies `yaml:"testImport,omitempty"`
+	DevImports Dependencies `yaml:"testDependencies"`
 }
 
 // A transitive representation of a dependency for importing and exporting to yaml.
-type cf1 struct {
-	Name        string       `yaml:"package"`
-	Description string       `yaml:"description,omitempty"`
-	Home        string       `yaml:"homepage,omitempty"`
-	License     string       `yaml:"license,omitempty"`
-	Owners      Owners       `yaml:"owners,omitempty"`
-	Ignore      []string     `yaml:"ignore,omitempty"`
-	Exclude     []string     `yaml:"excludeDirs,omitempty"`
-	Imports     Dependencies `yaml:"dependencies"`
-	DevImports  Dependencies `yaml:"testdependencies,omitempty"`
-}
-
-// Legacy representation of a glide.yaml file.
 type cf struct {
 	Name        string       `yaml:"package"`
 	Description string       `yaml:"description,omitempty"`
@@ -78,16 +58,22 @@
 	License     string       `yaml:"license,omitempty"`
 	Owners      Owners       `yaml:"owners,omitempty"`
 	Ignore      []string     `yaml:"ignore,omitempty"`
-	Exclude     []string     `yaml:"excludeDirs,omitempty"`
-	Imports     Dependencies `yaml:"import"`
-	DevImports  Dependencies `yaml:"testImport,omitempty"`
+	Imports     Dependencies `yaml:"dependencies"`
+	DevImports  Dependencies `yaml:"testDependencies,omitempty"`
 }
 
 // ConfigFromYaml returns an instance of Config from YAML
-func ConfigFromYaml(yml []byte) (*Config, error) {
+func ConfigFromYaml(yml []byte) (*Config, bool, error) {
 	cfg := &Config{}
 	err := yaml.Unmarshal([]byte(yml), &cfg)
-	return cfg, err
+	if err != nil {
+		lcfg := &lConfig1{}
+		err = yaml.Unmarshal([]byte(yml), &lcfg)
+		if err != nil {
+			// TODO(sdboyer) convert to new form, then return
+		}
+	}
+	return cfg, false, err
 }
 
 // Marshal converts a Config instance to YAML
@@ -111,7 +97,6 @@
 	c.License = newConfig.License
 	c.Owners = newConfig.Owners
 	c.Ignore = newConfig.Ignore
-	c.Exclude = newConfig.Exclude
 	c.Imports = newConfig.Imports
 	c.DevImports = newConfig.DevImports
 
@@ -130,7 +115,6 @@
 		License:     c.License,
 		Owners:      c.Owners,
 		Ignore:      c.Ignore,
-		Exclude:     c.Exclude,
 	}
 	i, err := c.Imports.Clone().DeDupe()
 	if err != nil {
@@ -178,38 +162,12 @@
 func depsToVSolver(deps Dependencies) []gps.ProjectConstraint {
 	cp := make([]gps.ProjectConstraint, len(deps))
 	for k, d := range deps {
-		var c gps.Constraint
-		var err error
-
-		// Support both old and new. TODO handle this earlier
-		if d.Constraint != nil {
-			c = d.Constraint
-		} else {
-			// TODO need to differentiate types of constraints so that we don't have
-			// this ambiguity
-			// Try semver first
-			c, err = gps.NewSemverConstraint(d.Reference)
-			if err != nil {
-				// Not a semver constraint. Super crappy heuristic that'll cover hg
-				// and git revs, but not bzr (svn, you say? lol, madame. lol)
-				if len(d.Reference) == 40 {
-					c = gps.Revision(d.Reference)
-				} else {
-					// Otherwise, assume a branch. This also sucks, because it could
-					// very well be a shitty, non-semver tag.
-					c = gps.NewBranch(d.Reference)
-				}
-			}
-		}
-
-		id := gps.ProjectIdentifier{
-			ProjectRoot: gps.ProjectRoot(d.Name),
-			NetworkName: d.Repository,
-		}
-
 		cp[k] = gps.ProjectConstraint{
-			Ident:      id,
-			Constraint: c,
+			Ident: gps.ProjectIdentifier{
+				ProjectRoot: gps.ProjectRoot(d.Name),
+				NetworkName: d.Repository,
+			},
+			Constraint: d.Constraint,
 		}
 	}
 
@@ -242,18 +200,6 @@
 	return false
 }
 
-// HasExclude returns true if the given name is listed on the exclude list.
-func (c *Config) HasExclude(ex string) bool {
-	ep := normalizeSlash(ex)
-	for _, v := range c.Exclude {
-		if vp := normalizeSlash(v); vp == ep {
-			return true
-		}
-	}
-
-	return false
-}
-
 // Clone performs a deep clone of the Config instance
 func (c *Config) Clone() *Config {
 	n := &Config{}
@@ -263,7 +209,6 @@
 	n.License = c.License
 	n.Owners = c.Owners.Clone()
 	n.Ignore = c.Ignore
-	n.Exclude = c.Exclude
 	n.Imports = c.Imports.Clone()
 	n.DevImports = c.DevImports.Clone()
 	return n
@@ -430,16 +375,16 @@
 			// In here we've encountered a dependency for the second time.
 			// Make sure the details are the same or return an error.
 			v := imports[val]
-			if dep.Reference != v.Reference {
-				return d, fmt.Errorf("Import %s repeated with different versions '%s' and '%s'", dep.Name, dep.Reference, v.Reference)
+			// Have to do string-based comparison
+			if dep.Constraint.String() != v.Constraint.String() {
+				return d, fmt.Errorf("Import %s repeated with different versions '%s' and '%s'", dep.Name, dep.Constraint, v.Constraint)
 			}
-			if dep.Repository != v.Repository || dep.VcsType != v.VcsType {
+			if dep.Repository != v.Repository {
 				return d, fmt.Errorf("Import %s repeated with different Repository details", dep.Name)
 			}
 			if !reflect.DeepEqual(dep.Os, v.Os) || !reflect.DeepEqual(dep.Arch, v.Arch) {
 				return d, fmt.Errorf("Import %s repeated with different OS or Architecture filtering", dep.Name)
 			}
-			imports[checked[dep.Name]].Subpackages = stringArrayDeDupe(v.Subpackages, dep.Subpackages...)
 		}
 	}
 
@@ -448,60 +393,58 @@
 
 // Dependency describes a package that the present package depends upon.
 type Dependency struct {
-	Name             string         `yaml:"package"`
-	Constraint       gps.Constraint `yaml:"-"` // TODO temporary, for experimenting; reconcile with other data
-	Reference        string         `yaml:"version,omitempty"`
-	Pin              string         `yaml:"-"`
-	Repository       string         `yaml:"repo,omitempty"`
-	VcsType          string         `yaml:"vcs,omitempty"`
-	Subpackages      []string       `yaml:"subpackages,omitempty"`
-	Arch             []string       `yaml:"arch,omitempty"`
-	Os               []string       `yaml:"os,omitempty"`
-	UpdateAsVendored bool           `yaml:"-"`
+	Name       string
+	VcsType    string // TODO remove
+	Constraint gps.Constraint
+	Repository string
+	Arch       []string
+	Os         []string
 }
 
-// A transitive representation of a dependency for importing and exploting to yaml.
+// A transitive representation of a dependency for yaml import/export.
 type dep struct {
-	Name        string   `yaml:"package"`
-	Reference   string   `yaml:"version,omitempty"`
-	Branch      string   `yaml:"branch,omitempty"`
-	Ref         string   `yaml:"ref,omitempty"`
-	Repository  string   `yaml:"repo,omitempty"`
-	VcsType     string   `yaml:"vcs,omitempty"`
-	Subpackages []string `yaml:"subpackages,omitempty"`
-	Arch        []string `yaml:"arch,omitempty"`
-	Os          []string `yaml:"os,omitempty"`
+	Name       string   `yaml:"package"`
+	Reference  string   `yaml:"version,omitempty"`
+	Branch     string   `yaml:"branch,omitempty"`
+	Repository string   `yaml:"repo,omitempty"`
+	Arch       []string `yaml:"arch,omitempty"`
+	Os         []string `yaml:"os,omitempty"`
 }
 
 // DependencyFromLock converts a Lock to a Dependency
 func DependencyFromLock(lock *Lock) *Dependency {
-	return &Dependency{
-		Name:        lock.Name,
-		Reference:   lock.Version,
-		Repository:  lock.Repository,
-		VcsType:     lock.VcsType,
-		Subpackages: lock.Subpackages,
-		Arch:        lock.Arch,
-		Os:          lock.Os,
+	d := &Dependency{
+		Name:       lock.Name,
+		Repository: lock.Repository,
 	}
+
+	r := gps.Revision(lock.Revision)
+	if lock.Version != "" {
+		d.Constraint = gps.NewVersion(lock.Version).Is(r)
+	} else if lock.Branch != "" {
+		d.Constraint = gps.NewBranch(lock.Version).Is(r)
+	} else {
+		d.Constraint = r
+	}
+
+	return d
 }
 
 // UnmarshalYAML is a hook for gopkg.in/yaml.v2 in the unmarshaling process
 func (d *Dependency) UnmarshalYAML(unmarshal func(interface{}) error) error {
-	newDep := &dep{}
+	newDep := dep{}
 	err := unmarshal(&newDep)
 	if err != nil {
 		return err
 	}
+
 	d.Name = newDep.Name
-	d.Reference = newDep.Reference
+	d.Repository = newDep.Repository
+	d.Arch = newDep.Arch
+	d.Os = newDep.Os
 
-	if d.Reference == "" && newDep.Ref != "" {
-		d.Reference = newDep.Ref
-	}
-
-	if d.Reference != "" {
-		r := d.Reference
+	if newDep.Reference != "" {
+		r := newDep.Reference
 		// TODO(sdboyer) this covers git & hg; bzr and svn (??) need love
 		if len(r) == 40 {
 			if _, err := hex.DecodeString(r); err == nil {
@@ -527,44 +470,16 @@
 		d.Constraint = gps.Any()
 	}
 
-	d.Repository = newDep.Repository
-	d.VcsType = newDep.VcsType
-	d.Subpackages = newDep.Subpackages
-	d.Arch = newDep.Arch
-	d.Os = newDep.Os
-
-	// Make sure only legitimate VCS are listed.
-	d.VcsType = filterVcsType(d.VcsType)
-
-	// Get the root name for the package
-	tn, subpkg := util.NormalizeName(d.Name)
-	d.Name = tn
-	if subpkg != "" {
-		d.Subpackages = append(d.Subpackages, subpkg)
-	}
-
-	// Older versions of Glide had a / prefix on subpackages in some cases.
-	// Here that's cleaned up. Someday we should be able to remove this.
-	for k, v := range d.Subpackages {
-		d.Subpackages[k] = strings.TrimPrefix(v, "/")
-	}
-
 	return nil
 }
 
 // MarshalYAML is a hook for gopkg.in/yaml.v2 in the marshaling process
 func (d *Dependency) MarshalYAML() (interface{}, error) {
-
-	// Make sure we only write the correct vcs type to file
-	t := filterVcsType(d.VcsType)
-
 	newDep := &dep{
-		Name:        d.Name,
-		Repository:  d.Repository,
-		VcsType:     t,
-		Subpackages: d.Subpackages,
-		Arch:        d.Arch,
-		Os:          d.Os,
+		Name:       d.Name,
+		Repository: d.Repository,
+		Arch:       d.Arch,
+		Os:         d.Os,
 	}
 
 	// Pull out the correct type of constraint
@@ -580,10 +495,9 @@
 	} else if gps.IsAny(d.Constraint) {
 		// We do nothing here, as the way any gets represented is with no
 		// constraint information at all
-		// TODO for now, probably until we add first-class 'default branch'
 	} else if d.Constraint != nil {
 		// The only other thing this could really be is a semver range. This
-		// will dump that up appropriately.
+		// will dump that appropriately.
 		newDep.Reference = d.Constraint.String()
 	}
 	// Just ignore any other case
@@ -593,8 +507,8 @@
 
 // GetRepo retrieves a Masterminds/vcs repo object configured for the root
 // of the package being retrieved.
+// TODO remove
 func (d *Dependency) GetRepo(dest string) (vcs.Repo, error) {
-
 	// The remote location is either the configured repo or the package
 	// name as an https url.
 	var remote string
@@ -626,29 +540,14 @@
 
 // Clone creates a clone of a Dependency
 func (d *Dependency) Clone() *Dependency {
-	return &Dependency{
-		Name:             d.Name,
-		Constraint:       d.Constraint,
-		Reference:        d.Reference,
-		Pin:              d.Pin,
-		Repository:       d.Repository,
-		VcsType:          d.VcsType,
-		Subpackages:      d.Subpackages,
-		Arch:             d.Arch,
-		Os:               d.Os,
-		UpdateAsVendored: d.UpdateAsVendored,
-	}
+	var d2 Dependency
+	d2 = *d
+	return &d2
 }
 
 // HasSubpackage returns if the subpackage is present on the dependency
+// TODO remove
 func (d *Dependency) HasSubpackage(sub string) bool {
-
-	for _, v := range d.Subpackages {
-		if sub == v {
-			return true
-		}
-	}
-
 	return false
 }
 
diff --git a/cfg/config_test.go b/cfg/config_test.go
index 6313ff0..082a9a4 100644
--- a/cfg/config_test.go
+++ b/cfg/config_test.go
@@ -15,6 +15,30 @@
 - name: foo
   email: bar@example.com
   homepage: https://example.com
+dependencies:
+- github.com/kylelemons/go-gypsy:
+    version: 1.0.0
+- github.com/Masterminds/convert:
+    repo: git@github.com:Masterminds/convert.git
+    version: a9949121a2e2192ca92fa6dddfeaaa4a4412d955
+- github.com/Masterminds/structable:
+    branch: master
+- github.com/Masterminds/cookoo/convert
+    repo: https://github.com/cookoo/convert.git
+
+testDependencies:
+  - package: github.com/kylelemons/go-gypsy
+`
+
+var lyml = `
+package: fake/testing
+description: foo bar baz
+homepage: https://example.com
+license: MIT
+owners:
+- name: foo
+  email: bar@example.com
+  homepage: https://example.com
 import:
   - package: github.com/kylelemons/go-gypsy
     subpackages:
@@ -41,8 +65,8 @@
   - package: github.com/kylelemons/go-gypsy
 `
 
-func TestManualConfigFromYaml(t *testing.T) {
-	cfg := &Config{}
+func TestLegacyManualConfigFromYaml(t *testing.T) {
+	cfg := &lConfig1{}
 	err := yaml.Unmarshal([]byte(yml), &cfg)
 	if err != nil {
 		t.Errorf("Unable to Unmarshal config yaml")
@@ -112,7 +136,7 @@
 }
 
 func TestConfigFromYaml(t *testing.T) {
-	c, err := ConfigFromYaml([]byte(yml))
+	c, legacy, err := ConfigFromYaml([]byte(yml))
 	if err != nil {
 		t.Error("ConfigFromYaml failed to parse yaml")
 	}
@@ -123,7 +147,7 @@
 }
 
 func TestHasDependency(t *testing.T) {
-	c, err := ConfigFromYaml([]byte(yml))
+	c, legacy, err := ConfigFromYaml([]byte(yml))
 	if err != nil {
 		t.Error("ConfigFromYaml failed to parse yaml for HasDependency")
 	}
diff --git a/cfg/legacy.go b/cfg/legacy.go
new file mode 100644
index 0000000..4cf294d
--- /dev/null
+++ b/cfg/legacy.go
@@ -0,0 +1,221 @@
+package cfg
+
+import (
+	"fmt"
+	"reflect"
+	"strings"
+
+	"github.com/Masterminds/glide/util"
+)
+
+// lConfig1 is a legacy Config file.
+type lConfig1 struct {
+	Name        string         `yaml:"package"`
+	Description string         `json:"description,omitempty"`
+	Home        string         `yaml:"homepage,omitempty"`
+	License     string         `yaml:"license,omitempty"`
+	Owners      Owners         `yaml:"owners,omitempty"`
+	Ignore      []string       `yaml:"ignore,omitempty"`
+	Exclude     []string       `yaml:"excludeDirs,omitempty"`
+	Imports     lDependencies1 `yaml:"import"`
+	DevImports  lDependencies1 `yaml:"testImport,omitempty"`
+}
+
+func (c *lConfig1) UnmarshalYAML(unmarshal func(interface{}) error) error {
+	newConfig := &lcf1{}
+	if err := unmarshal(&newConfig); err != nil {
+		return err
+	}
+	c.Name = newConfig.Name
+	c.Description = newConfig.Description
+	c.Home = newConfig.Home
+	c.License = newConfig.License
+	c.Owners = newConfig.Owners
+	c.Ignore = newConfig.Ignore
+	c.Exclude = newConfig.Exclude
+	c.Imports = newConfig.Imports
+	c.DevImports = newConfig.DevImports
+
+	// Cleanup the Config object now that we have it.
+	err := c.DeDupe()
+
+	return err
+}
+
+// DeDupe consolidates duplicate dependencies on a Config instance
+func (c *lConfig1) DeDupe() error {
+
+	// Remove duplicates in the imports
+	var err error
+	c.Imports, err = c.Imports.DeDupe()
+	if err != nil {
+		return err
+	}
+	c.DevImports, err = c.DevImports.DeDupe()
+	if err != nil {
+		return err
+	}
+
+	// If the name on the config object is part of the imports remove it.
+	found := -1
+	for i, dep := range c.Imports {
+		if dep.Name == c.Name {
+			found = i
+		}
+	}
+	if found >= 0 {
+		c.Imports = append(c.Imports[:found], c.Imports[found+1:]...)
+	}
+
+	found = -1
+	for i, dep := range c.DevImports {
+		if dep.Name == c.Name {
+			found = i
+		}
+	}
+	if found >= 0 {
+		c.DevImports = append(c.DevImports[:found], c.DevImports[found+1:]...)
+	}
+
+	// If something is on the ignore list remove it from the imports.
+	for _, v := range c.Ignore {
+		found = -1
+		for k, d := range c.Imports {
+			if v == d.Name {
+				found = k
+			}
+		}
+		if found >= 0 {
+			c.Imports = append(c.Imports[:found], c.Imports[found+1:]...)
+		}
+
+		found = -1
+		for k, d := range c.DevImports {
+			if v == d.Name {
+				found = k
+			}
+		}
+		if found >= 0 {
+			c.DevImports = append(c.DevImports[:found], c.DevImports[found+1:]...)
+		}
+	}
+
+	return nil
+}
+
+// Legacy representation of a glide.yaml file.
+type lcf1 struct {
+	Name        string         `yaml:"package"`
+	Description string         `yaml:"description,omitempty"`
+	Home        string         `yaml:"homepage,omitempty"`
+	License     string         `yaml:"license,omitempty"`
+	Owners      Owners         `yaml:"owners,omitempty"`
+	Ignore      []string       `yaml:"ignore,omitempty"`
+	Exclude     []string       `yaml:"excludeDirs,omitempty"`
+	Imports     lDependencies1 `yaml:"import"`
+	DevImports  lDependencies1 `yaml:"testImport,omitempty"`
+}
+
+type lDependencies1 []*lDependency1
+
+type lDependency1 struct {
+	Name        string   `yaml:"package"`
+	Reference   string   `yaml:"version,omitempty"`
+	Pin         string   `yaml:"-"`
+	Repository  string   `yaml:"repo,omitempty"`
+	VcsType     string   `yaml:"vcs,omitempty"`
+	Subpackages []string `yaml:"subpackages,omitempty"`
+	Arch        []string `yaml:"arch,omitempty"`
+	Os          []string `yaml:"os,omitempty"`
+}
+
+// Legacy unmarshaler
+func (d *lDependency1) UnmarshalYAML(unmarshal func(interface{}) error) error {
+	newDep := &ldep1{}
+	err := unmarshal(&newDep)
+	if err != nil {
+		return err
+	}
+	d.Name = newDep.Name
+	d.Reference = newDep.Reference
+	d.Repository = newDep.Repository
+	d.VcsType = newDep.VcsType
+	d.Subpackages = newDep.Subpackages
+	d.Arch = newDep.Arch
+	d.Os = newDep.Os
+
+	if d.Reference == "" && newDep.Ref != "" {
+		d.Reference = newDep.Ref
+	}
+
+	// Make sure only legitimate VCS are listed.
+	d.VcsType = filterVcsType(d.VcsType)
+
+	// Get the root name for the package
+	tn, subpkg := util.NormalizeName(d.Name)
+	d.Name = tn
+	if subpkg != "" {
+		d.Subpackages = append(d.Subpackages, subpkg)
+	}
+
+	// Older versions of Glide had a / prefix on subpackages in some cases.
+	// Here that's cleaned up. Someday we should be able to remove this.
+	for k, v := range d.Subpackages {
+		d.Subpackages[k] = strings.TrimPrefix(v, "/")
+	}
+
+	return nil
+}
+
+// DeDupe cleans up duplicates on a list of dependencies.
+func (d lDependencies1) DeDupe() (lDependencies1, error) {
+	checked := map[string]int{}
+	imports := make(lDependencies1, 0, 1)
+	i := 0
+	for _, dep := range d {
+		// The first time we encounter a dependency add it to the list
+		if val, ok := checked[dep.Name]; !ok {
+			checked[dep.Name] = i
+			imports = append(imports, dep)
+			i++
+		} else {
+			// In here we've encountered a dependency for the second time.
+			// Make sure the details are the same or return an error.
+			v := imports[val]
+			if dep.Reference != v.Reference {
+				return d, fmt.Errorf("Import %s repeated with different versions '%s' and '%s'", dep.Name, dep.Reference, v.Reference)
+			}
+			if dep.Repository != v.Repository || dep.VcsType != v.VcsType {
+				return d, fmt.Errorf("Import %s repeated with different Repository details", dep.Name)
+			}
+			if !reflect.DeepEqual(dep.Os, v.Os) || !reflect.DeepEqual(dep.Arch, v.Arch) {
+				return d, fmt.Errorf("Import %s repeated with different OS or Architecture filtering", dep.Name)
+			}
+			imports[checked[dep.Name]].Subpackages = stringArrayDeDupe(v.Subpackages, dep.Subpackages...)
+		}
+	}
+
+	return imports, nil
+}
+
+// Legacy representation of a dep constraint
+type ldep1 struct {
+	Name        string   `yaml:"package"`
+	Reference   string   `yaml:"version,omitempty"`
+	Ref         string   `yaml:"ref,omitempty"`
+	Repository  string   `yaml:"repo,omitempty"`
+	VcsType     string   `yaml:"vcs,omitempty"`
+	Subpackages []string `yaml:"subpackages,omitempty"`
+	Arch        []string `yaml:"arch,omitempty"`
+	Os          []string `yaml:"os,omitempty"`
+}
+
+type lLock1 struct {
+	Name        string   `yaml:"name"`
+	Version     string   `yaml:"version"`
+	Repository  string   `yaml:"repo,omitempty"`
+	VcsType     string   `yaml:"vcs,omitempty"`
+	Subpackages []string `yaml:"subpackages,omitempty"`
+	Arch        []string `yaml:"arch,omitempty"`
+	Os          []string `yaml:"os,omitempty"`
+}
diff --git a/cfg/lock.go b/cfg/lock.go
index b822f29..9bb23b4 100644
--- a/cfg/lock.go
+++ b/cfg/lock.go
@@ -38,8 +38,7 @@
 	for _, p := range r.Projects() {
 		pi := p.Ident()
 		l := &Lock{
-			Name:    string(pi.ProjectRoot),
-			VcsType: "", // TODO allow this to be extracted from sm
+			Name: string(pi.ProjectRoot),
 		}
 
 		if l.Name != pi.NetworkName && pi.NetworkName != "" {
@@ -80,10 +79,6 @@
 // MarshalYAML is a hook for gopkg.in/yaml.v2.
 // It sorts import subpackages lexicographically for reproducibility.
 func (lf *Lockfile) MarshalYAML() (interface{}, error) {
-	for _, imp := range lf.Imports {
-		sort.Strings(imp.Subpackages)
-	}
-
 	// Ensure elements on testImport don't already exist on import.
 	var newDI Locks
 	var found bool
@@ -104,9 +99,6 @@
 	}
 	lf.DevImports = newDI
 
-	for _, imp := range lf.DevImports {
-		sort.Strings(imp.Subpackages)
-	}
 	return lf, nil
 }
 
@@ -236,39 +228,28 @@
 
 // Lock represents an individual locked dependency.
 type Lock struct {
-	Name        string   `yaml:"name"`
-	Version     string   `yaml:"version"`
-	Repository  string   `yaml:"repo,omitempty"`
-	VcsType     string   `yaml:"vcs,omitempty"`
-	Subpackages []string `yaml:"subpackages,omitempty"`
-	Arch        []string `yaml:"arch,omitempty"`
-	Os          []string `yaml:"os,omitempty"`
+	Name       string `yaml:"name"`
+	Version    string `yaml:"version,omitempty"`
+	Branch     string `yaml:"branch,omitempty"`
+	Revision   string `yaml:"revision"`
+	Repository string `yaml:"repo,omitempty"`
 }
 
 // Clone creates a clone of a Lock.
 func (l *Lock) Clone() *Lock {
-	return &Lock{
-		Name:        l.Name,
-		Version:     l.Version,
-		Repository:  l.Repository,
-		VcsType:     l.VcsType,
-		Subpackages: l.Subpackages,
-		Arch:        l.Arch,
-		Os:          l.Os,
-	}
+	var l2 Lock
+	l2 = *l
+	return &l2
 }
 
 // LockFromDependency converts a Dependency to a Lock
 func LockFromDependency(dep *Dependency) *Lock {
-	return &Lock{
-		Name:        dep.Name,
-		Version:     dep.Pin,
-		Repository:  dep.Repository,
-		VcsType:     dep.VcsType,
-		Subpackages: dep.Subpackages,
-		Arch:        dep.Arch,
-		Os:          dep.Os,
+	l := &Lock{
+		Name:       dep.Name,
+		Repository: dep.Repository,
 	}
+
+	return l
 }
 
 // NewLockfile is used to create an instance of Lockfile.
@@ -292,8 +273,8 @@
 		for ii := 0; ii < len(ds); ii++ {
 			if ds[ii].Name == tds[i].Name {
 				found = true
-				if ds[ii].Reference != tds[i].Reference {
-					return &Lockfile{}, fmt.Errorf("Generating lock produced conflicting versions of %s. import (%s), testImport (%s)", tds[i].Name, ds[ii].Reference, tds[i].Reference)
+				if ds[ii].Constraint.String() != tds[i].Constraint.String() {
+					return &Lockfile{}, fmt.Errorf("Generating lock produced conflicting versions of %s. import (%s), testImport (%s)", tds[i].Name, ds[ii].Constraint, tds[i].Constraint)
 				}
 				break
 			}
diff --git a/cfg/lock_test.go b/cfg/lock_test.go
index 81edcd0..7f9ac95 100644
--- a/cfg/lock_test.go
+++ b/cfg/lock_test.go
@@ -7,14 +7,14 @@
 )
 
 func TestSortLocks(t *testing.T) {
-	c, err := ConfigFromYaml([]byte(yml))
+	c, legacy, err := ConfigFromYaml([]byte(yml))
 	if err != nil {
 		t.Error("ConfigFromYaml failed to parse yaml for TestSortDependencies")
 	}
 
 	ls := make(Locks, len(c.Imports))
 	for i := 0; i < len(c.Imports); i++ {
-		ls[i] = &Lock{
+		ls[i] = &lLock1{
 			Name:    c.Imports[i].Name,
 			Version: c.Imports[i].Reference,
 		}