blob: 5d4165c9443225163f6a50936c4d9ac2a3461dad [file] [log] [blame]
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package modconv
import (
"fmt"
"os"
"runtime"
"sort"
"strings"
"cmd/go/internal/base"
"cmd/go/internal/modfetch"
"golang.org/x/mod/modfile"
"golang.org/x/mod/module"
"golang.org/x/mod/semver"
)
// ConvertLegacyConfig converts legacy config to modfile.
// The file argument is slash-delimited.
func ConvertLegacyConfig(f *modfile.File, file string, data []byte) error {
i := strings.LastIndex(file, "/")
j := -2
if i >= 0 {
j = strings.LastIndex(file[:i], "/")
}
convert := Converters[file[i+1:]]
if convert == nil && j != -2 {
convert = Converters[file[j+1:]]
}
if convert == nil {
return fmt.Errorf("unknown legacy config file %s", file)
}
mf, err := convert(file, data)
if err != nil {
return fmt.Errorf("parsing %s: %v", file, err)
}
// Convert requirements block, which may use raw SHA1 hashes as versions,
// to valid semver requirement list, respecting major versions.
versions := make([]module.Version, len(mf.Require))
replace := make(map[string]*modfile.Replace)
for _, r := range mf.Replace {
replace[r.New.Path] = r
replace[r.Old.Path] = r
}
type token struct{}
sem := make(chan token, runtime.GOMAXPROCS(0))
for i, r := range mf.Require {
m := r.Mod
if m.Path == "" {
continue
}
if re, ok := replace[m.Path]; ok {
m = re.New
}
sem <- token{}
go func(i int, m module.Version) {
defer func() { <-sem }()
repo, info, err := modfetch.ImportRepoRev(m.Path, m.Version)
if err != nil {
fmt.Fprintf(os.Stderr, "go: converting %s: stat %s@%s: %v\n", base.ShortPath(file), m.Path, m.Version, err)
return
}
path := repo.ModulePath()
versions[i].Path = path
versions[i].Version = info.Version
}(i, m)
}
// Fill semaphore channel to wait for all tasks to finish.
for n := cap(sem); n > 0; n-- {
sem <- token{}
}
need := map[string]string{}
for _, v := range versions {
if v.Path == "" {
continue
}
// Don't use semver.Max here; need to preserve +incompatible suffix.
if needv, ok := need[v.Path]; !ok || semver.Compare(needv, v.Version) < 0 {
need[v.Path] = v.Version
}
}
paths := make([]string, 0, len(need))
for path := range need {
paths = append(paths, path)
}
sort.Strings(paths)
for _, path := range paths {
if re, ok := replace[path]; ok {
err := f.AddReplace(re.Old.Path, re.Old.Version, path, need[path])
if err != nil {
return fmt.Errorf("add replace: %v", err)
}
}
f.AddNewRequire(path, need[path], false)
}
f.Cleanup()
return nil
}