github.com/lineaje-labs/syft@v0.98.1-0.20231227153149-9e393f60ff1b/syft/format/table/encoder.go (about) 1 package table 2 3 import ( 4 "fmt" 5 "io" 6 "sort" 7 "strings" 8 9 "github.com/olekukonko/tablewriter" 10 11 "github.com/anchore/syft/syft/sbom" 12 ) 13 14 const ID sbom.FormatID = "syft-table" 15 16 type encoder struct { 17 } 18 19 func NewFormatEncoder() sbom.FormatEncoder { 20 return encoder{} 21 } 22 23 func (e encoder) ID() sbom.FormatID { 24 return ID 25 } 26 27 func (e encoder) Aliases() []string { 28 return []string{ 29 "table", 30 } 31 } 32 33 func (e encoder) Version() string { 34 return sbom.AnyVersion 35 } 36 37 func (e encoder) Encode(writer io.Writer, s sbom.SBOM) error { 38 var rows [][]string 39 40 columns := []string{"Name", "Version", "Type"} 41 for _, p := range s.Artifacts.Packages.Sorted() { 42 row := []string{ 43 p.Name, 44 p.Version, 45 string(p.Type), 46 } 47 rows = append(rows, row) 48 } 49 50 if len(rows) == 0 { 51 _, err := fmt.Fprintln(writer, "No packages discovered") 52 return err 53 } 54 55 // sort by name, version, then type 56 sort.SliceStable(rows, func(i, j int) bool { 57 for col := 0; col < len(columns); col++ { 58 if rows[i][col] != rows[j][col] { 59 return rows[i][col] < rows[j][col] 60 } 61 } 62 return false 63 }) 64 rows = removeDuplicateRows(rows) 65 66 table := tablewriter.NewWriter(writer) 67 68 table.SetHeader(columns) 69 table.SetHeaderLine(false) 70 table.SetBorder(false) 71 table.SetAutoWrapText(false) 72 table.SetAutoFormatHeaders(true) 73 table.SetHeaderAlignment(tablewriter.ALIGN_LEFT) 74 table.SetAlignment(tablewriter.ALIGN_LEFT) 75 table.SetCenterSeparator("") 76 table.SetColumnSeparator("") 77 table.SetRowSeparator("") 78 table.SetTablePadding(" ") 79 table.SetNoWhiteSpace(true) 80 81 table.AppendBulk(rows) 82 table.Render() 83 84 return nil 85 } 86 87 func removeDuplicateRows(items [][]string) [][]string { 88 seen := map[string][]string{} 89 var result [][]string 90 91 for _, v := range items { 92 key := strings.Join(v, "|") 93 if seen[key] != nil { 94 // dup! 95 continue 96 } 97 98 seen[key] = v 99 result = append(result, v) 100 } 101 return result 102 }