return
}
mod := module.Version{Path: m.Path, Version: m.Version}
- m.Zip, err = modfetch.DownloadZip(mod)
+ m.Zip, err = modfetch.DownloadZip(ctx, mod)
if err != nil {
m.Error = err.Error()
return
"cmd/go/internal/par"
"cmd/go/internal/renameio"
"cmd/go/internal/robustio"
+ "cmd/go/internal/trace"
"golang.org/x/mod/module"
"golang.org/x/mod/sumdb/dirhash"
err error
}
c := downloadCache.Do(mod, func() interface{} {
- dir, err := download(mod)
+ dir, err := download(ctx, mod)
if err != nil {
return cached{"", err}
}
return c.dir, c.err
}
-func download(mod module.Version) (dir string, err error) {
+func download(ctx context.Context, mod module.Version) (dir string, err error) {
+ ctx, span := trace.StartSpan(ctx, "modfetch.download "+mod.String())
+ defer span.Done()
+
// If the directory exists, and no .partial file exists, the module has
// already been completely extracted. .partial files may be created when a
// module zip directory is extracted in place instead of being extracted to a
// To avoid cluttering the cache with extraneous files,
// DownloadZip uses the same lockfile as Download.
// Invoke DownloadZip before locking the file.
- zipfile, err := DownloadZip(mod)
+ zipfile, err := DownloadZip(ctx, mod)
if err != nil {
return "", err
}
return "", err
}
+ ctx, span = trace.StartSpan(ctx, "unzip "+zipfile)
if unzipInPlace {
if err := ioutil.WriteFile(partialPath, nil, 0666); err != nil {
return "", err
return "", err
}
}
+ defer span.Done()
if !cfg.ModCacheRW {
// Make dir read-only only *after* renaming it.
// DownloadZip downloads the specific module version to the
// local zip cache and returns the name of the zip file.
-func DownloadZip(mod module.Version) (zipfile string, err error) {
+func DownloadZip(ctx context.Context, mod module.Version) (zipfile string, err error) {
// The par.Cache here avoids duplicate work.
type cached struct {
zipfile string
if err := os.MkdirAll(filepath.Dir(zipfile), 0777); err != nil {
return cached{"", err}
}
- if err := downloadZip(mod, zipfile); err != nil {
+ if err := downloadZip(ctx, mod, zipfile); err != nil {
return cached{"", err}
}
return cached{zipfile, nil}
return c.zipfile, c.err
}
-func downloadZip(mod module.Version, zipfile string) (err error) {
+func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err error) {
+ ctx, span := trace.StartSpan(ctx, "modfetch.downloadZip "+zipfile)
+ defer span.Done()
+
// Clean up any remaining tempfiles from previous runs.
// This is only safe to do because the lock file ensures that their
// writers are no longer active.
package zip_sum_test
import (
+ "context"
"crypto/sha256"
"encoding/csv"
"encoding/hex"
name := fmt.Sprintf("%s@%s", strings.ReplaceAll(test.m.Path, "/", "_"), test.m.Version)
t.Run(name, func(t *testing.T) {
t.Parallel()
- zipPath, err := modfetch.DownloadZip(test.m)
+ zipPath, err := modfetch.DownloadZip(context.Background(), test.m)
if err != nil {
if *updateTestData {
t.Logf("%s: could not download module: %s (will remove from testdata)", test.m, err)
"cmd/go/internal/modfetch"
"cmd/go/internal/search"
"cmd/go/internal/str"
+ "cmd/go/internal/trace"
"golang.org/x/mod/module"
"golang.org/x/mod/semver"
}
func queryProxy(ctx context.Context, proxy, path, query, current string, allowed func(module.Version) bool) (*modfetch.RevInfo, error) {
+ ctx, span := trace.StartSpan(ctx, "modload.queryProxy "+path+" "+query)
+ defer span.Done()
+
if current != "" && !semver.IsValid(current) {
return nil, fmt.Errorf("invalid previous version %q", current)
}
// the main module and only the version "latest", without checking for other
// possible modules.
func QueryPattern(ctx context.Context, pattern, query string, allowed func(module.Version) bool) ([]QueryResult, error) {
+ ctx, span := trace.StartSpan(ctx, "modload.QueryPattern "+pattern+" "+query)
+ defer span.Done()
+
base := pattern
firstError := func(m *search.Match) error {
}
err := modfetch.TryProxies(func(proxy string) error {
- queryModule := func(path string) (r QueryResult, err error) {
+ queryModule := func(ctx context.Context, path string) (r QueryResult, err error) {
+ ctx, span := trace.StartSpan(ctx, "modload.QueryPattern.queryModule ["+proxy+"] "+path)
+ defer span.Done()
+
current := findCurrentVersion(path)
r.Mod.Path = path
r.Rev, err = queryProxy(ctx, proxy, path, query, current, allowed)
}
var err error
- results, err = queryPrefixModules(candidateModules, queryModule)
+ results, err = queryPrefixModules(ctx, candidateModules, queryModule)
return err
})
err error
}
-func queryPrefixModules(candidateModules []string, queryModule func(path string) (QueryResult, error)) (found []QueryResult, err error) {
+func queryPrefixModules(ctx context.Context, candidateModules []string, queryModule func(ctx context.Context, path string) (QueryResult, error)) (found []QueryResult, err error) {
+ ctx, span := trace.StartSpan(ctx, "modload.queryPrefixModules")
+ defer span.Done()
+
// If the path we're attempting is not in the module cache and we don't have a
// fetch result cached either, we'll end up making a (potentially slow)
// request to the proxy or (often even slower) the origin server.
var wg sync.WaitGroup
wg.Add(len(candidateModules))
for i, p := range candidateModules {
+ ctx := trace.StartGoroutine(ctx)
go func(p string, r *result) {
- r.QueryResult, r.err = queryModule(p)
+ r.QueryResult, r.err = queryModule(ctx, p)
wg.Done()
}(p, &results[i])
}