Skip to content

Commit

Permalink
clitable: Add support for TSV data
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidGamba committed May 19, 2023
1 parent 4ae7da9 commit 11eaa8b
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 18 deletions.
12 changes: 11 additions & 1 deletion clitable/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ Pretty print Data as tables on the command line.

The csvtable cli tool allows printing CSV data as a table:

go install github.com/DavidGamba/dgtools/clitable/cmd/csvtable
go install github.com/DavidGamba/dgtools/clitable/cmd/[email protected]

To parse TSV data use the `--tsv` flag.

== Library

Expand Down Expand Up @@ -41,6 +43,14 @@ r := strings.NewReader("Hello,1\nWorld,2\n")
clitable.NewTablePrinter().FprintCSVReader(os.Stdout, r)
----

For TSV from an `io.Reader`:

[source, go]
----
r := strings.NewReader("Hello 1\nWorld 2\n")
clitable.NewTablePrinter().Separator('\t').FprintCSVReader(os.Stdout, r)
----

----
┌───────┬───┐
│ Hello │ 1 │
Expand Down
4 changes: 4 additions & 0 deletions clitable/changelog.adoc
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
= Changelog
:toc:

== v0.3.0: New feature

* Add support for TSV data.

== v0.2.0: New feature

* Add CSV Printer
Expand Down
16 changes: 14 additions & 2 deletions clitable/clitable.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ var Logger = log.New(ioutil.Discard, "clitable DEBUG ", log.LstdFlags)

type TablePrinter struct {
tableConfig tableConfig
separator rune
}

type tableConfig struct {
Expand Down Expand Up @@ -91,6 +92,11 @@ func (tp *TablePrinter) HasHeader(b bool) *TablePrinter {
return tp
}

func (tp *TablePrinter) Separator(c rune) *TablePrinter {
tp.separator = c
return tp
}

func (tp *TablePrinter) SetStyle(s Style) *TablePrinter {
tp.tableConfig.Style = s

Expand Down Expand Up @@ -207,13 +213,19 @@ func (tp *TablePrinter) FprintCSVReader(w io.Writer, r io.Reader) error {
// TODO: I am sure I can make this simpler and maybe even not necessary
var readerCopy bytes.Buffer
reader := io.TeeReader(r, &readerCopy)
t := CSVTable{reader}
t := CSVTable{
Reader: reader,
Separator: tp.separator,
}
tableInfo, err := GetTableInfo(t)
if err != nil {
return err
}
Logger.Printf("tableInfo: %s\n", tableInfo)
t = CSVTable{&readerCopy}
t = CSVTable{
Reader: &readerCopy,
Separator: tp.separator,
}
return tp.fprint(os.Stdout, t, tableInfo)
}

Expand Down
61 changes: 49 additions & 12 deletions clitable/cmd/csvtable/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@
/*
Package csvtable provides a tool to view csv files on the cmdline.
┌──┬──┐
│ │ │
├──┼──┤
└──┴──┘
┌──┬──┐
│ │ │
├──┼──┤
└──┴──┘
*/
package main

Expand All @@ -23,16 +22,13 @@ import (
"io/ioutil"
"log"
"os"
"runtime/debug"
"time"

"github.com/DavidGamba/dgtools/clitable"
"github.com/DavidGamba/go-getoptions"
)

// BuildMetadata - Provides the metadata part of the version information.
//
// go build -ldflags="-X main.BuildMetadata=`date +'%Y%m%d%H%M%S'`.`git rev-parse --short HEAD`"
var BuildMetadata = "dev"

const semVersion = "0.3.0"

var logger = log.New(ioutil.Discard, "main DEBUG ", log.LstdFlags)
Expand All @@ -52,6 +48,7 @@ func main() {
opt.Bool("help", false, opt.Alias("?"))
opt.Bool("debug", false)
opt.Bool("version", false, opt.Alias("V"))
opt.Bool("tsv", false)
header := opt.Bool("no-header", true)
opt.HelpSynopsisArgs("<csv_filename>")
remaining, err := opt.Parse(os.Args[1:])
Expand All @@ -65,7 +62,12 @@ func main() {
os.Exit(1)
}
if opt.Called("version") {
fmt.Printf("Version: %s+%s\n", semVersion, BuildMetadata)
v, err := version(semVersion)
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR: %s\n", err)
os.Exit(1)
}
fmt.Printf("Version: %s\n", v)
os.Exit(0)
}
if opt.Called("debug") {
Expand Down Expand Up @@ -98,9 +100,44 @@ func main() {
defer fh.Close()
reader = fh
}
err = clitable.NewTablePrinter().HasHeader(*header).FprintCSVReader(os.Stdout, reader)
tp := clitable.NewTablePrinter()
if opt.Called("tsv") {
tp.Separator('\t')
}
err = tp.HasHeader(*header).FprintCSVReader(os.Stdout, reader)
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR: %s\n", err)
os.Exit(1)
}
}

func version(semVersion string) (string, error) {
var revision, timeStr, modified string
info, ok := debug.ReadBuildInfo()
if ok {
for _, s := range info.Settings {
switch s.Key {
case "vcs.revision":
revision = s.Value
case "vcs.time":
vcsTime := s.Value
date, err := time.Parse("2006-01-02T15:04:05Z", vcsTime)
if err != nil {
return "", fmt.Errorf("failed to parse time: %w", err)
}
timeStr = date.Format("20060102_150405")
case "vcs.modified":
if s.Value == "true" {
modified = "modified"
}
}
}
}
if revision != "" && timeStr != "" {
semVersion += fmt.Sprintf("+%s.%s", revision, timeStr)
if modified != "" {
semVersion += fmt.Sprintf(".%s", modified)
}
}
return semVersion, nil
}
10 changes: 7 additions & 3 deletions clitable/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,23 @@ func SimpleRowIterator(data [][]string) <-chan Row {

// CSVTable - Implements the table interface from an io.Reader to CSV data.
type CSVTable struct {
Reader io.Reader
Reader io.Reader
Separator rune
}

// RowIterator - Implements the Table interface.
func (t CSVTable) RowIterator() <-chan Row {
return CSVRowIterator(t.Reader)
return CSVRowIterator(t.Reader, t.Separator)
}

// CSVRowIterator -
func CSVRowIterator(reader io.Reader) <-chan Row {
func CSVRowIterator(reader io.Reader, separator rune) <-chan Row {
c := make(chan Row)
go func() {
r := csv.NewReader(reader)
if separator != 0 {
r.Comma = separator
}
r.FieldsPerRecord = -1
for {
record, err := r.Read()
Expand Down

0 comments on commit 11eaa8b

Please sign in to comment.