use serde::Deserialize;
use std::{
collections::HashMap,
path::{Path, PathBuf},
};
use crate::error::{Error, Result};
use crate::utils;
#[derive(Clone, Debug, Deserialize)]
pub struct Manifest {
pub workspace: Option<Workspace>,
pub package: Option<Package>,
pub lib: Option<Lib>,
#[serde(default, rename = "bin")]
pub bins: Vec<Bin>,
#[serde(default, rename = "example")]
pub examples: Vec<Example>,
}
impl Manifest {
pub fn parse_from_toml(path: &Path) -> Result<Self> {
let contents = std::fs::read_to_string(path).map_err(|e| Error::Io(path.to_owned(), e))?;
toml::from_str(&contents).map_err(|e| Error::Toml(path.to_owned(), e))
}
pub fn members(&self, workspace_root: &Path) -> Result<HashMap<PathBuf, (PathBuf, Manifest)>> {
let workspace = self
.workspace
.as_ref()
.ok_or(Error::ManifestNotAWorkspace)?;
let workspace_root = utils::canonicalize(workspace_root)?;
let mut all_members = HashMap::new();
for member in &workspace.members {
for manifest_dir in glob::glob(workspace_root.join(member).to_str().unwrap())? {
let manifest_dir = manifest_dir?;
let manifest_path = manifest_dir.join("Cargo.toml");
let manifest = Manifest::parse_from_toml(&manifest_path)?;
if manifest.workspace.is_some() {
return Err(Error::UnexpectedWorkspace(manifest_path));
}
if manifest.package.is_none() {
return Err(Error::NoPackageInManifest(manifest_path));
}
all_members.insert(manifest_dir, (manifest_path, manifest));
}
}
Ok(all_members)
}
pub fn map_nonvirtual_package(
self,
manifest_path: PathBuf,
name: Option<&str>,
) -> Result<(PathBuf, Self)> {
if self.workspace.is_some() {
return Err(Error::UnexpectedWorkspace(manifest_path));
}
if let Some(package) = &self.package {
if let Some(name) = name {
if package.name == name {
Ok((manifest_path, self))
} else {
Err(Error::PackageNotFound(manifest_path, name.into()))
}
} else {
Ok((manifest_path, self))
}
} else {
Err(Error::NoPackageInManifest(manifest_path))
}
}
}
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct Workspace {
#[serde(default)]
pub default_members: Vec<String>,
#[serde(default)]
pub members: Vec<String>,
}
const fn default_true() -> bool {
true
}
#[derive(Clone, Debug, Deserialize)]
pub struct Package {
pub name: String,
#[serde(default = "default_true")]
pub autobins: bool,
#[serde(default = "default_true")]
pub autoexamples: bool,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Deserialize)]
pub enum CrateType {
Bin,
Lib,
Staticlib,
Cdylib,
}
#[derive(Clone, Debug, Deserialize)]
pub struct Lib {
pub name: Option<String>,
pub path: Option<PathBuf>,
}
#[derive(Clone, Debug, Deserialize)]
pub struct Bin {
pub name: String,
pub path: Option<PathBuf>,
}
#[derive(Clone, Debug, Deserialize)]
pub struct Example {
pub name: String,
pub path: Option<PathBuf>,
}