fork.rs
1 use std::ffi::OsString; 2 use std::path::Path; 3 4 use anyhow::Context as _; 5 6 use radicle::prelude::Id; 7 use radicle::rad; 8 9 use crate::terminal as term; 10 use crate::terminal::args; 11 use crate::terminal::args::{Args, Error, Help}; 12 13 pub const HELP: Help = Help { 14 name: "fork", 15 description: "Create a fork of a project", 16 version: env!("CARGO_PKG_VERSION"), 17 usage: r#" 18 Usage 19 20 rad fork [<rid>] [<option>...] 21 22 Options 23 24 --help Print help 25 "#, 26 }; 27 28 pub struct Options { 29 rid: Option<Id>, 30 } 31 32 impl Args for Options { 33 fn from_args(args: Vec<OsString>) -> anyhow::Result<(Self, Vec<OsString>)> { 34 use lexopt::prelude::*; 35 36 let mut parser = lexopt::Parser::from_args(args); 37 let mut rid = None; 38 39 if let Some(arg) = parser.next()? { 40 match arg { 41 Long("help") | Short('h') => { 42 return Err(Error::Help.into()); 43 } 44 Value(val) if rid.is_none() => { 45 rid = Some(args::rid(&val)?); 46 } 47 _ => return Err(anyhow::anyhow!(arg.unexpected())), 48 } 49 } 50 51 Ok((Options { rid }, vec![])) 52 } 53 } 54 55 pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> { 56 let profile = ctx.profile()?; 57 let signer = profile.signer()?; 58 let storage = &profile.storage; 59 60 let rid = match options.rid { 61 Some(rid) => rid, 62 None => { 63 let (_, rid) = radicle::rad::repo(Path::new(".")) 64 .context("Current directory is not a radicle project")?; 65 66 rid 67 } 68 }; 69 70 rad::fork(rid, &signer, &storage)?; 71 term::success!("Forked project {rid} for {}", profile.id()); 72 73 Ok(()) 74 }