#![cfg_attr(coverage_nightly, coverage(off))]
use std::fs;
use std::path::Path;
use anyhow::{Context, Result};
use super::types::DepEdge;
#[allow(clippy::type_complexity)]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn parse_cargo_toml(
path: &Path,
) -> Result<(Vec<(String, String, bool)>, Vec<(String, String, bool)>)> {
let content =
fs::read_to_string(path).with_context(|| format!("Failed to read {}", path.display()))?;
let toml: toml::Value =
toml::from_str(&content).with_context(|| "Failed to parse Cargo.toml")?;
let mut deps = Vec::new();
let mut dev_deps = Vec::new();
if let Some(dependencies) = toml.get("dependencies").and_then(|d| d.as_table()) {
for (name, value) in dependencies {
let version = match value {
toml::Value::String(v) => v.clone(),
toml::Value::Table(t) => t
.get("version")
.and_then(|v| v.as_str())
.unwrap_or("*")
.to_string(),
_ => "*".to_string(),
};
deps.push((name.clone(), version, false));
}
}
if let Some(dependencies) = toml.get("dev-dependencies").and_then(|d| d.as_table()) {
for (name, value) in dependencies {
let version = match value {
toml::Value::String(v) => v.clone(),
toml::Value::Table(t) => t
.get("version")
.and_then(|v| v.as_str())
.unwrap_or("*")
.to_string(),
_ => "*".to_string(),
};
dev_deps.push((name.clone(), version, true));
}
}
Ok((deps, dev_deps))
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn parse_cargo_lock(path: &Path) -> Result<(Vec<String>, Vec<DepEdge>)> {
let candidates = [
path.join("Cargo.lock"),
path.parent()
.map(|p| p.join("Cargo.lock"))
.unwrap_or_default(),
path.parent()
.and_then(|p| p.parent())
.map(|p| p.join("Cargo.lock"))
.unwrap_or_default(),
];
let lock_path = candidates.iter().find(|p| p.exists());
let Some(lock_path) = lock_path else {
return Ok((Vec::new(), Vec::new()));
};
let content = fs::read_to_string(lock_path)
.with_context(|| format!("Failed to read {}", lock_path.display()))?;
let toml: toml::Value =
toml::from_str(&content).with_context(|| "Failed to parse Cargo.lock")?;
let mut all_packages = Vec::new();
let mut edges = Vec::new();
if let Some(packages) = toml.get("package").and_then(|p| p.as_array()) {
for pkg in packages {
if let Some(name) = pkg.get("name").and_then(|n| n.as_str()) {
all_packages.push(name.to_string());
if let Some(deps) = pkg.get("dependencies").and_then(|d| d.as_array()) {
for dep in deps {
if let Some(dep_str) = dep.as_str() {
let dep_name = dep_str.split_whitespace().next().unwrap_or(dep_str);
edges.push(DepEdge {
from: name.to_string(),
to: dep_name.to_string(),
});
}
}
}
}
}
}
Ok((all_packages, edges))
}