Skip to content
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

Support building only specific components #1515

Merged
merged 1 commit into from
May 22, 2023
Merged

Conversation

itowlson
Copy link
Contributor

@itowlson itowlson commented May 18, 2023

spin doctor is set up to build only the component that the user asks it to fix, but the spin build side of that was not ready in time. Now it is.

# Happy path
ivan@hecate:~/testing/kvmadness$ spin build -c kvmadness
Executing the build command for component kvmadness: cargo build --target wasm32-wasi --release
    Finished release [optimized] target(s) in 0.03s
Successfully ran the build command for component 'kvmadness'.

# No-op path
ivan@hecate:~/testing/kvmadness$ spin build -c moarmadness
Component 'moarmadness' does not have a build command.
For information on specifying a build command, see https://developer.fermyon.com/spin/build#setting-up-for-spin-build.

# Sad path
$ spin build -c moarmadness2
Error: There is no component 'moarmadness2' in the manifest.

Closes #903 [lann: should cover the use case]

Comment on lines 42 to 43
eprintln!("Component '{id}' does not have a build command.");
eprintln!("For information on specifying a build command, see https://developer.fermyon.com/spin/build#setting-up-for-spin-build.");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this return an error result? That would signal to doctor that the fix didn't work, and might be helpful for other kinds of automation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The doctor should never call this for components without a build command - it checks before recommending the "build" treatment.

Yeah I dithered about the error result. I think I kind of reached the conclusion that it hadn't failed, there was just nothing to do. And so I was a bit wary about Rust printing Error: ... which we can't currently stop it doing. But if other folks would prefer an error than I'm happy to go along with that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the existing flow, "no components have a build command" is currently not an error (and prints to stdout rather than stderr so I am being inconsistent there at least).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am reworking it as you suggested to take a list of components so this will unify it to the existing flow. I will use that existing flow for now; we can change it to be an error if we want.

@lann
Copy link
Collaborator

lann commented May 18, 2023

Ah yes, I purposefully left this unimplemented to....drive developer engagement?

@@ -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?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense for component_id to be a Vec<String> (allowing the flag to be specified multiple times)? I'm thinking that would give feature parity with the zombie PR #903

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.

@itowlson
Copy link
Contributor Author

Updated to allow multiple use, resulting in a slight change to some cases:

ivan@hecate:~/testing/kvmadness$ spin build -c moarmadness
None of the components have a build command.
For information on specifying a build command, see https://developer.fermyon.com/spin/build#setting-up-for-spin-build.
ivan@hecate:~/testing/kvmadness$ spin build -c moarmadness -c fie
Error: Unknown component(s) fie
ivan@hecate:~/testing/kvmadness$ spin build -c moarmadness -c fie -c zounds
Error: Unknown component(s) fie, zounds

@itowlson itowlson changed the title Support building a single component Support building only specific components May 19, 2023
Comment on lines +29 to +37
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(", "));
}
Copy link
Collaborator

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?

Suggested change
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(", "));
}
let unknown_component_ids = component_ids
.iter()
.filter(|id| !all_ids.contains(id))
.peekable();
if unknown_component_ids.peek().is_some() {
bail!("Unknown component(s) {}", unknown_component_ids.collect::<Vec<_>>().join(", "));
}

Copy link
Contributor Author

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_empty more obvious than peek().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::join to simplify the sad path in this one.

Copy link
Collaborator

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. 😀

Copy link
Collaborator

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".

Comment on lines +29 to +37
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(", "));
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yet another option...

Suggested change
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(", "));
}
let unknown_component_ids = component_ids
.iter()
.filter(|id| !all_ids.contains(id))
.map(|s| s.as_str())
.collect::<Vec<_>>()
.join(", ");
ensure!(
unknown_component_ids.is_empty(),
"Unknown component(s) {unknown_component_ids}",
);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sub-option: itertools (which other spin crates already use) has itertools::join

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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."

Signed-off-by: itowlson <ivan.towlson@fermyon.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants