use std::borrow::Cow;
use std::path::Path;
use tracing::debug;
use url::Url;
use crate::error::Error;
use crate::metadata::{Metadata, load_metadata_from_path};
pub(crate) fn find_in_vcs<P: AsRef<Path>>(root: P, name: &str) -> Option<(String, Metadata)> {
let path = root.as_ref().join("Cargo.toml");
let md = load_metadata_from_path(&path).ok()?;
let [package]: [cargo_metadata::Package; 1] = md
.packages
.into_iter()
.filter(|p| p.name.as_ref() == name)
.collect::<Vec<_>>()
.try_into()
.inspect_err(|_| {
debug!("Failed to load crate metadata (name does not match any single workspace member): {name}");
})
.ok()?;
let Some(cpath_in_vcs) = package.manifest_path.parent() else {
debug!(
"Failed to load crate metadata (manifest path invalid): {}",
package.manifest_path
);
return None;
};
let Ok(path_in_vcs) = cpath_in_vcs.as_std_path().strip_prefix(&root) else {
debug!(
"Failed to load crate metadata (manifest path invalid): {}",
package.manifest_path
);
return None;
};
let path = path_in_vcs.to_string_lossy().to_string();
Some((path.clone(), Metadata::from_cargo_metadata(package, root, Some(&path))))
}
pub(crate) fn sanitize_repo_url(url: &str) -> Result<Cow<'_, str>, Error> {
let mut parsed = Url::parse(url).map_err(|_| Error::InvalidRepoUrl {
repo: String::from(url),
})?;
if parsed.host_str() == Some("github.com") {
let Some(segments) = parsed.path_segments() else {
return Err(Error::InvalidRepoUrl {
repo: String::from(url),
});
};
let segments: Vec<_> = segments.collect();
match segments.as_slice() {
[_org, _repo] => {}, [] | [_] => {
return Err(Error::InvalidRepoUrl {
repo: String::from(url),
});
},
[org, repo, ..] => {
debug!("Attempting to sanitize GitHub repository URL: {url}");
parsed.set_path(&format!("{org}/{repo}"));
},
}
return Ok(Cow::Owned(parsed.to_string()));
}
Ok(Cow::Borrowed(url))
}