diff --git a/devenv-eval-cache/src/command.rs b/devenv-eval-cache/src/command.rs index 155c1c5aa..e8811423e 100644 --- a/devenv-eval-cache/src/command.rs +++ b/devenv-eval-cache/src/command.rs @@ -202,6 +202,7 @@ pub fn supports_eval_caching(cmd: &Command) -> bool { cmd.get_program().to_string_lossy().ends_with("nix") } +#[derive(Debug)] pub struct Output { /// The status code of the command. pub status: process::ExitStatus, diff --git a/devenv-tasks/src/lib.rs b/devenv-tasks/src/lib.rs index 4ab09fe6b..5016bd119 100644 --- a/devenv-tasks/src/lib.rs +++ b/devenv-tasks/src/lib.rs @@ -613,6 +613,7 @@ impl Tasks { } } +#[derive(Debug)] pub struct TasksStatus { lines: Vec, pub pending: usize, diff --git a/devenv-tasks/src/main.rs b/devenv-tasks/src/main.rs index 8b1fc9fad..34ec4fcba 100644 --- a/devenv-tasks/src/main.rs +++ b/devenv-tasks/src/main.rs @@ -33,7 +33,11 @@ async fn main() -> Result<(), Box> { let config = Config { tasks, roots }; let mut tasks_ui = TasksUi::new(config).await?; - tasks_ui.run().await?; + let (status, _outputs) = tasks_ui.run().await?; + + if status.failed + status.dependency_failed > 0 { + std::process::exit(1); + } } Command::Export { strings } => { let output_file = diff --git a/devenv/src/cnix.rs b/devenv/src/cnix.rs index 18881966f..f92a37e2f 100644 --- a/devenv/src/cnix.rs +++ b/devenv/src/cnix.rs @@ -29,13 +29,44 @@ pub struct Nix<'a> { #[derive(Clone)] pub struct Options<'a> { + /// Run `exec` to replace the shell with the command. pub replace_shell: bool, + /// Error out if the command returns a non-zero status code. + pub bail_on_error: bool, + /// Cache the output of the command. This is opt-in per command. pub cache_output: bool, + /// Enable logging. pub logging: bool, + /// Log the stdout of the command. pub logging_stdout: bool, + /// Extra flags to pass to nix commands. pub nix_flags: &'a [&'a str], } +impl Default for Options<'_> { + fn default() -> Self { + Self { + replace_shell: false, + bail_on_error: true, + // Individual commands opt into caching + cache_output: false, + logging: true, + logging_stdout: false, + nix_flags: &[ + "--show-trace", + "--extra-experimental-features", + "nix-command", + "--extra-experimental-features", + "flakes", + "--option", + "warn-dirty", + "false", + "--keep-going", + ], + } + } +} + impl<'a> Nix<'a> { pub async fn new>( logger: log::Logger, @@ -54,24 +85,7 @@ impl<'a> Nix<'a> { let devenv_root = devenv_root.as_ref().to_path_buf(); let cachix_caches = RefCell::new(None); - let options = Options { - replace_shell: false, - // Individual commands opt into caching - cache_output: false, - logging: true, - logging_stdout: false, - nix_flags: &[ - "--show-trace", - "--extra-experimental-features", - "nix-command", - "--extra-experimental-features", - "flakes", - "--option", - "warn-dirty", - "false", - "--keep-going", - ], - }; + let options = Options::default(); let database_url = format!( "sqlite:{}/nix-eval-cache.db", @@ -106,6 +120,7 @@ impl<'a> Nix<'a> { // Cannot cache this because we don't get the derivation back. // We'd need to switch to print-dev-env and our own `nix develop`. cache_output: false, + bail_on_error: false, replace_shell, ..self.options }; @@ -393,27 +408,32 @@ impl<'a> Nix<'a> { Some(code) => format!("with exit code {}", code), None => "without exit code".to_string(), }; - if options.logging { - eprintln!(); - self.logger.error(&format!( - "Command produced the following output:\n{}\n{}", - String::from_utf8_lossy(&result.stdout), - String::from_utf8_lossy(&result.stderr), - )); - } + if self.global_options.nix_debugger && cmd.get_program().to_string_lossy().ends_with("bin/nix") { self.logger.info("Starting Nix debugger ..."); cmd.arg("--debugger").exec(); } - bail!(format!( - "Command `{}` failed with {code}", - display_command(&cmd) - )) - } else { - Ok(result) + + if options.bail_on_error { + if options.logging { + eprintln!(); + self.logger.error(&format!( + "Command produced the following output:\n{}\n{}", + String::from_utf8_lossy(&result.stdout), + String::from_utf8_lossy(&result.stderr), + )); + } + + bail!(format!( + "Command `{}` failed with {code}", + display_command(&cmd) + )) + } } + + Ok(result) } // We have a separate function to avoid recursion as this needs to call self.prepare_command diff --git a/devenv/src/devenv.rs b/devenv/src/devenv.rs index eaa8f78b1..08dca14e9 100644 --- a/devenv/src/devenv.rs +++ b/devenv/src/devenv.rs @@ -563,7 +563,7 @@ impl Devenv { .iter() .map(|s| s.as_str()) .collect::>(), - false, + false, // replace_shell ) .await? };