blob: 480bf23715d6101a6710ffb3411e3c33902c151c [file] [edit]
// Copyright 2026 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 main
import (
"context"
"flag"
"fmt"
"io"
"golang.org/x/pkgsite/cmd/internal/pkgsite-cli/client"
)
func runPackage(fs *flag.FlagSet, p *packageFlags, stdout, stderr io.Writer) int {
if fs.NArg() != 1 {
fmt.Fprintf(stderr, "Error: expected exactly 1 package argument, got %d\n", fs.NArg())
fs.Usage()
return 2
}
path, version := splitPathVersion(fs.Arg(0))
ctx, cancel := context.WithTimeout(context.Background(), p.timeout)
defer cancel()
c, err := client.New(p.server)
if err != nil {
handleErr(stdout, stderr, err, p.jsonOut)
return 1
}
c.PrintURLs = p.printURLs
c.Output = stderr
pkg, err := c.GetPackage(ctx, path, version, client.PackageOptions{
Module: p.module,
Doc: p.doc,
Examples: p.examples,
Imports: p.imports,
Licenses: p.licenses,
GOOS: p.goos,
GOARCH: p.goarch,
})
if err != nil {
handleErr(stdout, stderr, err, p.jsonOut)
return 1
}
result := packageResult{Package: pkg}
if p.symbols {
fetch := func(token string, limit int) (*client.PaginatedResponse[client.Symbol], error) {
return c.GetSymbols(ctx, path, version, client.SymbolsOptions{
Module: p.module,
GOOS: p.goos,
GOARCH: p.goarch,
PaginationOptions: client.PaginationOptions{
Limit: limit,
Token: token,
},
})
}
items, total, nextToken, err := client.AllItems(p.symbolToken, p.effectiveLimit(), fetch)
if err != nil {
if client.Is429(err) {
result.Symbols = &client.PaginatedResponse[client.Symbol]{
Items: items,
Total: total,
NextPageToken: nextToken,
}
return printPartialPackageResult(stdout, stderr, result, p.jsonOut)
}
handleErr(stdout, stderr, err, p.jsonOut)
return 1
}
result.Symbols = &client.PaginatedResponse[client.Symbol]{
Items: items,
Total: total,
}
}
if p.importedBy {
var initialResp *client.PackageImportedBy
fetch := func(token string, limit int) (*client.PaginatedResponse[string], error) {
r, err := c.GetImportedBy(ctx, path, version, client.ImportedByOptions{
Module: p.module,
PaginationOptions: client.PaginationOptions{
Limit: limit,
Token: token,
},
})
if err != nil {
return nil, err
}
if initialResp == nil {
initialResp = r
}
return &r.ImportedBy, nil
}
items, total, nextToken, err := client.AllItems(p.importedByToken, p.effectiveLimit(), fetch)
if err != nil {
if client.Is429(err) {
if initialResp == nil {
initialResp = &client.PackageImportedBy{}
}
result.ImportedBy = initialResp
result.ImportedBy.ImportedBy.Items = items
result.ImportedBy.ImportedBy.Total = total
result.ImportedBy.ImportedBy.NextPageToken = nextToken
return printPartialPackageResult(stdout, stderr, result, p.jsonOut)
}
handleErr(stdout, stderr, err, p.jsonOut)
return 1
}
result.ImportedBy = initialResp
result.ImportedBy.ImportedBy.Items = items
result.ImportedBy.ImportedBy.Total = total
}
if p.jsonOut {
return writeJSON(stdout, stderr, result)
}
formatPackage(stdout, result)
return 0
}
// packageFlags are flags for the package subcommand.
type packageFlags struct {
commonFlags
doc string
examples bool
imports bool
importedBy bool
symbols bool
licenses bool
module string
goos string
goarch string
symbolToken string
importedByToken string
}
func (f *packageFlags) register(fs *flag.FlagSet) {
f.commonFlags.register(fs)
fs.StringVar(&f.doc, "doc", "", "render docs in format: text, md, html")
fs.BoolVar(&f.examples, "examples", false, "include examples (requires -doc)")
fs.BoolVar(&f.imports, "imports", false, "list imported packages")
fs.BoolVar(&f.importedBy, "imported-by", false, "list reverse dependencies")
fs.BoolVar(&f.symbols, "symbols", false, "list exported symbols")
fs.BoolVar(&f.licenses, "licenses", false, "show license information")
fs.StringVar(&f.module, "module", "", "disambiguate module path")
fs.StringVar(&f.goos, "goos", "", "target GOOS")
fs.StringVar(&f.goarch, "goarch", "", "target GOARCH")
fs.StringVar(&f.symbolToken, "symbol-token", "", "page token for symbols pagination")
fs.StringVar(&f.importedByToken, "imported-by-token", "", "page token for imported-by pagination")
}
func printPartialPackageResult(stdout, stderr io.Writer, result packageResult, jsonMode bool) int {
if jsonMode {
writeJSON(stdout, stderr, result)
} else {
formatPackage(stdout, result)
fmt.Fprintln(stderr, "Warning: hit rate limit (429); results are incomplete.")
}
return 1
}