mod args; use radicle::node::Handle; use radicle::node::policy; use radicle::node::policy::{Policy, Scope}; use radicle::{Node, prelude::*}; use radicle_term::Element as _; use crate::commands::sync; use crate::terminal as term; pub use args::Args; pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> { let profile = ctx.profile()?; let mut node = radicle::Node::new(profile.socket_from_env()); match args::Operation::from(args) { args::Operation::List => seeding(&profile)?, args::Operation::Seed { rids, should_fetch, settings, scope, } => { let settings = settings.with_profile(&profile); for rid in rids { update(rid, scope, &mut node, &profile)?; if should_fetch && node.is_running() && let Err(e) = sync::fetch(rid, settings.clone(), &mut node, &profile) { term::error(e); } } } } Ok(()) } pub fn update( rid: RepoId, scope: Option, node: &mut Node, profile: &Profile, ) -> Result<(), anyhow::Error> { let scope = match scope { Some(scope) => scope, None => profile .policies()? .seed_policy(&rid)? .scope() .unwrap_or(Scope::Followed), }; let updated = profile.seed(rid, scope, node)?; let outcome = if updated { "updated" } else { "exists" }; if let Ok(repo) = profile.storage.repository(rid) && repo.identity_doc()?.is_public() { profile.add_inventory(rid, node)?; term::success!("Inventory updated with {}", term::format::tertiary(rid)); } term::success!( "Seeding policy {outcome} for {} with scope '{scope}'", term::format::tertiary(rid), ); Ok(()) } pub fn seeding(profile: &Profile) -> anyhow::Result<()> { let store = profile.policies()?; let storage = &profile.storage; let mut t = term::Table::new(term::table::TableOptions::bordered()); t.header([ term::format::default(String::from("Repository")), term::format::default(String::from("Name")), term::format::default(String::from("Policy")), term::format::default(String::from("Scope")), ]); t.divider(); for policy in store.seed_policies()? { match policy { Ok(policy::SeedPolicy { rid, policy }) => { let id = rid.to_string(); let name = storage .repository(rid) .and_then(|repo| repo.project().map(|proj| proj.name().to_string())) .unwrap_or_default(); let scope = policy .scope() .map_or(String::new(), |scope| scope.to_string()); let policy = term::format::policy(&Policy::from(policy)); t.push([ term::format::tertiary(id), name.into(), policy, term::format::dim(scope), ]) } Err(err) => { term::error(format!("Failed to read a seeding policy: {err}")); } } } if t.is_empty() { term::println(term::format::dim("No seeding policies to show.")); } else { t.print(); } Ok(()) }