1use semver::Version;
2use std::{fs, io::Error as IoError, path::Path};
3use thiserror::Error;
4use toml_edit::{value, Document, Item, TomlError};
5
6#[derive(Debug, Error)]
8pub enum Error {
9 #[error("an io error occurred")]
12 IoError(#[from] IoError),
13 #[error("An error occurred during version parsing")]
15 SemverParseError(#[from] semver::Error),
16 #[error("a parser error occurred")]
18 ParseError(#[from] TomlError),
19 #[error("the field {field:?} is not of type {ty:?}")]
22 InvalidFieldType { field: String, ty: String },
23}
24
25#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
27pub enum SemVer {
28 Major,
30 Minor,
32 Patch,
34}
35
36pub fn get_version(path: impl AsRef<Path>) -> Result<Version, Error> {
47 let cargo_toml_content = fs::read_to_string(path.as_ref())?;
48 let doc = cargo_toml_content.parse::<Document>()?;
49 let item: &Item = &doc["package"]["version"];
50
51 if let Some(s) = item.as_str() {
53 Ok(Version::parse(s)?)
54 } else {
55 Err(Error::InvalidFieldType {
56 field: "version".to_string(),
57 ty: "string".to_string(),
58 })
59 }
60}
61
62pub fn set_version(path: impl AsRef<Path>, version: impl AsRef<str>) -> Result<(), Error> {
74 let cargo_toml_content = fs::read_to_string(path.as_ref())?;
75 let mut doc = cargo_toml_content.parse::<Document>()?;
76
77 doc["package"]["version"] = value(version.as_ref());
78 fs::write(path.as_ref(), doc.to_string())?;
79
80 Ok(())
81}
82
83pub fn bump_version(path: impl AsRef<Path>, r#type: SemVer) -> Result<Version, Error> {
94 let mut version = get_version(path.as_ref())?;
95 match r#type {
96 SemVer::Major => version.increment_major(),
97 SemVer::Minor => version.increment_minor(),
98 SemVer::Patch => version.increment_patch(),
99 }
100
101 set_version(path, &version.to_string())?;
102 Ok(version)
103}
104
105trait SemVerExt {
106 fn increment_major(&mut self);
107 fn increment_minor(&mut self);
108 fn increment_patch(&mut self);
109}
110
111impl SemVerExt for Version {
112 fn increment_major(&mut self) {
113 self.major += 1;
114 }
115
116 fn increment_minor(&mut self) {
117 self.minor += 1;
118 }
119
120 fn increment_patch(&mut self) {
121 self.patch += 1;
122 }
123}