diff --git a/src/search.rs b/src/search.rs index 01dcdacff9..09d8f1a5ee 100644 --- a/src/search.rs +++ b/src/search.rs @@ -34,12 +34,13 @@ impl Search { paths } + /// Find justfile given 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 { + /// Find justfile starting from parent directory of current justfile + pub(crate) fn search_parent_directory(&self) -> SearchResult { + let parent = self + .justfile + .parent() + .and_then(|path| path.parent()) + .ok_or_else(|| SearchError::JustfileHadNoParent { + path: self.justfile.clone(), + })?; + Self::find_in_directory(parent) + } + + /// Find justfile starting in given directory searching upwards in 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 9e7486863d..eb8f3c6cec 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, compilation, 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,88 +99,47 @@ impl Subcommand { fn run<'src>( config: &Config, loader: &'src Loader, + mut search: Search, + mut compilation: Compilation<'src>, 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 + let starting_parent = search.justfile.parent().as_ref().unwrap().lexiclean(); + + loop { + let justfile = &compilation.justfile; + let fallback = justfile.settings.fallback + && matches!( + config.search_config, + SearchConfig::FromInvocationDirectory | SearchConfig::FromSearchDirectory { .. } + ); + + let result = justfile.run(config, &search, overrides, arguments); + + if fallback { + if let Err(err @ (Error::UnknownRecipe { .. } | Error::UnknownSubmodule { .. })) = result { + search = search.search_parent_directory().map_err(|_| err)?; + + let new_parent = starting_parent + .strip_prefix(search.justfile.parent().unwrap()) + .unwrap() + .components() + .map(|_| path::Component::ParentDir) + .collect::() + .join(search.justfile.file_name().unwrap()); + + if config.verbosity.loquacious() { + eprintln!("Trying {}", new_parent.display()); } - }; - - 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), - } - } - result => return result.map_err(|(err, _fallback)| err), + + compilation = Self::compile(config, loader, &search)?; + + continue; } } - } 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)) + return result; + } } fn compile<'src>(