cli/main: migrate main to use clap
Now that all commands can be parsed by clap, remove any custom parsing and
directly use `CliArgs::parse`.
The `Diff` command was removed, since only one `external_command` can be
declared for a subcommand. The handling of `rad diff` is now done via the
`External` variant. If the subcommand name is `diff` then this is executed,
otherwise delegate to the possible `rad-{exe}` command.
Also of note, the `rad inspect` command has an alias `rad .`. This changes the
behaviour of `rad . --help`. Before, it would print the help of the `rad`
command. Now, it prints the help of `rad inspect`.
Co-authored-by: Lorenz Leutgeb <lorenz.leutgeb@radicle.xyz>
This commit is contained in:
parent
5053a1aa77
commit
23332fa318
|
|
@ -1,45 +1,52 @@
|
||||||
```
|
```
|
||||||
$ rad --help
|
$ rad --help
|
||||||
rad [..]
|
Radicle is a sovereign code forge built on Git.
|
||||||
Radicle command line interface
|
|
||||||
|
|
||||||
Usage: rad <command> [--help]
|
See `rad <COMMAND> --help` to learn about a specific command.
|
||||||
Common `rad` commands used in various situations:
|
|
||||||
|
|
||||||
auth Manage identities and profiles
|
|
||||||
block Block repositories or nodes from being seeded or followed
|
|
||||||
checkout Checkout a repository into the local directory
|
|
||||||
clone Clone a Radicle repository
|
|
||||||
config Manage your local Radicle configuration
|
|
||||||
debug Write out information to help debug your Radicle node remotely
|
|
||||||
fork Create a fork of a repository
|
|
||||||
help CLI help
|
|
||||||
id Manage repository identities
|
|
||||||
init Initialize a Radicle repository
|
|
||||||
inbox Manage your Radicle notifications
|
|
||||||
inspect Inspect a Radicle repository
|
|
||||||
issue Manage issues
|
|
||||||
ls List repositories
|
|
||||||
node Control and query the Radicle Node
|
|
||||||
patch Manage patches
|
|
||||||
path Display the Radicle home path
|
|
||||||
publish Publish a repository to the network
|
|
||||||
clean Remove all remotes from a repository
|
|
||||||
self Show information about your identity and device
|
|
||||||
seed Manage repository seeding policies
|
|
||||||
follow Manage node follow policies
|
|
||||||
unblock Unblock repositories or nodes to allow them to be seeded or followed
|
|
||||||
unfollow Unfollow a peer
|
|
||||||
unseed Remove repository seeding policies
|
|
||||||
remote Manage a repository's remotes
|
|
||||||
stats Displays aggregated repository and node metrics
|
|
||||||
sync Sync repositories to the network
|
|
||||||
watch Wait for some state to be updated
|
|
||||||
|
|
||||||
See `rad <command> --help` to learn about a specific command.
|
|
||||||
|
|
||||||
Do you have feedback?
|
Do you have feedback?
|
||||||
- Chat[..]
|
- Chat <radicle.zulipchat.com>
|
||||||
- Mail[..]
|
- Mail <feedback@radicle.xyz>
|
||||||
(Messages are automatically posted to the public #feedback channel on Zulip.)
|
(Messages are automatically posted to the public #feedback channel on Zulip.)
|
||||||
|
|
||||||
|
Usage: rad <COMMAND>
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
auth Manage identities and profiles
|
||||||
|
block Block repositories or nodes from being seeded or followed
|
||||||
|
checkout Checkout a repository into the local directory
|
||||||
|
clean Remove all remotes from a repository
|
||||||
|
clone Clone a Radicle repository
|
||||||
|
config Manage your local Radicle configuration
|
||||||
|
debug Write out information to help debug your Radicle node remotely
|
||||||
|
follow Manage node follow policies
|
||||||
|
fork Create a fork of a repository
|
||||||
|
id Manage repository identities
|
||||||
|
inbox Manage your Radicle notifications
|
||||||
|
init Initialize a Radicle repository
|
||||||
|
inspect Inspect a Radicle repository
|
||||||
|
issue Manage issues
|
||||||
|
ls List repositories
|
||||||
|
node Control and query the Radicle Node
|
||||||
|
patch Manage patches
|
||||||
|
path Display the Radicle home path
|
||||||
|
publish Publish a repository to the network
|
||||||
|
remote Manage a repository's remotes
|
||||||
|
seed Manage repository seeding policies
|
||||||
|
self Show information about your identity and device
|
||||||
|
stats Displays aggregated repository and node metrics
|
||||||
|
sync Sync repositories to the network
|
||||||
|
unblock Unblock repositories or nodes to allow them to be seeded or followed
|
||||||
|
unfollow Unfollow a peer
|
||||||
|
unseed Remove repository seeding policies
|
||||||
|
watch Wait for some state to be updated
|
||||||
|
version Print the version information of the CLI
|
||||||
|
help Print this message or the help of the given subcommand(s)
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help
|
||||||
|
Print help (see a summary with '-h')
|
||||||
|
|
||||||
|
-V, --version
|
||||||
|
Print version
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::io::{self, Write};
|
use std::io;
|
||||||
use std::{io::ErrorKind, iter, process};
|
use std::io::Write;
|
||||||
|
use std::{io::ErrorKind, process};
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use clap::builder::styling::AnsiColor;
|
use clap::builder::styling::AnsiColor;
|
||||||
|
|
@ -18,7 +19,16 @@ pub const RADICLE_VERSION: &str = env!("RADICLE_VERSION");
|
||||||
pub const RADICLE_VERSION_LONG: &str =
|
pub const RADICLE_VERSION_LONG: &str =
|
||||||
concat!(env!("RADICLE_VERSION"), " (", env!("GIT_HEAD"), ")");
|
concat!(env!("RADICLE_VERSION"), " (", env!("GIT_HEAD"), ")");
|
||||||
pub const DESCRIPTION: &str = "Radicle command line interface";
|
pub const DESCRIPTION: &str = "Radicle command line interface";
|
||||||
pub const LONG_DESCRIPTION: &str = "Radicle is a sovereign code forge built on Git.";
|
pub const LONG_DESCRIPTION: &str = "
|
||||||
|
Radicle is a sovereign code forge built on Git.
|
||||||
|
|
||||||
|
See `rad <COMMAND> --help` to learn about a specific command.
|
||||||
|
|
||||||
|
Do you have feedback?
|
||||||
|
- Chat <\x1b]8;;https://radicle.zulipchat.com\x1b\\radicle.zulipchat.com\x1b]8;;\x1b\\>
|
||||||
|
- Mail <\x1b]8;;mailto:feedback@radicle.xyz\x1b\\feedback@radicle.xyz\x1b]8;;\x1b\\>
|
||||||
|
(Messages are automatically posted to the public #feedback channel on Zulip.)\
|
||||||
|
";
|
||||||
pub const TIMESTAMP: &str = env!("SOURCE_DATE_EPOCH");
|
pub const TIMESTAMP: &str = env!("SOURCE_DATE_EPOCH");
|
||||||
pub const VERSION: Version = Version {
|
pub const VERSION: Version = Version {
|
||||||
name: NAME,
|
name: NAME,
|
||||||
|
|
@ -36,15 +46,17 @@ const STYLES: Styles = Styles::styled()
|
||||||
#[command(name = NAME)]
|
#[command(name = NAME)]
|
||||||
#[command(version = RADICLE_VERSION)]
|
#[command(version = RADICLE_VERSION)]
|
||||||
#[command(long_version = RADICLE_VERSION_LONG)]
|
#[command(long_version = RADICLE_VERSION_LONG)]
|
||||||
|
#[command(about = DESCRIPTION)]
|
||||||
|
#[command(long_about = LONG_DESCRIPTION)]
|
||||||
#[command(propagate_version = true)]
|
#[command(propagate_version = true)]
|
||||||
#[command(styles = STYLES)]
|
#[command(styles = STYLES)]
|
||||||
struct CliArgs {
|
struct CliArgs {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
pub command: Option<Commands>,
|
pub command: Command,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subcommand, Debug)]
|
#[derive(Subcommand, Debug)]
|
||||||
enum Commands {
|
enum Command {
|
||||||
Auth(auth::Args),
|
Auth(auth::Args),
|
||||||
Block(block::Args),
|
Block(block::Args),
|
||||||
Checkout(checkout::Args),
|
Checkout(checkout::Args),
|
||||||
|
|
@ -54,23 +66,12 @@ enum Commands {
|
||||||
Cob(cob::Args),
|
Cob(cob::Args),
|
||||||
Config(config::Args),
|
Config(config::Args),
|
||||||
Debug(debug::Args),
|
Debug(debug::Args),
|
||||||
|
|
||||||
/// This command is deprecated and delegates to `git diff`.
|
|
||||||
/// Even before it was deprecated, it was not printed by
|
|
||||||
/// `rad -h`, so it is also hidden.
|
|
||||||
///
|
|
||||||
/// Since it is hidden, it makes no sense to add `about`
|
|
||||||
/// for the command listing, and since it is external,
|
|
||||||
/// `--help` will delegate to `git diff --help` it makes
|
|
||||||
/// no sense to add `long_about` for `rad diff --help`.
|
|
||||||
#[command(external_subcommand, hide = true)]
|
|
||||||
Diff(Vec<OsString>),
|
|
||||||
|
|
||||||
Follow(follow::Args),
|
Follow(follow::Args),
|
||||||
Fork(fork::Args),
|
Fork(fork::Args),
|
||||||
Id(id::Args),
|
Id(id::Args),
|
||||||
Inbox(inbox::Args),
|
Inbox(inbox::Args),
|
||||||
Init(init::Args),
|
Init(init::Args),
|
||||||
|
#[command(alias = ".")]
|
||||||
Inspect(inspect::Args),
|
Inspect(inspect::Args),
|
||||||
Issue(issue::Args),
|
Issue(issue::Args),
|
||||||
Ls(ls::Args),
|
Ls(ls::Args),
|
||||||
|
|
@ -88,13 +89,16 @@ enum Commands {
|
||||||
Unfollow(unfollow::Args),
|
Unfollow(unfollow::Args),
|
||||||
Unseed(unseed::Args),
|
Unseed(unseed::Args),
|
||||||
Watch(watch::Args),
|
Watch(watch::Args),
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
/// Print the version information of the CLI
|
||||||
enum Command {
|
Version {
|
||||||
Other(Vec<OsString>),
|
/// Print the version information in JSON format
|
||||||
Help,
|
#[arg(long)]
|
||||||
Version { json: bool },
|
json: bool,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[command(external_subcommand)]
|
||||||
|
External(Vec<OsString>),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
@ -113,291 +117,92 @@ fn main() {
|
||||||
if let Err(e) = radicle::io::set_file_limit(4096) {
|
if let Err(e) = radicle::io::set_file_limit(4096) {
|
||||||
log::warn!(target: "cli", "Unable to set open file limit: {e}");
|
log::warn!(target: "cli", "Unable to set open file limit: {e}");
|
||||||
}
|
}
|
||||||
match parse_args().map_err(Some).and_then(run) {
|
let CliArgs { command } = CliArgs::parse();
|
||||||
|
match run(command, term::DefaultContext) {
|
||||||
Ok(_) => process::exit(0),
|
Ok(_) => process::exit(0),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if let Some(err) = err {
|
term::error(format!("{err}"));
|
||||||
term::error(format!("rad: {err}"));
|
|
||||||
}
|
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_args() -> anyhow::Result<Command> {
|
fn write_version(as_json: bool) -> anyhow::Result<()> {
|
||||||
use lexopt::prelude::*;
|
let mut stdout = io::stdout();
|
||||||
|
if as_json {
|
||||||
let mut parser = lexopt::Parser::from_env();
|
VERSION.write_json(&mut stdout)?;
|
||||||
let mut command = None;
|
writeln!(&mut stdout)?;
|
||||||
let mut json = false;
|
Ok(())
|
||||||
|
} else {
|
||||||
while let Some(arg) = parser.next()? {
|
VERSION.write(&mut stdout)?;
|
||||||
match arg {
|
Ok(())
|
||||||
Long("json") => {
|
|
||||||
json = true;
|
|
||||||
}
|
|
||||||
Long("help") | Short('h') => {
|
|
||||||
command = Some(Command::Help);
|
|
||||||
}
|
|
||||||
Long("version") => {
|
|
||||||
command = Some(Command::Version { json: false });
|
|
||||||
}
|
|
||||||
Value(val) if command.is_none() => {
|
|
||||||
if val == *"." {
|
|
||||||
command = Some(Command::Other(vec![OsString::from("inspect")]));
|
|
||||||
} else if val == "version" {
|
|
||||||
command = Some(Command::Version { json: false });
|
|
||||||
} else {
|
|
||||||
let args = iter::once(val)
|
|
||||||
.chain(iter::from_fn(|| parser.value().ok()))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
command = Some(Command::Other(args))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => anyhow::bail!(arg.unexpected()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if let Some(Command::Version { json: j }) = &mut command {
|
|
||||||
*j = json;
|
|
||||||
}
|
|
||||||
Ok(command.unwrap_or_else(|| Command::Other(vec![])))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_help() -> anyhow::Result<()> {
|
fn run(command: Command, ctx: impl term::Context) -> Result<(), anyhow::Error> {
|
||||||
VERSION.write(&mut io::stdout())?;
|
|
||||||
println!("{DESCRIPTION}");
|
|
||||||
println!();
|
|
||||||
|
|
||||||
help::run(Default::default(), term::DefaultContext)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(command: Command) -> Result<(), Option<anyhow::Error>> {
|
|
||||||
match command {
|
match command {
|
||||||
Command::Version { json } => {
|
Command::Auth(args) => term::run_command_fn(auth::run, args, ctx),
|
||||||
let mut stdout = io::stdout();
|
Command::Block(args) => term::run_command_fn(block::run, args, ctx),
|
||||||
if json {
|
Command::Checkout(args) => term::run_command_fn(checkout::run, args, ctx),
|
||||||
VERSION
|
Command::Clean(args) => term::run_command_fn(clean::run, args, ctx),
|
||||||
.write_json(&mut stdout)
|
Command::Clone(args) => term::run_command_fn(clone::run, args, ctx),
|
||||||
.map_err(|e| Some(e.into()))?;
|
Command::Cob(args) => term::run_command_fn(cob::run, args, ctx),
|
||||||
writeln!(&mut stdout).ok();
|
Command::Config(args) => term::run_command_fn(config::run, args, ctx),
|
||||||
} else {
|
Command::Debug(args) => term::run_command_fn(debug::run, args, ctx),
|
||||||
VERSION.write(&mut stdout).map_err(|e| Some(e.into()))?;
|
Command::Follow(args) => term::run_command_fn(follow::run, args, ctx),
|
||||||
}
|
Command::Fork(args) => term::run_command_fn(fork::run, args, ctx),
|
||||||
}
|
Command::Id(args) => term::run_command_fn(id::run, args, ctx),
|
||||||
Command::Help => {
|
Command::Inbox(args) => term::run_command_fn(inbox::run, args, ctx),
|
||||||
print_help()?;
|
Command::Init(args) => term::run_command_fn(init::run, args, ctx),
|
||||||
}
|
Command::Inspect(args) => term::run_command_fn(inspect::run, args, ctx),
|
||||||
Command::Other(args) => {
|
Command::Issue(args) => term::run_command_fn(issue::run, args, ctx),
|
||||||
let exe = args.first();
|
Command::Ls(args) => term::run_command_fn(ls::run, args, ctx),
|
||||||
|
Command::Node(args) => term::run_command_fn(node::run, args, ctx),
|
||||||
|
Command::Patch(args) => term::run_command_fn(patch::run, args, ctx),
|
||||||
|
Command::Path(args) => term::run_command_fn(path::run, args, ctx),
|
||||||
|
Command::Publish(args) => term::run_command_fn(publish::run, args, ctx),
|
||||||
|
Command::Remote(args) => term::run_command_fn(remote::run, args, ctx),
|
||||||
|
Command::Seed(args) => term::run_command_fn(seed::run, args, ctx),
|
||||||
|
Command::RadSelf(args) => term::run_command_fn(rad_self::run, args, ctx),
|
||||||
|
Command::Stats(args) => term::run_command_fn(stats::run, args, ctx),
|
||||||
|
Command::Sync(args) => term::run_command_fn(sync::run, args, ctx),
|
||||||
|
Command::Unblock(args) => term::run_command_fn(unblock::run, args, ctx),
|
||||||
|
Command::Unfollow(args) => term::run_command_fn(unfollow::run, args, ctx),
|
||||||
|
Command::Unseed(args) => term::run_command_fn(unseed::run, args, ctx),
|
||||||
|
Command::Watch(args) => term::run_command_fn(watch::run, args, ctx),
|
||||||
|
Command::Version { json } => write_version(json),
|
||||||
|
Command::External(mut args) => {
|
||||||
|
let exe = args.remove(0);
|
||||||
|
|
||||||
if let Some(Some(exe)) = exe.map(|s| s.to_str()) {
|
// This command is deprecated and delegates to `git diff`.
|
||||||
run_other(exe, &args[1..])?;
|
// Even before it was deprecated, it was not printed by
|
||||||
} else {
|
// `rad -h`.
|
||||||
print_help()?;
|
//
|
||||||
|
// Since it is external, `--help` will delegate to `git diff --help`.
|
||||||
|
if exe == "diff" {
|
||||||
|
return diff::run(args);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
let exe = format!("{NAME}-{exe:?}");
|
||||||
}
|
let status = process::Command::new(&exe).args(&args).status();
|
||||||
|
|
||||||
/// Runs a `rad` command. `exe` expects the commands' name, e.g. `issue`,
|
|
||||||
/// `args` expects all other arguments.
|
|
||||||
///
|
|
||||||
/// For commands that are already migrated to `clap`, we need to parse the
|
|
||||||
/// arguments again. This needs to be done for each migrated command
|
|
||||||
/// individually, otherwise `clap` would fail to parse on an non-migrated and
|
|
||||||
/// therefore unknown command.
|
|
||||||
pub(crate) fn run_other(exe: &str, args: &[OsString]) -> Result<(), Option<anyhow::Error>> {
|
|
||||||
match exe {
|
|
||||||
"auth" => {
|
|
||||||
if let Some(Commands::Auth(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(auth::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"block" => {
|
|
||||||
if let Some(Commands::Block(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(block::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"checkout" => {
|
|
||||||
if let Some(Commands::Checkout(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(checkout::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"clone" => {
|
|
||||||
if let Some(Commands::Clone(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(clone::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"cob" => {
|
|
||||||
if let Some(Commands::Cob(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(cob::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"config" => {
|
|
||||||
if let Some(Commands::Config(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(config::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"diff" => {
|
|
||||||
if let Some(Commands::Diff(mut args)) = CliArgs::parse().command {
|
|
||||||
debug_assert_eq!(args[0], "diff");
|
|
||||||
args.remove(0);
|
|
||||||
return diff::run(args).map_err(Some);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"debug" => {
|
|
||||||
if let Some(Commands::Debug(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(debug::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"follow" => {
|
|
||||||
if let Some(Commands::Follow(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(follow::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"fork" => {
|
|
||||||
if let Some(Commands::Fork(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(fork::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"help" => {
|
|
||||||
term::run_command_args::<help::Options, _>(help::HELP, help::run, args.to_vec());
|
|
||||||
}
|
|
||||||
"id" => {
|
|
||||||
if let Some(Commands::Id(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(id::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"inbox" => {
|
|
||||||
if let Some(Commands::Inbox(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(inbox::run, args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"init" => {
|
|
||||||
if let Some(Commands::Init(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(init::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"inspect" => {
|
|
||||||
let reconstructed_args = {
|
|
||||||
// This is a horrible workaround to reconstruct the original
|
|
||||||
// args after having them mangled by our `lexopt`-style parser
|
|
||||||
// in `parse_args()` in case they were `rad .`.
|
|
||||||
// TODO: Remove this, when `rad` is fully migrated to `clap`.
|
|
||||||
vec!["rad", "inspect"]
|
|
||||||
.into_iter()
|
|
||||||
.map(OsString::from)
|
|
||||||
.chain(args.iter().cloned())
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(Commands::Inspect(args)) = CliArgs::parse_from(reconstructed_args).command {
|
|
||||||
term::run_command_fn(inspect::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"issue" => {
|
|
||||||
if let Some(Commands::Issue(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(issue::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"ls" => {
|
|
||||||
if let Some(Commands::Ls(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(ls::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"node" => {
|
|
||||||
if let Some(Commands::Node(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(node::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"patch" => {
|
|
||||||
if let Some(Commands::Patch(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(patch::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"path" => {
|
|
||||||
if let Some(Commands::Path(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(path::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"publish" => {
|
|
||||||
if let Some(Commands::Publish(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(publish::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"clean" => {
|
|
||||||
if let Some(Commands::Clean(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(clean::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"self" => {
|
|
||||||
if let Some(Commands::RadSelf(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(rad_self::run, args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"sync" => {
|
|
||||||
if let Some(Commands::Sync(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(sync::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"seed" => {
|
|
||||||
if let Some(Commands::Seed(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(seed::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"unblock" => {
|
|
||||||
if let Some(Commands::Unblock(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(unblock::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"unfollow" => {
|
|
||||||
if let Some(Commands::Unfollow(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(unfollow::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"unseed" => {
|
|
||||||
if let Some(Commands::Unseed(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(unseed::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"remote" => {
|
|
||||||
if let Some(Commands::Remote(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(remote::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"stats" => {
|
|
||||||
if let Some(Commands::Stats(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(stats::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"watch" => {
|
|
||||||
if let Some(Commands::Watch(args)) = CliArgs::parse().command {
|
|
||||||
term::run_command_fn(watch::run, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
other => {
|
|
||||||
let exe = format!("{NAME}-{exe}");
|
|
||||||
let status = process::Command::new(exe).args(args).status();
|
|
||||||
|
|
||||||
match status {
|
match status {
|
||||||
Ok(status) => {
|
Ok(status) => {
|
||||||
if !status.success() {
|
if !status.success() {
|
||||||
return Err(None);
|
return Err(anyhow!("`{exe}` exited with an error."));
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if let ErrorKind::NotFound = err.kind() {
|
if let ErrorKind::NotFound = err.kind() {
|
||||||
return Err(Some(anyhow!(
|
Err(anyhow!(
|
||||||
"`{other}` is not a command. See `rad --help` for a list of commands.",
|
"`{exe}` is not a command. See `rad --help` for a list of commands.",
|
||||||
)));
|
))
|
||||||
} else {
|
} else {
|
||||||
return Err(Some(err.into()));
|
Err(err.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,11 +57,12 @@ where
|
||||||
|
|
||||||
/// Execute a function `cmd` that runs a command with parsed the `args`
|
/// Execute a function `cmd` that runs a command with parsed the `args`
|
||||||
/// and a default context.
|
/// and a default context.
|
||||||
pub fn run_command_fn<F, P: Parser>(cmd: F, args: P) -> !
|
pub fn run_command_fn<F, P: Parser, C>(cmd: F, args: P, ctx: C) -> !
|
||||||
where
|
where
|
||||||
F: FnOnce(P, DefaultContext) -> anyhow::Result<()>,
|
F: FnOnce(P, C) -> anyhow::Result<()>,
|
||||||
|
C: Context,
|
||||||
{
|
{
|
||||||
match cmd(args, DefaultContext) {
|
match cmd(args, ctx) {
|
||||||
Ok(()) => process::exit(0),
|
Ok(()) => process::exit(0),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
// First parameter is not used and can just be empty.
|
// First parameter is not used and can just be empty.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue