use clap::{Args, Subcommand};
use serde::Serialize;
use homeboy::logs::{self, LogContent, LogEntry, LogSearchResult, PinnedLogsContent};
use crate::commands::CmdResult;
#[derive(Args)]
pub struct LogsArgs {
#[command(subcommand)]
command: LogsCommand,
}
#[derive(Subcommand)]
pub enum LogsCommand {
List {
project_id: String,
},
Show {
project_id: String,
path: Option<String>,
#[arg(short = 'n', long, default_value = "100")]
lines: u32,
#[arg(short, long)]
follow: bool,
},
Clear {
project_id: String,
path: String,
},
Search {
project_id: String,
path: String,
pattern: String,
#[arg(short = 'i', long)]
ignore_case: bool,
#[arg(short = 'n', long)]
lines: Option<u32>,
#[arg(short = 'C', long)]
context: Option<u32>,
},
}
pub fn is_interactive(args: &LogsArgs) -> bool {
matches!(&args.command, LogsCommand::Show { follow: true, .. })
}
pub fn run(args: LogsArgs, _global: &crate::commands::GlobalArgs) -> CmdResult<LogsOutput> {
match args.command {
LogsCommand::List { project_id } => list(&project_id),
LogsCommand::Show {
project_id,
path: Some(path),
lines,
follow,
} => show(&project_id, &path, lines, follow),
LogsCommand::Show {
project_id,
path: None,
lines,
follow,
} => show_pinned(&project_id, lines, follow),
LogsCommand::Clear { project_id, path } => clear(&project_id, &path),
LogsCommand::Search {
project_id,
path,
pattern,
ignore_case,
lines,
context,
} => search(&project_id, &path, &pattern, ignore_case, lines, context),
}
}
#[derive(Serialize)]
pub struct LogsOutput {
pub command: String,
pub project_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub entries: Option<Vec<LogEntry>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub log: Option<LogContent>,
#[serde(skip_serializing_if = "Option::is_none")]
pub pinned_logs: Option<PinnedLogsContent>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cleared_path: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub search_result: Option<LogSearchResult>,
}
fn list(project_id: &str) -> CmdResult<LogsOutput> {
let entries = logs::list(project_id)?;
Ok((
LogsOutput {
command: "logs.list".to_string(),
project_id: project_id.to_string(),
entries: Some(entries),
log: None,
pinned_logs: None,
cleared_path: None,
search_result: None,
},
0,
))
}
fn show(project_id: &str, path: &str, lines: u32, follow: bool) -> CmdResult<LogsOutput> {
if follow {
let code = logs::follow(project_id, path)?;
Ok((
LogsOutput {
command: "logs.follow".to_string(),
project_id: project_id.to_string(),
entries: None,
log: None,
pinned_logs: None,
cleared_path: None,
search_result: None,
},
code,
))
} else {
let content = logs::show(project_id, path, lines)?;
Ok((
LogsOutput {
command: "logs.show".to_string(),
project_id: project_id.to_string(),
entries: None,
log: Some(content),
pinned_logs: None,
cleared_path: None,
search_result: None,
},
0,
))
}
}
fn show_pinned(project_id: &str, lines: u32, follow: bool) -> CmdResult<LogsOutput> {
if follow {
return Err(homeboy::Error::validation_invalid_argument(
"follow",
"Cannot follow multiple pinned logs. Specify a log path to follow.",
None,
Some(vec![
format!("homeboy logs show {} <path> --follow", project_id),
format!("homeboy logs list {}", project_id),
]),
));
}
let content = logs::show_pinned(project_id, lines)?;
Ok((
LogsOutput {
command: "logs.show_pinned".to_string(),
project_id: project_id.to_string(),
entries: None,
log: None,
pinned_logs: Some(content),
cleared_path: None,
search_result: None,
},
0,
))
}
fn clear(project_id: &str, path: &str) -> CmdResult<LogsOutput> {
let cleared_path = logs::clear(project_id, path)?;
Ok((
LogsOutput {
command: "logs.clear".to_string(),
project_id: project_id.to_string(),
entries: None,
log: None,
pinned_logs: None,
cleared_path: Some(cleared_path),
search_result: None,
},
0,
))
}
fn search(
project_id: &str,
path: &str,
pattern: &str,
ignore_case: bool,
lines: Option<u32>,
context: Option<u32>,
) -> CmdResult<LogsOutput> {
let result = logs::search(project_id, path, pattern, ignore_case, lines, context)?;
Ok((
LogsOutput {
command: "logs.search".to_string(),
project_id: project_id.to_string(),
entries: None,
log: None,
pinned_logs: None,
cleared_path: None,
search_result: Some(result),
},
0,
))
}