diff --git a/Cargo.toml b/Cargo.toml index 9bfd08e275..36273aeb57 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ members = [ "packages/fuels-test-helpers", "packages/wasm-tests", "scripts/check-docs", + "scripts/versions-replacer", ] [workspace.package] @@ -90,3 +91,6 @@ fuels-core = { version = "0.46.0", path = "./packages/fuels-core", default-featu fuels-macros = { version = "0.46.0", path = "./packages/fuels-macros", default-features = false } fuels-programs = { version = "0.46.0", path = "./packages/fuels-programs", default-features = false } fuels-test-helpers = { version = "0.46.0", path = "./packages/fuels-test-helpers", default-features = false } + +[workspace.metadata.versions-replacer.external-versions] +fuels-types = "0.35.3" diff --git a/docs/src/types/address.md b/docs/src/types/address.md index 31da7dadab..c95fed2014 100644 --- a/docs/src/types/address.md +++ b/docs/src/types/address.md @@ -1,6 +1,6 @@ # Address -Like `Bytes32`, `Address` is a wrapper on `[u8; 32]` with similar methods and implements the same traits (see [fuel-types documentation](https://docs.rs/fuel-types/{{versions.fuels_types}}/fuel_types/struct.Address.html)). +Like `Bytes32`, `Address` is a wrapper on `[u8; 32]` with similar methods and implements the same traits (see [fuel-types documentation](https://docs.rs/fuel-types/{{versions.fuels-types}}/fuel_types/struct.Address.html)). These are the main ways of creating an `Address`: diff --git a/docs/src/types/asset-id.md b/docs/src/types/asset-id.md index 387f3dc6dc..06aaf3ff77 100644 --- a/docs/src/types/asset-id.md +++ b/docs/src/types/asset-id.md @@ -1,6 +1,6 @@ # AssetId -Like `Bytes32`, `AssetId` is a wrapper on `[u8; 32]` with similar methods and implements the same traits (see [fuel-types documentation](https://docs.rs/fuel-types/{{versions.fuels_types}}/fuel_types/struct.AssetId.html)). +Like `Bytes32`, `AssetId` is a wrapper on `[u8; 32]` with similar methods and implements the same traits (see [fuel-types documentation](https://docs.rs/fuel-types/{{versions.fuels-types}}/fuel_types/struct.AssetId.html)). These are the main ways of creating an `AssetId`: diff --git a/docs/src/types/bytes32.md b/docs/src/types/bytes32.md index bdd6db05ef..e31e0d7757 100644 --- a/docs/src/types/bytes32.md +++ b/docs/src/types/bytes32.md @@ -14,6 +14,6 @@ These are the main ways of creating a `Bytes32`: {{#include ../../../examples/types/src/lib.rs:bytes32_format}} ``` -For a full list of implemented methods and traits, see the [fuel-types documentation](https://docs.rs/fuel-types/{{versions.fuels_types}}/fuel_types/struct.Bytes32.html). +For a full list of implemented methods and traits, see the [fuel-types documentation](https://docs.rs/fuel-types/{{versions.fuels-types}}/fuel_types/struct.Bytes32.html). > **Note:** In Fuel, there's a special type called `b256`, which is similar to `Bytes32`; also used to represent hashes, and it holds a 256-bit value. In Rust, through the SDK, this is represented as `Bits256(value)` where `value` is a `[u8; 32]`. If your contract method takes a `b256` as input, all you need to do is pass a `Bits256([u8; 32])` when calling it from the SDK. diff --git a/docs/src/types/contract-id.md b/docs/src/types/contract-id.md index 84b65e248b..76516b0b00 100644 --- a/docs/src/types/contract-id.md +++ b/docs/src/types/contract-id.md @@ -1,6 +1,6 @@ # ContractId -Like `Bytes32`, `ContractId` is a wrapper on `[u8; 32]` with similar methods and implements the same traits (see [fuel-types documentation](https://docs.rs/fuel-types/{{versions.fuels_types}}/fuel_types/struct.ContractId.html)). +Like `Bytes32`, `ContractId` is a wrapper on `[u8; 32]` with similar methods and implements the same traits (see [fuel-types documentation](https://docs.rs/fuel-types/{{versions.fuels-types}}/fuel_types/struct.ContractId.html)). These are the main ways of creating a `ContractId`: diff --git a/scripts/versions-replacer/Cargo.toml b/scripts/versions-replacer/Cargo.toml new file mode 100644 index 0000000000..2bd80128e1 --- /dev/null +++ b/scripts/versions-replacer/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "versions-replacer" +publish = false +authors.workspace = true +edition.workspace = true +homepage.workspace = true +readme.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true +version.workspace = true + +[dependencies] +argh = "0.1.12" +cargo_metadata = "0.17.0" +color-eyre = "0.6.2" +once_cell = "1.18.0" +regex = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +walkdir = "2.3.3" diff --git a/scripts/versions-replacer/src/lib.rs b/scripts/versions-replacer/src/lib.rs new file mode 100644 index 0000000000..b019f47b1c --- /dev/null +++ b/scripts/versions-replacer/src/lib.rs @@ -0,0 +1,2 @@ +pub mod metadata; +pub mod replace; diff --git a/scripts/versions-replacer/src/main.rs b/scripts/versions-replacer/src/main.rs new file mode 100644 index 0000000000..327353d8c2 --- /dev/null +++ b/scripts/versions-replacer/src/main.rs @@ -0,0 +1,55 @@ +use std::path::PathBuf; + +use argh::FromArgs; +use color_eyre::{ + eyre::{eyre, Context}, + Result, +}; +use regex::Regex; +use walkdir::WalkDir; + +use versions_replacer::{ + metadata::collect_versions_from_cargo_toml, replace::replace_versions_in_file, +}; + +#[derive(FromArgs)] +/// Replace variables like '{{{{versions.fuels}}}}' with correct versions from Cargo.toml. +/// Uses versions from '[workspace.members]' and '[workspace.metadata.versions-replacer.external-versions]'. +struct VersionsReplacer { + /// path to directory with files containing variables + #[argh(positional)] + path: PathBuf, + /// path to Cargo.toml with versions + #[argh(option)] + manifest_path: PathBuf, + /// regex to filter filenames (example: "\.md$") + #[argh(option)] + filename_regex: Option, +} + +fn main() -> Result<()> { + let args: VersionsReplacer = argh::from_env(); + let versions = collect_versions_from_cargo_toml(&args.manifest_path)?; + + for entry in WalkDir::new(&args.path) { + let entry = entry.wrap_err("failed to get directory entry")?; + + if entry.path().is_file() { + if let Some(filename_regex) = &args.filename_regex { + let file_name = entry + .path() + .file_name() + .ok_or_else(|| eyre!("{:?} has an invalid file name", entry.path()))? + .to_str() + .ok_or_else(|| eyre!("filename is not valid UTF-8"))?; + if !filename_regex.is_match(file_name) { + continue; + } + } + + replace_versions_in_file(entry.path(), &versions) + .wrap_err_with(|| format!("failed to replace versions in {:?}", entry.path()))?; + } + } + Ok(()) +} diff --git a/scripts/versions-replacer/src/metadata.rs b/scripts/versions-replacer/src/metadata.rs new file mode 100644 index 0000000000..878c3fd941 --- /dev/null +++ b/scripts/versions-replacer/src/metadata.rs @@ -0,0 +1,42 @@ +use std::{collections::HashMap, path::Path}; + +use cargo_metadata::MetadataCommand; +use color_eyre::{eyre::Context, Result}; +use serde::Deserialize; + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub struct WorkspaceMetadata { + pub versions_replacer: VersionsReplacerMetadata, +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub struct VersionsReplacerMetadata { + pub external_versions: HashMap, +} + +pub fn collect_versions_from_cargo_toml( + manifest_path: impl AsRef, +) -> Result> { + let metadata = MetadataCommand::new() + .manifest_path(manifest_path.as_ref()) + .exec() + .wrap_err("failed to execute 'cargo metadata'")?; + let version_map = metadata + .workspace_members + .iter() + .map(|package_id| { + let package = &metadata[package_id]; + (package.name.clone(), package.version.to_string()) + }) + .chain( + serde_json::from_value::(metadata.workspace_metadata.clone()) + .wrap_err("failed to parse '[workspace.metadata]'")? + .versions_replacer + .external_versions + .into_iter(), + ) + .collect::>(); + Ok(version_map) +} diff --git a/scripts/versions-replacer/src/replace.rs b/scripts/versions-replacer/src/replace.rs new file mode 100644 index 0000000000..5ae46acca2 --- /dev/null +++ b/scripts/versions-replacer/src/replace.rs @@ -0,0 +1,22 @@ +use std::{collections::HashMap, fs, path::Path}; + +use color_eyre::{eyre::Context, Result}; +use once_cell::sync::Lazy; +use regex::{Captures, Regex}; + +pub static VERSIONS_REGEX: Lazy = + Lazy::new(|| Regex::new(r"\{\{versions\.([\w_-]+)\}\}").unwrap()); + +pub fn replace_versions_in_file( + path: impl AsRef, + versions: &HashMap, +) -> Result<()> { + let path = path.as_ref(); + let contents = + fs::read_to_string(path).wrap_err_with(|| format!("failed to read {:?}", path))?; + let replaced_contents = + VERSIONS_REGEX.replace_all(&contents, |caps: &Captures| &versions[&caps[1]]); + fs::write(path, replaced_contents.as_bytes()) + .wrap_err_with(|| format!("failed to write back to {:?}", path))?; + Ok(()) +}