radicle_cli/commands/
fork.rs1use 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}