Use ...? instead of try!(...) (#72)

See https://blog.rust-lang.org/2016/11/10/Rust-1.13.html for more info.

Huge diff, but all tests still pass, so yolo.
This commit is contained in:
Casey Rodarmor 2016-11-11 21:37:16 -08:00 committed by GitHub
parent bd69f3298e
commit 5663cb61a6

View File

@ -48,7 +48,7 @@ trait Slurp {
impl Slurp for fs::File { impl Slurp for fs::File {
fn slurp(&mut self) -> Result<String, std::io::Error> { fn slurp(&mut self) -> Result<String, std::io::Error> {
let mut destination = String::new(); let mut destination = String::new();
try!(self.read_to_string(&mut destination)); self.read_to_string(&mut destination)?;
Ok(destination) Ok(destination)
} }
} }
@ -114,10 +114,10 @@ impl<'a> Iterator for Variables<'a> {
impl<'a> Display for Expression<'a> { impl<'a> Display for Expression<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self { match *self {
Expression::Backtick {raw, .. } => try!(write!(f, "`{}`", raw)), Expression::Backtick {raw, .. } => write!(f, "`{}`", raw)?,
Expression::Concatination{ref lhs, ref rhs} => try!(write!(f, "{} + {}", lhs, rhs)), Expression::Concatination{ref lhs, ref rhs} => write!(f, "{} + {}", lhs, rhs)?,
Expression::String {raw, .. } => try!(write!(f, "\"{}\"", raw)), Expression::String {raw, .. } => write!(f, "\"{}\"", raw)?,
Expression::Variable {name, .. } => try!(write!(f, "{}", name)), Expression::Variable {name, .. } => write!(f, "{}", name)?,
} }
Ok(()) Ok(())
} }
@ -184,7 +184,7 @@ fn run_backtick<'a>(
) -> Result<String, RunError<'a>> { ) -> Result<String, RunError<'a>> {
let mut cmd = process::Command::new("sh"); let mut cmd = process::Command::new("sh");
try!(export_env(&mut cmd, scope, exports)); export_env(&mut cmd, scope, exports)?;
cmd.arg("-cu") cmd.arg("-cu")
.arg(raw); .arg(raw);
@ -247,7 +247,7 @@ impl<'a> Recipe<'a> {
if self.shebang { if self.shebang {
let mut evaluated_lines = vec![]; let mut evaluated_lines = vec![];
for line in &self.lines { for line in &self.lines {
evaluated_lines.push(try!(evaluator.evaluate_line(&line, &argument_map))); evaluated_lines.push(evaluator.evaluate_line(&line, &argument_map)?);
} }
if options.dry_run { if options.dry_run {
@ -257,17 +257,13 @@ impl<'a> Recipe<'a> {
return Ok(()); return Ok(());
} }
let tmp = try!( let tmp = tempdir::TempDir::new("just")
tempdir::TempDir::new("just") .map_err(|error| RunError::TmpdirIoError{recipe: self.name, io_error: error})?;
.map_err(|error| RunError::TmpdirIoError{recipe: self.name, io_error: error})
);
let mut path = tmp.path().to_path_buf(); let mut path = tmp.path().to_path_buf();
path.push(self.name); path.push(self.name);
{ {
let mut f = try!( let mut f = fs::File::create(&path)
fs::File::create(&path) .map_err(|error| RunError::TmpdirIoError{recipe: self.name, io_error: error})?;
.map_err(|error| RunError::TmpdirIoError{recipe: self.name, io_error: error})
);
let mut text = String::new(); let mut text = String::new();
// add the shebang // add the shebang
text += &evaluated_lines[0]; text += &evaluated_lines[0];
@ -282,44 +278,40 @@ impl<'a> Recipe<'a> {
text += line; text += line;
text += "\n"; text += "\n";
} }
try!( f.write_all(text.as_bytes())
f.write_all(text.as_bytes()) .map_err(|error| RunError::TmpdirIoError{recipe: self.name, io_error: error})?;
.map_err(|error| RunError::TmpdirIoError{recipe: self.name, io_error: error})
);
} }
// get current permissions // get current permissions
let mut perms = try!( let mut perms = fs::metadata(&path)
fs::metadata(&path) .map_err(|error| RunError::TmpdirIoError{recipe: self.name, io_error: error})?
.map_err(|error| RunError::TmpdirIoError{recipe: self.name, io_error: error}) .permissions();
).permissions();
// make the script executable // make the script executable
let current_mode = perms.mode(); let current_mode = perms.mode();
perms.set_mode(current_mode | 0o100); perms.set_mode(current_mode | 0o100);
try!(fs::set_permissions(&path, perms) fs::set_permissions(&path, perms)
.map_err(|error| RunError::TmpdirIoError{recipe: self.name, io_error: error})); .map_err(|error| RunError::TmpdirIoError{recipe: self.name, io_error: error})?;
// run it! // run it!
let mut command = process::Command::new(path); let mut command = process::Command::new(path);
try!(export_env(&mut command, scope, exports)); export_env(&mut command, scope, exports)?;
try!(match command.status() { match command.status() {
Ok(exit_status) => if let Some(code) = exit_status.code() { Ok(exit_status) => if let Some(code) = exit_status.code() {
if code == 0 { if code != 0 {
Ok(()) return Err(RunError::Code{recipe: self.name, code: code})
} else {
Err(RunError::Code{recipe: self.name, code: code})
} }
} else { } else {
Err(error_from_signal(self.name, exit_status)) return Err(error_from_signal(self.name, exit_status))
}, },
Err(io_error) => Err(RunError::TmpdirIoError{recipe: self.name, io_error: io_error}) Err(io_error) => return Err(RunError::TmpdirIoError{
}); recipe: self.name, io_error: io_error})
};
} else { } else {
for line in &self.lines { for line in &self.lines {
let evaluated = &try!(evaluator.evaluate_line(&line, &argument_map)); let evaluated = &evaluator.evaluate_line(&line, &argument_map)?;
let mut command = evaluated.as_str(); let mut command = evaluated.as_str();
let quiet_command = command.starts_with('@'); let quiet_command = command.starts_with('@');
if quiet_command { if quiet_command {
@ -341,20 +333,19 @@ impl<'a> Recipe<'a> {
cmd.stdout(process::Stdio::null()); cmd.stdout(process::Stdio::null());
} }
try!(export_env(&mut cmd, scope, exports)); export_env(&mut cmd, scope, exports)?;
try!(match cmd.status() { match cmd.status() {
Ok(exit_status) => if let Some(code) = exit_status.code() { Ok(exit_status) => if let Some(code) = exit_status.code() {
if code == 0 { if code != 0 {
Ok(()) return Err(RunError::Code{recipe: self.name, code: code});
} else {
Err(RunError::Code{recipe: self.name, code: code})
} }
} else { } else {
Err(error_from_signal(self.name, exit_status)) return Err(error_from_signal(self.name, exit_status));
}, },
Err(io_error) => Err(RunError::IoError{recipe: self.name, io_error: io_error}) Err(io_error) => return Err(RunError::IoError{
}); recipe: self.name, io_error: io_error}),
};
} }
} }
Ok(()) Ok(())
@ -363,31 +354,31 @@ impl<'a> Recipe<'a> {
impl<'a> Display for Recipe<'a> { impl<'a> Display for Recipe<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
try!(write!(f, "{}", self.name)); write!(f, "{}", self.name)?;
for parameter in &self.parameters { for parameter in &self.parameters {
try!(write!(f, " {}", parameter)); write!(f, " {}", parameter)?;
} }
try!(write!(f, ":")); write!(f, ":")?;
for dependency in &self.dependencies { for dependency in &self.dependencies {
try!(write!(f, " {}", dependency)) write!(f, " {}", dependency)?;
} }
for (i, pieces) in self.lines.iter().enumerate() { for (i, pieces) in self.lines.iter().enumerate() {
if i == 0 { if i == 0 {
try!(writeln!(f, "")); writeln!(f, "")?;
} }
for (j, piece) in pieces.iter().enumerate() { for (j, piece) in pieces.iter().enumerate() {
if j == 0 { if j == 0 {
try!(write!(f, " ")); write!(f, " ")?;
} }
match *piece { match *piece {
Fragment::Text{ref text} => try!(write!(f, "{}", text.lexeme)), Fragment::Text{ref text} => write!(f, "{}", text.lexeme)?,
Fragment::Expression{ref expression, ..} => Fragment::Expression{ref expression, ..} =>
try!(write!(f, "{}{}{}", "{{", expression, "}}")), write!(f, "{}{}{}", "{{", expression, "}}")?,
} }
} }
if i + 1 < self.lines.len() { if i + 1 < self.lines.len() {
try!(write!(f, "\n")); write!(f, "\n")?;
} }
} }
Ok(()) Ok(())
@ -407,7 +398,7 @@ fn resolve_recipes<'a>(
}; };
for recipe in recipes.values() { for recipe in recipes.values() {
try!(resolver.resolve(&recipe)); resolver.resolve(&recipe)?;
} }
for recipe in recipes.values() { for recipe in recipes.values() {
@ -502,7 +493,7 @@ fn resolve_assignments<'a>(
}; };
for name in assignments.keys() { for name in assignments.keys() {
try!(resolver.resolve_assignment(name)); resolver.resolve_assignment(name)?;
} }
Ok(()) Ok(())
@ -526,7 +517,7 @@ impl<'a: 'b, 'b> AssignmentResolver<'a, 'b> {
self.stack.push(name); self.stack.push(name);
if let Some(expression) = self.assignments.get(name) { if let Some(expression) = self.assignments.get(name) {
try!(self.resolve_expression(expression)); self.resolve_expression(expression)?;
self.evaluated.insert(name); self.evaluated.insert(name);
} else { } else {
return Err(internal_error(format!("attempted to resolve unknown assignment `{}`", name))); return Err(internal_error(format!("attempted to resolve unknown assignment `{}`", name)));
@ -547,14 +538,14 @@ impl<'a: 'b, 'b> AssignmentResolver<'a, 'b> {
circle: self.stack.clone(), circle: self.stack.clone(),
})); }));
} else if self.assignments.contains_key(name) { } else if self.assignments.contains_key(name) {
try!(self.resolve_assignment(name)); self.resolve_assignment(name)?;
} else { } else {
return Err(token.error(ErrorKind::UndefinedVariable{variable: name})); return Err(token.error(ErrorKind::UndefinedVariable{variable: name}));
} }
} }
Expression::Concatination{ref lhs, ref rhs} => { Expression::Concatination{ref lhs, ref rhs} => {
try!(self.resolve_expression(lhs)); self.resolve_expression(lhs)?;
try!(self.resolve_expression(rhs)); self.resolve_expression(rhs)?;
} }
Expression::String{..} | Expression::Backtick{..} => {} Expression::String{..} | Expression::Backtick{..} => {}
} }
@ -577,7 +568,7 @@ fn evaluate_assignments<'a>(
}; };
for name in assignments.keys() { for name in assignments.keys() {
try!(evaluator.evaluate_assignment(name)); evaluator.evaluate_assignment(name)?;
} }
Ok(evaluator.evaluated) Ok(evaluator.evaluated)
@ -603,7 +594,7 @@ impl<'a, 'b> Evaluator<'a, 'b> {
match *fragment { match *fragment {
Fragment::Text{ref text} => evaluated += text.lexeme, Fragment::Text{ref text} => evaluated += text.lexeme,
Fragment::Expression{ref expression} => { Fragment::Expression{ref expression} => {
evaluated += &try!(self.evaluate_expression(expression, arguments)); evaluated += &self.evaluate_expression(expression, arguments)?;
} }
} }
} }
@ -619,7 +610,7 @@ impl<'a, 'b> Evaluator<'a, 'b> {
if let Some(value) = self.overrides.get(name) { if let Some(value) = self.overrides.get(name) {
self.evaluated.insert(name, value.to_string()); self.evaluated.insert(name, value.to_string());
} else { } else {
let value = try!(self.evaluate_expression(expression, &Map::new())); let value = self.evaluate_expression(expression, &Map::new())?;
self.evaluated.insert(name, value); self.evaluated.insert(name, value);
} }
} else { } else {
@ -643,7 +634,7 @@ impl<'a, 'b> Evaluator<'a, 'b> {
} else if self.scope.contains_key(name) { } else if self.scope.contains_key(name) {
self.scope[name].clone() self.scope[name].clone()
} else if self.assignments.contains_key(name) { } else if self.assignments.contains_key(name) {
try!(self.evaluate_assignment(name)); self.evaluate_assignment(name)?;
self.evaluated[name].clone() self.evaluated[name].clone()
} else if arguments.contains_key(name) { } else if arguments.contains_key(name) {
arguments[name].to_string() arguments[name].to_string()
@ -655,12 +646,12 @@ impl<'a, 'b> Evaluator<'a, 'b> {
} }
Expression::String{ref cooked, ..} => cooked.clone(), Expression::String{ref cooked, ..} => cooked.clone(),
Expression::Backtick{raw, ref token} => { Expression::Backtick{raw, ref token} => {
try!(run_backtick(raw, token, &self.scope, &self.exports, self.quiet)) run_backtick(raw, token, &self.scope, &self.exports, self.quiet)?
} }
Expression::Concatination{ref lhs, ref rhs} => { Expression::Concatination{ref lhs, ref rhs} => {
try!(self.evaluate_expression(lhs, arguments)) self.evaluate_expression(lhs, arguments)?
+ +
&try!(self.evaluate_expression(rhs, arguments)) &self.evaluate_expression(rhs, arguments)?
} }
}) })
} }
@ -760,15 +751,15 @@ fn conjoin<T: Display>(
) -> Result<(), fmt::Error> { ) -> Result<(), fmt::Error> {
match values.len() { match values.len() {
0 => {}, 0 => {},
1 => try!(write!(f, "{}", values[0])), 1 => write!(f, "{}", values[0])?,
2 => try!(write!(f, "{} {} {}", values[0], conjunction, values[1])), 2 => write!(f, "{} {} {}", values[0], conjunction, values[1])?,
_ => for (i, item) in values.iter().enumerate() { _ => for (i, item) in values.iter().enumerate() {
try!(write!(f, "{}", item)); write!(f, "{}", item)?;
if i == values.len() - 1 { if i == values.len() - 1 {
} else if i == values.len() - 2 { } else if i == values.len() - 2 {
try!(write!(f, ", {} ", conjunction)); write!(f, ", {} ", conjunction)?;
} else { } else {
try!(write!(f, ", ")) write!(f, ", ")?
} }
}, },
} }
@ -813,18 +804,18 @@ 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();
try!(write!(f, "{0:1$} |\n", "", line_number_width)); write!(f, "{0:1$} |\n", "", line_number_width)?;
try!(write!(f, "{} | {}\n", line_number, space_line)); write!(f, "{} | {}\n", line_number, space_line)?;
try!(write!(f, "{0:1$} |", "", line_number_width)); write!(f, "{0:1$} |", "", line_number_width)?;
if width == None { if width == None {
try!(write!(f, " {0:1$}{2}^{3}", "", space_column, red.prefix(), red.suffix())); write!(f, " {0:1$}{2}^{3}", "", space_column, red.prefix(), red.suffix())?;
} else { } else {
try!(write!(f, " {0:1$}{2}{3:^<4$}{5}", "", space_column, write!(f, " {0:1$}{2}{3:^<4$}{5}", "", space_column,
red.prefix(), "", space_width, red.suffix())); red.prefix(), "", space_width, red.suffix())?;
} }
}, },
None => if index != text.len() { None => if index != text.len() {
try!(write!(f, "internal error: Error has invalid line number: {}", line_number)) write!(f, "internal error: Error has invalid line number: {}", line_number)?
}, },
} }
Ok(()) Ok(())
@ -862,96 +853,94 @@ impl<'a> Display for Error<'a> {
let red = maybe_red(f.alternate()); let red = maybe_red(f.alternate());
let bold = maybe_bold(f.alternate()); let bold = maybe_bold(f.alternate());
try!(write!(f, "{} {}", red.paint("error:"), bold.prefix())); write!(f, "{} {}", red.paint("error:"), bold.prefix())?;
match self.kind { match self.kind {
ErrorKind::CircularRecipeDependency{recipe, ref circle} => { ErrorKind::CircularRecipeDependency{recipe, ref circle} => {
if circle.len() == 2 { if circle.len() == 2 {
try!(write!(f, "recipe `{}` depends on itself", recipe)); write!(f, "recipe `{}` depends on itself", recipe)?;
} else { } else {
try!(writeln!(f, "recipe `{}` has circular dependency `{}`", writeln!(f, "recipe `{}` has circular dependency `{}`",
recipe, circle.join(" -> "))); recipe, circle.join(" -> "))?;
} }
} }
ErrorKind::CircularVariableDependency{variable, ref circle} => { ErrorKind::CircularVariableDependency{variable, ref circle} => {
if circle.len() == 2 { if circle.len() == 2 {
try!(writeln!(f, "variable `{}` depends on its own value: `{}`", writeln!(f, "variable `{}` depends on its own value: `{}`",
variable, circle.join(" -> "))); variable, circle.join(" -> "))?;
} else { } else {
try!(writeln!(f, "variable `{}` depends on its own value: `{}`", writeln!(f, "variable `{}` depends on its own value: `{}`",
variable, circle.join(" -> "))); variable, circle.join(" -> "))?;
} }
} }
ErrorKind::InvalidEscapeSequence{character} => { ErrorKind::InvalidEscapeSequence{character} => {
try!(writeln!(f, "`\\{}` is not a valid escape sequence", writeln!(f, "`\\{}` is not a valid escape sequence",
character.escape_default().collect::<String>())); character.escape_default().collect::<String>())?;
} }
ErrorKind::DuplicateParameter{recipe, parameter} => { ErrorKind::DuplicateParameter{recipe, parameter} => {
try!(writeln!(f, "recipe `{}` has duplicate parameter `{}`", recipe, parameter)); writeln!(f, "recipe `{}` has duplicate parameter `{}`", recipe, parameter)?;
} }
ErrorKind::DuplicateVariable{variable} => { ErrorKind::DuplicateVariable{variable} => {
try!(writeln!(f, "variable `{}` is has multiple definitions", variable)); writeln!(f, "variable `{}` is has multiple definitions", variable)?;
} }
ErrorKind::UnexpectedToken{ref expected, found} => { ErrorKind::UnexpectedToken{ref expected, found} => {
try!(writeln!(f, "expected {} but found {}", Or(expected), found)); writeln!(f, "expected {} but found {}", Or(expected), found)?;
} }
ErrorKind::DuplicateDependency{recipe, dependency} => { ErrorKind::DuplicateDependency{recipe, dependency} => {
try!(writeln!(f, "recipe `{}` has duplicate dependency `{}`", recipe, dependency)); writeln!(f, "recipe `{}` has duplicate dependency `{}`", recipe, dependency)?;
} }
ErrorKind::DuplicateRecipe{recipe, first} => { ErrorKind::DuplicateRecipe{recipe, first} => {
try!(writeln!(f, "recipe `{}` first defined on line {} is redefined on line {}", writeln!(f, "recipe `{}` first defined on line {} is redefined on line {}",
recipe, first, self.line)); recipe, first, self.line)?;
} }
ErrorKind::DependencyHasParameters{recipe, dependency} => { ErrorKind::DependencyHasParameters{recipe, dependency} => {
try!(writeln!(f, "recipe `{}` depends on `{}` which requires arguments. \ writeln!(f, "recipe `{}` depends on `{}` which requires arguments. \
dependencies may not require arguments", recipe, dependency)); dependencies may not require arguments", recipe, dependency)?;
} }
ErrorKind::ParameterShadowsVariable{parameter} => { ErrorKind::ParameterShadowsVariable{parameter} => {
try!(writeln!(f, "parameter `{}` shadows variable of the same name", parameter)); writeln!(f, "parameter `{}` shadows variable of the same name", parameter)?;
} }
ErrorKind::MixedLeadingWhitespace{whitespace} => { ErrorKind::MixedLeadingWhitespace{whitespace} => {
try!(writeln!(f, writeln!(f,
"found a mix of tabs and spaces in leading whitespace: `{}`\n\ "found a mix of tabs and spaces in leading whitespace: `{}`\n\
leading whitespace may consist of tabs or spaces, but not both", leading whitespace may consist of tabs or spaces, but not both",
show_whitespace(whitespace) show_whitespace(whitespace)
)); )?;
} }
ErrorKind::ExtraLeadingWhitespace => { ErrorKind::ExtraLeadingWhitespace => {
try!(writeln!(f, "recipe line has extra leading whitespace")); writeln!(f, "recipe line has extra leading whitespace")?;
} }
ErrorKind::InconsistentLeadingWhitespace{expected, found} => { ErrorKind::InconsistentLeadingWhitespace{expected, found} => {
try!(writeln!(f, writeln!(f,
"inconsistant leading whitespace: recipe started with `{}` but found line with `{}`:", "inconsistant leading whitespace: recipe started with `{}` but found line with `{}`:",
show_whitespace(expected), show_whitespace(found) show_whitespace(expected), show_whitespace(found)
)); )?;
} }
ErrorKind::OuterShebang => { ErrorKind::OuterShebang => {
try!(writeln!(f, "a shebang `#!` is reserved syntax outside of recipes")) writeln!(f, "a shebang `#!` is reserved syntax outside of recipes")?;
} }
ErrorKind::UnknownDependency{recipe, unknown} => { ErrorKind::UnknownDependency{recipe, unknown} => {
try!(writeln!(f, "recipe `{}` has unknown dependency `{}`", recipe, unknown)); writeln!(f, "recipe `{}` has unknown dependency `{}`", recipe, unknown)?;
} }
ErrorKind::UndefinedVariable{variable} => { ErrorKind::UndefinedVariable{variable} => {
try!(writeln!(f, "variable `{}` not defined", variable)); writeln!(f, "variable `{}` not defined", variable)?;
} }
ErrorKind::UnknownStartOfToken => { ErrorKind::UnknownStartOfToken => {
try!(writeln!(f, "unknown start of token:")); writeln!(f, "unknown start of token:")?;
} }
ErrorKind::UnterminatedString => { ErrorKind::UnterminatedString => {
try!(writeln!(f, "unterminated string")); writeln!(f, "unterminated string")?;
} }
ErrorKind::InternalError{ref message} => { ErrorKind::InternalError{ref message} => {
try!(writeln!(f, "internal error, this may indicate a bug in just: {}\n\ writeln!(f, "internal error, this may indicate a bug in just: {}\n\
consider filing an issue: https://github.com/casey/just/issues/new", consider filing an issue: https://github.com/casey/just/issues/new",
message)); message)?;
} }
} }
try!(write!(f, "{}", bold.suffix())); write!(f, "{}", bold.suffix())?;
try!(write_error_context(f, self.text, self.index, self.line, self.column, self.width)); write_error_context(f, self.text, self.index, self.line, self.column, self.width)
Ok(())
} }
} }
@ -1005,7 +994,7 @@ impl<'a, 'b> Justfile<'a> where 'a: 'b {
return Err(RunError::UnknownOverrides{overrides: unknown_overrides}); return Err(RunError::UnknownOverrides{overrides: unknown_overrides});
} }
let scope = try!(evaluate_assignments(&self.assignments, &options.overrides, options.quiet)); let scope = evaluate_assignments(&self.assignments, &options.overrides, options.quiet)?;
if options.evaluate { if options.evaluate {
for (name, value) in scope { for (name, value) in scope {
println!("{} = \"{}\"", name, value); println!("{} = \"{}\"", name, value);
@ -1029,8 +1018,7 @@ impl<'a, 'b> Justfile<'a> where 'a: 'b {
expected: recipe.parameters.len(), expected: recipe.parameters.len(),
}); });
} }
try!(self.run_recipe(recipe, rest, &scope, &mut ran, options)); return self.run_recipe(recipe, rest, &scope, &mut ran, options);
return Ok(());
} }
} else { } else {
break; break;
@ -1047,7 +1035,7 @@ impl<'a, 'b> Justfile<'a> where 'a: 'b {
return Err(RunError::UnknownRecipes{recipes: missing}); return Err(RunError::UnknownRecipes{recipes: missing});
} }
for recipe in arguments.iter().map(|name| &self.recipes[name]) { for recipe in arguments.iter().map(|name| &self.recipes[name]) {
try!(self.run_recipe(recipe, &[], &scope, &mut ran, options)); self.run_recipe(recipe, &[], &scope, &mut ran, options)?;
} }
Ok(()) Ok(())
} }
@ -1062,10 +1050,10 @@ impl<'a, 'b> Justfile<'a> where 'a: 'b {
) -> Result<(), RunError> { ) -> Result<(), RunError> {
for dependency_name in &recipe.dependencies { for dependency_name in &recipe.dependencies {
if !ran.contains(dependency_name) { if !ran.contains(dependency_name) {
try!(self.run_recipe(&self.recipes[dependency_name], &[], scope, ran, options)); self.run_recipe(&self.recipes[dependency_name], &[], scope, ran, options)?;
} }
} }
try!(recipe.run(arguments, &scope, &self.exports, options)); recipe.run(arguments, &scope, &self.exports, options)?;
ran.insert(recipe.name); ran.insert(recipe.name);
Ok(()) Ok(())
} }
@ -1080,19 +1068,19 @@ impl<'a> Display for Justfile<'a> {
let mut items = self.recipes.len() + self.assignments.len(); let mut items = self.recipes.len() + self.assignments.len();
for (name, expression) in &self.assignments { for (name, expression) in &self.assignments {
if self.exports.contains(name) { if self.exports.contains(name) {
try!(write!(f, "export ")); write!(f, "export ")?;
} }
try!(write!(f, "{} = {}", name, expression)); write!(f, "{} = {}", name, expression)?;
items -= 1; items -= 1;
if items != 0 { if items != 0 {
try!(write!(f, "\n\n")); write!(f, "\n\n")?;
} }
} }
for recipe in self.recipes.values() { for recipe in self.recipes.values() {
try!(write!(f, "{}", recipe)); write!(f, "{}", recipe)?;
items -= 1; items -= 1;
if items != 0 { if items != 0 {
try!(write!(f, "\n\n")); write!(f, "\n\n")?;
} }
} }
Ok(()) Ok(())
@ -1122,41 +1110,40 @@ impl<'a> Display for RunError<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let red = maybe_red(f.alternate()); let red = maybe_red(f.alternate());
let bold = maybe_bold(f.alternate()); let bold = maybe_bold(f.alternate());
try!(write!(f, "{} {}", red.paint("error:"), bold.prefix())); write!(f, "{} {}", red.paint("error:"), bold.prefix())?;
let mut error_token = None; let mut error_token = None;
match *self { match *self {
RunError::UnknownRecipes{ref recipes} => { RunError::UnknownRecipes{ref recipes} => {
try!(write!(f, "Justfile does not contain recipe{} {}", write!(f, "Justfile does not contain recipe{} {}",
maybe_s(recipes.len()), Or(&ticks(&recipes)))); maybe_s(recipes.len()), Or(&ticks(&recipes)))?;
}, },
RunError::UnknownOverrides{ref overrides} => { RunError::UnknownOverrides{ref overrides} => {
try!(write!(f, write!(f, "Variable{} {} overridden on the command line but not present in justfile",
"Variable{} {} overridden on the command line but not present in justfile", maybe_s(overrides.len()),
maybe_s(overrides.len()), And(&overrides.iter().map(Tick).collect::<Vec<_>>()))?;
And(&overrides.iter().map(Tick).collect::<Vec<_>>())))
}, },
RunError::NonLeadingRecipeWithParameters{recipe} => { RunError::NonLeadingRecipeWithParameters{recipe} => {
try!(write!(f, "Recipe `{}` takes arguments and so must be the first and only recipe \ write!(f, "Recipe `{}` takes arguments and so must be the first and only recipe \
specified on the command line", recipe)); specified on the command line", recipe)?;
}, },
RunError::ArgumentCountMismatch{recipe, found, expected} => { RunError::ArgumentCountMismatch{recipe, found, expected} => {
try!(write!(f, "Recipe `{}` got {} argument{} but {}takes {}", write!(f, "Recipe `{}` got {} argument{} but {}takes {}",
recipe, found, maybe_s(found), recipe, found, maybe_s(found),
if expected < found { "only " } else { "" }, expected)); if expected < found { "only " } else { "" }, expected)?;
}, },
RunError::Code{recipe, code} => { RunError::Code{recipe, code} => {
try!(write!(f, "Recipe `{}` failed with exit code {}", recipe, code)); write!(f, "Recipe `{}` failed with exit code {}", recipe, code)?;
}, },
RunError::Signal{recipe, signal} => { RunError::Signal{recipe, signal} => {
try!(write!(f, "Recipe `{}` wast terminated by signal {}", recipe, signal)); write!(f, "Recipe `{}` wast terminated by signal {}", recipe, signal)?;
} }
RunError::UnknownFailure{recipe} => { RunError::UnknownFailure{recipe} => {
try!(write!(f, "Recipe `{}` failed for an unknown reason", recipe)); write!(f, "Recipe `{}` failed for an unknown reason", recipe)?;
}, },
RunError::IoError{recipe, ref io_error} => { RunError::IoError{recipe, ref io_error} => {
try!(match io_error.kind() { match io_error.kind() {
io::ErrorKind::NotFound => write!(f, io::ErrorKind::NotFound => write!(f,
"Recipe `{}` could not be run because just could not find `sh` the command:\n{}", "Recipe `{}` could not be run because just could not find `sh` the command:\n{}",
recipe, io_error), recipe, io_error),
@ -1165,26 +1152,26 @@ impl<'a> Display for RunError<'a> {
recipe, io_error), recipe, io_error),
_ => write!(f, "Recipe `{}` could not be run because of an IO error while \ _ => write!(f, "Recipe `{}` could not be run because of an IO error while \
launching `sh`:\n{}", recipe, io_error), launching `sh`:\n{}", recipe, io_error),
}); }?;
}, },
RunError::TmpdirIoError{recipe, ref io_error} => RunError::TmpdirIoError{recipe, ref io_error} =>
try!(write!(f, "Recipe `{}` could not be run because of an IO error while trying \ write!(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`:\n{}",
recipe, io_error)), recipe, io_error)?,
RunError::BacktickCode{code, ref token} => { RunError::BacktickCode{code, ref token} => {
try!(write!(f, "backtick failed with exit code {}\n", code)); write!(f, "backtick failed with exit code {}\n", code)?;
error_token = Some(token); error_token = Some(token);
} }
RunError::BacktickSignal{ref token, signal} => { RunError::BacktickSignal{ref token, signal} => {
try!(write!(f, "backtick was terminated by signal {}", signal)); write!(f, "backtick was terminated by signal {}", signal)?;
error_token = Some(token); error_token = Some(token);
} }
RunError::BacktickUnknownFailure{ref token} => { RunError::BacktickUnknownFailure{ref token} => {
try!(write!(f, "backtick failed for an uknown reason")); write!(f, "backtick failed for an uknown reason")?;
error_token = Some(token); error_token = Some(token);
} }
RunError::BacktickIoError{ref token, ref io_error} => { RunError::BacktickIoError{ref token, ref io_error} => {
try!(match io_error.kind() { match io_error.kind() {
io::ErrorKind::NotFound => write!( io::ErrorKind::NotFound => write!(
f, "backtick could not be run because just could not find `sh` the command:\n{}", f, "backtick could not be run because just could not find `sh` the command:\n{}",
io_error), io_error),
@ -1192,23 +1179,24 @@ impl<'a> Display for RunError<'a> {
f, "backtick could not be run because just could not run `sh`:\n{}", io_error), f, "backtick could not be run because just could not run `sh`:\n{}", io_error),
_ => write!(f, "backtick could not be run because of an IO \ _ => write!(f, "backtick could not be run because of an IO \
error while launching `sh`:\n{}", io_error), error while launching `sh`:\n{}", io_error),
}); }?;
error_token = Some(token); error_token = Some(token);
} }
RunError::BacktickUtf8Error{ref token, ref utf8_error} => { RunError::BacktickUtf8Error{ref token, ref utf8_error} => {
try!(write!(f, "backtick succeeded but stdout was not utf8: {}", utf8_error)); write!(f, "backtick succeeded but stdout was not utf8: {}", utf8_error)?;
error_token = Some(token); error_token = Some(token);
} }
RunError::InternalError{ref message} => { RunError::InternalError{ref message} => {
try!(write!(f, "internal error, this may indicate a bug in just: {} write!(f, "internal error, this may indicate a bug in just: {} \
consider filing an issue: https://github.com/casey/just/issues/new", message)); consider filing an issue: https://github.com/casey/just/issues/new",
message)?;
} }
} }
try!(write!(f, "{}", bold.suffix())); write!(f, "{}", bold.suffix())?;
if let Some(token) = error_token { if let Some(token) = error_token {
try!(write_token_error_context(f, token)); write_token_error_context(f, token)?;
} }
Ok(()) Ok(())
@ -1261,7 +1249,7 @@ enum TokenKind {
impl Display for TokenKind { impl Display for TokenKind {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
try!(write!(f, "{}", match *self { write!(f, "{}", match *self {
Backtick => "backtick", Backtick => "backtick",
Colon => "\":\"", Colon => "\":\"",
Comment => "comment", Comment => "comment",
@ -1278,8 +1266,7 @@ impl Display for TokenKind {
StringToken => "string", StringToken => "string",
RawString => "raw string", RawString => "raw string",
Text => "command text", Text => "command text",
})); })
Ok(())
} }
} }
@ -1541,7 +1528,7 @@ fn tokenize(text: &str) -> Result<Vec<Token>, Error> {
} }
fn parse(text: &str) -> Result<Justfile, Error> { fn parse(text: &str) -> Result<Justfile, Error> {
let tokens = try!(tokenize(text)); let tokens = tokenize(text)?;
let filtered: Vec<_> = tokens.into_iter().filter(|token| token.kind != Comment).collect(); let filtered: Vec<_> = tokens.into_iter().filter(|token| token.kind != Comment).collect();
let parser = Parser { let parser = Parser {
text: text, text: text,
@ -1551,8 +1538,7 @@ fn parse(text: &str) -> Result<Justfile, Error> {
assignment_tokens: Map::<&str, Token>::new(), assignment_tokens: Map::<&str, Token>::new(),
exports: Set::<&str>::new(), exports: Set::<&str>::new(),
}; };
let justfile = try!(parser.file()); parser.file()
Ok(justfile)
} }
struct Parser<'a> { struct Parser<'a> {
@ -1690,7 +1676,7 @@ impl<'a> Parser<'a> {
return Err(self.unexpected_token(&token, &[Text, InterpolationStart, Eol])); return Err(self.unexpected_token(&token, &[Text, InterpolationStart, Eol]));
} else { } else {
pieces.push(Fragment::Expression{ pieces.push(Fragment::Expression{
expression: try!(self.expression(true)) expression: self.expression(true)?
}); });
if let Some(token) = self.expect(InterpolationEnd) { if let Some(token) = self.expect(InterpolationEnd) {
return Err(self.unexpected_token(&token, &[InterpolationEnd])); return Err(self.unexpected_token(&token, &[InterpolationEnd]));
@ -1760,7 +1746,7 @@ impl<'a> Parser<'a> {
}; };
if self.accepted(Plus) { if self.accepted(Plus) {
let rhs = try!(self.expression(interpolation)); let rhs = self.expression(interpolation)?;
Ok(Expression::Concatination{lhs: Box::new(lhs), rhs: Box::new(rhs)}) Ok(Expression::Concatination{lhs: Box::new(lhs), rhs: Box::new(rhs)})
} else if interpolation && self.peek(InterpolationEnd) { } else if interpolation && self.peek(InterpolationEnd) {
Ok(lhs) Ok(lhs)
@ -1782,7 +1768,7 @@ impl<'a> Parser<'a> {
if export { if export {
self.exports.insert(name.lexeme); self.exports.insert(name.lexeme);
} }
let expression = try!(self.expression(false)); let expression = self.expression(false)?;
self.assignments.insert(name.lexeme, expression); self.assignments.insert(name.lexeme, expression);
self.assignment_tokens.insert(name.lexeme, name); self.assignment_tokens.insert(name.lexeme, name);
Ok(()) Ok(())
@ -1797,15 +1783,15 @@ impl<'a> Parser<'a> {
Name => if token.lexeme == "export" { Name => if token.lexeme == "export" {
let next = self.tokens.next().unwrap(); let next = self.tokens.next().unwrap();
if next.kind == Name && self.accepted(Equals) { if next.kind == Name && self.accepted(Equals) {
try!(self.assignment(next, true)); self.assignment(next, true)?;
} else { } else {
self.tokens.put_back(next); self.tokens.put_back(next);
try!(self.recipe(token)); self.recipe(token)?;
} }
} else if self.accepted(Equals) { } else if self.accepted(Equals) {
try!(self.assignment(token, false)); self.assignment(token, false)?;
} else { } else {
try!(self.recipe(token)); self.recipe(token)?;
}, },
Comment => return Err(token.error(ErrorKind::InternalError { Comment => return Err(token.error(ErrorKind::InternalError {
message: "found comment in token stream".to_string() message: "found comment in token stream".to_string()
@ -1831,7 +1817,7 @@ impl<'a> Parser<'a> {
})) }))
} }
try!(resolve_recipes(&self.recipes, &self.assignments, self.text)); resolve_recipes(&self.recipes, &self.assignments, self.text)?;
for recipe in self.recipes.values() { for recipe in self.recipes.values() {
for parameter in &recipe.parameter_tokens { for parameter in &recipe.parameter_tokens {
@ -1852,7 +1838,7 @@ impl<'a> Parser<'a> {
} }
} }
try!(resolve_assignments(&self.assignments, &self.assignment_tokens)); resolve_assignments(&self.assignments, &self.assignment_tokens)?;
Ok(Justfile { Ok(Justfile {
recipes: self.recipes, recipes: self.recipes,