Skip to main content

propel_core/
project.rs

1use serde::Deserialize;
2use std::path::Path;
3
4/// Metadata extracted from the user's Cargo.toml
5#[derive(Debug, Clone)]
6pub struct ProjectMeta {
7    pub name: String,
8    pub version: String,
9    pub binary_name: String,
10}
11
12#[derive(Deserialize)]
13struct CargoToml {
14    package: Option<PackageSection>,
15    bin: Option<Vec<BinSection>>,
16}
17
18#[derive(Deserialize)]
19struct PackageSection {
20    name: Option<String>,
21    version: Option<String>,
22}
23
24#[derive(Deserialize)]
25struct BinSection {
26    name: Option<String>,
27}
28
29impl ProjectMeta {
30    /// Extract project metadata from a Cargo.toml file.
31    pub fn from_cargo_toml(project_dir: &Path) -> crate::Result<Self> {
32        let cargo_path = project_dir.join("Cargo.toml");
33        let content =
34            std::fs::read_to_string(&cargo_path).map_err(|e| crate::Error::CargoTomlRead {
35                path: cargo_path.clone(),
36                source: e,
37            })?;
38
39        let parsed: CargoToml =
40            toml::from_str(&content).map_err(|e| crate::Error::CargoTomlParse {
41                path: cargo_path.clone(),
42                source: e,
43            })?;
44
45        let package = parsed
46            .package
47            .ok_or_else(|| crate::Error::MissingPackageSection(cargo_path.clone()))?;
48
49        let name = package
50            .name
51            .ok_or_else(|| crate::Error::MissingPackageName(cargo_path.clone()))?;
52
53        let version = package.version.unwrap_or_else(|| "0.1.0".to_owned());
54
55        // Binary name: first [[bin]] entry, or package name
56        let binary_name = parsed
57            .bin
58            .and_then(|bins| bins.into_iter().next())
59            .and_then(|b| b.name)
60            .unwrap_or_else(|| name.clone());
61
62        Ok(Self {
63            name,
64            version,
65            binary_name,
66        })
67    }
68}