use crate::build::{get_hos_sdk, Context, Template};
use crate::create_dist_dir;
use anyhow::Error;
use cargo_metadata::{MetadataCommand, Package};
use sha2::{Digest, Sha256};
use std::path::PathBuf;
use std::time::SystemTime;
use std::{env, fs};
use version_compare::compare_to;
use version_compare::Cmp;
pub fn prepare(args: &mut crate::BuildArgs, ctx: &mut Context) -> anyhow::Result<()> {
ctx.pwd = env::current_dir()?;
ctx.copy_static = args.copy_static;
ctx.skip_libs = args.skip_libs;
ctx.dts_cache = args.dts_cache;
ctx.skip_check = args.skip_check;
ctx.zigbuild = args.zigbuild;
ctx.bisheng = args.bisheng;
ctx.skip_napi_check = args.skip_napi_check;
let cargo_file = ctx.pwd.join("./Cargo.toml");
let cargo_file_str = cargo_file.to_str().unwrap_or_default();
if cargo_file.try_exists().is_err() {
return Err(Error::msg(format!(
"No Rust project found in path: {}.",
cargo_file_str
)));
}
let metadata = MetadataCommand::new()
.no_deps()
.manifest_path(&cargo_file)
.exec()?;
let is_workspace = !metadata.workspace_members.is_empty();
let packages_to_build: Vec<&Package> = if is_workspace {
let all_candidates: Vec<&Package> = metadata
.workspace_members
.iter()
.filter_map(|member_id| metadata.packages.iter().find(|p| &p.id == member_id))
.filter(|p| {
ctx.skip_napi_check
|| p
.dependencies
.iter()
.any(|dep| dep.name == "napi-derive-ohos")
})
.collect();
let current_pkg = all_candidates.iter().find(|p| {
if let Some(manifest_dir) = p.manifest_path.parent() {
let pwd_canonical = ctx.pwd.canonicalize().ok();
let manifest_dir_path = PathBuf::from(manifest_dir.as_str());
let manifest_dir_canonical = manifest_dir_path.canonicalize().ok();
if let (Some(pwd), Some(md)) = (pwd_canonical, manifest_dir_canonical) {
pwd.starts_with(&md) || pwd == md
} else {
let pwd_str = ctx.pwd.to_string_lossy();
let manifest_dir_str = manifest_dir.as_str();
pwd_str.starts_with(manifest_dir_str) || pwd_str == manifest_dir_str
}
} else {
false
}
});
if let Some(pkg) = current_pkg {
if ctx.skip_napi_check
|| pkg
.dependencies
.iter()
.any(|dep| dep.name == "napi-derive-ohos")
{
vec![*pkg]
} else {
vec![]
}
} else {
all_candidates
}
} else {
let pkg = metadata
.packages
.iter()
.find(|p| {
return p.manifest_path.eq(cargo_file_str);
})
.ok_or(Error::msg("Try to get package meta-info failed."))?;
if ctx.skip_napi_check
|| pkg
.dependencies
.iter()
.any(|dep| dep.name == "napi-derive-ohos")
{
vec![pkg]
} else {
vec![]
}
};
if packages_to_build.is_empty() {
return Err(Error::msg(
"No package need to build.",
));
}
let pkg = packages_to_build[0];
let toml_content: Option<Template> = pkg
.metadata
.get("template")
.and_then(|v| serde_json::from_value(v.clone()).unwrap_or(None));
if !ctx.skip_check {
let full_metadata = MetadataCommand::new().manifest_path(&cargo_file).exec()?;
let napi_ohos_version = full_metadata
.packages
.iter()
.find(|p| p.name == "napi-ohos")
.and_then(|v| Some(v.version.to_string()))
.ok_or(Error::msg(
"Try to get the version of the napi-ohos failed.",
))?;
let napi_backend_ohos_version = full_metadata
.packages
.iter()
.find(|p| p.name == "napi-derive-ohos")
.and_then(|v| Some(v.version.to_string()))
.ok_or(Error::msg(
"Try to get the version of the napi-derive-ohos failed.",
))?;
let result = compare_to(&napi_ohos_version, "1.1.0", Cmp::Ge).unwrap_or(false);
if !result {
return Err(Error::msg(format!(
r#"The version of the napi-ohos is not >= 1.1.0, please update the napi-ohos to >= 1.1.0, the current version is {}.
If you want to skip the check, you can set the skip_check to true: ohrs build --skip-check"#,
&napi_ohos_version
)));
}
let result = compare_to(&napi_backend_ohos_version, "1.1.0", Cmp::Ge).unwrap_or(false);
if !result {
return Err(Error::msg(format!(
r#"The version of the napi-derive-ohos is not >= 1.1.0, please update the napi-derive-ohos to >= 1.1.0, the current version is {}.
If you want to skip the check, you can set the skip_check to true: ohrs build --skip-check"#,
&napi_backend_ohos_version
)));
}
}
ctx.template = toml_content;
ctx.package = Some((*pkg).clone());
ctx.workspace_packages = packages_to_build.iter().map(|p| (*p).clone()).collect();
ctx.cargo_build_target_dir = Some(metadata.target_directory.clone());
ctx.init_args = if ctx.zigbuild {
vec!["zigbuild"]
} else {
vec!["build"]
};
if let Some(cargo_args) = &args.cargo_args {
if args.release && !cargo_args.contains(&String::from("--release")) {
ctx.init_args.push("--release");
}
}
if is_workspace {
let current_pkg_dir = packages_to_build.iter().find_map(|p| {
if let Some(manifest_dir) = p.manifest_path.parent() {
let pwd_canonical = ctx.pwd.canonicalize().ok();
let manifest_dir_path = PathBuf::from(manifest_dir.as_str());
let manifest_dir_canonical = manifest_dir_path.canonicalize().ok();
if let (Some(pwd), Some(md)) = (pwd_canonical, manifest_dir_canonical) {
if pwd.starts_with(&md) || pwd == md {
Some(manifest_dir_path)
} else {
None
}
} else {
let pwd_str = ctx.pwd.to_string_lossy();
let manifest_dir_str = manifest_dir.as_str();
if pwd_str.starts_with(manifest_dir_str) || pwd_str == manifest_dir_str {
Some(manifest_dir_path)
} else {
None
}
}
} else {
None
}
});
if let Some(pkg_dir) = current_pkg_dir {
ctx.dist = pkg_dir.join(&args.dist);
} else {
ctx.dist = ctx.pwd.join(&args.dist);
}
} else {
ctx.dist = ctx.pwd.join(&args.dist);
}
create_dist_dir!(ctx.dist.clone());
let target_dir = args
.target_dir
.to_owned()
.unwrap_or(metadata.target_directory.clone().to_string());
let mut hasher = Sha256::new();
hasher.update(&pkg.manifest_path.as_str());
let hash_result = hasher.finalize();
let hash_hex = format!("{:x}", hash_result);
let short_hash = &hash_hex[..8];
let mut tmp_full_path = PathBuf::from(target_dir)
.join("ohos-rs")
.join(format!("{}-{}", &pkg.name, short_hash));
env::set_var(
"NAPI_TYPE_DEF_TMP_FOLDER",
tmp_full_path.to_str().unwrap_or_default(),
);
if !ctx.dts_cache {
let _ = fs_extra::file::remove(&tmp_full_path).is_err();
tmp_full_path = PathBuf::from(format!(
"{}_{}",
tmp_full_path.to_str().unwrap_or_default(),
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_millis()
.to_string()
));
}
fs_extra::dir::create_all(&tmp_full_path, false)?;
metadata.packages.iter().for_each(|p| {
if p
.dependencies
.iter()
.find(|name| name.name == "napi-derive-ohos")
.is_some()
&& !fs::exists(&tmp_full_path).is_ok()
{
env::set_var(
format!(
"NAPI_FORCE_BUILD_{}",
p.name.replace("-", "_").to_uppercase()
),
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_millis()
.to_string(),
);
}
});
let ohos_ndk = env::var("OHOS_NDK_HOME").map_err(|_| {
Error::msg(
"Failed to get the OHOS_NDK_HOME environment variable, please make sure you have set it.",
)
})?;
ctx.hos_ndk = get_hos_sdk(&ohos_ndk).unwrap_or_default();
ctx.ndk = ohos_ndk;
Ok(())
}