Slake Clippy's thirst for blood (#347)

This commit is contained in:
Casey Rodarmor 2018-08-27 18:36:40 -07:00 committed by GitHub
parent b14d1ec97c
commit 4e6585d391
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 69 additions and 72 deletions

View File

@ -173,7 +173,7 @@ mod test {
#[test] #[test]
fn backtick_code() { fn backtick_code() {
match parse_success("a:\n echo {{`f() { return 100; }; f`}}") match parse_success("a:\n echo {{`f() { return 100; }; f`}}")
.run(no_cwd_err(), &["a"], &Default::default()).unwrap_err() { .run(&no_cwd_err(), &["a"], &Default::default()).unwrap_err() {
RuntimeError::Backtick{token, output_error: OutputError::Code(code)} => { RuntimeError::Backtick{token, output_error: OutputError::Code(code)} => {
assert_eq!(code, 100); assert_eq!(code, 100);
assert_eq!(token.lexeme, "`f() { return 100; }; f`"); assert_eq!(token.lexeme, "`f() { return 100; }; f`");
@ -196,7 +196,7 @@ recipe:
..Default::default() ..Default::default()
}; };
match parse_success(text).run(no_cwd_err(), &["recipe"], &configuration).unwrap_err() { match parse_success(text).run(&no_cwd_err(), &["recipe"], &configuration).unwrap_err() {
RuntimeError::Backtick{token, output_error: OutputError::Code(_)} => { RuntimeError::Backtick{token, output_error: OutputError::Code(_)} => {
assert_eq!(token.lexeme, "`echo $exported_variable`"); assert_eq!(token.lexeme, "`echo $exported_variable`");
}, },

View File

@ -30,7 +30,7 @@ pub use misc::{default, empty};
pub use parameter::Parameter; pub use parameter::Parameter;
pub use parser::Parser; pub use parser::Parser;
pub use range_ext::RangeExt; pub use range_ext::RangeExt;
pub use recipe::Recipe; pub use recipe::{Recipe, RecipeContext};
pub use recipe_resolver::RecipeResolver; pub use recipe_resolver::RecipeResolver;
pub use runtime_error::{RuntimeError, RunResult}; pub use runtime_error::{RuntimeError, RunResult};
pub use shebang::Shebang; pub use shebang::Shebang;

View File

@ -8,10 +8,7 @@ pub struct Justfile<'a> {
pub exports: Set<&'a str>, pub exports: Set<&'a str>,
} }
impl<'a, 'b> Justfile<'a> impl<'a> Justfile<'a> where {
where
'a: 'b,
{
pub fn first(&self) -> Option<&Recipe> { pub fn first(&self) -> Option<&Recipe> {
let mut first: Option<&Recipe> = None; let mut first: Option<&Recipe> = None;
for recipe in self.recipes.values() { for recipe in self.recipes.values() {
@ -47,9 +44,9 @@ where
pub fn run( pub fn run(
&'a self, &'a self,
invocation_directory: Result<PathBuf, String>, invocation_directory: &'a Result<PathBuf, String>,
arguments: &[&'a str], arguments: &[&'a str],
configuration: &Configuration<'a>, configuration: &'a Configuration<'a>,
) -> RunResult<'a, ()> { ) -> RunResult<'a, ()> {
let unknown_overrides = configuration let unknown_overrides = configuration
.overrides .overrides
@ -68,7 +65,7 @@ where
let scope = AssignmentEvaluator::evaluate_assignments( let scope = AssignmentEvaluator::evaluate_assignments(
&self.assignments, &self.assignments,
&invocation_directory, invocation_directory,
&dotenv, &dotenv,
&configuration.overrides, &configuration.overrides,
configuration.quiet, configuration.quiet,
@ -128,15 +125,15 @@ where
}); });
} }
let context = RecipeContext{invocation_directory, configuration, scope};
let mut ran = empty(); let mut ran = empty();
for (recipe, arguments) in grouped { for (recipe, arguments) in grouped {
self.run_recipe( self.run_recipe(
&invocation_directory, &context,
recipe, recipe,
arguments, arguments,
&scope,
&dotenv, &dotenv,
configuration,
&mut ran, &mut ran,
)? )?
} }
@ -144,36 +141,30 @@ where
Ok(()) Ok(())
} }
fn run_recipe<'c>( fn run_recipe<'b>(
&'c self, &self,
invocation_directory: &Result<PathBuf, String>, context: &'b RecipeContext<'a>,
recipe: &Recipe<'a>, recipe: &Recipe<'a>,
arguments: &[&'a str], arguments: &[&'a str],
scope: &Map<&'c str, String>,
dotenv: &Map<String, String>, dotenv: &Map<String, String>,
configuration: &Configuration<'a>,
ran: &mut Set<&'a str>, ran: &mut Set<&'a str>,
) -> RunResult<()> { ) -> RunResult<()> {
for dependency_name in &recipe.dependencies { for dependency_name in &recipe.dependencies {
if !ran.contains(dependency_name) { if !ran.contains(dependency_name) {
self.run_recipe( self.run_recipe(
invocation_directory, context,
&self.recipes[dependency_name], &self.recipes[dependency_name],
&[], &[],
scope,
dotenv, dotenv,
configuration,
ran, ran,
)?; )?;
} }
} }
recipe.run( recipe.run(
invocation_directory, context,
arguments, arguments,
scope,
dotenv, dotenv,
&self.exports, &self.exports,
configuration,
)?; )?;
ran.insert(recipe.name); ran.insert(recipe.name);
Ok(()) Ok(())
@ -217,7 +208,7 @@ mod test {
#[test] #[test]
fn unknown_recipes() { fn unknown_recipes() {
match parse_success("a:\nb:\nc:") match parse_success("a:\nb:\nc:")
.run(no_cwd_err(), &["a", "x", "y", "z"], &Default::default()) .run(&no_cwd_err(), &["a", "x", "y", "z"], &Default::default())
.unwrap_err() .unwrap_err()
{ {
UnknownRecipes { UnknownRecipes {
@ -250,7 +241,7 @@ a:
"; ";
match parse_success(text) match parse_success(text)
.run(no_cwd_err(), &["a"], &Default::default()) .run(&no_cwd_err(), &["a"], &Default::default())
.unwrap_err() .unwrap_err()
{ {
Code { Code {
@ -269,7 +260,7 @@ a:
#[test] #[test]
fn code_error() { fn code_error() {
match parse_success("fail:\n @exit 100") match parse_success("fail:\n @exit 100")
.run(no_cwd_err(), &["fail"], &Default::default()) .run(&no_cwd_err(), &["fail"], &Default::default())
.unwrap_err() .unwrap_err()
{ {
Code { Code {
@ -292,7 +283,7 @@ a return code:
@x() { {{return}} {{code + "0"}}; }; x"#; @x() { {{return}} {{code + "0"}}; }; x"#;
match parse_success(text) match parse_success(text)
.run(no_cwd_err(), &["a", "return", "15"], &Default::default()) .run(&no_cwd_err(), &["a", "return", "15"], &Default::default())
.unwrap_err() .unwrap_err()
{ {
Code { Code {
@ -311,7 +302,7 @@ a return code:
#[test] #[test]
fn missing_some_arguments() { fn missing_some_arguments() {
match parse_success("a b c d:") match parse_success("a b c d:")
.run(no_cwd_err(), &["a", "b", "c"], &Default::default()) .run(&no_cwd_err(), &["a", "b", "c"], &Default::default())
.unwrap_err() .unwrap_err()
{ {
ArgumentCountMismatch { ArgumentCountMismatch {
@ -332,7 +323,7 @@ a return code:
#[test] #[test]
fn missing_some_arguments_variadic() { fn missing_some_arguments_variadic() {
match parse_success("a b c +d:") match parse_success("a b c +d:")
.run(no_cwd_err(), &["a", "B", "C"], &Default::default()) .run(&no_cwd_err(), &["a", "B", "C"], &Default::default())
.unwrap_err() .unwrap_err()
{ {
ArgumentCountMismatch { ArgumentCountMismatch {
@ -353,7 +344,7 @@ a return code:
#[test] #[test]
fn missing_all_arguments() { fn missing_all_arguments() {
match parse_success("a b c d:\n echo {{b}}{{c}}{{d}}") match parse_success("a b c d:\n echo {{b}}{{c}}{{d}}")
.run(no_cwd_err(), &["a"], &Default::default()) .run(&no_cwd_err(), &["a"], &Default::default())
.unwrap_err() .unwrap_err()
{ {
ArgumentCountMismatch { ArgumentCountMismatch {
@ -374,7 +365,7 @@ a return code:
#[test] #[test]
fn missing_some_defaults() { fn missing_some_defaults() {
match parse_success("a b c d='hello':") match parse_success("a b c d='hello':")
.run(no_cwd_err(), &["a", "b"], &Default::default()) .run(&no_cwd_err(), &["a", "b"], &Default::default())
.unwrap_err() .unwrap_err()
{ {
ArgumentCountMismatch { ArgumentCountMismatch {
@ -395,7 +386,7 @@ a return code:
#[test] #[test]
fn missing_all_defaults() { fn missing_all_defaults() {
match parse_success("a b c='r' d='h':") match parse_success("a b c='r' d='h':")
.run(no_cwd_err(), &["a"], &Default::default()) .run(&no_cwd_err(), &["a"], &Default::default())
.unwrap_err() .unwrap_err()
{ {
ArgumentCountMismatch { ArgumentCountMismatch {
@ -419,7 +410,7 @@ a return code:
configuration.overrides.insert("foo", "bar"); configuration.overrides.insert("foo", "bar");
configuration.overrides.insert("baz", "bob"); configuration.overrides.insert("baz", "bob");
match parse_success("a:\n echo {{`f() { return 100; }; f`}}") match parse_success("a:\n echo {{`f() { return 100; }; f`}}")
.run(no_cwd_err(), &["a"], &configuration) .run(&no_cwd_err(), &["a"], &configuration)
.unwrap_err() .unwrap_err()
{ {
UnknownOverrides { overrides } => { UnknownOverrides { overrides } => {
@ -447,7 +438,7 @@ wut:
}; };
match parse_success(text) match parse_success(text)
.run(no_cwd_err(), &["wut"], &configuration) .run(&no_cwd_err(), &["wut"], &configuration)
.unwrap_err() .unwrap_err()
{ {
Code { Code {

View File

@ -86,8 +86,8 @@ pub fn write_error_context(
i += c.len_utf8(); i += c.len_utf8();
} }
let line_number_width = line_number.to_string().len(); let line_number_width = line_number.to_string().len();
write!(f, "{0:1$} |\n", "", line_number_width)?; writeln!(f, "{0:1$} |", "", line_number_width)?;
write!(f, "{} | {}\n", line_number, space_line)?; writeln!(f, "{} | {}", line_number, space_line)?;
write!(f, "{0:1$} |", "", line_number_width)?; write!(f, "{0:1$} |", "", line_number_width)?;
if width == None { if width == None {
write!(f, " {0:1$}{2}^{3}", "", space_column, red.prefix(), red.suffix())?; write!(f, " {0:1$}{2}^{3}", "", space_column, red.prefix(), red.suffix())?;

View File

@ -31,13 +31,19 @@ pub struct Recipe<'a> {
pub shebang: bool, pub shebang: bool,
} }
pub struct RecipeContext<'a> {
pub invocation_directory: &'a Result<PathBuf, String>,
pub configuration: &'a Configuration<'a>,
pub scope: Map<&'a str, String>,
}
impl<'a> Recipe<'a> { impl<'a> Recipe<'a> {
pub fn argument_range(&self) -> Range<usize> { pub fn argument_range(&self) -> Range<usize> {
self.min_arguments()..self.max_arguments() + 1 self.min_arguments()..self.max_arguments() + 1
} }
pub fn min_arguments(&self) -> usize { pub fn min_arguments(&self) -> usize {
self.parameters.iter().filter(|p| !p.default.is_some()).count() self.parameters.iter().filter(|p| p.default.is_none()).count()
} }
pub fn max_arguments(&self) -> usize { pub fn max_arguments(&self) -> usize {
@ -50,13 +56,13 @@ impl<'a> Recipe<'a> {
pub fn run( pub fn run(
&self, &self,
invocation_directory: &Result<PathBuf, String>, context: &RecipeContext<'a>,
arguments: &[&'a str], arguments: &[&'a str],
scope: &Map<&'a str, String>, dotenv: &Map<String, String>,
dotenv: &Map<String, String>, exports: &Set<&'a str>,
exports: &Set<&'a str>,
configuration: &Configuration,
) -> RunResult<'a, ()> { ) -> RunResult<'a, ()> {
let configuration = &context.configuration;
if configuration.verbose { if configuration.verbose {
let color = configuration.color.stderr().banner(); let color = configuration.color.stderr().banner();
eprintln!("{}===> Running recipe `{}`...{}", color.prefix(), self.name, color.suffix()); eprintln!("{}===> Running recipe `{}`...{}", color.prefix(), self.name, color.suffix());
@ -86,16 +92,16 @@ impl<'a> Recipe<'a> {
} }
let mut evaluator = AssignmentEvaluator { let mut evaluator = AssignmentEvaluator {
assignments: &empty(), assignments: &empty(),
invocation_directory, dry_run: configuration.dry_run,
dry_run: configuration.dry_run, evaluated: empty(),
evaluated: empty(), invocation_directory: context.invocation_directory,
overrides: &empty(), overrides: &empty(),
quiet: configuration.quiet, quiet: configuration.quiet,
shell: configuration.shell, scope: &context.scope,
shell: configuration.shell,
dotenv, dotenv,
exports, exports,
scope,
}; };
if self.shebang { if self.shebang {
@ -157,7 +163,7 @@ impl<'a> Recipe<'a> {
let mut command = Platform::make_shebang_command(&path, interpreter, argument) let mut command = Platform::make_shebang_command(&path, interpreter, argument)
.map_err(|output_error| RuntimeError::Cygpath{recipe: self.name, output_error})?; .map_err(|output_error| RuntimeError::Cygpath{recipe: self.name, output_error})?;
command.export_environment_variables(scope, dotenv, exports)?; command.export_environment_variables(&context.scope, dotenv, exports)?;
// run it! // run it!
match InterruptHandler::guard(|| command.status()) { match InterruptHandler::guard(|| command.status()) {
@ -232,7 +238,7 @@ impl<'a> Recipe<'a> {
cmd.stdout(Stdio::null()); cmd.stdout(Stdio::null());
} }
cmd.export_environment_variables(scope, dotenv, exports)?; cmd.export_environment_variables(&context.scope, dotenv, exports)?;
match InterruptHandler::guard(|| cmd.status()) { match InterruptHandler::guard(|| cmd.status()) {
Ok(exit_status) => if let Some(code) = exit_status.code() { Ok(exit_status) => if let Some(code) = exit_status.code() {
@ -271,7 +277,7 @@ impl<'a> Display for Recipe<'a> {
for (i, pieces) in self.lines.iter().enumerate() { for (i, pieces) in self.lines.iter().enumerate() {
if i == 0 { if i == 0 {
writeln!(f, "")?; writeln!(f)?;
} }
for (j, piece) in pieces.iter().enumerate() { for (j, piece) in pieces.iter().enumerate() {
if j == 0 { if j == 0 {
@ -280,11 +286,11 @@ impl<'a> Display for Recipe<'a> {
match *piece { match *piece {
Fragment::Text{ref text} => write!(f, "{}", text.lexeme)?, Fragment::Text{ref text} => write!(f, "{}", text.lexeme)?,
Fragment::Expression{ref expression, ..} => Fragment::Expression{ref expression, ..} =>
write!(f, "{}{}{}", "{{", expression, "}}")?, write!(f, "{{{{{}}}}}", expression)?,
} }
} }
if i + 1 < self.lines.len() { if i + 1 < self.lines.len() {
write!(f, "\n")?; writeln!(f)?;
} }
} }
Ok(()) Ok(())

View File

@ -360,7 +360,7 @@ pub fn run() {
} }
if let Err(run_error) = justfile.run( if let Err(run_error) = justfile.run(
invocation_directory, &invocation_directory,
&arguments, &arguments,
&configuration) &configuration)
{ {

View File

@ -122,10 +122,10 @@ impl<'a> Display for RuntimeError<'a> {
} }
}, },
Dotenv{ref dotenv_error} => { Dotenv{ref dotenv_error} => {
write!(f, "Failed to load .env: {}\n", dotenv_error)?; writeln!(f, "Failed to load .env: {}", dotenv_error)?;
} }
FunctionCall{ref token, ref message} => { FunctionCall{ref token, ref message} => {
write!(f, "Call to function `{}` failed: {}\n", token.lexeme, message)?; writeln!(f, "Call to function `{}` failed: {}", token.lexeme, message)?;
error_token = Some(token); error_token = Some(token);
} }
Shebang{recipe, ref command, ref argument, ref io_error} => { Shebang{recipe, ref command, ref argument, ref io_error} => {
@ -152,31 +152,31 @@ impl<'a> Display for RuntimeError<'a> {
}, },
IoError{recipe, ref io_error} => { IoError{recipe, ref io_error} => {
match io_error.kind() { match io_error.kind() {
io::ErrorKind::NotFound => write!(f, io::ErrorKind::NotFound => writeln!(f,
"Recipe `{}` could not be run because just could not find `sh`:\n{}", "Recipe `{}` could not be run because just could not find `sh`:{}",
recipe, io_error), recipe, io_error),
io::ErrorKind::PermissionDenied => write!( io::ErrorKind::PermissionDenied => writeln!(
f, "Recipe `{}` could not be run because just could not run `sh`:\n{}", f, "Recipe `{}` could not be run because just could not run `sh`:{}",
recipe, io_error), recipe, io_error),
_ => write!(f, "Recipe `{}` could not be run because of an IO error while \ _ => writeln!(f, "Recipe `{}` could not be run because of an IO error while \
launching `sh`:\n{}", recipe, io_error), launching `sh`:{}", recipe, io_error),
}?; }?;
}, },
TmpdirIoError{recipe, ref io_error} => TmpdirIoError{recipe, ref io_error} =>
write!(f, "Recipe `{}` could not be run because of an IO error while trying \ writeln!(f, "Recipe `{}` could not be run because of an IO error while trying \
to create a temporary directory or write a file to that directory`:\n{}", to create a temporary directory or write a file to that directory`:{}",
recipe, io_error)?, recipe, io_error)?,
Backtick{ref token, ref output_error} => match *output_error { Backtick{ref token, ref output_error} => match *output_error {
OutputError::Code(code) => { OutputError::Code(code) => {
write!(f, "Backtick failed with exit code {}\n", code)?; writeln!(f, "Backtick failed with exit code {}", code)?;
error_token = Some(token); error_token = Some(token);
} }
OutputError::Signal(signal) => { OutputError::Signal(signal) => {
write!(f, "Backtick was terminated by signal {}\n", signal)?; writeln!(f, "Backtick was terminated by signal {}", signal)?;
error_token = Some(token); error_token = Some(token);
} }
OutputError::Unknown => { OutputError::Unknown => {
write!(f, "Backtick failed for an unknown reason\n")?; writeln!(f, "Backtick failed for an unknown reason")?;
error_token = Some(token); error_token = Some(token);
} }
OutputError::Io(ref io_error) => { OutputError::Io(ref io_error) => {
@ -192,7 +192,7 @@ impl<'a> Display for RuntimeError<'a> {
error_token = Some(token); error_token = Some(token);
} }
OutputError::Utf8(ref utf8_error) => { OutputError::Utf8(ref utf8_error) => {
write!(f, "Backtick succeeded but stdout was not utf8: {}\n", utf8_error)?; writeln!(f, "Backtick succeeded but stdout was not utf8: {}", utf8_error)?;
error_token = Some(token); error_token = Some(token);
} }
}, },