use crate::{Error, Result, HOST_DIRNAME};
use artifact_dependency::ARTIFACT_NAMEPARTS;
use cargo_subcommand::Subcommand;
use std::{fs::read_dir, path::PathBuf};
use typed_builder::TypedBuilder;
#[derive(TypedBuilder, Debug, Clone, Default)]
pub struct PackageArtifacts {
pub libs: Vec<PathBuf>,
pub files: Vec<(String, String)>,
}
impl PackageArtifacts {
pub fn from_subcommand(subcommand: &Subcommand) -> Result<Self> {
let module_cdylib = subcommand
.artifacts()
.map(|a| {
subcommand.build_dir(subcommand.target()).join(format!(
"{}{}{}",
ARTIFACT_NAMEPARTS.0,
a.name.replace('_', "-"),
ARTIFACT_NAMEPARTS.1
))
})
.find(|p| p.exists())
.ok_or_else(|| Error::CdylibArtifactNotFound {
package: subcommand.package().to_string(),
})?;
let module_artifact = PathBuf::from({
let file_name = module_cdylib
.file_name()
.ok_or_else(|| Error::FilenameNotFound {
path: module_cdylib.to_path_buf(),
})?
.to_str()
.ok_or_else(|| Error::FilenameNotFound {
path: module_cdylib.to_path_buf(),
})?;
let module_cdylib_dir =
module_cdylib
.parent()
.ok_or_else(|| Error::ParentNotFound {
path: module_cdylib.to_path_buf(),
})?;
module_cdylib_dir
.join(file_name.replace('_', "-"))
.to_str()
.ok_or_else(|| Error::FilenameNotFound {
path: module_cdylib.to_path_buf(),
})?
});
let target_profile_build_dir = subcommand.build_dir(subcommand.target()).join("build");
let target_profile_build_subdirs = read_dir(target_profile_build_dir)?
.filter_map(|rd| rd.ok())
.map(|de| de.path())
.filter(|p| {
p.is_dir()
&& p.file_name().is_some_and(|n| {
n.to_str()
.is_some_and(|ns| ns.starts_with(subcommand.package()))
})
&& !p
.join(format!("build-script-build{}", ARTIFACT_NAMEPARTS.4))
.exists()
&& p.join("out").is_dir()
})
.collect::<Vec<_>>();
let cdylib_out_artifacts = target_profile_build_subdirs
.iter()
.map(|bd| bd.join("out"))
.map(|od| {
read_dir(od).map(|rd| {
Ok(rd
.filter_map(|rd| rd.ok())
.map(|de| de.path())
.filter(|p| {
p.file_name().is_some_and(|n| {
n.to_str().is_some_and(|ns| {
ns.starts_with(ARTIFACT_NAMEPARTS.0)
&& ns.ends_with(ARTIFACT_NAMEPARTS.1)
})
})
})
.collect::<Vec<_>>())
})?
})
.collect::<Result<Vec<_>>>()?
.into_iter()
.flatten()
.map(|a| {
a.file_name()
.and_then(|n| n.to_str())
.ok_or_else(|| Error::FilenameNotFound { path: a.clone() })
.map(|t| (a.clone(), subcommand.build_dir(subcommand.target()).join(t)))
})
.collect::<Result<Vec<_>>>()?;
let cdylib_out_artifacts = cdylib_out_artifacts
.iter()
.map(|a| a.1.clone())
.collect::<Vec<_>>();
let libs = vec![module_artifact]
.into_iter()
.chain(cdylib_out_artifacts)
.collect::<Vec<_>>();
let host_dir = PathBuf::from(HOST_DIRNAME);
let lib_dir = host_dir.join("lib");
let files = libs
.iter()
.map(|file_path| {
file_path
.canonicalize()
.map_err(Error::from)
.and_then(|file_path| {
file_path
.file_name()
.ok_or_else(|| Error::FilenameNotFound {
path: file_path.clone(),
})
.and_then(|file_name| {
lib_dir
.join(file_name)
.to_str()
.ok_or_else(|| Error::PathConversionError {
path: lib_dir.join(file_name),
})
.and_then(|packaged_file_path| {
Ok((
packaged_file_path.to_string(),
file_path
.to_str()
.ok_or_else(|| Error::PathConversionError {
path: file_path.clone(),
})?
.to_string(),
))
})
})
})
})
.collect::<Result<Vec<_>>>()?;
Ok(Self { libs, files })
}
}