Skip to content

Commit

Permalink
feat(env): supports glob patterns in env._.file and env._.source (f…
Browse files Browse the repository at this point in the history
…ix #1916) (#2016)
  • Loading branch information
noirbizarre committed May 5, 2024
1 parent 11d6f71 commit b08c5cc
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 19 deletions.
2 changes: 2 additions & 0 deletions e2e/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ Library
/pyproject.toml
/poetry.lock
/test-e2e/
env.d
source.d
19 changes: 19 additions & 0 deletions e2e/test_env_file_glob
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
set -euo pipefail
# shellcheck source-path=SCRIPTDIR
source "$(dirname "$0")/assert.sh"

cat >.e2e.mise.toml <<EOF
[env]
_.file = "env.d/*.env"
EOF

mkdir -p env.d

echo "VAR1=1" >env.d/1.env
echo "VAR2=2" >env.d/2.env

# mise trust --verbose
mise env -s bash
assert_contains "mise env -s bash" "VAR1=1"
assert_contains "mise env -s bash" "VAR2=2"
26 changes: 26 additions & 0 deletions e2e/test_env_source_glob
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env bash
set -euo pipefail
# shellcheck source-path=SCRIPTDIR
source "$(dirname "$0")/assert.sh"

export MISE_EXPERIMENTAL=1

cat >.e2e.mise.toml <<EOF
[env]
_.source = "source.d/*.sh"
EOF

mkdir -p source.d

cat >source.d/1.sh <<EOF
#!/usr/bin/env bash
export SOURCE1=1
EOF

cat >source.d/2.sh <<EOF
#!/usr/bin/env bash
export SOURCE2=2
EOF

assert_contains "mise env -s bash" "SOURCE1=1"
assert_contains "mise env -s bash" "SOURCE2=2"
58 changes: 39 additions & 19 deletions src/config/env_directive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::fmt::Display;
use std::path::{Path, PathBuf};

use eyre::Context;
use globwalk::{GlobError, GlobWalkerBuilder};
use indexmap::IndexMap;

use crate::cmd::CmdLineRunner;
Expand Down Expand Up @@ -110,6 +111,23 @@ impl EnvResults {
_ => p.to_path_buf(),
}
};
let glob_files = |path: PathBuf| {
// Use the longuest path without any glob pattern character as root
let root = path
.ancestors()
.skip(1)
.find(|a| !"*[{?".chars().any(|c| a.to_str().unwrap().contains(c)))
.unwrap()
.to_path_buf();
let pattern = path.strip_prefix(&root).unwrap();
let files = GlobWalkerBuilder::new(root, pattern.to_string_lossy())
.follow_links(true)
.build()?
.filter_map(|e| e.ok())
.filter(|e| e.file_type().is_file())
.map(|e| e.into_path());
Ok::<_, GlobError>(files)
};
match directive {
EnvDirective::Val(k, v) => {
let v = r.parse_template(&ctx, &source, &v)?;
Expand All @@ -129,31 +147,33 @@ impl EnvResults {
EnvDirective::File(input) => {
trust_check(&source)?;
let s = r.parse_template(&ctx, &source, input.to_string_lossy().as_ref())?;
let p = normalize_path(s.into());
r.env_files.push(p.clone());
let errfn = || eyre!("failed to parse dotenv file: {}", display_path(&p));
for item in dotenvy::from_path_iter(&p).wrap_err_with(errfn)? {
let (k, v) = item.wrap_err_with(errfn)?;
r.env_remove.remove(&k);
env.insert(k, (v, Some(p.clone())));
for p in glob_files(normalize_path(s.into()))? {
r.env_files.push(p.clone());
let errfn = || eyre!("failed to parse dotenv file: {}", display_path(&p));
for item in dotenvy::from_path_iter(&p).wrap_err_with(errfn)? {
let (k, v) = item.wrap_err_with(errfn)?;
r.env_remove.remove(&k);
env.insert(k, (v, Some(p.clone())));
}
}
}
EnvDirective::Source(input) => {
settings.ensure_experimental("env._.source")?;
trust_check(&source)?;
let s = r.parse_template(&ctx, &source, input.to_string_lossy().as_ref())?;
let p = normalize_path(s.into());
r.env_scripts.push(p.clone());
let env_diff = EnvDiff::from_bash_script(&p, env_vars.clone())?;
for p in env_diff.to_patches() {
match p {
EnvDiffOperation::Add(k, v) | EnvDiffOperation::Change(k, v) => {
r.env_remove.remove(&k);
env.insert(k.clone(), (v.clone(), Some(source.clone())));
}
EnvDiffOperation::Remove(k) => {
env.shift_remove(&k);
r.env_remove.insert(k);
for p in glob_files(normalize_path(s.into()))? {
r.env_scripts.push(p.clone());
let env_diff = EnvDiff::from_bash_script(&p, env_vars.clone())?;
for p in env_diff.to_patches() {
match p {
EnvDiffOperation::Add(k, v) | EnvDiffOperation::Change(k, v) => {
r.env_remove.remove(&k);
env.insert(k.clone(), (v.clone(), Some(source.clone())));
}
EnvDiffOperation::Remove(k) => {
env.shift_remove(&k);
r.env_remove.insert(k);
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ fn init_term_logger(level: LevelFilter) -> Box<dyn SharedLogger> {
.set_thread_level(trace_level)
.set_location_level(trace_level)
.set_target_level(trace_level)
.add_filter_ignore(String::from("globset")) // debug!() statements break outputs
.build(),
TerminalMode::Stderr,
ColorChoice::Auto,
Expand Down

0 comments on commit b08c5cc

Please sign in to comment.