#![warn(missing_docs)]
use std::{env, io, path::{PathBuf}, process, string};
pub fn locate_manifest() -> Result<PathBuf, LocateManifestError> {
let cargo = env::var("CARGO").unwrap_or("cargo".to_owned());
let output = process::Command::new(cargo).arg("locate-project").output()?;
if !output.status.success() {
return Err(LocateManifestError::CargoExecution{ stderr: output.stderr});
}
let output = String::from_utf8(output.stdout)?;
let parsed = json::parse(&output)?;
let root = parsed["root"].as_str().ok_or(LocateManifestError::NoRoot)?;
Ok(PathBuf::from(root))
}
#[derive(Debug)]
pub enum LocateManifestError {
Io(io::Error),
CargoExecution{
stderr: Vec<u8>,
},
StringConversion(string::FromUtf8Error),
ParseJson(json::Error),
NoRoot,
}
impl From<io::Error> for LocateManifestError {
fn from(err: io::Error) -> Self {
LocateManifestError::Io(err)
}
}
impl From<string::FromUtf8Error> for LocateManifestError {
fn from(err: string::FromUtf8Error) -> Self {
LocateManifestError::StringConversion(err)
}
}
impl From<json::Error> for LocateManifestError {
fn from(err: json::Error) -> Self {
LocateManifestError::ParseJson(err)
}
}
#[test]
fn test_manifest_path() {
use std::path::Path;
let manifest_path = locate_manifest().expect("failed to retrieve cargo manifest path");
let manual_path = Path::new(file!()).parent().unwrap().join("../Cargo.toml").canonicalize().unwrap();
assert_eq!(manifest_path, manual_path);
}