This commit is contained in:
parent
73be4df8f8
commit
182bc09d87
11 changed files with 198 additions and 91 deletions
|
@ -12,14 +12,9 @@ import (
|
|||
|
||||
// ShowConfigCommand configures the command name, flags, and action.
|
||||
var ShowConfigCommand = cli.Command{
|
||||
Name: "config",
|
||||
Usage: "Shows global config option names and values",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "md, m",
|
||||
Usage: "render Markdown without line breaks",
|
||||
},
|
||||
},
|
||||
Name: "config",
|
||||
Usage: "Shows global config option names and values",
|
||||
Flags: report.CliFlags,
|
||||
Action: showConfigAction,
|
||||
}
|
||||
|
||||
|
@ -30,7 +25,9 @@ func showConfigAction(ctx *cli.Context) error {
|
|||
|
||||
rows, cols := conf.Report()
|
||||
|
||||
fmt.Println(report.Table(rows, cols, ctx.Bool("md")))
|
||||
result, err := report.Render(rows, cols, report.CliFormat(ctx))
|
||||
|
||||
return nil
|
||||
fmt.Println(result)
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -12,14 +12,9 @@ import (
|
|||
|
||||
// ShowFiltersCommand configures the command name, flags, and action.
|
||||
var ShowFiltersCommand = cli.Command{
|
||||
Name: "filters",
|
||||
Usage: "Displays a search filter overview with examples",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "md, m",
|
||||
Usage: "render Markdown without line breaks",
|
||||
},
|
||||
},
|
||||
Name: "filters",
|
||||
Usage: "Displays a search filter overview with examples",
|
||||
Flags: report.CliFlags,
|
||||
Action: showFiltersAction,
|
||||
}
|
||||
|
||||
|
@ -35,7 +30,9 @@ func showFiltersAction(ctx *cli.Context) error {
|
|||
}
|
||||
})
|
||||
|
||||
fmt.Println(report.Table(rows, cols, ctx.Bool("md")))
|
||||
result, err := report.Render(rows, cols, report.CliFormat(ctx))
|
||||
|
||||
return nil
|
||||
fmt.Println(result)
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,23 +15,20 @@ var ShowFormatsCommand = cli.Command{
|
|||
Name: "formats",
|
||||
Aliases: []string{"filetypes"},
|
||||
Usage: "Lists supported media and sidecar file formats",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "short, s",
|
||||
Usage: "hide format descriptions",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "md, m",
|
||||
Usage: "render Markdown without line breaks",
|
||||
},
|
||||
},
|
||||
Flags: append(report.CliFlags, cli.BoolFlag{
|
||||
Name: "short, s",
|
||||
Usage: "hide links to documentation",
|
||||
}),
|
||||
Action: showFormatsAction,
|
||||
}
|
||||
|
||||
// showFormatsAction lists supported media and sidecar file formats.
|
||||
func showFormatsAction(ctx *cli.Context) error {
|
||||
rows, cols := media.Report(fs.Extensions.Types(true), !ctx.Bool("short"), true, true)
|
||||
fmt.Println(report.Table(rows, cols, ctx.Bool("md")))
|
||||
|
||||
return nil
|
||||
result, err := report.Render(rows, cols, report.CliFormat(ctx))
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -4,10 +4,9 @@ import (
|
|||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/meta"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/meta"
|
||||
"github.com/photoprism/photoprism/pkg/report"
|
||||
)
|
||||
|
||||
|
@ -16,16 +15,10 @@ var ShowTagsCommand = cli.Command{
|
|||
Name: "tags",
|
||||
Aliases: []string{"metadata"},
|
||||
Usage: "Shows an overview of the supported metadata tags",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "short, s",
|
||||
Usage: "hide links to documentation",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "md, m",
|
||||
Usage: "render Markdown without line breaks",
|
||||
},
|
||||
},
|
||||
Flags: append(report.CliFlags, cli.BoolFlag{
|
||||
Name: "short, s",
|
||||
Usage: "hide links to documentation",
|
||||
}),
|
||||
Action: showTagsAction,
|
||||
}
|
||||
|
||||
|
@ -42,14 +35,21 @@ func showTagsAction(ctx *cli.Context) error {
|
|||
}
|
||||
})
|
||||
|
||||
// Show table with the supported metadata tags.
|
||||
fmt.Println(report.Table(rows, cols, ctx.Bool("md")))
|
||||
// Output overview of supported metadata tags.
|
||||
format := report.CliFormat(ctx)
|
||||
result, err := report.Render(rows, cols, format)
|
||||
|
||||
// Show documentation links for those who want to delve deeper.
|
||||
if !ctx.Bool("short") {
|
||||
fmt.Printf("## Metadata Tags by Namespace ##\n\n")
|
||||
fmt.Println(report.Table(meta.Docs, []string{"Namespace", "Documentation"}, ctx.Bool("md")))
|
||||
fmt.Println(result)
|
||||
|
||||
if err != nil || ctx.Bool("short") || format == report.TSV {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
// Documentation links for those who want to delve deeper.
|
||||
result, err = report.Render(meta.Docs, []string{"Namespace", "Documentation"}, format)
|
||||
|
||||
fmt.Printf("## Metadata Tags by Namespace ##\n\n")
|
||||
fmt.Println(result)
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
31
pkg/report/cli.go
Normal file
31
pkg/report/cli.go
Normal file
|
@ -0,0 +1,31 @@
|
|||
package report
|
||||
|
||||
import "github.com/urfave/cli"
|
||||
|
||||
func CliFormat(ctx *cli.Context) Format {
|
||||
switch {
|
||||
case ctx.Bool("md"), ctx.Bool("markdown"):
|
||||
return Markdown
|
||||
case ctx.Bool("tsv"):
|
||||
return TSV
|
||||
case ctx.Bool("csv"):
|
||||
return CSV
|
||||
default:
|
||||
return Default
|
||||
}
|
||||
}
|
||||
|
||||
var CliFlags = []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "md, m",
|
||||
Usage: "format as machine-readable Markdown",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "csv, c",
|
||||
Usage: "export as semicolon separated values",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "tsv, t",
|
||||
Usage: "export as tab separated values",
|
||||
},
|
||||
}
|
26
pkg/report/csv.go
Normal file
26
pkg/report/csv.go
Normal file
|
@ -0,0 +1,26 @@
|
|||
package report
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/csv"
|
||||
)
|
||||
|
||||
// CsvExport returns the report as character separated values.
|
||||
func CsvExport(rows [][]string, cols []string, sep rune) (string, error) {
|
||||
buf := &bytes.Buffer{}
|
||||
writer := csv.NewWriter(buf)
|
||||
|
||||
if sep > 0 {
|
||||
writer.Comma = sep
|
||||
}
|
||||
|
||||
err := writer.Write(cols)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = writer.WriteAll(rows)
|
||||
|
||||
return buf.String(), nil
|
||||
}
|
10
pkg/report/format.go
Normal file
10
pkg/report/format.go
Normal file
|
@ -0,0 +1,10 @@
|
|||
package report
|
||||
|
||||
type Format string
|
||||
|
||||
const (
|
||||
Default = ""
|
||||
Markdown = "markdown"
|
||||
TSV = "tsv"
|
||||
CSV = "csv"
|
||||
)
|
|
@ -7,17 +7,11 @@ import (
|
|||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
// Table returns a text-formatted table, optionally as valid Markdown,
|
||||
// MarkdownTable returns a text-formatted table with caption, optionally as valid Markdown,
|
||||
// so the output can be pasted into the docs.
|
||||
func Table(rows [][]string, cols []string, markDown bool) string {
|
||||
return TableWithCaption(rows, cols, "", markDown)
|
||||
}
|
||||
|
||||
// TableWithCaption returns a text-formatted table with caption, optionally as valid Markdown,
|
||||
// so the output can be pasted into the docs.
|
||||
func TableWithCaption(rows [][]string, cols []string, caption string, markDown bool) string {
|
||||
func MarkdownTable(rows [][]string, cols []string, caption string, valid bool) string {
|
||||
// Escape Markdown.
|
||||
if markDown {
|
||||
if valid {
|
||||
for i := range rows {
|
||||
for j := range rows[i] {
|
||||
if strings.ContainsRune(rows[i][j], '|') {
|
||||
|
@ -33,8 +27,8 @@ func TableWithCaption(rows [][]string, cols []string, caption string, markDown b
|
|||
borders := tablewriter.Border{
|
||||
Left: true,
|
||||
Right: true,
|
||||
Top: !markDown,
|
||||
Bottom: !markDown,
|
||||
Top: !valid,
|
||||
Bottom: !valid,
|
||||
}
|
||||
|
||||
// Render.
|
||||
|
@ -45,7 +39,7 @@ func TableWithCaption(rows [][]string, cols []string, caption string, markDown b
|
|||
table.SetCaption(true, caption)
|
||||
}
|
||||
|
||||
table.SetAutoWrapText(!markDown)
|
||||
table.SetAutoWrapText(!valid)
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table.SetHeader(cols)
|
||||
table.SetBorders(borders)
|
24
pkg/report/render.go
Normal file
24
pkg/report/render.go
Normal file
|
@ -0,0 +1,24 @@
|
|||
package report
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/photoprism/photoprism/pkg/clean"
|
||||
)
|
||||
|
||||
// Render returns a text-formatted table, optionally as valid Markdown,
|
||||
// so the output can be pasted into the docs.
|
||||
func Render(rows [][]string, cols []string, format Format) (string, error) {
|
||||
switch format {
|
||||
case CSV:
|
||||
return CsvExport(rows, cols, ';')
|
||||
case TSV:
|
||||
return CsvExport(rows, cols, '\t')
|
||||
case Markdown:
|
||||
return MarkdownTable(rows, cols, "", true), nil
|
||||
case Default:
|
||||
return MarkdownTable(rows, cols, "", false), nil
|
||||
default:
|
||||
return "", fmt.Errorf("invalid format %s", clean.Log(string(format)))
|
||||
}
|
||||
}
|
59
pkg/report/render_test.go
Normal file
59
pkg/report/render_test.go
Normal file
|
@ -0,0 +1,59 @@
|
|||
package report
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTable(t *testing.T) {
|
||||
cols := []string{"Col1", "Col2"}
|
||||
rows := [][]string{
|
||||
{"foo", "bar" + strings.Repeat(", abc", 30)},
|
||||
{"bar", "b & a | z"}}
|
||||
|
||||
t.Run("DefaultTable", func(t *testing.T) {
|
||||
result, err := Render(rows, cols, Default)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Contains(t, result, "| bar | b & a | z |")
|
||||
})
|
||||
t.Run("MarkdownTable", func(t *testing.T) {
|
||||
result, err := Render(rows, cols, Markdown)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// fmt.Println(result)
|
||||
assert.Contains(t, result, "| bar | b & a \\| z")
|
||||
})
|
||||
t.Run("CsvExport", func(t *testing.T) {
|
||||
result, err := Render(rows, cols, CSV)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := "Col1;Col2\nfoo;bar, abc, abc, abc, abc, abc, abc," +
|
||||
" abc, abc, abc, abc, abc, abc, abc, abc, abc," +
|
||||
" abc, abc, abc, abc, abc, abc, abc, abc, abc," +
|
||||
" abc, abc, abc, abc, abc, abc\nbar;b & a \\| z\n"
|
||||
|
||||
assert.Equal(t, expected, result)
|
||||
})
|
||||
t.Run("TsvExport", func(t *testing.T) {
|
||||
result, err := Render(rows, cols, TSV)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Contains(t, result, "Col1\tCol2\nfoo\tbar, abc, abc")
|
||||
})
|
||||
t.Run("Invalid", func(t *testing.T) {
|
||||
_, err := Render(rows, cols, Format("invalid"))
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("error expected")
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package report
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTable(t *testing.T) {
|
||||
t.Run("Standard", func(t *testing.T) {
|
||||
cols := []string{"Col1", "Col2"}
|
||||
rows := [][]string{
|
||||
{"foo", "bar" + strings.Repeat(", abc", 30)},
|
||||
{"bar", "b & a | z"}}
|
||||
result := Table(rows, cols, false)
|
||||
assert.Contains(t, result, "| bar | b & a | z |")
|
||||
})
|
||||
t.Run("Markdown", func(t *testing.T) {
|
||||
cols := []string{"Col1", "Col2"}
|
||||
rows := [][]string{
|
||||
{"foo", "bar" + strings.Repeat(", abc", 30)},
|
||||
{"bar", "b & a | z"}}
|
||||
result := Table(rows, cols, true)
|
||||
// fmt.Println(result)
|
||||
assert.Contains(t, result, "| bar | b & a \\| z")
|
||||
})
|
||||
}
|
Loading…
Reference in a new issue