aboutsummaryrefslogtreecommitdiff
path: root/stm32-gen-features/src
diff options
context:
space:
mode:
authorCôme ALLART <[email protected]>2021-08-27 11:09:27 +0200
committerCôme ALLART <[email protected]>2021-08-27 11:09:27 +0200
commit022b8092485c39cd68ad4e259ced5253b8a59460 (patch)
tree5f46664ba3947af8513e6ef63ca99a99db81c7b8 /stm32-gen-features/src
parent1e1cd0506aa655456d7cbf7d6915b46abf7829e5 (diff)
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/src')
-rw-r--r--stm32-gen-features/src/lib.rs177
-rw-r--r--stm32-gen-features/src/main.rs18
2 files changed, 195 insertions, 0 deletions
diff --git a/stm32-gen-features/src/lib.rs b/stm32-gen-features/src/lib.rs
new file mode 100644
index 000000000..b20a1ba4a
--- /dev/null
+++ b/stm32-gen-features/src/lib.rs
@@ -0,0 +1,177 @@
1use std::{
2 collections::HashMap,
3 path::{Path, PathBuf},
4};
5
6const SUPPORTED_FAMILIES: [&str; 8] = [
7 "STM32F0",
8 "STM32F4",
9 "STM32G0",
10 "STM32L0",
11 "STM32L4",
12 "STM32H7",
13 "STM32WB55",
14 "STM32WL55",
15];
16
17const SEPARATOR_START: &str = "# BEGIN GENERATED FEATURES\n";
18const SEPARATOR_END: &str = "# END GENERATED FEATURES\n";
19const HELP: &str = "# Generated by stm32-gen-features. DO NOT EDIT.\n";
20
21/// True if the chip named `name` is supported else false
22fn is_supported(name: &str) -> bool {
23 SUPPORTED_FAMILIES
24 .iter()
25 .any(|family| name.starts_with(family))
26}
27
28/// Get the yaml file names and the associated chip names for supported chips
29///
30/// Print errors to `stderr` when something is returned by the glob but is not in the returned
31/// [`Vec`]
32fn supported_chip_yaml_files_with_names() -> Vec<(PathBuf, String)> {
33 glob::glob("../stm32-data/data/chips/*.yaml")
34 .expect("bad glob pattern")
35 .filter_map(|entry| entry.map_err(|e| eprintln!("{:?}", e)).ok())
36 .filter_map(|entry| {
37 if let Some(name) = entry.file_stem().and_then(|stem| stem.to_str()) {
38 if is_supported(name) {
39 let owned_name = name.to_lowercase();
40 Some((entry, owned_name))
41 } else {
42 eprintln!("{} is not supported", name);
43 None
44 }
45 } else {
46 eprintln!("{:?} is not a regural file", entry);
47 None
48 }
49 })
50 .collect()
51}
52
53/// Get the list of the cores of a chip by its associated file
54///
55/// # Panic
56/// Panics if the file does not exist or if it contains yaml syntax errors
57///
58/// # None
59/// Returns none if "cores" is not an array
60fn chip_cores(path: &Path) -> Option<Vec<yaml_rust::Yaml>> {
61 let file_contents = std::fs::read_to_string(path).unwrap();
62 let doc = &yaml_rust::YamlLoader::load_from_str(&file_contents).unwrap()[0];
63 doc["cores"].as_vec().cloned()
64}
65
66/// Load the list of chips
67///
68/// # Panic
69/// Panics if a file contains yaml syntax errors or if a value does not have a consistent type
70pub fn load_chip_list() -> HashMap<String, Vec<String>> {
71 let mut result = HashMap::new();
72 for (path, name) in supported_chip_yaml_files_with_names() {
73 let cores = chip_cores(&path).unwrap_or_else(|| panic!("{}[cores] is not an array", name));
74 if cores.len() > 1 {
75 for (i, core) in cores.into_iter().enumerate() {
76 let core_name = core["name"]
77 .as_str()
78 .unwrap_or_else(|| panic!("{}[cores][{}][name] is not a string", name, i));
79 let key = format!("{}_{}", name, core_name);
80 let value = vec![format!("stm32-metapac/{}_{}", name, core_name)];
81 result.insert(key, value);
82 }
83 } else {
84 let value = vec![format!("stm32-metapac/{}", &name)];
85 result.insert(name, value);
86 }
87 }
88 result
89}
90
91/// Get contents before and after generated contents
92///
93/// # Panic
94/// Panics when a separator cound not be not found
95fn split_cargo_toml_contents(contents: &str) -> (&str, &str) {
96 let (before, remainder) = contents
97 .split_once(SEPARATOR_START)
98 .unwrap_or_else(|| panic!("missing \"{}\" tag", SEPARATOR_START));
99 let (_, after) = remainder
100 .split_once(SEPARATOR_END)
101 .unwrap_or_else(|| panic!("missing \"{}\" tag", SEPARATOR_END));
102
103 (before, after)
104}
105
106/// Generates new contents for Cargo.toml
107///
108/// # Panic
109/// Panics when a separator cound not be not found
110pub fn generate_cargo_toml_file(
111 previous_text: &str,
112 new_contents: &HashMap<String, Vec<String>>,
113) -> String {
114 let (before, after) = split_cargo_toml_contents(previous_text);
115 let generated_content = toml::to_string(new_contents).unwrap();
116 before.to_owned() + SEPARATOR_START + HELP + &generated_content + SEPARATOR_END + after
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn stm32f407vg_is_supported() {
125 assert!(is_supported("STM32F407VG"))
126 }
127
128 #[test]
129 fn abcdef_is_not_supported() {
130 assert!(!is_supported("ABCDEF"))
131 }
132
133 #[test]
134 fn stm32f407vg_yaml_file_exists() {
135 assert!(supported_chip_yaml_files_with_names()
136 .into_iter()
137 .any(|(path, name)| {
138 name == "stm32f407vg"
139 && path.to_str() == Some("../stm32-data/data/chips/STM32F407VG.yaml")
140 }))
141 }
142
143 #[test]
144 fn keeps_text_around_separators() {
145 let initial = "\
146before
147# BEGIN GENERATED FEATURES
148# END GENERATED FEATURES
149after
150";
151
152 let expected = "\
153before
154# BEGIN GENERATED FEATURES
155# Generated by stm32-gen-features. DO NOT EDIT.
156a = [\"b\"]
157# END GENERATED FEATURES
158after
159";
160
161 let map = HashMap::from([(String::from("a"), vec![String::from("b")])]);
162 assert_eq!(generate_cargo_toml_file(initial, &map), expected);
163 }
164
165 #[test]
166 #[should_panic]
167 fn does_not_generate_if_separators_are_missing() {
168 let initial = "\
169before
170# END GENERATED FEATURES
171after
172";
173
174 let map = HashMap::from([(String::from("a"), vec![String::from("b")])]);
175 generate_cargo_toml_file(initial, &map);
176 }
177}
diff --git a/stm32-gen-features/src/main.rs b/stm32-gen-features/src/main.rs
new file mode 100644
index 000000000..9f1d8ef34
--- /dev/null
+++ b/stm32-gen-features/src/main.rs
@@ -0,0 +1,18 @@
1use std::collections::HashMap;
2
3use gen_features::{generate_cargo_toml_file, load_chip_list};
4
5fn main() {
6 let chip_list = load_chip_list();
7 update_cargo_file("../embassy-stm32/Cargo.toml", &chip_list);
8}
9
10/// Update a Cargo.toml file
11///
12/// Update the content between "# BEGIN GENERATED FEATURES" and "# END GENERATED FEATURES"
13/// with the given content
14fn update_cargo_file(path: &str, new_contents: &HashMap<String, Vec<String>>) {
15 let previous_text = std::fs::read_to_string(path).unwrap();
16 let new_text = generate_cargo_toml_file(&previous_text, new_contents);
17 std::fs::write(path, new_text).unwrap();
18}