From 234fb37b82e61c7f89ee98295313a4aff5e227a2 Mon Sep 17 00:00:00 2001 From: Simon Vieille Date: Mon, 22 Jul 2024 13:32:47 +0200 Subject: [PATCH] add output format option --- README.md | 9 ++++++++ app.go | 32 ++++++++++++++++++++++++-- checker/struct.go | 8 +++---- render/render.go | 57 ++++++++++++++++++++++++++++++++++------------- 4 files changed, 84 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 0238243..7b81882 100644 --- a/README.md +++ b/README.md @@ -25,3 +25,12 @@ $ expiration-check certificates -d example.com -d other-example.com -d mail.exam | mail.example.com | XXX | YYYY-MM-DD HH:MM:SS | +-------------------+------+---------------------+ ``` + +You can specify an ouput format using `--format` or `-f`: + +- `table` (default) +- `json` +- `csv` +- `tsv` +- `html` +- `markdown` diff --git a/app.go b/app.go index bfa9e7f..e6896d6 100644 --- a/app.go +++ b/app.go @@ -6,12 +6,32 @@ import ( "gitnet.fr/deblan/expiration-check/render" ) +func NormalizeFormat(format string) string { + formats := []string{"json", "table", "csv", "tsv", "html", "markdown"} + + for _, f := range formats { + if f == format { + return f + } + } + + return "table" +} + func App() *cli.App { flags := []cli.Flag{ &cli.StringSliceFlag{ Name: "domain", Aliases: []string{"d"}, Required: true, + Usage: "list of domains", + }, + &cli.StringFlag{ + Name: "format", + Aliases: []string{"f"}, + Required: false, + Value: "table", + Usage: "output format: table, csv, tsv, html, json, markdown", }, } @@ -23,7 +43,11 @@ func App() *cli.App { Usage: "Checks certificate", Flags: flags, Action: func(c *cli.Context) error { - render.Render(checker.CheckCertificates(c.StringSlice("domain")), 30, 14) + render.Render( + checker.CheckCertificates(c.StringSlice("domain")), + 30, 14, + NormalizeFormat(c.String("format")), + ) return nil }, @@ -34,7 +58,11 @@ func App() *cli.App { Aliases: []string{"d", "domains"}, Flags: flags, Action: func(c *cli.Context) error { - render.Render(checker.CheckDomains(c.StringSlice("domain")), 30, 14) + render.Render( + checker.CheckDomains(c.StringSlice("domain")), + 30, 14, + NormalizeFormat(c.String("format")), + ) return nil }, diff --git a/checker/struct.go b/checker/struct.go index 645dc88..ffdcfde 100644 --- a/checker/struct.go +++ b/checker/struct.go @@ -1,8 +1,8 @@ package checker type Domain struct { - Name string - DaysLeft float64 - Date string - Failed bool + Name string `json:"name"` + DaysLeft float64 `json:"days"` + Date string `json:"date"` + Failed bool `json:"failed"` } diff --git a/render/render.go b/render/render.go index 868ded3..d3cd037 100644 --- a/render/render.go +++ b/render/render.go @@ -1,6 +1,8 @@ package render import ( + "encoding/json" + "fmt" "os" "sort" @@ -9,7 +11,15 @@ import ( "gitnet.fr/deblan/expiration-check/checker" ) -func Render(values []checker.Domain, warning, danger float64) { +func RenderColor(value string, c text.Colors, format string) string { + if format != "table" { + return value + } + + return c.Sprint(value) +} + +func Render(values []checker.Domain, warning, danger float64, format string) { sort.SliceStable(values, func(i, j int) bool { if values[i].Failed && values[j].Failed { return values[i].Name < values[j].Name @@ -26,12 +36,19 @@ func Render(values []checker.Domain, warning, danger float64) { return values[i].DaysLeft < values[j].DaysLeft }) + if format == "json" { + data, _ := json.Marshal(&values) + os.Stdout.Write(data) + + return + } + t := table.NewWriter() t.SetOutputMirror(os.Stdout) t.AppendHeader(table.Row{ - text.Colors{0, text.FgCyan}.Sprint("Domain"), - text.Colors{0, text.FgCyan}.Sprint("Days"), - text.Colors{0, text.FgCyan}.Sprint("Date"), + RenderColor("Domain", text.Colors{0, text.FgCyan}, format), + RenderColor("Days", text.Colors{0, text.FgCyan}, format), + RenderColor("Date", text.Colors{0, text.FgCyan}, format), }) t.SetColumnConfigs([]table.ColumnConfig{ {Number: 2, Align: text.AlignRight}, @@ -39,25 +56,23 @@ func Render(values []checker.Domain, warning, danger float64) { }) for _, value := range values { + failed := RenderColor("FAIL", text.Colors{0, text.FgRed}, format) + if value.Failed { - t.AppendRow(table.Row{ - value.Name, - text.Colors{0, text.FgRed}.Sprint("FAIL"), - text.Colors{0, text.FgRed}.Sprint("FAIL"), - }, table.RowConfig{}) + t.AppendRow(table.Row{value.Name, failed, failed}, table.RowConfig{}) } else { var days string var date string if value.DaysLeft <= danger { - days = text.Colors{0, text.FgRed}.Sprint("FAIL") - date = text.Colors{0, text.FgRed}.Sprint("FAIL") + days = failed + date = failed } else if value.DaysLeft <= warning { - days = text.Colors{0, text.FgYellow}.Sprint(value.DaysLeft) - date = text.Colors{0, text.FgYellow}.Sprint(value.Date) + days = RenderColor(fmt.Sprintf("%.0f", value.DaysLeft), text.Colors{0, text.FgYellow}, format) + date = RenderColor(value.Date, text.Colors{0, text.FgYellow}, format) } else { - days = text.Colors{0, text.FgGreen}.Sprint(value.DaysLeft) - date = text.Colors{0, text.FgGreen}.Sprint(value.Date) + days = RenderColor(fmt.Sprintf("%.0f", value.DaysLeft), text.Colors{0, text.FgGreen}, format) + date = RenderColor(value.Date, text.Colors{0, text.FgGreen}, format) } t.AppendRow(table.Row{ @@ -68,5 +83,15 @@ func Render(values []checker.Domain, warning, danger float64) { } } - t.Render() + if format == "table" { + t.Render() + } else if format == "csv" { + t.RenderCSV() + } else if format == "html" { + t.RenderHTML() + } else if format == "tsv" { + t.RenderTSV() + } else if format == "markdown" { + t.RenderMarkdown() + } }