use std::path::{Path, PathBuf};
use fs_err as fs;
use rattler_build_recipe::stage1::{TestType, requirements::Dependency, tests::CommandsTest};
use rattler_build_script::{
ResolvedScriptContents, ScriptContent, determine_interpreter_from_path,
platform_script_extensions,
};
use rattler_conda_types::{MatchSpec, PackageNameMatcher};
use crate::{metadata::Output, packaging::PackagingError};
fn resolve_dependency(dep: &Dependency, output: &Output) -> Dependency {
match dep {
Dependency::Spec(_) => dep.clone(),
Dependency::PinSubpackage(pin) => {
let name = &pin.pin_subpackage.name;
if let Some(subpackage) = output.build_configuration.subpackages.get(name) {
match pin
.pin_subpackage
.apply(&subpackage.version, &subpackage.build_string)
{
Ok(spec) => Dependency::Spec(Box::new(spec)),
Err(_) => {
Dependency::Spec(Box::new(MatchSpec {
name: PackageNameMatcher::Exact(name.clone()),
..Default::default()
}))
}
}
} else {
Dependency::Spec(Box::new(MatchSpec {
name: PackageNameMatcher::Exact(name.clone()),
..Default::default()
}))
}
}
Dependency::PinCompatible(pin) => {
let name = &pin.pin_compatible.name;
Dependency::Spec(Box::new(MatchSpec {
name: PackageNameMatcher::Exact(name.clone()),
..Default::default()
}))
}
}
}
fn resolve_test_requirements(command_test: &mut CommandsTest, output: &Output) {
command_test.requirements.run = command_test
.requirements
.run
.iter()
.map(|dep| resolve_dependency(dep, output))
.collect();
command_test.requirements.build = command_test
.requirements
.build
.iter()
.map(|dep| resolve_dependency(dep, output))
.collect();
}
pub fn write_command_test_files(
command_test: &CommandsTest,
folder: &Path,
output: &Output,
) -> Result<Vec<PathBuf>, PackagingError> {
let mut test_files = Vec::new();
if !command_test.files.recipe.is_empty() || !command_test.files.source.is_empty() {
fs::create_dir_all(folder)?;
}
if !command_test.files.recipe.is_empty() {
let globs = &command_test.files.recipe;
let copy_dir = crate::source::copy_dir::CopyDir::new(
&output.build_configuration.directories.recipe_dir,
folder,
)
.with_globvec(globs)
.use_gitignore(false)
.run()?;
test_files.extend(copy_dir.copied_paths().iter().cloned());
}
if !command_test.files.source.is_empty() {
let globs = &command_test.files.source;
let copy_dir = crate::source::copy_dir::CopyDir::new(
&output.build_configuration.directories.work_dir,
folder,
)
.with_globvec(globs)
.use_gitignore(false)
.run()?;
test_files.extend(copy_dir.copied_paths().iter().cloned());
}
Ok(test_files)
}
pub(crate) fn write_test_files(
output: &Output,
tmp_dir_path: &Path,
) -> Result<Vec<PathBuf>, PackagingError> {
let mut test_files = Vec::new();
let name = output.name().as_normalized();
let mut tests = output.recipe.tests.clone();
tests.retain(|test| !matches!(test, TestType::PackageContents { .. }));
for (idx, test) in tests.iter_mut().enumerate() {
if let TestType::Commands(command_test) = test {
resolve_test_requirements(command_test, output);
let cwd = PathBuf::from(format!("etc/conda/test-files/{name}/{idx}"));
let folder = tmp_dir_path.join(&cwd);
let files = write_command_test_files(command_test, &folder, output)?;
if !files.is_empty() {
test_files.extend(files);
command_test.script.cwd = Some(cwd);
}
let jinja_renderer = output.jinja_renderer();
let contents = command_test.script.resolve_content(
&output.build_configuration.directories.recipe_dir,
Some(jinja_renderer),
platform_script_extensions(),
)?;
match contents {
ResolvedScriptContents::Inline(contents) => {
command_test.script.content = ScriptContent::Command(contents)
}
ResolvedScriptContents::Path(path, contents) => {
if command_test.script.interpreter.is_none() {
command_test.script.interpreter = determine_interpreter_from_path(&path);
}
command_test.script.content = ScriptContent::Command(contents);
}
ResolvedScriptContents::Missing => {
command_test.script.content = ScriptContent::Command("".to_string());
}
}
}
}
let test_file_dir = tmp_dir_path.join("info/tests");
fs::create_dir_all(&test_file_dir)?;
let test_file = test_file_dir.join("tests.yaml");
fs::write(&test_file, serde_yaml::to_string(&tests)?)?;
test_files.push(test_file);
Ok(test_files)
}