cmd/internal/pkgsite-cli: move the design memo to the package dir This change will make the memo shown in pkgsite. Also apply minor polishing of help message and source code documentation. Change-Id: Ia26e705171aea9d649e3469ad14ba256ba044ebc Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/781241 Reviewed-by: Jonathan Amsterdam <jba@google.com> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Ethan Lee <ethanalee@google.com> kokoro-CI: kokoro <noreply+kokoro@google.com>
diff --git a/cmd/internal/pkgsite-cli/README.md b/cmd/internal/pkgsite-cli/README.md new file mode 100644 index 0000000..7b8c397 --- /dev/null +++ b/cmd/internal/pkgsite-cli/README.md
@@ -0,0 +1,113 @@ +# pkgsite-cli + +A command-line interface for querying [pkg.go.dev](https://pkg.go.dev/). + +Currently, the API is on `v1beta`, but we expect to move to `v1` soon. + +Related to issue [76718](https://go.dev/issue/76718). + +## Quick start + +To install the `pkgsite-cli` tool, run: + +```bash +go install golang.org/x/pkgsite/cmd/internal/pkgsite-cli@latest +``` + +## Motivation + +The [pkg.go.dev](https://pkg.go.dev/) service provides an API interface at +https://pkg.go.dev/api to allow querying information about published Go +packages and modules. The API uses a stateless, GET-only architecture designed +for stability and efficient caching. `pkgsite-cli` is a lightweight CLI that +uses this API. There is no official SDK for the API, but this tool serves as a +reference client implementation that developers can use in other projects. See +the [API spec](https://pkg.go.dev/api) and the +[OpenAPI specification](https://pkg.go.dev/v1beta/openapi.yaml). + +## Relationship to existing tools + +- **`go doc`** renders documentation for packages available locally. + `pkgsite-cli` does not replace it for reading local documentation. +- **`cmd/pkgsite`** is a web server that serves documentation for packages + available locally. It does not provide full version listings, vulnerability + reports, reverse dependencies, licenses, or search capabilities (yet). +- **`pkgsite-cli`** provides access to information that `go doc` or a local + instance of `cmd/pkgsite` cannot reach: version listings, vulnerability + reports, reverse dependencies, licenses, documentation of modules/packages, + and search results for packages not yet downloaded. + +Rule of thumb: Use `go doc` for local code; use `pkgsite-cli` for package +discovery and metadata lookup. + +## Commands + +Run `pkgsite-cli <command> -h` for details on available flags for each command. + +Available commands: + * `package` + * `module` + * `search` + +Additional commands will be added in the future. + +## Usage Examples + +### Search for packages: + +```bash +pkgsite-cli search uuid +``` + +### Inspect a specific package: + +```bash +pkgsite-cli package github.com/google/go-cmp/cmp +``` + +### See reverse dependencies for a package: + +```bash +pkgsite-cli package -imported-by github.com/google/go-cmp/cmp +``` + +### List exported symbols declared by a package: + +```bash +pkgsite-cli package -symbols github.com/google/go-cmp/cmp +``` + +### List versions of a module: + +```bash +pkgsite-cli module -versions github.com/google/go-cmp +``` + +### List both versions and packages belonging to a module: + +```bash +pkgsite-cli module -packages -versions github.com/google/go-cmp +``` + +## Details +- **Ambiguous paths**: Unlike `go mod tidy` or the + [pkg.go.dev](https://pkg.go.dev) web interface, which use the "longest + module path" rule to resolve ambiguous package paths, the API requires the + module to be specified unambiguously. If a package path is ambiguous + because it exists in multiple modules, the API returns a list of candidates + and reports an error. Use the `-module` flag to specify the correct + module path. + + +## Status and Implementation +- **Experimental**: This tool is currently a prototype. +- **Minimal Dependencies**: To facilitate potential migration to other + repositories (e.g., `x/tools`), the tool depends only on the Go standard + library. +- **Duplicate Types**: API request and response types are duplicated in the + tool's source instead of imported from `pkgsite` for now. We ruled out + releasing a full SDK because the REST API is simple enough to consume + directly. This keeps the tool self-contained. However, if this tool remains + in this repository, we can eliminate this duplication by using the internal + package. +
diff --git a/cmd/internal/pkgsite-cli/client/client.go b/cmd/internal/pkgsite-cli/client/client.go index e78b26f..f4b6553 100644 --- a/cmd/internal/pkgsite-cli/client/client.go +++ b/cmd/internal/pkgsite-cli/client/client.go
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// Package client provides a client for the pkg.go.dev v1beta API. package client //go:generate go test -run=TestTypesUpToDate -update @@ -166,6 +167,7 @@ GOARCH string } +// GetPackage fetches package information for the given path and version. func (c *Client) GetPackage(ctx context.Context, path, version string, opts PackageOptions) (*Package, error) { q := make(url.Values) if version != "" { @@ -216,6 +218,7 @@ PaginationOptions } +// GetSymbols fetches symbols for the given package path and version. func (c *Client) GetSymbols(ctx context.Context, path, version string, opts SymbolsOptions) (*PaginatedResponse[Symbol], error) { q := make(url.Values) if version != "" { @@ -251,6 +254,7 @@ PaginationOptions } +// GetImportedBy fetches packages that import the given package path and version. func (c *Client) GetImportedBy(ctx context.Context, path, version string, opts ImportedByOptions) (*PackageImportedBy, error) { q := make(url.Values) if version != "" { @@ -280,6 +284,7 @@ Licenses bool } +// GetModule fetches module information for the given path and version. func (c *Client) GetModule(ctx context.Context, path, version string, opts ModuleOptions) (*Module, error) { q := make(url.Values) if version != "" { @@ -305,6 +310,7 @@ Version string `json:"version"` } +// GetVersions fetches a list of versions for the given module path. func (c *Client) GetVersions(ctx context.Context, path string, opts PaginationOptions) (*PaginatedResponse[VersionResponse], error) { q := make(url.Values) if opts.Limit > 0 { @@ -322,6 +328,7 @@ return &resp, nil } +// GetVulns fetches a list of vulnerabilities for the given module path and version. func (c *Client) GetVulns(ctx context.Context, path, version string, opts PaginationOptions) (*PaginatedResponse[Vulnerability], error) { q := make(url.Values) if version != "" { @@ -348,6 +355,7 @@ Synopsis string `json:"synopsis"` } +// GetPackages fetches a list of packages for the given module path and version. func (c *Client) GetPackages(ctx context.Context, modulePath, version string, opts PaginationOptions) (*PaginatedResponse[ModulePackageResponse], error) { q := make(url.Values) if version != "" { @@ -385,6 +393,7 @@ PaginationOptions } +// Search queries the pkg.go.dev API for packages matching the given query. func (c *Client) Search(ctx context.Context, query string, opts SearchOptions) (*PaginatedResponse[SearchResult], error) { q := make(url.Values) q.Set("q", query)
diff --git a/cmd/internal/pkgsite-cli/command.go b/cmd/internal/pkgsite-cli/command.go index 16160f1..94dc6d5 100644 --- a/cmd/internal/pkgsite-cli/command.go +++ b/cmd/internal/pkgsite-cli/command.go
@@ -53,12 +53,13 @@ // printUsage writes usage for all commands to w. func printUsage(w io.Writer, cmds []*command) { + fmt.Fprintf(w, "%s queries the pkg.go.dev API for information about Go packages and modules.\n\n", filepath.Base(os.Args[0])) fmt.Fprintln(w, "Usage:") for _, c := range cmds { line := c.usageLine() fmt.Fprintf(w, " %-50s %s\n", line, c.summary) } - fmt.Fprintf(w, "\nRun \"%s <command> -h\" for command-specific flags.\n", filepath.Base(os.Args[0])) + fmt.Fprintf(w, "\nRun \"%s <command> -h\" for details on available flags for each command.\n", filepath.Base(os.Args[0])) } // dispatch finds and runs the matching command. It returns the exit code.
diff --git a/cmd/internal/pkgsite-cli/main.go b/cmd/internal/pkgsite-cli/main.go index 2cbbdc7..704583b 100644 --- a/cmd/internal/pkgsite-cli/main.go +++ b/cmd/internal/pkgsite-cli/main.go
@@ -5,13 +5,13 @@ // Command pkgsite-cli queries the pkg.go.dev API for information about // Go packages and modules. // +// For more information, see https://go.dev/blog/pkgsite-api. +// // Usage: // -// pkgsite-cli package <package>[@version] [flags] package information -// pkgsite-cli module <module>[@version] [flags] module information -// pkgsite-cli search <query> [flags] search for packages -// -// See doc/pkgsite-cli.md for the full design document. +// pkgsite-cli package <package>[@version] [flags] Show package details. +// pkgsite-cli module <module>[@version] [flags] Show module details. +// pkgsite-cli search <query> [flags] Search for packages. package main import ( @@ -57,7 +57,10 @@ pkgRun := func(fs *flag.FlagSet, stdout, stderr io.Writer) int { return runPackage(fs, &pf, stdout, stderr) } - const packageDoc = ` + const packageDoc = `Queries information about a specific Go package from pkg.go.dev. +By default, this prints basic metadata. Use flags to request additional +information such as exported symbols, reverse dependencies, or rendered documentation. + When using -json, the output is a JSON object with the following structure: type packageResult struct { @@ -88,7 +91,10 @@ } ` - const moduleDoc = ` + const moduleDoc = `Queries information about a specific Go module from pkg.go.dev. +By default, this prints basic metadata. Use flags to request additional +information such as versions, vulnerabilities, or packages contained in the module. + When using -json, the output is a JSON object with the following structure: type moduleResult struct { @@ -113,7 +119,9 @@ } ` - const searchDoc = ` + const searchDoc = `Searches for Go packages on pkg.go.dev matching the given query. +By default, this prints a list of matching packages with their synopsis. + When using -json, the output is a JSON object with the following structure: type PaginatedResponse[SearchResult] struct { @@ -135,7 +143,7 @@ { name: "package", args: "<package>[@version]", - summary: "package information", + summary: "Show package details", description: strings.TrimSpace(packageDoc), flags: pkgFS, run: pkgRun, @@ -143,7 +151,7 @@ { name: "module", args: "<module>[@version]", - summary: "module information", + summary: "Show module details", description: strings.TrimSpace(moduleDoc), flags: modFS, run: func(fs *flag.FlagSet, stdout, stderr io.Writer) int { return runModule(fs, &mf, stdout, stderr) }, @@ -151,19 +159,19 @@ { name: "search", args: "<query>", - summary: "search for packages", + summary: "Search for packages", description: strings.TrimSpace(searchDoc), flags: searchFS, run: func(fs *flag.FlagSet, stdout, stderr io.Writer) int { return runSearch(fs, &sf, stdout, stderr) }, }, { name: "help", - summary: "show this help message", + summary: "Show this help message", run: func(_ *flag.FlagSet, stdout, _ io.Writer) int { printUsage(stdout, cmds); return 0 }, }, { name: "version", - summary: "print version information", + summary: "Print version information", run: func(_ *flag.FlagSet, stdout, _ io.Writer) int { fmt.Fprintln(stdout, versionInfo()); return 0 }, }, }
diff --git a/cmd/internal/pkgsite-cli/module.go b/cmd/internal/pkgsite-cli/module.go index 296b171..08aeaec 100644 --- a/cmd/internal/pkgsite-cli/module.go +++ b/cmd/internal/pkgsite-cli/module.go
@@ -7,6 +7,7 @@ import ( "context" "flag" + "fmt" "io" "golang.org/x/pkgsite/cmd/internal/pkgsite-cli/client" @@ -15,6 +16,7 @@ func runModule(fs *flag.FlagSet, m *moduleFlags, stdout, stderr io.Writer) int { if fs.NArg() != 1 { + fmt.Fprintf(stderr, "Error: expected exactly 1 module argument, got %d\n", fs.NArg()) fs.Usage() return 2 }
diff --git a/cmd/internal/pkgsite-cli/search.go b/cmd/internal/pkgsite-cli/search.go index 9e0d5d3..bf1866e 100644 --- a/cmd/internal/pkgsite-cli/search.go +++ b/cmd/internal/pkgsite-cli/search.go
@@ -7,6 +7,7 @@ import ( "context" "flag" + "fmt" "io" "strings" @@ -15,6 +16,7 @@ func runSearch(fs *flag.FlagSet, s *searchFlags, stdout, stderr io.Writer) int { if fs.NArg() < 1 { + fmt.Fprintln(stderr, "Error: expected at least 1 search query argument") fs.Usage() return 2 }
diff --git a/doc/pkgsite-cli.md b/doc/pkgsite-cli.md deleted file mode 100644 index 19c2cc3..0000000 --- a/doc/pkgsite-cli.md +++ /dev/null
@@ -1,82 +0,0 @@ -# pkgsite-cli - -A command-line interface for querying pkg.go.dev. - -Currently the API is on `v1beta`, but we expect to move to `v1` soon. - -Related to https://go.dev/issue/76718. - -## Quick start - -To install the `pkgsite-cli` tool, run: - -```bash -go install golang.org/x/pkgsite/cmd/internal/pkgsite-cli@latest -``` - -## Motivation - -The pkg.go.dev service exposes a REST API for package and module metadata. -(TODO: link to the API doc). -`pkgsite-cli` provides a lightweight CLI that queries the API and -prints results for both humans and automated tools. -There is no official SDK for the API, but this tool serves as a reference -client implementation that developers can use in other projects. - -## Relationship to existing tools - -- **`go doc`** renders documentation for packages available locally. - `pkgsite-cli` does not replace it for reading local documentation. -- **`cmd/pkgsite`** is a webserver that serves documentation for packages - available locally. It does not provide full version listings, vulnerability - reports, reverse dependencies, licenses, or search capabilities (yet). -- **`pkgsite-cli`** provides access to information `go doc` or a local instance - of `cmd/pkgsite` cannot reach: version listings, vulnerability reports, reverse - dependencies, licenses, documentation of modules/packages, and search - results for packages not yet downloaded. - -Rule of thumb: Use `go doc` for local code; use `pkgsite-cli` -for package discovery and metadata lookup. - -## Commands - -Run `pkgsite-cli <command> -h` for details on available flags for each command. - -Available commands: - * package - * module - * search - -More commands will be added. - -### Package info - -`pkgsite-cli package [flags] <package>[@version]` - -Example: -``` -$ pkgsite-cli package encoding/json -encoding/json (standard library) - Module: std - Version: go1.24.2 (latest) -``` - -### Module info -`pkgsite-cli module [flags] <module>[@version]` - -### Search -`pkgsite-cli search [flags] <query>` - -## Details -- Ambiguous path: CLI shows candidates. Use `--module` to resolve. -- Pagination: JSON returns `nextPageToken`. Use `--token` to continue. - -## Status and Implementation -- **Experimental**: This tool is currently a prototype. -- **Minimal Dependencies**: To facilitate potential migration to other repositories -(e.g. `x/tools`), the tool depends only on the Go standard library. -- **Duplicated Types**: API request/response types are duplicated in the tool's source - instead of imported from `pkgsite` for now. We ruled out releasing a full SDK - because the REST API is simple enough to consume directly. - This keeps the tool self-contained. If this tool remains in this repo, - however, we can eliminate this duplication and use the internal package.