diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c84ef38..f75fe53 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -177,6 +177,7 @@ jobs: LINUX64_MUSL: linux64-musl LINUX64_MUSL_BIN: distant-linux64-musl steps: + - uses: actions/checkout@v2 - uses: actions/download-artifact@v2 - name: Generate MacOS SHA256 checksums run: | @@ -203,6 +204,7 @@ jobs: run: | TAG_NAME=${{ github.ref }} echo "TAG_NAME=${TAG_NAME#refs/tags/}" >> $GITHUB_ENV + echo "TAG_VERSION=${TAG_NAME#refs/tags/v}" >> $GITHUB_ENV - name: Check git tag for pre-release id: check-tag run: | @@ -212,6 +214,12 @@ jobs: - name: Print pre-release status run: | echo "Is ${{ github.ref }} a pre-release: ${{ steps.check-tag.outputs.match }}" + - name: Get Changelog Entry + id: changelog + uses: mindsers/changelog-reader-action@v2 + with: + version: ${{ env.TAG_VERSION }} + path: "./CHANGELOG.md" - name: Publish uses: softprops/action-gh-release@v1 with: @@ -227,6 +235,8 @@ jobs: ${{ env.LINUX64_MUSL }}/${{ env.LINUX64_MUSL_BIN }} **/*.sha256sum body: | + ## Release Notes + ${{ steps.changelog.outputs.changes }} ## Binaries Standalone binaries are built out for Windows (x86_64), MacOS (Intel & ARM), and Linux (x86_64). - **linux64-gnu** is the x86-64 release on Linux using libc diff --git a/CHANGELOG.md b/CHANGELOG.md index 21cc761..c6617e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed ### Removed +## [0.16.3] - 2022-05-29 +### Added +- New `--ssh-backend` option for CLI that accepts `libssh` or `ssh2` for + native backend ssh support +- `distant_ssh2::SshBackend` now supports parsing from a `&str` and producing a + `&'static str` from an instance + ## [0.16.2] - 2022-05-27 ### Changed - The following fields now default to false when missing in JSON request body diff --git a/Cargo.lock b/Cargo.lock index b9dcd63..4c52f24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -539,7 +539,7 @@ dependencies = [ [[package]] name = "distant" -version = "0.16.2" +version = "0.16.3" dependencies = [ "assert_cmd", "assert_fs", @@ -567,7 +567,7 @@ dependencies = [ [[package]] name = "distant-core" -version = "0.16.2" +version = "0.16.3" dependencies = [ "assert_fs", "bitflags", @@ -596,7 +596,7 @@ dependencies = [ [[package]] name = "distant-ssh2" -version = "0.16.2" +version = "0.16.3" dependencies = [ "assert_cmd", "assert_fs", diff --git a/Cargo.toml b/Cargo.toml index b549ef7..a885e56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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.16.2" +version = "0.16.3" authors = ["Chip Senkbeil "] edition = "2018" homepage = "https://github.com/chipsenkbeil/distant" @@ -26,7 +26,7 @@ ssh2 = ["distant-ssh2/ssh2"] [dependencies] derive_more = { version = "0.99.16", default-features = false, features = ["display", "from", "error", "is_variant"] } -distant-core = { version = "=0.16.2", path = "distant-core", features = ["structopt"] } +distant-core = { version = "=0.16.3", path = "distant-core", features = ["structopt"] } flexi_logger = "0.18.0" indoc = "1.0.3" log = "0.4.14" @@ -43,7 +43,7 @@ termwiz = "0.15.0" whoami = "1.1.2" # Optional native SSH functionality -distant-ssh2 = { version = "=0.16.2", path = "distant-ssh2", default-features = false, features = ["serde"], optional = true } +distant-ssh2 = { version = "=0.16.3", path = "distant-ssh2", default-features = false, features = ["serde"], optional = true } [target.'cfg(unix)'.dependencies] fork = "0.1.18" diff --git a/distant-core/Cargo.toml b/distant-core/Cargo.toml index 44b66c5..9365b2b 100644 --- a/distant-core/Cargo.toml +++ b/distant-core/Cargo.toml @@ -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.16.2" +version = "0.16.3" authors = ["Chip Senkbeil "] edition = "2018" homepage = "https://github.com/chipsenkbeil/distant" diff --git a/distant-ssh2/Cargo.toml b/distant-ssh2/Cargo.toml index 453da0e..48400e4 100644 --- a/distant-ssh2/Cargo.toml +++ b/distant-ssh2/Cargo.toml @@ -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.16.2" +version = "0.16.3" authors = ["Chip Senkbeil "] edition = "2018" homepage = "https://github.com/chipsenkbeil/distant" @@ -17,7 +17,7 @@ ssh2 = ["wezterm-ssh/ssh2", "wezterm-ssh/vendored-openssl-ssh2"] [dependencies] async-compat = "0.2.1" -distant-core = { version = "=0.16.2", path = "../distant-core" } +distant-core = { version = "=0.16.3", path = "../distant-core" } futures = "0.3.16" log = "0.4.14" rand = { version = "0.8.4", features = ["getrandom"] } diff --git a/distant-ssh2/src/lib.rs b/distant-ssh2/src/lib.rs index 3534a3f..5f13a1d 100644 --- a/distant-ssh2/src/lib.rs +++ b/distant-ssh2/src/lib.rs @@ -1,3 +1,6 @@ +#[cfg(not(any(feature = "libssh", feature = "ssh2")))] +compile_error!("Either feature \"libssh\" or \"ssh2\" must be enabled for this crate."); + use async_compat::CompatExt; use distant_core::{ Request, Session, SessionChannelExt, SessionDetails, SessionInfo, Transport, @@ -11,6 +14,7 @@ use std::{ io::{self, Write}, net::{IpAddr, SocketAddr}, path::PathBuf, + str::FromStr, sync::Arc, time::Duration, }; @@ -26,26 +30,67 @@ mod process; #[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))] pub enum SshBackend { /// Use libssh as backend + #[cfg(feature = "libssh")] LibSsh, /// Use ssh2 as backend + #[cfg(feature = "ssh2")] Ssh2, } +impl SshBackend { + pub fn as_static_str(&self) -> &'static str { + match self { + #[cfg(feature = "libssh")] + Self::LibSsh => "libssh", + + #[cfg(feature = "ssh2")] + Self::Ssh2 => "ssh2", + } + } +} + impl Default for SshBackend { - /// Defaults to ssh2 + /// Defaults to ssh2 if enabled, otherwise uses libssh by default /// /// NOTE: There are currently bugs in libssh that cause our implementation to hang related to /// process stdout/stderr and maybe other logic. fn default() -> Self { - Self::Ssh2 + #[cfg(feature = "ssh2")] + { + Self::Ssh2 + } + + #[cfg(not(feature = "ssh2"))] + { + Self::LibSsh + } + } +} + +impl FromStr for SshBackend { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + match s { + #[cfg(feature = "ssh2")] + s if s.trim().eq_ignore_ascii_case("ssh2") => Ok(Self::Ssh2), + + #[cfg(feature = "libssh")] + s if s.trim().eq_ignore_ascii_case("libssh") => Ok(Self::LibSsh), + + _ => Err("SSH backend must be \"libssh\" or \"ssh2\""), + } } } impl fmt::Display for SshBackend { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { + #[cfg(feature = "libssh")] Self::LibSsh => write!(f, "libssh"), + + #[cfg(feature = "ssh2")] Self::Ssh2 => write!(f, "ssh2"), } } diff --git a/src/opt.rs b/src/opt.rs index b520732..9537287 100644 --- a/src/opt.rs +++ b/src/opt.rs @@ -202,7 +202,7 @@ pub enum Method { Distant, /// Connect to an SSH server running on a remote machine - #[cfg(feature = "ssh2")] + #[cfg(any(feature = "libssh", feature = "ssh2"))] Ssh, } @@ -504,6 +504,11 @@ pub struct LaunchSubcommand { #[structopt(long, default_value = "ssh")] pub ssh: String, + /// If using native ssh integration, represents the backend + #[cfg(any(feature = "libssh", feature = "ssh2"))] + #[structopt(long, default_value = distant_ssh2::SshBackend::default().as_static_str())] + pub ssh_backend: distant_ssh2::SshBackend, + /// If specified, will use the external ssh program to launch the server /// instead of the native integration; does nothing if the ssh2 feature is /// not enabled as there is no other option than external ssh diff --git a/src/subcommand/launch.rs b/src/subcommand/launch.rs index caae9ed..0f1436d 100644 --- a/src/subcommand/launch.rs +++ b/src/subcommand/launch.rs @@ -192,21 +192,21 @@ async fn socket_loop( } async fn spawn_remote_server(cmd: LaunchSubcommand, opt: CommonOpt) -> Result { - #[cfg(feature = "ssh2")] + #[cfg(any(feature = "libssh", feature = "ssh2"))] if cmd.external_ssh { external_spawn_remote_server(cmd, opt).await } else { native_spawn_remote_server(cmd, opt).await } - #[cfg(not(feature = "ssh2"))] + #[cfg(not(any(feature = "libssh", feature = "ssh2")))] external_spawn_remote_server(cmd, opt).await } /// Spawns a remote server using native ssh library that listens for requests /// /// Returns the session associated with the server -#[cfg(feature = "ssh2")] +#[cfg(any(feature = "libssh", feature = "ssh2"))] async fn native_spawn_remote_server( cmd: LaunchSubcommand, _opt: CommonOpt, @@ -223,6 +223,7 @@ async fn native_spawn_remote_server( if let Some(path) = cmd.identity_file { opts.identity_files.push(path); } + opts.backend = cmd.ssh_backend; opts.port = Some(cmd.port); opts.user = Some(cmd.username); diff --git a/src/subcommand/mod.rs b/src/subcommand/mod.rs index cddb2d2..c9c970a 100644 --- a/src/subcommand/mod.rs +++ b/src/subcommand/mod.rs @@ -47,7 +47,7 @@ impl CommandRunner { } = self; let (session, lsp_data) = match method { - #[cfg(feature = "ssh2")] + #[cfg(any(feature = "libssh", feature = "ssh2"))] Method::Ssh => { use distant_ssh2::{Ssh2Session, Ssh2SessionOpts}; let SshConnectionOpts { host, port, user } = ssh_connection;