Source file src/cmd/go/internal/modconv/convert.go

Documentation: cmd/go/internal/modconv

     1  // Copyright 2018 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package modconv
     6  
     7  import (
     8  	"fmt"
     9  	"os"
    10  	"sort"
    11  	"strings"
    12  	"sync"
    13  
    14  	"cmd/go/internal/base"
    15  	"cmd/go/internal/modfetch"
    16  	"cmd/go/internal/modfile"
    17  	"cmd/go/internal/module"
    18  	"cmd/go/internal/par"
    19  	"cmd/go/internal/semver"
    20  )
    21  
    22  // ConvertLegacyConfig converts legacy config to modfile.
    23  // The file argument is slash-delimited.
    24  func ConvertLegacyConfig(f *modfile.File, file string, data []byte) error {
    25  	i := strings.LastIndex(file, "/")
    26  	j := -2
    27  	if i >= 0 {
    28  		j = strings.LastIndex(file[:i], "/")
    29  	}
    30  	convert := Converters[file[i+1:]]
    31  	if convert == nil && j != -2 {
    32  		convert = Converters[file[j+1:]]
    33  	}
    34  	if convert == nil {
    35  		return fmt.Errorf("unknown legacy config file %s", file)
    36  	}
    37  	mf, err := convert(file, data)
    38  	if err != nil {
    39  		return fmt.Errorf("parsing %s: %v", file, err)
    40  	}
    41  
    42  	// Convert requirements block, which may use raw SHA1 hashes as versions,
    43  	// to valid semver requirement list, respecting major versions.
    44  	var (
    45  		work    par.Work
    46  		mu      sync.Mutex
    47  		need    = make(map[string]string)
    48  		replace = make(map[string]*modfile.Replace)
    49  	)
    50  
    51  	for _, r := range mf.Replace {
    52  		replace[r.New.Path] = r
    53  		replace[r.Old.Path] = r
    54  	}
    55  	for _, r := range mf.Require {
    56  		m := r.Mod
    57  		if m.Path == "" {
    58  			continue
    59  		}
    60  		if re, ok := replace[m.Path]; ok {
    61  			work.Add(re.New)
    62  			continue
    63  		}
    64  		work.Add(r.Mod)
    65  	}
    66  
    67  	work.Do(10, func(item interface{}) {
    68  		r := item.(module.Version)
    69  		repo, info, err := modfetch.ImportRepoRev(r.Path, r.Version)
    70  		if err != nil {
    71  			fmt.Fprintf(os.Stderr, "go: converting %s: stat %s@%s: %v\n", base.ShortPath(file), r.Path, r.Version, err)
    72  			return
    73  		}
    74  		mu.Lock()
    75  		path := repo.ModulePath()
    76  		// Don't use semver.Max here; need to preserve +incompatible suffix.
    77  		if v, ok := need[path]; !ok || semver.Compare(v, info.Version) < 0 {
    78  			need[path] = info.Version
    79  		}
    80  		mu.Unlock()
    81  	})
    82  
    83  	var paths []string
    84  	for path := range need {
    85  		paths = append(paths, path)
    86  	}
    87  	sort.Strings(paths)
    88  	for _, path := range paths {
    89  		if re, ok := replace[path]; ok {
    90  			err := f.AddReplace(re.Old.Path, re.Old.Version, path, need[path])
    91  			if err != nil {
    92  				return fmt.Errorf("add replace: %v", err)
    93  			}
    94  		}
    95  		f.AddNewRequire(path, need[path], false)
    96  	}
    97  
    98  	f.Cleanup()
    99  	return nil
   100  }
   101  

View as plain text