Split Recipe::run into Recipe::{run_shebang,run_linewise} (#1270)
This commit is contained in:
parent
64b4d71d66
commit
4a4c669db9
7
justfile
7
justfile
@ -17,6 +17,13 @@ export JUST_LOG := log
|
|||||||
test:
|
test:
|
||||||
cargo test
|
cargo test
|
||||||
|
|
||||||
|
ci: build-book
|
||||||
|
cargo test --all
|
||||||
|
cargo clippy --all --all-targets
|
||||||
|
cargo fmt --all -- --check
|
||||||
|
./bin/forbid
|
||||||
|
cargo update --locked --package just
|
||||||
|
|
||||||
fuzz:
|
fuzz:
|
||||||
cargo +nightly fuzz run fuzz-compiler
|
cargo +nightly fuzz run fuzz-compiler
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
clippy::shadow_unrelated,
|
clippy::shadow_unrelated,
|
||||||
clippy::struct_excessive_bools,
|
clippy::struct_excessive_bools,
|
||||||
clippy::too_many_lines,
|
clippy::too_many_lines,
|
||||||
|
clippy::type_repetition_in_bounds,
|
||||||
clippy::wildcard_imports
|
clippy::wildcard_imports
|
||||||
)]
|
)]
|
||||||
|
|
||||||
|
254
src/recipe.rs
254
src/recipe.rs
@ -85,10 +85,134 @@ impl<'src, D> Recipe<'src, D> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut evaluator =
|
let evaluator =
|
||||||
Evaluator::recipe_evaluator(context.config, dotenv, &scope, context.settings, search);
|
Evaluator::recipe_evaluator(context.config, dotenv, &scope, context.settings, search);
|
||||||
|
|
||||||
if self.shebang {
|
if self.shebang {
|
||||||
|
self.run_shebang(context, dotenv, &scope, positional, config, evaluator)
|
||||||
|
} else {
|
||||||
|
self.run_linewise(context, dotenv, &scope, positional, config, evaluator)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn run_linewise<'run>(
|
||||||
|
&self,
|
||||||
|
context: &RecipeContext<'src, 'run>,
|
||||||
|
dotenv: &BTreeMap<String, String>,
|
||||||
|
scope: &Scope<'src, 'run>,
|
||||||
|
positional: &[String],
|
||||||
|
config: &Config,
|
||||||
|
mut evaluator: Evaluator<'src, 'run>,
|
||||||
|
) -> RunResult<'src, ()> {
|
||||||
|
let mut lines = self.body.iter().peekable();
|
||||||
|
let mut line_number = self.line_number() + 1;
|
||||||
|
loop {
|
||||||
|
if lines.peek().is_none() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let mut evaluated = String::new();
|
||||||
|
let mut continued = false;
|
||||||
|
let quiet_command = lines.peek().map_or(false, |line| line.is_quiet());
|
||||||
|
let infallible_command = lines.peek().map_or(false, |line| line.is_infallible());
|
||||||
|
loop {
|
||||||
|
if lines.peek().is_none() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let line = lines.next().unwrap();
|
||||||
|
line_number += 1;
|
||||||
|
evaluated += &evaluator.evaluate_line(line, continued)?;
|
||||||
|
if line.is_continuation() {
|
||||||
|
continued = true;
|
||||||
|
evaluated.pop();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut command = evaluated.as_str();
|
||||||
|
|
||||||
|
if quiet_command {
|
||||||
|
command = &command[1..];
|
||||||
|
}
|
||||||
|
|
||||||
|
if infallible_command {
|
||||||
|
command = &command[1..];
|
||||||
|
}
|
||||||
|
|
||||||
|
if command.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.dry_run
|
||||||
|
|| config.verbosity.loquacious()
|
||||||
|
|| !((quiet_command ^ self.quiet) || config.verbosity.quiet())
|
||||||
|
{
|
||||||
|
let color = if config.highlight {
|
||||||
|
config.color.command()
|
||||||
|
} else {
|
||||||
|
config.color
|
||||||
|
};
|
||||||
|
eprintln!("{}", color.stderr().paint(command));
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.dry_run {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut cmd = context.settings.shell_command(config);
|
||||||
|
|
||||||
|
cmd.current_dir(&context.search.working_directory);
|
||||||
|
|
||||||
|
cmd.arg(command);
|
||||||
|
|
||||||
|
if context.settings.positional_arguments {
|
||||||
|
cmd.arg(self.name.lexeme());
|
||||||
|
cmd.args(positional);
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.verbosity.quiet() {
|
||||||
|
cmd.stderr(Stdio::null());
|
||||||
|
cmd.stdout(Stdio::null());
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.export(context.settings, dotenv, scope);
|
||||||
|
|
||||||
|
match InterruptHandler::guard(|| cmd.status()) {
|
||||||
|
Ok(exit_status) => {
|
||||||
|
if let Some(code) = exit_status.code() {
|
||||||
|
if code != 0 && !infallible_command {
|
||||||
|
return Err(Error::Code {
|
||||||
|
recipe: self.name(),
|
||||||
|
line_number: Some(line_number),
|
||||||
|
code,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(error_from_signal(
|
||||||
|
self.name(),
|
||||||
|
Some(line_number),
|
||||||
|
exit_status,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(io_error) => {
|
||||||
|
return Err(Error::Io {
|
||||||
|
recipe: self.name(),
|
||||||
|
io_error,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn run_shebang<'run>(
|
||||||
|
&self,
|
||||||
|
context: &RecipeContext<'src, 'run>,
|
||||||
|
dotenv: &BTreeMap<String, String>,
|
||||||
|
scope: &Scope<'src, 'run>,
|
||||||
|
positional: &[String],
|
||||||
|
config: &Config,
|
||||||
|
mut evaluator: Evaluator<'src, 'run>,
|
||||||
|
) -> RunResult<'src, ()> {
|
||||||
let mut evaluated_lines = vec![];
|
let mut evaluated_lines = vec![];
|
||||||
for line in &self.body {
|
for line in &self.body {
|
||||||
evaluated_lines.push(evaluator.evaluate_line(line, false)?);
|
evaluated_lines.push(evaluator.evaluate_line(line, false)?);
|
||||||
@ -177,133 +301,31 @@ impl<'src, D> Recipe<'src, D> {
|
|||||||
command.args(positional);
|
command.args(positional);
|
||||||
}
|
}
|
||||||
|
|
||||||
command.export(context.settings, dotenv, &scope);
|
command.export(context.settings, dotenv, scope);
|
||||||
|
|
||||||
// run it!
|
// run it!
|
||||||
match InterruptHandler::guard(|| command.status()) {
|
match InterruptHandler::guard(|| command.status()) {
|
||||||
Ok(exit_status) => {
|
Ok(exit_status) => exit_status.code().map_or_else(
|
||||||
if let Some(code) = exit_status.code() {
|
|| Err(error_from_signal(self.name(), None, exit_status)),
|
||||||
if code != 0 {
|
|code| {
|
||||||
return Err(Error::Code {
|
if code == 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Error::Code {
|
||||||
recipe: self.name(),
|
recipe: self.name(),
|
||||||
line_number: None,
|
line_number: None,
|
||||||
code,
|
code,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
} else {
|
},
|
||||||
return Err(error_from_signal(self.name(), None, exit_status));
|
),
|
||||||
}
|
Err(io_error) => Err(Error::Shebang {
|
||||||
}
|
|
||||||
Err(io_error) => {
|
|
||||||
return Err(Error::Shebang {
|
|
||||||
recipe: self.name(),
|
recipe: self.name(),
|
||||||
command: shebang.interpreter.to_owned(),
|
command: shebang.interpreter.to_owned(),
|
||||||
argument: shebang.argument.map(String::from),
|
argument: shebang.argument.map(String::from),
|
||||||
io_error,
|
io_error,
|
||||||
});
|
}),
|
||||||
}
|
}
|
||||||
};
|
|
||||||
} else {
|
|
||||||
let mut lines = self.body.iter().peekable();
|
|
||||||
let mut line_number = self.line_number() + 1;
|
|
||||||
loop {
|
|
||||||
if lines.peek().is_none() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let mut evaluated = String::new();
|
|
||||||
let mut continued = false;
|
|
||||||
let quiet_command = lines.peek().map_or(false, |line| line.is_quiet());
|
|
||||||
let infallible_command = lines.peek().map_or(false, |line| line.is_infallible());
|
|
||||||
loop {
|
|
||||||
if lines.peek().is_none() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let line = lines.next().unwrap();
|
|
||||||
line_number += 1;
|
|
||||||
evaluated += &evaluator.evaluate_line(line, continued)?;
|
|
||||||
if line.is_continuation() {
|
|
||||||
continued = true;
|
|
||||||
evaluated.pop();
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mut command = evaluated.as_str();
|
|
||||||
|
|
||||||
if quiet_command {
|
|
||||||
command = &command[1..];
|
|
||||||
}
|
|
||||||
|
|
||||||
if infallible_command {
|
|
||||||
command = &command[1..];
|
|
||||||
}
|
|
||||||
|
|
||||||
if command.is_empty() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.dry_run
|
|
||||||
|| config.verbosity.loquacious()
|
|
||||||
|| !((quiet_command ^ self.quiet) || config.verbosity.quiet())
|
|
||||||
{
|
|
||||||
let color = if config.highlight {
|
|
||||||
config.color.command()
|
|
||||||
} else {
|
|
||||||
config.color
|
|
||||||
};
|
|
||||||
eprintln!("{}", color.stderr().paint(command));
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.dry_run {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut cmd = context.settings.shell_command(config);
|
|
||||||
|
|
||||||
cmd.current_dir(&context.search.working_directory);
|
|
||||||
|
|
||||||
cmd.arg(command);
|
|
||||||
|
|
||||||
if context.settings.positional_arguments {
|
|
||||||
cmd.arg(self.name.lexeme());
|
|
||||||
cmd.args(positional);
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.verbosity.quiet() {
|
|
||||||
cmd.stderr(Stdio::null());
|
|
||||||
cmd.stdout(Stdio::null());
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.export(context.settings, dotenv, &scope);
|
|
||||||
|
|
||||||
match InterruptHandler::guard(|| cmd.status()) {
|
|
||||||
Ok(exit_status) => {
|
|
||||||
if let Some(code) = exit_status.code() {
|
|
||||||
if code != 0 && !infallible_command {
|
|
||||||
return Err(Error::Code {
|
|
||||||
recipe: self.name(),
|
|
||||||
line_number: Some(line_number),
|
|
||||||
code,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(error_from_signal(
|
|
||||||
self.name(),
|
|
||||||
Some(line_number),
|
|
||||||
exit_status,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(io_error) => {
|
|
||||||
return Err(Error::Io {
|
|
||||||
recipe: self.name(),
|
|
||||||
io_error,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +254,6 @@ impl Subcommand {
|
|||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
|
||||||
let recipes = stdout
|
let recipes = stdout
|
||||||
.trim()
|
|
||||||
.split_whitespace()
|
.split_whitespace()
|
||||||
.map(str::to_owned)
|
.map(str::to_owned)
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
|
Loading…
Reference in New Issue
Block a user