aboutsummaryrefslogtreecommitdiff
path: root/release/src
diff options
context:
space:
mode:
Diffstat (limited to 'release/src')
-rw-r--r--release/src/build.rs4
-rw-r--r--release/src/cargo.rs9
-rw-r--r--release/src/main.rs130
-rw-r--r--release/src/types.rs9
4 files changed, 114 insertions, 38 deletions
diff --git a/release/src/build.rs b/release/src/build.rs
index d1abb2aa1..7c777d36c 100644
--- a/release/src/build.rs
+++ b/release/src/build.rs
@@ -34,6 +34,10 @@ pub(crate) fn build(ctx: &crate::Context, crate_name: Option<&str>) -> Result<()
34 args_builder = args_builder.features(&config.features); 34 args_builder = args_builder.features(&config.features);
35 } 35 }
36 36
37 if let Some(ref artifact_dir) = config.artifact_dir {
38 args_builder = args_builder.artifact_dir(artifact_dir);
39 }
40
37 batch_builder.add_command(args_builder.build()); 41 batch_builder.add_command(args_builder.build());
38 } 42 }
39 } 43 }
diff --git a/release/src/cargo.rs b/release/src/cargo.rs
index 0b28458e9..826a3a8b2 100644
--- a/release/src/cargo.rs
+++ b/release/src/cargo.rs
@@ -149,6 +149,15 @@ impl CargoArgsBuilder {
149 } 149 }
150 150
151 #[must_use] 151 #[must_use]
152 pub fn artifact_dir<S>(mut self, artifact_dir: S) -> Self
153 where
154 S: Into<String>,
155 {
156 self.args.push(format!("--artifact-dir={}", artifact_dir.into()));
157 self
158 }
159
160 #[must_use]
152 pub fn arg<S>(mut self, arg: S) -> Self 161 pub fn arg<S>(mut self, arg: S) -> Self
153 where 162 where
154 S: Into<String>, 163 S: Into<String>,
diff --git a/release/src/main.rs b/release/src/main.rs
index b1bc17255..5605ca332 100644
--- a/release/src/main.rs
+++ b/release/src/main.rs
@@ -3,7 +3,7 @@ use std::fs;
3use std::path::{Path, PathBuf}; 3use std::path::{Path, PathBuf};
4use std::process::Command as ProcessCommand; 4use std::process::Command as ProcessCommand;
5 5
6use anyhow::{anyhow, Result}; 6use anyhow::{anyhow, bail, Result};
7use clap::{Parser, Subcommand}; 7use clap::{Parser, Subcommand};
8use log::info; 8use log::info;
9use petgraph::graph::{Graph, NodeIndex}; 9use petgraph::graph::{Graph, NodeIndex};
@@ -13,6 +13,25 @@ use simple_logger::SimpleLogger;
13use toml_edit::{DocumentMut, Item, Value}; 13use toml_edit::{DocumentMut, Item, Value};
14use types::*; 14use types::*;
15 15
16fn check_publish_dependencies(ctx: &Context) -> Result<()> {
17 for krate in ctx.crates.values() {
18 if krate.publish {
19 for dep_name in &krate.dependencies {
20 if let Some(dep_crate) = ctx.crates.get(dep_name) {
21 if !dep_crate.publish {
22 return Err(anyhow!(
23 "Publishable crate '{}' depends on non-publishable crate '{}'. This is not allowed.",
24 krate.name,
25 dep_name
26 ));
27 }
28 }
29 }
30 }
31 }
32 Ok(())
33}
34
16mod build; 35mod build;
17mod cargo; 36mod cargo;
18mod semver_check; 37mod semver_check;
@@ -56,7 +75,7 @@ enum Command {
56 }, 75 },
57 /// SemverCheck 76 /// SemverCheck
58 SemverCheck { 77 SemverCheck {
59 /// Crate to check. Will traverse that crate an it's dependents. If not specified checks all crates. 78 /// Specific crate name to check
60 #[arg(value_name = "CRATE")] 79 #[arg(value_name = "CRATE")]
61 crate_name: String, 80 crate_name: String,
62 }, 81 },
@@ -120,53 +139,72 @@ fn update_versions(to_update: &Crate, dep: &CrateId, new_version: &str) -> Resul
120} 139}
121 140
122fn list_crates(root: &PathBuf) -> Result<BTreeMap<CrateId, Crate>> { 141fn list_crates(root: &PathBuf) -> Result<BTreeMap<CrateId, Crate>> {
123 let d = std::fs::read_dir(root)?;
124 let mut crates = BTreeMap::new(); 142 let mut crates = BTreeMap::new();
143 discover_crates(root, &mut crates)?;
144 Ok(crates)
145}
146
147fn discover_crates(dir: &PathBuf, crates: &mut BTreeMap<CrateId, Crate>) -> Result<()> {
148 let d = std::fs::read_dir(dir)?;
125 for c in d { 149 for c in d {
126 let entry = c?; 150 let entry = c?;
127 if entry.file_type()?.is_dir() { 151 if entry.file_type()?.is_dir() {
128 let path = root.join(entry.path()); 152 let path = dir.join(entry.path());
129 let entry = path.join("Cargo.toml"); 153 let cargo_toml = path.join("Cargo.toml");
130 if entry.exists() {
131 let content = fs::read_to_string(&entry)?;
132 let parsed: ParsedCrate = toml::from_str(&content)?;
133 let id = parsed.package.name;
134 154
135 let metadata = &parsed.package.metadata.embassy; 155 if cargo_toml.exists() {
156 let content = fs::read_to_string(&cargo_toml)?;
136 157
137 if metadata.skip { 158 // Try to parse as a crate, skip if it's a workspace
138 continue; 159 let parsed: Result<ParsedCrate, _> = toml::from_str(&content);
139 } 160 if let Ok(parsed) = parsed {
161 let id = parsed.package.name;
140 162
141 let mut dependencies = Vec::new(); 163 let metadata = &parsed.package.metadata.embassy;
142 for (k, _) in parsed.dependencies { 164
143 if k.starts_with("embassy-") { 165 if metadata.skip {
144 dependencies.push(k); 166 continue;
145 } 167 }
146 }
147 168
148 let mut configs = metadata.build.clone(); 169 let mut dependencies = Vec::new();
149 if configs.is_empty() { 170 for (k, _) in parsed.dependencies {
150 configs.push(BuildConfig { 171 if k.starts_with("embassy-") {
151 features: vec![], 172 dependencies.push(k);
152 target: None, 173 }
153 }) 174 }
154 } 175
176 let mut configs = metadata.build.clone();
177 if configs.is_empty() {
178 configs.push(BuildConfig {
179 features: vec![],
180 target: None,
181 artifact_dir: None,
182 })
183 }
155 184
156 crates.insert( 185 crates.insert(
157 id.clone(), 186 id.clone(),
158 Crate { 187 Crate {
159 name: id, 188 name: id,
160 version: parsed.package.version, 189 version: parsed.package.version,
161 path, 190 path,
162 dependencies, 191 dependencies,
163 configs, 192 configs,
164 }, 193 publish: parsed.package.publish,
165 ); 194 },
195 );
196 }
197 } else {
198 // Recursively search subdirectories, but only for examples, tests, and docs
199 let file_name = entry.file_name();
200 let dir_name = file_name.to_string_lossy();
201 if dir_name == "examples" || dir_name == "tests" || dir_name == "docs" {
202 discover_crates(&path, crates)?;
203 }
166 } 204 }
167 } 205 }
168 } 206 }
169 Ok(crates) 207 Ok(())
170} 208}
171 209
172fn build_graph(crates: &BTreeMap<CrateId, Crate>) -> (Graph<CrateId, ()>, HashMap<CrateId, NodeIndex>) { 210fn build_graph(crates: &BTreeMap<CrateId, Crate>) -> (Graph<CrateId, ()>, HashMap<CrateId, NodeIndex>) {
@@ -214,12 +252,17 @@ fn load_context(args: &Args) -> Result<Context> {
214 let crates = list_crates(&root)?; 252 let crates = list_crates(&root)?;
215 let (graph, indices) = build_graph(&crates); 253 let (graph, indices) = build_graph(&crates);
216 254
217 Ok(Context { 255 let ctx = Context {
218 root, 256 root,
219 crates, 257 crates,
220 graph, 258 graph,
221 indices, 259 indices,
222 }) 260 };
261
262 // Check for publish dependency conflicts
263 check_publish_dependencies(&ctx)?;
264
265 Ok(ctx)
223} 266}
224 267
225fn main() -> Result<()> { 268fn main() -> Result<()> {
@@ -274,10 +317,21 @@ fn main() -> Result<()> {
274 } 317 }
275 Command::SemverCheck { crate_name } => { 318 Command::SemverCheck { crate_name } => {
276 let c = ctx.crates.get(&crate_name).unwrap(); 319 let c = ctx.crates.get(&crate_name).unwrap();
320 if !c.publish {
321 bail!("Cannot run semver-check on non-publishable crate '{}'", crate_name);
322 }
277 check_semver(&c)?; 323 check_semver(&c)?;
278 } 324 }
279 Command::PrepareRelease { crate_name } => { 325 Command::PrepareRelease { crate_name } => {
280 let start = ctx.indices.get(&crate_name).expect("unable to find crate in tree"); 326 let start = ctx.indices.get(&crate_name).expect("unable to find crate in tree");
327
328 // Check if the target crate is publishable
329 let start_weight = ctx.graph.node_weight(*start).unwrap();
330 let start_crate = ctx.crates.get(start_weight).unwrap();
331 if !start_crate.publish {
332 bail!("Cannot prepare release for non-publishable crate '{}'", crate_name);
333 }
334
281 let mut rgraph = ctx.graph.clone(); 335 let mut rgraph = ctx.graph.clone();
282 rgraph.reverse(); 336 rgraph.reverse();
283 337
diff --git a/release/src/types.rs b/release/src/types.rs
index c5b774977..4d9d440d8 100644
--- a/release/src/types.rs
+++ b/release/src/types.rs
@@ -13,10 +13,16 @@ pub struct ParsedCrate {
13pub struct ParsedPackage { 13pub struct ParsedPackage {
14 pub name: String, 14 pub name: String,
15 pub version: String, 15 pub version: String,
16 #[serde(default = "default_publish")]
17 pub publish: bool,
16 #[serde(default)] 18 #[serde(default)]
17 pub metadata: Metadata, 19 pub metadata: Metadata,
18} 20}
19 21
22fn default_publish() -> bool {
23 true
24}
25
20#[derive(Debug, Deserialize, Default)] 26#[derive(Debug, Deserialize, Default)]
21pub struct Metadata { 27pub struct Metadata {
22 #[serde(default)] 28 #[serde(default)]
@@ -36,6 +42,8 @@ pub struct BuildConfig {
36 #[serde(default)] 42 #[serde(default)]
37 pub features: Vec<String>, 43 pub features: Vec<String>,
38 pub target: Option<String>, 44 pub target: Option<String>,
45 #[serde(rename = "artifact-dir")]
46 pub artifact_dir: Option<String>,
39} 47}
40 48
41pub type CrateId = String; 49pub type CrateId = String;
@@ -47,4 +55,5 @@ pub struct Crate {
47 pub path: PathBuf, 55 pub path: PathBuf,
48 pub dependencies: Vec<CrateId>, 56 pub dependencies: Vec<CrateId>,
49 pub configs: Vec<BuildConfig>, 57 pub configs: Vec<BuildConfig>,
58 pub publish: bool,
50} 59}