// Copyright 2018 astonbitecode // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. extern crate dirs; extern crate fs_extra; use std::error::Error; use std::fmt; #[allow(unused_imports)] use std::fs::{File, OpenOptions}; use std::io::prelude::*; use std::path::{Path, PathBuf}; use std::{env, fs}; use glob::glob; use java_locator; use sha2::{Digest, Sha256}; // This is the version of the jar that should be used const VERSION: &'static str = "0.18.0-SNAPSHOT"; const JAVA_FX_VERSION: &'static str = "19.0.2.1"; fn main() -> Result<(), J4rsBuildError> { let out_dir = env::var("OUT_DIR")?; let source_jar_location = format!("../java/target/j4rs-{}-jar-with-dependencies.jar", VERSION); if File::open(&source_jar_location).is_ok() { println!("cargo:rerun-if-changed={}", source_jar_location); } let target_os_res = env::var("CARGO_CFG_TARGET_OS"); let target_os = target_os_res.as_ref().map(|x| &**x).unwrap_or("unknown"); if target_os == "android" { generate_src(&out_dir)?; return Ok(()); } // Copy the needed jar files if they are available // (that is, if the build is done with the full source-code - not in crates.io) copy_jars_from_java(&source_jar_location)?; let _ = copy_jars_to_exec_directory(&out_dir)?; generate_src(&out_dir)?; if cfg!(feature = "javafx") { println!("cargo:warning=JAVAFX"); println!("cargo:rustc-env=J4RS_JAVAFX=TRUE") } Ok(()) } fn generate_src(out_dir: &str) -> Result<(), J4rsBuildError> { let dest_path = Path::new(&out_dir).join("j4rs_init.rs"); let mut f = File::create(&dest_path)?; let contents = format!( " pub(crate) fn j4rs_version() -> &'static str {{ \"{}\" }} pub(crate) fn java_fx_version() -> &'static str {{ \"{}\" }} ", VERSION, JAVA_FX_VERSION ); f.write_all(contents.as_bytes())?; Ok(()) } // Copies the jars from the `java` directory to the source directory of rust. fn copy_jars_from_java(jar_source_path: &str) -> Result<(), J4rsBuildError> { if let Ok(mut source_jar_file) = File::open(&jar_source_path) { // Find the destination file let home = env::var("CARGO_MANIFEST_DIR")?; let jassets_path_buf = Path::new(&home).join("jassets"); let jassets_path = jassets_path_buf.to_str().unwrap().to_owned(); let destination_jar_file_res = { let djpb = Path::new(&jassets_path) .join(format!("j4rs-{}-jar-with-dependencies.jar", VERSION)); File::open(djpb) }; // Copy only if the files are not the same let do_copy = if destination_jar_file_res.is_ok() { let mut destination_jar_file = destination_jar_file_res.unwrap(); !are_same_files(&mut source_jar_file, &mut destination_jar_file).unwrap_or(true) } else { true }; if do_copy { fs_extra::remove_items(vec![jassets_path.clone()].as_ref())?; let _ = fs::create_dir_all(jassets_path_buf.clone()) .map_err(|error| panic!("Cannot create dir '{:?}': {:?}", jassets_path_buf, error)); let ref options = fs_extra::dir::CopyOptions::new(); let _ = fs_extra::copy_items(vec![jar_source_path].as_ref(), jassets_path, options)?; } } Ok(()) } fn are_same_files(f1: &mut File, f2: &mut File) -> Result { let mut buffer1: Vec = Vec::new(); let mut hasher1 = Sha256::new(); let mut buffer2: Vec = Vec::new(); let mut hasher2 = Sha256::new(); f1.read_to_end(&mut buffer1)?; hasher1.update(&buffer1); let hash1 = hasher1.finalize(); f2.read_to_end(&mut buffer2)?; hasher2.update(&buffer2); let hash2 = hasher2.finalize(); Ok(hash1 == hash2) } // Copies the jars to and returns the PathBuf of the exec directory. fn copy_jars_to_exec_directory(out_dir: &str) -> Result { let mut exec_dir_path_buf = PathBuf::from(out_dir); exec_dir_path_buf.pop(); exec_dir_path_buf.pop(); exec_dir_path_buf.pop(); let jassets_output = exec_dir_path_buf.clone(); let jassets_output_dir = jassets_output.to_str().unwrap(); let home = env::var("CARGO_MANIFEST_DIR")?; let jassets_path_buf = Path::new(&home).join("jassets"); let jassets_path = jassets_path_buf.to_str().unwrap().to_owned(); let jassets_jar_file_res = { let japb = Path::new(&jassets_path).join(format!("j4rs-{}-jar-with-dependencies.jar", VERSION)); File::open(japb) }; let jassets_output_file_res = { let jaopb = Path::new(&jassets_output_dir) .join("jassets") .join(format!("j4rs-{}-jar-with-dependencies.jar", VERSION)); File::open(jaopb) }; // Delete the target jassets and copy only if the files are not the same let do_copy = if jassets_jar_file_res.is_ok() && jassets_output_file_res.is_ok() { let mut jassets_jar_file = jassets_jar_file_res.unwrap(); let mut jassets_output_jar_file = jassets_output_file_res.unwrap(); !are_same_files(&mut jassets_jar_file, &mut jassets_output_jar_file).unwrap_or(true) } else { true }; if do_copy { fs_extra::remove_items(vec![format!("{}/jassets", jassets_output_dir)].as_ref())?; let ref options = fs_extra::dir::CopyOptions::new(); let _ = fs_extra::copy_items(vec![jassets_path].as_ref(), jassets_output_dir, options)?; } let jassets_output_files = glob(format!("{}/jassets/**/*", jassets_output_dir).as_str())?; for glob_res in jassets_output_files { println!("cargo:rerun-if-changed={}", glob_res?.to_str().unwrap()); } Ok(exec_dir_path_buf) } #[derive(Debug)] struct J4rsBuildError { description: String, } impl fmt::Display for J4rsBuildError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description) } } impl Error for J4rsBuildError { fn description(&self) -> &str { self.description.as_str() } } impl From for J4rsBuildError { fn from(err: std::env::VarError) -> J4rsBuildError { J4rsBuildError { description: format!("{:?}", err), } } } impl From for J4rsBuildError { fn from(err: std::io::Error) -> J4rsBuildError { J4rsBuildError { description: format!("{:?}", err), } } } impl From for J4rsBuildError { fn from(err: java_locator::errors::JavaLocatorError) -> J4rsBuildError { J4rsBuildError { description: format!("{:?}", err), } } } impl From for J4rsBuildError { fn from(err: fs_extra::error::Error) -> J4rsBuildError { J4rsBuildError { description: format!("{:?}", err), } } } impl From for J4rsBuildError { fn from(err: glob::PatternError) -> J4rsBuildError { J4rsBuildError { description: format!("{:?}", err), } } } impl From for J4rsBuildError { fn from(err: glob::GlobError) -> J4rsBuildError { J4rsBuildError { description: format!("{:?}", err), } } }