Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
cli: Fix `rad config` bugs
cloudhead committed 2 years ago
commit d86d99e0021258c701deeb293ab3b192ceb1d9aa
parent b0fbbeed6b42b1846dbd9b2a2d45bc9c2b25e881
3 files changed +55 -27
modified radicle-cli/src/commands/config.rs
@@ -2,8 +2,11 @@
use std::ffi::OsString;
use std::path::Path;
use std::process;
+
use std::str::FromStr;

use anyhow::anyhow;
+
use radicle::node::Alias;
+
use radicle::profile::Config;

use crate::terminal as term;
use crate::terminal::args::{Args, Error, Help};
@@ -18,11 +21,10 @@ Usage

    rad config [<option>...]
    rad config show [<option>...]
-
    rad config init [<option>...]
+
    rad config init --alias <alias> [<option>...]
    rad config edit [<option>...]
    rad config get <key> [<option>...]

-

    If no argument is specified, prints the current radicle configuration as JSON.
    To initialize a new configuration file, use `rad config init`.

@@ -44,6 +46,7 @@ enum Operation {

pub struct Options {
    op: Operation,
+
    alias: Option<Alias>,
}

impl Args for Options {
@@ -52,6 +55,7 @@ impl Args for Options {

        let mut parser = lexopt::Parser::from_args(args);
        let mut op: Option<Operation> = None;
+
        let mut alias = None;

        #[allow(clippy::never_loop)]
        while let Some(arg) = parser.next()? {
@@ -59,6 +63,13 @@ impl Args for Options {
                Long("help") | Short('h') => {
                    return Err(Error::Help.into());
                }
+
                Long("alias") => {
+
                    let value = parser.value()?;
+
                    let input = value.to_string_lossy();
+
                    let input = Alias::from_str(&input)?;
+

+
                    alias = Some(input);
+
                }
                Value(val) if op.is_none() => match val.to_string_lossy().as_ref() {
                    "show" => op = Some(Operation::Show),
                    "edit" => op = Some(Operation::Edit),
@@ -78,6 +89,7 @@ impl Args for Options {
        Ok((
            Options {
                op: op.unwrap_or_default(),
+
                alias,
            },
            vec![],
        ))
@@ -85,14 +97,16 @@ impl Args for Options {
}

pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
-
    let profile = ctx.profile()?;
-
    let path = profile.home.config();
+
    let home = ctx.home()?;
+
    let path = home.config();

    match options.op {
        Operation::Show => {
+
            let profile = ctx.profile()?;
            term::json::to_pretty(&profile.config, path.as_path())?.print();
        }
        Operation::Get(key) => {
+
            let profile = ctx.profile()?;
            let data = serde_json::to_value(profile.config)?;
            if let Some(value) = get_value(&data, &key) {
                print_value(value)?;
@@ -102,7 +116,16 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
            if path.try_exists()? {
                anyhow::bail!("configuration file already exists at `{}`", path.display());
            }
-
            profile.config.write(&path)?;
+
            Config::init(
+
                options.alias.ok_or(anyhow!(
+
                    "an alias must be provided to initialize a new configuration"
+
                ))?,
+
                &path,
+
            )?;
+
            term::success!(
+
                "Initialized new Radicle configuration at {}",
+
                path.display()
+
            );
        }
        Operation::Edit => {
            let Some(cmd) = term::editor::default_editor() else {
modified radicle-cli/src/main.rs
@@ -75,7 +75,7 @@ fn print_help() -> anyhow::Result<()> {
    println!("{DESCRIPTION}");
    println!();

-
    rad_help::run(Default::default(), term::profile)
+
    rad_help::run(Default::default(), term::DefaultContext)
}

fn run(command: Command) -> Result<(), Option<anyhow::Error>> {
modified radicle-cli/src/terminal.rs
@@ -14,7 +14,7 @@ use std::process;

pub use radicle_term::*;

-
use radicle::profile::Profile;
+
use radicle::profile::{Home, Profile};

use crate::terminal;

@@ -22,20 +22,17 @@ use crate::terminal;
pub trait Context {
    /// Return the currently active profile, or an error if no profile is active.
    fn profile(&self) -> Result<Profile, anyhow::Error>;
+
    /// Return the Radicle home.
+
    fn home(&self) -> Result<Home, std::io::Error>;
}

impl Context for Profile {
    fn profile(&self) -> Result<Profile, anyhow::Error> {
        Ok(self.clone())
    }
-
}

-
impl<F> Context for F
-
where
-
    F: Fn() -> Result<Profile, anyhow::Error>,
-
{
-
    fn profile(&self) -> Result<Profile, anyhow::Error> {
-
        self()
+
    fn home(&self) -> Result<Home, std::io::Error> {
+
        Ok(self.home.clone())
    }
}

@@ -57,7 +54,7 @@ where
pub fn run_command<A, C>(help: Help, cmd: C) -> !
where
    A: Args,
-
    C: Command<A, fn() -> anyhow::Result<Profile>>,
+
    C: Command<A, DefaultContext>,
{
    let args = std::env::args_os().skip(1).collect();

@@ -67,7 +64,7 @@ where
pub fn run_command_args<A, C>(help: Help, cmd: C, args: Vec<OsString>) -> !
where
    A: Args,
-
    C: Command<A, fn() -> anyhow::Result<Profile>>,
+
    C: Command<A, DefaultContext>,
{
    use io as term;

@@ -108,7 +105,7 @@ where
        }
    };

-
    match cmd.run(options, self::profile) {
+
    match cmd.run(options, DefaultContext) {
        Ok(()) => process::exit(0),
        Err(err) => {
            terminal::fail(help.name, &err);
@@ -117,17 +114,25 @@ where
    }
}

-
/// Get the default profile. Fails if there is no profile.
-
pub fn profile() -> Result<Profile, anyhow::Error> {
-
    match Profile::load() {
-
        Ok(profile) => Ok(profile),
-
        Err(radicle::profile::Error::NotFound(path)) => Err(args::Error::WithHint {
-
            err: anyhow::anyhow!("Radicle profile not found in '{}'.", path.display()),
-
            hint: "To setup your radicle profile, run `rad auth`.",
+
/// Gets the default profile. Fails if there is no profile.
+
pub struct DefaultContext;
+

+
impl Context for DefaultContext {
+
    fn home(&self) -> Result<Home, std::io::Error> {
+
        radicle::profile::home()
+
    }
+

+
    fn profile(&self) -> Result<Profile, anyhow::Error> {
+
        match Profile::load() {
+
            Ok(profile) => Ok(profile),
+
            Err(radicle::profile::Error::NotFound(path)) => Err(args::Error::WithHint {
+
                err: anyhow::anyhow!("Radicle profile not found in '{}'.", path.display()),
+
                hint: "To setup your radicle profile, run `rad auth`.",
+
            }
+
            .into()),
+
            Err(radicle::profile::Error::Config(e)) => Err(e.into()),
+
            Err(e) => Err(anyhow::anyhow!("Could not load radicle profile: {e}")),
        }
-
        .into()),
-
        Err(radicle::profile::Error::Config(e)) => Err(e.into()),
-
        Err(e) => Err(anyhow::anyhow!("Could not load radicle profile: {e}")),
    }
}