Skip to main content

changeset_operations/providers/
manifest.rs

1use std::path::Path;
2use std::process::Command;
3
4use changeset_manifest::{InitConfig, MetadataSection};
5use semver::Version;
6
7use crate::Result;
8use crate::error::OperationError;
9use crate::traits::{
10    InheritedVersionChecker, LockfileUpdater, ManifestDependencyWriter, ManifestMetadataWriter,
11    ManifestVersionWriter, WorkspaceVersionManager,
12};
13
14pub struct FileSystemManifestWriter;
15
16impl FileSystemManifestWriter {
17    #[must_use]
18    pub fn new() -> Self {
19        Self
20    }
21}
22
23impl Default for FileSystemManifestWriter {
24    fn default() -> Self {
25        Self::new()
26    }
27}
28
29impl InheritedVersionChecker for FileSystemManifestWriter {
30    fn has_inherited_version(&self, manifest_path: &Path) -> Result<bool> {
31        Ok(changeset_manifest::has_inherited_version(manifest_path)?)
32    }
33}
34
35impl ManifestVersionWriter for FileSystemManifestWriter {
36    fn write_version(&self, manifest_path: &Path, new_version: &Version) -> Result<()> {
37        Ok(changeset_manifest::write_version(
38            manifest_path,
39            new_version,
40        )?)
41    }
42
43    fn verify_version(&self, manifest_path: &Path, expected: &Version) -> Result<()> {
44        Ok(changeset_manifest::verify_version(manifest_path, expected)?)
45    }
46}
47
48impl ManifestDependencyWriter for FileSystemManifestWriter {
49    fn update_dependency_version(
50        &self,
51        manifest_path: &Path,
52        dependency_name: &str,
53        new_version: &Version,
54    ) -> Result<bool> {
55        Ok(changeset_manifest::update_dependency_version(
56            manifest_path,
57            dependency_name,
58            new_version,
59        )?)
60    }
61}
62
63impl WorkspaceVersionManager for FileSystemManifestWriter {
64    fn read_workspace_version(&self, manifest_path: &Path) -> Result<Option<Version>> {
65        match changeset_manifest::read_workspace_version(manifest_path) {
66            Ok(version) => Ok(Some(version)),
67            Err(changeset_manifest::ManifestError::MissingField { .. }) => Ok(None),
68            Err(e) => Err(e.into()),
69        }
70    }
71
72    fn remove_workspace_version(&self, manifest_path: &Path) -> Result<()> {
73        Ok(changeset_manifest::remove_workspace_version(manifest_path)?)
74    }
75
76    fn write_workspace_version(&self, manifest_path: &Path, version: &Version) -> Result<()> {
77        Ok(changeset_manifest::write_workspace_version(
78            manifest_path,
79            version,
80        )?)
81    }
82}
83
84impl LockfileUpdater for FileSystemManifestWriter {
85    fn generate_lockfile(&self, project_root: &Path) -> Result<()> {
86        let output = Command::new("cargo")
87            .arg("generate-lockfile")
88            .current_dir(project_root)
89            .output()
90            .map_err(|source| OperationError::LockfileGeneration {
91                path: project_root.to_path_buf(),
92                source,
93            })?;
94
95        if !output.status.success() {
96            return Err(OperationError::LockfileCommandFailed {
97                stderr: String::from_utf8_lossy(&output.stderr).into_owned(),
98            });
99        }
100
101        Ok(())
102    }
103
104    fn read_lockfile(&self, project_root: &Path) -> Result<Option<Vec<u8>>> {
105        let lockfile_path = project_root.join("Cargo.lock");
106        if lockfile_path.exists() {
107            let content =
108                std::fs::read(&lockfile_path).map_err(|source| OperationError::LockfileRead {
109                    path: lockfile_path,
110                    source,
111                })?;
112            Ok(Some(content))
113        } else {
114            Ok(None)
115        }
116    }
117
118    fn restore_lockfile(&self, project_root: &Path, content: &[u8]) -> Result<()> {
119        let lockfile_path = project_root.join("Cargo.lock");
120        std::fs::write(&lockfile_path, content).map_err(|source| {
121            OperationError::LockfileWrite {
122                path: lockfile_path,
123                source,
124            }
125        })?;
126        Ok(())
127    }
128
129    fn remove_lockfile(&self, project_root: &Path) -> Result<()> {
130        let lockfile_path = project_root.join("Cargo.lock");
131        if lockfile_path.exists() {
132            std::fs::remove_file(&lockfile_path).map_err(|source| {
133                OperationError::LockfileWrite {
134                    path: lockfile_path,
135                    source,
136                }
137            })?;
138        }
139        Ok(())
140    }
141}
142
143impl ManifestMetadataWriter for FileSystemManifestWriter {
144    fn write_metadata(
145        &self,
146        manifest_path: &Path,
147        section: MetadataSection,
148        config: &InitConfig,
149    ) -> Result<()> {
150        Ok(changeset_manifest::write_metadata_section(
151            manifest_path,
152            section,
153            config,
154        )?)
155    }
156}