cargo_v/
parser.rs

1use std::error::Error;
2
3pub fn get_version_from_cargo_toml(
4  cargo_toml: &str,
5) -> Result<String, Box<dyn Error>> {
6  get_prop_from_cargo_toml(cargo_toml, "version")
7}
8
9pub fn get_version_from_cargo_lock(
10  cargo_lock: &str,
11  cargo_toml: &str,
12) -> Result<String, Box<dyn Error>> {
13  let mut version: Option<String> = None;
14  let lines: Vec<&str> = cargo_lock.lines().collect();
15  let mut should_copy = false;
16  let project_name = get_name_from_cargo_toml(cargo_toml)?;
17
18  for line in lines {
19    if line.starts_with("name") {
20      should_copy = line.starts_with(&format!("name = \"{}\"", project_name));
21    }
22
23    if should_copy && line.starts_with("version") {
24      version = Some(get_value_from_toml_line(line, "version"));
25    }
26  }
27
28  match version {
29    Some(v) => Ok(v),
30    None => Err("Cargo.lock does not have a `version` entry")?,
31  }
32}
33
34pub fn set_version_in_cargo_toml(cargo_toml: &str, version: &str) -> String {
35  let lines: Vec<&str> = cargo_toml.lines().collect();
36  let mut new_cargo_toml: Vec<String> = Vec::new();
37  let mut should_write = false;
38
39  for line in lines {
40    let mut new_line = line.to_owned();
41    if line.starts_with('[') {
42      should_write = line.starts_with("[package]");
43    }
44
45    if should_write && line.starts_with("version") {
46      new_line = format!("version = \"{}\"", version);
47    }
48
49    new_cargo_toml.push(new_line);
50  }
51
52  new_cargo_toml.join("\n")
53}
54
55pub fn set_version_in_cargo_lock(
56  cargo_lock: &str,
57  project_name: &str,
58  version: &str,
59) -> String {
60  let lines: Vec<&str> = cargo_lock.lines().collect();
61  let mut new_cargo_lock: Vec<String> = Vec::new();
62  let mut should_write = false;
63
64  for line in lines {
65    let mut new_line = line.to_owned();
66    if line.starts_with("name") {
67      should_write = line.starts_with(&format!("name = \"{}\"", project_name));
68    }
69
70    if should_write && line.starts_with("version") {
71      new_line = format!("version = \"{}\"", version);
72    }
73
74    new_cargo_lock.push(new_line);
75  }
76
77  new_cargo_lock.join("\n")
78}
79
80pub fn get_name_from_cargo_toml(
81  cargo_toml: &str,
82) -> Result<String, Box<dyn Error>> {
83  get_prop_from_cargo_toml(cargo_toml, "name")
84}
85
86fn get_prop_from_cargo_toml(
87  cargo_toml: &str,
88  prop: &str,
89) -> Result<String, Box<dyn Error>> {
90  let mut property: Option<String> = None;
91  let lines: Vec<&str> = cargo_toml.lines().collect();
92  let mut should_copy = false;
93
94  for line in lines {
95    if line.starts_with('[') {
96      should_copy = line.starts_with("[package]")
97    }
98
99    if should_copy && line.starts_with(prop) {
100      property = Some(get_value_from_toml_line(line, prop));
101    }
102  }
103
104  match property {
105    Some(v) => Ok(v),
106    None => Err(format!(
107      "Cargo.toml does not have a `{prop}` entry inside [package]"
108    ))?,
109  }
110}
111
112fn get_value_from_toml_line(line: &str, prop: &str) -> String {
113  line
114    .replace(prop, "")
115    .replace('=', "")
116    .replace('"', "")
117    .trim()
118    .to_string()
119}
120
121#[cfg(test)]
122mod tests {
123  use super::*;
124
125  fn get_cargo_toml(version: &str) -> String {
126    format!("\
127[dependencies]
128tokio = {{ version = \"1.1.1\" }}
129
130[package]
131name = \"cargo-v\"
132version = \"{}\"
133edition = \"2021\"
134description = \"Update the version of your package easily\"
135license = \"MIT\"
136
137# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
138[dependencies.dev]
139other = {{ version = \"1.1.8\" }}
140      ",
141    version)
142  }
143
144  fn get_cargo_lock(version: &str) -> String {
145    format!(
146      "
147# This file is automatically @generated by Cargo.
148# It is not intended for manual editing.
149version = 3
150
151[[package]]
152name = \"tokio\"
153version = \"0.1.8\"
154
155[[package]]
156name = \"cargo-v\"
157version = \"{}\"
158
159[[package]]
160name = \"regex\"
161version = \"0.1.8\"
162      ",
163      version
164    )
165  }
166
167  #[test]
168  fn should_get_version_from_cargo_toml() {
169    let cargo_toml = &get_cargo_toml("0.1.6");
170    let actual = get_version_from_cargo_toml(cargo_toml).unwrap();
171    let expected = "0.1.6";
172    assert_eq!(actual, expected);
173  }
174
175  #[test]
176  fn should_get_name_from_cargo_toml() {
177    let cargo_toml = &get_cargo_toml("0.1.6");
178    let actual = get_name_from_cargo_toml(cargo_toml).unwrap();
179    let expected = "cargo-v";
180    assert_eq!(actual, expected);
181  }
182
183  #[test]
184  fn should_get_property_edition_from_cargo_toml() {
185    let cargo_toml = &get_cargo_toml("0.1.6");
186    let actual = get_prop_from_cargo_toml(&cargo_toml, "edition").unwrap();
187    let expected = "2021";
188    assert_eq!(actual, expected);
189  }
190
191  #[test]
192  fn should_get_version_from_cargo_lock() {
193    let cargo_toml = &get_cargo_toml("0.1.6");
194    let cargo_lock = &get_cargo_lock("0.1.6");
195    let actual = get_version_from_cargo_lock(cargo_lock, cargo_toml).unwrap();
196    let expected = "0.1.6";
197    assert_eq!(actual, expected);
198  }
199
200  #[test]
201  fn should_get_value_from_line_in_cargo_toml() {
202    let line = "version = \"1.1.1\"";
203    let actual = get_value_from_toml_line(line, "version");
204    let expected = "1.1.1";
205    assert_eq!(actual, expected);
206  }
207
208  #[test]
209  fn should_write_new_version_in_cargo_toml() {
210    let cargo_toml = get_cargo_toml("0.1.6");
211    let actual = set_version_in_cargo_toml(&cargo_toml, "0.1.7");
212    let expected = get_cargo_toml("0.1.7");
213    assert_eq!(actual, expected);
214  }
215
216  #[test]
217  fn should_write_new_version_in_cargo_lock() {
218    let cargo_toml = &get_cargo_toml("0.1.6");
219    let cargo_lock = get_cargo_lock("0.1.6");
220    let project_name = &get_name_from_cargo_toml(cargo_toml).unwrap();
221    let actual = set_version_in_cargo_lock(&cargo_lock, project_name, "0.1.7");
222    let expected = get_cargo_lock("0.1.7");
223    assert_eq!(actual, expected);
224  }
225}