diff --git a/README.md b/README.md index d98df0f..83ed1d8 100644 --- a/README.md +++ b/README.md @@ -128,36 +128,29 @@ Python expressions are **not** supported. ## Layering data from multiple sources By default envcat reads variables only from your shell environment. -With `-i` you can additionally source data from YAML, JSON or TOML files. +With `-i` you can additionally source data from YAML, JSON or TOML files. +With `-s` you can override variables directly on the command line. -**Example:** +Both flags can be given multiple times. + +**Examples:** ```bash -# Override an env-var via YAML file -$ export FOO=bar -$ echo "foo: batz" >demo.yaml +# Override vars with YAML file +$ export FOO=from_env +$ echo "foo: from_file" >demo.yaml $ envcat -i env -i yaml:demo.yaml FOO -{"FOO":"batz"} - -# We can also ignore the environment -# altogether and use only file sources. -$ envcat -i yaml:foo.yaml -i json:bar.json FOO -{"FOO":"batz"} -``` - -With `-s` you can overwrite values directly. +{"FOO":"from_file"} -**Example:** +# Override a var with `-s` +$ envcat -i env -i yaml:demo.yaml -s FOO=from_arg FOO +{"FOO":"from_arg"} -```bash -$ export FOO=bar -$ envcat -s FOO=batz HELLO -batz +# Layer data from foo.yaml, the environment, +# JSON from stdin and lastly override FOO +$ envcat -i yaml:foo.yaml -i env -i json:- -s FOO=bar [..] ``` -`-s` takes precedence over all other data sources. - - ### Input normalization envcat flattens the structure of data sourced via `-i` as follows. diff --git a/docs/templates/README.md.j2 b/docs/templates/README.md.j2 index 724271d..6577913 100644 --- a/docs/templates/README.md.j2 +++ b/docs/templates/README.md.j2 @@ -131,36 +131,29 @@ Python expressions are **not** supported. ## Layering data from multiple sources By default envcat reads variables only from your shell environment. -With `-i` you can additionally source data from YAML, JSON or TOML files. +With `-i` you can additionally source data from YAML, JSON or TOML files. +With `-s` you can override variables directly on the command line. -**Example:** +Both flags can be given multiple times. + +**Examples:** ```bash -# Override an env-var via YAML file -$ export FOO=bar -$ echo "foo: batz" >demo.yaml +# Override vars with YAML file +$ export FOO=from_env +$ echo "foo: from_file" >demo.yaml $ envcat -i env -i yaml:demo.yaml FOO -{"FOO":"batz"} - -# We can also ignore the environment -# altogether and use only file sources. -$ envcat -i yaml:foo.yaml -i json:bar.json FOO -{"FOO":"batz"} -``` - -With `-s` you can overwrite values directly. +{"FOO":"from_file"} -**Example:** +# Override a var with `-s` +$ envcat -i env -i yaml:demo.yaml -s FOO=from_arg FOO +{"FOO":"from_arg"} -```bash -$ export FOO=bar -$ envcat -s FOO=batz HELLO -batz +# Layer data from foo.yaml, the environment, +# JSON from stdin and lastly override FOO +$ envcat -i yaml:foo.yaml -i env -i json:- -s FOO=bar [..] ``` -`-s` takes precedence over all other data sources. - - ### Input normalization envcat flattens the structure of data sourced via `-i` as follows. diff --git a/fixtures/input/test_normalized.yaml b/fixtures/input/test_normalized.yaml new file mode 100644 index 0000000..e133965 --- /dev/null +++ b/fixtures/input/test_normalized.yaml @@ -0,0 +1,43 @@ +--- +NAME: John Doe +AGE: "30" +CITY: New York +HOBBIES_0: Reading +HOBBIES_1: Hiking +HOBBIES_2: Cooking +MATRIX_0_0: "1" +MATRIX_0_1: "2" +MATRIX_0_2: "3" +MATRIX_1_0: "4" +MATRIX_1_1: "5" +MATRIX_1_2: "6" +MATRIX_2_0: "7" +MATRIX_2_1: "8" +MATRIX_2_2: "9" +PEOPLE_0_NAME: Alice +PEOPLE_0_AGE: "25" +PEOPLE_1_NAME: Bob +PEOPLE_1_AGE: "28" +ADDRESS_STREET: 123 Main St +ADDRESS_CITY: Springfield +ADDRESS_ZIP: "12345" +EMPLOYEE_NAME: Jane Smith +EMPLOYEE_DEPARTMENT: HR +EMPLOYEE_CONTACT_EMAIL: jane@example.com +EMPLOYEE_CONTACT_PHONE: 555-123-4567 +EMPLOYEE_PROJECTS_0: Project A +EMPLOYEE_PROJECTS_1: Project B +EMPLOYEE_SKILLS_0: Skill 1 +EMPLOYEE_SKILLS_1: Skill 2 +COLORS_0: Red +COLORS_1: Green +COLORS_2: Blue +PERSON_FIRST_NAME: Mary +PERSON_LAST_NAME: Johnson +DESCRIPTION: 'This is a multi-line + + description in YAML. + + It can span multiple lines. + +' diff --git a/spec/envcat/cli/input_spec.cr b/spec/envcat/cli/input_spec.cr index 0f9f432..c826d19 100644 --- a/spec/envcat/cli/input_spec.cr +++ b/spec/envcat/cli/input_spec.cr @@ -3,21 +3,59 @@ require "../../../src/envcat/cli" require "digest/sha256" describe Envcat::Cli do - describe "-i json:fixtures/input/test.json -s AGE=42" do - it "overwrites value from json" do + {% for fmt in %w[json yaml toml] %} + describe "-i {{fmt.id}}:fixtures/input/test.{{fmt.id}}" do + it "parses and normalizes {{fmt.id}}" do expect_output(nil, nil) { |o, e, i| - Envcat::Cli.invoke(%w[-f kv -i json:fixtures/input/test.json -s AGE=42 AGE], o, e, i) - o.to_s.should eq("AGE=42\n") + Envcat::Cli.invoke(%w[-f yaml -i {{fmt.id}}:fixtures/input/test.{{fmt.id}} *], o, e, i) + fixture = YAML.parse(File.read("fixtures/input/test_normalized.yaml")) + YAML.parse(o.to_s).should eq(fixture) } end end - describe "-s AGE=42 -i json:fixtures/input/test.json" do - it "overwrites value from json" do - expect_output(nil, nil) { |o, e, i| - Envcat::Cli.invoke(%w[-f kv -s AGE=42 -i json:fixtures/input/test.json AGE], o, e, i) - o.to_s.should eq("AGE=42\n") + describe "-i {{fmt.id}}:fixtures/input/test.invalid" do + it "prints error and exits with code 11 if parsing fails" do + expect_output(nil, /Malformed input.*is not valid {{fmt.id.upcase}}/) { |o, e, i| + expect_raises(Exit, "11") { + Envcat::Cli.invoke(%w[-f yaml -i {{fmt.id}}:fixtures/input/test.invalid *], o, e, i) + } + } + end + end + + describe "-i {{fmt.id}}:fixtures/input/test.notfound" do + it "prints error and exits with code 7 if input file doesn't exist" do + expect_output(nil, /No such file or directory/) { |o, e, i| + expect_raises(Exit, "7") { + Envcat::Cli.invoke(%w[-f yaml -i {{fmt.id}}:fixtures/input/test.notfound *], o, e, i) + } + } + end + end + {% end %} + + {% for fmt in %w[env- derp] %} + describe "-i {{fmt.id}}" do + it "prints error and exits with code 3 if argument to -i is invalid" do + expect_output(nil, /Unknown input type/) { |o, e, i| + expect_raises(Exit, "3") { + Envcat::Cli.invoke(%w[-i {{fmt.id}} *], o, e, i) + } + } + end + end + {% end %} + + {% for fmt in %w[yaml yaml: json json: toml toml:] %} + describe "-i {{fmt.id}}" do + it "prints error and exits with code 3 if argument to -i misses path" do + expect_output(nil, /Path is required/) { |o, e, i| + expect_raises(Exit, "3") { + Envcat::Cli.invoke(%w[-i {{fmt.id}} *], o, e, i) + } } end end + {% end %} end diff --git a/spec/envcat/cli/set_spec.cr b/spec/envcat/cli/set_spec.cr index 49a6017..0f9f432 100644 --- a/spec/envcat/cli/set_spec.cr +++ b/spec/envcat/cli/set_spec.cr @@ -3,58 +3,21 @@ require "../../../src/envcat/cli" require "digest/sha256" describe Envcat::Cli do - {% for fmt in %w[json yaml toml] %} - describe "-i {{fmt.id}}:fixtures/input/test.{{fmt.id}}" do - it "parses and normalizes {{fmt.id}}" do + describe "-i json:fixtures/input/test.json -s AGE=42" do + it "overwrites value from json" do expect_output(nil, nil) { |o, e, i| - Envcat::Cli.invoke(%w[-f yaml -i {{fmt.id}}:fixtures/input/test.{{fmt.id}} *], o, e, i) - Digest::SHA256.hexdigest(o.to_s.split("\n").sort.join("\n")).should eq("66dc73717712ef4ed7ac7fa0cd1ccad48c67b718c038fb9c2f852c10e52e77d6") + Envcat::Cli.invoke(%w[-f kv -i json:fixtures/input/test.json -s AGE=42 AGE], o, e, i) + o.to_s.should eq("AGE=42\n") } end end - describe "-i {{fmt.id}}:fixtures/input/test.invalid" do - it "prints error and exits with code 11 if parsing fails" do - expect_output(nil, /Malformed input.*is not valid {{fmt.id.upcase}}/) { |o, e, i| - expect_raises(Exit, "11") { - Envcat::Cli.invoke(%w[-f yaml -i {{fmt.id}}:fixtures/input/test.invalid *], o, e, i) - } - } - end - end - - describe "-i {{fmt.id}}:fixtures/input/test.notfound" do - it "prints error and exits with code 7 if input file doesn't exist" do - expect_output(nil, /No such file or directory/) { |o, e, i| - expect_raises(Exit, "7") { - Envcat::Cli.invoke(%w[-f yaml -i {{fmt.id}}:fixtures/input/test.notfound *], o, e, i) - } - } - end - end - {% end %} - - {% for fmt in %w[env- derp] %} - describe "-i {{fmt.id}}" do - it "prints error and exits with code 3 if argument to -i is invalid" do - expect_output(nil, /Unknown input type/) { |o, e, i| - expect_raises(Exit, "3") { - Envcat::Cli.invoke(%w[-i {{fmt.id}} *], o, e, i) - } - } - end - end - {% end %} - - {% for fmt in %w[yaml yaml: json json: toml toml:] %} - describe "-i {{fmt.id}}" do - it "prints error and exits with code 3 if argument to -i misses path" do - expect_output(nil, /Path is required/) { |o, e, i| - expect_raises(Exit, "3") { - Envcat::Cli.invoke(%w[-i {{fmt.id}} *], o, e, i) - } + describe "-s AGE=42 -i json:fixtures/input/test.json" do + it "overwrites value from json" do + expect_output(nil, nil) { |o, e, i| + Envcat::Cli.invoke(%w[-f kv -s AGE=42 -i json:fixtures/input/test.json AGE], o, e, i) + o.to_s.should eq("AGE=42\n") } end end - {% end %} end