Skip to content

Commit

Permalink
New feature: YAML<->JSON transformation
Browse files Browse the repository at this point in the history
  • Loading branch information
Mercurio committed Oct 15, 2021
1 parent cbe3400 commit 8fd90a3
Show file tree
Hide file tree
Showing 16 changed files with 328 additions and 43 deletions.
53 changes: 41 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ Limner colorizes and transforms CLI outputs.

When playing with `kubectl`, I sometimes found it hard to extract the information I needed most from the extermely **long, mono-colored** output produced by the CLI. The same things happens when I'm using `curl` to test some REST APIs which usually return a long string of JSON.

Of course I can use GUI tools like *Kubernetes Dashboard* and *Postman*, but for simple operations that need to be performed swiftly, CLIs have their own advantages. Therefore, I made limner to bring some changes to the CLIs' output.
Of course I can use GUI tools like _Kubernetes Dashboard_ and _Postman_, but for simple operations that need to be performed swiftly, CLIs have their own advantages. Therefore, I made limner to bring some changes to the CLIs' output.

## Installation

### Download a release binary

Go to [Release Page](https://github.com/SignorMercurio/limner/releases), download a release and run:

```bash
tar zxvf lm_[version]_[os]_[arch].tar.gz
cd lm_[version]_[os]_[arch]
Expand All @@ -42,13 +44,15 @@ Remember to replace the text in `[]`.
1. You'll need Go [installed](https://golang.org/doc/install).

2. Clone the repo:

```bash
git clone https://github.com/SignorMercurio/limner.git
cd limner
go build -o lm .
```

3. Run the command:

```bash
[your command] | ./lm
```
Expand All @@ -61,35 +65,60 @@ go build -o lm .

In most cases, you don't need to append any arguments when using limner as it automatically detects the format of the output.

Colorize tables:
#### Colorize tables

```bash
kubectl get po | lm
```

Colorize YAML files:
![Table colorization](img/table.png)

#### Colorize YAML files

```bash
kubectl describe deploy/nginx | lm
```

![YAML colorization](img/yml.png)

#### Colorize JSON responses

```bash
cat nginx-deploy.yml | lm
curl -s https://api.github.com/users/SignorMercurio | lm
```

Colorize JSON responses:
![JSON colorization](img/json.png)

#### Transform YAML to JSON

```bash
curl https://api.github.com/users/SignorMercurio | lm
cat nginx/deploy.yml | lm tr -i yaml -o json
```

You can always omit `-i yaml` as long as the format of input is YAML.

![YAML->JSON transformation](img/yml2json.png)

#### Transform JSON to YAML

```bash
curl -s https://jsonplaceholder.typicode.com/users/1/albums | lm tr -o yml
```

![JSON->YAML transformation](img/json2yml.png)

> TODO: Add support for more formats and transformation between different formats.
### Create a shortcut

Take `kubectl` as an example.
Take `kubectl` as an example.

#### Bash

Suppose you've already [configured autocompletion](https://kubernetes.io/docs/tasks/tools/included/optional-kubectl-configs-bash-linux/) for `kubectl` (Optional).

In your `.bash_profile` or `.bashrc`, append the following lines:

```bash
function k() {kubectl $@ | lm}
complete -o default -F __start_kubectl k
Expand All @@ -100,15 +129,15 @@ complete -o default -F __start_kubectl k
Suppose you've already [configured autocompletion](https://kubernetes.io/docs/tasks/tools/included/optional-kubectl-configs-zsh/) for `kubectl` (Optional).

In your `.zprofile` or `.zshrc`, append the following lines:

```bash
function k() {kubectl $@ | lm}
compdef k=kubectl
```

After the above steps, you'll be able to use `kubectl` with color and autocompletion like:
```bash
k get po
```

![Using a shortcut](img/shortcut.png)

### Non-terminal output

Expand Down Expand Up @@ -166,8 +195,8 @@ Thank you for willing to contribute to this project!
- [x] JSON
- [x] Tables
- [ ] ...
- [ ] Simple data format transformation
- [ ] YAML <-> JSON
- [x] Simple data format transformation
- [x] YAML <-> JSON
- [ ] ...

If you have any suggestions for the project, please don't hesitate to open an [issue](https://github.com/SignorMercurio/limner/issues) or [pull request](https://github.com/SignorMercurio/limner/pulls).
Expand Down
3 changes: 2 additions & 1 deletion cmd/tr.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ func NewTrCmd() *cobra.Command {
Short: "tr helps to transform data format",
Long: `tr helps to transform data format
Example:
curl -s https://api.github.com/users/SignorMercurio | lm tr -i json -o yaml ("-i json" can be omitted)`,
curl -s https://api.github.com/users/SignorMercurio | lm tr -i json -o yaml ("-i json" can be omitted)
cat nginx.yml | lm tr -o json`,
RunE: func(cmd *cobra.Command, args []string) error {
var err error
if inType == outType {
Expand Down
Binary file added img/json.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/json2yml.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/shortcut.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/table.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/yml.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/yml2json.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 12 additions & 8 deletions printer/color.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package printer

import (
"encoding/json"
"fmt"
"io"
"strings"
Expand All @@ -15,26 +14,31 @@ type ColorPrinter struct {
}

func (cp *ColorPrinter) Print(buf string, w io.Writer) {
var printer Printer = &SingleColorPrinter{Color: stringColor}
var jsonObj map[string]interface{}
var (
printer Printer = &SingleColorPrinter{Color: stringColor}
bufByte = []byte(buf)
jsonObj interface{}
isJson bool
)

// change the printer if type is already enforced
switch cp.Type {
case "yaml", "yml":
printer = NewYamlPrinter()
case "json":
if err := json.Unmarshal([]byte(buf), &jsonObj); err != nil {
fmt.Fprintln(w, color.Apply("Failed to unmarshal json, using default printer", color.Yellow))
} else {
if jsonObj, isJson = util.ShouldJson(bufByte); isJson {
printer = NewJsonPrinter(jsonObj)
} else {
fmt.Fprintln(w, color.Apply("Failed to unmarshal json, using default printer", color.Yellow))
}
case "table":
printer = NewTablePrinter(ColorStatus)
// case "xml":
default:
// otherwise, try to determine the type
// try json first
jsonObj, isJson = util.ShouldJson(bufByte)
switch {
case util.ShouldJson([]byte(buf), &jsonObj):
case isJson:
printer = NewJsonPrinter(jsonObj)
case util.ShouldTable(buf):
printer = NewTablePrinter(ColorStatus)
Expand Down
4 changes: 2 additions & 2 deletions printer/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

type JsonPrinter struct {
jsonObj map[string]interface{}
jsonObj interface{}
}

func (jp *JsonPrinter) Print(buf string, w io.Writer) {
Expand All @@ -21,7 +21,7 @@ func (jp *JsonPrinter) Print(buf string, w io.Writer) {
}
}

func NewJsonPrinter(jsonObj map[string]interface{}) *JsonPrinter {
func NewJsonPrinter(jsonObj interface{}) *JsonPrinter {
return &JsonPrinter{
jsonObj: jsonObj,
}
Expand Down
12 changes: 12 additions & 0 deletions transformer/format.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package transformer

import (
"fmt"

"github.com/SignorMercurio/limner/color"
)

type FormatTransformer struct {
InType string
OutType string
Expand All @@ -11,7 +17,13 @@ func (ft *FormatTransformer) Transform(input []byte) ([]byte, error) {
switch ft.OutType {
case "yaml", "yml":
trans = NewYamlTransformer(ft.InType)
case "json":
trans = NewJsonTransformer(ft.InType)
}

return trans.Transform(input)
}

func unknownInput() {
fmt.Println(color.Apply("Unknown input format, using default transformer", color.Yellow))
}
40 changes: 40 additions & 0 deletions transformer/json.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package transformer

import (
"encoding/json"

"github.com/SignorMercurio/limner/util"
"gopkg.in/yaml.v3"
)

type JsonTransformer struct {
Type string
obj util.Obj
}

func (jt *JsonTransformer) Transform(input []byte) ([]byte, error) {
// fill the obj if the type is already enforced
switch jt.Type {
case "yaml":
if err := yaml.Unmarshal(input, &jt.obj); err == nil {
return json.MarshalIndent(jt.obj, "", " ")
}
default:
// otherwise, try to determine the type
switch {
case util.ShouldYaml(string(input)):
if err := yaml.Unmarshal(input, &jt.obj); err == nil {
return json.MarshalIndent(jt.obj, "", " ")
}
}
}

unknownInput()
return input, nil
}

func NewJsonTransformer(Type string) *JsonTransformer {
return &JsonTransformer{
Type: Type,
}
}
Loading

0 comments on commit 8fd90a3

Please sign in to comment.