...

Source file src/cuelang.org/go/internal/mod/modload/query.go

Documentation: cuelang.org/go/internal/mod/modload

     1  package modload
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"path"
     7  	"runtime"
     8  	"sync"
     9  
    10  	"cuelang.org/go/internal/mod/modpkgload"
    11  	"cuelang.org/go/internal/mod/modrequirements"
    12  	"cuelang.org/go/internal/mod/semver"
    13  	"cuelang.org/go/internal/par"
    14  	"cuelang.org/go/mod/module"
    15  )
    16  
    17  // queryImport attempts to locate a module that can be added to the
    18  // current build list to provide the package with the given import path.
    19  // It also reports whether a default major version will be required
    20  // to select the candidates (this will be true if pkgPath lacks
    21  // a major version).
    22  //
    23  // It avoids results that are already in the given requirements.
    24  func (ld *loader) queryImport(ctx context.Context, pkgPath string, rs *modrequirements.Requirements) (candidates []module.Version, needsDefault bool, err error) {
    25  	if modpkgload.IsStdlibPackage(pkgPath) {
    26  		// This package isn't in the standard library and isn't in any module already
    27  		// in the build list.
    28  		//
    29  		// Moreover, the import path is reserved for the standard library, so
    30  		// QueryPattern cannot possibly find a module containing this package.
    31  		//
    32  		// Instead of trying QueryPattern, report an ImportMissingError immediately.
    33  		return nil, false, &modpkgload.ImportMissingError{Path: pkgPath}
    34  	}
    35  
    36  	// Look up module containing the package, for addition to the build list.
    37  	// Goal is to determine the module, download it to dir,
    38  	// and return m, dir, ImportMissingError.
    39  
    40  	// TODO this should probably be a non-debug log message.
    41  	logf("cue: finding module for package %s", pkgPath)
    42  
    43  	candidates, needsDefault, err = ld.queryLatestModules(ctx, pkgPath, rs)
    44  	if err != nil {
    45  		return nil, false, err
    46  	}
    47  	if len(candidates) == 0 {
    48  		return nil, false, fmt.Errorf("%v", &modpkgload.ImportMissingError{Path: pkgPath})
    49  	}
    50  	return candidates, needsDefault, nil
    51  }
    52  
    53  // queryLatestModules looks for potential modules that might contain the given
    54  // package by looking for the latest module version of all viable prefixes of pkgPath.
    55  // It does not return modules that are already present in the given requirements.
    56  // It also reports whether a default major version will be required.
    57  func (ld *loader) queryLatestModules(ctx context.Context, pkgPath string, rs *modrequirements.Requirements) ([]module.Version, bool, error) {
    58  	parts := module.ParseImportPath(pkgPath)
    59  	latestModuleForPrefix := func(prefix string) (module.Version, error) {
    60  		mv := parts.Version
    61  		if mv == "" {
    62  			var status modrequirements.MajorVersionDefaultStatus
    63  			mv, status = rs.DefaultMajorVersion(prefix)
    64  			if status == modrequirements.AmbiguousDefault {
    65  				// There are already multiple possibilities and
    66  				// we don't have any way of choosing one.
    67  				return module.Version{}, nil
    68  			}
    69  		}
    70  		mpath := prefix
    71  		if mv != "" {
    72  			mpath = prefix + "@" + mv
    73  			if _, ok := rs.RootSelected(mpath); ok {
    74  				// Already present in current requirements.
    75  				return module.Version{}, nil
    76  			}
    77  		}
    78  
    79  		versions, err := ld.registry.ModuleVersions(ctx, mpath)
    80  		logf("getting module versions for %q (prefix %q) -> %q, %v", mpath, prefix, versions, err)
    81  		if err != nil {
    82  			return module.Version{}, err
    83  		}
    84  		logf("-> %q", versions)
    85  		if v := latestVersion(versions); v != "" {
    86  			return module.NewVersion(prefix, v)
    87  		}
    88  		return module.Version{}, nil
    89  	}
    90  	work := par.NewQueue(runtime.GOMAXPROCS(0))
    91  	var (
    92  		mu         sync.Mutex
    93  		candidates []module.Version
    94  		queryErr   error
    95  	)
    96  	logf("initial module path %q", parts.Path)
    97  	for prefix := parts.Path; prefix != "."; prefix = path.Dir(prefix) {
    98  		prefix := prefix
    99  		work.Add(func() {
   100  			v, err := latestModuleForPrefix(prefix)
   101  			mu.Lock()
   102  			defer mu.Unlock()
   103  			if err != nil {
   104  				if queryErr == nil {
   105  					queryErr = err
   106  				}
   107  				return
   108  			}
   109  			if v.IsValid() {
   110  				candidates = append(candidates, v)
   111  			}
   112  		})
   113  	}
   114  	<-work.Idle()
   115  	return candidates, parts.Version == "", queryErr
   116  }
   117  
   118  // latestVersion returns the latest of any of the given versions,
   119  // ignoring prerelease versions if there is any stable version.
   120  func latestVersion(versions []string) string {
   121  	maxStable := ""
   122  	maxAny := ""
   123  	for _, v := range versions {
   124  		if semver.Prerelease(v) == "" && (maxStable == "" || semver.Compare(v, maxStable) > 0) {
   125  			maxStable = v
   126  		}
   127  		if maxAny == "" || semver.Compare(v, maxAny) > 0 {
   128  			maxAny = v
   129  		}
   130  	}
   131  	if maxStable != "" {
   132  		return maxStable
   133  	}
   134  	return maxAny
   135  }
   136  

View as plain text