Skip to content

Commit 9255ccc

Browse files
committed
Factor client feature check from connect to helpers
This creates two helper functions and moves the logic for the SSH client feature check (determining the `ProgramKind`) to them. Further refactoring is possible, especially since some of the use of mutability might be replaceable by early return with no loss of readability. But for now this maintains the preexisting structure of the code covering the case where it is not necessary to pre-run the SSH client.
1 parent a445b72 commit 9255ccc

File tree

1 file changed

+50
-33
lines changed
  • gix-transport/src/client/blocking_io/ssh

1 file changed

+50
-33
lines changed

gix-transport/src/client/blocking_io/ssh/mod.rs

Lines changed: 50 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
use std::process::Stdio;
1+
use std::{
2+
ffi::OsStr,
3+
process::{Command, Stdio},
4+
};
25

3-
use gix_url::ArgumentSafety::*;
6+
use gix_url::{ArgumentSafety::*, Url};
47

5-
use crate::{client::blocking_io, Protocol};
8+
use crate::{
9+
client::{self, blocking_io::file::SpawnProcessOnDemand},
10+
Protocol,
11+
};
612

713
/// The error used in [`connect()`].
814
#[derive(Debug, thiserror::Error)]
@@ -100,44 +106,18 @@ pub mod connect {
100106
/// If `trace` is `true`, all packetlines received or sent will be passed to the facilities of the `gix-trace` crate.
101107
#[allow(clippy::result_large_err)]
102108
pub fn connect(
103-
url: gix_url::Url,
109+
url: Url,
104110
desired_version: Protocol,
105111
options: connect::Options,
106112
trace: bool,
107-
) -> Result<blocking_io::file::SpawnProcessOnDemand, Error> {
113+
) -> Result<SpawnProcessOnDemand, Error> {
108114
if url.scheme != gix_url::Scheme::Ssh || url.host().is_none() {
109115
return Err(Error::UnsupportedScheme(url));
110116
}
111117
let ssh_cmd = options.ssh_command();
112-
let mut kind = options.kind.unwrap_or_else(|| ProgramKind::from(ssh_cmd));
113-
if options.kind.is_none() && kind == ProgramKind::Simple {
114-
let mut cmd = std::process::Command::from({
115-
let mut prepare = gix_command::prepare(ssh_cmd)
116-
.stderr(Stdio::null())
117-
.stdout(Stdio::null())
118-
.stdin(Stdio::null())
119-
.command_may_be_shell_script()
120-
.arg("-G")
121-
.arg(match url.host_as_argument() {
122-
Usable(host) => host,
123-
Dangerous(host) => Err(Error::AmbiguousHostName { host: host.into() })?,
124-
Absent => panic!("BUG: host should always be present in SSH URLs"),
125-
});
126-
if options.disallow_shell {
127-
prepare.use_shell = false;
128-
}
129-
prepare
130-
});
131-
gix_features::trace::debug!(cmd = ?cmd, "invoking `ssh` for feature check");
132-
kind = if cmd.status().ok().is_some_and(|status| status.success()) {
133-
ProgramKind::Ssh
134-
} else {
135-
ProgramKind::Simple
136-
};
137-
}
138-
118+
let kind = determine_client_kind(options.kind, ssh_cmd, &url, options.disallow_shell)?;
139119
let path = gix_url::expand_path::for_shell(url.path.clone());
140-
Ok(blocking_io::file::SpawnProcessOnDemand::new_ssh(
120+
Ok(SpawnProcessOnDemand::new_ssh(
141121
url,
142122
ssh_cmd,
143123
path,
@@ -148,5 +128,42 @@ pub fn connect(
148128
))
149129
}
150130

131+
fn determine_client_kind(
132+
known_kind: Option<ProgramKind>,
133+
ssh_cmd: &OsStr,
134+
url: &Url,
135+
disallow_shell: bool,
136+
) -> Result<ProgramKind, Error> {
137+
let mut kind = known_kind.unwrap_or_else(|| ProgramKind::from(ssh_cmd));
138+
if known_kind.is_none() && kind == ProgramKind::Simple {
139+
let mut cmd = build_client_feature_check_command(ssh_cmd, url, disallow_shell)?;
140+
gix_features::trace::debug!(cmd = ?cmd, "invoking `ssh` for feature check");
141+
kind = if cmd.status().ok().is_some_and(|status| status.success()) {
142+
ProgramKind::Ssh
143+
} else {
144+
ProgramKind::Simple
145+
};
146+
}
147+
Ok(kind)
148+
}
149+
150+
fn build_client_feature_check_command(ssh_cmd: &OsStr, url: &Url, disallow_shell: bool) -> Result<Command, Error> {
151+
let mut prepare = gix_command::prepare(ssh_cmd)
152+
.stderr(Stdio::null())
153+
.stdout(Stdio::null())
154+
.stdin(Stdio::null())
155+
.command_may_be_shell_script()
156+
.arg("-G")
157+
.arg(match url.host_as_argument() {
158+
Usable(host) => host,
159+
Dangerous(host) => Err(Error::AmbiguousHostName { host: host.into() })?,
160+
Absent => panic!("BUG: host should always be present in SSH URLs"),
161+
});
162+
if disallow_shell {
163+
prepare.use_shell = false;
164+
}
165+
Ok(prepare.into())
166+
}
167+
151168
#[cfg(test)]
152169
mod tests;

0 commit comments

Comments
 (0)