Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect input format based on file name extension #1582

Merged
merged 4 commits into from
Mar 8, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
221 changes: 221 additions & 0 deletions acceptance_tests/inputs-format-auto.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
#!/bin/bash

setUp() {
rm test*.yml 2>/dev/null || true
rm test*.json 2>/dev/null || true
rm test*.properties 2>/dev/null || true
rm test*.csv 2>/dev/null || true
rm test*.tsv 2>/dev/null || true
rm test*.xml 2>/dev/null || true
}

testInputJson() {
cat >test.json <<EOL
{ "mike" : { "things": "cool" } }
EOL

read -r -d '' expected << EOM
mike:
things: cool
EOM

X=$(./yq test.json)
assertEquals "$expected" "$X"

X=$(./yq ea test.json)
assertEquals "$expected" "$X"
}

testInputProperties() {
cat >test.properties <<EOL
mike.things = hello
EOL

read -r -d '' expected << EOM
mike:
things: hello
EOM

X=$(./yq e test.properties)
assertEquals "$expected" "$X"

X=$(./yq ea test.properties)
assertEquals "$expected" "$X"
}

testInputPropertiesGitHubAction() {
cat >test.properties <<EOL
mike.things = hello
EOL

read -r -d '' expected << EOM
mike:
things: hello
EOM

X=$(cat /dev/null | ./yq e test.properties)
assertEquals "$expected" "$X"

X=$(cat /dev/null | ./yq ea test.properties)
assertEquals "$expected" "$X"
}

testInputCSV() {
cat >test.csv <<EOL
fruit,yumLevel
apple,5
banana,4
EOL

read -r -d '' expected << EOM
- fruit: apple
yumLevel: 5
- fruit: banana
yumLevel: 4
EOM

X=$(./yq e test.csv)
assertEquals "$expected" "$X"

X=$(./yq ea test.csv)
assertEquals "$expected" "$X"
}

testInputCSVUTF8() {
read -r -d '' expected << EOM
- id: 1
first: john
last: smith
- id: 1
first: jane
last: smith
EOM

X=$(./yq utf8.csv)
assertEquals "$expected" "$X"
}

testInputTSV() {
cat >test.tsv <<EOL
fruit yumLevel
apple 5
banana 4
EOL

read -r -d '' expected << EOM
- fruit: apple
yumLevel: 5
- fruit: banana
yumLevel: 4
EOM

X=$(./yq e test.tsv)
assertEquals "$expected" "$X"

X=$(./yq ea test.tsv)
assertEquals "$expected" "$X"
}




testInputXml() {
cat >test.xml <<EOL
<cat legs="4">BiBi</cat>
EOL

read -r -d '' expected << EOM
cat:
+content: BiBi
+@legs: "4"
EOM

X=$(./yq e test.xml)
assertEquals "$expected" "$X"

X=$(./yq ea test.xml)
assertEquals "$expected" "$X"
}

testInputXmlNamespaces() {
cat >test.xml <<EOL
<?xml version="1.0"?>
<map xmlns="some-namespace" xmlns:xsi="some-instance" xsi:schemaLocation="some-url">
</map>
EOL

read -r -d '' expected << EOM
+p_xml: version="1.0"
map:
+@xmlns: some-namespace
+@xmlns:xsi: some-instance
+@xsi:schemaLocation: some-url
EOM

X=$(./yq e test.xml)
assertEquals "$expected" "$X"

X=$(./yq ea test.xml)
assertEquals "$expected" "$X"
}

testInputXmlRoundtrip() {
cat >test.xml <<EOL
<?xml version="1.0"?>
<!DOCTYPE config SYSTEM "/etc/iwatch/iwatch.dtd" >
<map xmlns="some-namespace" xmlns:xsi="some-instance" xsi:schemaLocation="some-url">Meow</map>
EOL

read -r -d '' expected << EOM
<?xml version="1.0"?>
<!DOCTYPE config SYSTEM "/etc/iwatch/iwatch.dtd" >
<map xmlns="some-namespace" xmlns:xsi="some-instance" xsi:schemaLocation="some-url">Meow</map>
EOM

X=$(./yq -o=xml test.xml)
assertEquals "$expected" "$X"

X=$(./yq ea -o=xml test.xml)
assertEquals "$expected" "$X"
}


testInputXmlStrict() {
cat >test.xml <<EOL
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY writer "Catherine.">
<!ENTITY copyright "(r) Great">
]>
<root>
<item>&writer;&copyright;</item>
</root>
EOL

X=$(./yq --xml-strict-mode test.xml -o=xml 2>&1)
assertEquals 1 $?
assertEquals "Error: bad file 'test.xml': XML syntax error on line 7: invalid character entity &writer;" "$X"

X=$(./yq ea --xml-strict-mode test.xml -o=xml 2>&1)
assertEquals "Error: bad file 'test.xml': XML syntax error on line 7: invalid character entity &writer;" "$X"
}

testInputXmlGithubAction() {
cat >test.xml <<EOL
<cat legs="4">BiBi</cat>
EOL

read -r -d '' expected << EOM
cat:
+content: BiBi
+@legs: "4"
EOM

X=$(cat /dev/null | ./yq e test.xml)
assertEquals "$expected" "$X"

X=$(cat /dev/null | ./yq ea test.xml)
assertEquals "$expected" "$X"
}

source ./scripts/shunit2
3 changes: 2 additions & 1 deletion cmd/constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ var unwrapScalar = false
var writeInplace = false
var outputToJSON = false
var outputFormat = "yaml"
var inputFormat = "yaml"
var inputFormatDefault = "yaml"
var inputFormat = ""

var exitStatus = false
var forceColor = false
Expand Down
7 changes: 6 additions & 1 deletion cmd/evaluate_all_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,12 @@ func evaluateAll(cmd *cobra.Command, args []string) (cmdError error) {
return err
}

decoder, err := configureDecoder(true)
inputFilename := ""
if len(args) > 0 {
inputFilename = args[0]
}

decoder, err := configureDecoder(true, inputFilename)
if err != nil {
return err
}
Expand Down
7 changes: 6 additions & 1 deletion cmd/evalute_sequence_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,12 @@ func evaluateSequence(cmd *cobra.Command, args []string) (cmdError error) {

printer := yqlib.NewPrinter(encoder, printerWriter)

decoder, err := configureDecoder(false)
inputFilename := ""
if len(args) > 0 {
inputFilename = args[0]
}

decoder, err := configureDecoder(false, inputFilename)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ yq -P sample.json
}

rootCmd.PersistentFlags().StringVarP(&outputFormat, "output-format", "o", "yaml", "[yaml|y|json|j|props|p|xml|x] output format type.")
rootCmd.PersistentFlags().StringVarP(&inputFormat, "input-format", "p", "yaml", "[yaml|y|props|p|xml|x] parse format for input. Note that json is a subset of yaml.")
rootCmd.PersistentFlags().StringVarP(&inputFormat, "input-format", "p", "", "[yaml|y|props|p|xml|x] parse format for input. Note that json is a subset of yaml.")

rootCmd.PersistentFlags().StringVar(&yqlib.ConfiguredXMLPreferences.AttributePrefix, "xml-attribute-prefix", yqlib.ConfiguredXMLPreferences.AttributePrefix, "prefix for xml attributes")
rootCmd.PersistentFlags().StringVar(&yqlib.ConfiguredXMLPreferences.ContentName, "xml-content-name", yqlib.ConfiguredXMLPreferences.ContentName, "name for xml content (if no attribute name is present).")
Expand Down
7 changes: 6 additions & 1 deletion cmd/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@ func initCommand(cmd *cobra.Command, args []string) (string, []string, error) {
return expression, args, nil
}

func configureDecoder(evaluateTogether bool) (yqlib.Decoder, error) {
func configureDecoder(evaluateTogether bool, inputFilename string) (yqlib.Decoder, error) {
if inputFormat == "" {
inputFormat = yqlib.InputFormatFromFilename(inputFilename, inputFormatDefault)
} else {
yqlib.GetLogger().Debugf("user specified inputFormat '%s'", inputFormat)
}
yqlibInputFormat, err := yqlib.InputFormatFromString(inputFormat)
if err != nil {
return nil, err
Expand Down
20 changes: 18 additions & 2 deletions pkg/yqlib/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package yqlib
import (
"fmt"
"io"
"strings"
)

type InputFormat uint
Expand All @@ -25,11 +26,11 @@ type Decoder interface {

func InputFormatFromString(format string) (InputFormat, error) {
switch format {
case "yaml", "y":
case "yaml", "yml", "y":
return YamlInputFormat, nil
case "xml", "x":
return XMLInputFormat, nil
case "props", "p":
case "properties", "props", "p":
return PropertiesInputFormat, nil
case "json", "ndjson", "j":
return JsonInputFormat, nil
Expand All @@ -41,3 +42,18 @@ func InputFormatFromString(format string) (InputFormat, error) {
return 0, fmt.Errorf("unknown format '%v' please use [yaml|xml|props]", format)
}
}

func InputFormatFromFilename(filename string, defaultFormat string) string {
if filename != "" {
GetLogger().Debugf("checking filename '%s' for inputFormat", filename)
nPos := strings.LastIndex(filename, ".")
if nPos > -1 {
inputFormat := filename[nPos+1:]
GetLogger().Debugf("detected inputFormat '%s'", inputFormat)
return inputFormat
}
}

GetLogger().Debugf("using default inputFormat '%s'", defaultFormat)
return defaultFormat
}