diff --git a/.cargo/config.toml b/.cargo/config.toml index fdb297c0..556f371b 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,3 +1,4 @@ [alias] lint = "clippy --all-targets --all-features -- --no-deps" docs = "doc --all-features --no-deps" +xtask = "run --quiet --package xtask --" diff --git a/Cargo.lock b/Cargo.lock index 1e72afe2..8414f667 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -776,6 +776,46 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clap" +version = "4.5.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "clap_lex" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" + [[package]] name = "colorchoice" version = "1.0.3" @@ -1257,6 +1297,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "home" version = "0.5.9" @@ -2166,7 +2212,7 @@ version = "0.17.0-pre.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d96498e9684848c6676c399032ebc37c52da95ecbefa83d71ccc53b9f8a4a8e" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "syn 2.0.89", @@ -2464,6 +2510,12 @@ dependencies = [ "precomputed-hash", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "1.0.109" @@ -3130,6 +3182,17 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32ac00cd3f8ec9c1d33fb3e7958a82df6989c42d747bd326c822b1d625283547" +[[package]] +name = "xtask" +version = "1.0.0" +dependencies = [ + "anyhow", + "clap", + "semver", + "toml_edit", + "xshell", +] + [[package]] name = "xxhash-rust" version = "0.8.12" diff --git a/Cargo.toml b/Cargo.toml index 21cdc12f..ac3d5d19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,9 @@ description = "The Cairo Language Server" license = "Apache-2.0" repository = "https://github.com/software-mansion/cairols" +[workspace] +members = ["xtask"] + [features] testing = [] diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml new file mode 100644 index 00000000..86867311 --- /dev/null +++ b/xtask/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "xtask" +version = "1.0.0" +edition = "2021" + +[dependencies] +anyhow = "1" +clap = { version = "4.5", features = ["derive"] } +semver = "1" +toml_edit = "0.22.22" +xshell = "0.2.7" diff --git a/xtask/src/main.rs b/xtask/src/main.rs new file mode 100644 index 00000000..e6cd3c9b --- /dev/null +++ b/xtask/src/main.rs @@ -0,0 +1,34 @@ +use anyhow::Result; +use clap::Parser; + +macro_rules! command { + ($enum_name:ident ( $($module:ident,)+ )) => { + $(mod $module;)+ + + #[derive(::clap::Subcommand)] + #[allow(non_camel_case_types)] + enum $enum_name { + $($module(crate::$module::Args),)+ + } + + impl $enum_name { + fn main(self) -> ::anyhow::Result<()> { + match self { + $(Self::$module(args) => crate::$module::main(args),)+ + } + } + } + } +} + +command!(Command(set_version,)); + +#[derive(Parser)] +struct Args { + #[command(subcommand)] + command: Command, +} + +fn main() -> Result<()> { + Args::parse().command.main() +} diff --git a/xtask/src/set_version.rs b/xtask/src/set_version.rs new file mode 100644 index 00000000..44d8cc98 --- /dev/null +++ b/xtask/src/set_version.rs @@ -0,0 +1,71 @@ +use anyhow::{Result, ensure}; +use clap::Parser; +use semver::{Prerelease, Version}; +use toml_edit::{DocumentMut, value}; +use xshell::{Shell, cmd}; + +pub fn expected_version() -> Result { + // NOTE: We are deliberately not using cargo_metadata to reduce build times of xtasks. + + let sh = Shell::new()?; + let cargo_lock = sh.read_file("Cargo.lock")?.parse::()?; + let packages = cargo_lock["package"].as_array_of_tables().unwrap(); + let compiler = { + let pkgs = packages + .into_iter() + .filter(|pkg| pkg["name"].as_str().unwrap() == "cairo-lang-compiler") + .collect::>(); + ensure!( + pkgs.len() == 1, + "expected exactly one cairo-lang-compiler package in Cargo.lock, found: {}", + pkgs.len() + ); + pkgs.into_iter().next().unwrap() + }; + let compiler_version = compiler["version"].as_str().unwrap(); + Ok(compiler_version.parse()?) +} + +/// Synchronise the `cairo-language-server` crate version with the `cairo-lang-*` crates. +#[derive(Default, Parser)] +pub struct Args { + /// Do not edit any files, just inform what would be done. + #[arg(long, default_value_t = false)] + pub dry_run: bool, + + /// Set a custom value for the `build` metadata. + #[arg(long)] + pub build: Option, + + /// Clear the pre-release identifier from the version. + #[arg(long, default_value_t = false)] + pub no_pre_release: bool, +} + +pub fn main(args: Args) -> Result<()> { + let sh = Shell::new()?; + + let mut cargo_toml = sh.read_file("Cargo.toml")?.parse::()?; + let package = cargo_toml["package"].as_table_mut().unwrap(); + + let mut version = expected_version()?; + + if let Some(build) = args.build { + version.build = build.parse()?; + } + if args.no_pre_release { + version.pre = Prerelease::EMPTY; + } + + package["version"] = value(version.to_string()); + + eprintln!("[package]\n{package}"); + + if !args.dry_run { + sh.write_file("Cargo.toml", cargo_toml.to_string())?; + + cmd!(sh, "cargo fetch").run()?; + } + + Ok(()) +}