cairo_toolchain_xtasks/
sync_version.rs

1//! Synchronise this crate's version with the `cairo-lang-*` crates.
2
3use anyhow::{Result, ensure};
4use clap::Parser;
5use semver::{Prerelease, Version};
6use toml_edit::{DocumentMut, value};
7use xshell::{Shell, cmd};
8
9/// Synchronise this crate's version with the `cairo-lang-*` crates.
10#[derive(Default, Parser)]
11pub struct Args {
12    /// Do not edit any files, just inform what would be done.
13    #[arg(long, default_value_t = false)]
14    pub dry_run: bool,
15
16    /// Set a custom value for the `build` metadata.
17    #[arg(long)]
18    pub build: Option<String>,
19
20    /// Clear the pre-release identifier from the version.
21    #[arg(long, default_value_t = false)]
22    pub no_pre_release: bool,
23}
24
25pub fn main(args: Args) -> Result<()> {
26    let sh = Shell::new()?;
27
28    let mut cargo_toml = sh.read_file("Cargo.toml")?.parse::<DocumentMut>()?;
29
30    let (package, table_path) = if let Some(workspace_package) = cargo_toml
31        .get_mut("workspace")
32        .and_then(|t| t.get_mut("package"))
33        .and_then(|t| t.as_table_mut())
34    {
35        (workspace_package, "workspace.package")
36    } else {
37        (cargo_toml["package"].as_table_mut().unwrap(), "package")
38    };
39
40    let mut version = expected_version()?;
41
42    if let Some(build) = args.build {
43        version.build = build.parse()?;
44    }
45    if args.no_pre_release {
46        version.pre = Prerelease::EMPTY;
47    }
48
49    package["version"] = value(version.to_string());
50
51    eprintln!("[{table_path}]\n{package}");
52
53    if !args.dry_run {
54        sh.write_file("Cargo.toml", cargo_toml.to_string())?;
55
56        cmd!(sh, "cargo fetch").run()?;
57    }
58
59    Ok(())
60}
61
62/// Gets the version of the `cairo-lang-compiler` crate from `Cargo.lock`, which is the expected
63/// version for the crate this script is being run on.
64pub fn expected_version() -> Result<Version> {
65    // NOTE: We are deliberately not using cargo_metadata to reduce build times of xtasks.
66
67    let sh = Shell::new()?;
68    let cargo_lock = sh.read_file("Cargo.lock")?.parse::<DocumentMut>()?;
69    let packages = cargo_lock["package"].as_array_of_tables().unwrap();
70    let compiler = {
71        let pkgs = packages
72            .into_iter()
73            .filter(|pkg| pkg["name"].as_str().unwrap() == "cairo-lang-compiler")
74            .collect::<Vec<_>>();
75        ensure!(
76            pkgs.len() == 1,
77            "expected exactly one cairo-lang-compiler package in Cargo.lock, found: {}",
78            pkgs.len()
79        );
80        pkgs.into_iter().next().unwrap()
81    };
82    let compiler_version = compiler["version"].as_str().unwrap();
83    Ok(compiler_version.parse()?)
84}