// 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" "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, queryPackage func(path, rev string) (module.Version, error)) 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 }() version, err := queryPackage(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 } versions[i] = 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 }