Sebastian Thielthanks clippy9e046853 years agoHistory
131 lines · 4.4 KB · Rust
RawDownload
use std::process::Stdio; use crate::{client::blocking_io, Protocol}; /// The error used in [`connect()`].#[derive(Debug, thiserror::Error)]#[allow(missing_docs)]pub enum Error {    #[error("The scheme in \"{}\" is not usable for an ssh connection", .0.to_bstring())]    UnsupportedScheme(git_url::Url),} impl crate::IsSpuriousError for Error {} /// The kind of SSH programs we have built-in support for.////// Various different programs exists with different capabilities, and we have a few built in.#[derive(Debug, Copy, Clone, Eq, PartialEq)]pub enum ProgramKind {    /// The standard linux ssh program    Ssh,    /// The `(plink|putty).exe` binaries, typically only on windows.    Plink,    /// The `putty.exe` binary, typically only on windows.    Putty,    /// The `tortoiseplink.exe` binary, only on windows.    TortoisePlink,    /// A minimal ssh client that supports on options.    Simple,} mod program_kind; ///pub mod invocation {    use std::ffi::OsString;     /// The error returned when producing ssh invocation arguments based on a selected invocation kind.    #[derive(Debug, thiserror::Error)]    #[error("The 'Simple' ssh variant doesn't support {function}")]    pub struct Error {        /// The simple command that should have been invoked.        pub command: OsString,        /// The function that was unsupported        pub function: &'static str,    }} ///pub mod connect {    use std::ffi::{OsStr, OsString};     use crate::client::ssh::ProgramKind;     /// The options for use when [connecting][super::connect()] via the `ssh` protocol.    #[derive(Debug, Clone, Default)]    pub struct Options {        /// The program or script to use.        /// If unset, it defaults to `ssh` or `ssh.exe`, or the program implied by `kind` if that one is set.        pub command: Option<OsString>,        /// If `true`, a shell must not be used to execute `command`.        /// This defaults to `false`, and a shell can then be used if `command` seems to require it, but won't be        /// used unnecessarily.        pub disallow_shell: bool,        /// The ssh variant further identifying `program`. This determines which arguments will be used        /// when invoking the program.        /// If unset, the `program` basename determines the variant, or an invocation of the `command` itself.        pub kind: Option<ProgramKind>,    }     impl Options {        /// Return the configured ssh command, defaulting to `ssh` if neither the `command` nor the `kind` fields are set.        pub fn ssh_command(&self) -> &OsStr {            self.command                .as_deref()                .or_else(|| self.kind.and_then(|kind| kind.exe()))                .unwrap_or_else(|| OsStr::new("ssh"))        }    }} /// Connect to `host` using the ssh program to obtain data from the repository at `path` on the remote.////// The optional `user` identifies the user's account to which to connect, while `port` allows to specify non-standard/// ssh ports.////// The `desired_version` is the preferred protocol version when establishing the connection, but note that it can be/// downgraded by servers not supporting it.pub fn connect(    url: git_url::Url,    desired_version: Protocol,    options: connect::Options,) -> Result<blocking_io::file::SpawnProcessOnDemand, Error> {    if url.scheme != git_url::Scheme::Ssh || url.host().is_none() {        return Err(Error::UnsupportedScheme(url));    }    let ssh_cmd = options.ssh_command();    let mut kind = options.kind.unwrap_or_else(|| ProgramKind::from(ssh_cmd));    if options.kind.is_none() && kind == ProgramKind::Simple {        kind = if std::process::Command::from(            git_command::prepare(ssh_cmd)                .stderr(Stdio::null())                .stdout(Stdio::null())                .stdin(Stdio::null())                .with_shell()                .arg("-G")                .arg(url.host().expect("always set for ssh urls")),        )        .status()        .ok()        .map_or(false, |status| status.success())        {            ProgramKind::Ssh        } else {            ProgramKind::Simple        };    }     let path = git_url::expand_path::for_shell(url.path.clone());    Ok(blocking_io::file::SpawnProcessOnDemand::new_ssh(        url,        ssh_cmd,        path,        kind,        options.disallow_shell,        desired_version,    ))} #[cfg(test)]mod tests;