use crate::bindings::TargetLanguage;
use crate::{bindings::RunScriptOptions, library_mode::generate_bindings, BindingGeneratorDefault};
use anyhow::{bail, Context, Result};
use camino::{Utf8Path, Utf8PathBuf};
use std::env;
use std::process::Command;
use uniffi_testing::UniFFITestHelper;
pub fn run_test(tmp_dir: &str, fixture_name: &str, script_file: &str) -> Result<()> {
run_script(
tmp_dir,
fixture_name,
script_file,
vec![],
&RunScriptOptions::default(),
)
}
pub fn run_script(
tmp_dir: &str,
crate_name: &str,
script_file: &str,
args: Vec<String>,
options: &RunScriptOptions,
) -> Result<()> {
let script_path = Utf8Path::new(script_file);
let test_helper = UniFFITestHelper::new(crate_name)?;
let out_dir = test_helper.create_out_dir(tmp_dir, script_path)?;
let cdylib_path = test_helper.copy_cdylib_to_out_dir(&out_dir)?;
generate_bindings(
&cdylib_path,
None,
&BindingGeneratorDefault {
target_languages: vec![TargetLanguage::Kotlin],
try_format_code: false,
},
None,
&out_dir,
false,
)?;
let jar_file = build_jar(crate_name, &out_dir, options)?;
let mut command = kotlinc_command(options);
command
.arg("-classpath")
.arg(calc_classpath(vec![&out_dir, &jar_file]))
.arg("-J-ea")
.arg("-Werror")
.arg("-script")
.arg(script_path)
.args(if args.is_empty() {
vec![]
} else {
std::iter::once(String::from("--")).chain(args).collect()
});
let status = command
.spawn()
.context("Failed to spawn `kotlinc` to run Kotlin script")?
.wait()
.context("Failed to wait for `kotlinc` when running Kotlin script")?;
if !status.success() {
anyhow::bail!("running `kotlinc` failed")
}
Ok(())
}
fn build_jar(
crate_name: &str,
out_dir: &Utf8Path,
options: &RunScriptOptions,
) -> Result<Utf8PathBuf> {
let mut jar_file = Utf8PathBuf::from(out_dir);
jar_file.push(format!("{crate_name}.jar"));
let sources = glob::glob(out_dir.join("**/*.kt").as_str())?
.flatten()
.map(|p| String::from(p.to_string_lossy()))
.collect::<Vec<String>>();
if sources.is_empty() {
bail!("No kotlin sources found in {out_dir}")
}
let mut command = kotlinc_command(options);
command
.arg("-Werror")
.arg("-d")
.arg(&jar_file)
.arg("-classpath")
.arg(calc_classpath(vec![]))
.args(sources);
let status = command
.spawn()
.context("Failed to spawn `kotlinc` to compile the bindings")?
.wait()
.context("Failed to wait for `kotlinc` when compiling the bindings")?;
if !status.success() {
bail!("running `kotlinc` failed")
}
Ok(jar_file)
}
fn kotlinc_command(options: &RunScriptOptions) -> Command {
let mut command = Command::new("kotlinc");
if !options.show_compiler_messages {
command.arg("-nowarn");
}
command
}
fn calc_classpath(extra_paths: Vec<&Utf8Path>) -> String {
extra_paths
.into_iter()
.map(|p| p.to_string())
.chain(env::var("CLASSPATH"))
.collect::<Vec<String>>()
.join(":")
}