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
10 changes: 10 additions & 0 deletions crates/uv/src/commands/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use crate::commands::project::run::RecursionLimitError;
use crate::commands::project::version::MissingProjectVersionError;
use crate::commands::tool::common::NoExecutablesError;
use crate::commands::tool::run::ToolRunScriptError;
use crate::printer::Printer;

static SUGGESTIONS: LazyLock<FxHashMap<PackageName, PackageName>> = LazyLock::new(|| {
let suggestions: Vec<(String, String)> =
Expand Down Expand Up @@ -223,6 +224,15 @@ fn no_solution(err: &uv_resolver::NoSolutionError, context: Option<&'static str>
anstream::eprint!("{hints}");
}

/// Format an error chain with the default user-facing hints and output settings.
pub(crate) fn write_error_chain(err: &anyhow::Error, printer: Printer) -> std::fmt::Result {
uv_errors::write_error_chain_with_options(
err.as_ref(),
hints_for_error(err),
uv_errors::ErrorOptions::default().with_stream(printer.stderr_important()),
)
}

/// Walk an error chain and collect hint strings from all known error types.
///
/// This is the central "hint for error" function. It walks the full error chain
Expand Down
26 changes: 12 additions & 14 deletions crates/uv/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,17 +530,7 @@ pub async fn run(cli: Cli, global_initialization: GlobalInitialization) -> Resul
}

// Configure the `Printer`, which controls user-facing output in the CLI.
let printer = if globals.quiet == 1 {
Printer::Quiet
} else if globals.quiet > 1 {
Printer::Silent
} else if globals.verbose > 0 {
Printer::Verbose
} else if globals.no_progress {
Printer::NoProgress
} else {
Printer::Default
};
let printer = Printer::new(globals.quiet, globals.verbose, globals.no_progress);

// Configure the `warn!` macros, which control user-facing warnings in the CLI.
if globals.quiet > 0 {
Expand Down Expand Up @@ -3025,6 +3015,14 @@ where
}
};

// Configure a printer for failures that escape command execution. The resolved `no_progress`
// setting can differ due to environment variables, but it does not affect important stderr.
let printer = Printer::new(
cli.top_level.global_args.quiet,
cli.top_level.global_args.verbose,
cli.top_level.global_args.no_progress,
);

// See `min_stack_size` doc comment about `main2`
let min_stack_size = min_stack_size();
let main2 = move || {
Expand Down Expand Up @@ -3061,13 +3059,13 @@ where
match error {
UvError::User(err) => {
trace!("Error trace: {err:?}");
anstream::eprintln!("{}", err.to_string().bold());
writeln!(printer.stderr_important(), "{}", err.to_string().bold())
.expect("writing to stderr should not fail");
ExitStatus::Failure.into()
}
UvError::Unexpected(err) => {
trace!("Error trace: {err:?}");
let hints = commands::diagnostics::hints_for_error(&err);
uv_errors::write_error_chain(err.as_ref(), hints)
commands::diagnostics::write_error_chain(&err, printer)
.expect("writing to stderr should not fail");
ExitStatus::Error.into()
}
Expand Down
15 changes: 15 additions & 0 deletions crates/uv/src/printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,21 @@ pub(crate) enum Printer {
}

impl Printer {
/// Create a printer from the global output settings.
pub(crate) fn new(quiet: u8, verbose: u8, no_progress: bool) -> Self {
if quiet == 1 {
Self::Quiet
} else if quiet > 1 {
Self::Silent
} else if verbose > 0 {
Self::Verbose
} else if no_progress {
Self::NoProgress
} else {
Self::Default
}
}

/// Return the [`ProgressDrawTarget`] for this printer.
pub(crate) fn target(self) -> ProgressDrawTarget {
match self {
Expand Down
17 changes: 17 additions & 0 deletions crates/uv/tests/project/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5281,6 +5281,23 @@ fn run_with_not_existing_env_file() -> Result<()> {
error: No environment file found at: `.env.development`
");

uv_snapshot!(context.filters(), context.run().arg("--env-file").arg(".env.development").arg("--quiet").arg("test.py"), @"
success: false
exit_code: 2
----- stdout -----

----- stderr -----
error: No environment file found at: `.env.development`
");

uv_snapshot!(context.filters(), context.run().arg("--env-file").arg(".env.development").arg("--quiet").arg("--quiet").arg("test.py"), @"
success: false
exit_code: 2
----- stdout -----

----- stderr -----
");

Ok(())
}

Expand Down
19 changes: 19 additions & 0 deletions crates/uv/tests/sync/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,25 @@ fn locked() -> Result<()> {
The lockfile at `uv.lock` needs to be updated, but `--locked` was provided. To update the lockfile, run `uv lock`.
");

// Quiet mode suppresses the resolution summary, but preserves the user-facing failure.
uv_snapshot!(context.filters(), context.sync().arg("--locked").arg("--quiet"), @"
success: false
exit_code: 1
----- stdout -----

----- stderr -----
The lockfile at `uv.lock` needs to be updated, but `--locked` was provided. To update the lockfile, run `uv lock`.
");

// Silent mode suppresses the final error too.
uv_snapshot!(context.filters(), context.sync().arg("--locked").arg("--quiet").arg("--quiet"), @"
success: false
exit_code: 1
----- stdout -----

----- stderr -----
");

let updated = context.read("uv.lock");

// And the lockfile should be unchanged.
Expand Down
Loading