use std::{
io,
process::{Command, ExitStatus, Stdio},
};
use thiserror::Error;
use crate::wizard::keyring::TokenBroker;
#[derive(Debug, Error)]
pub enum OrtieSignInError {
#[error("Cannot find ortie on PATH")]
NotInstalled,
#[error("Cannot send ortie output to stderr")]
Stderr(#[source] io::Error),
#[error("Cannot run {command}")]
Spawn {
command: &'static str,
#[source]
err: io::Error,
},
#[error("Cannot sign in through {command}, {status}")]
Failed {
command: &'static str,
status: ExitStatus,
},
}
pub fn sign_in(
input: &str,
name: &str,
services: &[&str],
) -> Result<Vec<String>, OrtieSignInError> {
if !TokenBroker::Ortie.installed() {
return Err(OrtieSignInError::NotInstalled);
}
run("ortie configure", &configure_args(input, name, services))?;
run("ortie auth get", &["auth", "get", "-a", name])?;
Ok(TokenBroker::Ortie.read_command(name))
}
fn configure_args<'a>(input: &'a str, name: &'a str, services: &[&'a str]) -> Vec<&'a str> {
let mut args = vec!["configure", "--name", name];
for service in services {
args.push("--service");
args.push(service);
}
args.push("--");
args.push(input);
args
}
fn run(command: &'static str, args: &[&str]) -> Result<(), OrtieSignInError> {
let stdout = stderr_copy().map_err(OrtieSignInError::Stderr)?;
let status = Command::new("ortie")
.args(args)
.stdout(stdout)
.status()
.map_err(|err| OrtieSignInError::Spawn { command, err })?;
if !status.success() {
return Err(OrtieSignInError::Failed { command, status });
}
Ok(())
}
#[cfg(unix)]
fn stderr_copy() -> io::Result<Stdio> {
use std::os::fd::AsFd;
let fd = io::stderr().as_fd().try_clone_to_owned()?;
Ok(Stdio::from(fd))
}
#[cfg(windows)]
fn stderr_copy() -> io::Result<Stdio> {
use std::os::windows::io::AsHandle;
let handle = io::stderr().as_handle().try_clone_to_owned()?;
Ok(Stdio::from(handle))
}
#[cfg(test)]
mod tests {
use crate::wizard::ortie::*;
#[test]
fn configure_names_the_account_and_each_service_before_the_input() {
assert_eq!(
configure_args("jane@example.org", "example", &["imap", "smtp"]),
[
"configure",
"--name",
"example",
"--service",
"imap",
"--service",
"smtp",
"--",
"jane@example.org"
],
);
assert_eq!(
configure_args("-h", "example", &[]),
["configure", "--name", "example", "--", "-h"],
);
}
}