From 975510c86ac911ac4c11ded03c74cc4b63dbbbf8 Mon Sep 17 00:00:00 2001 From: Thomas von Dein Date: Fri, 21 Oct 2022 10:21:07 +0200 Subject: [PATCH] using enum modeflags, use my own usage template, generated from manpage so I don't have to maintain it twice, it's also nicer --- Makefile | 4 +++ cfg/config.go | 67 ++++++++++++++++++++------------------------- cfg/config_test.go | 46 +++++++++---------------------- cmd/root.go | 21 +++++--------- cmd/tablizer.go | 57 +++++++++++++++++++++++++++++++++----- lib/printer.go | 13 +++++---- lib/printer_test.go | 16 +++++------ tablizer.1 | 24 ++++++++++------ tablizer.pod | 22 ++++++++++----- 9 files changed, 149 insertions(+), 121 deletions(-) diff --git a/Makefile b/Makefile index 879de3b..3756e48 100644 --- a/Makefile +++ b/Makefile @@ -41,6 +41,10 @@ cmd/%.go: %.pod pod2text $*.pod >> cmd/$*.go echo "\`" >> cmd/$*.go + echo "var usage = \`" >> cmd/$*.go + awk '/SYNOPS/{f=1;next} /DESCR/{f=0} f' $*.pod | sed 's/^ //' >> cmd/$*.go + echo "\`" >> cmd/$*.go + buildlocal: go build -ldflags "-X 'github.com/tlinden/tablizer/cfg.VERSION=$(VERSION)'" diff --git a/cfg/config.go b/cfg/config.go index 5b5c5a1..7f1c829 100644 --- a/cfg/config.go +++ b/cfg/config.go @@ -17,15 +17,12 @@ along with this program. If not, see . package cfg import ( - "errors" "fmt" "github.com/gookit/color" - "regexp" ) const DefaultSeparator string = `(\s\s+|\t)` -const ValidOutputModes string = "(orgtbl|markdown|extended|ascii|yaml|shell)" -const Version string = "v1.0.11" +const Version string = "v1.0.12" var VERSION string // maintained by -x @@ -35,7 +32,7 @@ type Config struct { Columns string UseColumns []int Separator string - OutputMode string + OutputMode int InvertMatch bool Pattern string @@ -64,6 +61,16 @@ type Modeflag struct { A bool } +// used for switching printers +const ( + Extended = iota + 1 + Orgtbl + Markdown + Shell + Yaml + Ascii +) + // various sort types type Sortmode struct { Numeric bool @@ -97,39 +104,6 @@ func Getversion() string { return fmt.Sprintf("This is tablizer version %s", VERSION) } -func (conf *Config) PrepareModeFlags(flag Modeflag, mode string) error { - if len(mode) == 0 { - // associate short flags like -X with mode selector - switch { - case flag.X: - conf.OutputMode = "extended" - case flag.M: - conf.OutputMode = "markdown" - case flag.O: - conf.OutputMode = "orgtbl" - case flag.S: - conf.OutputMode = "shell" - conf.NoNumbering = true - case flag.Y: - conf.OutputMode = "yaml" - conf.NoNumbering = true - default: - conf.OutputMode = "ascii" - } - } else { - r, _ := regexp.Compile(ValidOutputModes) // hardcoded, no fail expected - match := r.MatchString(mode) - - if !match { - return errors.New("Invalid output mode!") - } - - conf.OutputMode = mode - } - - return nil -} - func (conf *Config) PrepareSortFlags(flag Sortmode) { switch { case flag.Numeric: @@ -142,3 +116,20 @@ func (conf *Config) PrepareSortFlags(flag Sortmode) { conf.SortMode = "string" } } + +func (conf *Config) PrepareModeFlags(flag Modeflag) { + switch { + case flag.X: + conf.OutputMode = Extended + case flag.O: + conf.OutputMode = Orgtbl + case flag.M: + conf.OutputMode = Markdown + case flag.S: + conf.OutputMode = Shell + case flag.Y: + conf.OutputMode = Yaml + default: + conf.OutputMode = Ascii + } +} diff --git a/cfg/config_test.go b/cfg/config_test.go index 56b2f23..150ed25 100644 --- a/cfg/config_test.go +++ b/cfg/config_test.go @@ -26,46 +26,26 @@ import ( func TestPrepareModeFlags(t *testing.T) { var tests = []struct { flag Modeflag - mode string // input, if any - expect string // output - want bool + expect int // output (constant enum) }{ // short commandline flags like -M - {Modeflag{X: true}, "", "extended", false}, - {Modeflag{S: true}, "", "shell", false}, - {Modeflag{O: true}, "", "orgtbl", false}, - {Modeflag{Y: true}, "", "yaml", false}, - {Modeflag{M: true}, "", "markdown", false}, - {Modeflag{}, "", "ascii", false}, - - // long flags like -o yaml - {Modeflag{}, "extended", "extended", false}, - {Modeflag{}, "shell", "shell", false}, - {Modeflag{}, "orgtbl", "orgtbl", false}, - {Modeflag{}, "yaml", "yaml", false}, - {Modeflag{}, "markdown", "markdown", false}, - - // failing - {Modeflag{}, "blah", "", true}, + {Modeflag{X: true}, Extended}, + {Modeflag{S: true}, Shell}, + {Modeflag{O: true}, Orgtbl}, + {Modeflag{Y: true}, Yaml}, + {Modeflag{M: true}, Markdown}, + {Modeflag{}, Ascii}, } + // FIXME: use a map for easier printing for _, tt := range tests { - testname := fmt.Sprintf("PrepareModeFlags-flags-mode-%s-expect-%s-want-%t", - tt.mode, tt.expect, tt.want) + testname := fmt.Sprintf("PrepareModeFlags-expect-%d", tt.expect) t.Run(testname, func(t *testing.T) { - c := Config{OutputMode: tt.mode} + c := Config{} - // check either flag or pre filled mode, whatever is defined in tt - err := c.PrepareModeFlags(tt.flag, tt.mode) - if err != nil { - if !tt.want { - // expect to fail - t.Fatalf("PrepareModeFlags returned unexpected error: %s", err) - } - } else { - if c.OutputMode != tt.expect { - t.Errorf("got: %s, expect: %s", c.OutputMode, tt.expect) - } + c.PrepareModeFlags(tt.flag) + if c.OutputMode != tt.expect { + t.Errorf("got: %d, expect: %d", c.OutputMode, tt.expect) } }) } diff --git a/cmd/root.go b/cmd/root.go index 58ef950..466c85d 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -25,6 +25,7 @@ import ( "log" "os" "os/exec" + "strings" ) func man() { @@ -48,7 +49,6 @@ func Execute() { var ( conf cfg.Config ShowManual bool - Outputmode string ShowVersion bool modeflag cfg.Modeflag sortmode cfg.Sortmode @@ -70,11 +70,7 @@ func Execute() { } // prepare flags - err := conf.PrepareModeFlags(modeflag, Outputmode) - if err != nil { - return err - } - + conf.PrepareModeFlags(modeflag) conf.PrepareSortFlags(sortmode) // actual execution starts here @@ -94,26 +90,23 @@ func Execute() { // sort options rootCmd.PersistentFlags().IntVarP(&conf.SortByColumn, "sort-by", "k", 0, "Sort by column (default: 1)") + + // sort mode, only 1 allowed rootCmd.PersistentFlags().BoolVarP(&conf.SortDescending, "sort-desc", "D", false, "Sort in descending order (default: ascending)") rootCmd.PersistentFlags().BoolVarP(&sortmode.Numeric, "sort-numeric", "i", false, "sort according to string numerical value") rootCmd.PersistentFlags().BoolVarP(&sortmode.Time, "sort-time", "t", false, "sort according to time string") rootCmd.PersistentFlags().BoolVarP(&sortmode.Age, "sort-age", "a", false, "sort according to age (duration) string") + rootCmd.MarkFlagsMutuallyExclusive("sort-desc", "sort-numeric", "sort-time", "sort-age") - // output flags, only 1 allowed, hidden, since just short cuts + // output flags, only 1 allowed rootCmd.PersistentFlags().BoolVarP(&modeflag.X, "extended", "X", false, "Enable extended output") rootCmd.PersistentFlags().BoolVarP(&modeflag.M, "markdown", "M", false, "Enable markdown table output") rootCmd.PersistentFlags().BoolVarP(&modeflag.O, "orgtbl", "O", false, "Enable org-mode table output") rootCmd.PersistentFlags().BoolVarP(&modeflag.S, "shell", "S", false, "Enable shell mode output") rootCmd.PersistentFlags().BoolVarP(&modeflag.Y, "yaml", "Y", false, "Enable yaml output") rootCmd.MarkFlagsMutuallyExclusive("extended", "markdown", "orgtbl", "shell", "yaml") - _ = rootCmd.Flags().MarkHidden("extended") - _ = rootCmd.Flags().MarkHidden("orgtbl") - _ = rootCmd.Flags().MarkHidden("markdown") - _ = rootCmd.Flags().MarkHidden("shell") - _ = rootCmd.Flags().MarkHidden("yaml") - // same thing but more common, takes precedence over above group - rootCmd.PersistentFlags().StringVarP(&Outputmode, "output", "o", "", "Output mode - one of: orgtbl, markdown, extended, shell, ascii(default)") + rootCmd.SetUsageTemplate(strings.TrimSpace(usage) + "\n") err := rootCmd.Execute() if err != nil { diff --git a/cmd/tablizer.go b/cmd/tablizer.go index 332edef..61448cc 100644 --- a/cmd/tablizer.go +++ b/cmd/tablizer.go @@ -8,24 +8,32 @@ SYNOPSIS Usage: tablizer [regex] [file, ...] [flags] - Flags: + Operational Flags: -c, --columns string Only show the speficied columns (separated by ,) - -d, --debug Enable debugging - -h, --help help for tablizer -v, --invert-match select non-matching rows - -m, --man Display manual page -n, --no-numbering Disable header numbering -N, --no-color Disable pattern highlighting - -o, --output string Output mode - one of: orgtbl, markdown, extended, yaml, ascii(default) + -s, --separator string Custom field separator + -k, --sort-by int Sort by column (default: 1) + + Output Flags (mutually exclusive): -X, --extended Enable extended output -M, --markdown Enable markdown table output -O, --orgtbl Enable org-mode table output - -s, --separator string Custom field separator + -S, --shell Enable shell evaluable ouput + -Y, --yaml Enable yaml output + -A, --ascii Default output mode, ascii tabular + + Sort Mode Flags (mutually exclusive): -a, --sort-age sort according to age (duration) string - -k, --sort-by int Sort by column (default: 1) -D, --sort-desc Sort in descending order (default: ascending) -i, --sort-numeric sort according to string numerical value -t, --sort-time sort according to time string + + Other Flags: + -d, --debug Enable debugging + -h, --help help for tablizer + -m, --man Display manual page -v, --version Print program version DESCRIPTION @@ -205,3 +213,38 @@ AUTHORS Thomas von Dein tom AT vondein DOT org ` +var usage = ` + +Usage: + tablizer [regex] [file, ...] [flags] + +Operational Flags: + -c, --columns string Only show the speficied columns (separated by ,) + -v, --invert-match select non-matching rows + -n, --no-numbering Disable header numbering + -N, --no-color Disable pattern highlighting + -s, --separator string Custom field separator + -k, --sort-by int Sort by column (default: 1) + +Output Flags (mutually exclusive): + -X, --extended Enable extended output + -M, --markdown Enable markdown table output + -O, --orgtbl Enable org-mode table output + -S, --shell Enable shell evaluable ouput + -Y, --yaml Enable yaml output + -A, --ascii Default output mode, ascii tabular + +Sort Mode Flags (mutually exclusive): + -a, --sort-age sort according to age (duration) string + -D, --sort-desc Sort in descending order (default: ascending) + -i, --sort-numeric sort according to string numerical value + -t, --sort-time sort according to time string + +Other Flags: + -d, --debug Enable debugging + -h, --help help for tablizer + -m, --man Display manual page + -v, --version Print program version + + +` diff --git a/lib/printer.go b/lib/printer.go index 61b0306..20c6587 100644 --- a/lib/printer.go +++ b/lib/printer.go @@ -43,21 +43,22 @@ func printData(w io.Writer, c cfg.Config, data *Tabdata) { sortTable(c, data) switch c.OutputMode { - case "extended": + case cfg.Extended: printExtendedData(w, c, data) - case "ascii": + case cfg.Ascii: printAsciiData(w, c, data) - case "orgtbl": + case cfg.Orgtbl: printOrgmodeData(w, c, data) - case "markdown": + case cfg.Markdown: printMarkdownData(w, c, data) - case "shell": + case cfg.Shell: printShellData(w, c, data) - case "yaml": + case cfg.Yaml: printYamlData(w, c, data) default: printAsciiData(w, c, data) } + } func output(w io.Writer, str string) { diff --git a/lib/printer_test.go b/lib/printer_test.go index dbb1f1f..5f0efd0 100644 --- a/lib/printer_test.go +++ b/lib/printer_test.go @@ -72,14 +72,14 @@ var tests = []struct { column int // sort by this column, 0 == default first or NO Sort desc bool // sort in descending order, default == ascending nonum bool // hide numbering - mode string // shell, orgtbl, etc. empty == default: ascii + mode int // shell, orgtbl, etc. empty == default: ascii usecol []int // columns to display, empty == display all usecolstr string // for testname, must match usecol expect string // rendered output we expect }{ // --------------------- Default settings mode tests `` { - mode: "ascii", + mode: cfg.Ascii, name: "default", expect: ` NAME(1) DURATION(2) COUNT(3) WHEN(4) @@ -89,7 +89,7 @@ ceta 33d12h 9 06/Jan/2008 15:04:05 -0700`, }, { name: "default", - mode: "orgtbl", + mode: cfg.Orgtbl, expect: ` +---------+-------------+----------+----------------------------+ | NAME(1) | DURATION(2) | COUNT(3) | WHEN(4) | @@ -101,7 +101,7 @@ ceta 33d12h 9 06/Jan/2008 15:04:05 -0700`, }, { name: "default", - mode: "markdown", + mode: cfg.Markdown, expect: ` | NAME(1) | DURATION(2) | COUNT(3) | WHEN(4) | |---------|-------------|----------|----------------------------| @@ -111,7 +111,7 @@ ceta 33d12h 9 06/Jan/2008 15:04:05 -0700`, }, { name: "default", - mode: "shell", + mode: cfg.Shell, nonum: true, expect: ` NAME="beta" DURATION="1d10h5m1s" COUNT="33" WHEN="3/1/2014" @@ -120,7 +120,7 @@ NAME="ceta" DURATION="33d12h" COUNT="9" WHEN="06/Jan/2008 15:04:05 -0700"`, }, { name: "default", - mode: "yaml", + mode: cfg.Yaml, nonum: true, expect: ` entries: @@ -139,7 +139,7 @@ entries: }, { name: "default", - mode: "extended", + mode: cfg.Extended, expect: ` NAME(1): beta DURATION(2): 1d10h5m1s @@ -248,7 +248,7 @@ DURATION(2) WHEN(4) func TestPrinter(t *testing.T) { for _, tt := range tests { - testname := fmt.Sprintf("print-sortcol-%d-desc-%t-sortby-%s-mode-%s-usecolumns-%s", + testname := fmt.Sprintf("print-sortcol-%d-desc-%t-sortby-%s-mode-%d-usecolumns-%s", tt.column, tt.desc, tt.sortby, tt.mode, tt.usecolstr) t.Run(testname, func(t *testing.T) { // replaces os.Stdout, but we ignore it diff --git a/tablizer.1 b/tablizer.1 index e867e0b..b8112c8 100644 --- a/tablizer.1 +++ b/tablizer.1 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "TABLIZER 1" -.TH TABLIZER 1 "2022-10-16" "1" "User Commands" +.TH TABLIZER 1 "2022-10-21" "1" "User Commands" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l @@ -146,24 +146,32 @@ tablizer \- Manipulate tabular output of other programs \& Usage: \& tablizer [regex] [file, ...] [flags] \& -\& Flags: +\& Operational Flags: \& \-c, \-\-columns string Only show the speficied columns (separated by ,) -\& \-d, \-\-debug Enable debugging -\& \-h, \-\-help help for tablizer \& \-v, \-\-invert\-match select non\-matching rows -\& \-m, \-\-man Display manual page \& \-n, \-\-no\-numbering Disable header numbering \& \-N, \-\-no\-color Disable pattern highlighting -\& \-o, \-\-output string Output mode \- one of: orgtbl, markdown, extended, yaml, ascii(default) +\& \-s, \-\-separator string Custom field separator +\& \-k, \-\-sort\-by int Sort by column (default: 1) +\& +\& Output Flags (mutually exclusive): \& \-X, \-\-extended Enable extended output \& \-M, \-\-markdown Enable markdown table output \& \-O, \-\-orgtbl Enable org\-mode table output -\& \-s, \-\-separator string Custom field separator +\& \-S, \-\-shell Enable shell evaluable ouput +\& \-Y, \-\-yaml Enable yaml output +\& \-A, \-\-ascii Default output mode, ascii tabular +\& +\& Sort Mode Flags (mutually exclusive): \& \-a, \-\-sort\-age sort according to age (duration) string -\& \-k, \-\-sort\-by int Sort by column (default: 1) \& \-D, \-\-sort\-desc Sort in descending order (default: ascending) \& \-i, \-\-sort\-numeric sort according to string numerical value \& \-t, \-\-sort\-time sort according to time string +\& +\& Other Flags: +\& \-d, \-\-debug Enable debugging +\& \-h, \-\-help help for tablizer +\& \-m, \-\-man Display manual page \& \-v, \-\-version Print program version .Ve .SH "DESCRIPTION" diff --git a/tablizer.pod b/tablizer.pod index b2091e4..68235b5 100644 --- a/tablizer.pod +++ b/tablizer.pod @@ -7,24 +7,32 @@ tablizer - Manipulate tabular output of other programs Usage: tablizer [regex] [file, ...] [flags] - Flags: + Operational Flags: -c, --columns string Only show the speficied columns (separated by ,) - -d, --debug Enable debugging - -h, --help help for tablizer -v, --invert-match select non-matching rows - -m, --man Display manual page -n, --no-numbering Disable header numbering -N, --no-color Disable pattern highlighting - -o, --output string Output mode - one of: orgtbl, markdown, extended, yaml, ascii(default) + -s, --separator string Custom field separator + -k, --sort-by int Sort by column (default: 1) + + Output Flags (mutually exclusive): -X, --extended Enable extended output -M, --markdown Enable markdown table output -O, --orgtbl Enable org-mode table output - -s, --separator string Custom field separator + -S, --shell Enable shell evaluable ouput + -Y, --yaml Enable yaml output + -A, --ascii Default output mode, ascii tabular + + Sort Mode Flags (mutually exclusive): -a, --sort-age sort according to age (duration) string - -k, --sort-by int Sort by column (default: 1) -D, --sort-desc Sort in descending order (default: ascending) -i, --sort-numeric sort according to string numerical value -t, --sort-time sort according to time string + + Other Flags: + -d, --debug Enable debugging + -h, --help help for tablizer + -m, --man Display manual page -v, --version Print program version