usable backend for terminal launch

This commit is contained in:
Joseph Montanaro
2023-08-03 16:35:15 -07:00
parent 89bc74e644
commit 890f715388
5 changed files with 103 additions and 77 deletions

View File

@ -3,39 +3,25 @@ use std::process::Command;
use tauri::Manager;
use crate::app::APP;
use crate::config::TermConfig;
use crate::credentials::Session;
use crate::errors::*;
use crate::state::AppState;
pub async fn launch(use_base: bool) -> Result<(), ExecError> {
// we may have multiple candidates, because we might be on unix and
// we don't have a good way of detecting for sure what default to use
pub async fn launch(use_base: bool) -> Result<(), LaunchError> {
let state = APP.get().unwrap().state::<AppState>();
let config = state.config.read().await;
let _ = match config.terminal {
Some(ref term) => launch_term(term, use_base).await,
None => launch_default(use_base).await,
}?;
Ok(())
}
async fn launch_term(term: &TermConfig, use_base: bool) -> Result<(), std::io::Error> {
// do all this in a block so we don't hold the lock any longer than necessary
let mut cmd = Command::new(&term.exec);
cmd.args(&term.args);
let mut cmd = {
let config = state.config.read().await;
let mut cmd = Command::new(&config.terminal.exec);
cmd.args(&config.terminal.args);
cmd
};
// similarly
{
// note: if called from launch(), there is already a lock being held on state.config
// don't read that here or we will deadlock
let state = APP.get().unwrap().state::<AppState>();
let app_session = state.session.read().await;
let (base_creds, session_creds) = match *app_session {
Session::Locked(_) | Session::Empty => todo!(),
Session::Unlocked{ref base, ref session} => (base, session),
};
let (base_creds, session_creds) = app_session.try_get()?;
if use_base {
cmd.env("AWS_ACCESS_KEY_ID", &base_creds.access_key_id);
cmd.env("AWS_SECRET_ACCESS_KEY", &base_creds.secret_access_key);
@ -47,51 +33,16 @@ async fn launch_term(term: &TermConfig, use_base: bool) -> Result<(), std::io::E
}
}
let _ = cmd.spawn()?;
Ok(())
}
async fn launch_default(use_base: bool) -> Result<(), std::io::Error> {
let defaults = default_terms();
let last_idx = defaults.len() - 1;
for (i, candidate) in defaults.iter().enumerate() {
match launch_term(candidate, use_base).await {
Ok(_) => return Ok(()),
Err(e) => {
if std::io::ErrorKind::NotFound == e.kind() && i < last_idx {
continue;
}
return Err(e);
match cmd.spawn() {
Ok(_) => Ok(()),
Err(e) => {
use std::io::ErrorKind::*;
if let NotFound = e.kind() {
Err(LaunchError::ExeNotFound(cmd.get_program().to_owned()))
}
else {
Err(LaunchError::from(e))
}
}
}
// we only continue the loop if there are further iterations left, so this is safe
unreachable!()
}
pub fn default_terms() -> Vec<TermConfig> {
#[cfg(windows)]
return vec![
TermConfig {
name: "powershell.exe".into(),
exec: "conhost.exe".into(),
args: vec!["powershell.exe".into()]
}
];
#[cfg(unix)]
return vec![
TermConfig {
name: "gnome-terminal".into(),
exec: "gnome-terminal".into(),
args: vec![],
},
TermConfig {
name: "konsole".into(),
exec: "konsole".into(),
args: vec![],
},
];
}