use std::error::Error;
pub fn get_version_from_cargo_toml(
cargo_toml: &str,
) -> Result<String, Box<dyn Error>> {
get_prop_from_cargo_toml(cargo_toml, "version")
}
pub fn get_version_from_cargo_lock(
cargo_lock: &str,
cargo_toml: &str,
) -> Result<String, Box<dyn Error>> {
let mut version: Option<String> = None;
let lines: Vec<&str> = cargo_lock.lines().collect();
let mut should_copy = false;
let project_name = get_name_from_cargo_toml(cargo_toml)?;
for line in lines {
if line.starts_with("name") {
should_copy = line.starts_with(&format!("name = \"{}\"", project_name));
}
if should_copy && line.starts_with("version") {
version = Some(get_value_from_toml_line(line, "version"));
}
}
match version {
Some(v) => Ok(v),
None => Err("Cargo.lock does not have a `version` entry")?,
}
}
pub fn set_version_in_cargo_toml(cargo_toml: &str, version: &str) -> String {
let lines: Vec<&str> = cargo_toml.lines().collect();
let mut new_cargo_toml: Vec<String> = Vec::new();
let mut should_write = false;
for line in lines {
let mut new_line = line.to_owned();
if line.starts_with('[') {
should_write = line.starts_with("[package]");
}
if should_write && line.starts_with("version") {
new_line = format!("version = \"{}\"", version);
}
new_cargo_toml.push(new_line);
}
new_cargo_toml.join("\n")
}
pub fn set_version_in_cargo_lock(
cargo_lock: &str,
project_name: &str,
version: &str,
) -> String {
let lines: Vec<&str> = cargo_lock.lines().collect();
let mut new_cargo_lock: Vec<String> = Vec::new();
let mut should_write = false;
for line in lines {
let mut new_line = line.to_owned();
if line.starts_with("name") {
should_write = line.starts_with(&format!("name = \"{}\"", project_name));
}
if should_write && line.starts_with("version") {
new_line = format!("version = \"{}\"", version);
}
new_cargo_lock.push(new_line);
}
new_cargo_lock.join("\n")
}
pub fn get_name_from_cargo_toml(
cargo_toml: &str,
) -> Result<String, Box<dyn Error>> {
get_prop_from_cargo_toml(cargo_toml, "name")
}
fn get_prop_from_cargo_toml(
cargo_toml: &str,
prop: &str,
) -> Result<String, Box<dyn Error>> {
let mut property: Option<String> = None;
let lines: Vec<&str> = cargo_toml.lines().collect();
let mut should_copy = false;
for line in lines {
if line.starts_with('[') {
should_copy = line.starts_with("[package]")
}
if should_copy && line.starts_with(prop) {
property = Some(get_value_from_toml_line(line, prop));
}
}
match property {
Some(v) => Ok(v),
None => Err(format!(
"Cargo.toml does not have a `{prop}` entry inside [package]"
))?,
}
}
fn get_value_from_toml_line(line: &str, prop: &str) -> String {
line
.replace(prop, "")
.replace('=', "")
.replace('"', "")
.trim()
.to_string()
}
#[cfg(test)]
mod tests {
use super::*;
fn get_cargo_toml(version: &str) -> String {
format!("\
[dependencies]
tokio = {{ version = \"1.1.1\" }}
[package]
name = \"cargo-v\"
version = \"{}\"
edition = \"2021\"
description = \"Update the version of your package easily\"
license = \"MIT\"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies.dev]
other = {{ version = \"1.1.8\" }}
",
version)
}
fn get_cargo_lock(version: &str) -> String {
format!(
"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = \"tokio\"
version = \"0.1.8\"
[[package]]
name = \"cargo-v\"
version = \"{}\"
[[package]]
name = \"regex\"
version = \"0.1.8\"
",
version
)
}
#[test]
fn should_get_version_from_cargo_toml() {
let cargo_toml = &get_cargo_toml("0.1.6");
let actual = get_version_from_cargo_toml(cargo_toml).unwrap();
let expected = "0.1.6";
assert_eq!(actual, expected);
}
#[test]
fn should_get_name_from_cargo_toml() {
let cargo_toml = &get_cargo_toml("0.1.6");
let actual = get_name_from_cargo_toml(cargo_toml).unwrap();
let expected = "cargo-v";
assert_eq!(actual, expected);
}
#[test]
fn should_get_property_edition_from_cargo_toml() {
let cargo_toml = &get_cargo_toml("0.1.6");
let actual = get_prop_from_cargo_toml(&cargo_toml, "edition").unwrap();
let expected = "2021";
assert_eq!(actual, expected);
}
#[test]
fn should_get_version_from_cargo_lock() {
let cargo_toml = &get_cargo_toml("0.1.6");
let cargo_lock = &get_cargo_lock("0.1.6");
let actual = get_version_from_cargo_lock(cargo_lock, cargo_toml).unwrap();
let expected = "0.1.6";
assert_eq!(actual, expected);
}
#[test]
fn should_get_value_from_line_in_cargo_toml() {
let line = "version = \"1.1.1\"";
let actual = get_value_from_toml_line(line, "version");
let expected = "1.1.1";
assert_eq!(actual, expected);
}
#[test]
fn should_write_new_version_in_cargo_toml() {
let cargo_toml = get_cargo_toml("0.1.6");
let actual = set_version_in_cargo_toml(&cargo_toml, "0.1.7");
let expected = get_cargo_toml("0.1.7");
assert_eq!(actual, expected);
}
#[test]
fn should_write_new_version_in_cargo_lock() {
let cargo_toml = &get_cargo_toml("0.1.6");
let cargo_lock = get_cargo_lock("0.1.6");
let project_name = &get_name_from_cargo_toml(cargo_toml).unwrap();
let actual = set_version_in_cargo_lock(&cargo_lock, project_name, "0.1.7");
let expected = get_cargo_lock("0.1.7");
assert_eq!(actual, expected);
}
}