Skip to content

Commit

Permalink
Fix json support for client launch/connect and add json format suppor…
Browse files Browse the repository at this point in the history
…t for client select (#118)
  • Loading branch information
chipsenkbeil authored Aug 16, 2022
1 parent dde3cb2 commit 4223c4e
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 19 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.17.1] - 2022-08-16
### Added

- New `format` option available for `client select`
- Choices are provided via `{"type": "select", "choices": ["...", ...], "current": 0}`
- Selection is specified via `{"type": "selected", "choice": 0}`

### Fixed

- `distant client launch` using `--format json` now properly prints out id in
JSON format (`{"type": "launched", "id": "..."}`)
- `distant client connect` using `--format json` now properly prints out id in
JSON format (`{"type": "connected", "id": "..."}`)

## [0.17.0] - 2022-08-09
### Added

Expand Down
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "distant"
description = "Operate on a remote computer through file and process manipulation"
categories = ["command-line-utilities"]
keywords = ["cli"]
version = "0.17.0"
version = "0.17.1"
authors = ["Chip Senkbeil <[email protected]>"]
edition = "2021"
homepage = "https://github.com/chipsenkbeil/distant"
Expand Down Expand Up @@ -32,7 +32,7 @@ clap_complete = "3.2.3"
config = { version = "0.13.2", default-features = false, features = ["toml"] }
derive_more = { version = "0.99.17", default-features = false, features = ["display", "from", "error", "is_variant"] }
dialoguer = { version = "0.10.2", default-features = false }
distant-core = { version = "=0.17.0", path = "distant-core", features = ["clap", "schemars"] }
distant-core = { version = "=0.17.1", path = "distant-core", features = ["clap", "schemars"] }
directories = "4.0.1"
flexi_logger = "0.23.0"
indoc = "1.0.7"
Expand All @@ -55,7 +55,7 @@ winsplit = "0.1.0"
whoami = "1.2.1"

# Optional native SSH functionality
distant-ssh2 = { version = "=0.17.0", path = "distant-ssh2", default-features = false, features = ["serde"], optional = true }
distant-ssh2 = { version = "=0.17.1", path = "distant-ssh2", default-features = false, features = ["serde"], optional = true }

[target.'cfg(unix)'.dependencies]
fork = "0.1.19"
Expand Down
6 changes: 3 additions & 3 deletions distant-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "distant-core"
description = "Core library for distant, enabling operation on a remote computer through file and process manipulation"
categories = ["network-programming"]
keywords = ["api", "async"]
version = "0.17.0"
version = "0.17.1"
authors = ["Chip Senkbeil <[email protected]>"]
edition = "2021"
homepage = "https://github.com/chipsenkbeil/distant"
Expand All @@ -19,11 +19,11 @@ async-trait = "0.1.57"
bitflags = "1.3.2"
bytes = "1.2.1"
derive_more = { version = "0.99.17", default-features = false, features = ["as_mut", "as_ref", "deref", "deref_mut", "display", "from", "error", "into", "into_iterator", "is_variant", "try_into"] }
distant-net = { version = "=0.17.0", path = "../distant-net" }
distant-net = { version = "=0.17.1", path = "../distant-net" }
futures = "0.3.21"
hex = "0.4.3"
log = "0.4.17"
notify = { version = "5.0.0-pre.15", features = ["serde"] }
notify = { version = "=5.0.0-pre.15", features = ["serde"] }
once_cell = "1.13.0"
portable-pty = "0.7.0"
rand = { version = "0.8.5", features = ["getrandom"] }
Expand Down
2 changes: 1 addition & 1 deletion distant-net/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "distant-net"
description = "Network library for distant, providing implementations to support client/server architecture"
categories = ["network-programming"]
keywords = ["api", "async"]
version = "0.17.0"
version = "0.17.1"
authors = ["Chip Senkbeil <[email protected]>"]
edition = "2021"
homepage = "https://github.com/chipsenkbeil/distant"
Expand Down
4 changes: 2 additions & 2 deletions distant-ssh2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "distant-ssh2"
description = "Library to enable native ssh-2 protocol for use with distant sessions"
categories = ["network-programming"]
version = "0.17.0"
version = "0.17.1"
authors = ["Chip Senkbeil <[email protected]>"]
edition = "2021"
homepage = "https://github.com/chipsenkbeil/distant"
Expand All @@ -20,7 +20,7 @@ async-compat = "0.2.1"
async-once-cell = "0.4.2"
async-trait = "0.1.57"
derive_more = { version = "0.99.17", default-features = false, features = ["display", "error"] }
distant-core = { version = "=0.17.0", path = "../distant-core" }
distant-core = { version = "=0.17.1", path = "../distant-core" }
futures = "0.3.21"
hex = "0.4.3"
log = "0.4.17"
Expand Down
85 changes: 75 additions & 10 deletions src/cli/commands/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use distant_core::{
DistantResponseData, Extra, RemoteCommand, Watcher,
};
use log::*;
use serde_json::{json, Value};
use std::{
io,
path::{Path, PathBuf},
Expand Down Expand Up @@ -178,6 +179,9 @@ pub enum ClientSubcommand {
/// Connection to use, otherwise will prompt to select
connection: Option<ConnectionId>,

#[clap(short, long, default_value_t, value_enum)]
format: Format,

#[clap(flatten)]
network: NetworkConfig,
},
Expand Down Expand Up @@ -401,7 +405,17 @@ impl ClientSubcommand {
*cache.data.selected = id;
cache.write_to_disk().await?;

println!("{}", id);
match format {
Format::Shell => println!("{}", id),
Format::Json => println!(
"{}",
serde_json::to_string(&json!({
"type": "connected",
"id": id,
}))
.unwrap()
),
}
}
Self::Launch {
config: launcher_config,
Expand Down Expand Up @@ -465,7 +479,17 @@ impl ClientSubcommand {
*cache.data.selected = id;
cache.write_to_disk().await?;

println!("{}", id);
match format {
Format::Shell => println!("{}", id),
Format::Json => println!(
"{}",
serde_json::to_string(&json!({
"type": "launched",
"id": id,
}))
.unwrap()
),
}
}
Self::Lsp {
connection,
Expand Down Expand Up @@ -583,6 +607,7 @@ impl ClientSubcommand {
}
Self::Select {
connection,
format,
network,
..
} => match connection {
Expand All @@ -608,8 +633,8 @@ impl ClientSubcommand {
)));
}

trace!("Building selection prompt of {} choices", list.len());
let selected = list
// Figure out the current selection
let current = list
.iter()
.enumerate()
.find_map(|(i, (id, _))| {
Expand All @@ -621,6 +646,7 @@ impl ClientSubcommand {
})
.unwrap_or_default();

trace!("Building selection prompt of {} choices", list.len());
let items: Vec<String> = list
.iter()
.map(|(_, destination)| {
Expand All @@ -639,12 +665,51 @@ impl ClientSubcommand {
})
.collect();

trace!("Rendering prompt");
let selected = Select::with_theme(&ColorfulTheme::default())
.items(&items)
.default(selected)
.interact_on_opt(&Term::stderr())
.context("Failed to render prompt")?;
// Prompt for a selection, with None meaning no change
let selected = match format {
Format::Shell => {
trace!("Rendering prompt");
Select::with_theme(&ColorfulTheme::default())
.items(&items)
.default(current)
.interact_on_opt(&Term::stderr())
.context("Failed to render prompt")?
}

Format::Json => {
// Print out choices
MsgSender::from_stdout()
.send_blocking(&json!({
"type": "select",
"choices": items,
"current": current,
}))
.context("Failed to send JSON choices")?;

// Wait for a response
let msg = MsgReceiver::from_stdin()
.recv_blocking::<Value>()
.context("Failed to receive JSON selection")?;

// Verify the response type is "selected"
match msg.get("type") {
Some(value) if value == "selected" => msg
.get("choice")
.and_then(|value| value.as_u64())
.map(|choice| choice as usize),
Some(value) => {
return Err(CliError::Error(anyhow::anyhow!(
"Unexpected 'type' field value: {value}"
)))
}
None => {
return Err(CliError::Error(anyhow::anyhow!(
"Missing 'type' field"
)))
}
}
}
};

match selected {
Some(index) => {
Expand Down

0 comments on commit 4223c4e

Please sign in to comment.