Skip to content

Commit

Permalink
Search for .env file from working directory (#661)
Browse files Browse the repository at this point in the history
Search for a `.env` file starting in the  working directory, instead of
the invocation directory.
  • Loading branch information
casey authored Jul 19, 2020
1 parent 8fad062 commit 05d73a4
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 14 deletions.
2 changes: 1 addition & 1 deletion src/justfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ impl<'src> Justfile<'src> {
}

let dotenv = if config.load_dotenv {
load_dotenv()?
load_dotenv(&search.working_directory)?
} else {
BTreeMap::new()
};
Expand Down
27 changes: 14 additions & 13 deletions src/load_dotenv.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
use crate::common::*;

pub(crate) fn load_dotenv() -> RunResult<'static, BTreeMap<String, String>> {
// `dotenv::dotenv_iter` should eventually be un-deprecated, see:
pub(crate) fn load_dotenv(
working_directory: &Path,
) -> RunResult<'static, BTreeMap<String, String>> {
// `dotenv::from_path_iter` should eventually be un-deprecated, see:
// https://github.com/dotenv-rs/dotenv/issues/13
#![allow(deprecated)]
match dotenv::dotenv_iter() {
Ok(iter) => {
for directory in working_directory.ancestors() {
let path = directory.join(".env");

if path.is_file() {
let iter = dotenv::from_path_iter(&path)?;
let mut dotenv = BTreeMap::new();
for result in iter {
let (key, value) = result.map_err(|dotenv_error| RuntimeError::Dotenv { dotenv_error })?;
let (key, value) = result?;
if env::var_os(&key).is_none() {
dotenv.insert(key, value);
}
}
Ok(dotenv)
},
Err(dotenv_error) =>
if dotenv_error.not_found() {
Ok(BTreeMap::new())
} else {
Err(RuntimeError::Dotenv { dotenv_error })
},
return Ok(dotenv);
}
}

Ok(BTreeMap::new())
}
6 changes: 6 additions & 0 deletions src/runtime_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,3 +395,9 @@ impl<'src> Display for RuntimeError<'src> {
Ok(())
}
}

impl<'src> From<dotenv::Error> for RuntimeError<'src> {
fn from(dotenv_error: dotenv::Error) -> RuntimeError<'src> {
RuntimeError::Dotenv { dotenv_error }
}
}
28 changes: 28 additions & 0 deletions tests/dotenv.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use executable_path::executable_path;
use std::{process, str};

use test_utilities::tmptree;

#[test]
fn dotenv() {
let tmp = tmptree! {
".env": "KEY=ROOT",
sub: {
".env": "KEY=SUB",
justfile: "default:\n\techo KEY=$KEY",
},
};

let binary = executable_path("just");

let output = process::Command::new(binary)
.current_dir(tmp.path())
.arg("sub/default")
.output()
.expect("just invocation failed");

assert_eq!(output.status.code().unwrap(), 0);

let stdout = str::from_utf8(&output.stdout).unwrap();
assert_eq!(stdout, "KEY=SUB\n");
}

0 comments on commit 05d73a4

Please sign in to comment.