From 07b65bcff58e6075076527b6e3368342cc1e973a Mon Sep 17 00:00:00 2001 From: Thomas von Dein Date: Sun, 2 Oct 2022 15:06:11 +0200 Subject: [PATCH 1/4] fix release maker --- Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile b/Makefile index eafedff..a053f9d 100644 --- a/Makefile +++ b/Makefile @@ -33,8 +33,7 @@ buildlocal: go build release: - mkdir -p releases - $(foreach arch,$(archs), GOOS=$(arch) GOARCH=amd64 go build -x -o releases/$(tool)-$(arch)-amd64-$(version); sha256sum releases/$(tool)-$(arch)-amd64-$(version) | cut -d' ' -f1 > releases/$(tool)-$(arch)-amd64-$(version).sha256sum;) + ./mkrel.sh $(tool) $(version) install: buildlocal install -d -o $(UID) -g $(GID) $(PREFIX)/bin From 65cbaddd5f0d6949577d038820eb1e85436f44f0 Mon Sep 17 00:00:00 2001 From: Thomas von Dein Date: Mon, 3 Oct 2022 12:52:26 +0200 Subject: [PATCH 2/4] don't use die() anymore, butt dtd go errros --- lib/helpers.go | 6 ------ lib/io.go | 6 +++++- lib/parser.go | 12 +++++------- lib/parser_test.go | 7 ++++++- lib/printer_test.go | 7 ++++++- 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/lib/helpers.go b/lib/helpers.go index ddda4ee..0ed1ed0 100644 --- a/lib/helpers.go +++ b/lib/helpers.go @@ -20,17 +20,11 @@ package lib import ( "errors" "fmt" - "os" "regexp" "strconv" "strings" ) -func die(v ...interface{}) { - fmt.Fprintln(os.Stderr, v...) - os.Exit(1) -} - func contains(s []int, e int) bool { for _, a := range s { if a == e { diff --git a/lib/io.go b/lib/io.go index 4c6a726..4d70b94 100644 --- a/lib/io.go +++ b/lib/io.go @@ -31,7 +31,11 @@ func ProcessFiles(args []string) error { } for _, fd := range fds { - printData(parseFile(fd, pattern)) + data, err := parseFile(fd, pattern) + if err != nil { + return err + } + printData(data) } return nil diff --git a/lib/parser.go b/lib/parser.go index 0b19e14..53c0af6 100644 --- a/lib/parser.go +++ b/lib/parser.go @@ -19,6 +19,7 @@ package lib import ( "bufio" + "errors" "fmt" "github.com/alecthomas/repr" "io" @@ -43,7 +44,7 @@ type Tabdata struct { way we can turn "tabular data" (with fields containing whitespaces) into real tabular data. We re-tabulate our input if you will. */ -func parseFile(input io.Reader, pattern string) Tabdata { +func parseFile(input io.Reader, pattern string) (Tabdata, error) { data := Tabdata{} var scanner *bufio.Scanner @@ -65,7 +66,7 @@ func parseFile(input io.Reader, pattern string) Tabdata { patternR, err := regexp.Compile(pattern) if err != nil { - die(err) + return data, errors.Unwrap(fmt.Errorf("Regexp pattern %s is invalid: %w", pattern, err)) } if !hadFirst { @@ -145,20 +146,17 @@ func parseFile(input io.Reader, pattern string) Tabdata { idx++ } - if Debug { - fmt.Println() - } data.entries = append(data.entries, values) } } if scanner.Err() != nil { - die(scanner.Err()) + return data, errors.Unwrap(fmt.Errorf("Regexp pattern %s is invalid: %w", pattern, scanner.Err())) } if Debug { repr.Print(data) } - return data + return data, nil } diff --git a/lib/parser_test.go b/lib/parser_test.go index 19218b3..24fca81 100644 --- a/lib/parser_test.go +++ b/lib/parser_test.go @@ -70,7 +70,12 @@ asd igig cxxxncnc 19191 EDD 1 X` readFd := strings.NewReader(table) - gotdata := parseFile(readFd, "") + gotdata, err := parseFile(readFd, "") + + if err != nil { + t.Errorf("Parser returned error: %s\nData processed so far: %+v", err, gotdata) + } + if !reflect.DeepEqual(data, gotdata) { t.Errorf("Parser returned invalid data\nExp: %+v\nGot: %+v\n", data, gotdata) } diff --git a/lib/printer_test.go b/lib/printer_test.go index 5abb75a..2131156 100644 --- a/lib/printer_test.go +++ b/lib/printer_test.go @@ -54,7 +54,12 @@ asd igig cxxxncnc for mode, expect := range expects { OutputMode = mode fd := strings.NewReader(table) - data := parseFile(fd, "") + data, err := parseFile(fd, "") + + if err != nil { + t.Errorf("Parser returned error: %s\nData processed so far: %+v", err, data) + } + printData(data) buf := make([]byte, 1024) From 3fd2e6ac2f5499cf70fea5ffcd0955b2499993db Mon Sep 17 00:00:00 2001 From: Thomas von Dein Date: Mon, 3 Oct 2022 13:10:23 +0200 Subject: [PATCH 3/4] use pointer of Tabdata, so there's only 1 copy around --- lib/helpers.go | 10 ++++++++++ lib/io.go | 2 +- lib/printer.go | 25 ++++++++----------------- lib/printer_test.go | 2 +- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/lib/helpers.go b/lib/helpers.go index 0ed1ed0..9498b1a 100644 --- a/lib/helpers.go +++ b/lib/helpers.go @@ -76,3 +76,13 @@ func PrepareModeFlags() error { return nil } + +func trimRow(row []string) []string { + // FIXME: remove this when we only use Tablewriter and strip in ParseFile()! + var fixedrow []string + for _, cell := range row { + fixedrow = append(fixedrow, strings.TrimSpace(cell)) + } + + return fixedrow +} diff --git a/lib/io.go b/lib/io.go index 4d70b94..adab95b 100644 --- a/lib/io.go +++ b/lib/io.go @@ -35,7 +35,7 @@ func ProcessFiles(args []string) error { if err != nil { return err } - printData(data) + printData(&data) } return nil diff --git a/lib/printer.go b/lib/printer.go index 2f6a056..c045c43 100644 --- a/lib/printer.go +++ b/lib/printer.go @@ -25,14 +25,15 @@ import ( "strings" ) -func printData(data Tabdata) { - // prepare headers - // FIXME: maybe do this already in parseFile()? +func printData(data *Tabdata) { + // prepare headers: add numbers to headers if !NoNumbering { numberedHeaders := []string{} for i, head := range data.headers { if len(Columns) > 0 { + // -c specified if !contains(UseColumns, i+1) { + // ignore this one continue } } @@ -73,20 +74,10 @@ func printData(data Tabdata) { } } -func trimRow(row []string) []string { - // FIXME: remove this when we only use Tablewriter and strip in ParseFile()! - var fixedrow []string - for _, cell := range row { - fixedrow = append(fixedrow, strings.TrimSpace(cell)) - } - - return fixedrow -} - /* Emacs org-mode compatible table (also orgtbl-mode) */ -func printOrgmodeData(data Tabdata) { +func printOrgmodeData(data *Tabdata) { tableString := &strings.Builder{} table := tablewriter.NewWriter(tableString) @@ -118,7 +109,7 @@ func printOrgmodeData(data Tabdata) { /* Markdown table */ -func printMarkdownData(data Tabdata) { +func printMarkdownData(data *Tabdata) { table := tablewriter.NewWriter(os.Stdout) table.SetHeader(data.headers) @@ -136,7 +127,7 @@ func printMarkdownData(data Tabdata) { /* Simple ASCII table without any borders etc, just like the input we expect */ -func printAsciiData(data Tabdata) { +func printAsciiData(data *Tabdata) { table := tablewriter.NewWriter(os.Stdout) table.SetHeader(data.headers) @@ -164,7 +155,7 @@ func printAsciiData(data Tabdata) { /* We simulate the \x command of psql (the PostgreSQL client) */ -func printExtendedData(data Tabdata) { +func printExtendedData(data *Tabdata) { // needed for data output format := fmt.Sprintf("%%%ds: %%s\n", data.maxwidthHeader) // FIXME: re-calculate if -c has been set diff --git a/lib/printer_test.go b/lib/printer_test.go index 2131156..9530574 100644 --- a/lib/printer_test.go +++ b/lib/printer_test.go @@ -60,7 +60,7 @@ asd igig cxxxncnc t.Errorf("Parser returned error: %s\nData processed so far: %+v", err, data) } - printData(data) + printData(&data) buf := make([]byte, 1024) n, err := r.Read(buf) From 76f49a532f7bb636cee346f4b87c20568832cc4f Mon Sep 17 00:00:00 2001 From: Thomas von Dein Date: Mon, 3 Oct 2022 13:28:04 +0200 Subject: [PATCH 4/4] added shell mode output --- TODO | 4 ---- cmd/root.go | 6 ++++-- lib/common.go | 3 ++- lib/helpers.go | 3 +++ lib/printer.go | 47 +++++++++++++++++++++++++++++++++++++---------- tablizer.pod | 15 +++++++++++++-- 6 files changed, 59 insertions(+), 19 deletions(-) diff --git a/TODO b/TODO index 73b8d16..8b13789 100644 --- a/TODO +++ b/TODO @@ -1,5 +1 @@ -Add a mode like FreeBSD stat(1): - -stat -s dead.letter -st_dev=170671546954750497 st_ino=159667 st_mode=0100644 st_nlink=1 st_uid=1001 st_gid=1001 st_rdev=18446744073709551615 st_size=573 st_atime=1661994007 st_mtime=1661961878 st_ctime=1661961878 st_birthtime=1658394900 st_blksize=4096 st_blocks=3 st_flags=2048 diff --git a/cmd/root.go b/cmd/root.go index 6d047eb..2b20534 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -65,11 +65,13 @@ func init() { rootCmd.PersistentFlags().BoolVarP(&lib.OutflagExtended, "extended", "X", false, "Enable extended output") rootCmd.PersistentFlags().BoolVarP(&lib.OutflagMarkdown, "markdown", "M", false, "Enable markdown table output") rootCmd.PersistentFlags().BoolVarP(&lib.OutflagOrgtable, "orgtbl", "O", false, "Enable org-mode table output") - rootCmd.MarkFlagsMutuallyExclusive("extended", "markdown", "orgtbl") + rootCmd.PersistentFlags().BoolVarP(&lib.OutflagShell, "shell", "S", false, "Enable shell mode output") + rootCmd.MarkFlagsMutuallyExclusive("extended", "markdown", "orgtbl", "shell") rootCmd.Flags().MarkHidden("extended") rootCmd.Flags().MarkHidden("orgtbl") rootCmd.Flags().MarkHidden("markdown") + rootCmd.Flags().MarkHidden("shell") // same thing but more common, takes precedence over above group - rootCmd.PersistentFlags().StringVarP(&lib.OutputMode, "output", "o", "", "Output mode - one of: orgtbl, markdown, extended, ascii(default)") + rootCmd.PersistentFlags().StringVarP(&lib.OutputMode, "output", "o", "", "Output mode - one of: orgtbl, markdown, extended, shell, ascii(default)") } diff --git a/lib/common.go b/lib/common.go index 104d452..9e6cd85 100644 --- a/lib/common.go +++ b/lib/common.go @@ -28,7 +28,8 @@ var Separator string var OutflagExtended bool var OutflagMarkdown bool var OutflagOrgtable bool +var OutflagShell bool var OutputMode string -var Version = "v1.0.2" +var Version = "v1.0.3" var validOutputmodes = "(orgtbl|markdown|extended|ascii)" diff --git a/lib/helpers.go b/lib/helpers.go index 9498b1a..6d047a0 100644 --- a/lib/helpers.go +++ b/lib/helpers.go @@ -57,6 +57,9 @@ func PrepareModeFlags() error { OutputMode = "markdown" case OutflagOrgtable: OutputMode = "orgtbl" + case OutflagShell: + OutputMode = "shell" + NoNumbering = true default: OutputMode = "ascii" } diff --git a/lib/printer.go b/lib/printer.go index c045c43..937757d 100644 --- a/lib/printer.go +++ b/lib/printer.go @@ -27,20 +27,22 @@ import ( func printData(data *Tabdata) { // prepare headers: add numbers to headers - if !NoNumbering { - numberedHeaders := []string{} - for i, head := range data.headers { - if len(Columns) > 0 { - // -c specified - if !contains(UseColumns, i+1) { - // ignore this one - continue - } + numberedHeaders := []string{} + for i, head := range data.headers { + if len(Columns) > 0 { + // -c specified + if !contains(UseColumns, i+1) { + // ignore this one + continue } + } + if NoNumbering { + numberedHeaders = append(numberedHeaders, head) + } else { numberedHeaders = append(numberedHeaders, fmt.Sprintf("%s(%d)", head, i+1)) } - data.headers = numberedHeaders } + data.headers = numberedHeaders // prepare data if len(Columns) > 0 { @@ -69,6 +71,8 @@ func printData(data *Tabdata) { printOrgmodeData(data) case "markdown": printMarkdownData(data) + case "shell": + printShellData(data) default: printAsciiData(data) } @@ -177,3 +181,26 @@ func printExtendedData(data *Tabdata) { } } } + +/* + Shell output, ready to be eval'd. Just like FreeBSD stat(1) +*/ +func printShellData(data *Tabdata) { + if len(data.entries) > 0 { + var idx int + for _, entry := range data.entries { + idx = 0 + for i, value := range entry { + if len(Columns) > 0 { + if !contains(UseColumns, i+1) { + continue + } + } + + fmt.Printf("%s=\"%s\" ", data.headers[idx], value) + idx++ + } + fmt.Println() + } + } +} diff --git a/tablizer.pod b/tablizer.pod index 4808812..0451bbc 100644 --- a/tablizer.pod +++ b/tablizer.pod @@ -74,7 +74,7 @@ The numbering can be suppressed by using the B<-n> option. Finally the B<-d> option enables debugging output which is mostly usefull for the developer. -?head2 OUTPUT MODES +=head2 OUTPUT MODES There might be cases when the tabular output of a program is way too large for your current terminal but you still need to see every @@ -83,7 +83,7 @@ usefull which enables I. In this mode, each row will be printed vertically, header left, value right, aligned by the field widths. Here's an example: - kubectl get pods | ./tablizer -X + kubectl get pods | ./tablizer -o extended NAME: repldepl-7bcd8d5b64-7zq4l READY: 1/1 STATUS: Running @@ -93,6 +93,17 @@ widths. Here's an example: You can of course still use a regex to reduce the number of rows displayed. +The option B<-o shell> can be used if the output has to be processed +by the shell, it prints variable assignments for each cell, one line +per row: + + kubectl get pods | ./tablizer -o extended ./tablizer -o shell + NAME="repldepl-7bcd8d5b64-7zq4l" READY="1/1" STATUS="Running" RESTARTS="9 (47m ago)" AGE="4d23h" + NAME="repldepl-7bcd8d5b64-m48n8" READY="1/1" STATUS="Running" RESTARTS="9 (47m ago)" AGE="4d23h" + NAME="repldepl-7bcd8d5b64-q2bf4" READY="1/1" STATUS="Running" RESTARTS="9 (47m ago)" AGE="4d23h" + +You can use this in an eval loop. + Beside normal ascii mode (the default) and extended mode there are more output modes available: B which prints an Emacs org-mode table and B which prints a Markdown table.