use std::collections::HashMap;
use std::ffi::{OsString, OsStr};
use std::os::unix::prelude::OsStringExt;
use std::path::PathBuf;
use std::io::{Error, ErrorKind, Result};
use std::process::{Command, Stdio, Output};
mod with_ext;
mod boot_ext;
mod run_ext;
pub use with_ext::WineWithExt;
pub use boot_ext::WineBootExt;
pub use run_ext::WineRunExt;
pub use derive_builder::Builder;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum WineArch {
Win32,
Win64
}
impl WineArch {
#[allow(clippy::should_implement_trait)]
pub fn from_str(arch: &str) -> Option<Self> {
match arch {
"win32" | "x32" | "32" => Some(Self::Win32),
"win64" | "x64" | "64" => Some(Self::Win64),
_ => None
}
}
pub fn to_str(&self) -> &str {
match self {
Self::Win32 => "win32",
Self::Win64 => "win64"
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum WineLoader {
Current,
Default,
Custom(PathBuf)
}
impl Default for WineLoader {
fn default() -> Self {
Self::Default
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Wine {
binary: PathBuf,
pub prefix: Option<PathBuf>,
pub arch: Option<WineArch>,
pub wineboot: Option<PathBuf>,
pub wineserver: Option<PathBuf>,
pub wineloader: WineLoader
}
impl Default for Wine {
fn default() -> Self {
Self::from_binary("wine")
}
}
impl Wine {
pub fn new<T: Into<PathBuf>>(binary: T, prefix: Option<T>, arch: Option<WineArch>, wineboot: Option<T>, wineserver: Option<T>, wineloader: WineLoader) -> Self {
Wine {
binary: binary.into(),
prefix: prefix.map(|value| value.into()),
arch,
wineboot: wineboot.map(|value| value.into()),
wineserver: wineserver.map(|value| value.into()),
wineloader
}
}
pub fn from_binary<T: Into<PathBuf>>(binary: T) -> Self {
Self::new(binary, None, None, None, None, WineLoader::default())
}
pub fn version(&self) -> Result<OsString> {
let output = Command::new(&self.binary)
.arg("--version")
.stdout(Stdio::piped())
.stderr(Stdio::null())
.output()?;
Ok(OsString::from_vec(output.stdout))
}
pub fn binary(&self) -> PathBuf {
self.binary.clone()
}
fn get_inner_binary(&self, binary: &str) -> PathBuf {
if let Some(parent) = self.binary.parent() {
let binary_path = parent.join(binary);
if binary_path.exists() {
return binary_path;
}
}
PathBuf::from(binary)
}
pub fn wineboot(&self) -> PathBuf {
self.wineboot.clone().unwrap_or_else(|| self.get_inner_binary("wineboot"))
}
pub fn wineserver(&self) -> PathBuf {
self.wineserver.clone().unwrap_or_else(|| self.get_inner_binary("wineserver"))
}
pub fn wineloader(&self) -> PathBuf {
match &self.wineloader {
WineLoader::Default => PathBuf::from("wine"),
WineLoader::Current => self.binary.clone(),
WineLoader::Custom(path) => path.clone()
}
}
pub fn get_envs(&self) -> HashMap<&str, OsString> {
let mut env = HashMap::new();
if let Some(prefix) = &self.prefix {
env.insert("WINEPREFIX", prefix.as_os_str().to_os_string());
}
if let Some(arch) = self.arch {
env.insert("WINEARCH", match arch {
WineArch::Win32 => OsString::from("win32"),
WineArch::Win64 => OsString::from("win64")
});
}
if let Some(server) = &self.wineserver {
env.insert("WINESERVER", server.as_os_str().to_os_string());
}
match &self.wineloader {
WineLoader::Default => (),
WineLoader::Current => {
env.insert("WINELOADER", self.binary.as_os_str().to_os_string());
},
WineLoader::Custom(path) => {
env.insert("WINELOADER", path.as_os_str().to_os_string());
}
}
env
}
#[cfg(feature = "dxvk")]
pub fn install_dxvk<T: Into<PathBuf>>(&self, dxvk_folder: T, params: super::dxvk::InstallParams) -> Result<()> {
super::dxvk::Dxvk::install(self, dxvk_folder, params)
}
#[cfg(feature = "dxvk")]
pub fn uninstall_dxvk(&self, params: super::dxvk::InstallParams) -> Result<()> {
super::dxvk::Dxvk::uninstall(self, params)
}
}