radicle_cli/commands/
fork.rs

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