use crate::{Invocation, Result};
use failure::bail;
use log::{info, debug};
use std::path::Path;
pub(crate) struct Meta<'a> {
packages: Vec<Package<'a>>,
target_dir: &'a Path,
}
pub(crate) struct Package<'a> {
name: &'a str,
lib_name: String,
}
impl<'a> Meta<'a> {
#[allow(clippy::useless_let_if_seq)] pub(crate) fn new(
invocation: &Invocation,
meta: &'a cargo_metadata::Metadata,
) -> Result<Meta<'a>> {
let package_names: Vec<_>;
let staticlib_required;
if !invocation.packages.is_empty() {
package_names = invocation.packages.iter().map(|p| p.as_str()).collect();
staticlib_required = true;
} else {
package_names = meta.workspace_members.iter().map(|m| m.name()).collect();
staticlib_required = meta.workspace_members.len() == 1 && !invocation.all;
}
debug!(
"Considering package(s) {:?}, `staticlib` target {}",
package_names,
if staticlib_required { "required" } else { "not required" }
);
let mut packages = vec![];
for &name in &package_names {
let package = match meta.packages.iter().find(|p| p.name == name) {
Some(p) => p,
None => bail!("No package metadata found for {:?}", name),
};
let lib_targets: Vec<_> = package
.targets
.iter()
.filter(|t| t.kind.iter().any(|k| k == "staticlib"))
.collect();
match lib_targets.as_slice() {
[] => {
if !staticlib_required {
debug!("Ignoring {:?} because it does not have a `staticlib` target", name);
continue;
}
bail!("No library target found for {:?}", name);
}
[target] => {
if target.crate_types.iter().any(|ct| ct == "staticlib") {
packages.push((package, target.name.replace('-', "_")));
} else {
if !staticlib_required {
debug!(
"Ignoring {:?} because it does not have a `staticlib` crate type",
name
);
continue;
}
bail!("No staticlib crate type found for {:?}", name);
}
}
_ => bail!("Found multiple lib targets for {:?}", name),
}
}
let packages = packages
.into_iter()
.map(|(p, lib_name)| Package { name: p.name.as_str(), lib_name })
.collect::<Vec<_>>();
let package_names = packages.iter().map(|p| p.name).collect::<Vec<_>>();
if packages.is_empty() {
bail!(
"Did not find any packages with a `staticlib` target, considered {:?}",
package_names
);
}
info!("Will build universal library for {:?}", package_names);
Ok(Meta { packages, target_dir: Path::new(&meta.target_directory) })
}
pub(crate) fn packages(&self) -> &[Package<'a>] {
&self.packages
}
pub(crate) fn target_dir(&self) -> &'a Path {
self.target_dir
}
}
impl<'a> Package<'a> {
pub(crate) fn name(&self) -> &'a str {
self.name
}
pub(crate) fn lib_name(&self) -> &str {
self.lib_name.as_str()
}
}