use crate::{
util::{cargo_package, cksum, extract_crate},
IndexDependency, IndexPackage,
};
use failure::{bail, format_err, Error, ResultExt};
use std::{
env,
path::{Path, PathBuf},
};
use url::Url;
pub(crate) struct MetaInfo {
pub(crate) index_pkg: IndexPackage,
pub(crate) crate_path: PathBuf,
}
pub fn metadata_from_crate(
index_url: &str,
crate_path: impl AsRef<Path>,
) -> Result<IndexPackage, Error> {
let crate_path = crate_path.as_ref();
let (_tmp_dir, pkg_path) = extract_crate(crate_path)?;
Ok(metadata_reg(
index_url,
Some(&pkg_path.join("Cargo.toml")),
Some(crate_path),
None,
)?
.index_pkg)
}
pub fn metadata(
index_url: &str,
manifest_path: Option<&Path>,
package_args: Option<&Vec<String>>,
) -> Result<IndexPackage, Error> {
Ok(metadata_reg(index_url, manifest_path, None, package_args)?.index_pkg)
}
pub(crate) fn metadata_reg(
index_url: &str,
manifest_path: Option<&Path>,
crate_path: Option<&Path>,
package_args: Option<&Vec<String>>,
) -> Result<MetaInfo, Error> {
let mut cmd = cargo_metadata::MetadataCommand::new();
if let Some(path) = manifest_path {
cmd.manifest_path(path);
}
let metadata = cmd
.exec()
.map_err(|e| format_err!("{}", e))
.with_context(|_| match manifest_path {
Some(path) => format_err!("Failed to read manifest at `{}`.", path.display()),
None => format_err!("Failed to read manifest from current directory."),
})?;
let cwd = env::current_dir()?;
let actual_manifest_path = match manifest_path {
Some(path) => path.to_path_buf(),
None => cwd
.ancestors()
.map(|p| p.join("Cargo.toml"))
.find(|p| p.exists())
.ok_or_else(|| {
format_err!(
"Could not find `Cargo.toml` in `{}` or any parent.",
cwd.display()
)
})?,
};
let pkg = metadata
.packages
.iter()
.find(|p| Path::new(&p.manifest_path) == actual_manifest_path)
.ok_or_else(|| {
format_err!(
"Could not find package at `{}`.",
actual_manifest_path.display()
)
})?;
let crate_path = match crate_path {
Some(path) => {
if !path.exists() {
bail!("Crate file not found at `{}`", path.display());
}
path.to_path_buf()
}
None => cargo_package(
&actual_manifest_path,
&metadata.target_directory,
pkg,
package_args,
)?,
};
let cksum = cksum(&crate_path)?;
let deps: Vec<IndexDependency> = pkg
.dependencies
.iter()
.map(|dep| {
let (name, package) = match &dep.rename {
Some(new_name) => (new_name.clone(), Some(dep.name.clone())),
None => (dep.name.clone(), None),
};
println!("dep ={:?} index_url={:?}", dep.registry, index_url);
let registry = dep
.registry
.as_ref()
.map(|s| s.as_ref())
.or_else(|| {
Some("https://github.com/rust-lang/crates.io-index")
})
.and_then(|r| {
if r == index_url {
None
} else {
Some(Url::parse(r).unwrap())
}
});
IndexDependency {
name,
req: dep.req.clone(),
features: dep.features.clone(),
optional: dep.optional,
default_features: dep.uses_default_features,
target: dep.target.as_ref().map(|t| format!("{}", t)),
kind: dep.kind,
registry,
package,
__nonexhaustive: (),
}
})
.collect();
let index_pkg = IndexPackage {
name: pkg.name.clone(),
vers: pkg.version.clone(),
deps,
features: pkg.features.clone().into_iter().collect(),
cksum,
yanked: false,
links: pkg.links.clone(),
__nonexhaustive: (),
};
let info = MetaInfo {
index_pkg,
crate_path,
};
Ok(info)
}