Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,26 @@ For more information, see here: [https://compgen.io/tabl](https://compgen.io/tab

Note: The `tabl less` pager forces 256-color output to keep formatting/colors consistent on terminals like tmux/screen (especially on RHEL8).

## Parquet

`view`, `less`, and `parquet2tab` can read Parquet files. Parquet is detected
automatically from the file's magic bytes, so no flag is needed:

tabl view data.parquet
tabl less data.parquet
tabl parquet2tab data.parquet > data.txt

Use `--parquet` to force it for a file that isn't named/detected as one.

The parquet schema supplies the header. Nested structs are flattened into dotted
column names (`addr.city`), while lists and maps are rendered as JSON in a single
cell. NULL cells are written as an empty value; use `--na=STRING` to change that
(e.g. `--na=NA`).

Because a parquet file's schema lives in a footer at the end of the file,
reading one requires random access -- parquet cannot be read from a pipe, so a
real file path is required.

## Examples

![Demo](https://github.com/compgen-io/tabl-docs/raw/master/assets/img/tabl-demo-2.gif)
13 changes: 5 additions & 8 deletions cmd/less.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ func init() {
lessCmd.Flags().BoolVar(&NoHeader, "no-header", false, "File has no header")
lessCmd.Flags().BoolVar(&HeaderComment, "header-comment", false, "The header is the last commented line")
lessCmd.Flags().BoolVar(&IsCSV, "csv", false, "The file is a CSV file")
lessCmd.Flags().BoolVar(&IsParquet, "parquet", false, "The file is a Parquet file")
lessCmd.Flags().StringVar(&NAString, "na", "", "Value shown for NULL cells (Parquet)")
lessCmd.Flags().IntVar(&MinWidth, "min", 0, "Minimum column width")
lessCmd.Flags().IntVar(&MaxWidth, "max", 0, "Maximum column width")
rootCmd.AddCommand(lessCmd)
Expand All @@ -34,16 +36,11 @@ var lessCmd = &cobra.Command{
if len(args) == 0 {
args = []string{"-"}
}
var txt *textfile.DelimitedTextFile
if !IsCSV {
txt = textfile.NewTabFile(args[0])
} else {
txt = textfile.NewCSVFile(args[0])
txt, err := openReader(cmd, args[0])
if err != nil {
er(err)
}

txt = txt.WithNoHeader(NoHeader).
WithHeaderComment(HeaderComment)

textfile.NewTextPager(txt).
WithShowLineNum(ShowLineNum).
WithMaxWidth(MaxWidth).
Expand Down
52 changes: 52 additions & 0 deletions cmd/parquet2tab.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package cmd

import (
"fmt"
"os"

"github.com/compgen-io/tabl/textfile"
"github.com/spf13/cobra"
)

func init() {
parquet2TabCmd.Flags().StringVar(&NAString, "na", "", "Value to write for NULL cells")
rootCmd.AddCommand(parquet2TabCmd)
}

var parquet2TabCmd = &cobra.Command{
Use: "parquet2tab [file]",
Short: "Convert a Parquet file to tab-delimited format",
Long: `Convert a Parquet file to tab-delimited format.

The parquet schema becomes the header. Nested structs are flattened into
dotted column names (addr.city), and lists and maps are written as JSON.

NULL cells are written as an empty value unless --na is given.

Note that parquet files can't be read from a pipe -- the schema lives in a
footer at the end of the file, so a real file path is required.
`,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return fmt.Errorf("Missing [file]")
}
if args[0] == "-" {
return textfile.ErrParquetStdin
}
_, err := os.Stat(args[0])
if os.IsNotExist(err) {
return fmt.Errorf("Missing file: %s", args[0])
}
return nil
},
Run: func(cmd *cobra.Command, args []string) {
pq := textfile.NewParquetFile(args[0]).WithNAString(NAString)
if err := pq.Open(); err != nil {
er(err)
}

if err := textfile.NewCSVExporter(pq).WriteFile(os.Stdout); err != nil {
er(err)
}
},
}
69 changes: 69 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
package cmd

import (
"bytes"
"fmt"
"io"
"os"

"github.com/compgen-io/tabl/textfile"
"github.com/spf13/cobra"
)

// IsCSV -- the file is a CSV file
var IsCSV bool

// IsParquet -- the file is a Parquet file
var IsParquet bool

// NAString -- the value written for NULL cells (Parquet only)
var NAString string

// NoHeader -- the file has no header
var NoHeader bool

Expand Down Expand Up @@ -45,3 +54,63 @@ func er(msg interface{}) {
fmt.Println("Error:", msg)
os.Exit(1)
}

// parquetMagic is the marker written at the start (and end) of a parquet file
var parquetMagic = []byte("PAR1")

// looksLikeParquet sniffs the leading magic bytes, in the same spirit as the
// gzip detection the delimited reader already does.
func looksLikeParquet(fname string) bool {
if fname == "-" {
return false
}

f, err := os.Open(fname)
if err != nil {
return false
}
defer f.Close()

buf := make([]byte, len(parquetMagic))
if _, err := io.ReadFull(f, buf); err != nil {
return false
}
return bytes.Equal(buf, parquetMagic)
}

// openReader builds the appropriate reader for a file. --parquet and --csv
// force the format; otherwise we sniff for parquet and fall back to text.
func openReader(cmd *cobra.Command, fname string) (textfile.RecordReader, error) {
if IsParquet || (!IsCSV && looksLikeParquet(fname)) {
if err := rejectTextOnlyFlags(cmd); err != nil {
return nil, err
}
pq := textfile.NewParquetFile(fname).WithNAString(NAString)
// open now so a bad path or corrupt file is reported before we start
// writing output
if err := pq.Open(); err != nil {
return nil, err
}
return pq, nil
}

var txt *textfile.DelimitedTextFile
if IsCSV {
txt = textfile.NewCSVFile(fname)
} else {
txt = textfile.NewTabFile(fname)
}

return txt.WithNoHeader(NoHeader).WithHeaderComment(HeaderComment), nil
}

// rejectTextOnlyFlags errors on flags that mean nothing for parquet input. We
// check Changed so that only flags the user actually typed complain.
func rejectTextOnlyFlags(cmd *cobra.Command) error {
for _, name := range []string{"csv", "no-header", "header-comment", "show-comments"} {
if f := cmd.Flags().Lookup(name); f != nil && f.Changed {
return fmt.Errorf("--%s cannot be used with parquet input", name)
}
}
return nil
}
13 changes: 5 additions & 8 deletions cmd/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ func init() {
viewCmd.Flags().BoolVarP(&ShowComments, "show-comments", "H", false, "Show comments")
viewCmd.Flags().BoolVarP(&ShowLineNum, "show-linenum", "L", false, "Show line number")
viewCmd.Flags().BoolVar(&IsCSV, "csv", false, "The file is a CSV file")
viewCmd.Flags().BoolVar(&IsParquet, "parquet", false, "The file is a Parquet file")
viewCmd.Flags().StringVar(&NAString, "na", "", "Value shown for NULL cells (Parquet)")
viewCmd.Flags().BoolVar(&HeaderComment, "header-comment", false, "The header is the last commented line")
viewCmd.Flags().BoolVar(&NoHeader, "no-header", false, "File has no header")
viewCmd.Flags().IntVar(&MinWidth, "min", 0, "Minimum column width")
Expand All @@ -35,16 +37,11 @@ var viewCmd = &cobra.Command{
if len(args) == 0 {
args = []string{"-"}
}
var txt *textfile.DelimitedTextFile
if !IsCSV {
txt = textfile.NewTabFile(args[0])
} else {
txt = textfile.NewCSVFile(args[0])
txt, err := openReader(cmd, args[0])
if err != nil {
er(err)
}

txt = txt.WithNoHeader(NoHeader).
WithHeaderComment(HeaderComment)

textfile.NewTextViewer(txt).
WithShowComments(ShowComments).
WithShowLineNum(ShowLineNum).
Expand Down
Binary file added examples/iris.parquet
Binary file not shown.
10 changes: 9 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,20 @@ go 1.22
require (
github.com/gizak/termui/v3 v3.1.0
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d
github.com/parquet-go/parquet-go v0.24.0
github.com/spf13/cobra v1.0.0
)

require (
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/mattn/go-runewidth v0.0.2 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/spf13/pflag v1.0.3 // indirect
golang.org/x/sys v0.21.0 // indirect
)
25 changes: 24 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
Expand Down Expand Up @@ -34,25 +36,33 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-runewidth v0.0.2 h1:UnlwIPBGaTZfPQ6T1IGzPI0EkYAQmT9fAEJ/poFC63o=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
Expand All @@ -62,7 +72,13 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d h1:x3S6kxmy49zXVVyhcnrFqxvNVCBPb2KZ9hV2RBdS840=
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/parquet-go/parquet-go v0.24.0 h1:VrsifmLPDnas8zpoHmYiWDZ1YHzLmc7NmNwPGkI2JM4=
github.com/parquet-go/parquet-go v0.24.0/go.mod h1:OqBBRGBl7+llplCvDMql8dEKaDqjaFA/VAPw+OJiNiw=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
Expand All @@ -74,6 +90,9 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
Expand Down Expand Up @@ -116,6 +135,8 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
Expand All @@ -125,6 +146,8 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
14 changes: 9 additions & 5 deletions textfile/csv_to_tab.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import (

// CSVExporter is used to export specific columns from a tab delimited file
type CSVExporter struct {
txt *DelimitedTextFile
txt RecordReader
showComments bool
}

// NewCSVExporter - create a new text exporter
func NewCSVExporter(f *DelimitedTextFile) *CSVExporter {
func NewCSVExporter(f RecordReader) *CSVExporter {
return &CSVExporter{
txt: f,
showComments: false,
Expand All @@ -36,6 +36,10 @@ func (tex *CSVExporter) WriteFile(out io.Writer) error {
for err == nil {
line, err = tex.txt.ReadLine()
if err != nil {
if err != io.EOF {
tex.txt.Close()
return err
}
break
}

Expand All @@ -48,7 +52,7 @@ func (tex *CSVExporter) WriteFile(out io.Writer) error {
}

if !wroteHeader {
if !tex.txt.noHeader {
if !tex.txt.NoHeader() {
err := tex.writeHeader(out)
if err != nil {
return err
Expand All @@ -68,10 +72,10 @@ func (tex *CSVExporter) WriteFile(out io.Writer) error {
}

func (tex *CSVExporter) writeHeader(out io.Writer) error {
if tex.txt.noHeader {
if tex.txt.NoHeader() {
return nil
}
for i, v := range tex.txt.Header {
for i, v := range tex.txt.GetHeader() {
if i > 0 {
fmt.Fprint(out, "\t")
}
Expand Down
Loading
Loading