-
Notifications
You must be signed in to change notification settings - Fork 297
Support building only specific components #1515
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -6,24 +6,49 @@ mod manifest; | |||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| use anyhow::{anyhow, bail, Context, Result}; | ||||||||||||||||||||||||||||||||||||||||
| use spin_loader::local::parent_dir; | ||||||||||||||||||||||||||||||||||||||||
| use std::path::{Path, PathBuf}; | ||||||||||||||||||||||||||||||||||||||||
| use std::{ | ||||||||||||||||||||||||||||||||||||||||
| collections::HashSet, | ||||||||||||||||||||||||||||||||||||||||
| path::{Path, PathBuf}, | ||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||
| use subprocess::{Exec, Redirection}; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| use crate::manifest::{BuildAppInfoAnyVersion, RawComponentManifest}; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| /// If present, run the build command of each component. | ||||||||||||||||||||||||||||||||||||||||
| pub async fn build(manifest_file: &Path) -> Result<()> { | ||||||||||||||||||||||||||||||||||||||||
| pub async fn build(manifest_file: &Path, component_ids: &[String]) -> Result<()> { | ||||||||||||||||||||||||||||||||||||||||
| let manifest_text = tokio::fs::read_to_string(manifest_file) | ||||||||||||||||||||||||||||||||||||||||
| .await | ||||||||||||||||||||||||||||||||||||||||
| .with_context(|| format!("Cannot read manifest file from {}", manifest_file.display()))?; | ||||||||||||||||||||||||||||||||||||||||
| let app = toml::from_str(&manifest_text).map(BuildAppInfoAnyVersion::into_v1)?; | ||||||||||||||||||||||||||||||||||||||||
| let app_dir = parent_dir(manifest_file)?; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if app.components.iter().all(|c| c.build.is_none()) { | ||||||||||||||||||||||||||||||||||||||||
| println!("No build command found!"); | ||||||||||||||||||||||||||||||||||||||||
| let components_to_build = if component_ids.is_empty() { | ||||||||||||||||||||||||||||||||||||||||
| app.components | ||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||
| let all_ids: HashSet<_> = app.components.iter().map(|c| &c.id).collect(); | ||||||||||||||||||||||||||||||||||||||||
| let unknown_component_ids: Vec<_> = component_ids | ||||||||||||||||||||||||||||||||||||||||
| .iter() | ||||||||||||||||||||||||||||||||||||||||
| .filter(|id| !all_ids.contains(id)) | ||||||||||||||||||||||||||||||||||||||||
| .map(|s| s.as_str()) | ||||||||||||||||||||||||||||||||||||||||
| .collect(); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if !unknown_component_ids.is_empty() { | ||||||||||||||||||||||||||||||||||||||||
| bail!("Unknown component(s) {}", unknown_component_ids.join(", ")); | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+29
to
+37
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yet another option...
Suggested change
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sub-option:
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought about this but felt that "this set is empty" was more explanatory than "this string we are composing for UI purposes is empty." |
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| app.components | ||||||||||||||||||||||||||||||||||||||||
| .into_iter() | ||||||||||||||||||||||||||||||||||||||||
| .filter(|c| component_ids.contains(&c.id)) | ||||||||||||||||||||||||||||||||||||||||
| .collect() | ||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if components_to_build.iter().all(|c| c.build.is_none()) { | ||||||||||||||||||||||||||||||||||||||||
| println!("None of the components have a build command."); | ||||||||||||||||||||||||||||||||||||||||
| println!("For information on specifying a build command, see https://developer.fermyon.com/spin/build#setting-up-for-spin-build."); | ||||||||||||||||||||||||||||||||||||||||
| return Ok(()); | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| app.components | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| components_to_build | ||||||||||||||||||||||||||||||||||||||||
| .into_iter() | ||||||||||||||||||||||||||||||||||||||||
| .map(|c| build_component(c, &app_dir)) | ||||||||||||||||||||||||||||||||||||||||
| .collect::<Result<Vec<_>, _>>()?; | ||||||||||||||||||||||||||||||||||||||||
|
|
@@ -101,6 +126,6 @@ mod tests { | |||||||||||||||||||||||||||||||||||||||
| #[tokio::test] | ||||||||||||||||||||||||||||||||||||||||
| async fn can_load_even_if_trigger_invalid() { | ||||||||||||||||||||||||||||||||||||||||
| let bad_trigger_file = test_data_root().join("bad_trigger.toml"); | ||||||||||||||||||||||||||||||||||||||||
| build(&bad_trigger_file).await.unwrap(); | ||||||||||||||||||||||||||||||||||||||||
| build(&bad_trigger_file, &[]).await.unwrap(); | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,9 +23,9 @@ pub struct BuildCommand { | |
| )] | ||
| pub app_source: PathBuf, | ||
|
|
||
| /// Component ID to build. The default is all components. | ||
| #[clap(short = 'c', long)] | ||
| pub component_id: Option<String>, | ||
| /// Component ID to build. This can be specified multiple times. The default is all components. | ||
| #[clap(short = 'c', long, multiple = true)] | ||
| pub component_id: Vec<String>, | ||
|
|
||
| /// Run the application after building. | ||
| #[clap(name = BUILD_UP_OPT, short = 'u', long = "up")] | ||
|
|
@@ -38,7 +38,7 @@ pub struct BuildCommand { | |
| impl BuildCommand { | ||
| pub async fn run(self) -> Result<()> { | ||
| let manifest_file = crate::manifest::resolve_file_path(&self.app_source)?; | ||
| spin_build::build(&manifest_file).await?; | ||
| spin_build::build(&manifest_file, &self.component_id).await?; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it make sense for
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It couldn't possibly do any harm, he said, cheerily placing his Jenga block. |
||
|
|
||
| if self.up { | ||
| let mut cmd = UpCommand::parse_from( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Might as well avoid the unnecessary allocation in the happy path?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL:
peekable()- thank you!"Avoid allocating an empty vector" doesn't feel like a huge priority when the happy path goes on to run an external process (a compiler, no less). And I have to admit I find
is_emptymore obvious thanpeek().is_some(), though maybe the latter is idiomatic to Rust devs?But I can change it (to this or @lann's suggestion) if other folks prefer. We could also use @lann's mention of
itertools::jointo simplify the sad path in this one.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to block on my nits. I'll let you decide how to proceed from here. 😀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah same for my suggestions, which are more along the lines of "behold the majesty of the yak shave".