Skip to main content

UserOutput

Struct UserOutput 

Source
pub struct UserOutput { /* private fields */ }
Expand description

User-facing output handler with sink-based architecture

UserOutput provides a clean interface for displaying messages to users with support for:

  • Multiple output sinks (console, file, telemetry, etc.)
  • Verbosity levels (quiet, normal, verbose, debug)
  • Customizable themes (emoji, plain text, ASCII)
  • Optional formatter overrides (JSON, colored output)
  • Dual-channel routing (stdout for results, stderr for progress)

§Examples

Basic usage:

use torrust_tracker_deployer_lib::presentation::cli::views::{UserOutput, VerbosityLevel};

let mut output = UserOutput::new(VerbosityLevel::Normal);
output.progress("Starting operation...");
output.success("Operation completed successfully");
output.result(r#"{"status": "completed"}"#);

With custom theme:

use torrust_tracker_deployer_lib::presentation::cli::views::{UserOutput, VerbosityLevel, Theme};

let mut output = UserOutput::with_theme(VerbosityLevel::Normal, Theme::plain());
output.progress("Processing...");

Implementations§

Source§

impl UserOutput

Source

pub fn new(verbosity: VerbosityLevel) -> Self

Create new UserOutput with default stdout/stderr channels and emoji theme

Uses StandardSink for backward compatibility with existing console output.

§Examples
use torrust_tracker_deployer_lib::presentation::cli::views::{UserOutput, VerbosityLevel};

let output = UserOutput::new(VerbosityLevel::Normal);
Source

pub fn with_theme(verbosity: VerbosityLevel, theme: Theme) -> Self

Create UserOutput with a specific theme

Allows customization of output symbols while using default stdout/stderr channels. Uses StandardSink internally for backward compatibility.

§Examples
use torrust_tracker_deployer_lib::presentation::cli::views::{UserOutput, VerbosityLevel, Theme};

// Use plain text theme for CI/CD
let output = UserOutput::with_theme(VerbosityLevel::Normal, Theme::plain());

// Use ASCII theme for limited terminals
let output = UserOutput::with_theme(VerbosityLevel::Normal, Theme::ascii());
Source

pub fn with_theme_and_writers( verbosity: VerbosityLevel, theme: Theme, stdout_writer: Box<dyn Write + Send + Sync>, stderr_writer: Box<dyn Write + Send + Sync>, ) -> Self

Create UserOutput with theme and custom writers (for testing)

This constructor allows full customization including theme and writers, primarily used for testing where output needs to be captured.

§Examples
use torrust_tracker_deployer_lib::presentation::cli::views::{UserOutput, VerbosityLevel, Theme};
use std::io::Cursor;

let stdout_buf = Vec::new();
let stderr_buf = Vec::new();

let output = UserOutput::with_theme_and_writers(
    VerbosityLevel::Normal,
    Theme::plain(),
    Box::new(Cursor::new(stdout_buf)),
    Box::new(Cursor::new(stderr_buf)),
);
Source

pub fn progress(&mut self, message: &str)

Display progress message to stderr (Normal level and above)

Progress messages go to stderr following cargo/docker patterns. This keeps stdout clean for result data that may be piped.

§Examples
use torrust_tracker_deployer_lib::presentation::cli::views::{UserOutput, VerbosityLevel};

let mut output = UserOutput::new(VerbosityLevel::Normal);
output.progress("Destroying environment...");
// Output to stderr: ⏳ Destroying environment...
Source

pub fn success(&mut self, message: &str)

Display success message to stderr (Normal level and above)

Success status goes to stderr to allow clean result piping.

§Examples
use torrust_tracker_deployer_lib::presentation::cli::views::{UserOutput, VerbosityLevel};

let mut output = UserOutput::new(VerbosityLevel::Normal);
output.success("Environment destroyed successfully");
// Output to stderr: ✅ Environment destroyed successfully
Source

pub fn warn(&mut self, message: &str)

Display warning message to stderr (Normal level and above)

§Examples
use torrust_tracker_deployer_lib::presentation::cli::views::{UserOutput, VerbosityLevel};

let mut output = UserOutput::new(VerbosityLevel::Normal);
output.warn("Infrastructure may already be destroyed");
// Output to stderr: ⚠️  Infrastructure may already be destroyed
Source

pub fn error(&mut self, message: &str)

Display error message to stderr (all levels)

Errors are always shown regardless of verbosity level.

§Examples
use torrust_tracker_deployer_lib::presentation::cli::views::{UserOutput, VerbosityLevel};

let mut output = UserOutput::new(VerbosityLevel::Quiet);
output.error("Failed to destroy environment");
// Output to stderr: ❌ Failed to destroy environment
Source

pub fn step_progress(&mut self, message: &str)

Display a step progress message to stderr (Verbose level and above)

Step progress messages mark workflow step boundaries during command execution. They are shown when the user requests verbose output (-v).

§Examples
use torrust_tracker_deployer_lib::presentation::cli::views::{UserOutput, VerbosityLevel};

let mut output = UserOutput::new(VerbosityLevel::Verbose);
output.step_progress("  [Step 1/9] Rendering OpenTofu templates...");
// Output to stderr: 📋   [Step 1/9] Rendering OpenTofu templates...
Source

pub fn detail(&mut self, message: &str)

Display a detail message to stderr (VeryVerbose level and above)

Detail messages provide contextual information within steps during command execution. They are shown when the user requests very verbose output (-vv).

§Examples
use torrust_tracker_deployer_lib::presentation::cli::views::{UserOutput, VerbosityLevel};

let mut output = UserOutput::new(VerbosityLevel::VeryVerbose);
output.detail("     → Instance IP: 10.140.190.235");
// Output to stderr: 📋      → Instance IP: 10.140.190.235
Source

pub fn debug_detail(&mut self, message: &str)

Display a debug detail message to stderr (Debug level and above)

Debug detail messages provide technical implementation details during command execution. They are shown when the user requests maximum verbosity (-vvv).

§Examples
use torrust_tracker_deployer_lib::presentation::cli::views::{UserOutput, VerbosityLevel};

let mut output = UserOutput::new(VerbosityLevel::Debug);
output.debug_detail("     → Command: tofu init");
// Output to stderr: 🔍      → Command: tofu init
Source

pub fn result(&mut self, message: &str)

Output final results to stdout for piping/redirection

This is where deployment results, configuration summaries, etc. go. Since this goes to stdout, it can be cleanly piped to other commands.

§Examples
use torrust_tracker_deployer_lib::presentation::cli::views::{UserOutput, VerbosityLevel};

let mut output = UserOutput::new(VerbosityLevel::Normal);
output.result("Deployment complete");
// Output to stdout: Deployment complete
Source

pub fn data(&mut self, data: &str)

Output structured data to stdout (JSON, etc.)

For machine-readable output that should be piped or processed. This is equivalent to result() but exists for semantic clarity.

§Examples
use torrust_tracker_deployer_lib::presentation::cli::views::{UserOutput, VerbosityLevel};

let mut output = UserOutput::new(VerbosityLevel::Normal);
output.data(r#"{"status": "destroyed", "environment": "test"}"#);
// Output to stdout: {"status": "destroyed", "environment": "test"}
Source

pub fn blank_line(&mut self)

Display a blank line to stderr (Normal level and above)

Used for spacing between sections of output to improve readability.

§Examples
use torrust_tracker_deployer_lib::presentation::cli::views::{UserOutput, VerbosityLevel};

let mut output = UserOutput::new(VerbosityLevel::Normal);
output.success("Configuration template generated");
output.blank_line();
output.progress("Starting next steps...");
Source

pub fn steps(&mut self, title: &str, steps: &[&str])

Display a numbered list of steps to stderr (Normal level and above)

Useful for displaying sequential instructions or action items.

§Examples
use torrust_tracker_deployer_lib::presentation::cli::views::{UserOutput, VerbosityLevel};

let mut output = UserOutput::new(VerbosityLevel::Normal);
output.steps("Next steps:", &[
    "Edit the configuration file",
    "Review the settings",
    "Run the deploy command",
]);
// Output to stderr:
// Next steps:
// 1. Edit the configuration file
// 2. Review the settings
// 3. Run the deploy command
Source

pub fn info_block(&mut self, title: &str, lines: &[&str])

Display a multi-line information block to stderr (Normal level and above)

Useful for displaying grouped information or detailed messages.

§Examples
use torrust_tracker_deployer_lib::presentation::cli::views::{UserOutput, VerbosityLevel};

let mut output = UserOutput::new(VerbosityLevel::Normal);
output.info_block("Configuration options:", &[
    "  - username: 'torrust' (default)",
    "  - port: 22 (default SSH port)",
    "  - key_path: path/to/key",
]);
// Output to stderr:
// Configuration options:
//   - username: 'torrust' (default)
//   - port: 22 (default SSH port)
//   - key_path: path/to/key

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<T> IntoResult<T> for T

Source§

type Err = !

Source§

fn into_result(self) -> Result<T, <T as IntoResult<T>>::Err>

Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more