use serde::Deserialize;
use std::env;
use std::error::Error;
use std::fs::read_to_string;
#[cfg(any(target_os = "windows", target_os = "macos"))]
use std::{
fmt::{Display, Formatter},
path::Path,
process,
};
#[derive(Debug)]
#[cfg(any(target_os = "windows", target_os = "macos"))]
pub(crate) enum BuildError {
FileMaker,
Bundle,
}
#[cfg(any(target_os = "windows", target_os = "macos"))]
impl Display for BuildError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}
#[cfg(any(target_os = "windows", target_os = "macos"))]
impl Error for BuildError {}
#[derive(Deserialize, Debug)]
pub(crate) struct Config {
pub(crate) filemaker: FileMaker,
pub(crate) plugin: Plugin,
pub(crate) log: Log,
pub(crate) code_signing: CodeSigning,
}
#[derive(Deserialize, Debug)]
pub(crate) struct FileMaker {
pub(crate) ext_path: Option<String>,
pub(crate) bin_path: Option<String>,
pub(crate) launch: bool,
pub(crate) kill: bool,
}
#[derive(Deserialize, Debug)]
pub(crate) struct Plugin {
pub(crate) name: String,
pub(crate) bundle: bool,
pub(crate) move_to_ext: bool,
}
#[derive(Deserialize, Debug)]
pub(crate) struct CodeSigning {
pub(crate) sign: bool,
pub(crate) windows: SignWindows,
pub(crate) macos: SignMacOs,
}
#[derive(Deserialize, Debug)]
pub(crate) struct SignWindows {
pub(crate) signtool_path: String,
pub(crate) cert_path: String,
pub(crate) cert_pass: String,
pub(crate) timestamp_url: String,
}
#[derive(Deserialize, Debug)]
pub(crate) struct SignMacOs {
pub(crate) identity: String,
}
#[derive(Deserialize, Debug)]
pub(crate) struct Log {
pub(crate) path: Option<String>,
pub(crate) clear_on_launch: bool,
}
pub(crate) fn read_config() -> Result<Config, Box<dyn Error>> {
let current_dir = env::current_dir().unwrap();
let mut config_path = current_dir.join("config.toml");
if !config_path.is_file() {
for entry in current_dir.read_dir()? {
if let Ok(f) = entry {
if f.file_type()?.is_dir() {
let test_path = current_dir.join(f.file_name()).join("config.toml");
if test_path.is_file() {
config_path = test_path;
break;
}
}
}
}
}
let contents = read_to_string(&config_path)
.map_err(|e| format!("config read failed. path: {:?}, error: {}", config_path, e))?;
let config: Config = toml::from_str(&contents)?;
Ok(config)
}
#[cfg(any(target_os = "windows", target_os = "macos"))]
pub fn kill_filemaker() -> Result<(), Box<dyn Error>> {
if let Ok(profile) = env::var("PROFILE") {
if profile == "release" {
let config = read_config()?;
kill_filemaker_command(&config)?;
}
}
Ok(())
}
#[cfg(target_os = "linux")]
pub fn kill_filemaker() -> Result<(), Box<dyn Error>> {
Ok(())
}
#[cfg(target_os = "windows")]
fn kill_filemaker_command(config: &Config) -> Result<(), Box<dyn Error>> {
if !config.filemaker.kill {
return Ok(());
}
let app_path = Path::new(config.filemaker.bin_path.as_ref().unwrap());
let app = app_path.file_name().ok_or(BuildError::FileMaker)?;
process::Command::new("taskkill")
.arg("/IM")
.arg(app)
.arg("/F")
.spawn()?;
Ok(())
}
#[cfg(target_os = "macos")]
fn kill_filemaker_command(config: &Config) -> Result<(), Box<dyn Error>> {
if !config.filemaker.kill {
return Ok(());
}
let app_path = Path::new(config.filemaker.bin_path.as_ref().unwrap());
let app = app_path.file_stem().ok_or(BuildError::FileMaker)?;
process::Command::new("pkill").arg(app).spawn().ok();
Ok(())
}