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

Handle env files from stdin #33

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ env_logger = []
[dependencies]
clap = { version = "4", features = ["derive", "env", "unicode", "cargo"] }
color-eyre = "0.6"
dotenvy = "0.15.7"
env_logger = "0.11"
fluent-templates = { version = "0.9", optional = true, default-features = false, features = ["tera", "use-ignore"] }
log = "0.4"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ Passing the `-a | --escape` flag allows escaping the content.
Usage: tera [OPTIONS] --template <TEMPLATE> [CONTEXT]

Arguments:
[CONTEXT] Location of the context data. This file can be of the following type: json | toml | yaml. If you prefer to pass the data as stdin, use `--stdin`
[CONTEXT] Location of the context data. This file can be of the following type: json | toml | yaml. If you prefer to pass the data as stdin, use `--stdin`. On stdin, .env files are also supported.

Options:
-t, --template <TEMPLATE> Location of the template
Expand Down
3 changes: 3 additions & 0 deletions data/env-file/.env.file
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
LOGNAME=chevdor
HOME=/home/foobarqux
EDITOR=emacs?
15 changes: 15 additions & 0 deletions data/env-file/env-file.tera
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# ENV Demo

{% if LOGNAME %}
Hello **{{ LOGNAME }}**.
{% endif %}

This demo shows how your ENV variables can be used in a template.

- Home: {% set fragments = HOME | split(pat="/") %}
{%- for fragment in fragments -%}
{%- if fragment -%}
/{{ fragment }}
{%- endif %}
{%- endfor %}
- Editor: {{ EDITOR }}
2 changes: 1 addition & 1 deletion doc/usage.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Command line utility for the tera templating engine. You need to provide a templ
Usage: tera [OPTIONS] --template <TEMPLATE> [CONTEXT]

Arguments:
[CONTEXT] Location of the context data. This file can be of the following type: json | toml | yaml. If you prefer to pass the data as stdin, use `--stdin`
[CONTEXT] Location of the context data. This file can be of the following type: json | toml | yaml. If you prefer to pass the data as stdin, use `--stdin`. On stdin, .env files are also supported.

Options:
-t, --template <TEMPLATE> Location of the template
Expand Down
3 changes: 2 additions & 1 deletion src/opts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ pub struct Opts {
pub locales_path: Option<PathBuf>,

/// Location of the context data. This file can be of the following type:
/// json | toml | yaml. If you prefer to pass the data as stdin, use `--stdin`
/// json | toml | yaml. If you prefer to pass the data as stdin, use `--stdin`.
/// On stdin, .env files are also supported.
#[clap(index = 1, required_unless_present_any = &["stdin", "env_only"], conflicts_with = "env_only")]
pub context: Option<PathBuf>,

Expand Down
22 changes: 21 additions & 1 deletion src/wrapped_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub enum SupportedType {
Json,
Toml,
Yaml,
Env,
}

impl WrappedContext {
Expand Down Expand Up @@ -73,6 +74,17 @@ impl WrappedContext {
Ok(())
}

pub fn append_env_file(&mut self, str: &str) -> Result<()> {
debug!("Appending env file");
let env_cursor = std::io::Cursor::new(str);
for item in dotenvy::from_read_iter(env_cursor) {
let (k, v) = item.context("Failed to parse .env file line")?;
self.handle_collision("env", &k, &v);
}

Ok(())
}

fn handle_collision<K, V>(&mut self, from: &str, k: K, v: V)
where
K: Debug + AsRef<str>,
Expand Down Expand Up @@ -138,6 +150,13 @@ impl WrappedContext {
debug!("not yaml");
}

let env_cursor = std::io::Cursor::new(str); // Create a reader from the string
if dotenvy::from_read_iter(env_cursor).all(|item| item.is_ok()) {
return Some(SupportedType::Env);
} else {
debug!("not env");
}

None
}

Expand All @@ -158,12 +177,13 @@ impl WrappedContext {
Some(SupportedType::Json) if !input.is_empty() => self.append_json(&input),
Some(SupportedType::Toml) if !input.is_empty() => self.append_toml(&input),
Some(SupportedType::Yaml) if !input.is_empty() => self.append_yaml(&input),
Some(SupportedType::Env) if !input.is_empty() => self.append_env_file(&input),
_ => Ok(()),
}
.context("failed to append stdin to context")?;
} else if let Some(context_file) = &self.opts.context {
let input = fs::read_to_string(context_file).context("failed to read context file")?;

match context_file.extension() {
Some(ext) if ext == "json" => self.append_json(&input),
Some(ext) if ext == "toml" => self.append_toml(&input),
Expand Down
13 changes: 13 additions & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,19 @@ mod cli_tests {
let assert = cmd.write_stdin(stdin).arg("-t").arg("data/basic/basic.tera").arg("--stdin").assert();
assert.success().stdout(predicate::str::contains("Bob likes orange"));
}

#[test]
fn it_process_env_stdin() {
let mut cmd = Command::cargo_bin("tera").unwrap();
let stdin = fs::read_to_string("data/env-file/.env.file").unwrap();

let assert = cmd.write_stdin(stdin).arg("-t").arg("data/env-file/env-file.tera").arg("--stdin").assert();

assert.success().stdout(
predicate::str::contains("Hello **chevdor**")
.and(predicate::str::contains("Home: /home/foobarqux"))
.and(predicate::str::contains("Editor: emacs?")));
}
}

#[cfg(test)]
Expand Down
Loading