use std::path::{Path, PathBuf};
use crate::cli_outbound::{Cli, Streamed, StreamedOutcome, StreamedPoll};
use crate::opslog::{self, OpEntry};
pub mod auth;
#[cfg(test)]
mod tests;
const LOGIN_FLAG: &str = "--login";
const PROVIDER_FLAG: &str = "--provider";
pub fn provider_rows(dump_config_stdout: &str) -> Vec<String> {
crate::config_edit::brazen::provider_names(dump_config_stdout)
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct LoginView {
pub lines: Vec<String>,
pub outcome: Option<i32>,
pub fallback: Option<String>,
}
pub struct LoginRun {
streamed: Streamed,
view: LoginView,
argv: Vec<String>,
state_root: PathBuf,
ts: String,
}
pub fn start(bz: &Cli, provider: &str, state_root: &Path, ts: &str) -> std::io::Result<LoginRun> {
let args = [LOGIN_FLAG, PROVIDER_FLAG, provider];
let mut argv = vec![bz.binary().display().to_string()];
argv.extend(args.iter().map(|s| (*s).to_string()));
match bz.run(&args) {
Ok(stream) => Ok(LoginRun {
streamed: Streamed::new(stream),
view: LoginView::default(),
argv,
state_root: state_root.to_path_buf(),
ts: ts.to_owned(),
}),
Err(spawn) => {
let entry =
OpEntry::synthetic_failure(ts.to_owned(), argv, String::new(), spawn.to_string());
opslog::append(state_root, &entry)?;
Err(std::io::Error::other(spawn))
}
}
}
impl LoginRun {
pub fn view(&self) -> LoginView {
self.view.clone()
}
pub fn poll(&mut self) -> bool {
if self.view.outcome.is_some() {
return false;
}
match self.streamed.poll() {
StreamedPoll::Lines(lines) => {
self.view.lines.extend(lines);
true
}
StreamedPoll::Pending => true,
StreamedPoll::Done(outcome) => {
self.finalize(outcome);
false
}
}
}
fn finalize(&mut self, outcome: StreamedOutcome) {
self.view.lines.extend(outcome.lines);
self.view.outcome = Some(outcome.exit);
if outcome.exit != 0 {
self.view.fallback = Some(self.argv.join(" "));
}
let entry = OpEntry {
ts: self.ts.clone(),
argv: self.argv.clone(),
cwd: String::new(),
exit: outcome.exit,
stdout: String::new(),
stderr: outcome.stderr,
};
let _ = opslog::append(&self.state_root, &entry);
}
#[cfg(test)]
pub(crate) fn from_streamed(streamed: Streamed, argv: Vec<String>, state_root: &Path) -> Self {
Self {
streamed,
view: LoginView::default(),
argv,
state_root: state_root.to_path_buf(),
ts: "TS".to_owned(),
}
}
}