use std::io::{self, Write};
#[cfg(feature = "ui")]
use std::path::PathBuf;
use anyhow::Result;
use crate::classify;
#[cfg(feature = "ui")]
use crate::entry::SortOrder;
use crate::render::{self, RenderConfig};
#[cfg(feature = "ui")]
use crate::scan::HardlinkPolicy;
use crate::scan::{self};
use crate::wire::explain::WireExplain;
use super::plan::{RunPlan, ScanPlan};
pub(super) fn run(plan: RunPlan) -> Result<()> {
match plan {
RunPlan::ExplainCategory { name, json } => run_explain(&name, json),
#[cfg(feature = "ui")]
RunPlan::Ui {
path,
port,
sort,
reverse,
hardlinks,
} => run_ui(path, port, sort, reverse, hardlinks),
RunPlan::Scan(scan) => run_scan(scan),
}
}
fn run_explain(name: &str, json: bool) -> Result<()> {
let stdout = io::stdout();
let mut out = stdout.lock();
explain_category(name, json, &mut out)?;
out.flush()?;
Ok(())
}
#[cfg(feature = "ui")]
fn run_ui(
path: PathBuf,
port: u16,
sort: SortOrder,
reverse: bool,
hardlinks: HardlinkPolicy,
) -> Result<()> {
let rt = tokio::runtime::Runtime::new()?;
rt.block_on(crate::ui::serve(path, port, sort, reverse, hardlinks))?;
Ok(())
}
fn run_scan(plan: ScanPlan) -> Result<()> {
let (mut tree, counts) = scan::scan(&plan.path, plan.hardlinks)?;
tree.sort(&plan.sort, plan.reverse);
let config = RenderConfig {
max_depth: plan.max_depth,
top: plan.top,
scan_root: &plan.path,
counts: &counts,
hardlinks: plan.hardlinks,
filter: &plan.filter,
};
let stdout = io::stdout();
let mut out = stdout.lock();
render::write(&tree, &config, plan.mode, &mut out)?;
out.flush()?;
let skipped = counts.skipped();
if skipped > 0 {
let plural = if skipped == 1 { "" } else { "s" };
eprintln!(
"warning: {skipped} path{plural} could not be read \
(permission denied or path vanished); reported total may be incomplete"
);
}
Ok(())
}
fn explain_category(name: &str, json: bool, out: &mut impl Write) -> Result<()> {
let as_dir = classify::explain_dir(name);
let as_file = classify::explain_file(name);
if json {
let payload = WireExplain::new(name, &as_dir, &as_file);
writeln!(out, "{}", serde_json::to_string_pretty(&payload)?)?;
} else {
writeln!(out, "{name:?}")?;
writeln!(
out,
" as directory: {:<12} ({})",
as_dir.category.label(),
as_dir.reason.describe()
)?;
writeln!(
out,
" as file: {:<12} ({})",
as_file.category.label(),
as_file.reason.describe()
)?;
}
Ok(())
}