use std::io;
use std::io::Write as _;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use ::litany::cmd::{self, Fx, Outcome, prelude};
use clap::Parser as _;
use crate::cli_outbound::{Binary, Cli};
use crate::tool_host;
use crate::ui_state::SystemClock;
use crate::world::tools;
pub(super) fn run(args: &[String]) -> i32 {
let cli = match parse(args) {
Ok(cli) => cli,
Err(code) => return code,
};
crate::world::inhabit();
cli.command.preludes().iter().for_each(|p| p());
let (driver_target, adapter_target) = match targets() {
Ok(t) => t,
Err(e) => {
let _ = writeln!(io::stderr(), "yog litany: seed world tool shims: {e}");
return 1;
}
};
let conv_branch = std::env::var_os(cmd::seam::ENV_CONV_BRANCH);
let editor_cmd = std::env::var("EDITOR").unwrap_or_else(|_| "vi".to_string());
let editor = move |dir: &Path| edit_with(&editor_cmd, dir);
let injection = tool_host::Injection::new(
crate::xdg::Env::from_env().yog_state_root(),
driver_target.clone(),
tool_host::ask::Budget::default(),
tool_host::remote::patience(),
Arc::new(SystemClock),
);
let result = {
let mut stdin = io::stdin().lock();
let mut stdout = io::stdout().lock();
let mut stderr = io::stderr().lock();
let mut fx = Fx {
driver_target,
adapter_target: Some(adapter_target),
conv_branch,
editor: &editor,
tool_stdin: &mut stdin,
tool_stdout: &mut stdout,
tool_stderr: &mut stderr,
stop: prelude::stop_flag(),
tool_injection: Some(&injection),
};
cli.command.run(&mut fx)
};
conclude(result)
}
fn parse(args: &[String]) -> Result<cmd::Cli, i32> {
let argv = std::iter::once("litany".to_owned()).chain(args.iter().cloned());
cmd::Cli::try_parse_from(argv).map_err(|e| {
let _ = e.print();
e.exit_code()
})
}
fn targets() -> io::Result<(PathBuf, PathBuf)> {
let dir = crate::world::layout(&crate::xdg::Env::from_env()).tools;
Ok((
tools::ensure_shim(&dir, tools::LITANY, &Cli::resolve(Binary::Litany))?,
tools::ensure_shim(&dir, tools::BZ, &Cli::resolve(Binary::Bz))?,
))
}
fn edit_with(editor: &str, dir: &Path) -> io::Result<()> {
let status = crate::git_env::status(
crate::git_env::command(Path::new("sh"))
.arg("-c")
.arg(format!("exec {editor} \"$1\""))
.arg("sh")
.arg(dir),
)?;
if status.success() {
Ok(())
} else {
Err(io::Error::other(format!("editor exited with {status}")))
}
}
fn conclude(result: Result<Outcome, cmd::Error>) -> i32 {
match result {
Ok(outcome) => perform(outcome),
Err(e) => {
let _ = writeln!(io::stderr(), "{e}");
1
}
}
}
fn perform(outcome: Outcome) -> i32 {
match outcome {
Outcome::Line(line) => {
let _ = writeln!(io::stdout(), "{line}");
0
}
Outcome::Quiet => 0,
Outcome::Exec(mut command) => {
let failure = crate::git_env::exec(&mut command);
let _ = writeln!(io::stderr(), "litany advance: exec successor: {failure}");
1
}
Outcome::Code(code) => i32::from(code),
}
}
#[cfg(test)]
mod tests;