Fix CLI commands with --format json not outputting errors in JSON

pull/218/head
Chip Senkbeil 10 months ago
parent eb23b4e1ad
commit 56b3b8f4f1
No known key found for this signature in database
GPG Key ID: 35EF1F8EC72A4131

@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Fixed
- CLI commands like `distant manager select` will now output errors in a JSON
format when configured to communicate using JSON
## [0.20.0-alpha.12]
### Changed

@ -17,24 +17,54 @@ mod options;
pub mod win_service;
pub use cli::Cli;
pub use options::{Options, OptionsError};
pub use options::{Format, Options, OptionsError};
/// Wrapper around a [`CliResult`] that provides [`Termination`] support
pub struct MainResult(CliResult);
/// Wrapper around a [`CliResult`] that provides [`Termination`] support and [`Format`]ing.
pub struct MainResult {
inner: CliResult,
format: Format,
}
impl MainResult {
pub const OK: MainResult = MainResult(Ok(()));
pub const OK: MainResult = MainResult {
inner: Ok(()),
format: Format::Shell,
};
/// Creates a new result that performs general shell formatting.
pub fn new(inner: CliResult) -> Self {
Self {
inner,
format: Format::Shell,
}
}
/// Converts to shell formatting for errors.
pub fn shell(self) -> Self {
Self {
inner: self.inner,
format: Format::Shell,
}
}
/// Converts to a JSON formatting for errors.
pub fn json(self) -> Self {
Self {
inner: self.inner,
format: Format::Json,
}
}
}
impl From<CliResult> for MainResult {
fn from(res: CliResult) -> Self {
Self(res)
Self::new(res)
}
}
impl From<OptionsError> for MainResult {
fn from(x: OptionsError) -> Self {
Self(match x {
Self::new(match x {
OptionsError::Config(x) => Err(CliError::Error(x)),
OptionsError::Options(x) => match x.kind() {
// --help and --version should not actually exit with an error and instead display
@ -57,13 +87,13 @@ impl From<OptionsError> for MainResult {
impl From<anyhow::Error> for MainResult {
fn from(x: anyhow::Error) -> Self {
Self(Err(CliError::Error(x)))
Self::new(Err(CliError::Error(x)))
}
}
impl From<anyhow::Result<()>> for MainResult {
fn from(res: anyhow::Result<()>) -> Self {
Self(res.map_err(CliError::Error))
Self::new(res.map_err(CliError::Error))
}
}
@ -86,12 +116,22 @@ impl CliError {
impl Termination for MainResult {
fn report(self) -> ExitCode {
match self.0 {
match self.inner {
Ok(_) => ExitCode::SUCCESS,
Err(x) => match x {
CliError::Exit(code) => ExitCode::from(code),
CliError::Error(x) => {
eprintln!("{x:?}");
match self.format {
Format::Shell => eprintln!("{x}"),
Format::Json => println!(
"{}",
serde_json::to_string(&serde_json::json!({
"type": "error",
"msg": x.to_string(),
}),)
.expect("Failed to format error to JSON")
),
}
::log::error!("{x:?}");
::log::logger().flush();
ExitCode::FAILURE

@ -1,4 +1,4 @@
use distant::{Cli, MainResult};
use distant::{Cli, Format, MainResult};
#[cfg(unix)]
fn main() -> MainResult {
@ -8,7 +8,12 @@ fn main() -> MainResult {
};
let _logger = cli.init_logger();
MainResult::from(cli.run())
let format = cli.options.command.format();
let result = MainResult::from(cli.run());
match format {
Format::Shell => result.shell(),
Format::Json => result.json(),
}
}
#[cfg(windows)]
@ -18,6 +23,7 @@ fn main() -> MainResult {
Err(x) => return MainResult::from(x),
};
let _logger = cli.init_logger();
let format = cli.options.command.format();
// If we are trying to listen as a manager, try as a service first
if cli.is_manager_listen_command() {
@ -36,5 +42,9 @@ fn main() -> MainResult {
}
// Otherwise, execute as a non-service CLI
MainResult::from(cli.run())
let result = MainResult::from(cli.run());
match format {
Format::Shell => result.shell(),
Format::Json => result.json(),
}
}

@ -281,6 +281,19 @@ pub enum DistantSubcommand {
Generate(GenerateSubcommand),
}
impl DistantSubcommand {
/// Format used by the subcommand.
#[inline]
pub fn format(&self) -> Format {
match self {
Self::Client(x) => x.format(),
Self::Manager(x) => x.format(),
Self::Server(x) => x.format(),
Self::Generate(x) => x.format(),
}
}
}
/// Subcommands for `distant client`.
#[derive(Debug, PartialEq, Subcommand, IsVariant)]
pub enum ClientSubcommand {
@ -539,6 +552,21 @@ impl ClientSubcommand {
Self::Version { network, .. } => network,
}
}
/// Format used by the subcommand.
#[inline]
pub fn format(&self) -> Format {
match self {
Self::Api { .. } => Format::Json,
Self::Connect { format, .. } => *format,
Self::FileSystem(fs) => fs.format(),
Self::Launch { format, .. } => *format,
Self::Shell { .. } => Format::Shell,
Self::Spawn { .. } => Format::Shell,
Self::SystemInfo { .. } => Format::Shell,
Self::Version { format, .. } => *format,
}
}
}
/// Subcommands for `distant fs`.
@ -936,6 +964,12 @@ impl ClientFileSystemSubcommand {
Self::Write { network, .. } => network,
}
}
/// Format used by the subcommand.
#[inline]
pub fn format(&self) -> Format {
Format::Shell
}
}
/// Subcommands for `distant generate`.
@ -960,6 +994,14 @@ pub enum GenerateSubcommand {
},
}
impl GenerateSubcommand {
/// Format used by the subcommand.
#[inline]
pub fn format(&self) -> Format {
Format::Shell
}
}
/// Subcommands for `distant manager`.
#[derive(Debug, PartialEq, Eq, Subcommand, IsVariant)]
pub enum ManagerSubcommand {
@ -1056,6 +1098,22 @@ pub enum ManagerSubcommand {
},
}
impl ManagerSubcommand {
/// Format used by the subcommand.
#[inline]
pub fn format(&self) -> Format {
match self {
Self::Select { format, .. } => *format,
Self::Service(_) => Format::Shell,
Self::Listen { .. } => Format::Shell,
Self::Capabilities { format, .. } => *format,
Self::Info { format, .. } => *format,
Self::List { format, .. } => *format,
Self::Kill { format, .. } => *format,
}
}
}
/// Subcommands for `distant manager service`.
#[derive(Debug, PartialEq, Eq, Subcommand, IsVariant)]
pub enum ManagerServiceSubcommand {
@ -1172,6 +1230,14 @@ pub enum ServerSubcommand {
},
}
impl ServerSubcommand {
/// Format used by the subcommand.
#[inline]
pub fn format(&self) -> Format {
Format::Shell
}
}
#[derive(Args, Debug, PartialEq)]
pub struct ServerListenWatchOptions {
/// If specified, will use the polling-based watcher for filesystem changes

Loading…
Cancel
Save