diff --git a/cmd/krew/cmd/update.go b/cmd/krew/cmd/update.go index 4d5fff2f..506c9ac2 100644 --- a/cmd/krew/cmd/update.go +++ b/cmd/krew/cmd/update.go @@ -15,15 +15,21 @@ package cmd import ( + "bytes" "fmt" + "io" "os" + "strings" "github.com/pkg/errors" "github.com/spf13/cobra" "k8s.io/klog" "sigs.k8s.io/krew/internal/gitutil" + "sigs.k8s.io/krew/internal/index/indexscanner" + "sigs.k8s.io/krew/internal/installation" "sigs.k8s.io/krew/pkg/constants" + "sigs.k8s.io/krew/pkg/index" ) // updateCmd represents the update command @@ -41,12 +47,94 @@ Remarks: RunE: ensureIndexUpdated, } +func showFormattedPluginsInfo(out io.Writer, header string, plugins []string) { + var b bytes.Buffer + b.WriteString(fmt.Sprintf(" %s: ", header)) + + chunkSize := 5 + var s []string + for i := 0; i < len(plugins); i += chunkSize { + end := i + chunkSize + if end > len(plugins) { + end = len(plugins) + } + s = append(s, strings.Join(plugins[i:end], ", ")) + } + + b.WriteString(strings.Join(s, "\n\t")) + fmt.Fprintln(out, b.String()) +} + +func showUpdatedPlugins(out io.Writer, preUpdate, posUpdate []index.Plugin, installedPlugins map[string]string) { + var newPlugins []index.Plugin + var updatedPlugins []index.Plugin + + oldIndex := make(map[string]index.Plugin) + for _, p := range preUpdate { + oldIndex[p.Name] = p + } + + for _, p := range posUpdate { + old, ok := oldIndex[p.Name] + if !ok { + newPlugins = append(newPlugins, p) + continue + } + + if _, ok := installedPlugins[p.Name]; !ok { + continue + } + + if old.Spec.Version != p.Spec.Version { + updatedPlugins = append(updatedPlugins, p) + } + } + + if len(newPlugins) > 0 { + var s []string + for _, p := range newPlugins { + s = append(s, fmt.Sprintf("%s %s", p.Name, p.Spec.Version)) + } + + showFormattedPluginsInfo(out, "New plugins available", s) + } + + if len(updatedPlugins) > 0 { + var s []string + for _, p := range updatedPlugins { + old := oldIndex[p.Name] + s = append(s, fmt.Sprintf("%s %s -> %s", p.Name, old.Spec.Version, p.Spec.Version)) + } + + showFormattedPluginsInfo(out, "Upgrades available", s) + } +} + func ensureIndexUpdated(_ *cobra.Command, _ []string) error { + preUpdateIndex, _ := indexscanner.LoadPluginListFromFS(paths.IndexPluginsPath()) + klog.V(1).Infof("Updating the local copy of plugin index (%s)", paths.IndexPath()) if err := gitutil.EnsureUpdated(constants.IndexURI, paths.IndexPath()); err != nil { return errors.Wrap(err, "failed to update the local index") } fmt.Fprintln(os.Stderr, "Updated the local copy of plugin index.") + + if len(preUpdateIndex) == 0 { + return nil + } + + posUpdateIndex, err := indexscanner.LoadPluginListFromFS(paths.IndexPluginsPath()) + if err != nil { + return errors.Wrap(err, "failed to load plugin index after update") + } + + installedPlugins, err := installation.ListInstalledPlugins(paths.InstallReceiptsPath()) + if err != nil { + return errors.Wrap(err, "failed to load installed plugins list after update") + } + + showUpdatedPlugins(os.Stderr, preUpdateIndex, posUpdateIndex, installedPlugins) + return nil }