Source File
fetch.go
Belonging Package
golang.org/x/pkgsite/internal/fetch
package fetch
import (
)
var (
ErrModuleContainsNoPackages = errors.New("module contains 0 packages")
errMalformedZip = errors.New("module zip is malformed")
)
var (
fetchLatency = stats.Float64(
"go-discovery/worker/fetch-latency",
"Latency of a fetch request.",
stats.UnitSeconds,
)
fetchesShedded = stats.Int64(
"go-discovery/worker/fetch-shedded",
"Count of shedded fetches.",
stats.UnitDimensionless,
)
fetchedPackages = stats.Int64(
"go-discovery/worker/fetch-package-count",
"Count of successfully fetched packages.",
stats.UnitDimensionless,
)
FetchLatencyDistribution = &view.View{
Name: "go-discovery/worker/fetch-latency",
Measure: fetchLatency,
Aggregation: ochttp.DefaultLatencyDistribution,
Description: "Fetch latency by result status.",
TagKeys: []tag.Key{dcensus.KeyStatus},
FetchResponseCount = &view.View{
Name: "go-discovery/worker/fetch-count",
Measure: fetchLatency,
Aggregation: view.Count(),
Description: "Fetch request count by result status",
TagKeys: []tag.Key{dcensus.KeyStatus},
FetchPackageCount = &view.View{
Name: "go-discovery/worker/fetch-package-count",
Measure: fetchedPackages,
Aggregation: view.Count(),
Description: "Count of packages successfully fetched",
SheddedFetchCount = &view.View{
Name: "go-discovery/worker/fetch-shedded",
Measure: fetchesShedded,
Aggregation: view.Count(),
Description: "Count of shedded fetches",
}
)
type FetchResult struct {
ModulePath string
RequestedVersion string
ResolvedVersion string
MainVersion string
func ( context.Context, , string, *proxy.Client, *source.Client) ( *FetchResult) {
:= time.Now()
defer func() {
:= float64(time.Since().Seconds())
dcensus.RecordWithTag(, dcensus.KeyStatus, strconv.Itoa(.Status), fetchLatency.M())
if .Status < 300 {
stats.Record(, fetchedPackages.M(int64(len(.PackageVersionStates))))
}
}()
= &FetchResult{
ModulePath: ,
RequestedVersion: ,
Defer: func() {},
}
defer derrors.Wrap(&.Error, "FetchModule(%q, %q)", , )
, := fetchModule(, , , )
.Error =
if != nil {
.Status = derrors.ToStatus(.Error)
}
if .Status == 0 {
.Status = http.StatusOK
}
if != nil {
finishFetchInfo(, .Status, .Error)
}
return
}
func ( context.Context, *FetchResult, *proxy.Client, *source.Client) (*FetchInfo, error) {
, := GetInfo(, .ModulePath, .RequestedVersion, )
if != nil {
return nil,
}
.ResolvedVersion = .Version
:= .Time
var int64
if zipLoadShedder != nil {
var error
, = getZipSize(, .ModulePath, .ResolvedVersion, )
if != nil {
return nil,
, := zipLoadShedder.shouldShed(uint64())
.Defer =
if {
stats.Record(, fetchesShedded.M(1))
return nil, fmt.Errorf("%w: size=%dMi", derrors.SheddingLoad, /mib)
}
if > maxModuleZipSize {
log.Warningf(, "FetchModule: %s@%s zip size %dMi exceeds max %dMi",
.ModulePath, .ResolvedVersion, /mib, maxModuleZipSize/mib)
return nil, derrors.ModuleTooLarge
}
}
:= &FetchInfo{
ModulePath: .ModulePath,
Version: .ResolvedVersion,
ZipSize: uint64(),
Start: time.Now(),
}
startFetchInfo()
var *zip.Reader
if .ModulePath == stdlib.ModulePath {
var string
, , , = stdlib.Zip(.RequestedVersion)
if != nil {
return ,
.ResolvedVersion =
.Version =
} else {
, = .Zip(, .ModulePath, .ResolvedVersion)
if != nil {
return ,
}
}
if .ModulePath == stdlib.ModulePath {
.HasGoMod = true
} else {
.HasGoMod = hasGoModFile(, .ModulePath, .ResolvedVersion)
}
var []byte
.GoModPath, , = getGoModPath(, .ModulePath, .ResolvedVersion, )
if != nil {
return ,
}
, , := processZipFile(, .ModulePath, .ResolvedVersion, , , )
if != nil {
return ,
}
.HasGoMod = .HasGoMod
if != nil {
if := processGoModFile(, ); != nil {
return , fmt.Errorf("%v: %w", .Error(), derrors.BadModule)
}
}
.Module =
.PackageVersionStates =
for , := range .PackageVersionStates {
if .Status != http.StatusOK {
.Status = derrors.ToStatus(derrors.HasIncompletePackages)
}
}
return , nil
}
func ( context.Context, , string, *proxy.Client) ( *proxy.VersionInfo, error) {
if == stdlib.ModulePath {
var string
, = stdlib.ZipInfo()
if != nil {
return nil,
}
return &proxy.VersionInfo{Version: }, nil
}
return .Info(, , )
}
func ( context.Context, , string, *proxy.Client) ( int64, error) {
if == stdlib.ModulePath {
return stdlib.EstimatedZipSize, nil
}
return .ZipSize(, , )
}
return , , fmt.Errorf("module path=%s, go.mod path=%s: %w", , , derrors.AlternativeModule)
}
return , , nil
}
func ( context.Context, string, string, time.Time, *zip.Reader, *source.Client) ( *internal.Module, []*internal.PackageVersionState, error) {
defer derrors.Wrap(&, "processZipFile(%q, %q)", , )
, := trace.StartSpan(, "fetch.processZipFile")
defer .End()
, := source.ModuleInfo(, , , )
if != nil {
log.Infof(, "error getting source info: %v", )
}
, := extractReadmesFromZip(, , )
if != nil {
return nil, nil, fmt.Errorf("extractReadmesFromZip(%q, %q, zipReader): %v", , , )
}
:= func( string, ...interface{}) {
log.Infof(, , ...)
}
:= licenses.NewDetector(, , , )
:= .AllLicenses()
, , := extractPackagesFromZip(, , , , , )
if errors.Is(, ErrModuleContainsNoPackages) || errors.Is(, errMalformedZip) {
return nil, nil, fmt.Errorf("%v: %w", .Error(), derrors.BadModule)
}
if != nil {
return nil, nil, fmt.Errorf("extractPackagesFromZip(%q, %q, zipReader, %v): %v", , , , )
}
return &internal.Module{
ModuleInfo: internal.ModuleInfo{
ModulePath: ,
Version: ,
CommitTime: ,
IsRedistributable: .ModuleIsRedistributable(),
func ( []byte, *internal.Module) ( error) {
defer derrors.Wrap(&, "processGoModFile")
, := modfile.Parse("go.mod", , nil)
if != nil {
return
}
.Deprecated, .DeprecationComment = extractDeprecatedComment()
return nil
}
func ( *modfile.File) (bool, string) {
const = "Deprecated:"
if .Module == nil {
return false, ""
}
for , := range append(.Module.Syntax.Before, .Module.Syntax.Suffix...) {
:= strings.TrimSpace(strings.TrimPrefix(.Token, "//"))
if strings.HasPrefix(, ) {
return true, strings.TrimSpace([len():])
}
}
return false, ""
}
func ( *zip.Reader, string) *zip.File {
for , := range .File {
if .Name == {
return
}
}
return nil
}
type FetchInfo struct {
ModulePath string
Version string
ZipSize uint64
Start time.Time
Finish time.Time
Status int
Error error
}
var (
fetchInfoMu sync.Mutex
fetchInfoMap = map[*FetchInfo]struct{}{}
)
func () {
const = time.Minute
go func() {
for {
:= time.Now()
fetchInfoMu.Lock()
for := range fetchInfoMap {
if !.Finish.IsZero() && .Sub(.Finish) > {
delete(fetchInfoMap, )
}
}
fetchInfoMu.Unlock()
time.Sleep()
}
}()
}
func ( *FetchInfo) {
fetchInfoMu.Lock()
defer fetchInfoMu.Unlock()
fetchInfoMap[] = struct{}{}
}
func ( *FetchInfo, int, error) {
fetchInfoMu.Lock()
defer fetchInfoMu.Unlock()
.Finish = time.Now()
.Status =
.Error =
}
func () []*FetchInfo {
var []*FetchInfo
fetchInfoMu.Lock()
:= *
= append(, &)
}
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |