Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#260] Show failed nix command #310

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

heitor-lassarote
Copy link
Member

This PR displays the command that failed when an error is produced after a command exits with a non-zero code. The output is also cleared a bit. Example:

🚀 ℹ️ [deploy] [INFO] Running checks for flake in examples/simple/flake.nix
🚀 ❌ [deploy] [ERROR] Failed to check deployment: Nix checking command resulted in a bad exit code: Some(1). The failed command is provided below:
Command { std: "nix" "flake" "check" "examples/simple/flake.nix", kill_on_drop: false }
The stderr output is provided below:
error: in flake URL 'examples/simple/flake.nix', 'flake.nix' is not a commit hash

Problem: Many errors result from attempts to build commands which might
error with a non-zero exit code. The failed commands are not displayed
to the user, however.

Solution: For every `([A-Za-z])Exit(Option<i32>)` error, change it to
`\1Exit(Option<i32>, String)`, where the `String` contains the failed
command. Format each `tokyo` command using `{:?}` and save it to the
corresponding error.

Note that `Command` cannot be copied or cloned, and it's not possible to
access a command's `std` field to get the underlying command, so we
resort to putting the `Debug`-formatted command.
Problem: It's common to spawn a command and occasionally fail during
running the command or because it exited, leading to code repetition.

Solution: Create a `command` module to abstract some of the boilerplate
by wrapping `tokio::process::Command`. Create a `run` function that
abstracts most of this boilerplate.

In some parts, the way commands are executed are a bit different, so
instead we leave them as it is.
Problem: The output when a command failed for deployment would show the
error message in the console output and _then_ the error message, which
was confusing.

Solution: Show the error message together with the error in an order
that makes sense. This is done by capturing the output in the error
message and printinting it in an exit error. We also use `Stdio::null`
rather than `Stdio::piped` to avoid printing to the console.
@heitor-lassarote heitor-lassarote self-assigned this Jan 10, 2025
@heitor-lassarote heitor-lassarote marked this pull request as ready for review January 10, 2025 22:54
src/command.rs Outdated
}
}

pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the motivation behind the reimplementation of arg and other methods defined for TokioCommand rather than creating a single new constructor that accepts already constructed TokioCommand and run to run the command handling the result?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed a commit with your suggestion. It simplifies command.rs, but makes the consumer code a bit more verbose.

"Nix activation script".to_string()
}
}

#[derive(Error, Debug)]
pub enum ActivateError {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the fact that this error type became simpler

}

let ssh_activate_exit_status = ssh_activate_child
.wait()
.wait_with_output()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why the run method of command::Command is not used here instead of wait_with_output?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because ssh_activate_child is a tokio::process::Child and not a command::Command or tokio::process::Command. Although there are patterns, the way the codebase handles children is not repetitive enough to easily abstract them into a run command for a new command::Child, but I can put some more thought into this if you'd like.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants