use std::path::PathBuf;
use clap::{Args as ClapArgs, Subcommand};
use crate::cli::output;
use crate::sdk::profile;
use crate::shared::error::Error;
use crate::shared::time::parse_duration;
#[derive(ClapArgs, Debug)]
pub struct Args {
#[command(subcommand)]
pub sub: ProfileSub,
}
#[derive(Subcommand, Debug)]
pub enum ProfileSub {
List(ListArgs),
Info(InfoArgs),
LockStatus(InfoArgs),
Downloads(InfoArgs),
Delete(DeleteArgs),
Prune(PruneArgs),
Cookies(InfoArgs),
}
#[derive(ClapArgs, Debug)]
pub struct ListArgs {
#[arg(long)]
pub profile_root: Option<PathBuf>,
}
#[derive(ClapArgs, Debug)]
pub struct InfoArgs {
pub name: String,
#[arg(long)]
pub profile_root: Option<PathBuf>,
}
#[derive(ClapArgs, Debug)]
pub struct DeleteArgs {
pub name: String,
#[arg(long)]
pub confirm: String,
#[arg(long)]
pub profile_root: Option<PathBuf>,
}
#[derive(ClapArgs, Debug)]
pub struct PruneArgs {
#[arg(long)]
pub older_than: String,
#[arg(long, default_value_t = false)]
pub dry_run: bool,
#[arg(long)]
pub profile_root: Option<PathBuf>,
}
pub async fn run(args: Args) -> Result<(), Error> {
match args.sub {
ProfileSub::List(a) => {
let root = profile_root_for_output(a.profile_root.as_deref());
let entries = profile::list(a.profile_root.as_deref())?;
output::emit(
"profile_list",
&serde_json::json!({
"profile_root": root.display().to_string(),
"profiles": entries,
}),
)
}
ProfileSub::Info(a) => {
let entry = profile::info(&a.name, a.profile_root.as_deref())?;
output::emit("profile_info", &entry)
}
ProfileSub::LockStatus(a) => {
let status = profile::lock_status(&a.name, a.profile_root.as_deref())?;
output::emit("profile_lock_status", &status)
}
ProfileSub::Downloads(a) => {
let entry = profile::info(&a.name, a.profile_root.as_deref())?;
let download_dir = entry.path.join("downloads");
let download_dir = download_dir.canonicalize().unwrap_or(download_dir);
let downloads = profile::downloads(&a.name, a.profile_root.as_deref())?;
output::emit(
"profile_downloads",
&serde_json::json!({
"name": a.name,
"download_dir": download_dir.display().to_string(),
"downloads": downloads,
}),
)
}
ProfileSub::Delete(a) => {
profile::delete(&a.name, &a.confirm, a.profile_root.as_deref())?;
output::emit(
"profile_delete",
&serde_json::json!({"name": a.name, "deleted": true}),
)
}
ProfileSub::Prune(a) => {
let root = profile_root_for_output(a.profile_root.as_deref());
let older_than = parse_duration(&a.older_than)?;
let removed = profile::prune(older_than, a.dry_run, a.profile_root.as_deref())?;
output::emit(
"profile_prune",
&serde_json::json!({
"profile_root": root.display().to_string(),
"dry_run": a.dry_run,
"profiles": removed,
}),
)
}
ProfileSub::Cookies(a) => {
let entry = profile::info(&a.name, a.profile_root.as_deref())?;
let jar_path = entry.path.join("cookies.jar.json");
let jar = crate::sdk::profile::cookie_jar::CookieJar::load(&jar_path)?;
let cookies = jar.cookies_redacted();
output::emit(
"profile_cookies",
&serde_json::json!({
"name": a.name,
"jar_path": jar_path.display().to_string(),
"count": cookies.len(),
"cookies": cookies,
}),
)
}
}
}
fn profile_root_for_output(root: Option<&std::path::Path>) -> PathBuf {
root.map(PathBuf::from)
.unwrap_or_else(profile::paths::default_root)
}