-
Notifications
You must be signed in to change notification settings - Fork 1
/
imports.go
163 lines (144 loc) · 5.83 KB
/
imports.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// Copyright 2019 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 frontend
import (
"context"
"strings"
"github.com/khulnasoft-lab/godep/internal"
"github.com/khulnasoft-lab/godep/internal/frontend/serrors"
"github.com/khulnasoft-lab/godep/internal/log"
"github.com/khulnasoft-lab/godep/internal/stdlib"
"golang.org/x/text/language"
"golang.org/x/text/message"
)
// ImportsDetails contains information for a package's imports.
type ImportsDetails struct {
ModulePath string
// ExternalImports is the collection of package imports that are not in
// the Go standard library and are not part of the same module
ExternalImports []string
// InternalImports is an array of packages representing the package's
// imports that are part of the same module.
InternalImports []string
// StdLib is an array of packages representing the package's imports
// that are in the Go standard library.
StdLib []string
}
// fetchImportsDetails fetches imports for the package version specified by
// pkgPath, modulePath and version from the database and returns a ImportsDetails.
func fetchImportsDetails(ctx context.Context, ds internal.DataSource, pkgPath, modulePath, resolvedVersion string) (_ *ImportsDetails, err error) {
u, err := ds.GetUnit(ctx, &internal.UnitMeta{
Path: pkgPath,
ModuleInfo: internal.ModuleInfo{
ModulePath: modulePath,
Version: resolvedVersion,
},
}, internal.WithImports, internal.BuildContext{})
if err != nil {
return nil, err
}
var externalImports, moduleImports, std []string
for _, p := range u.Imports {
if stdlib.Contains(p) {
std = append(std, p)
} else if strings.HasPrefix(p+"/", modulePath+"/") {
moduleImports = append(moduleImports, p)
} else {
externalImports = append(externalImports, p)
}
}
return &ImportsDetails{
ModulePath: modulePath,
ExternalImports: externalImports,
InternalImports: moduleImports,
StdLib: std,
}, nil
}
// ImportedByDetails contains information for the collection of packages that
// import a given package.
type ImportedByDetails struct {
// ModulePath is the module path for the package referenced on this page.
ModulePath string
// ImportedBy is the collection of packages that import the
// given package and are not part of the same module.
// They are organized into a tree of sections by prefix.
ImportedBy []*Section
// NumImportedByDisplay is the display text at the top of the imported by
// tab section, which shows the imported by count and package limit.
NumImportedByDisplay string
// Total is the total number of importers.
Total int
}
var (
// importedByLimit is the maximum number of importers displayed on the imported
// by page.
// Variable for testing.
importedByLimit = 20001
)
// fetchImportedByDetails fetches importers for the package version specified by
// path and version from the database and returns a ImportedByDetails.
func fetchImportedByDetails(ctx context.Context, ds internal.DataSource, pkgPath, modulePath string) (*ImportedByDetails, error) {
db, ok := ds.(internal.PostgresDB)
if !ok {
// The proxydatasource does not support the imported by page.
return nil, serrors.DatasourceNotSupportedError()
}
importedBy, err := db.GetImportedBy(ctx, pkgPath, modulePath, importedByLimit)
if err != nil {
return nil, err
}
numImportedBy := len(importedBy)
numImportedBySearch, err := db.GetImportedByCount(ctx, pkgPath, modulePath)
if err != nil {
return nil, err
}
if numImportedBy < importedByLimit && numImportedBySearch > numImportedBy {
// Unless we hit the limit, numImportedBySearch should never be greater
// than numImportedBy. If that happens, log an error so that we can
// debug, but continue with generating the page for the user.
log.Errorf(ctx, "pkg %q, module %q: search_documents.num_imported_by %d > numImportedBy %d from imports unique, which shouldn't happen",
pkgPath, modulePath, numImportedBySearch, numImportedBy)
}
if numImportedBy >= importedByLimit {
importedBy = importedBy[:importedByLimit-1]
}
sections := Sections(importedBy, nextPrefixAccount)
// Display the number of importers, taking into account the number we
// actually retrieved, the limit on that number, and the imported-by count
// in the search_documents table.
pr := message.NewPrinter(language.English)
var (
display string
pkgword = "package"
)
if numImportedBy > 1 {
pkgword = "packages"
}
switch {
// If there are more importers than the limit, and the search number is
// greater, use the search number and indicate that we're displaying fewer.
case numImportedBy >= importedByLimit && numImportedBySearch > numImportedBy:
display = pr.Sprintf("%d (displaying %d %s)", numImportedBySearch, importedByLimit-1, pkgword)
// If we've exceeded the limit but the search number is smaller, we don't
// know the true number, so say so.
case numImportedBy >= importedByLimit:
display = pr.Sprintf("%d (displaying more than %d %s, including internal and invalid packages)", numImportedBySearch, importedByLimit-1, pkgword)
// If we haven't exceeded the limit and we have more than the search number,
// then display both numbers so users coming from the search page won't see
// a mismatch.
case numImportedBy > numImportedBySearch:
display = pr.Sprintf("%d (displaying %d %s, including internal and invalid packages)", numImportedBySearch, numImportedBy, pkgword)
// Otherwise, we have all the packages, and the search number is either
// wrong (perhaps it hasn't been recomputed yet) or it is the same as the
// retrieved number. In that case, just display the retrieved number.
default:
display = pr.Sprint(numImportedBy)
}
return &ImportedByDetails{
ModulePath: modulePath,
ImportedBy: sections,
NumImportedByDisplay: display,
Total: numImportedBy,
}, nil
}