diff options
author | Côme ALLART <come.allart@etu.emse.fr> | 2021-08-27 11:09:27 +0200 |
---|---|---|
committer | Côme ALLART <come.allart@etu.emse.fr> | 2021-08-27 11:09:27 +0200 |
commit | 022b8092485c39cd68ad4e259ced5253b8a59460 (patch) | |
tree | 5f46664ba3947af8513e6ef63ca99a99db81c7b8 /stm32-gen-features | |
parent | 1e1cd0506aa655456d7cbf7d6915b46abf7829e5 (diff) | |
download | embassy-022b8092485c39cd68ad4e259ced5253b8a59460.zip |
refactor(gen_features): use Rust instead of Python
Done for /embassy-stm32 only
The new generator is in /stm32-gen-features
/stm32-metapac could/should be added too
A CI check "generated features up to date" could/should be performed
Diffstat (limited to 'stm32-gen-features')
-rw-r--r-- | stm32-gen-features/.cargo/config.toml | 3 | ||||
-rw-r--r-- | stm32-gen-features/.gitignore | 1 | ||||
-rw-r--r-- | stm32-gen-features/Cargo.toml | 12 | ||||
-rw-r--r-- | stm32-gen-features/src/lib.rs | 177 | ||||
-rw-r--r-- | stm32-gen-features/src/main.rs | 18 |
5 files changed, 211 insertions, 0 deletions
diff --git a/stm32-gen-features/.cargo/config.toml b/stm32-gen-features/.cargo/config.toml new file mode 100644 index 00000000..17d81c14 --- /dev/null +++ b/stm32-gen-features/.cargo/config.toml @@ -0,0 +1,3 @@ +[profile.dev] +opt-level = 3 +lto = false diff --git a/stm32-gen-features/.gitignore b/stm32-gen-features/.gitignore new file mode 100644 index 00000000..ea8c4bf7 --- /dev/null +++ b/stm32-gen-features/.gitignore @@ -0,0 +1 @@ +/target diff --git a/stm32-gen-features/Cargo.toml b/stm32-gen-features/Cargo.toml new file mode 100644 index 00000000..1b8f7951 --- /dev/null +++ b/stm32-gen-features/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "gen_features" +version = "0.1.0" +authors = ["Côme ALLART <come.allart@netc.fr>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +glob = "0.3.0" +yaml-rust = "0.4.5" +toml = "0.5.8" diff --git a/stm32-gen-features/src/lib.rs b/stm32-gen-features/src/lib.rs new file mode 100644 index 00000000..b20a1ba4 --- /dev/null +++ b/stm32-gen-features/src/lib.rs @@ -0,0 +1,177 @@ +use std::{ + collections::HashMap, + path::{Path, PathBuf}, +}; + +const SUPPORTED_FAMILIES: [&str; 8] = [ + "STM32F0", + "STM32F4", + "STM32G0", + "STM32L0", + "STM32L4", + "STM32H7", + "STM32WB55", + "STM32WL55", +]; + +const SEPARATOR_START: &str = "# BEGIN GENERATED FEATURES\n"; +const SEPARATOR_END: &str = "# END GENERATED FEATURES\n"; +const HELP: &str = "# Generated by stm32-gen-features. DO NOT EDIT.\n"; + +/// True if the chip named `name` is supported else false +fn is_supported(name: &str) -> bool { + SUPPORTED_FAMILIES + .iter() + .any(|family| name.starts_with(family)) +} + +/// Get the yaml file names and the associated chip names for supported chips +/// +/// Print errors to `stderr` when something is returned by the glob but is not in the returned +/// [`Vec`] +fn supported_chip_yaml_files_with_names() -> Vec<(PathBuf, String)> { + glob::glob("../stm32-data/data/chips/*.yaml") + .expect("bad glob pattern") + .filter_map(|entry| entry.map_err(|e| eprintln!("{:?}", e)).ok()) + .filter_map(|entry| { + if let Some(name) = entry.file_stem().and_then(|stem| stem.to_str()) { + if is_supported(name) { + let owned_name = name.to_lowercase(); + Some((entry, owned_name)) + } else { + eprintln!("{} is not supported", name); + None + } + } else { + eprintln!("{:?} is not a regural file", entry); + None + } + }) + .collect() +} + +/// Get the list of the cores of a chip by its associated file +/// +/// # Panic +/// Panics if the file does not exist or if it contains yaml syntax errors +/// +/// # None +/// Returns none if "cores" is not an array +fn chip_cores(path: &Path) -> Option<Vec<yaml_rust::Yaml>> { + let file_contents = std::fs::read_to_string(path).unwrap(); + let doc = &yaml_rust::YamlLoader::load_from_str(&file_contents).unwrap()[0]; + doc["cores"].as_vec().cloned() +} + +/// Load the list of chips +/// +/// # Panic +/// Panics if a file contains yaml syntax errors or if a value does not have a consistent type +pub fn load_chip_list() -> HashMap<String, Vec<String>> { + let mut result = HashMap::new(); + for (path, name) in supported_chip_yaml_files_with_names() { + let cores = chip_cores(&path).unwrap_or_else(|| panic!("{}[cores] is not an array", name)); + if cores.len() > 1 { + for (i, core) in cores.into_iter().enumerate() { + let core_name = core["name"] + .as_str() + .unwrap_or_else(|| panic!("{}[cores][{}][name] is not a string", name, i)); + let key = format!("{}_{}", name, core_name); + let value = vec![format!("stm32-metapac/{}_{}", name, core_name)]; + result.insert(key, value); + } + } else { + let value = vec![format!("stm32-metapac/{}", &name)]; + result.insert(name, value); + } + } + result +} + +/// Get contents before and after generated contents +/// +/// # Panic +/// Panics when a separator cound not be not found +fn split_cargo_toml_contents(contents: &str) -> (&str, &str) { + let (before, remainder) = contents + .split_once(SEPARATOR_START) + .unwrap_or_else(|| panic!("missing \"{}\" tag", SEPARATOR_START)); + let (_, after) = remainder + .split_once(SEPARATOR_END) + .unwrap_or_else(|| panic!("missing \"{}\" tag", SEPARATOR_END)); + + (before, after) +} + +/// Generates new contents for Cargo.toml +/// +/// # Panic +/// Panics when a separator cound not be not found +pub fn generate_cargo_toml_file( + previous_text: &str, + new_contents: &HashMap<String, Vec<String>>, +) -> String { + let (before, after) = split_cargo_toml_contents(previous_text); + let generated_content = toml::to_string(new_contents).unwrap(); + before.to_owned() + SEPARATOR_START + HELP + &generated_content + SEPARATOR_END + after +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn stm32f407vg_is_supported() { + assert!(is_supported("STM32F407VG")) + } + + #[test] + fn abcdef_is_not_supported() { + assert!(!is_supported("ABCDEF")) + } + + #[test] + fn stm32f407vg_yaml_file_exists() { + assert!(supported_chip_yaml_files_with_names() + .into_iter() + .any(|(path, name)| { + name == "stm32f407vg" + && path.to_str() == Some("../stm32-data/data/chips/STM32F407VG.yaml") + })) + } + + #[test] + fn keeps_text_around_separators() { + let initial = "\ +before +# BEGIN GENERATED FEATURES +# END GENERATED FEATURES +after +"; + + let expected = "\ +before +# BEGIN GENERATED FEATURES +# Generated by stm32-gen-features. DO NOT EDIT. +a = [\"b\"] +# END GENERATED FEATURES +after +"; + + let map = HashMap::from([(String::from("a"), vec![String::from("b")])]); + assert_eq!(generate_cargo_toml_file(initial, &map), expected); + } + + #[test] + #[should_panic] + fn does_not_generate_if_separators_are_missing() { + let initial = "\ +before +# END GENERATED FEATURES +after +"; + + let map = HashMap::from([(String::from("a"), vec![String::from("b")])]); + generate_cargo_toml_file(initial, &map); + } +} diff --git a/stm32-gen-features/src/main.rs b/stm32-gen-features/src/main.rs new file mode 100644 index 00000000..9f1d8ef3 --- /dev/null +++ b/stm32-gen-features/src/main.rs @@ -0,0 +1,18 @@ +use std::collections::HashMap; + +use gen_features::{generate_cargo_toml_file, load_chip_list}; + +fn main() { + let chip_list = load_chip_list(); + update_cargo_file("../embassy-stm32/Cargo.toml", &chip_list); +} + +/// Update a Cargo.toml file +/// +/// Update the content between "# BEGIN GENERATED FEATURES" and "# END GENERATED FEATURES" +/// with the given content +fn update_cargo_file(path: &str, new_contents: &HashMap<String, Vec<String>>) { + let previous_text = std::fs::read_to_string(path).unwrap(); + let new_text = generate_cargo_toml_file(&previous_text, new_contents); + std::fs::write(path, new_text).unwrap(); +} |