use std::ffi::{OsStr, OsString};
use std::path::PathBuf;
use std::process::{Command, ExitStatus};
use crate::env_paths::{self, PathExt};
#[derive(Clone, Debug, Default)]
pub struct JavaRun {
java_home: Option<PathBuf>,
class_paths: Vec<OsString>,
main_class: Option<OsString>,
jar_file: Option<OsString>,
args: Vec<OsString>,
enable_preview_features: bool,
}
impl JavaRun {
pub fn new() -> Self {
Default::default()
}
pub fn run(&self) -> std::io::Result<ExitStatus> {
self.command()?.status()
}
pub fn command(&self) -> std::io::Result<Command> {
let jh_clone = self.java_home.clone();
let java_home = jh_clone
.and_then(PathExt::path_if_exists)
.or_else(env_paths::java_home)
.ok_or_else(|| std::io::Error::other(
"JAVA_HOME not provided, and could not be auto-discovered."
))?;
let mut cmd = Command::new(java_home.join("bin").join("java"));
if self.enable_preview_features {
cmd.arg("--enable-preview");
}
if !self.class_paths.is_empty() {
cmd.arg("-cp").arg(self.class_paths.join(OsStr::new(";")));
}
match (self.main_class.as_ref(), self.jar_file.as_ref()) {
(Some(main_class), None) => { cmd.arg(main_class); }
(None, Some(jar_file)) => { cmd.arg("-jar").arg(jar_file); }
(Some(_), Some(_)) => {
return Err(std::io::Error::other(
"Cannot provide both a main class AND a JAR file."
));
},
_ => { }
}
self.args.iter().for_each(|f| { cmd.arg(f); });
Ok(cmd)
}
pub fn java_home<P: AsRef<OsStr>>(&mut self, java_home: P) -> &mut Self {
self.java_home = Some(java_home.as_ref().into());
self
}
pub fn class_path<S: AsRef<OsStr>>(&mut self, class_path: S) -> &mut Self {
self.class_paths.push(class_path.as_ref().into());
self
}
pub fn enable_preview_features(&mut self, enable_preview_features: bool) -> &mut Self {
self.enable_preview_features = enable_preview_features;
self
}
pub fn main_class<S: AsRef<OsStr>>(&mut self, class: S) -> &mut Self {
self.main_class = Some(class.as_ref().into());
self
}
pub fn jar_file<P: AsRef<OsStr>>(&mut self, jar_file: P) -> &mut Self {
self.jar_file = Some(jar_file.as_ref().into());
self
}
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self {
self.args.push(arg.as_ref().into());
self
}
pub fn args<I>(&mut self, args: I) -> &mut Self
where
I: IntoIterator,
I::Item: AsRef<OsStr>,
{
self.args.extend(args.into_iter().map(|a| a.as_ref().into()));
self
}
}