use std::path::{Path, PathBuf};
use bindgen::cargo::cargo_expand;
use bindgen::cargo::cargo_lock::{self, Lock};
use bindgen::cargo::cargo_metadata::{self, Metadata};
use bindgen::cargo::cargo_toml;
use bindgen::error::Error;
fn parse_dep_string(dep_string: &str) -> (&str, &str) {
let split: Vec<&str> = dep_string.split_whitespace().collect();
(split[0], split[1])
}
pub(crate) struct PackageRef {
pub name: String,
pub version: String,
}
#[derive(Clone, Debug)]
pub(crate) struct Cargo {
manifest_path: PathBuf,
binding_crate_name: String,
lock: Option<Lock>,
metadata: Metadata,
clean: bool,
}
impl Cargo {
pub(crate) fn load(
crate_dir: &Path,
lock_file: Option<&str>,
binding_crate_name: Option<&str>,
use_cargo_lock: bool,
clean: bool,
) -> Result<Cargo, Error> {
let toml_path = crate_dir.join("Cargo.toml");
let metadata = cargo_metadata::metadata(&toml_path)
.map_err(|x| Error::CargoMetadata(toml_path.to_str().unwrap().to_owned(), x))?;
let lock_path = lock_file
.map(PathBuf::from)
.unwrap_or_else(|| Path::new(&metadata.workspace_root).join("Cargo.lock"));
let lock = if use_cargo_lock {
match cargo_lock::lock(&lock_path) {
Ok(lock) => Some(lock),
Err(x) => {
warn!("Couldn't load lock file {:?}: {:?}", lock_path, x);
None
}
}
} else {
None
};
let manifest = cargo_toml::manifest(&toml_path)
.map_err(|x| Error::CargoToml(toml_path.to_str().unwrap().to_owned(), x))?;
let binding_crate_name =
binding_crate_name.map_or(manifest.package.name.clone(), |x| x.to_owned());
Ok(Cargo {
manifest_path: toml_path,
binding_crate_name: binding_crate_name,
lock: lock,
metadata: metadata,
clean: clean,
})
}
pub(crate) fn binding_crate_name(&self) -> &str {
&self.binding_crate_name
}
pub(crate) fn binding_crate_ref(&self) -> PackageRef {
self.find_pkg_ref(&self.binding_crate_name).unwrap()
}
fn find_pkg_ref(&self, package_name: &str) -> Option<PackageRef> {
for package in &self.metadata.packages {
if package.name == package_name {
return Some(PackageRef {
name: package_name.to_owned(),
version: package.version.clone(),
});
}
}
None
}
pub(crate) fn find_dep_ref(
&self,
package: &PackageRef,
dependency_name: &str,
) -> Option<PackageRef> {
if self.lock.is_none() {
return None;
}
let lock = self.lock.as_ref().unwrap();
let replaced_name = dependency_name.replace("_", "-");
if let &Some(ref root) = &lock.root {
if root.name == package.name && root.version == package.version {
if let Some(ref deps) = root.dependencies {
for dep in deps {
let (name, version) = parse_dep_string(dep);
if name == dependency_name || name == &replaced_name {
return Some(PackageRef {
name: name.to_owned(),
version: version.to_owned(),
});
}
}
}
return None;
}
}
if let &Some(ref lock_packages) = &lock.package {
for lock_package in lock_packages {
if lock_package.name == package.name && lock_package.version == package.version {
if let Some(ref deps) = lock_package.dependencies {
for dep in deps {
let (name, version) = parse_dep_string(dep);
if name == dependency_name || name == &replaced_name {
return Some(PackageRef {
name: name.to_owned(),
version: version.to_owned(),
});
}
}
}
return None;
}
}
}
None
}
#[allow(unused)]
pub(crate) fn find_crate_dir(&self, package: &PackageRef) -> Option<PathBuf> {
for meta_package in &self.metadata.packages {
if meta_package.name == package.name && meta_package.version == package.version {
return Path::new(&meta_package.manifest_path)
.parent()
.map(|x| x.to_owned());
}
}
None
}
pub(crate) fn find_crate_src(&self, package: &PackageRef) -> Option<PathBuf> {
let kind_lib = String::from("lib");
let kind_staticlib = String::from("staticlib");
let kind_rlib = String::from("rlib");
let kind_cdylib = String::from("cdylib");
let kind_dylib = String::from("dylib");
for meta_package in &self.metadata.packages {
if meta_package.name == package.name && meta_package.version == package.version {
for target in &meta_package.targets {
if target.kind.contains(&kind_lib)
|| target.kind.contains(&kind_staticlib)
|| target.kind.contains(&kind_rlib)
|| target.kind.contains(&kind_cdylib)
|| target.kind.contains(&kind_dylib)
{
return Some(PathBuf::from(&target.src_path));
}
}
break;
}
}
None
}
pub(crate) fn expand_crate(
&self,
package: &PackageRef,
expand_all_features: bool,
expand_default_features: bool,
expand_features: &Option<Vec<String>>,
) -> Result<String, cargo_expand::Error> {
cargo_expand::expand(
&self.manifest_path,
&package.name,
&package.version,
self.clean,
expand_all_features,
expand_default_features,
expand_features,
)
}
}