| // Copyright 2023 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. | |
| // Command modinfo displays module info from the pkgsite database. | |
| // | |
| // One-time setup: install the cloud sql proxy: | |
| // | |
| // > curl -o cloud-sql-proxy https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/v2.6.0/cloud-sql-proxy.linux.amd64 | |
| // > chmod +x cloud-sql-proxy | |
| // > ./cloud-sql-proxy $MODINFO_DB?port=5429 & | |
| // | |
| // cloud-sql-proxy must be running in the background to run this command. | |
| // If it stops, restart it by running the last command above. | |
| // | |
| // You will also need to do | |
| // | |
| // > gcloud auth application-default login | |
| // | |
| // if you haven't already. | |
| package main | |
| import ( | |
| "context" | |
| "fmt" | |
| "log" | |
| "os" | |
| "sort" | |
| "strings" | |
| "text/tabwriter" | |
| "golang.org/x/exp/maps" | |
| "golang.org/x/vulndb/cmd/modinfo/internal/pkgsitedb" | |
| ) | |
| func main() { | |
| args := os.Args[1:] | |
| if len(args) == 0 { | |
| log.Fatal("missing module paths") | |
| } | |
| var cfg pkgsitedb.Config | |
| cfg.User = mustEnv("MODINFO_USER") | |
| cfg.Password = mustEnv("MODINFO_PASSWORD") | |
| cfg.Host = "127.0.0.1" | |
| cfg.Port = "5429" | |
| cfg.DBName = mustEnv("MODINFO_DBNAME") | |
| ctx := context.Background() | |
| db, err := pkgsitedb.Open(ctx, cfg) | |
| if err != nil { | |
| fmt.Fprintf(os.Stderr, `Could not open DB. You may need to run | |
| cloud-sql-proxy $MODINFO_DB?port=5429 & | |
| Details: %v`, err) | |
| fmt.Fprintln(os.Stderr) | |
| os.Exit(1) | |
| } | |
| defer db.Close() | |
| for _, modpath := range args { | |
| mod, err := pkgsitedb.QueryModule(ctx, db, modpath) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| display(mod) | |
| } | |
| } | |
| func mustEnv(ev string) string { | |
| if r := os.Getenv(ev); r != "" { | |
| return r | |
| } | |
| fmt.Fprintf(os.Stderr, "need value for environment variable %s\n", ev) | |
| os.Exit(1) | |
| return "" | |
| } | |
| func display(m *pkgsitedb.Module) { | |
| if len(m.Packages) == 0 { | |
| fmt.Printf("No packages for module %s; maybe it doesn't exist?\n", m.Path) | |
| return | |
| } | |
| versionMap := map[string]bool{} | |
| for _, p := range m.Packages { | |
| versionMap[p.Version] = true | |
| } | |
| versions := maps.Keys(versionMap) | |
| sort.Strings(versions) | |
| fmt.Printf("==== %s @ %s ====\n", m.Path, strings.Join(versions, ", ")) | |
| tw := tabwriter.NewWriter(os.Stdout, 2, 4, 1, ' ', 0) | |
| fmt.Fprintf(tw, "%s\t%s\n", "Import Path", "Importers") | |
| for _, p := range m.Packages { | |
| fmt.Fprintf(tw, "%s\t%5d\n", p.Path, p.NumImporters) | |
| } | |
| tw.Flush() | |
| } |