Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion crates/vite_task/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ pub mod session;

// Public exports for vite_task_bin
pub use cli::{CacheSubcommand, Command, RunCommand, RunFlags};
pub use session::{CommandHandler, ExitStatus, HandledCommand, Session, SessionConfig};
pub use session::{
CommandHandler, ExitStatus, HandledCommand, Session, SessionConfig, print_error,
};
pub use vite_task_graph::{
config::{
self,
Expand Down
41 changes: 34 additions & 7 deletions crates/vite_task/src/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,15 +244,19 @@ impl<'a> Session<'a> {

/// Primary entry point for CLI usage. Plans and executes the given command.
///
/// # Errors
///
/// Returns an error if planning or execution fails.
/// Any error encountered during planning or execution is printed to stderr
/// with a bold red `error:` prefix, with each level of the error chain on
/// its own `* `-prefixed line. Returns the exit status — callers exit the
/// process with it.
#[tracing::instrument(level = "debug", skip_all)]
pub async fn main(mut self, command: Command) -> anyhow::Result<ExitStatus> {
pub async fn main(mut self, command: Command) -> ExitStatus {
match self.main_inner(command).await {
Ok(()) => Ok(ExitStatus::SUCCESS),
Err(SessionError::EarlyExit(status)) => Ok(status),
Err(SessionError::Anyhow(err)) => Err(err),
Ok(()) => ExitStatus::SUCCESS,
Err(SessionError::EarlyExit(status)) => status,
Err(SessionError::Anyhow(err)) => {
print_error(&err);
ExitStatus::FAILURE
}
}
}

Expand Down Expand Up @@ -795,6 +799,29 @@ impl<'a> Session<'a> {
}
}

/// Print `error` to stderr formatted as the `vp` CLI does:
///
/// ```text
/// error: <top-level message>
/// * <source>
/// * <source.source()>
/// ```
///
/// The `error:` prefix is bold red when stderr supports ANSI colors.
pub fn print_error(error: &anyhow::Error) {
use std::io::Write as _;

use owo_colors::{OwoColorize as _, Stream, Style};

let prefix = "error:".if_supports_color(Stream::Stderr, |s| s.style(Style::new().red().bold()));
let mut stderr = std::io::stderr().lock();
let _ = write!(stderr, "{prefix} {error}");
for source in error.chain().skip(1) {
let _ = write!(stderr, "\n* {source}");
}
let _ = writeln!(stderr);
}

/// Whether stdout supports ANSI color output for the current process. Honors
/// `NO_COLOR`/`FORCE_COLOR` and detects TTY capability via the `supports-color`
/// crate. Result is cached for the process lifetime.
Expand Down
25 changes: 11 additions & 14 deletions crates/vite_task_bin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,21 @@ use vite_task::{Command, ExitStatus, Session};
use vite_task_bin::OwnedSessionConfig;

fn main() -> ! {
let exit_code: i32 =
tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap().block_on(async {
match run().await {
Ok(status) => i32::from(status.0),
#[expect(clippy::print_stderr, reason = "top-level error reporting")]
Err(err) => {
eprintln!("Error: {err:?}");
1
}
}
});
let status: ExitStatus =
tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap().block_on(run());

std::process::exit(exit_code);
std::process::exit(i32::from(status.0));
}

async fn run() -> anyhow::Result<ExitStatus> {
async fn run() -> ExitStatus {
let args = Command::parse();
let mut owned_config = OwnedSessionConfig::default();
let session = Session::init(owned_config.as_config())?;
let session = match Session::init(owned_config.as_config()) {
Ok(session) => session,
Err(err) => {
vite_task::print_error(&err);
return ExitStatus::FAILURE;
}
};
session.main(args).await
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ task-a -> task-b -> task-a cycle
**Exit code:** 1

```
Error: Cycle dependency detected: error-cycle-dependency-test#task-a -> error-cycle-dependency-test#task-b -> error-cycle-dependency-test#task-a
error: Cycle dependency detected: error-cycle-dependency-test#task-a -> error-cycle-dependency-test#task-b -> error-cycle-dependency-test#task-a
```
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ A typoed task name combined with `-r` (not cwd-only) should error without listin
**Exit code:** 1

```
Error: Task "buid" not found
error: Task "buid" not found
```
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
**Exit code:** 1

```
Error: No task specifier provided for 'run' command
error: No task specifier provided for 'run' command
```
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
**Exit code:** 1

```
Error: Task "buid" not found
error: Task "buid" not found
```
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ A typo inside a task's own script (i.e. a nested `vp run` command) should surfac
**Exit code:** 1

```
Error: Failed to plan tasks from `vt run nonexistent-xyz` in task task-select-test#run-typo-task

Caused by:
Task "nonexistent-xyz" not found
error: Failed to plan tasks from `vt run nonexistent-xyz` in task task-select-test#run-typo-task
* Task "nonexistent-xyz" not found
```
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
**Exit code:** 1

```
Error: No task specifier provided for 'run' command
error: No task specifier provided for 'run' command
```
Loading