diff --git a/src/search.rs b/src/search.rs index 01dcdacff9..233e638bd4 100644 --- a/src/search.rs +++ b/src/search.rs @@ -34,12 +34,13 @@ impl Search { paths } + /// Attempt to find a justfile given the search configuration and invocation directory pub(crate) fn find( search_config: &SearchConfig, invocation_directory: &Path, ) -> SearchResult { match search_config { - SearchConfig::FromInvocationDirectory => Self::find_next(invocation_directory), + SearchConfig::FromInvocationDirectory => Self::find_in_directory(invocation_directory), SearchConfig::FromSearchDirectory { search_directory } => { let search_directory = Self::clean(invocation_directory, search_directory); let justfile = Self::justfile(&search_directory)?; @@ -75,7 +76,20 @@ impl Search { } } - pub(crate) fn find_next(starting_dir: &Path) -> SearchResult { + /// Look for a justfile starting from the parent directory to the current justfile + pub(crate) fn search_parent_directory(&self) -> SearchResult { + let parent_dir = self + .justfile + .parent() + .and_then(|p| p.parent()) + .ok_or_else(|| SearchError::JustfileHadNoParent { + path: self.justfile.clone(), + })?; + Self::find_in_directory(parent_dir) + } + + /// Find a justfile starting in the given directory and searching upwards in the directory tree + fn find_in_directory(starting_dir: &Path) -> SearchResult { let justfile = Self::justfile(starting_dir)?; let working_directory = Self::working_directory_from_justfile(&justfile)?; Ok(Self { diff --git a/src/subcommand.rs b/src/subcommand.rs index 449d4a0920..36a9a9c0fd 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -53,10 +53,6 @@ impl Subcommand { Completions { shell } => return Self::completions(*shell), Init => return Self::init(config), Man => return Self::man(), - Run { - arguments, - overrides, - } => return Self::run(config, loader, arguments, overrides), _ => {} } @@ -70,6 +66,10 @@ impl Subcommand { let justfile = &compilation.justfile; match self { + Run { + arguments, + overrides, + } => Self::run(config, loader, search, arguments, overrides)?, Choose { overrides, chooser } => { Self::choose(config, justfile, &search, overrides, chooser.as_deref())?; } @@ -83,7 +83,7 @@ impl Subcommand { Show { path } => Self::show(config, justfile, path)?, Summary => Self::summary(config, justfile), Variables => Self::variables(justfile), - Changelog | Completions { .. } | Edit | Init | Man | Run { .. } => unreachable!(), + Changelog | Completions { .. } | Edit | Init | Man => unreachable!(), } Ok(()) @@ -99,90 +99,54 @@ impl Subcommand { fn run<'src>( config: &Config, loader: &'src Loader, + initial_search: Search, arguments: &[String], overrides: &BTreeMap, ) -> RunResult<'src> { - 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 } => config - .invocation_directory - .join(search_directory) - .lexiclean(), - _ => unreachable!(), - }; - - let mut path = starting_path.clone(); - - let mut unknown_recipes_errors = None; - - loop { - let search = match Search::find_next(&path) { - Err(SearchError::NotFound) => match unknown_recipes_errors { - Some(err) => return Err(err), - None => return Err(SearchError::NotFound.into()), - }, - Err(err) => return Err(err.into()), - Ok(search) => { - if config.verbosity.loquacious() && path != starting_path { - eprintln!( - "Trying {}", - starting_path - .strip_prefix(path) - .unwrap() - .components() - .map(|_| path::Component::ParentDir) - .collect::() - .join(search.justfile.file_name().unwrap()) - .display() - ); - } - search - } - }; - - match Self::run_inner(config, loader, arguments, overrides, &search) { - Err((err @ (Error::UnknownRecipe { .. } | Error::UnknownSubmodule { .. }), true)) => { - match search.justfile.parent().unwrap().parent() { - Some(parent) => { - unknown_recipes_errors.get_or_insert(err); - path = parent.into(); - } - None => return Err(err), - } + let starting_path = initial_search + .justfile + .parent() + .as_ref() + .unwrap() + .lexiclean(); + + let mut search = initial_search; + + loop { + let compilation = Self::compile(config, loader, &search)?; + let justfile = &compilation.justfile; + let fallback = justfile.settings.fallback + && matches!( + config.search_config, + SearchConfig::FromInvocationDirectory | SearchConfig::FromSearchDirectory { .. } + ); + let run_result = justfile.run(config, &search, overrides, arguments); + + match run_result { + Err(err @ (Error::UnknownRecipe { .. } | Error::UnknownSubmodule { .. })) if fallback => { + let new_search = search + .search_parent_directory() + .map_err(|_search_err| err)?; + let p = new_search.justfile.parent().unwrap(); + let new_path = starting_path + .strip_prefix(p) + .unwrap() + .components() + .map(|_| path::Component::ParentDir) + .collect::() + .join(new_search.justfile.file_name().unwrap()); + + search = new_search; + + if config.verbosity.loquacious() { + eprintln!("Trying {}", new_path.display()); } - result => return result.map_err(|(err, _fallback)| err), } + result => return result, } - } else { - Self::run_inner( - config, - loader, - arguments, - overrides, - &Search::find(&config.search_config, &config.invocation_directory)?, - ) - .map_err(|(err, _fallback)| err) } } - fn run_inner<'src>( - config: &Config, - loader: &'src Loader, - arguments: &[String], - overrides: &BTreeMap, - search: &Search, - ) -> Result<(), (Error<'src>, bool)> { - let compilation = Self::compile(config, loader, search).map_err(|err| (err, false))?; - let justfile = &compilation.justfile; - justfile - .run(config, search, overrides, arguments) - .map_err(|err| (err, justfile.settings.fallback)) - } - fn compile<'src>( config: &Config, loader: &'src Loader,