use std::path::PathBuf;
use clap::Parser;
use radicle::identity::doc::RepoId;
use radicle::identity::IdError;
use radicle::node::policy::Scope;
use radicle::prelude::*;
use radicle::storage::refs;
use crate::common_args::{
SignedReferencesFeatureLevel, SignedReferencesFeatureLevelParser,
ABOUT_FETCH_SIGNED_REFERENCES_FEATURE_LEVEL_MINIMUM,
};
use crate::node::SyncSettings;
use crate::terminal;
const ABOUT: &str = "Clone a Radicle repository";
const LONG_ABOUT: &str = r#"
The `clone` command will use your local node's routing table to find seeds from
which it can clone the repository.
For private repositories, use the `--seed` options, to clone directly
from known seeds in the privacy set."#;
fn parse_rid(value: &str) -> Result<RepoId, IdError> {
value.strip_prefix("rad://").unwrap_or(value).parse()
}
#[derive(Debug, Parser)]
pub(super) struct SyncArgs {
#[arg(short, long = "seed", value_name = "NID", action = clap::ArgAction::Append)]
seeds: Vec<NodeId>,
#[arg(long, value_parser = humantime::parse_duration, default_value = "9s")]
timeout: std::time::Duration,
#[arg(
long,
value_parser = SignedReferencesFeatureLevelParser,
help = ABOUT_FETCH_SIGNED_REFERENCES_FEATURE_LEVEL_MINIMUM
)]
signed_refs_feature_level: Option<SignedReferencesFeatureLevel>,
}
impl From<SyncArgs> for SyncSettings {
fn from(args: SyncArgs) -> Self {
SyncSettings {
timeout: args.timeout,
seeds: args.seeds.into_iter().collect(),
signed_references_minimum_feature_level: args
.signed_refs_feature_level
.map(refs::FeatureLevel::from),
..SyncSettings::default()
}
}
}
#[derive(Debug, Parser)]
#[clap(about = ABOUT, long_about = LONG_ABOUT, disable_version_flag = true)]
pub struct Args {
#[arg(value_name = "RID", value_parser = parse_rid)]
pub(super) repo: RepoId,
#[arg(value_name = "PATH")]
pub(super) directory: Option<PathBuf>,
#[arg(
long,
value_parser = terminal::args::ScopeParser
)]
pub(super) scope: Option<Scope>,
#[clap(flatten)]
pub(super) sync: SyncArgs,
#[arg(long)]
pub(super) bare: bool,
#[arg(long, hide = true)]
pub(super) no_confirm: bool,
}
#[cfg(test)]
mod test {
use super::Args;
use clap::Parser;
#[test]
fn should_parse_rid_non_urn() {
let args = Args::try_parse_from(["clone", "z3Tr6bC7ctEg2EHmLvknUr29mEDLH"]);
assert!(args.is_ok())
}
#[test]
fn should_parse_rid_urn() {
let args = Args::try_parse_from(["clone", "rad:z3Tr6bC7ctEg2EHmLvknUr29mEDLH"]);
assert!(args.is_ok())
}
#[test]
fn should_parse_rid_url() {
let args = Args::try_parse_from(["clone", "rad://z3Tr6bC7ctEg2EHmLvknUr29mEDLH"]);
assert!(args.is_ok())
}
}