Source File
search.go
Belonging Package
golang.org/x/pkgsite/internal/frontend
package frontend
import (
)
const defaultSearchLimit = 10
type SearchPage struct {
basePage
Pagination pagination
Results []*SearchResult
}
type SearchResult struct {
Name string
PackagePath string
ModulePath string
Synopsis string
DisplayVersion string
Licenses []string
CommitTime string
NumImportedBy int
Approximate bool
Symbols *subResult
SameModule *subResult // package paths in the same module
LowerMajor *subResult // package paths in lower major versions
}
type subResult struct {
Heading string
Links []link
Suffix string
}
func ( context.Context, *postgres.DB, string, paginationParams) (*SearchPage, error) {
:= maxSearchOffset + .limit
:= false
if strings.HasPrefix(, "identifier:") {
= strings.TrimPrefix(, "identifier:")
= true
}
, := .Search(, , .limit, .offset(), , )
if != nil {
return nil,
}
var []*SearchResult
for , := range {
= append(, &SearchResult{
Name: .Name,
PackagePath: .PackagePath,
ModulePath: .ModulePath,
Synopsis: .Synopsis,
DisplayVersion: displayVersion(.Version, .ModulePath),
Licenses: .Licenses,
CommitTime: elapsedTime(.CommitTime),
NumImportedBy: int(.NumImportedBy),
SameModule: packagePaths("Other packages in module "+.ModulePath+":", .SameModule, 5),
LowerMajor: modulePaths("Lower module versions:", .LowerMajor),
Symbols: symbolResults("Identifiers:", .PackagePath, .Symbols, 5),
})
}
var (
int
bool
)
if len() > 0 {
= int([0].NumResults)
= approximateNumber(, 0.1)
= true
}
}
:= 0
+= 1 + len(.SameModule)
}
:= newPagination(, , )
.Approximate =
return &SearchPage{
Results: ,
Pagination: ,
}, nil
}
return int( * math.Round(float64()/))
}
func ( string, []*internal.SearchResult, int) *subResult {
if len() == 0 {
return nil
}
var []link
for , := range {
if >= {
break
}
= append(, link{Href: .PackagePath, Body: internal.Suffix(.PackagePath, .ModulePath)})
}
:= ""
if len() > len() {
= fmt.Sprintf("(and %d more)", len()-len())
}
return &subResult{
Heading: ,
Links: ,
Suffix: ,
}
}
func ( string, []*internal.SearchResult) *subResult {
if len() == 0 {
return nil
}
:= map[string]bool{}
for , := range {
[.ModulePath] = true
}
var []string
for := range {
= append(, )
}
sort.Slice(, func(, int) bool {
, := internal.SeriesPathAndMajorVersion([])
, := internal.SeriesPathAndMajorVersion([])
return >
})
:= make([]link, len())
for , := range {
[] = link{Href: , Body: }
}
return &subResult{
Heading: ,
Links: ,
}
}
func (, string, []string, int) *subResult {
if len() == 0 {
return nil
}
var []link
for , := range {
if >= {
break
}
:= symbolLink(, , internal.BuildContexts)
= append(, link{Href: , Body: })
}
:= ""
if len() > len() {
= fmt.Sprintf("(and %d more)", len()-len())
}
return &subResult{
Heading: ,
Links: ,
Suffix: ,
}
}
maxSearchQueryLength = 500
maxSearchOffset = 90
maxSearchPageSize = 100
)
func ( *Server) ( http.ResponseWriter, *http.Request, internal.DataSource) error {
if .Method != http.MethodGet && .Method != http.MethodHead {
return &serverError{status: http.StatusMethodNotAllowed}
}
, := .(*postgres.DB)
return proxydatasourceNotSupportedErr()
}
:= .Context()
:= searchQuery()
if !utf8.ValidString() {
return &serverError{status: http.StatusBadRequest}
}
if len() > maxSearchQueryLength {
return &serverError{
status: http.StatusBadRequest,
epage: &errorPage{
messageTemplate: template.MakeTrustedTemplate(
`<h3 class="Error-message">Search query too long.</h3>`),
},
}
}
if == "" {
http.Redirect(, , "/", http.StatusFound)
return nil
}
:= newPaginationParams(, defaultSearchLimit)
if .offset() > maxSearchOffset {
return &serverError{
status: http.StatusBadRequest,
epage: &errorPage{
messageTemplate: template.MakeTrustedTemplate(
`<h3 class="Error-message">Search page number too large.</h3>`),
},
}
}
if .limit > maxSearchPageSize {
return &serverError{
status: http.StatusBadRequest,
epage: &errorPage{
messageTemplate: template.MakeTrustedTemplate(
`<h3 class="Error-message">Search page size too large.</h3>`),
},
}
}
if := searchRequestRedirectPath(, , ); != "" {
http.Redirect(, , , http.StatusFound)
return nil
}
, := fetchSearchPage(, , , )
if != nil {
return fmt.Errorf("fetchSearchPage(ctx, db, %q): %v", , )
}
.basePage = .newBasePage(, fmt.Sprintf("%s - Search Results", ))
.servePage(, , "search.tmpl", )
return nil
}
func ( context.Context, internal.DataSource, string) string {
:= strings.Index(, "://")
if > -1 {
= [+3:]
}
:= path.Clean()
if !strings.Contains(, "/") {
return ""
}
, := .GetUnitMeta(, , internal.UnknownModulePath, internal.LatestVersion)
if != nil {
if !errors.Is(, derrors.NotFound) {
log.Errorf(, "searchRequestRedirectPath(%q): %v", , )
}
return ""
}
return fmt.Sprintf("/%s", )
}
![]() |
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. |