use std::env::current_dir;
use std::fs::{read_to_string, OpenOptions};
use std::io::Write;
use std::path::PathBuf;
use std::process::{Command, Stdio};
use anyhow::Result;
use semver::Version as SemVer;
use serde::Deserialize;
use crate::version::Version;
const CARGO_TOML: &str = "Cargo.toml";
#[derive(Debug, Default)]
pub struct Metadata {
path: PathBuf,
}
#[derive(Debug, Deserialize)]
pub struct CargoToml {
#[serde(flatten)]
pub(crate) manifest: Manifest,
#[serde(skip_deserializing)]
pub(crate) meta: Metadata,
}
#[derive(Debug, Deserialize)]
pub enum Manifest {
#[serde(rename = "package")]
Package(Package),
#[serde(rename = "workspace")]
Workspace { package: Package },
}
impl Manifest {
pub fn package(&self) -> &Package {
match self {
Manifest::Package(package) => package,
Manifest::Workspace { package } => package,
}
}
}
#[derive(Debug, Deserialize)]
pub struct Package {
pub(crate) version: SemVer,
}
impl CargoToml {
pub fn open() -> Result<Self> {
let mut path = current_dir()?;
path.push(CARGO_TOML);
let file = read_to_string(&path)?;
let mut package: CargoToml = toml::from_str(&file)?;
package.meta.path = path;
Ok(package)
}
pub fn write_version(&self, version: &Version) -> Result<()> {
let file_str = read_to_string(&self.meta.path)?;
let mut document = file_str.parse::<toml_edit::DocumentMut>()?;
match self.manifest {
Manifest::Package(_) => {
document["package"]["version"] = toml_edit::value(version.ver.to_string());
}
Manifest::Workspace { .. } => {
document["workspace"]["package"]["version"] =
toml_edit::value(version.ver.to_string());
}
}
let mut file = OpenOptions::new()
.write(true)
.truncate(true)
.open(&self.meta.path)?;
file.write_all(document.to_string().as_bytes())?;
Ok(())
}
pub fn run_cargo_fetch(&self) -> Result<()> {
let mut cmd = Command::new("cargo");
cmd.arg("fetch");
cmd.stderr(Stdio::inherit());
cmd.status()?;
Ok(())
}
}