Skip to content

Commit bef87fc

Browse files
authored
Merge pull request #6 from spatialcurrent/pipe
Compatibility with go-pipe
2 parents 4798aa2 + e0b7981 commit bef87fc

43 files changed

Lines changed: 1706 additions & 254 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.circleci/config.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ version: 2.1
22
executors:
33
base:
44
docker:
5-
- image: circleci/golang:1.12.1
5+
- image: circleci/golang:1.12
66
working_directory: /go/src/github.com/spatialcurrent/go-simple-serializer
77
jobs:
88
pre_deps_golang:
99
executor: base
1010
steps:
1111
- checkout
12-
- run: go get -d ./...
12+
- run: make deps
1313
- run: sudo chown -R circleci /go/src
1414
- save_cache:
1515
key: v1-go-src-{{ .Branch }}-{{ .Revision }}
@@ -40,7 +40,7 @@ jobs:
4040
- run:
4141
name: Download and install staticheck
4242
command: go get -u honnef.co/go/tools/cmd/staticcheck
43-
- run: bash scripts/test.sh
43+
- run: make test
4444
validate:
4545
executor: base
4646
steps:
@@ -68,7 +68,7 @@ jobs:
6868
keys:
6969
- v1-go-src-{{ .Branch }}-{{ .Revision }}
7070
- run: go get github.com/inconshreveable/mousetrap # for windows CLI builds
71-
- run: bash scripts/build_cli.sh
71+
- run: make build_cli
7272
- store_artifacts:
7373
path: bin
7474
destination: /
@@ -82,7 +82,7 @@ jobs:
8282
- run:
8383
name: Install GopherJS
8484
command: go get -u github.com/gopherjs/gopherjs
85-
- run: bash scripts/build_javascript.sh
85+
- run: make build_javascript
8686
- store_artifacts:
8787
path: bin
8888
destination: /
@@ -93,7 +93,7 @@ jobs:
9393
- restore_cache:
9494
keys:
9595
- v1-go-src-{{ .Branch }}-{{ .Revision }}
96-
- run: bash scripts/build_so.sh
96+
- run: make build_so
9797
- store_artifacts:
9898
path: bin
9999
destination: /

Makefile

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# =================================================================
2+
#
3+
# Copyright (C) 2019 Spatial Current, Inc. - All Rights Reserved
4+
# Released as open source under the MIT License. See LICENSE file.
5+
#
6+
# =================================================================
7+
8+
ifdef GOPATH
9+
GCFLAGS=-trimpath=$(shell printenv GOPATH)/src
10+
else
11+
GCFLAGS=-trimpath=$(shell go env GOPATH)/src
12+
endif
13+
14+
LDFLAGS=-X main.gitBranch=$(shell git branch | grep \* | cut -d ' ' -f2) -X main.gitCommit=$(shell git rev-list -1 HEAD)
15+
16+
ifndef DEST
17+
DEST=bin
18+
endif
19+
20+
deps:
21+
go get -d -t ./...
22+
23+
fmt:
24+
go fmt $$(go list ./... )
25+
26+
vet:
27+
go vet $$(go list ./...)
28+
29+
test:
30+
bash scripts/test.sh
31+
32+
bin/gss_darwin_amd64:
33+
GOOS=darwin GOARCH=amd64 go build -o $(DEST)/gss_darwin_amd64 -gcflags="$(GCFLAGS)" -ldflags="$(LDFLAGS)" github.com/spatialcurrent/go-simple-serializer/cmd/gss
34+
35+
bin/gss_linux_amd64:
36+
GOOS=linux GOARCH=amd64 go build -o $(DEST)/gss_linux_amd64 -gcflags="$(GCFLAGS)" -ldflags="$(LDFLAGS)" github.com/spatialcurrent/go-simple-serializer/cmd/gss
37+
38+
bin/gss_windows_amd64.exe:
39+
GOOS=windows GOARCH=amd64 go build -o $(DEST)/gss_windows_amd64.exe -gcflags="$(GCFLAGS)" -ldflags="$(LDFLAGS)" github.com/spatialcurrent/go-simple-serializer/cmd/gss
40+
41+
bin/gss_linux_arm64:
42+
GOOS=linux GOARCH=arm64 go build -o $(DEST)/gss_linux_arm64 -gcflags="$(GCFLAGS)" -ldflags="$(LDFLAGS)" github.com/spatialcurrent/go-simple-serializer/cmd/gss
43+
44+
# Build Shared Object
45+
bin/gss.so:
46+
go build -o $(DEST)/gss.so -buildmode=c-shared -ldflags "$(LDFLAGS)" -gcflags="$(GCFLAGS)" github.com/spatialcurrent/go-simple-serializer/plugins/gss
47+
48+
# Build JavaScript Library
49+
bin/gss.js:
50+
gopherjs build -o $(DEST)/gss.js github.com/spatialcurrent/go-simple-serializer/cmd/gss.js
51+
52+
# Build Minified JavaScript Library
53+
bin/gss.min.js:
54+
gopherjs build -m -o $(DEST)/gss.min.js github.com/spatialcurrent/go-simple-serializer/cmd/gss.js
55+
56+
# Build Android Archive Library
57+
bin/gss.aar:
58+
gomobile bind -target android -javapkg=com.spatialcurrent -o $(DEST)/gss.aar -gcflags="$(GCFLAGS)" github.com/spatialcurrent/go-simple-serializer/gss
59+
60+
build_cli: bin/gss_darwin_amd64 bin/gss_linux_amd64 bin/gss_windows_amd64.exe bin/gss_linux_arm64
61+
62+
build_javascript: bin/gss.js bin/gss.min.js
63+
64+
build_android: bin/gss.arr
65+
66+
build_so: bin/gss.so
67+
68+
build: build_cli build_javascript build_so build_android
69+
70+
install:
71+
go install -gcflags="$(GCFLAGS)" -ldflags="$(LDFLAGS)" github.com/spatialcurrent/go-simple-serializer/cmd/gss
72+
73+
clean:
74+
rm -fr bin

README.md

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,38 @@ Using cross compilers, this library can also be called by other languages. This
1414

1515
**CLI**
1616

17-
You can use the command line tool to convert between formats.
17+
You can use the command line tool to convert between serialization formats.
1818

1919
```
20-
Usage: gss -i INPUT_FORMAT -o OUTPUT_FORMAT [-h HEADER] [-c COMMENT]
21-
Options:
22-
-c string
23-
The input comment character, e.g., #. Commented lines are not sent to output.
24-
-h string
25-
The input header if the stdin input has no header.
26-
-help
27-
Print help.
28-
-i string
29-
The input format: bson, csv, tsv, hcl, hcl2, json, jsonl, properties, toml, yaml
30-
-o string
31-
The output format: bson, csv, tsv, hcl, hcl2, json, jsonl, properties, toml, yaml
32-
-version
33-
Prints version to stdout.
20+
gss is a simple program for serializing/deserializing data.
21+
22+
Usage:
23+
gss [flags]
24+
gss [command]
25+
26+
Available Commands:
27+
completion Generates bash completion scripts
28+
help Help about any command
29+
version print version information to stdout
30+
31+
Flags:
32+
-a, --async async processing
33+
-h, --help help for gss
34+
-c, --input-comment string The input comment character, e.g., #. Commented lines are not sent to output.
35+
-i, --input-format string The input format: bson, csv, tsv, hcl, hcl2, json, jsonl, properties, toml, yaml
36+
--input-header strings The input header if the stdin input has no header.
37+
--input-lazy-quotes allows lazy quotes for CSV and TSV
38+
-l, --input-limit int The input limit (default -1)
39+
--input-skip-lines int The number of lines to skip before processing
40+
-t, --input-trim trim input lines
41+
-o, --output-format string The output format: bson, csv, tsv, hcl, hcl2, json, jsonl, properties, toml, yaml
42+
--output-header strings The output header if the stdout output has no header.
43+
-n, --output-limit int the output limit (default -1)
44+
-p, --output-pretty print pretty output
45+
-s, --output-sorted sort output
46+
--verbose Print debug info to stdout
47+
48+
Use "gss [command] --help" for more information about a command.
3449
```
3550

3651
**Go**
@@ -131,23 +146,23 @@ language=$(cat .travis.yml | ./gss_linux_amd64 -i yaml -o json -c '#' | jq .lang
131146

132147
**CLI**
133148

134-
The `build_cli.sh` script is used to build executables for Linux and Windows.
149+
The `make build_cli` script is used to build executables for Linux and Windows.
135150

136151
**JavaScript**
137152

138-
You can compile GSS to pure JavaScript with the `scripts/build_javascript.sh` script.
153+
You can compile GSS to pure JavaScript with the `make build_javascript` script.
139154

140155
**Android**
141156

142-
The `build_android.sh` script is used to build an [Android Archive](https://developer.android.com/studio/projects/android-library) (AAR) file and associated Javadocs.
157+
The `make build_android` script is used to build an [Android Archive](https://developer.android.com/studio/projects/android-library) (AAR) file and associated Javadocs.
143158

144159
**Shared Object**
145160

146-
The `build_so.sh` script is used to build a Shared Object (`*.go`), which can be called by `C`, `C++`, and `Python` on Linux machines.
161+
The `make build_so` script is used to build a Shared Object (`*.go`), which can be called by `C`, `C++`, and `Python` on Linux machines.
147162

148163
**Changing Destination**
149164

150-
The default destination for build artifacts is `go-simple-serializer/bin`, but you can change the destination with a CLI argument. For building on a Chromebook consider saving the artifacts in `/usr/local/go/bin`, e.g., `bash scripts/build_cli.sh /usr/local/go/bin`
165+
The default destination for build artifacts is `go-simple-serializer/bin`, but you can change the destination with an environment variable. For building on a Chromebook consider saving the artifacts in `/usr/local/go/bin`, e.g., `DEST=/usr/local/go/bin make build_cli`
151166

152167
# Contributing
153168

cmd/gss/main.go

Lines changed: 117 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ package main
1111

1212
import (
1313
"fmt"
14+
"io"
1415
"io/ioutil"
1516
"os"
1617
"strings"
@@ -23,13 +24,52 @@ import (
2324
)
2425

2526
import (
27+
"github.com/spatialcurrent/go-pipe/pkg/pipe"
2628
"github.com/spatialcurrent/go-simple-serializer/gss"
29+
"github.com/spatialcurrent/go-simple-serializer/pkg/iterator"
30+
"github.com/spatialcurrent/go-simple-serializer/pkg/jsonl"
31+
"github.com/spatialcurrent/go-simple-serializer/pkg/sv"
2732
)
2833

2934
var gitTag string
3035
var gitBranch string
3136
var gitCommit string
3237

38+
func buildValueSerializer(decimal bool, noDataValue string) func(object interface{}) (string, error) {
39+
if decimal {
40+
return sv.DecimalValueSerializer(noDataValue)
41+
}
42+
return sv.DefaultValueSerializer(noDataValue)
43+
}
44+
45+
func buildWriter(outputWriter io.Writer, outputFormat string, outputHeader []interface{}, outputValueSerializer func(object interface{}) (string, error)) (pipe.Writer, error) {
46+
if outputFormat == "csv" || outputFormat == "tsv" {
47+
separator, err := sv.FormatToSeparator(outputFormat)
48+
if err != nil {
49+
return nil, err
50+
}
51+
return sv.NewWriter(outputWriter, separator, outputHeader, outputValueSerializer), nil
52+
} else if outputFormat == "jsonl" {
53+
return jsonl.NewWriter(outputWriter), nil
54+
}
55+
return nil, fmt.Errorf("invalid format %q", outputFormat)
56+
}
57+
58+
func canStream(inputFormat string, outputFormat string, outputSorted bool) bool {
59+
if !outputSorted {
60+
if inputFormat == "csv" || inputFormat == "tsv" {
61+
if outputFormat == "csv" || outputFormat == "tsv" || outputFormat == "jsonl" {
62+
return true
63+
}
64+
} else if inputFormat == "jsonl" {
65+
if outputFormat == "jsonl" {
66+
return true
67+
}
68+
}
69+
}
70+
return false
71+
}
72+
3373
func main() {
3474
rootCommand := &cobra.Command{
3575
Use: "gss",
@@ -57,25 +97,84 @@ func main() {
5797
return errors.New("output-format is required")
5898
}
5999

100+
outputHeader := v.GetStringSlice("output-header")
101+
102+
outputSorted := v.GetBool("output-sorted")
103+
104+
outputValueSerializer := buildValueSerializer(v.GetBool("output-decimal"), v.GetString("output-no-data-value"))
105+
106+
if canStream(inputFormat, outputFormat, outputSorted) {
107+
108+
p := pipe.NewBuilder()
109+
110+
it, errorIterator := iterator.NewIterator(&iterator.NewIteratorInput{
111+
Reader: os.Stdin,
112+
Format: inputFormat,
113+
SkipLines: v.GetInt("input-skip-lines"),
114+
SkipBlanks: true,
115+
SkipComments: true,
116+
Comment: v.GetString("input-comment"),
117+
Trim: v.GetBool("input-trim"),
118+
})
119+
if it == nil {
120+
return errors.New(fmt.Sprintf("error building input iterator with format %q", inputFormat))
121+
}
122+
if errorIterator != nil {
123+
return errors.Wrap(errorIterator, "error creating input iterator")
124+
}
125+
p = p.Input(it)
126+
127+
if inputLimit := v.GetInt("input-limit"); inputLimit >= 0 {
128+
p = p.InputLimit(inputLimit)
129+
}
130+
131+
outputColumns := make([]interface{}, 0, len(outputHeader))
132+
for _, str := range outputHeader {
133+
outputColumns = append(outputColumns, str)
134+
}
135+
136+
w, errorWriter := buildWriter(
137+
os.Stdout,
138+
outputFormat,
139+
outputColumns,
140+
outputValueSerializer)
141+
if errorWriter != nil {
142+
return errors.Wrap(errorWriter, "error building output writer")
143+
}
144+
p = p.Output(w)
145+
146+
if outputLimit := v.GetInt("output-limit"); outputLimit >= 0 {
147+
p = p.OutputLimit(outputLimit)
148+
}
149+
150+
errorRun := p.Run()
151+
if errorRun != nil {
152+
return errors.Wrap(errorRun, "error piping data")
153+
}
154+
return nil
155+
}
156+
60157
inputBytes, err := ioutil.ReadAll(os.Stdin)
61158
if err != nil {
62159
return errors.Wrap(err, "error reading from stdin")
63160
}
64161

65162
outputString, err := gss.Convert(&gss.ConvertInput{
66-
InputBytes: inputBytes,
67-
InputFormat: inputFormat,
68-
InputHeader: v.GetStringSlice("input-header"),
69-
InputComment: v.GetString("input-comment"),
70-
InputLazyQuotes: v.GetBool("input-lazy-quotes"),
71-
InputSkipLines: v.GetInt("input-skip-lines"),
72-
InputLimit: v.GetInt("input-limit"),
73-
OutputFormat: outputFormat,
74-
OutputHeader: v.GetStringSlice("output-header"),
75-
OutputLimit: v.GetInt("output-limit"),
76-
OutputPretty: v.GetBool("output-pretty"),
77-
Async: v.GetBool("async"),
78-
Verbose: v.GetBool("verbose"),
163+
InputBytes: inputBytes,
164+
InputFormat: inputFormat,
165+
InputHeader: v.GetStringSlice("input-header"),
166+
InputComment: v.GetString("input-comment"),
167+
InputLazyQuotes: v.GetBool("input-lazy-quotes"),
168+
InputSkipLines: v.GetInt("input-skip-lines"),
169+
InputLimit: v.GetInt("input-limit"),
170+
OutputFormat: outputFormat,
171+
OutputHeader: v.GetStringSlice("output-header"),
172+
OutputLimit: v.GetInt("output-limit"),
173+
OutputPretty: v.GetBool("output-pretty"),
174+
OutputSorted: v.GetBool("output-sorted"),
175+
OutputValueSerializer: outputValueSerializer,
176+
Async: v.GetBool("async"),
177+
Verbose: v.GetBool("verbose"),
79178
})
80179
if err != nil {
81180
return errors.Wrap(err, "error converting")
@@ -91,14 +190,17 @@ func main() {
91190
flags.Bool("input-lazy-quotes", false, "allows lazy quotes for CSV and TSV")
92191
flags.Int("input-skip-lines", gss.NoSkip, "The number of lines to skip before processing")
93192
flags.IntP("input-limit", "l", gss.NoLimit, "The input limit")
193+
flags.BoolP("input-trim", "t", false, "trim input lines")
94194
flags.StringP("output-format", "o", "", "The output format: "+strings.Join(gss.Formats, ", "))
95195
flags.StringSlice("output-header", []string{}, "The output header if the stdout output has no header.")
96-
flags.Int("output-limit", gss.NoLimit, "the output limit")
196+
flags.IntP("output-limit", "n", gss.NoLimit, "the output limit")
97197
flags.BoolP("output-pretty", "p", false, "print pretty output")
198+
flags.BoolP("output-sorted", "s", false, "sort output")
199+
flags.BoolP("output-decimal", "d", false, "when converting floats to strings use decimals rather than scientific notation")
200+
flags.StringP("output-no-data-value", "0", "", "no data value, e.g., used for missing values when converting JSON to CSV")
98201
flags.BoolP("async", "a", false, "async processing")
99202
flags.Bool("verbose", false, "Print debug info to stdout")
100203

101-
102204
completionCommandLong := ""
103205
if _, err := os.Stat("/etc/bash_completion.d/"); !os.IsNotExist(err) {
104206
completionCommandLong = "To install completion scripts run:\ngss completion > /etc/bash_completion.d/gss"

0 commit comments

Comments
 (0)