Don't default to included recipes (#1740)

This commit is contained in:
Casey Rodarmor 2023-11-22 10:27:49 -08:00 committed by GitHub
parent 7337447d42
commit ab16c0493f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 52 additions and 14 deletions

View File

@ -9,14 +9,16 @@ pub(crate) struct Analyzer<'src> {
impl<'src> Analyzer<'src> { impl<'src> Analyzer<'src> {
pub(crate) fn analyze( pub(crate) fn analyze(
paths: &HashMap<PathBuf, PathBuf>,
asts: &HashMap<PathBuf, Ast<'src>>, asts: &HashMap<PathBuf, Ast<'src>>,
root: &Path, root: &Path,
) -> CompileResult<'src, Justfile<'src>> { ) -> CompileResult<'src, Justfile<'src>> {
Analyzer::default().justfile(asts, root) Analyzer::default().justfile(paths, asts, root)
} }
fn justfile( fn justfile(
mut self, mut self,
paths: &HashMap<PathBuf, PathBuf>,
asts: &HashMap<PathBuf, Ast<'src>>, asts: &HashMap<PathBuf, Ast<'src>>,
root: &Path, root: &Path,
) -> CompileResult<'src, Justfile<'src>> { ) -> CompileResult<'src, Justfile<'src>> {
@ -83,9 +85,12 @@ impl<'src> Analyzer<'src> {
aliases.insert(Self::resolve_alias(&recipes, alias)?); aliases.insert(Self::resolve_alias(&recipes, alias)?);
} }
let root = paths.get(root).unwrap();
Ok(Justfile { Ok(Justfile {
first: recipes first: recipes
.values() .values()
.filter(|recipe| recipe.name.path == root)
.fold(None, |accumulator, next| match accumulator { .fold(None, |accumulator, next| match accumulator {
None => Some(Rc::clone(next)), None => Some(Rc::clone(next)),
Some(previous) => Some(if previous.line_number() < next.line_number() { Some(previous) => Some(if previous.line_number() < next.line_number() {

View File

@ -10,12 +10,15 @@ impl Compiler {
) -> RunResult<'src, Compilation<'src>> { ) -> RunResult<'src, Compilation<'src>> {
let mut srcs: HashMap<PathBuf, &str> = HashMap::new(); let mut srcs: HashMap<PathBuf, &str> = HashMap::new();
let mut asts: HashMap<PathBuf, Ast> = HashMap::new(); let mut asts: HashMap<PathBuf, Ast> = HashMap::new();
let mut paths: HashMap<PathBuf, PathBuf> = HashMap::new();
let mut paths: Vec<PathBuf> = Vec::new(); let mut stack: Vec<PathBuf> = Vec::new();
paths.push(root.into()); stack.push(root.into());
while let Some(current) = paths.pop() { while let Some(current) = stack.pop() {
let (relative, src) = loader.load(root, &current)?; let (relative, src) = loader.load(root, &current)?;
paths.insert(current.clone(), relative.into());
let tokens = Lexer::lex(relative, src)?; let tokens = Lexer::lex(relative, src)?;
let mut ast = Parser::parse(&tokens)?; let mut ast = Parser::parse(&tokens)?;
@ -37,14 +40,14 @@ impl Compiler {
*absolute = Some(include.clone()); *absolute = Some(include.clone());
paths.push(include); stack.push(include);
} }
} }
asts.insert(current.clone(), ast.clone()); asts.insert(current.clone(), ast.clone());
} }
let justfile = Analyzer::analyze(&asts, root)?; let justfile = Analyzer::analyze(&paths, &asts, root)?;
Ok(Compilation { Ok(Compilation {
asts, asts,
@ -61,7 +64,9 @@ impl Compiler {
let root = PathBuf::from("justfile"); let root = PathBuf::from("justfile");
let mut asts: HashMap<PathBuf, Ast> = HashMap::new(); let mut asts: HashMap<PathBuf, Ast> = HashMap::new();
asts.insert(root.clone(), ast); asts.insert(root.clone(), ast);
Analyzer::analyze(&asts, &root) let mut paths: HashMap<PathBuf, PathBuf> = HashMap::new();
paths.insert(root.clone(), root.clone());
Analyzer::analyze(&paths, &asts, &root)
} }
} }

View File

@ -106,6 +106,7 @@ pub(crate) enum Error<'src> {
io_error: io::Error, io_error: io::Error,
}, },
NoChoosableRecipes, NoChoosableRecipes,
NoDefaultRecipe,
NoRecipes, NoRecipes,
NotConfirmed { NotConfirmed {
recipe: &'src str, recipe: &'src str,
@ -350,6 +351,7 @@ impl<'src> ColorDisplay for Error<'src> {
write!(f, "Failed to read justfile at `{path}`: {io_error}")?; write!(f, "Failed to read justfile at `{path}`: {io_error}")?;
} }
NoChoosableRecipes => write!(f, "Justfile contains no choosable recipes.")?, NoChoosableRecipes => write!(f, "Justfile contains no choosable recipes.")?,
NoDefaultRecipe => write!(f, "Justfile contains no default recipe.")?,
NoRecipes => write!(f, "Justfile contains no recipes.")?, NoRecipes => write!(f, "Justfile contains no recipes.")?,
NotConfirmed { recipe } => { NotConfirmed { recipe } => {
write!(f, "Recipe `{recipe}` was not confirmed")?; write!(f, "Recipe `{recipe}` was not confirmed")?;

View File

@ -199,8 +199,10 @@ impl<'src> Justfile<'src> {
}); });
} }
vec![recipe.name()] vec![recipe.name()]
} else { } else if self.recipes.is_empty() {
return Err(Error::NoRecipes); return Err(Error::NoRecipes);
} else {
return Err(Error::NoDefaultRecipe);
}; };
let arguments = argvec.as_slice(); let arguments = argvec.as_slice();

View File

@ -25,6 +25,10 @@ impl<'key, V: Keyed<'key>> Table<'key, V> {
self.map.get(key) self.map.get(key)
} }
pub(crate) fn is_empty(&self) -> bool {
self.map.is_empty()
}
pub(crate) fn values(&self) -> btree_map::Values<&'key str, V> { pub(crate) fn values(&self) -> btree_map::Values<&'key str, V> {
self.map.values() self.map.values()
} }

View File

@ -65,7 +65,10 @@ pub(crate) fn analysis_error(
let mut asts: HashMap<PathBuf, Ast> = HashMap::new(); let mut asts: HashMap<PathBuf, Ast> = HashMap::new();
asts.insert(root.clone(), ast); asts.insert(root.clone(), ast);
match Analyzer::analyze(&asts, &root) { let mut paths: HashMap<PathBuf, PathBuf> = HashMap::new();
paths.insert("justfile".into(), "justfile".into());
match Analyzer::analyze(&paths, &asts, &root) {
Ok(_) => panic!("Analysis unexpectedly succeeded"), Ok(_) => panic!("Analysis unexpectedly succeeded"),
Err(have) => { Err(have) => {
let want = CompileError { let want = CompileError {

View File

@ -37,12 +37,15 @@ fn include_succeeds_with_unstable() {
fn trailing_spaces_after_include_are_ignored() { fn trailing_spaces_after_include_are_ignored() {
Test::new() Test::new()
.tree(tree! { .tree(tree! {
"include.justfile": " "include.justfile": "",
})
.justfile(
"
!include ./include.justfile\x20
a: a:
@echo A @echo A
", ",
}) )
.justfile("!include ./include.justfile\x20")
.arg("--unstable") .arg("--unstable")
.test_round_trip(false) .test_round_trip(false)
.stdout("A\n") .stdout("A\n")
@ -103,3 +106,17 @@ fn circular_include() {
)) ))
.run(); .run();
} }
#[test]
fn include_recipes_are_not_default() {
Test::new()
.tree(tree! {
"include.justfile": "bar:",
})
.justfile("!include ./include.justfile")
.arg("--unstable")
.test_round_trip(false)
.status(EXIT_FAILURE)
.stderr("error: Justfile contains no default recipe.\n")
.run();
}