cmd/go/internal/modconv: support conversion preserves replace and exclude statement

Now modconv is only work with the basic cases, we need support
"replace" and "exclude" from legacy config.

In followup CLs, It will preserve replacements from glide and vendor.json.

Updates golang/go#25556
Updates golang/go#24087

Change-Id: Ie5ca8df7f685177afea9cc7affcc6240b38223b5
Reviewed-on: https://go-review.googlesource.com/120075
Reviewed-by: Russ Cox <rsc@golang.org>
diff --git a/vendor/cmd/go/internal/modconv/dep.go b/vendor/cmd/go/internal/modconv/dep.go
index 28dd28a..690c206 100644
--- a/vendor/cmd/go/internal/modconv/dep.go
+++ b/vendor/cmd/go/internal/modconv/dep.go
@@ -9,11 +9,13 @@
 	"strconv"
 	"strings"
 
+	"cmd/go/internal/modfile"
 	"cmd/go/internal/module"
 	"cmd/go/internal/semver"
 )
 
-func ParseGopkgLock(file string, data []byte) ([]module.Version, error) {
+func ParseGopkgLock(file string, data []byte) (*modfile.File, error) {
+	mf := new(modfile.File)
 	var list []module.Version
 	var r *module.Version
 	for lineno, line := range strings.Split(string(data), "\n") {
@@ -66,6 +68,7 @@
 		if r.Path == "" || r.Version == "" {
 			return nil, fmt.Errorf("%s: empty [[projects]] stanza (%s)", file, r.Path)
 		}
+		mf.Require = append(mf.Require, &modfile.Require{Mod: r})
 	}
-	return list, nil
+	return mf, nil
 }
diff --git a/vendor/cmd/go/internal/modconv/glide.go b/vendor/cmd/go/internal/modconv/glide.go
index abe88c4..3bc675f 100644
--- a/vendor/cmd/go/internal/modconv/glide.go
+++ b/vendor/cmd/go/internal/modconv/glide.go
@@ -5,12 +5,14 @@
 package modconv
 
 import (
-	"cmd/go/internal/module"
 	"strings"
+
+	"cmd/go/internal/modfile"
+	"cmd/go/internal/module"
 )
 
-func ParseGlideLock(file string, data []byte) ([]module.Version, error) {
-	var list []module.Version
+func ParseGlideLock(file string, data []byte) (*modfile.File, error) {
+	mf := new(modfile.File)
 	imports := false
 	name := ""
 	for lineno, line := range strings.Split(string(data), "\n") {
@@ -32,9 +34,9 @@
 		if strings.HasPrefix(line, "  version:") {
 			version := strings.TrimSpace(line[len("  version:"):])
 			if name != "" && version != "" {
-				list = append(list, module.Version{Path: name, Version: version})
+				mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: name, Version: version}})
 			}
 		}
 	}
-	return list, nil
+	return mf, nil
 }
diff --git a/vendor/cmd/go/internal/modconv/glock.go b/vendor/cmd/go/internal/modconv/glock.go
index 57eb66e..1b786a9 100644
--- a/vendor/cmd/go/internal/modconv/glock.go
+++ b/vendor/cmd/go/internal/modconv/glock.go
@@ -7,17 +7,18 @@
 import (
 	"strings"
 
+	"cmd/go/internal/modfile"
 	"cmd/go/internal/module"
 )
 
-func ParseGLOCKFILE(file string, data []byte) ([]module.Version, error) {
-	var list []module.Version
+func ParseGLOCKFILE(file string, data []byte) (*modfile.File, error) {
+	mf := new(modfile.File)
 	for lineno, line := range strings.Split(string(data), "\n") {
 		lineno++
 		f := strings.Fields(line)
 		if len(f) >= 2 && f[0] != "cmd" {
-			list = append(list, module.Version{Path: f[0], Version: f[1]})
+			mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: f[0], Version: f[1]}})
 		}
 	}
-	return list, nil
+	return mf, nil
 }
diff --git a/vendor/cmd/go/internal/modconv/godeps.go b/vendor/cmd/go/internal/modconv/godeps.go
index 904fd70..6398dbe 100644
--- a/vendor/cmd/go/internal/modconv/godeps.go
+++ b/vendor/cmd/go/internal/modconv/godeps.go
@@ -7,10 +7,11 @@
 import (
 	"encoding/json"
 
+	"cmd/go/internal/modfile"
 	"cmd/go/internal/module"
 )
 
-func ParseGodepsJSON(file string, data []byte) ([]module.Version, error) {
+func ParseGodepsJSON(file string, data []byte) (*modfile.File, error) {
 	var cfg struct {
 		ImportPath string
 		Deps       []struct {
@@ -21,9 +22,9 @@
 	if err := json.Unmarshal(data, &cfg); err != nil {
 		return nil, err
 	}
-	var list []module.Version
+	mf := new(modfile.File)
 	for _, d := range cfg.Deps {
-		list = append(list, module.Version{Path: d.ImportPath, Version: d.Rev})
+		mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: d.ImportPath, Version: d.Rev}})
 	}
-	return list, nil
+	return mf, nil
 }
diff --git a/vendor/cmd/go/internal/modconv/modconv.go b/vendor/cmd/go/internal/modconv/modconv.go
index b689b52..5cc61a8 100644
--- a/vendor/cmd/go/internal/modconv/modconv.go
+++ b/vendor/cmd/go/internal/modconv/modconv.go
@@ -4,9 +4,9 @@
 
 package modconv
 
-import "cmd/go/internal/module"
+import "cmd/go/internal/modfile"
 
-var Converters = map[string]func(string, []byte) ([]module.Version, error){
+var Converters = map[string]func(string, []byte) (*modfile.File, error){
 	"GLOCKFILE":          ParseGLOCKFILE,
 	"Godeps/Godeps.json": ParseGodepsJSON,
 	"Gopkg.lock":         ParseGopkgLock,
diff --git a/vendor/cmd/go/internal/modconv/modconv_test.go b/vendor/cmd/go/internal/modconv/modconv_test.go
index 5defacd..353161b 100644
--- a/vendor/cmd/go/internal/modconv/modconv_test.go
+++ b/vendor/cmd/go/internal/modconv/modconv_test.go
@@ -55,8 +55,8 @@
 				t.Error(err)
 			}
 			var buf bytes.Buffer
-			for _, r := range out {
-				fmt.Fprintf(&buf, "%s %s\n", r.Path, r.Version)
+			for _, r := range out.Require {
+				fmt.Fprintf(&buf, "%s %s\n", r.Mod.Path, r.Mod.Version)
 			}
 			if !bytes.Equal(buf.Bytes(), want) {
 				t.Errorf("have:\n%s\nwant:\n%s", buf.Bytes(), want)
diff --git a/vendor/cmd/go/internal/modconv/tsv.go b/vendor/cmd/go/internal/modconv/tsv.go
index fd33649..feba181 100644
--- a/vendor/cmd/go/internal/modconv/tsv.go
+++ b/vendor/cmd/go/internal/modconv/tsv.go
@@ -7,17 +7,18 @@
 import (
 	"strings"
 
+	"cmd/go/internal/modfile"
 	"cmd/go/internal/module"
 )
 
-func ParseDependenciesTSV(file string, data []byte) ([]module.Version, error) {
-	var list []module.Version
+func ParseDependenciesTSV(file string, data []byte) (*modfile.File, error) {
+	mf := new(modfile.File)
 	for lineno, line := range strings.Split(string(data), "\n") {
 		lineno++
 		f := strings.Split(line, "\t")
 		if len(f) >= 3 {
-			list = append(list, module.Version{Path: f[0], Version: f[2]})
+			mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: f[0], Version: f[2]}})
 		}
 	}
-	return list, nil
+	return mf, nil
 }
diff --git a/vendor/cmd/go/internal/modconv/vconf.go b/vendor/cmd/go/internal/modconv/vconf.go
index 5d3cd3c..a9a8e62 100644
--- a/vendor/cmd/go/internal/modconv/vconf.go
+++ b/vendor/cmd/go/internal/modconv/vconf.go
@@ -7,11 +7,12 @@
 import (
 	"strings"
 
+	"cmd/go/internal/modfile"
 	"cmd/go/internal/module"
 )
 
-func ParseVendorConf(file string, data []byte) ([]module.Version, error) {
-	var list []module.Version
+func ParseVendorConf(file string, data []byte) (*modfile.File, error) {
+	mf := new(modfile.File)
 	for lineno, line := range strings.Split(string(data), "\n") {
 		lineno++
 		if i := strings.Index(line, "#"); i >= 0 {
@@ -19,8 +20,8 @@
 		}
 		f := strings.Fields(line)
 		if len(f) >= 2 {
-			list = append(list, module.Version{Path: f[0], Version: f[1]})
+			mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: f[0], Version: f[1]}})
 		}
 	}
-	return list, nil
+	return mf, nil
 }
diff --git a/vendor/cmd/go/internal/modconv/vjson.go b/vendor/cmd/go/internal/modconv/vjson.go
index 38b0a68..eec86b7 100644
--- a/vendor/cmd/go/internal/modconv/vjson.go
+++ b/vendor/cmd/go/internal/modconv/vjson.go
@@ -7,10 +7,11 @@
 import (
 	"encoding/json"
 
+	"cmd/go/internal/modfile"
 	"cmd/go/internal/module"
 )
 
-func ParseVendorJSON(file string, data []byte) ([]module.Version, error) {
+func ParseVendorJSON(file string, data []byte) (*modfile.File, error) {
 	var cfg struct {
 		Package []struct {
 			Path     string
@@ -20,9 +21,9 @@
 	if err := json.Unmarshal(data, &cfg); err != nil {
 		return nil, err
 	}
-	var list []module.Version
+	mf := new(modfile.File)
 	for _, d := range cfg.Package {
-		list = append(list, module.Version{Path: d.Path, Version: d.Revision})
+		mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: d.Path, Version: d.Revision}})
 	}
-	return list, nil
+	return mf, nil
 }
diff --git a/vendor/cmd/go/internal/modconv/vmanifest.go b/vendor/cmd/go/internal/modconv/vmanifest.go
index f2cf0f5..c0ef2a9 100644
--- a/vendor/cmd/go/internal/modconv/vmanifest.go
+++ b/vendor/cmd/go/internal/modconv/vmanifest.go
@@ -7,10 +7,11 @@
 import (
 	"encoding/json"
 
+	"cmd/go/internal/modfile"
 	"cmd/go/internal/module"
 )
 
-func ParseVendorManifest(file string, data []byte) ([]module.Version, error) {
+func ParseVendorManifest(file string, data []byte) (*modfile.File, error) {
 	var cfg struct {
 		Dependencies []struct {
 			ImportPath string
@@ -20,9 +21,9 @@
 	if err := json.Unmarshal(data, &cfg); err != nil {
 		return nil, err
 	}
-	var list []module.Version
+	mf := new(modfile.File)
 	for _, d := range cfg.Dependencies {
-		list = append(list, module.Version{Path: d.ImportPath, Version: d.Revision})
+		mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: d.ImportPath, Version: d.Revision}})
 	}
-	return list, nil
+	return mf, nil
 }
diff --git a/vendor/cmd/go/internal/modconv/vyml.go b/vendor/cmd/go/internal/modconv/vyml.go
index e2ea9e3..0f017a3 100644
--- a/vendor/cmd/go/internal/modconv/vyml.go
+++ b/vendor/cmd/go/internal/modconv/vyml.go
@@ -5,12 +5,14 @@
 package modconv
 
 import (
-	"cmd/go/internal/module"
 	"strings"
+
+	"cmd/go/internal/modfile"
+	"cmd/go/internal/module"
 )
 
-func ParseVendorYML(file string, data []byte) ([]module.Version, error) {
-	var list []module.Version
+func ParseVendorYML(file string, data []byte) (*modfile.File, error) {
+	mf := new(modfile.File)
 	vendors := false
 	path := ""
 	for lineno, line := range strings.Split(string(data), "\n") {
@@ -32,9 +34,9 @@
 		if strings.HasPrefix(line, "  rev:") {
 			rev := strings.TrimSpace(line[len("  rev:"):])
 			if path != "" && rev != "" {
-				list = append(list, module.Version{Path: path, Version: rev})
+				mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: path, Version: rev}})
 			}
 		}
 	}
-	return list, nil
+	return mf, nil
 }
diff --git a/vendor/cmd/go/internal/modfetch/convert.go b/vendor/cmd/go/internal/modfetch/convert.go
index 9e15116..bebb6ee 100644
--- a/vendor/cmd/go/internal/modfetch/convert.go
+++ b/vendor/cmd/go/internal/modfetch/convert.go
@@ -33,7 +33,7 @@
 	if convert == nil {
 		return fmt.Errorf("unknown legacy config file %s", file)
 	}
-	require, err := convert(file, data)
+	result, err := convert(file, data)
 	if err != nil {
 		return fmt.Errorf("parsing %s: %v", file, err)
 	}
@@ -41,19 +41,20 @@
 	// Convert requirements block, which may use raw SHA1 hashes as versions,
 	// to valid semver requirement list, respecting major versions.
 	var work par.Work
-	for _, r := range require {
-		if r.Path == "" {
+	for _, r := range result.Require {
+		m := r.Mod
+		if m.Path == "" {
 			continue
 		}
 
 		// TODO: Something better here.
-		if strings.HasPrefix(r.Path, "github.com/") || strings.HasPrefix(r.Path, "golang.org/x/") {
-			f := strings.Split(r.Path, "/")
+		if strings.HasPrefix(m.Path, "github.com/") || strings.HasPrefix(m.Path, "golang.org/x/") {
+			f := strings.Split(m.Path, "/")
 			if len(f) > 3 {
-				r.Path = strings.Join(f[:3], "/")
+				m.Path = strings.Join(f[:3], "/")
 			}
 		}
-		work.Add(r)
+		work.Add(m)
 	}
 
 	var (
@@ -81,5 +82,12 @@
 		f.AddNewRequire(path, need[path])
 	}
 
+	for _, r := range result.Replace {
+		err := f.AddReplace(r.Old.Path, r.Old.Version, r.New.Path, r.New.Version)
+		if err != nil {
+			return fmt.Errorf("add replace: %v", err)
+		}
+	}
+	f.Cleanup()
 	return nil
 }