cargo_wizard/workspace/
mod.rs

1use std::path::Path;
2
3use anyhow::Context;
4
5use crate::Template;
6use manifest::CargoManifest;
7
8use crate::workspace::config::{config_path_from_manifest_path, CargoConfig};
9use crate::workspace::manifest::Profile;
10
11pub mod config;
12pub mod manifest;
13
14/// Cargo workspace project.
15#[derive(Clone)]
16pub struct CargoWorkspace {
17    manifest: CargoManifest,
18    config: CargoConfig,
19}
20
21impl CargoWorkspace {
22    pub fn apply_template(
23        self,
24        profile: &Profile,
25        template: &Template,
26    ) -> anyhow::Result<ModifiedWorkspace> {
27        let old_manifest = self.manifest.clone();
28        let new_manifest = self.manifest.apply_template(profile, template)?;
29        let manifest = if old_manifest.get_text() == new_manifest.get_text() {
30            ModificationResult::NoChange
31        } else {
32            ModificationResult::Modified {
33                old: old_manifest,
34                new: new_manifest,
35            }
36        };
37
38        let old_config = self.config.clone();
39        let new_config = self.config.apply_template(template)?;
40        let config = if old_config.get_text() == new_config.get_text() {
41            ModificationResult::NoChange
42        } else {
43            ModificationResult::Modified {
44                old: old_config,
45                new: new_config,
46            }
47        };
48        Ok(ModifiedWorkspace { manifest, config })
49    }
50
51    pub fn existing_profiles(&self) -> Vec<String> {
52        self.manifest.get_profiles()
53    }
54}
55
56/// Workspace that was modified through a template.
57pub struct ModifiedWorkspace {
58    manifest: ModificationResult<CargoManifest>,
59    config: ModificationResult<CargoConfig>,
60}
61
62impl ModifiedWorkspace {
63    pub fn manifest(&self) -> &ModificationResult<CargoManifest> {
64        &self.manifest
65    }
66
67    pub fn config(&self) -> &ModificationResult<CargoConfig> {
68        &self.config
69    }
70
71    pub fn write(self) -> anyhow::Result<()> {
72        match self.manifest {
73            ModificationResult::NoChange => {}
74            ModificationResult::Modified { new, .. } => {
75                new.write()?;
76            }
77        }
78        match self.config {
79            ModificationResult::NoChange => {}
80            ModificationResult::Modified { new, .. } => {
81                new.write()?;
82            }
83        }
84        Ok(())
85    }
86}
87
88/// Result of modification of a manifest or a config.
89pub enum ModificationResult<T> {
90    NoChange,
91    Modified { old: T, new: T },
92}
93
94/// Parses a Cargo workspace from a Cargo.toml manifest path.
95pub fn parse_workspace(manifest_path: &Path) -> anyhow::Result<CargoWorkspace> {
96    let manifest = CargoManifest::from_path(manifest_path)?;
97    let config = Some(config_path_from_manifest_path(manifest_path))
98        .filter(|p| p.exists())
99        .map(|path| CargoConfig::from_path(&path))
100        .transpose()
101        .with_context(|| "Cannot load config.toml")?
102        .unwrap_or_else(|| CargoConfig::empty_from_manifest(manifest_path));
103
104    Ok(CargoWorkspace { manifest, config })
105}