grype/cmd/db_diff.go

151 lines
3.3 KiB
Go

package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/wagoodman/go-partybus"
"github.com/anchore/grype/grype/db"
"github.com/anchore/grype/grype/differ"
"github.com/anchore/grype/grype/event"
"github.com/anchore/grype/internal/bus"
"github.com/anchore/grype/internal/log"
"github.com/anchore/grype/internal/ui"
"github.com/anchore/stereoscope"
)
var dbDiffOutputFormat string
const deleteFlag string = "delete"
var dbDiffCmd = &cobra.Command{
Use: "diff [flags] base_db_url target_db_url",
Short: "diff two DBs and display the result",
Args: cobra.MaximumNArgs(2),
RunE: runDBDiffCmd,
}
func init() {
dbDiffCmd.Flags().StringVarP(&dbDiffOutputFormat, "output", "o", "table", "format to display results (available=[table, json])")
dbDiffCmd.Flags().BoolP(deleteFlag, "d", false, "delete downloaded databases after diff occurs")
dbCmd.AddCommand(dbDiffCmd)
}
func startDBDiffCmd(base string, target string, deleteDatabases bool) <-chan error {
errs := make(chan error)
go func() {
defer close(errs)
d, err := differ.NewDiffer(appConfig.DB.ToCuratorConfig())
if err != nil {
errs <- err
return
}
if err := d.SetBaseDB(base); err != nil {
errs <- err
return
}
if err := d.SetTargetDB(target); err != nil {
errs <- err
return
}
diff, err := d.DiffDatabases()
if err != nil {
errs <- err
return
}
if len(*diff) == 0 {
fmt.Println("Databases are identical!")
} else {
err := d.Present(dbDiffOutputFormat, diff, os.Stdout)
if err != nil {
errs <- err
}
}
if deleteDatabases {
errs <- d.DeleteDatabases()
}
bus.Publish(partybus.Event{
Type: event.NonRootCommandFinished,
Value: "",
})
}()
return errs
}
func runDBDiffCmd(cmd *cobra.Command, args []string) error {
reporter, closer, err := reportWriter()
defer func() {
if err := closer(); err != nil {
log.Warnf("unable to write to report destination: %+v", err)
}
}()
if err != nil {
return err
}
deleteDatabases, err := cmd.Flags().GetBool(deleteFlag)
if err != nil {
return err
}
var base, target string
switch len(args) {
case 0:
log.Info("base_db_url and target_db_url not provided; fetching most recent")
base, target, err = getDefaultURLs()
if err != nil {
return err
}
case 1:
log.Info("target_db_url not provided; fetching most recent")
base = args[0]
_, target, err = getDefaultURLs()
if err != nil {
return err
}
default:
base = args[0]
target = args[1]
}
return eventLoop(
startDBDiffCmd(base, target, deleteDatabases),
setupSignals(),
eventSubscription,
stereoscope.Cleanup,
ui.Select(isVerbose(), appConfig.Quiet, reporter)...,
)
}
func getDefaultURLs() (baseURL string, targetURL string, err error) {
dbCurator, err := db.NewCurator(appConfig.DB.ToCuratorConfig())
if err != nil {
return "", "", err
}
listing, err := dbCurator.ListingFromURL()
if err != nil {
return "", "", err
}
supportedSchema := dbCurator.SupportedSchema()
available, exists := listing.Available[supportedSchema]
if len(available) < 2 || !exists {
return "", "", stderrPrintLnf("Not enough databases available for the current schema to diff (%d)", supportedSchema)
}
targetURL = available[0].URL.String()
baseURL = available[1].URL.String()
return baseURL, targetURL, nil
}