github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/pkg/task/display.go (about) 1 package task 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "log" 7 "os" 8 "strings" 9 10 "github.com/spf13/cobra" 11 "github.com/turbot/go-kit/files" 12 "github.com/turbot/steampipe/pkg/error_helpers" 13 "github.com/turbot/steampipe/pkg/filepaths" 14 "github.com/turbot/steampipe/pkg/plugin" 15 "github.com/turbot/steampipe/pkg/utils" 16 ) 17 18 const ( 19 AvailableVersionsCacheStructVersion = 20230117 20 ) 21 22 func (r *Runner) saveAvailableVersions(cli *CLIVersionCheckResponse, plugin map[string]plugin.VersionCheckReport) error { 23 utils.LogTime("Runner.saveAvailableVersions start") 24 defer utils.LogTime("Runner.saveAvailableVersions end") 25 26 if cli == nil && len(plugin) == 0 { 27 // nothing to save 28 return nil 29 } 30 31 notifs := &AvailableVersionCache{ 32 StructVersion: AvailableVersionsCacheStructVersion, 33 CliCache: cli, 34 PluginCache: plugin, 35 } 36 // create the file - if it exists, it will be truncated by os.Create 37 f, err := os.Create(filepaths.AvailableVersionsFilePath()) 38 if err != nil { 39 return err 40 } 41 defer f.Close() 42 encoder := json.NewEncoder(f) 43 return encoder.Encode(notifs) 44 } 45 46 func (r *Runner) hasAvailableVersion() bool { 47 utils.LogTime("Runner.hasNotifications start") 48 defer utils.LogTime("Runner.hasNotifications end") 49 return files.FileExists(filepaths.AvailableVersionsFilePath()) 50 } 51 52 func (r *Runner) loadCachedVersions() (*AvailableVersionCache, error) { 53 utils.LogTime("Runner.getNotifications start") 54 defer utils.LogTime("Runner.getNotifications end") 55 f, err := os.Open(filepaths.AvailableVersionsFilePath()) 56 if err != nil { 57 return nil, err 58 } 59 notifications := &AvailableVersionCache{} 60 decoder := json.NewDecoder(f) 61 if err := decoder.Decode(notifications); err != nil { 62 return nil, err 63 } 64 if err := error_helpers.CombineErrors(f.Close(), os.Remove(filepaths.AvailableVersionsFilePath())); err != nil { 65 // if Go couldn't close the file handle, no matter - this was just good practise 66 // if Go couldn't remove the notification file, it'll get truncated next time we try to write to it 67 // worst case is that the notification gets shown more than once 68 log.Println("[TRACE] could not close/delete notification file", err) 69 } 70 return notifications, nil 71 } 72 73 // displayNotifications checks if there are any pending notifications to display 74 // and if so, displays them 75 // does nothing if the given command is a command where notifications are not displayed 76 func (r *Runner) displayNotifications(cmd *cobra.Command, cmdArgs []string) error { 77 utils.LogTime("Runner.displayNotifications start") 78 defer utils.LogTime("Runner.displayNotifications end") 79 80 ctx := cmd.Context() 81 82 if !showNotificationsForCommand(cmd, cmdArgs) { 83 // do not do anything - just return 84 return nil 85 } 86 87 if !r.hasAvailableVersion() { 88 // nothing to display 89 return nil 90 } 91 92 cachedVersions, err := r.loadCachedVersions() 93 if err != nil { 94 return err 95 } 96 97 tableBuffer, err := cachedVersions.asTable(ctx) 98 if err != nil { 99 return err 100 } 101 // get the buffer width (to set the column width of ppTable) 102 lineLength := len(strings.Split(tableBuffer.String(), "\n")[0]) 103 104 ppTable, err := ppNoptificationAsTable(lineLength) 105 if err != nil { 106 return err 107 } 108 109 // table can be nil if there are no notifications to display 110 if tableBuffer != nil { 111 fmt.Println() //nolint:forbidigo // acceptable 112 fmt.Println(tableBuffer) //nolint:forbidigo // acceptable 113 } 114 115 if ppTable != nil { 116 ppTable.Render() 117 fmt.Println() //nolint:forbidigo // acceptable 118 } 119 120 return nil 121 }