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
3 changes: 2 additions & 1 deletion lychee-bin/src/commands/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ use lychee_lib::{ResponseBody, Status};

use crate::formatters::get_progress_formatter;
use crate::formatters::response::ResponseFormatter;
use crate::formatters::stats::ResponseStats;
use crate::formatters::suggestion::Suggestion;
use crate::parse::parse_duration_secs;
use crate::progress::Progress;
use crate::{ExitCode, cache::Cache, stats::ResponseStats};
use crate::{ExitCode, cache::Cache};

use super::CommandParams;

Expand Down
35 changes: 7 additions & 28 deletions lychee-bin/src/formatters/host_stats/compact.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,17 @@
use anyhow::Result;
use std::{
collections::HashMap,
fmt::{self, Display},
};
use std::fmt::{self, Display};

use crate::formatters::color::{DIM, NORMAL, color};
use lychee_lib::ratelimit::HostStats;
use lychee_lib::ratelimit::HostStatsMap;

use super::HostStatsFormatter;

struct CompactHostStats {
host_stats: HashMap<String, HostStats>,
pub(crate) struct CompactHostStats {
pub(crate) host_stats: Option<HostStatsMap>,
}

impl Display for CompactHostStats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.host_stats.is_empty() {
let Some(host_stats) = &self.host_stats else {
return Ok(());
}
};

writeln!(f)?;
writeln!(f, "📊 Per-host Statistics")?;
Expand All @@ -26,7 +20,7 @@ impl Display for CompactHostStats {
color!(f, DIM, "{}", separator)?;
writeln!(f)?;

let sorted_hosts = super::sort_host_stats(&self.host_stats);
let sorted_hosts = host_stats.sorted();

// Calculate optimal hostname width based on longest hostname
let max_hostname_len = sorted_hosts
Expand Down Expand Up @@ -60,18 +54,3 @@ impl Display for CompactHostStats {
Ok(())
}
}

pub(crate) struct Compact;

impl Compact {
pub(crate) const fn new() -> Self {
Self
}
}

impl HostStatsFormatter for Compact {
fn format(&self, host_stats: HashMap<String, HostStats>) -> Result<String> {
let compact = CompactHostStats { host_stats };
Ok(compact.to_string())
}
}
37 changes: 7 additions & 30 deletions lychee-bin/src/formatters/host_stats/detailed.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,21 @@
use anyhow::Result;
use std::{
collections::HashMap,
fmt::{self, Display},
};
use std::fmt::{self, Display};

use lychee_lib::ratelimit::HostStats;
use lychee_lib::ratelimit::HostStatsMap;

use super::HostStatsFormatter;

struct DetailedHostStats {
host_stats: HashMap<String, HostStats>,
pub(crate) struct DetailedHostStats {
pub(crate) host_stats: Option<HostStatsMap>,
}

impl Display for DetailedHostStats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.host_stats.is_empty() {
let Some(host_stats) = &self.host_stats else {
return Ok(());
}
};

writeln!(f, "\n📊 Per-host Statistics")?;
writeln!(f, "---------------------")?;

let sorted_hosts = super::sort_host_stats(&self.host_stats);

for (hostname, stats) in sorted_hosts {
for (hostname, stats) in host_stats.sorted() {
writeln!(f, "\nHost: {hostname}")?;
writeln!(f, " Total requests: {}", stats.total_requests)?;
writeln!(
Expand Down Expand Up @@ -69,18 +61,3 @@ impl Display for DetailedHostStats {
Ok(())
}
}

pub(crate) struct Detailed;

impl Detailed {
pub(crate) const fn new() -> Self {
Self
}
}

impl HostStatsFormatter for Detailed {
fn format(&self, host_stats: HashMap<String, HostStats>) -> Result<String> {
let detailed = DetailedHostStats { host_stats };
Ok(detailed.to_string())
}
}
51 changes: 0 additions & 51 deletions lychee-bin/src/formatters/host_stats/json.rs

This file was deleted.

62 changes: 22 additions & 40 deletions lychee-bin/src/formatters/host_stats/markdown.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
use std::{
collections::HashMap,
fmt::{self, Display},
};
use std::fmt::{self, Display};

use super::HostStatsFormatter;
use anyhow::Result;
use lychee_lib::ratelimit::HostStats;
use lychee_lib::ratelimit::HostStatsMap;
use tabled::{
Table, Tabled,
settings::{Alignment, Modify, Style, object::Segment},
};

pub(crate) struct MarkdownHostStats {
pub(crate) host_stats: Option<HostStatsMap>,
}

impl Display for MarkdownHostStats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Some(host_stats) = &self.host_stats else {
return Ok(());
};

writeln!(f, "\n## Per-host Statistics")?;
writeln!(f)?;
writeln!(f, "{}", host_stats_table(host_stats))?;

Ok(())
}
}

#[derive(Tabled)]
struct HostStatsTableEntry {
#[tabled(rename = "Host")]
Expand All @@ -25,8 +38,8 @@ struct HostStatsTableEntry {
cache_hit_rate: String,
}

fn host_stats_table(host_stats: &HashMap<String, HostStats>) -> String {
let sorted_hosts = super::sort_host_stats(host_stats);
fn host_stats_table(host_stats: &HostStatsMap) -> String {
let sorted_hosts = host_stats.sorted();

let entries: Vec<HostStatsTableEntry> = sorted_hosts
.into_iter()
Expand Down Expand Up @@ -55,34 +68,3 @@ fn host_stats_table(host_stats: &HashMap<String, HostStats>) -> String {
.with(style)
.to_string()
}

struct MarkdownHostStats(HashMap<String, HostStats>);

impl Display for MarkdownHostStats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.0.is_empty() {
return Ok(());
}

writeln!(f, "\n## Per-host Statistics")?;
writeln!(f)?;
writeln!(f, "{}", host_stats_table(&self.0))?;

Ok(())
}
}

pub(crate) struct Markdown;

impl Markdown {
pub(crate) const fn new() -> Self {
Self {}
}
}

impl HostStatsFormatter for Markdown {
fn format(&self, host_stats: HashMap<String, HostStats>) -> Result<String> {
let markdown = MarkdownHostStats(host_stats);
Ok(markdown.to_string())
}
}
27 changes: 3 additions & 24 deletions lychee-bin/src/formatters/host_stats/mod.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,7 @@
mod compact;
mod detailed;
mod json;
mod markdown;

pub(crate) use compact::Compact;
pub(crate) use detailed::Detailed;
pub(crate) use json::Json;
pub(crate) use markdown::Markdown;

use anyhow::Result;
use lychee_lib::ratelimit::HostStats;
use std::collections::HashMap;

/// Trait for formatting per-host statistics in different output formats
pub(crate) trait HostStatsFormatter {
/// Format the host statistics and return them as a string
fn format(&self, host_stats: HashMap<String, HostStats>) -> Result<String>;
}

/// Sort host statistics by request count (descending order)
/// This matches the display order we want in the output
fn sort_host_stats(host_stats: &HashMap<String, HostStats>) -> Vec<(&String, &HostStats)> {
let mut sorted_hosts: Vec<_> = host_stats.iter().collect();
// Sort by total requests (descending)
sorted_hosts.sort_by_key(|(_, stats)| std::cmp::Reverse(stats.total_requests));
sorted_hosts
}
pub(crate) use compact::CompactHostStats;
pub(crate) use detailed::DetailedHostStats;
pub(crate) use markdown::MarkdownHostStats;
15 changes: 1 addition & 14 deletions lychee-bin/src/formatters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub(crate) mod response;
pub(crate) mod stats;
pub(crate) mod suggestion;

use self::{host_stats::HostStatsFormatter, response::ResponseFormatter, stats::StatsFormatter};
use self::{response::ResponseFormatter, stats::StatsFormatter};
use crate::options::{OutputMode, StatsFormat};
use supports_color::Stream;

Expand Down Expand Up @@ -42,19 +42,6 @@ pub(crate) fn get_progress_formatter(mode: &OutputMode) -> Box<dyn ResponseForma
get_response_formatter(&mode)
}

/// Create a host stats formatter based on the given format and mode options
pub(crate) fn get_host_stats_formatter(
format: &StatsFormat,
_mode: &OutputMode,
) -> Box<dyn HostStatsFormatter> {
match format {
StatsFormat::Compact | StatsFormat::Raw => Box::new(host_stats::Compact::new()), // Use compact for raw
StatsFormat::Detailed => Box::new(host_stats::Detailed::new()),
StatsFormat::Json => Box::new(host_stats::Json::new()),
StatsFormat::Markdown => Box::new(host_stats::Markdown::new()),
}
}

/// Create a response formatter based on the given format option
pub(crate) fn get_response_formatter(mode: &OutputMode) -> Box<dyn ResponseFormatter> {
// Checks if color is supported in current environment or NO_COLOR is set (https://no-color.org)
Expand Down
Loading