Stabilize fallback (#1471)

This commit is contained in:
Casey Rodarmor 2023-01-03 22:31:56 -08:00 committed by GitHub
parent bb5b962c3d
commit 10ad32430b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 123 additions and 113 deletions

View File

@ -92,20 +92,20 @@ impl Subcommand {
arguments: &[String],
overrides: &BTreeMap<String, String>,
) -> Result<(), Error<'src>> {
if config.unstable
&& matches!(
config.search_config,
SearchConfig::FromInvocationDirectory | SearchConfig::FromSearchDirectory { .. }
)
{
let mut path = match &config.search_config {
if matches!(
config.search_config,
SearchConfig::FromInvocationDirectory | SearchConfig::FromSearchDirectory { .. }
) {
let starting_path = match &config.search_config {
SearchConfig::FromInvocationDirectory => config.invocation_directory.clone(),
SearchConfig::FromSearchDirectory { search_directory } => std::env::current_dir()
.unwrap()
.join(search_directory.clone()),
SearchConfig::FromSearchDirectory { search_directory } => {
std::env::current_dir().unwrap().join(search_directory)
}
_ => unreachable!(),
};
let mut path = starting_path.clone();
let mut unknown_recipes_errors = None;
loop {
@ -116,11 +116,10 @@ impl Subcommand {
},
Err(err) => return Err(err.into()),
Ok(search) => {
if config.verbosity.loud() && path != config.invocation_directory {
if config.verbosity.loud() && path != starting_path {
eprintln!(
"Trying {}",
config
.invocation_directory
starting_path
.strip_prefix(path)
.unwrap()
.components()

View File

@ -31,7 +31,7 @@ fn allow_duplicate_recipes_with_args() {
set allow-duplicate-recipes
",
)
.args(&["b", "one", "two"])
.args(["b", "one", "two"])
.stdout("bar one two\n")
.stderr("echo bar one two\n")
.run();

View File

@ -3,7 +3,7 @@ use super::*;
#[test]
fn print_changelog() {
Test::new()
.args(&["--changelog"])
.args(["--changelog"])
.stdout(fs::read_to_string("CHANGELOG.md").unwrap())
.run();
}

View File

@ -128,7 +128,7 @@ fn invoke_error_function() {
.stderr_regex("error: Chooser `/ -cu fzf` invocation failed: .*")
.status(EXIT_FAILURE)
.shell(false)
.args(&["--shell", "/", "--choose"])
.args(["--shell", "/", "--choose"])
.run();
}

View File

@ -2,26 +2,14 @@ use super::*;
#[test]
fn dotenv() {
let tmp = temptree! {
".env": "KEY=ROOT",
sub: {
".env": "KEY=SUB",
justfile: "default:\n\techo KEY=${KEY:-unset}",
},
};
let binary = executable_path("just");
let output = 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=unset\n");
Test::new()
.write(".env", "KEY=ROOT")
.write("sub/.env", "KEY=SUB")
.write("sub/justfile", "default:\n\techo KEY=${KEY:-unset}")
.args(["sub/default"])
.stdout("KEY=unset\n")
.stderr("echo KEY=${KEY:-unset}\n")
.run();
}
test! {
@ -83,7 +71,7 @@ fn path_not_found() {
echo $NAME
",
)
.args(&["--dotenv-path", ".env.prod"])
.args(["--dotenv-path", ".env.prod"])
.stderr(if cfg!(windows) {
"error: Failed to load environment file: The system cannot find the file specified. (os \
error 2)\n"
@ -108,7 +96,7 @@ fn path_resolves() {
".env": "NAME=bar"
}
})
.args(&["--dotenv-path", "subdir/.env"])
.args(["--dotenv-path", "subdir/.env"])
.stdout("bar\n")
.status(EXIT_SUCCESS)
.run();
@ -126,7 +114,7 @@ fn filename_resolves() {
.tree(tree! {
".env.special": "NAME=bar"
})
.args(&["--dotenv-filename", ".env.special"])
.args(["--dotenv-filename", ".env.special"])
.stdout("bar\n")
.status(EXIT_SUCCESS)
.run();
@ -146,7 +134,7 @@ fn filename_flag_overwrites_no_load() {
.tree(tree! {
".env.special": "NAME=bar"
})
.args(&["--dotenv-filename", ".env.special"])
.args(["--dotenv-filename", ".env.special"])
.stdout("bar\n")
.status(EXIT_SUCCESS)
.run();
@ -168,7 +156,7 @@ fn path_flag_overwrites_no_load() {
".env": "NAME=bar"
}
})
.args(&["--dotenv-path", "subdir/.env"])
.args(["--dotenv-path", "subdir/.env"])
.stdout("bar\n")
.status(EXIT_SUCCESS)
.run();

View File

@ -40,7 +40,7 @@ test! {
fn argument_count_mismatch() {
Test::new()
.justfile("foo a b:")
.args(&["foo"])
.args(["foo"])
.stderr(
"
error: Recipe `foo` got 0 arguments but takes 2

View File

@ -1,5 +1,45 @@
use super::*;
#[test]
fn fallback_from_subdir_bugfix() {
Test::new()
.write(
"sub/justfile",
unindent(
"
set fallback
@default:
echo foo
",
),
)
.args(["sub/default"])
.stdout("foo\n")
.run();
}
#[test]
fn fallback_from_subdir_message() {
Test::new()
.justfile("bar:\n echo bar")
.write(
"sub/justfile",
unindent(
"
set fallback
@foo:
echo foo
",
),
)
.args(["sub/bar"])
.stderr(path("Trying ../justfile\necho bar\n"))
.stdout("bar\n")
.run();
}
#[test]
fn runs_recipe_in_parent_if_not_found_in_current() {
Test::new()
@ -19,7 +59,7 @@ fn runs_recipe_in_parent_if_not_found_in_current() {
echo root
",
)
.args(&["--unstable", "foo"])
.args(["foo"])
.current_dir("bar")
.stderr(format!(
"
@ -51,7 +91,7 @@ fn setting_accepts_value() {
echo root
",
)
.args(&["--unstable", "foo"])
.args(["foo"])
.current_dir("bar")
.stderr(format!(
"
@ -78,7 +118,7 @@ fn print_error_from_parent_if_recipe_not_found_in_current() {
}
})
.justfile("foo:\n echo {{bar}}")
.args(&["--unstable", "foo"])
.args(["foo"])
.current_dir("bar")
.stderr(format!(
"
@ -95,31 +135,6 @@ fn print_error_from_parent_if_recipe_not_found_in_current() {
}
#[test]
fn requires_unstable() {
Test::new()
.tree(tree! {
bar: {
justfile: "
baz:
echo subdir
"
}
})
.justfile(
"
foo:
echo root
",
)
.args(&["foo"])
.current_dir("bar")
.status(EXIT_FAILURE)
.stderr("error: Justfile does not contain recipe `foo`.\n")
.run();
}
#[test]
#[ignore]
fn requires_setting() {
Test::new()
.tree(tree! {
@ -136,7 +151,7 @@ fn requires_setting() {
echo root
",
)
.args(&["--unstable", "foo"])
.args(["foo"])
.current_dir("bar")
.status(EXIT_FAILURE)
.stderr("error: Justfile does not contain recipe `foo`.\n")
@ -162,7 +177,7 @@ fn works_with_provided_search_directory() {
echo root
",
)
.args(&["--unstable", "./foo"])
.args(["./foo"])
.stdout("root\n")
.stderr(format!(
"
@ -192,7 +207,7 @@ fn doesnt_work_with_justfile() {
echo root
",
)
.args(&["--unstable", "--justfile", "justfile", "foo"])
.args(["--justfile", "justfile", "foo"])
.current_dir("bar")
.status(EXIT_FAILURE)
.stderr("error: Justfile does not contain recipe `foo`.\n")
@ -216,14 +231,7 @@ fn doesnt_work_with_justfile_and_working_directory() {
echo root
",
)
.args(&[
"--unstable",
"--justfile",
"justfile",
"--working-directory",
".",
"foo",
])
.args(["--justfile", "justfile", "--working-directory", ".", "foo"])
.current_dir("bar")
.status(EXIT_FAILURE)
.stderr("error: Justfile does not contain recipe `foo`.\n")
@ -249,7 +257,7 @@ fn prints_correct_error_message_when_recipe_not_found() {
echo root
",
)
.args(&["--unstable", "foo"])
.args(["foo"])
.current_dir("bar")
.status(EXIT_FAILURE)
.stderr(format!(
@ -289,7 +297,7 @@ fn multiple_levels_of_fallback_work() {
echo root
",
)
.args(&["--unstable", "baz"])
.args(["baz"])
.current_dir("a/b")
.stdout("root\n")
.stderr(format!(
@ -328,7 +336,7 @@ fn stop_fallback_when_fallback_is_false() {
echo root
",
)
.args(&["--unstable", "baz"])
.args(["baz"])
.current_dir("a/b")
.stderr(format!(
"

View File

@ -105,7 +105,7 @@ fn write_error() {
let test = Test::with_tempdir(tempdir)
.no_justfile()
.args(&["--fmt", "--unstable"])
.args(["--fmt", "--unstable"])
.status(EXIT_FAILURE)
.stderr_regex(if cfg!(windows) {
r"error: Failed to write justfile to `.*`: Access is denied. \(os error 5\)\n"
@ -1055,7 +1055,7 @@ test! {
fn exported_parameter() {
Test::new()
.justfile("foo +$f:")
.args(&["--dump"])
.args(["--dump"])
.stdout("foo +$f:\n")
.run();
}

View File

@ -414,7 +414,7 @@ test! {
fn assert_eval_eq(expression: &str, result: &str) {
Test::new()
.justfile(format!("x := {}", expression))
.args(&["--evaluate", "x"])
.args(["--evaluate", "x"])
.stdout(result)
.unindent_stdout(false)
.run();
@ -478,7 +478,7 @@ fn join() {
fn join_argument_count_error() {
Test::new()
.justfile("x := join('a')")
.args(&["--evaluate"])
.args(["--evaluate"])
.stderr(
"
error: Function `join` called with 1 argument but takes 2 or more
@ -498,7 +498,7 @@ fn test_path_exists_filepath_exist() {
testfile: ""
})
.justfile("x := path_exists('testfile')")
.args(&["--evaluate", "x"])
.args(["--evaluate", "x"])
.stdout("true")
.run();
}
@ -507,7 +507,7 @@ fn test_path_exists_filepath_exist() {
fn test_path_exists_filepath_doesnt_exist() {
Test::new()
.justfile("x := path_exists('testfile')")
.args(&["--evaluate", "x"])
.args(["--evaluate", "x"])
.stdout("false")
.run();
}
@ -516,7 +516,7 @@ fn test_path_exists_filepath_doesnt_exist() {
fn error_errors_with_message() {
Test::new()
.justfile("x := error ('Thing Not Supported')")
.args(&["--evaluate"])
.args(["--evaluate"])
.status(1)
.stderr("error: Call to function `error` failed: Thing Not Supported\n |\n1 | x := error ('Thing Not Supported')\n | ^^^^^\n")
.run();
@ -526,7 +526,7 @@ fn error_errors_with_message() {
fn test_absolute_path_resolves() {
let test_object = Test::new()
.justfile("path := absolute_path('./test_file')")
.args(&["--evaluate", "path"]);
.args(["--evaluate", "path"]);
let mut tempdir = test_object.tempdir.path().to_owned();
@ -546,7 +546,7 @@ fn test_absolute_path_resolves() {
fn test_absolute_path_resolves_parent() {
let test_object = Test::new()
.justfile("path := absolute_path('../test_file')")
.args(&["--evaluate", "path"]);
.args(["--evaluate", "path"]);
let mut tempdir = test_object.tempdir.path().to_owned();
@ -580,7 +580,7 @@ fn path_exists_subdir() {
})
.justfile("x := path_exists('foo')")
.current_dir("bar")
.args(&["--evaluate", "x"])
.args(["--evaluate", "x"])
.stdout("true")
.run();
}
@ -589,7 +589,7 @@ fn path_exists_subdir() {
fn uuid() {
Test::new()
.justfile("x := uuid()")
.args(&["--evaluate", "x"])
.args(["--evaluate", "x"])
.stdout_regex("........-....-....-....-............")
.run();
}
@ -598,7 +598,7 @@ fn uuid() {
fn sha256() {
Test::new()
.justfile("x := sha256('5943ee37-0000-1000-8000-010203040506')")
.args(&["--evaluate", "x"])
.args(["--evaluate", "x"])
.stdout("2330d7f5eb94a820b54fed59a8eced236f80b633a504289c030b6a65aef58871")
.run();
}
@ -613,7 +613,7 @@ fn sha256_file() {
}
})
.current_dir("sub")
.args(&["--evaluate", "x"])
.args(["--evaluate", "x"])
.stdout("177b3d79aaafb53a7a4d7aaba99a82f27c73370e8cb0295571aade1e4fea1cd2")
.run();
}

View File

@ -46,7 +46,7 @@ fn write_error() {
test
.no_justfile()
.args(&["--init"])
.args(["--init"])
.status(EXIT_FAILURE)
.stderr_regex(if cfg!(windows) {
r"error: Failed to write justfile to `.*`: Access is denied. \(os error 5\)\n"

View File

@ -3,7 +3,7 @@ use super::*;
fn test(justfile: &str, value: Value) {
Test::new()
.justfile(justfile)
.args(&["--dump", "--dump-format", "json", "--unstable"])
.args(["--dump", "--dump-format", "json", "--unstable"])
.stdout(format!("{}\n", serde_json::to_string(&value).unwrap()))
.run();
}
@ -709,7 +709,7 @@ fn quiet() {
fn requires_unstable() {
Test::new()
.justfile("foo:")
.args(&["--dump", "--dump-format", "json"])
.args(["--dump", "--dump-format", "json"])
.stderr("error: The JSON dump format is currently unstable. Invoke `just` with the `--unstable` flag to enable unstable features.\n")
.status(EXIT_FAILURE)
.run();

View File

@ -47,7 +47,7 @@ mod error_messages;
mod evaluate;
mod examples;
mod export;
mod fall_back_to_parent;
mod fallback;
mod fmt;
mod functions;
mod ignore_comments;
@ -83,3 +83,11 @@ mod undefined_variables;
#[cfg(target_family = "windows")]
mod windows_shell;
mod working_directory;
fn path(s: &str) -> String {
if cfg!(windows) {
s.replace('/', "\\")
} else {
s.into()
}
}

View File

@ -9,7 +9,7 @@ fn private_attribute_for_recipe() {
foo:
",
)
.args(&["--list"])
.args(["--list"])
.stdout(
"
Available recipes:
@ -29,7 +29,7 @@ fn private_attribute_for_alias() {
foo:
",
)
.args(&["--list"])
.args(["--list"])
.stdout(
"
Available recipes:

View File

@ -8,7 +8,7 @@ fn single_quotes_are_prepended_and_appended() {
x := quote('abc')
",
)
.args(&["--evaluate", "x"])
.args(["--evaluate", "x"])
.stdout("'abc'")
.run();
}
@ -21,7 +21,7 @@ fn quotes_are_escaped() {
x := quote("'")
"#,
)
.args(&["--evaluate", "x"])
.args(["--evaluate", "x"])
.stdout(r"''\'''")
.run();
}

View File

@ -9,7 +9,7 @@ fn dont_run_duplicate_recipes() {
# foo
",
)
.args(&["foo", "foo"])
.args(["foo", "foo"])
.stderr(
"
# foo

View File

@ -4,7 +4,7 @@ use super::*;
fn once() {
Test::new()
.justfile("x := 'a' / 'b'")
.args(&["--evaluate", "x"])
.args(["--evaluate", "x"])
.stdout("a/b")
.run();
}
@ -13,7 +13,7 @@ fn once() {
fn twice() {
Test::new()
.justfile("x := 'a' / 'b' / 'c'")
.args(&["--evaluate", "x"])
.args(["--evaluate", "x"])
.stdout("a/b/c")
.run();
}
@ -22,7 +22,7 @@ fn twice() {
fn no_lhs_once() {
Test::new()
.justfile("x := / 'a'")
.args(&["--evaluate", "x"])
.args(["--evaluate", "x"])
.stdout("/a")
.run();
}
@ -31,12 +31,12 @@ fn no_lhs_once() {
fn no_lhs_twice() {
Test::new()
.justfile("x := / 'a' / 'b'")
.args(&["--evaluate", "x"])
.args(["--evaluate", "x"])
.stdout("/a/b")
.run();
Test::new()
.justfile("x := // 'a'")
.args(&["--evaluate", "x"])
.args(["--evaluate", "x"])
.stdout("//a")
.run();
}

View File

@ -78,8 +78,8 @@ impl Test {
self
}
pub(crate) fn args(mut self, args: &[&str]) -> Self {
for arg in args {
pub(crate) fn args<'a>(mut self, args: impl AsRef<[&'a str]>) -> Self {
for arg in args.as_ref() {
self = self.arg(arg);
}
self
@ -154,6 +154,13 @@ impl Test {
self.unindent_stdout = unindent_stdout;
self
}
pub(crate) fn write(self, path: impl AsRef<Path>, content: impl AsRef<[u8]>) -> Self {
let path = self.tempdir.path().join(path);
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
std::fs::write(path, content).unwrap();
self
}
}
impl Test {